getcwd: fix test failures on mingw
[gnulib.git] / lib / getcwd.c
1 /* Copyright (C) 1991-1999, 2004-2011 Free Software Foundation, Inc.
2    This file is part of the GNU C Library.
3
4    This program is free software: you can redistribute it and/or modify
5    it under the terms of the GNU General Public License as published by
6    the Free Software Foundation; either version 3 of the License, or
7    (at your option) any later version.
8
9    This program 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
12    GNU General Public License for more details.
13
14    You should have received a copy of the GNU General Public License
15    along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
16
17 #if !_LIBC
18 # include <config.h>
19 # include <unistd.h>
20 #endif
21
22 #include <errno.h>
23 #include <sys/types.h>
24 #include <sys/stat.h>
25 #include <stdbool.h>
26 #include <stddef.h>
27
28 #include <fcntl.h> /* For AT_FDCWD on Solaris 9.  */
29
30 /* If this host provides the openat function, then enable
31    code below to make getcwd more efficient and robust.  */
32 #ifdef HAVE_OPENAT
33 # define HAVE_OPENAT_SUPPORT 1
34 #else
35 # define HAVE_OPENAT_SUPPORT 0
36 #endif
37
38 #ifndef __set_errno
39 # define __set_errno(val) (errno = (val))
40 #endif
41
42 #include <dirent.h>
43 #ifndef _D_EXACT_NAMLEN
44 # define _D_EXACT_NAMLEN(d) strlen ((d)->d_name)
45 #endif
46 #ifndef _D_ALLOC_NAMLEN
47 # define _D_ALLOC_NAMLEN(d) (_D_EXACT_NAMLEN (d) + 1)
48 #endif
49
50 #include <unistd.h>
51 #include <stdlib.h>
52 #include <string.h>
53
54 #if _LIBC
55 # ifndef mempcpy
56 #  define mempcpy __mempcpy
57 # endif
58 #endif
59
60 #ifndef MAX
61 # define MAX(a, b) ((a) < (b) ? (b) : (a))
62 #endif
63 #ifndef MIN
64 # define MIN(a, b) ((a) < (b) ? (a) : (b))
65 #endif
66
67 #include "pathmax.h"
68
69 /* In this file, PATH_MAX only serves as a threshold for choosing among two
70    algorithms.  */
71 #ifndef PATH_MAX
72 # define PATH_MAX 8192
73 #endif
74
75 #if D_INO_IN_DIRENT
76 # define MATCHING_INO(dp, ino) ((dp)->d_ino == (ino))
77 #else
78 # define MATCHING_INO(dp, ino) true
79 #endif
80
81 #if !_LIBC
82 # define __getcwd rpl_getcwd
83 # define __lstat lstat
84 # define __closedir closedir
85 # define __opendir opendir
86 # define __readdir readdir
87 #endif
88
89 /* The results of opendir() in this file are not used with dirfd and fchdir,
90    and we do not leak fds to any single-threaded code that could use stdio,
91    therefore save some unnecessary recursion in fchdir.c.
92    FIXME - if the kernel ever adds support for multi-thread safety for
93    avoiding standard fds, then we should use opendir_safer and
94    openat_safer.  */
95 #undef opendir
96 #undef closedir
97 \f
98 /* Get the name of the current working directory, and put it in SIZE
99    bytes of BUF.  Returns NULL if the directory couldn't be determined or
100    SIZE was too small.  If successful, returns BUF.  In GNU, if BUF is
101    NULL, an array is allocated with `malloc'; the array is SIZE bytes long,
102    unless SIZE == 0, in which case it is as big as necessary.  */
103
104 char *
105 __getcwd (char *buf, size_t size)
106 {
107   /* Lengths of big file name components and entire file names, and a
108      deep level of file name nesting.  These numbers are not upper
109      bounds; they are merely large values suitable for initial
110      allocations, designed to be large enough for most real-world
111      uses.  */
112   enum
113     {
114       BIG_FILE_NAME_COMPONENT_LENGTH = 255,
115       BIG_FILE_NAME_LENGTH = MIN (4095, PATH_MAX - 1),
116       DEEP_NESTING = 100
117     };
118
119 #if HAVE_OPENAT_SUPPORT
120   int fd = AT_FDCWD;
121   bool fd_needs_closing = false;
122 #else
123   char dots[DEEP_NESTING * sizeof ".." + BIG_FILE_NAME_COMPONENT_LENGTH + 1];
124   char *dotlist = dots;
125   size_t dotsize = sizeof dots;
126   size_t dotlen = 0;
127 #endif
128   DIR *dirstream = NULL;
129   dev_t rootdev, thisdev;
130   ino_t rootino, thisino;
131   char *dir;
132   register char *dirp;
133   struct stat st;
134   size_t allocated = size;
135   size_t used;
136
137 #if HAVE_RAW_DECL_GETCWD
138   /* If AT_FDCWD is not defined, the algorithm below is O(N**2) and
139      this is much slower than the system getcwd (at least on
140      GNU/Linux).  So trust the system getcwd's results unless they
141      look suspicious.
142
143      Use the system getcwd even if we have openat support, since the
144      system getcwd works even when a parent is unreadable, while the
145      openat-based approach does not.  */
146
147 # undef getcwd
148   dir = getcwd (buf, size);
149   if (dir || (size && errno == ERANGE))
150     return dir;
151
152   /* Solaris getcwd (NULL, 0) fails with errno == EINVAL, but it has
153      internal magic that lets it work even if an ancestor directory is
154      inaccessible, which is better in many cases.  So in this case try
155      again with a buffer that's almost always big enough.  */
156   if (errno == EINVAL && buf == NULL && size == 0)
157     {
158       char big_buffer[BIG_FILE_NAME_LENGTH + 1];
159       dir = getcwd (big_buffer, sizeof big_buffer);
160       if (dir)
161         return strdup (dir);
162     }
163
164 # if HAVE_PARTLY_WORKING_GETCWD
165   /* The system getcwd works, except it sometimes fails when it
166      shouldn't, setting errno to ERANGE, ENAMETOOLONG, or ENOENT.    */
167   if (errno != ERANGE && errno != ENAMETOOLONG && errno != ENOENT)
168     return NULL;
169 # endif
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 #if HAVE_OPENAT_SUPPORT
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 #if HAVE_OPENAT_SUPPORT
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 #if HAVE_OPENAT_SUPPORT
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 #if ! HAVE_OPENAT_SUPPORT
395   if (dotlist != dots)
396     free (dotlist);
397 #endif
398
399   used = dir + allocated - dirp;
400   memmove (dir, dirp, used);
401
402   if (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 #if HAVE_OPENAT_SUPPORT
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