1 /* Copyright (C) 1991,92,93,94,95,96,97,98,2002,2004,2009
2 Free Software Foundation, Inc.
3 This file is part of the GNU C Library.
5 The GNU C Library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Lesser General Public
7 License as published by the Free Software Foundation; either
8 version 2.1 of the License, or (at your option) any later version.
10 The GNU C Library is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Lesser General Public License for more details.
15 You should have received a copy of the GNU Lesser General Public
16 License along with the GNU C Library; if not, write to the Free
17 Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
21 #include <sys/types.h>
24 #include <hurd/port.h>
33 /* Get the canonical absolute name of the given directory port, and put it
34 in SIZE bytes of BUF. Returns NULL if the directory couldn't be
35 determined or SIZE was too small. If successful, returns BUF. In GNU,
36 if BUF is NULL, an array is allocated with `malloc'; the array is SIZE
37 bytes long, unless SIZE <= 0, in which case it is as big as necessary.
38 If our root directory cannot be reached, the result will not begin with
39 a slash to indicate that it is relative to some unknown root directory. */
42 _hurd_canonicalize_directory_name_internal (file_t thisdir
,
47 mach_port_t rootid
, thisid
, rootdevid
, thisdevid
;
48 ino64_t rootino
, thisino
;
50 register char *file_namep
;
53 unsigned int dirbufsize
= 0;
54 const size_t orig_size
= size
;
56 inline void cleanup (void)
58 if (parent
!= thisdir
)
59 __mach_port_deallocate (__mach_task_self (), parent
);
61 __mach_port_deallocate (__mach_task_self (), thisid
);
62 __mach_port_deallocate (__mach_task_self (), thisdevid
);
63 __mach_port_deallocate (__mach_task_self (), rootid
);
66 __vm_deallocate (__mach_task_self (),
67 (vm_address_t
) dirbuf
, dirbufsize
);
79 size
= FILENAME_MAX
* 4 + 1; /* Good starting guess. */
86 file_name
= malloc (size
);
87 if (file_name
== NULL
)
91 file_namep
= file_name
+ size
;
94 /* Get a port to our root directory and get its identity. */
96 if (err
= __USEPORT (CRDIR
, __io_identity (port
,
97 &rootid
, &rootdevid
, &rootino
)))
98 return __hurd_fail (err
), NULL
;
99 __mach_port_deallocate (__mach_task_self (), rootdevid
);
101 /* Stat the port to the directory of interest. */
103 if (err
= __io_identity (thisdir
, &thisid
, &thisdevid
, &thisino
))
105 __mach_port_deallocate (__mach_task_self (), rootid
);
106 return __hurd_fail (err
), NULL
;
110 while (thisid
!= rootid
)
112 /* PARENT is a port to the directory we are currently on;
113 THISID, THISDEV, and THISINO are its identity.
114 Look in its parent (..) for a file with the same file number. */
117 mach_port_t dotid
, dotdevid
;
123 int direntry
, nentries
;
126 /* Look at the parent directory. */
127 newp
= __file_name_lookup_under (parent
, "..", O_READ
, 0);
128 if (newp
== MACH_PORT_NULL
)
130 if (parent
!= thisdir
)
131 __mach_port_deallocate (__mach_task_self (), parent
);
134 /* Get this directory's identity and figure out if it's a mount
136 if (err
= __io_identity (parent
, &dotid
, &dotdevid
, &dotino
))
138 mount_point
= dotdevid
!= thisdevid
;
142 /* `..' == `.' but it is not our root directory. */
143 __mach_port_deallocate (__mach_task_self (), dotid
);
144 __mach_port_deallocate (__mach_task_self (), dotdevid
);
148 /* Search for the last directory. */
151 dirdatasize
= dirbufsize
;
152 while (!(err
= __dir_readdir (parent
, &dirdata
, &dirdatasize
,
153 direntry
, -1, 0, &nentries
)) &&
156 /* We have a block of directory entries. */
160 direntry
+= nentries
;
162 if (dirdata
!= dirbuf
)
164 /* The data was passed out of line, so our old buffer is no
165 longer useful. Deallocate the old buffer and reset our
166 information for the new buffer. */
167 __vm_deallocate (__mach_task_self (),
168 (vm_address_t
) dirbuf
, dirbufsize
);
170 dirbufsize
= round_page (dirdatasize
);
173 /* Iterate over the returned directory entries, looking for one
174 whose file number is THISINO. */
177 while (offset
< dirdatasize
)
179 d
= (struct dirent64
*) &dirdata
[offset
];
180 offset
+= d
->d_reclen
;
182 /* Ignore `.' and `..'. */
183 if (d
->d_name
[0] == '.' &&
185 (d
->d_namlen
== 2 && d
->d_name
[1] == '.')))
188 if (mount_point
|| d
->d_ino
== thisino
)
190 file_t
try = __file_name_lookup_under (parent
, d
->d_name
,
194 if (try == MACH_PORT_NULL
)
196 err
= __io_identity (try, &id
, &devid
, &fileno
);
197 __mach_port_deallocate (__mach_task_self (), try);
200 __mach_port_deallocate (__mach_task_self (), id
);
201 __mach_port_deallocate (__mach_task_self (), devid
);
210 inner_errlose
: /* Goto ERRLOSE: after cleaning up. */
211 __mach_port_deallocate (__mach_task_self (), dotid
);
212 __mach_port_deallocate (__mach_task_self (), dotdevid
);
215 else if (nentries
== 0)
217 /* We got to the end of the directory without finding anything!
218 We are in a directory that has been unlinked, or something is
226 /* Prepend the directory name just discovered. */
228 if (file_namep
- file_name
< d
->d_namlen
+ 1)
238 buf
= realloc (file_name
, size
);
244 file_namep
= &buf
[file_namep
- file_name
+ size
/ 2];
246 /* Move current contents up to the end of the buffer.
247 This is guaranteed to be non-overlapping. */
248 memcpy (file_namep
, file_namep
- size
/ 2,
249 file_name
+ size
- file_namep
);
252 file_namep
-= d
->d_namlen
;
253 (void) memcpy (file_namep
, d
->d_name
, d
->d_namlen
);
257 /* The next iteration will find the name of the directory we
258 just searched through. */
259 __mach_port_deallocate (__mach_task_self (), thisid
);
260 __mach_port_deallocate (__mach_task_self (), thisdevid
);
262 thisdevid
= dotdevid
;
266 if (file_namep
== &file_name
[size
- 1])
267 /* We found nothing and got all the way to the root.
268 So the root is our current directory. */
271 if (thisid
!= rootid
)
272 /* We did not get to our root directory. The returned name should
273 not begin with a slash. */
276 memmove (file_name
, file_namep
, file_name
+ size
- file_namep
);
282 (void) __hurd_fail (err
);
289 __canonicalize_directory_name_internal (thisdir
, buf
, size
)
295 file_t port
= __file_name_lookup (thisdir
, 0, 0);
296 if (port
== MACH_PORT_NULL
)
298 result
= _hurd_canonicalize_directory_name_internal (port
, buf
, size
);
299 __mach_port_deallocate (__mach_task_self (), port
);
303 /* Get the pathname of the current working directory, and put it in SIZE
304 bytes of BUF. Returns NULL if the directory couldn't be determined or
305 SIZE was too small. If successful, returns BUF. In GNU, if BUF is
306 NULL, an array is allocated with `malloc'; the array is SIZE bytes long,
307 unless SIZE <= 0, in which case it is as big as necessary. */
309 __getcwd (char *buf
, size_t size
)
313 _hurd_canonicalize_directory_name_internal (port
,
315 if (cwd
&& cwd
[0] != '/')
317 /* `cwd' is an unknown root directory. */
320 return __hurd_fail (EGRATUITOUS
), NULL
;
324 weak_alias (__getcwd
, getcwd
)