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