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