]> git.ipfire.org Git - thirdparty/glibc.git/blame - sysdeps/mach/hurd/getcwd.c
Update copyright notices with scripts/update-copyrights
[thirdparty/glibc.git] / sysdeps / mach / hurd / getcwd.c
CommitLineData
d4697bc9 1/* Copyright (C) 1991-2014 Free Software Foundation, Inc.
478b92f0 2 This file is part of the GNU C Library.
28f540f4 3
478b92f0 4 The GNU C Library is free software; you can redistribute it and/or
41bdb6e2
AJ
5 modify it under the terms of the GNU Lesser General Public
6 License as published by the Free Software Foundation; either
7 version 2.1 of the License, or (at your option) any later version.
28f540f4 8
478b92f0
UD
9 The GNU C Library is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
41bdb6e2 12 Lesser General Public License for more details.
28f540f4 13
41bdb6e2 14 You should have received a copy of the GNU Lesser General Public
59ba27a6
PE
15 License along with the GNU C Library; if not, see
16 <http://www.gnu.org/licenses/>. */
28f540f4
RM
17
18#include <errno.h>
19#include <sys/types.h>
20#include <sys/stat.h>
21#include <hurd.h>
22#include <hurd/port.h>
23#include <dirent.h>
24#include <unistd.h>
25#include <stdlib.h>
26#include <string.h>
27#include <stdio.h>
28#include <fcntl.h>
29
30
fa0bc87c
RM
31/* Get the canonical absolute name of the given directory port, and put it
32 in SIZE bytes of BUF. Returns NULL if the directory couldn't be
33 determined or SIZE was too small. If successful, returns BUF. In GNU,
34 if BUF is NULL, an array is allocated with `malloc'; the array is SIZE
657acd6c
RM
35 bytes long, unless SIZE <= 0, in which case it is as big as necessary.
36 If our root directory cannot be reached, the result will not begin with
37 a slash to indicate that it is relative to some unknown root directory. */
28f540f4
RM
38
39char *
fa0bc87c
RM
40_hurd_canonicalize_directory_name_internal (file_t thisdir,
41 char *buf,
42 size_t size)
28f540f4
RM
43{
44 error_t err;
0e3426bb 45 mach_port_t rootid, thisid, rootdevid, thisdevid;
337738b7 46 ino64_t rootino, thisino;
28f540f4 47 char *file_name;
2e09a79a 48 char *file_namep;
28f540f4
RM
49 file_t parent;
50 char *dirbuf = NULL;
51 unsigned int dirbufsize = 0;
fbf86dda 52 const size_t orig_size = size;
28f540f4
RM
53
54 inline void cleanup (void)
55 {
315289fb
MB
56 if (parent != thisdir)
57 __mach_port_deallocate (__mach_task_self (), parent);
58
0e3426bb
RM
59 __mach_port_deallocate (__mach_task_self (), thisid);
60 __mach_port_deallocate (__mach_task_self (), thisdevid);
61 __mach_port_deallocate (__mach_task_self (), rootid);
28f540f4
RM
62
63 if (dirbuf != NULL)
64 __vm_deallocate (__mach_task_self (),
65 (vm_address_t) dirbuf, dirbufsize);
66 }
67
b20e47cb 68
fbf86dda 69 if (size <= 0)
28f540f4
RM
70 {
71 if (buf != NULL)
72 {
73 errno = EINVAL;
74 return NULL;
75 }
76
77 size = FILENAME_MAX * 4 + 1; /* Good starting guess. */
78 }
79
80 if (buf != NULL)
81 file_name = buf;
82 else
83 {
84 file_name = malloc (size);
85 if (file_name == NULL)
86 return NULL;
87 }
88
89 file_namep = file_name + size;
90 *--file_namep = '\0';
91
0e3426bb 92 /* Get a port to our root directory and get its identity. */
28f540f4 93
0e3426bb
RM
94 if (err = __USEPORT (CRDIR, __io_identity (port,
95 &rootid, &rootdevid, &rootino)))
924b9ff6 96 return __hurd_fail (err), NULL;
0e3426bb 97 __mach_port_deallocate (__mach_task_self (), rootdevid);
28f540f4 98
fa0bc87c 99 /* Stat the port to the directory of interest. */
28f540f4 100
fa0bc87c 101 if (err = __io_identity (thisdir, &thisid, &thisdevid, &thisino))
28f540f4 102 {
0e3426bb 103 __mach_port_deallocate (__mach_task_self (), rootid);
28f540f4
RM
104 return __hurd_fail (err), NULL;
105 }
106
315289fb 107 parent = thisdir;
0e3426bb 108 while (thisid != rootid)
28f540f4
RM
109 {
110 /* PARENT is a port to the directory we are currently on;
0e3426bb
RM
111 THISID, THISDEV, and THISINO are its identity.
112 Look in its parent (..) for a file with the same file number. */
28f540f4 113
337738b7 114 struct dirent64 *d;
0e3426bb 115 mach_port_t dotid, dotdevid;
337738b7 116 ino64_t dotino;
28f540f4
RM
117 int mount_point;
118 file_t newp;
119 char *dirdata;
5b6cab3e 120 size_t dirdatasize;
28f540f4
RM
121 int direntry, nentries;
122
072d1145 123
28f540f4 124 /* Look at the parent directory. */
924b9ff6
RM
125 newp = __file_name_lookup_under (parent, "..", O_READ, 0);
126 if (newp == MACH_PORT_NULL)
28f540f4 127 goto lose;
315289fb
MB
128 if (parent != thisdir)
129 __mach_port_deallocate (__mach_task_self (), parent);
28f540f4
RM
130 parent = newp;
131
657acd6c
RM
132 /* Get this directory's identity and figure out if it's a mount
133 point. */
0e3426bb 134 if (err = __io_identity (parent, &dotid, &dotdevid, &dotino))
924b9ff6 135 goto errlose;
0e3426bb 136 mount_point = dotdevid != thisdevid;
28f540f4 137
657acd6c
RM
138 if (thisid == dotid)
139 {
140 /* `..' == `.' but it is not our root directory. */
141 __mach_port_deallocate (__mach_task_self (), dotid);
142 __mach_port_deallocate (__mach_task_self (), dotdevid);
143 break;
144 }
145
28f540f4
RM
146 /* Search for the last directory. */
147 direntry = 0;
148 dirdata = dirbuf;
149 dirdatasize = dirbufsize;
150 while (!(err = __dir_readdir (parent, &dirdata, &dirdatasize,
151 direntry, -1, 0, &nentries)) &&
b20e47cb 152 nentries != 0)
28f540f4
RM
153 {
154 /* We have a block of directory entries. */
155
156 unsigned int offset;
157
158 direntry += nentries;
159
160 if (dirdata != dirbuf)
161 {
162 /* The data was passed out of line, so our old buffer is no
163 longer useful. Deallocate the old buffer and reset our
164 information for the new buffer. */
165 __vm_deallocate (__mach_task_self (),
166 (vm_address_t) dirbuf, dirbufsize);
167 dirbuf = dirdata;
168 dirbufsize = round_page (dirdatasize);
169 }
170
171 /* Iterate over the returned directory entries, looking for one
172 whose file number is THISINO. */
173
174 offset = 0;
175 while (offset < dirdatasize)
176 {
337738b7 177 d = (struct dirent64 *) &dirdata[offset];
28f540f4
RM
178 offset += d->d_reclen;
179
b20e47cb 180 /* Ignore `.' and `..'. */
28f540f4
RM
181 if (d->d_name[0] == '.' &&
182 (d->d_namlen == 1 ||
183 (d->d_namlen == 2 && d->d_name[1] == '.')))
184 continue;
185
186 if (mount_point || d->d_ino == thisino)
187 {
924b9ff6
RM
188 file_t try = __file_name_lookup_under (parent, d->d_name,
189 O_NOLINK, 0);
0e3426bb 190 file_t id, devid;
337738b7 191 ino64_t fileno;
924b9ff6 192 if (try == MACH_PORT_NULL)
28f540f4 193 goto lose;
0e3426bb 194 err = __io_identity (try, &id, &devid, &fileno);
28f540f4
RM
195 __mach_port_deallocate (__mach_task_self (), try);
196 if (err)
aeb0816f 197 goto inner_errlose;
0e3426bb
RM
198 __mach_port_deallocate (__mach_task_self (), id);
199 __mach_port_deallocate (__mach_task_self (), devid);
200 if (id == thisid)
f5936b69 201 goto found;
28f540f4
RM
202 }
203 }
204 }
205
206 if (err)
aeb0816f
MB
207 {
208 inner_errlose: /* Goto ERRLOSE: after cleaning up. */
209 __mach_port_deallocate (__mach_task_self (), dotid);
210 __mach_port_deallocate (__mach_task_self (), dotdevid);
211 goto errlose;
212 }
b20e47cb
RM
213 else if (nentries == 0)
214 {
215 /* We got to the end of the directory without finding anything!
216 We are in a directory that has been unlinked, or something is
217 broken. */
218 err = ENOENT;
aeb0816f 219 goto inner_errlose;
b20e47cb 220 }
28f540f4 221 else
f5936b69 222 found:
28f540f4
RM
223 {
224 /* Prepend the directory name just discovered. */
225
226 if (file_namep - file_name < d->d_namlen + 1)
227 {
fbf86dda 228 if (orig_size > 0)
28f540f4
RM
229 {
230 errno = ERANGE;
231 return NULL;
232 }
233 else
234 {
235 size *= 2;
236 buf = realloc (file_name, size);
237 if (buf == NULL)
238 {
239 free (file_name);
240 return NULL;
241 }
b236e99d 242 file_namep = &buf[file_namep - file_name + size / 2];
28f540f4 243 file_name = buf;
b236e99d
UD
244 /* Move current contents up to the end of the buffer.
245 This is guaranteed to be non-overlapping. */
246 memcpy (file_namep, file_namep - size / 2,
247 file_name + size - file_namep);
28f540f4
RM
248 }
249 }
250 file_namep -= d->d_namlen;
251 (void) memcpy (file_namep, d->d_name, d->d_namlen);
252 *--file_namep = '/';
253 }
254
255 /* The next iteration will find the name of the directory we
256 just searched through. */
0e3426bb
RM
257 __mach_port_deallocate (__mach_task_self (), thisid);
258 __mach_port_deallocate (__mach_task_self (), thisdevid);
259 thisid = dotid;
260 thisdevid = dotdevid;
28f540f4
RM
261 thisino = dotino;
262 }
263
264 if (file_namep == &file_name[size - 1])
265 /* We found nothing and got all the way to the root.
266 So the root is our current directory. */
267 *--file_namep = '/';
268
657acd6c
RM
269 if (thisid != rootid)
270 /* We did not get to our root directory. The returned name should
271 not begin with a slash. */
272 ++file_namep;
273
28f540f4
RM
274 memmove (file_name, file_namep, file_name + size - file_namep);
275 cleanup ();
276 return file_name;
277
924b9ff6
RM
278 errlose:
279 /* Set errno. */
280 (void) __hurd_fail (err);
28f540f4
RM
281 lose:
282 cleanup ();
283 return NULL;
284}
fa0bc87c
RM
285
286char *
287__canonicalize_directory_name_internal (thisdir, buf, size)
288 const char *thisdir;
289 char *buf;
290 size_t size;
291{
292 char *result;
293 file_t port = __file_name_lookup (thisdir, 0, 0);
294 if (port == MACH_PORT_NULL)
295 return NULL;
296 result = _hurd_canonicalize_directory_name_internal (port, buf, size);
297 __mach_port_deallocate (__mach_task_self (), port);
298 return result;
299}
300\f
301/* Get the pathname of the current working directory, and put it in SIZE
302 bytes of BUF. Returns NULL if the directory couldn't be determined or
303 SIZE was too small. If successful, returns BUF. In GNU, if BUF is
304 NULL, an array is allocated with `malloc'; the array is SIZE bytes long,
305 unless SIZE <= 0, in which case it is as big as necessary. */
306char *
307__getcwd (char *buf, size_t size)
308{
657acd6c
RM
309 char *cwd =
310 __USEPORT (CWDIR,
311 _hurd_canonicalize_directory_name_internal (port,
312 buf, size));
313 if (cwd && cwd[0] != '/')
314 {
315 /* `cwd' is an unknown root directory. */
316 if (buf == NULL)
317 free (cwd);
318 return __hurd_fail (EGRATUITOUS), NULL;
319 }
320 return cwd;
fa0bc87c 321}
3ec41e03 322weak_alias (__getcwd, getcwd)