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