Remove redundant arguments in reduce_and_compute
[glibc.git] / sysdeps / posix / getcwd.c
blob0b5e32fb8209a54fcb14faa993e5e918ebd559ea
1 /* Copyright (C) 1991-2013 Free Software Foundation, Inc.
2 This file is part of the GNU C Library.
4 The GNU C Library is free software; you can redistribute it and/or
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.
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
12 Lesser General Public License for more details.
14 You should have received a copy of the GNU Lesser General Public
15 License along with the GNU C Library; if not, see
16 <http://www.gnu.org/licenses/>. */
18 /* Wants:
19 AC_STDC_HEADERS
20 AC_DIR_HEADER
21 AC_UNISTD_H
22 AC_MEMORY_H
23 AC_CONST
24 AC_ALLOCA
27 /* AIX requires this to be the first thing in the file. */
28 #if defined _AIX && !defined __GNUC__
29 #pragma alloca
30 #endif
32 #ifdef HAVE_CONFIG_H
33 # include "config.h"
34 #endif
36 #include <errno.h>
37 #include <fcntl.h>
38 #include <sys/types.h>
39 #include <sys/stat.h>
41 #ifdef STDC_HEADERS
42 # include <stddef.h>
43 #endif
45 #if !defined __GNU_LIBRARY__ && !defined STDC_HEADERS
46 extern int errno;
47 #endif
48 #ifndef __set_errno
49 # define __set_errno(val) errno = (val)
50 #endif
52 #ifndef NULL
53 # define NULL 0
54 #endif
56 #if defined USGr3 && !defined DIRENT
57 # define DIRENT
58 #endif /* USGr3 */
59 #if defined Xenix && !defined SYSNDIR
60 # define SYSNDIR
61 #endif /* Xenix */
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
71 #else /* not POSIX or DIRENT */
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 */
84 #endif /* POSIX or DIRENT or __GNU_LIBRARY__ */
86 #if defined HAVE_UNISTD_H || defined __GNU_LIBRARY__
87 # include <unistd.h>
88 #endif
90 #if defined STDC_HEADERS || defined __GNU_LIBRARY__ || defined POSIX
91 # include <stdlib.h>
92 # include <string.h>
93 # define ANSI_STRING
94 #else /* No standard headers. */
96 # ifdef USG
98 # include <string.h>
99 # ifdef NEED_MEMORY_H
100 # include <memory.h>
101 # endif
102 # define ANSI_STRING
104 # else /* Not USG. */
106 # ifdef NeXT
108 # include <string.h>
110 # else /* Not NeXT. */
112 # include <strings.h>
114 # ifndef bcmp
115 extern int bcmp ();
116 # endif
117 # ifndef bzero
118 extern void bzero ();
119 # endif
120 # ifndef bcopy
121 extern void bcopy ();
122 # endif
124 # endif /* NeXT. */
126 # endif /* USG. */
128 extern char *malloc (), *realloc ();
129 extern void free ();
131 #endif /* Standard headers. */
133 #ifndef ANSI_STRING
134 # define memcpy(d, s, n) bcopy((s), (d), (n))
135 # define memmove memcpy
136 #endif /* Not ANSI_STRING. */
138 #ifndef MAX
139 # define MAX(a, b) ((a) < (b) ? (b) : (a))
140 #endif
142 #ifdef _LIBC
143 # ifndef mempcpy
144 # define mempcpy __mempcpy
145 # endif
146 # define HAVE_MEMPCPY 1
147 #endif
149 #if !defined __alloca && !defined __GNU_LIBRARY__
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
159 extern char *alloca ();
160 # endif /* Not _AIX. */
161 # endif /* sparc or HAVE_ALLOCA_H. */
162 # endif /* GCC. */
164 # define __alloca alloca
166 #endif
168 #if defined HAVE_LIMITS_H || defined STDC_HEADERS || defined __GNU_LIBRARY__
169 # include <limits.h>
170 #else
171 # include <sys/param.h>
172 #endif
174 #if defined _LIBC
175 # include <not-cancel.h>
176 # include <kernel-features.h>
177 #else
178 # define openat64_not_cancel_3(dfd, name, mode) openat64 (dfd, name, mode)
179 # define close_not_cancel_no_status(fd) close (fd)
180 #endif
182 #ifndef PATH_MAX
183 # ifdef MAXPATHLEN
184 # define PATH_MAX MAXPATHLEN
185 # else
186 # define PATH_MAX 1024
187 # endif
188 #endif
190 #if !defined STDC_HEADERS && !defined __GNU_LIBRARY__
191 # undef size_t
192 # define size_t unsigned int
193 #endif
195 #ifndef __GNU_LIBRARY__
196 # define __lstat64 stat64
197 #endif
199 #ifndef _LIBC
200 # define __getcwd getcwd
201 #endif
203 #ifndef GETCWD_RETURN_TYPE
204 # define GETCWD_RETURN_TYPE char *
205 #endif
207 #ifdef __ASSUME_ATFCTS
208 # define __have_atfcts 1
209 #elif defined NOT_IN_libc && defined IS_IN_rtld
210 static int __rtld_have_atfcts;
211 # define __have_atfcts __rtld_have_atfcts
212 #endif
214 /* Get the pathname of the current working directory, and put it in SIZE
215 bytes of BUF. Returns NULL if the directory couldn't be determined or
216 SIZE was too small. If successful, returns BUF. In GNU, if BUF is
217 NULL, an array is allocated with `malloc'; the array is SIZE bytes long,
218 unless SIZE == 0, in which case it is as big as necessary. */
220 GETCWD_RETURN_TYPE
221 __getcwd (buf, size)
222 char *buf;
223 size_t size;
225 #ifndef __ASSUME_ATFCTS
226 static const char dots[]
227 = "../../../../../../../../../../../../../../../../../../../../../../../\
228 ../../../../../../../../../../../../../../../../../../../../../../../../../../\
229 ../../../../../../../../../../../../../../../../../../../../../../../../../..";
230 const char *dotp = &dots[sizeof (dots)];
231 const char *dotlist = dots;
232 size_t dotsize = sizeof (dots) - 1;
233 #endif
234 int prev_errno = errno;
235 DIR *dirstream = NULL;
236 bool fd_needs_closing = false;
237 int fd = AT_FDCWD;
239 char *path;
240 #ifndef NO_ALLOCATION
241 size_t allocated = size;
242 if (size == 0)
244 if (buf != NULL)
246 __set_errno (EINVAL);
247 return NULL;
250 allocated = PATH_MAX + 1;
253 if (buf == NULL)
255 path = malloc (allocated);
256 if (path == NULL)
257 return NULL;
259 else
260 #else
261 # define allocated size
262 #endif
263 path = buf;
265 char *pathp = path + allocated;
266 *--pathp = '\0';
268 struct stat64 st;
269 if (__lstat64 (".", &st) < 0)
270 goto lose;
271 dev_t thisdev = st.st_dev;
272 ino_t thisino = st.st_ino;
274 if (__lstat64 ("/", &st) < 0)
275 goto lose;
276 dev_t rootdev = st.st_dev;
277 ino_t rootino = st.st_ino;
279 while (!(thisdev == rootdev && thisino == rootino))
281 if (__have_atfcts >= 0)
283 int mode = O_RDONLY;
284 #ifdef O_CLOEXEC
285 mode |= O_CLOEXEC;
286 #endif
287 fd = openat64_not_cancel_3 (fd, "..", mode);
289 else
290 fd = -1;
291 if (fd >= 0)
293 fd_needs_closing = true;
294 if (__fstat64 (fd, &st) < 0)
295 goto lose;
297 #ifndef __ASSUME_ATFCTS
298 else if (errno == ENOSYS)
300 __have_atfcts = -1;
302 /* Look at the parent directory. */
303 if (dotp == dotlist)
305 # ifdef NO_ALLOCATION
306 __set_errno (ENOMEM);
307 goto lose;
308 # else
309 /* My, what a deep directory tree you have, Grandma. */
310 char *new;
311 if (dotlist == dots)
313 new = malloc (dotsize * 2 + 1);
314 if (new == NULL)
315 goto lose;
316 # ifdef HAVE_MEMPCPY
317 dotp = mempcpy (new, dots, dotsize);
318 # else
319 memcpy (new, dots, dotsize);
320 dotp = &new[dotsize];
321 # endif
323 else
325 new = realloc ((__ptr_t) dotlist, dotsize * 2 + 1);
326 if (new == NULL)
327 goto lose;
328 dotp = &new[dotsize];
330 # ifdef HAVE_MEMPCPY
331 *((char *) mempcpy ((char *) dotp, new, dotsize)) = '\0';
332 dotsize *= 2;
333 # else
334 memcpy ((char *) dotp, new, dotsize);
335 dotsize *= 2;
336 new[dotsize] = '\0';
337 # endif
338 dotlist = new;
339 # endif
342 dotp -= 3;
344 /* Figure out if this directory is a mount point. */
345 if (__lstat64 (dotp, &st) < 0)
346 goto lose;
348 #endif
349 else
350 goto lose;
352 if (dirstream && __closedir (dirstream) != 0)
354 dirstream = NULL;
355 goto lose;
358 dev_t dotdev = st.st_dev;
359 ino_t dotino = st.st_ino;
360 bool mount_point = dotdev != thisdev;
362 /* Search for the last directory. */
363 if (__have_atfcts >= 0)
364 dirstream = __fdopendir (fd);
365 #ifndef __ASSUME_ATFCTS
366 else
367 dirstream = __opendir (dotp);
368 #endif
369 if (dirstream == NULL)
370 goto lose;
371 fd_needs_closing = false;
373 struct dirent *d;
374 bool use_d_ino = true;
375 while (1)
377 /* Clear errno to distinguish EOF from error if readdir returns
378 NULL. */
379 __set_errno (0);
380 d = __readdir (dirstream);
381 if (d == NULL)
383 if (errno == 0)
385 /* When we've iterated through all directory entries
386 without finding one with a matching d_ino, rewind the
387 stream and consider each name again, but this time, using
388 lstat64. This is necessary in a chroot on at least one
389 system. */
390 if (use_d_ino)
392 use_d_ino = false;
393 rewinddir (dirstream);
394 continue;
397 /* EOF on dirstream, which means that the current directory
398 has been removed. */
399 __set_errno (ENOENT);
401 goto lose;
404 #ifdef _DIRENT_HAVE_D_TYPE
405 if (d->d_type != DT_DIR && d->d_type != DT_UNKNOWN)
406 continue;
407 #endif
408 if (d->d_name[0] == '.'
409 && (d->d_name[1] == '\0'
410 || (d->d_name[1] == '.' && d->d_name[2] == '\0')))
411 continue;
412 if (use_d_ino && !mount_point && (ino_t) d->d_ino != thisino)
413 continue;
415 if (__have_atfcts >= 0)
417 /* We don't fail here if we cannot stat64() a directory entry.
418 This can happen when (network) filesystems fail. If this
419 entry is in fact the one we are looking for we will find
420 out soon as we reach the end of the directory without
421 having found anything. */
422 if (__fstatat64 (fd, d->d_name, &st, AT_SYMLINK_NOFOLLOW) < 0)
423 continue;
425 #ifndef __ASSUME_ATFCTS
426 else
428 char name[dotlist + dotsize - dotp + 1 + _D_ALLOC_NAMLEN (d)];
429 # ifdef HAVE_MEMPCPY
430 char *tmp = mempcpy (name, dotp, dotlist + dotsize - dotp);
431 *tmp++ = '/';
432 strcpy (tmp, d->d_name);
433 # else
434 memcpy (name, dotp, dotlist + dotsize - dotp);
435 name[dotlist + dotsize - dotp] = '/';
436 strcpy (&name[dotlist + dotsize - dotp + 1], d->d_name);
437 # endif
438 /* We don't fail here if we cannot stat64() a directory entry.
439 This can happen when (network) filesystems fail. If this
440 entry is in fact the one we are looking for we will find
441 out soon as we reach the end of the directory without
442 having found anything. */
443 if (__lstat64 (name, &st) < 0)
444 continue;
446 #endif
447 if (S_ISDIR (st.st_mode)
448 && st.st_dev == thisdev && st.st_ino == thisino)
449 break;
452 size_t namlen = _D_EXACT_NAMLEN (d);
454 if ((size_t) (pathp - path) <= namlen)
456 #ifndef NO_ALLOCATION
457 if (size == 0)
459 size_t oldsize = allocated;
461 allocated = 2 * MAX (allocated, namlen);
462 char *tmp = realloc (path, allocated);
463 if (tmp == NULL)
464 goto lose;
466 /* Move current contents up to the end of the buffer.
467 This is guaranteed to be non-overlapping. */
468 pathp = memcpy (tmp + allocated - (path + oldsize - pathp),
469 tmp + (pathp - path),
470 path + oldsize - pathp);
471 path = tmp;
473 else
474 #endif
476 __set_errno (ERANGE);
477 goto lose;
480 pathp -= namlen;
481 (void) memcpy (pathp, d->d_name, namlen);
482 *--pathp = '/';
484 thisdev = dotdev;
485 thisino = dotino;
488 if (dirstream != NULL && __closedir (dirstream) != 0)
490 dirstream = NULL;
491 goto lose;
494 if (pathp == &path[allocated - 1])
495 *--pathp = '/';
497 #ifndef __ASSUME_ATFCTS
498 if (dotlist != dots)
499 free ((__ptr_t) dotlist);
500 #endif
502 size_t used = path + allocated - pathp;
503 memmove (path, pathp, used);
505 if (size == 0)
506 /* Ensure that the buffer is only as large as necessary. */
507 buf = realloc (path, used);
509 if (buf == NULL)
510 /* Either buf was NULL all along, or `realloc' failed but
511 we still have the original string. */
512 buf = path;
514 /* Restore errno on successful return. */
515 __set_errno (prev_errno);
517 return buf;
519 lose:;
520 int save_errno = errno;
521 #ifndef __ASSUME_ATFCTS
522 if (dotlist != dots)
523 free ((__ptr_t) dotlist);
524 #endif
525 if (dirstream != NULL)
526 __closedir (dirstream);
527 if (fd_needs_closing)
528 close_not_cancel_no_status (fd);
529 #ifndef NO_ALLOCATION
530 if (buf == NULL)
531 free (path);
532 #endif
533 __set_errno (save_errno);
534 return NULL;
537 #if defined _LIBC && !defined __getcwd
538 weak_alias (__getcwd, getcwd)
539 #endif