]> git.ipfire.org Git - thirdparty/glibc.git/blame - sysdeps/posix/getcwd.c
Update copyright dates with scripts/update-copyrights.
[thirdparty/glibc.git] / sysdeps / posix / getcwd.c
CommitLineData
b168057a 1/* Copyright (C) 1991-2015 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 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/* Wants:
19 AC_STDC_HEADERS
20 AC_DIR_HEADER
21 AC_UNISTD_H
22 AC_MEMORY_H
23 AC_CONST
24 AC_ALLOCA
25 */
26
27/* AIX requires this to be the first thing in the file. */
86187531 28#if defined _AIX && !defined __GNUC__
28f540f4
RM
29 #pragma alloca
30#endif
31
32#ifdef HAVE_CONFIG_H
86187531 33# include "config.h"
28f540f4
RM
34#endif
35
36#include <errno.h>
7fb90fb8 37#include <fcntl.h>
28f540f4
RM
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
46extern 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 115extern int bcmp ();
86187531
UD
116# endif
117# ifndef bzero
28f540f4 118extern void bzero ();
86187531
UD
119# endif
120# ifndef bcopy
28f540f4 121extern void bcopy ();
86187531 122# endif
28f540f4 123
86187531 124# endif /* NeXT. */
28f540f4 125
86187531 126# endif /* USG. */
28f540f4
RM
127
128extern char *malloc (), *realloc ();
129extern 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 159extern 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
6fb2dde3 174#if defined _LIBC
7fb90fb8 175# include <not-cancel.h>
37233df9 176# include <kernel-features.h>
7fb90fb8 177#else
6fb2dde3 178# define openat64_not_cancel_3(dfd, name, mode) openat64 (dfd, name, mode)
7fb90fb8
UD
179# define close_not_cancel_no_status(fd) close (fd)
180#endif
181
28f540f4 182#ifndef PATH_MAX
86187531
UD
183# ifdef MAXPATHLEN
184# define PATH_MAX MAXPATHLEN
185# else
186# define PATH_MAX 1024
187# endif
28f540f4
RM
188#endif
189
86187531
UD
190#if !defined STDC_HEADERS && !defined __GNU_LIBRARY__
191# undef size_t
192# define size_t unsigned int
28f540f4
RM
193#endif
194
28f540f4 195#ifndef __GNU_LIBRARY__
6fb2dde3 196# define __lstat64 stat64
28f540f4 197#endif
2f5c1b00
JM
198
199#ifndef _LIBC
200# define __rewinddir rewinddir
201#endif
28f540f4 202\f
7f811679 203#ifndef _LIBC
86187531 204# define __getcwd getcwd
7f811679
RM
205#endif
206
04be94a8
UD
207#ifndef GETCWD_RETURN_TYPE
208# define GETCWD_RETURN_TYPE char *
fe0ec73e
UD
209#endif
210
7fb90fb8 211#ifdef __ASSUME_ATFCTS
6fb2dde3 212# define __have_atfcts 1
a3848485 213#elif IS_IN (rtld)
6fb2dde3
UD
214static int __rtld_have_atfcts;
215# define __have_atfcts __rtld_have_atfcts
7fb90fb8
UD
216#endif
217
7f811679 218/* Get the pathname of the current working directory, and put it in SIZE
28f540f4
RM
219 bytes of BUF. Returns NULL if the directory couldn't be determined or
220 SIZE was too small. If successful, returns BUF. In GNU, if BUF is
221 NULL, an array is allocated with `malloc'; the array is SIZE bytes long,
a2b3aa73 222 unless SIZE == 0, in which case it is as big as necessary. */
28f540f4 223
04be94a8 224GETCWD_RETURN_TYPE
7f811679 225__getcwd (buf, size)
28f540f4
RM
226 char *buf;
227 size_t size;
228{
7fb90fb8 229#ifndef __ASSUME_ATFCTS
28f540f4
RM
230 static const char dots[]
231 = "../../../../../../../../../../../../../../../../../../../../../../../\
232../../../../../../../../../../../../../../../../../../../../../../../../../../\
233../../../../../../../../../../../../../../../../../../../../../../../../../..";
475e390e
UD
234 const char *dotp = &dots[sizeof (dots)];
235 const char *dotlist = dots;
236 size_t dotsize = sizeof (dots) - 1;
7fb90fb8 237#endif
f4017d20 238 int prev_errno = errno;
7fb90fb8
UD
239 DIR *dirstream = NULL;
240 bool fd_needs_closing = false;
241 int fd = AT_FDCWD;
28f540f4 242
7fb90fb8
UD
243 char *path;
244#ifndef NO_ALLOCATION
245 size_t allocated = size;
a2b3aa73 246 if (size == 0)
28f540f4
RM
247 {
248 if (buf != NULL)
249 {
c4029823 250 __set_errno (EINVAL);
28f540f4
RM
251 return NULL;
252 }
253
1823e76b 254 allocated = PATH_MAX + 1;
28f540f4
RM
255 }
256
7fb90fb8 257 if (buf == NULL)
28f540f4 258 {
1823e76b 259 path = malloc (allocated);
28f540f4
RM
260 if (path == NULL)
261 return NULL;
262 }
7fb90fb8
UD
263 else
264#else
265# define allocated size
266#endif
267 path = buf;
28f540f4 268
7fb90fb8 269 char *pathp = path + allocated;
28f540f4
RM
270 *--pathp = '\0';
271
6fb2dde3
UD
272 struct stat64 st;
273 if (__lstat64 (".", &st) < 0)
7fb90fb8
UD
274 goto lose;
275 dev_t thisdev = st.st_dev;
276 ino_t thisino = st.st_ino;
28f540f4 277
6fb2dde3 278 if (__lstat64 ("/", &st) < 0)
7fb90fb8
UD
279 goto lose;
280 dev_t rootdev = st.st_dev;
281 ino_t rootino = st.st_ino;
28f540f4 282
28f540f4
RM
283 while (!(thisdev == rootdev && thisino == rootino))
284 {
6fb2dde3 285 if (__have_atfcts >= 0)
28f540f4 286 {
7fb90fb8
UD
287 int mode = O_RDONLY;
288#ifdef O_CLOEXEC
289 mode |= O_CLOEXEC;
86187531 290#endif
6fb2dde3 291 fd = openat64_not_cancel_3 (fd, "..", mode);
7fb90fb8
UD
292 }
293 else
294 fd = -1;
295 if (fd >= 0)
296 {
297 fd_needs_closing = true;
6fb2dde3 298 if (__fstat64 (fd, &st) < 0)
7fb90fb8
UD
299 goto lose;
300 }
301#ifndef __ASSUME_ATFCTS
302 else if (errno == ENOSYS)
303 {
6fb2dde3 304 __have_atfcts = -1;
7fb90fb8
UD
305
306 /* Look at the parent directory. */
307 if (dotp == dotlist)
28f540f4 308 {
7fb90fb8
UD
309# ifdef NO_ALLOCATION
310 __set_errno (ENOMEM);
311 goto lose;
312# else
313 /* My, what a deep directory tree you have, Grandma. */
314 char *new;
315 if (dotlist == dots)
316 {
317 new = malloc (dotsize * 2 + 1);
318 if (new == NULL)
319 goto lose;
320# ifdef HAVE_MEMPCPY
321 dotp = mempcpy (new, dots, dotsize);
322# else
323 memcpy (new, dots, dotsize);
324 dotp = &new[dotsize];
325# endif
326 }
327 else
328 {
329 new = realloc ((__ptr_t) dotlist, dotsize * 2 + 1);
330 if (new == NULL)
331 goto lose;
332 dotp = &new[dotsize];
333 }
334# ifdef HAVE_MEMPCPY
335 *((char *) mempcpy ((char *) dotp, new, dotsize)) = '\0';
336 dotsize *= 2;
337# else
338 memcpy ((char *) dotp, new, dotsize);
339 dotsize *= 2;
340 new[dotsize] = '\0';
341# endif
342 dotlist = new;
343# endif
28f540f4 344 }
28f540f4 345
7fb90fb8 346 dotp -= 3;
28f540f4 347
7fb90fb8 348 /* Figure out if this directory is a mount point. */
6fb2dde3 349 if (__lstat64 (dotp, &st) < 0)
7fb90fb8
UD
350 goto lose;
351 }
352#endif
353 else
28f540f4 354 goto lose;
7fb90fb8
UD
355
356 if (dirstream && __closedir (dirstream) != 0)
357 {
358 dirstream = NULL;
359 goto lose;
360 }
361
362 dev_t dotdev = st.st_dev;
363 ino_t dotino = st.st_ino;
364 bool mount_point = dotdev != thisdev;
28f540f4
RM
365
366 /* Search for the last directory. */
6fb2dde3 367 if (__have_atfcts >= 0)
7fb90fb8
UD
368 dirstream = __fdopendir (fd);
369#ifndef __ASSUME_ATFCTS
370 else
371 dirstream = __opendir (dotp);
372#endif
28f540f4
RM
373 if (dirstream == NULL)
374 goto lose;
7fb90fb8
UD
375 fd_needs_closing = false;
376
377 struct dirent *d;
378 bool use_d_ino = true;
379 while (1)
28f540f4 380 {
7fb90fb8
UD
381 /* Clear errno to distinguish EOF from error if readdir returns
382 NULL. */
383 __set_errno (0);
384 d = __readdir (dirstream);
385 if (d == NULL)
386 {
387 if (errno == 0)
388 {
389 /* When we've iterated through all directory entries
390 without finding one with a matching d_ino, rewind the
391 stream and consider each name again, but this time, using
6fb2dde3 392 lstat64. This is necessary in a chroot on at least one
7fb90fb8
UD
393 system. */
394 if (use_d_ino)
395 {
396 use_d_ino = false;
2f5c1b00 397 __rewinddir (dirstream);
7fb90fb8
UD
398 continue;
399 }
400
401 /* EOF on dirstream, which means that the current directory
402 has been removed. */
403 __set_errno (ENOENT);
404 }
405 goto lose;
406 }
407
bea9b193 408#ifdef _DIRENT_HAVE_D_TYPE
7fb90fb8
UD
409 if (d->d_type != DT_DIR && d->d_type != DT_UNKNOWN)
410 continue;
bea9b193 411#endif
7fb90fb8
UD
412 if (d->d_name[0] == '.'
413 && (d->d_name[1] == '\0'
414 || (d->d_name[1] == '.' && d->d_name[2] == '\0')))
28f540f4 415 continue;
7fb90fb8
UD
416 if (use_d_ino && !mount_point && (ino_t) d->d_ino != thisino)
417 continue;
418
6fb2dde3 419 if (__have_atfcts >= 0)
7fb90fb8 420 {
6fb2dde3 421 /* We don't fail here if we cannot stat64() a directory entry.
7fb90fb8
UD
422 This can happen when (network) filesystems fail. If this
423 entry is in fact the one we are looking for we will find
424 out soon as we reach the end of the directory without
425 having found anything. */
6fb2dde3 426 if (__fstatat64 (fd, d->d_name, &st, AT_SYMLINK_NOFOLLOW) < 0)
7fb90fb8
UD
427 continue;
428 }
429#ifndef __ASSUME_ATFCTS
430 else
28f540f4 431 {
92777700 432 char name[dotlist + dotsize - dotp + 1 + _D_ALLOC_NAMLEN (d)];
7fb90fb8 433# ifdef HAVE_MEMPCPY
86187531
UD
434 char *tmp = mempcpy (name, dotp, dotlist + dotsize - dotp);
435 *tmp++ = '/';
436 strcpy (tmp, d->d_name);
7fb90fb8 437# else
28f540f4
RM
438 memcpy (name, dotp, dotlist + dotsize - dotp);
439 name[dotlist + dotsize - dotp] = '/';
92777700 440 strcpy (&name[dotlist + dotsize - dotp + 1], d->d_name);
7fb90fb8 441# endif
6fb2dde3 442 /* We don't fail here if we cannot stat64() a directory entry.
74f7e7c0
UD
443 This can happen when (network) filesystems fail. If this
444 entry is in fact the one we are looking for we will find
445 out soon as we reach the end of the directory without
446 having found anything. */
6fb2dde3 447 if (__lstat64 (name, &st) < 0)
7fb90fb8 448 continue;
28f540f4 449 }
7fb90fb8
UD
450#endif
451 if (S_ISDIR (st.st_mode)
452 && st.st_dev == thisdev && st.st_ino == thisino)
453 break;
28f540f4 454 }
92777700 455
7fb90fb8
UD
456 size_t namlen = _D_EXACT_NAMLEN (d);
457
458 if ((size_t) (pathp - path) <= namlen)
459 {
460#ifndef NO_ALLOCATION
461 if (size == 0)
28f540f4 462 {
7fb90fb8 463 size_t oldsize = allocated;
8325d82c 464
7fb90fb8
UD
465 allocated = 2 * MAX (allocated, namlen);
466 char *tmp = realloc (path, allocated);
467 if (tmp == NULL)
468 goto lose;
1823e76b 469
7fb90fb8
UD
470 /* Move current contents up to the end of the buffer.
471 This is guaranteed to be non-overlapping. */
472 pathp = memcpy (tmp + allocated - (path + oldsize - pathp),
473 tmp + (pathp - path),
474 path + oldsize - pathp);
475 path = tmp;
476 }
477 else
478#endif
479 {
480 __set_errno (ERANGE);
481 goto lose;
28f540f4 482 }
28f540f4 483 }
7fb90fb8
UD
484 pathp -= namlen;
485 (void) memcpy (pathp, d->d_name, namlen);
486 *--pathp = '/';
28f540f4
RM
487
488 thisdev = dotdev;
489 thisino = dotino;
490 }
491
7fb90fb8
UD
492 if (dirstream != NULL && __closedir (dirstream) != 0)
493 {
494 dirstream = NULL;
495 goto lose;
496 }
497
1823e76b 498 if (pathp == &path[allocated - 1])
28f540f4
RM
499 *--pathp = '/';
500
7fb90fb8 501#ifndef __ASSUME_ATFCTS
28f540f4
RM
502 if (dotlist != dots)
503 free ((__ptr_t) dotlist);
7fb90fb8 504#endif
28f540f4 505
7fb90fb8
UD
506 size_t used = path + allocated - pathp;
507 memmove (path, pathp, used);
508
509 if (size == 0)
510 /* Ensure that the buffer is only as large as necessary. */
511 buf = realloc (path, used);
512
513 if (buf == NULL)
514 /* Either buf was NULL all along, or `realloc' failed but
515 we still have the original string. */
516 buf = path;
f4017d20
UD
517
518 /* Restore errno on successful return. */
519 __set_errno (prev_errno);
520
7fb90fb8 521 return buf;
28f540f4 522
7fb90fb8
UD
523 lose:;
524 int save_errno = errno;
525#ifndef __ASSUME_ATFCTS
28f540f4
RM
526 if (dotlist != dots)
527 free ((__ptr_t) dotlist);
7fb90fb8
UD
528#endif
529 if (dirstream != NULL)
530 __closedir (dirstream);
531 if (fd_needs_closing)
532 close_not_cancel_no_status (fd);
533#ifndef NO_ALLOCATION
475e390e
UD
534 if (buf == NULL)
535 free (path);
7fb90fb8
UD
536#endif
537 __set_errno (save_errno);
28f540f4
RM
538 return NULL;
539}
3ec41e03 540
fe0ec73e 541#if defined _LIBC && !defined __getcwd
3ec41e03
RM
542weak_alias (__getcwd, getcwd)
543#endif