chiark / gitweb /
eglibc (2.11.3-4+deb6u3) squeeze-lts; urgency=medium
[eglibc.git] / sysdeps / posix / getcwd.c
1 /* Copyright (C) 1991,92,93,94,95,96,97,98,99 Free Software Foundation, Inc.
2    This file is part of the GNU C Library.
3
4    The GNU C Library is free software; you can redistribute it and/or
5    modify it under the terms of the GNU Lesser General Public
6    License as published by the Free Software Foundation; either
7    version 2.1 of the License, or (at your option) any later version.
8
9    The GNU C Library 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 GNU
12    Lesser General Public License for more details.
13
14    You should have received a copy of the GNU Lesser General Public
15    License along with the GNU C Library; if not, write to the Free
16    Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
17    02111-1307 USA.  */
18
19 /* Wants:
20    AC_STDC_HEADERS
21    AC_DIR_HEADER
22    AC_UNISTD_H
23    AC_MEMORY_H
24    AC_CONST
25    AC_ALLOCA
26  */
27
28 /* AIX requires this to be the first thing in the file.  */
29 #if defined _AIX && !defined __GNUC__
30  #pragma alloca
31 #endif
32
33 #ifdef  HAVE_CONFIG_H
34 # include "config.h"
35 #endif
36
37 #include <errno.h>
38 #include <sys/types.h>
39 #include <sys/stat.h>
40
41 #ifdef  STDC_HEADERS
42 # include <stddef.h>
43 #endif
44
45 #if !defined __GNU_LIBRARY__ && !defined STDC_HEADERS
46 extern int errno;
47 #endif
48 #ifndef __set_errno
49 # define __set_errno(val) errno = (val)
50 #endif
51
52 #ifndef NULL
53 # define NULL   0
54 #endif
55
56 #if defined USGr3 && !defined DIRENT
57 # define DIRENT
58 #endif /* USGr3 */
59 #if defined Xenix && !defined SYSNDIR
60 # define SYSNDIR
61 #endif /* Xenix */
62
63 #if defined POSIX || defined DIRENT || defined __GNU_LIBRARY__
64 # include <dirent.h>
65 # ifndef __GNU_LIBRARY__
66 #  define D_NAMLEN(d) strlen((d)->d_name)
67 # else
68 #  define HAVE_D_NAMLEN
69 #  define D_NAMLEN(d) ((d)->d_namlen)
70 # endif
71 #else /* not POSIX or DIRENT */
72 # define dirent         direct
73 # define D_NAMLEN(d)    ((d)->d_namlen)
74 # define HAVE_D_NAMLEN
75 # if defined USG && !defined sgi
76 #  if defined SYSNDIR
77 #   include <sys/ndir.h>
78 #  else /* Not SYSNDIR */
79 #   include "ndir.h"
80 #  endif /* SYSNDIR */
81 # else /* not USG */
82 #  include <sys/dir.h>
83 # endif /* USG */
84 #endif /* POSIX or DIRENT or __GNU_LIBRARY__ */
85
86 #if defined HAVE_UNISTD_H || defined __GNU_LIBRARY__
87 # include <unistd.h>
88 #endif
89
90 #if defined STDC_HEADERS || defined __GNU_LIBRARY__ || defined POSIX
91 # include <stdlib.h>
92 # include <string.h>
93 # define ANSI_STRING
94 #else   /* No standard headers.  */
95
96 # ifdef USG
97
98 #  include <string.h>
99 #  ifdef NEED_MEMORY_H
100 #   include <memory.h>
101 #  endif
102 #  define       ANSI_STRING
103
104 # else  /* Not USG.  */
105
106 #  ifdef NeXT
107
108 #   include <string.h>
109
110 #  else /* Not NeXT.  */
111
112 #   include <strings.h>
113
114 #   ifndef bcmp
115 extern int bcmp ();
116 #   endif
117 #   ifndef bzero
118 extern void bzero ();
119 #   endif
120 #   ifndef bcopy
121 extern void bcopy ();
122 #   endif
123
124 #  endif /* NeXT. */
125
126 # endif /* USG.  */
127
128 extern char *malloc (), *realloc ();
129 extern void free ();
130
131 #endif /* Standard headers.  */
132
133 #ifndef ANSI_STRING
134 # define memcpy(d, s, n)        bcopy((s), (d), (n))
135 # define memmove memcpy
136 #endif  /* Not ANSI_STRING.  */
137
138 #ifndef MAX
139 # define MAX(a, b) ((a) < (b) ? (b) : (a))
140 #endif
141
142 #ifdef _LIBC
143 # ifndef mempcpy
144 #  define mempcpy __mempcpy
145 # endif
146 # define HAVE_MEMPCPY   1
147 #endif
148
149 #if !defined __alloca && !defined __GNU_LIBRARY__
150
151 # ifdef __GNUC__
152 #  undef alloca
153 #  define alloca(n)     __builtin_alloca (n)
154 # else  /* Not GCC.  */
155 #  if   defined sparc || defined HAVE_ALLOCA_H
156 #   include <alloca.h>
157 #  else /* Not sparc or HAVE_ALLOCA_H.  */
158 #   ifndef _AIX
159 extern char *alloca ();
160 #   endif /* Not _AIX.  */
161 #  endif /* sparc or HAVE_ALLOCA_H.  */
162 # endif /* GCC.  */
163
164 # define __alloca       alloca
165
166 #endif
167
168 #if defined HAVE_LIMITS_H || defined STDC_HEADERS || defined __GNU_LIBRARY__
169 # include <limits.h>
170 #else
171 # include <sys/param.h>
172 #endif
173
174 #ifndef PATH_MAX
175 # ifdef MAXPATHLEN
176 #  define PATH_MAX MAXPATHLEN
177 # else
178 #  define PATH_MAX 1024
179 # endif
180 #endif
181
182 #if !defined STDC_HEADERS && !defined __GNU_LIBRARY__
183 # undef size_t
184 # define size_t unsigned int
185 #endif
186
187 #if !__STDC__ && !defined const
188 # define const
189 #endif
190
191 #ifndef __GNU_LIBRARY__
192 # define __lstat        stat
193 #endif
194 \f
195 #ifndef _LIBC
196 # define __getcwd getcwd
197 #endif
198
199 #ifndef GETCWD_RETURN_TYPE
200 # define GETCWD_RETURN_TYPE char *
201 #endif
202
203 /* Get the pathname of the current working directory, and put it in SIZE
204    bytes of BUF.  Returns NULL if the directory couldn't be determined or
205    SIZE was too small.  If successful, returns BUF.  In GNU, if BUF is
206    NULL, an array is allocated with `malloc'; the array is SIZE bytes long,
207    unless SIZE == 0, in which case it is as big as necessary.  */
208
209 GETCWD_RETURN_TYPE
210 __getcwd (buf, size)
211      char *buf;
212      size_t size;
213 {
214   static const char dots[]
215     = "../../../../../../../../../../../../../../../../../../../../../../../\
216 ../../../../../../../../../../../../../../../../../../../../../../../../../../\
217 ../../../../../../../../../../../../../../../../../../../../../../../../../..";
218   const char *dotp = &dots[sizeof (dots)];
219   const char *dotlist = dots;
220   size_t dotsize = sizeof (dots) - 1;
221   dev_t rootdev, thisdev;
222   ino_t rootino, thisino;
223   char *path;
224   register char *pathp;
225   struct stat st;
226   int prev_errno = errno;
227   size_t allocated = size;
228
229   if (size == 0)
230     {
231       if (buf != NULL)
232         {
233           __set_errno (EINVAL);
234           return NULL;
235         }
236
237       allocated = PATH_MAX + 1;
238     }
239
240   if (buf != NULL)
241     path = buf;
242   else
243     {
244       path = malloc (allocated);
245       if (path == NULL)
246         return NULL;
247     }
248
249   pathp = path + allocated;
250   *--pathp = '\0';
251
252   if (__lstat (".", &st) < 0)
253     goto lose2;
254   thisdev = st.st_dev;
255   thisino = st.st_ino;
256
257   if (__lstat ("/", &st) < 0)
258     goto lose2;
259   rootdev = st.st_dev;
260   rootino = st.st_ino;
261
262   while (!(thisdev == rootdev && thisino == rootino))
263     {
264       register DIR *dirstream;
265       struct dirent *d;
266       dev_t dotdev;
267       ino_t dotino;
268       char mount_point;
269
270       /* Look at the parent directory.  */
271       if (dotp == dotlist)
272         {
273           /* My, what a deep directory tree you have, Grandma.  */
274           char *new;
275           if (dotlist == dots)
276             {
277               new = malloc (dotsize * 2 + 1);
278               if (new == NULL)
279                 goto lose;
280 #ifdef HAVE_MEMPCPY
281               dotp = mempcpy (new, dots, dotsize);
282 #else
283               memcpy (new, dots, dotsize);
284               dotp = &new[dotsize];
285 #endif
286             }
287           else
288             {
289               new = realloc ((__ptr_t) dotlist, dotsize * 2 + 1);
290               if (new == NULL)
291                 goto lose;
292               dotp = &new[dotsize];
293             }
294 #ifdef HAVE_MEMPCPY
295           *((char *) mempcpy ((char *) dotp, new, dotsize)) = '\0';
296           dotsize *= 2;
297 #else
298           memcpy ((char *) dotp, new, dotsize);
299           dotsize *= 2;
300           new[dotsize] = '\0';
301 #endif
302           dotlist = new;
303         }
304
305       dotp -= 3;
306
307       /* Figure out if this directory is a mount point.  */
308       if (__lstat (dotp, &st) < 0)
309         goto lose;
310       dotdev = st.st_dev;
311       dotino = st.st_ino;
312       mount_point = dotdev != thisdev;
313
314       /* Search for the last directory.  */
315       dirstream = __opendir (dotp);
316       if (dirstream == NULL)
317         goto lose;
318       /* Clear errno to distinguish EOF from error if readdir returns
319          NULL.  */
320       __set_errno (0);
321       while ((d = __readdir (dirstream)) != NULL)
322         {
323           if (d->d_name[0] == '.' &&
324               (d->d_name[1] == '\0' ||
325                (d->d_name[1] == '.' && d->d_name[2] == '\0')))
326             continue;
327           if (mount_point || (ino_t) d->d_ino == thisino)
328             {
329               char name[dotlist + dotsize - dotp + 1 + _D_ALLOC_NAMLEN (d)];
330 #ifdef HAVE_MEMPCPY
331               char *tmp = mempcpy (name, dotp, dotlist + dotsize - dotp);
332               *tmp++ = '/';
333               strcpy (tmp, d->d_name);
334 #else
335               memcpy (name, dotp, dotlist + dotsize - dotp);
336               name[dotlist + dotsize - dotp] = '/';
337               strcpy (&name[dotlist + dotsize - dotp + 1], d->d_name);
338 #endif
339               /* We don't fail here if we cannot stat() a directory entry.
340                  This can happen when (network) filesystems fail.  If this
341                  entry is in fact the one we are looking for we will find
342                  out soon as we reach the end of the directory without
343                  having found anything.  */
344               if (__lstat (name, &st) >= 0
345                   && st.st_dev == thisdev && st.st_ino == thisino)
346                 break;
347             }
348         }
349       if (d == NULL)
350         {
351           int save = errno;
352           (void) __closedir (dirstream);
353           if (save == 0)
354             /* EOF on dirstream, which means that the current directory
355                has been removed.  */
356             save = ENOENT;
357           __set_errno (save);
358           goto lose;
359         }
360       else
361         {
362           size_t namlen = _D_EXACT_NAMLEN (d);
363
364           if ((size_t) (pathp - path) <= namlen)
365             {
366               if (size != 0)
367                 {
368                   (void) __closedir (dirstream);
369                   __set_errno (ERANGE);
370                   goto lose;
371                 }
372               else
373                 {
374                   char *tmp;
375                   size_t oldsize = allocated;
376
377                   allocated = 2 * MAX (allocated, namlen);
378                   tmp = realloc (path, allocated);
379                   if (tmp == NULL)
380                     {
381                       (void) __closedir (dirstream);
382                       __set_errno (ENOMEM);/* closedir might have changed it.*/
383                       goto lose;
384                     }
385
386                   /* Move current contents up to the end of the buffer.
387                      This is guaranteed to be non-overlapping.  */
388                   pathp = memcpy (tmp + allocated - (path + oldsize - pathp),
389                                   tmp + (pathp - path),
390                                   path + oldsize - pathp);
391                   path = tmp;
392                 }
393             }
394           pathp -= namlen;
395           (void) memcpy (pathp, d->d_name, namlen);
396           *--pathp = '/';
397           (void) __closedir (dirstream);
398         }
399
400       thisdev = dotdev;
401       thisino = dotino;
402     }
403
404   if (pathp == &path[allocated - 1])
405     *--pathp = '/';
406
407   if (dotlist != dots)
408     free ((__ptr_t) dotlist);
409
410   memmove (path, pathp, path + allocated - pathp);
411
412   /* Restore errno on successful return.  */
413   __set_errno (prev_errno);
414
415   return path;
416
417  lose:
418   if (dotlist != dots)
419     free ((__ptr_t) dotlist);
420  lose2:
421   if (buf == NULL)
422     free (path);
423   return NULL;
424 }
425
426 #if defined _LIBC && !defined __getcwd
427 weak_alias (__getcwd, getcwd)
428 #endif