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