]>
Commit | Line | Data |
---|---|---|
475e390e | 1 | /* Copyright (C) 1991,92,93,94,95,96,97,98,99 Free Software Foundation, Inc. |
47707456 | 2 | This file is part of the GNU C Library. |
28f540f4 | 3 | |
47707456 | 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 | |
47707456 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 AJ |
14 | You should have received a copy of the GNU Lesser General Public |
15 | License along with the GNU C Library; if not, write to the Free | |
16 | Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA | |
17 | 02111-1307 USA. */ | |
28f540f4 RM |
18 | |
19 | /* Wants: | |
20 | AC_STDC_HEADERS | |
21 | AC_DIR_HEADER | |
22 | AC_UNISTD_H | |
23 | AC_MEMORY_H | |
24 | AC_CONST | |
25 | AC_ALLOCA | |
26 | */ | |
27 | ||
28 | /* AIX requires this to be the first thing in the file. */ | |
86187531 | 29 | #if defined _AIX && !defined __GNUC__ |
28f540f4 RM |
30 | #pragma alloca |
31 | #endif | |
32 | ||
33 | #ifdef HAVE_CONFIG_H | |
86187531 | 34 | # include "config.h" |
28f540f4 RM |
35 | #endif |
36 | ||
37 | #include <errno.h> | |
38 | #include <sys/types.h> | |
39 | #include <sys/stat.h> | |
40 | ||
41 | #ifdef STDC_HEADERS | |
86187531 | 42 | # include <stddef.h> |
28f540f4 RM |
43 | #endif |
44 | ||
86187531 | 45 | #if !defined __GNU_LIBRARY__ && !defined STDC_HEADERS |
28f540f4 RM |
46 | extern int errno; |
47 | #endif | |
c4029823 | 48 | #ifndef __set_errno |
86187531 | 49 | # define __set_errno(val) errno = (val) |
c4029823 | 50 | #endif |
28f540f4 RM |
51 | |
52 | #ifndef NULL | |
86187531 | 53 | # define NULL 0 |
28f540f4 RM |
54 | #endif |
55 | ||
86187531 UD |
56 | #if defined USGr3 && !defined DIRENT |
57 | # define DIRENT | |
28f540f4 | 58 | #endif /* USGr3 */ |
86187531 UD |
59 | #if defined Xenix && !defined SYSNDIR |
60 | # define SYSNDIR | |
28f540f4 RM |
61 | #endif /* Xenix */ |
62 | ||
86187531 UD |
63 | #if defined POSIX || defined DIRENT || defined __GNU_LIBRARY__ |
64 | # include <dirent.h> | |
65 | # ifndef __GNU_LIBRARY__ | |
66 | # define D_NAMLEN(d) strlen((d)->d_name) | |
67 | # else | |
68 | # define HAVE_D_NAMLEN | |
69 | # define D_NAMLEN(d) ((d)->d_namlen) | |
70 | # endif | |
28f540f4 | 71 | #else /* not POSIX or DIRENT */ |
86187531 UD |
72 | # define dirent direct |
73 | # define D_NAMLEN(d) ((d)->d_namlen) | |
74 | # define HAVE_D_NAMLEN | |
75 | # if defined USG && !defined sgi | |
76 | # if defined SYSNDIR | |
77 | # include <sys/ndir.h> | |
78 | # else /* Not SYSNDIR */ | |
79 | # include "ndir.h" | |
80 | # endif /* SYSNDIR */ | |
81 | # else /* not USG */ | |
82 | # include <sys/dir.h> | |
83 | # endif /* USG */ | |
28f540f4 RM |
84 | #endif /* POSIX or DIRENT or __GNU_LIBRARY__ */ |
85 | ||
86187531 UD |
86 | #if defined HAVE_UNISTD_H || defined __GNU_LIBRARY__ |
87 | # include <unistd.h> | |
28f540f4 RM |
88 | #endif |
89 | ||
86187531 UD |
90 | #if defined STDC_HEADERS || defined __GNU_LIBRARY__ || defined POSIX |
91 | # include <stdlib.h> | |
92 | # include <string.h> | |
93 | # define ANSI_STRING | |
28f540f4 RM |
94 | #else /* No standard headers. */ |
95 | ||
86187531 | 96 | # ifdef USG |
28f540f4 | 97 | |
86187531 UD |
98 | # include <string.h> |
99 | # ifdef NEED_MEMORY_H | |
100 | # include <memory.h> | |
101 | # endif | |
102 | # define ANSI_STRING | |
28f540f4 | 103 | |
86187531 | 104 | # else /* Not USG. */ |
28f540f4 | 105 | |
86187531 | 106 | # ifdef NeXT |
28f540f4 | 107 | |
86187531 | 108 | # include <string.h> |
28f540f4 | 109 | |
86187531 | 110 | # else /* Not NeXT. */ |
28f540f4 | 111 | |
86187531 | 112 | # include <strings.h> |
28f540f4 | 113 | |
86187531 | 114 | # ifndef bcmp |
28f540f4 | 115 | extern int bcmp (); |
86187531 UD |
116 | # endif |
117 | # ifndef bzero | |
28f540f4 | 118 | extern void bzero (); |
86187531 UD |
119 | # endif |
120 | # ifndef bcopy | |
28f540f4 | 121 | extern void bcopy (); |
86187531 | 122 | # endif |
28f540f4 | 123 | |
86187531 | 124 | # endif /* NeXT. */ |
28f540f4 | 125 | |
86187531 | 126 | # endif /* USG. */ |
28f540f4 RM |
127 | |
128 | extern char *malloc (), *realloc (); | |
129 | extern void free (); | |
130 | ||
131 | #endif /* Standard headers. */ | |
132 | ||
133 | #ifndef ANSI_STRING | |
86187531 UD |
134 | # define memcpy(d, s, n) bcopy((s), (d), (n)) |
135 | # define memmove memcpy | |
28f540f4 RM |
136 | #endif /* Not ANSI_STRING. */ |
137 | ||
c9cddf51 UD |
138 | #ifndef MAX |
139 | # define MAX(a, b) ((a) < (b) ? (b) : (a)) | |
140 | #endif | |
141 | ||
cc3fa755 | 142 | #ifdef _LIBC |
50a1b837 UD |
143 | # ifndef mempcpy |
144 | # define mempcpy __mempcpy | |
145 | # endif | |
cc3fa755 UD |
146 | # define HAVE_MEMPCPY 1 |
147 | #endif | |
148 | ||
86187531 | 149 | #if !defined __alloca && !defined __GNU_LIBRARY__ |
28f540f4 | 150 | |
86187531 UD |
151 | # ifdef __GNUC__ |
152 | # undef alloca | |
153 | # define alloca(n) __builtin_alloca (n) | |
154 | # else /* Not GCC. */ | |
155 | # if defined sparc || defined HAVE_ALLOCA_H | |
156 | # include <alloca.h> | |
157 | # else /* Not sparc or HAVE_ALLOCA_H. */ | |
158 | # ifndef _AIX | |
28f540f4 | 159 | extern char *alloca (); |
86187531 UD |
160 | # endif /* Not _AIX. */ |
161 | # endif /* sparc or HAVE_ALLOCA_H. */ | |
162 | # endif /* GCC. */ | |
28f540f4 | 163 | |
86187531 | 164 | # define __alloca alloca |
28f540f4 RM |
165 | |
166 | #endif | |
167 | ||
86187531 UD |
168 | #if defined HAVE_LIMITS_H || defined STDC_HEADERS || defined __GNU_LIBRARY__ |
169 | # include <limits.h> | |
28f540f4 | 170 | #else |
86187531 | 171 | # include <sys/param.h> |
28f540f4 RM |
172 | #endif |
173 | ||
174 | #ifndef PATH_MAX | |
86187531 UD |
175 | # ifdef MAXPATHLEN |
176 | # define PATH_MAX MAXPATHLEN | |
177 | # else | |
178 | # define PATH_MAX 1024 | |
179 | # endif | |
28f540f4 RM |
180 | #endif |
181 | ||
86187531 UD |
182 | #if !defined STDC_HEADERS && !defined __GNU_LIBRARY__ |
183 | # undef size_t | |
184 | # define size_t unsigned int | |
28f540f4 RM |
185 | #endif |
186 | ||
86187531 UD |
187 | #if !__STDC__ && !defined const |
188 | # define const | |
28f540f4 RM |
189 | #endif |
190 | ||
191 | #ifndef __GNU_LIBRARY__ | |
86187531 | 192 | # define __lstat stat |
28f540f4 RM |
193 | #endif |
194 | \f | |
7f811679 | 195 | #ifndef _LIBC |
86187531 | 196 | # define __getcwd getcwd |
7f811679 RM |
197 | #endif |
198 | ||
04be94a8 UD |
199 | #ifndef GETCWD_RETURN_TYPE |
200 | # define GETCWD_RETURN_TYPE char * | |
fe0ec73e UD |
201 | #endif |
202 | ||
7f811679 | 203 | /* Get the pathname of the current working directory, and put it in SIZE |
28f540f4 RM |
204 | bytes of BUF. Returns NULL if the directory couldn't be determined or |
205 | SIZE was too small. If successful, returns BUF. In GNU, if BUF is | |
206 | NULL, an array is allocated with `malloc'; the array is SIZE bytes long, | |
a2b3aa73 | 207 | unless SIZE == 0, in which case it is as big as necessary. */ |
28f540f4 | 208 | |
04be94a8 | 209 | GETCWD_RETURN_TYPE |
7f811679 | 210 | __getcwd (buf, size) |
28f540f4 RM |
211 | char *buf; |
212 | size_t size; | |
213 | { | |
214 | static const char dots[] | |
215 | = "../../../../../../../../../../../../../../../../../../../../../../../\ | |
216 | ../../../../../../../../../../../../../../../../../../../../../../../../../../\ | |
217 | ../../../../../../../../../../../../../../../../../../../../../../../../../.."; | |
475e390e UD |
218 | const char *dotp = &dots[sizeof (dots)]; |
219 | const char *dotlist = dots; | |
220 | size_t dotsize = sizeof (dots) - 1; | |
28f540f4 RM |
221 | dev_t rootdev, thisdev; |
222 | ino_t rootino, thisino; | |
223 | char *path; | |
224 | register char *pathp; | |
225 | struct stat st; | |
f4017d20 | 226 | int prev_errno = errno; |
1823e76b | 227 | size_t allocated = size; |
28f540f4 | 228 | |
a2b3aa73 | 229 | if (size == 0) |
28f540f4 RM |
230 | { |
231 | if (buf != NULL) | |
232 | { | |
c4029823 | 233 | __set_errno (EINVAL); |
28f540f4 RM |
234 | return NULL; |
235 | } | |
236 | ||
1823e76b | 237 | allocated = PATH_MAX + 1; |
28f540f4 RM |
238 | } |
239 | ||
240 | if (buf != NULL) | |
241 | path = buf; | |
242 | else | |
243 | { | |
1823e76b | 244 | path = malloc (allocated); |
28f540f4 RM |
245 | if (path == NULL) |
246 | return NULL; | |
247 | } | |
248 | ||
1823e76b | 249 | pathp = path + allocated; |
28f540f4 RM |
250 | *--pathp = '\0'; |
251 | ||
7f811679 | 252 | if (__lstat (".", &st) < 0) |
475e390e | 253 | goto lose2; |
28f540f4 RM |
254 | thisdev = st.st_dev; |
255 | thisino = st.st_ino; | |
256 | ||
257 | if (__lstat ("/", &st) < 0) | |
475e390e | 258 | goto lose2; |
28f540f4 RM |
259 | rootdev = st.st_dev; |
260 | rootino = st.st_ino; | |
261 | ||
28f540f4 RM |
262 | while (!(thisdev == rootdev && thisino == rootino)) |
263 | { | |
264 | register DIR *dirstream; | |
a18f587d | 265 | struct dirent *d; |
28f540f4 RM |
266 | dev_t dotdev; |
267 | ino_t dotino; | |
268 | char mount_point; | |
269 | ||
270 | /* Look at the parent directory. */ | |
271 | if (dotp == dotlist) | |
272 | { | |
273 | /* My, what a deep directory tree you have, Grandma. */ | |
274 | char *new; | |
275 | if (dotlist == dots) | |
276 | { | |
277 | new = malloc (dotsize * 2 + 1); | |
278 | if (new == NULL) | |
475e390e | 279 | goto lose; |
86187531 UD |
280 | #ifdef HAVE_MEMPCPY |
281 | dotp = mempcpy (new, dots, dotsize); | |
282 | #else | |
28f540f4 | 283 | memcpy (new, dots, dotsize); |
86187531 UD |
284 | dotp = &new[dotsize]; |
285 | #endif | |
28f540f4 RM |
286 | } |
287 | else | |
288 | { | |
289 | new = realloc ((__ptr_t) dotlist, dotsize * 2 + 1); | |
290 | if (new == NULL) | |
291 | goto lose; | |
86187531 | 292 | dotp = &new[dotsize]; |
28f540f4 | 293 | } |
86187531 | 294 | #ifdef HAVE_MEMPCPY |
cc3fa755 | 295 | *((char *) mempcpy ((char *) dotp, new, dotsize)) = '\0'; |
86187531 UD |
296 | dotsize *= 2; |
297 | #else | |
cc3fa755 | 298 | memcpy ((char *) dotp, new, dotsize); |
28f540f4 RM |
299 | dotsize *= 2; |
300 | new[dotsize] = '\0'; | |
86187531 | 301 | #endif |
28f540f4 RM |
302 | dotlist = new; |
303 | } | |
304 | ||
305 | dotp -= 3; | |
306 | ||
307 | /* Figure out if this directory is a mount point. */ | |
308 | if (__lstat (dotp, &st) < 0) | |
309 | goto lose; | |
310 | dotdev = st.st_dev; | |
311 | dotino = st.st_ino; | |
312 | mount_point = dotdev != thisdev; | |
313 | ||
314 | /* Search for the last directory. */ | |
23396375 | 315 | dirstream = __opendir (dotp); |
28f540f4 RM |
316 | if (dirstream == NULL) |
317 | goto lose; | |
f4017d20 UD |
318 | /* Clear errno to distinguish EOF from error if readdir returns |
319 | NULL. */ | |
320 | __set_errno (0); | |
10dc2a90 | 321 | while ((d = __readdir (dirstream)) != NULL) |
28f540f4 RM |
322 | { |
323 | if (d->d_name[0] == '.' && | |
92777700 RM |
324 | (d->d_name[1] == '\0' || |
325 | (d->d_name[1] == '.' && d->d_name[2] == '\0'))) | |
28f540f4 | 326 | continue; |
d68171ed | 327 | if (mount_point || (ino_t) d->d_ino == thisino) |
28f540f4 | 328 | { |
92777700 | 329 | char name[dotlist + dotsize - dotp + 1 + _D_ALLOC_NAMLEN (d)]; |
86187531 UD |
330 | #ifdef HAVE_MEMPCPY |
331 | char *tmp = mempcpy (name, dotp, dotlist + dotsize - dotp); | |
332 | *tmp++ = '/'; | |
333 | strcpy (tmp, d->d_name); | |
334 | #else | |
28f540f4 RM |
335 | memcpy (name, dotp, dotlist + dotsize - dotp); |
336 | name[dotlist + dotsize - dotp] = '/'; | |
92777700 | 337 | strcpy (&name[dotlist + dotsize - dotp + 1], d->d_name); |
86187531 | 338 | #endif |
74f7e7c0 UD |
339 | /* We don't fail here if we cannot stat() a directory entry. |
340 | This can happen when (network) filesystems fail. If this | |
341 | entry is in fact the one we are looking for we will find | |
342 | out soon as we reach the end of the directory without | |
343 | having found anything. */ | |
344 | if (__lstat (name, &st) >= 0 | |
345 | && st.st_dev == thisdev && st.st_ino == thisino) | |
28f540f4 RM |
346 | break; |
347 | } | |
348 | } | |
349 | if (d == NULL) | |
350 | { | |
351 | int save = errno; | |
23396375 | 352 | (void) __closedir (dirstream); |
f4017d20 UD |
353 | if (save == 0) |
354 | /* EOF on dirstream, which means that the current directory | |
355 | has been removed. */ | |
356 | save = ENOENT; | |
c4029823 | 357 | __set_errno (save); |
28f540f4 RM |
358 | goto lose; |
359 | } | |
360 | else | |
361 | { | |
92777700 RM |
362 | size_t namlen = _D_EXACT_NAMLEN (d); |
363 | ||
9a0a462c | 364 | if ((size_t) (pathp - path) <= namlen) |
28f540f4 | 365 | { |
a2b3aa73 | 366 | if (size != 0) |
28f540f4 | 367 | { |
7cc27f44 | 368 | (void) __closedir (dirstream); |
c4029823 | 369 | __set_errno (ERANGE); |
7cc27f44 | 370 | goto lose; |
28f540f4 RM |
371 | } |
372 | else | |
373 | { | |
8325d82c | 374 | char *tmp; |
1823e76b | 375 | size_t oldsize = allocated; |
8325d82c | 376 | |
1823e76b UD |
377 | allocated = 2 * MAX (allocated, namlen); |
378 | tmp = realloc (path, allocated); | |
8325d82c | 379 | if (tmp == NULL) |
28f540f4 | 380 | { |
23396375 | 381 | (void) __closedir (dirstream); |
c4029823 | 382 | __set_errno (ENOMEM);/* closedir might have changed it.*/ |
7cc27f44 | 383 | goto lose; |
28f540f4 | 384 | } |
1823e76b | 385 | |
8a523922 UD |
386 | /* Move current contents up to the end of the buffer. |
387 | This is guaranteed to be non-overlapping. */ | |
1823e76b UD |
388 | pathp = memcpy (tmp + allocated - (path + oldsize - pathp), |
389 | tmp + (pathp - path), | |
390 | path + oldsize - pathp); | |
391 | path = tmp; | |
28f540f4 RM |
392 | } |
393 | } | |
92777700 RM |
394 | pathp -= namlen; |
395 | (void) memcpy (pathp, d->d_name, namlen); | |
28f540f4 | 396 | *--pathp = '/'; |
23396375 | 397 | (void) __closedir (dirstream); |
28f540f4 RM |
398 | } |
399 | ||
400 | thisdev = dotdev; | |
401 | thisino = dotino; | |
402 | } | |
403 | ||
1823e76b | 404 | if (pathp == &path[allocated - 1]) |
28f540f4 RM |
405 | *--pathp = '/'; |
406 | ||
407 | if (dotlist != dots) | |
408 | free ((__ptr_t) dotlist); | |
409 | ||
1823e76b | 410 | memmove (path, pathp, path + allocated - pathp); |
f4017d20 UD |
411 | |
412 | /* Restore errno on successful return. */ | |
413 | __set_errno (prev_errno); | |
414 | ||
28f540f4 RM |
415 | return path; |
416 | ||
417 | lose: | |
418 | if (dotlist != dots) | |
419 | free ((__ptr_t) dotlist); | |
475e390e UD |
420 | lose2: |
421 | if (buf == NULL) | |
422 | free (path); | |
28f540f4 RM |
423 | return NULL; |
424 | } | |
3ec41e03 | 425 | |
fe0ec73e | 426 | #if defined _LIBC && !defined __getcwd |
3ec41e03 RM |
427 | weak_alias (__getcwd, getcwd) |
428 | #endif |