Import upstream version 1.27
[debian/tar] / gnu / getcwd.c
1 /* -*- buffer-read-only: t -*- vi: set ro: */
2 /* DO NOT EDIT! GENERATED AUTOMATICALLY! */
3 /* Copyright (C) 1991-1999, 2004-2013 Free Software Foundation, Inc.
4    This file is part of the GNU C Library.
5
6    This program is free software: you can redistribute it and/or modify
7    it under the terms of the GNU General Public License as published by
8    the Free Software Foundation; either version 3 of the License, or
9    (at your option) any later version.
10
11    This program is distributed in the hope that it will be useful,
12    but WITHOUT ANY WARRANTY; without even the implied warranty of
13    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14    GNU General Public License for more details.
15
16    You should have received a copy of the GNU General Public License
17    along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
18
19 #if !_LIBC
20 # include <config.h>
21 # include <unistd.h>
22 #endif
23
24 #include <errno.h>
25 #include <sys/types.h>
26 #include <sys/stat.h>
27 #include <stdbool.h>
28 #include <stddef.h>
29
30 #include <fcntl.h> /* For AT_FDCWD on Solaris 9.  */
31
32 /* If this host provides the openat function or if we're using the
33    gnulib replacement function with a native fdopendir, then enable
34    code below to make getcwd more efficient and robust.  */
35 #if defined HAVE_OPENAT || (defined GNULIB_OPENAT && defined HAVE_FDOPENDIR)
36 # define HAVE_OPENAT_SUPPORT 1
37 #else
38 # define HAVE_OPENAT_SUPPORT 0
39 #endif
40
41 #ifndef __set_errno
42 # define __set_errno(val) (errno = (val))
43 #endif
44
45 #include <dirent.h>
46 #ifndef _D_EXACT_NAMLEN
47 # define _D_EXACT_NAMLEN(d) strlen ((d)->d_name)
48 #endif
49 #ifndef _D_ALLOC_NAMLEN
50 # define _D_ALLOC_NAMLEN(d) (_D_EXACT_NAMLEN (d) + 1)
51 #endif
52
53 #include <unistd.h>
54 #include <stdlib.h>
55 #include <string.h>
56
57 #if _LIBC
58 # ifndef mempcpy
59 #  define mempcpy __mempcpy
60 # endif
61 #endif
62
63 #ifndef MAX
64 # define MAX(a, b) ((a) < (b) ? (b) : (a))
65 #endif
66 #ifndef MIN
67 # define MIN(a, b) ((a) < (b) ? (a) : (b))
68 #endif
69
70 #include "pathmax.h"
71
72 /* In this file, PATH_MAX only serves as a threshold for choosing among two
73    algorithms.  */
74 #ifndef PATH_MAX
75 # define PATH_MAX 8192
76 #endif
77
78 #if D_INO_IN_DIRENT
79 # define MATCHING_INO(dp, ino) ((dp)->d_ino == (ino))
80 #else
81 # define MATCHING_INO(dp, ino) true
82 #endif
83
84 #if !_LIBC
85 # define __getcwd rpl_getcwd
86 # define __lstat lstat
87 # define __closedir closedir
88 # define __opendir opendir
89 # define __readdir readdir
90 #endif
91
92 /* The results of opendir() in this file are not used with dirfd and fchdir,
93    and we do not leak fds to any single-threaded code that could use stdio,
94    therefore save some unnecessary recursion in fchdir.c.
95    FIXME - if the kernel ever adds support for multi-thread safety for
96    avoiding standard fds, then we should use opendir_safer and
97    openat_safer.  */
98 #undef opendir
99 #undef closedir
100 \f
101 /* Get the name of the current working directory, and put it in SIZE
102    bytes of BUF.  Returns NULL if the directory couldn't be determined or
103    SIZE was too small.  If successful, returns BUF.  In GNU, if BUF is
104    NULL, an array is allocated with 'malloc'; the array is SIZE bytes long,
105    unless SIZE == 0, in which case it is as big as necessary.  */
106
107 char *
108 __getcwd (char *buf, size_t size)
109 {
110   /* Lengths of big file name components and entire file names, and a
111      deep level of file name nesting.  These numbers are not upper
112      bounds; they are merely large values suitable for initial
113      allocations, designed to be large enough for most real-world
114      uses.  */
115   enum
116     {
117       BIG_FILE_NAME_COMPONENT_LENGTH = 255,
118       BIG_FILE_NAME_LENGTH = MIN (4095, PATH_MAX - 1),
119       DEEP_NESTING = 100
120     };
121
122 #if HAVE_OPENAT_SUPPORT
123   int fd = AT_FDCWD;
124   bool fd_needs_closing = false;
125 #else
126   char dots[DEEP_NESTING * sizeof ".." + BIG_FILE_NAME_COMPONENT_LENGTH + 1];
127   char *dotlist = dots;
128   size_t dotsize = sizeof dots;
129   size_t dotlen = 0;
130 #endif
131   DIR *dirstream = NULL;
132   dev_t rootdev, thisdev;
133   ino_t rootino, thisino;
134   char *dir;
135   register char *dirp;
136   struct stat st;
137   size_t allocated = size;
138   size_t used;
139
140 #if HAVE_MINIMALLY_WORKING_GETCWD
141   /* If AT_FDCWD is not defined, the algorithm below is O(N**2) and
142      this is much slower than the system getcwd (at least on
143      GNU/Linux).  So trust the system getcwd's results unless they
144      look suspicious.
145
146      Use the system getcwd even if we have openat support, since the
147      system getcwd works even when a parent is unreadable, while the
148      openat-based approach does not.
149
150      But on AIX 5.1..7.1, the system getcwd is not even minimally
151      working: If the current directory name is slightly longer than
152      PATH_MAX, it omits the first directory component and returns
153      this wrong result with errno = 0.  */
154
155 # undef getcwd
156   dir = getcwd (buf, size);
157   if (dir || (size && errno == ERANGE))
158     return dir;
159
160   /* Solaris getcwd (NULL, 0) fails with errno == EINVAL, but it has
161      internal magic that lets it work even if an ancestor directory is
162      inaccessible, which is better in many cases.  So in this case try
163      again with a buffer that's almost always big enough.  */
164   if (errno == EINVAL && buf == NULL && size == 0)
165     {
166       char big_buffer[BIG_FILE_NAME_LENGTH + 1];
167       dir = getcwd (big_buffer, sizeof big_buffer);
168       if (dir)
169         return strdup (dir);
170     }
171
172 # if HAVE_PARTLY_WORKING_GETCWD
173   /* The system getcwd works, except it sometimes fails when it
174      shouldn't, setting errno to ERANGE, ENAMETOOLONG, or ENOENT.    */
175   if (errno != ERANGE && errno != ENAMETOOLONG && errno != ENOENT)
176     return NULL;
177 # endif
178 #endif
179
180   if (size == 0)
181     {
182       if (buf != NULL)
183         {
184           __set_errno (EINVAL);
185           return NULL;
186         }
187
188       allocated = BIG_FILE_NAME_LENGTH + 1;
189     }
190
191   if (buf == NULL)
192     {
193       dir = malloc (allocated);
194       if (dir == NULL)
195         return NULL;
196     }
197   else
198     dir = buf;
199
200   dirp = dir + allocated;
201   *--dirp = '\0';
202
203   if (__lstat (".", &st) < 0)
204     goto lose;
205   thisdev = st.st_dev;
206   thisino = st.st_ino;
207
208   if (__lstat ("/", &st) < 0)
209     goto lose;
210   rootdev = st.st_dev;
211   rootino = st.st_ino;
212
213   while (!(thisdev == rootdev && thisino == rootino))
214     {
215       struct dirent *d;
216       dev_t dotdev;
217       ino_t dotino;
218       bool mount_point;
219       int parent_status;
220       size_t dirroom;
221       size_t namlen;
222       bool use_d_ino = true;
223
224       /* Look at the parent directory.  */
225 #if HAVE_OPENAT_SUPPORT
226       fd = openat (fd, "..", O_RDONLY);
227       if (fd < 0)
228         goto lose;
229       fd_needs_closing = true;
230       parent_status = fstat (fd, &st);
231 #else
232       dotlist[dotlen++] = '.';
233       dotlist[dotlen++] = '.';
234       dotlist[dotlen] = '\0';
235       parent_status = __lstat (dotlist, &st);
236 #endif
237       if (parent_status != 0)
238         goto lose;
239
240       if (dirstream && __closedir (dirstream) != 0)
241         {
242           dirstream = NULL;
243           goto lose;
244         }
245
246       /* Figure out if this directory is a mount point.  */
247       dotdev = st.st_dev;
248       dotino = st.st_ino;
249       mount_point = dotdev != thisdev;
250
251       /* Search for the last directory.  */
252 #if HAVE_OPENAT_SUPPORT
253       dirstream = fdopendir (fd);
254       if (dirstream == NULL)
255         goto lose;
256       fd_needs_closing = false;
257 #else
258       dirstream = __opendir (dotlist);
259       if (dirstream == NULL)
260         goto lose;
261       dotlist[dotlen++] = '/';
262 #endif
263       for (;;)
264         {
265           /* Clear errno to distinguish EOF from error if readdir returns
266              NULL.  */
267           __set_errno (0);
268           d = __readdir (dirstream);
269
270           /* When we've iterated through all directory entries without finding
271              one with a matching d_ino, rewind the stream and consider each
272              name again, but this time, using lstat.  This is necessary in a
273              chroot on at least one system (glibc-2.3.6 + linux 2.6.12), where
274              .., ../.., ../../.., etc. all had the same device number, yet the
275              d_ino values for entries in / did not match those obtained
276              via lstat.  */
277           if (d == NULL && errno == 0 && use_d_ino)
278             {
279               use_d_ino = false;
280               rewinddir (dirstream);
281               d = __readdir (dirstream);
282             }
283
284           if (d == NULL)
285             {
286               if (errno == 0)
287                 /* EOF on dirstream, which can mean e.g., that the current
288                    directory has been removed.  */
289                 __set_errno (ENOENT);
290               goto lose;
291             }
292           if (d->d_name[0] == '.' &&
293               (d->d_name[1] == '\0' ||
294                (d->d_name[1] == '.' && d->d_name[2] == '\0')))
295             continue;
296
297           if (use_d_ino)
298             {
299               bool match = (MATCHING_INO (d, thisino) || mount_point);
300               if (! match)
301                 continue;
302             }
303
304           {
305             int entry_status;
306 #if HAVE_OPENAT_SUPPORT
307             entry_status = fstatat (fd, d->d_name, &st, AT_SYMLINK_NOFOLLOW);
308 #else
309             /* Compute size needed for this file name, or for the file
310                name ".." in the same directory, whichever is larger.
311                Room for ".." might be needed the next time through
312                the outer loop.  */
313             size_t name_alloc = _D_ALLOC_NAMLEN (d);
314             size_t filesize = dotlen + MAX (sizeof "..", name_alloc);
315
316             if (filesize < dotlen)
317               goto memory_exhausted;
318
319             if (dotsize < filesize)
320               {
321                 /* My, what a deep directory tree you have, Grandma.  */
322                 size_t newsize = MAX (filesize, dotsize * 2);
323                 size_t i;
324                 if (newsize < dotsize)
325                   goto memory_exhausted;
326                 if (dotlist != dots)
327                   free (dotlist);
328                 dotlist = malloc (newsize);
329                 if (dotlist == NULL)
330                   goto lose;
331                 dotsize = newsize;
332
333                 i = 0;
334                 do
335                   {
336                     dotlist[i++] = '.';
337                     dotlist[i++] = '.';
338                     dotlist[i++] = '/';
339                   }
340                 while (i < dotlen);
341               }
342
343             memcpy (dotlist + dotlen, d->d_name, _D_ALLOC_NAMLEN (d));
344             entry_status = __lstat (dotlist, &st);
345 #endif
346             /* We don't fail here if we cannot stat() a directory entry.
347                This can happen when (network) file systems fail.  If this
348                entry is in fact the one we are looking for we will find
349                out soon as we reach the end of the directory without
350                having found anything.  */
351             if (entry_status == 0 && S_ISDIR (st.st_mode)
352                 && st.st_dev == thisdev && st.st_ino == thisino)
353               break;
354           }
355         }
356
357       dirroom = dirp - dir;
358       namlen = _D_EXACT_NAMLEN (d);
359
360       if (dirroom <= namlen)
361         {
362           if (size != 0)
363             {
364               __set_errno (ERANGE);
365               goto lose;
366             }
367           else
368             {
369               char *tmp;
370               size_t oldsize = allocated;
371
372               allocated += MAX (allocated, namlen);
373               if (allocated < oldsize
374                   || ! (tmp = realloc (dir, allocated)))
375                 goto memory_exhausted;
376
377               /* Move current contents up to the end of the buffer.
378                  This is guaranteed to be non-overlapping.  */
379               dirp = memcpy (tmp + allocated - (oldsize - dirroom),
380                              tmp + dirroom,
381                              oldsize - dirroom);
382               dir = tmp;
383             }
384         }
385       dirp -= namlen;
386       memcpy (dirp, d->d_name, namlen);
387       *--dirp = '/';
388
389       thisdev = dotdev;
390       thisino = dotino;
391     }
392
393   if (dirstream && __closedir (dirstream) != 0)
394     {
395       dirstream = NULL;
396       goto lose;
397     }
398
399   if (dirp == &dir[allocated - 1])
400     *--dirp = '/';
401
402 #if ! HAVE_OPENAT_SUPPORT
403   if (dotlist != dots)
404     free (dotlist);
405 #endif
406
407   used = dir + allocated - dirp;
408   memmove (dir, dirp, used);
409
410   if (size == 0)
411     /* Ensure that the buffer is only as large as necessary.  */
412     buf = realloc (dir, used);
413
414   if (buf == NULL)
415     /* Either buf was NULL all along, or 'realloc' failed but
416        we still have the original string.  */
417     buf = dir;
418
419   return buf;
420
421  memory_exhausted:
422   __set_errno (ENOMEM);
423  lose:
424   {
425     int save = errno;
426     if (dirstream)
427       __closedir (dirstream);
428 #if HAVE_OPENAT_SUPPORT
429     if (fd_needs_closing)
430       close (fd);
431 #else
432     if (dotlist != dots)
433       free (dotlist);
434 #endif
435     if (buf == NULL)
436       free (dir);
437     __set_errno (save);
438   }
439   return NULL;
440 }
441
442 #ifdef weak_alias
443 weak_alias (__getcwd, getcwd)
444 #endif