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