Update.
[glibc.git] / sysdeps / posix / getcwd.c
blobdf48804f7a3ae397081a96b65a83316f2774ad31
1 /* Copyright (C) 1991,92,93,94,95,96,97,98 Free Software Foundation, Inc.
2 This file is part of the GNU C Library.
4 The GNU C Library is free software; you can redistribute it and/or
5 modify it under the terms of the GNU Library General Public License as
6 published by the Free Software Foundation; either version 2 of the
7 License, or (at your option) any later version.
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 Library General Public License for more details.
14 You should have received a copy of the GNU Library General Public
15 License along with the GNU C Library; see the file COPYING.LIB. If not,
16 write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17 Boston, MA 02111-1307, USA. */
19 /* Wants:
20 AC_STDC_HEADERS
21 AC_DIR_HEADER
22 AC_UNISTD_H
23 AC_MEMORY_H
24 AC_CONST
25 AC_ALLOCA
28 /* AIX requires this to be the first thing in the file. */
29 #if defined _AIX && !defined __GNUC__
30 #pragma alloca
31 #endif
33 #ifdef HAVE_CONFIG_H
34 # include "config.h"
35 #endif
37 #include <errno.h>
38 #include <sys/types.h>
39 #include <sys/stat.h>
41 #ifdef STDC_HEADERS
42 # include <stddef.h>
43 #endif
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
52 #ifndef NULL
53 # define NULL 0
54 #endif
56 #if defined USGr3 && !defined DIRENT
57 # define DIRENT
58 #endif /* USGr3 */
59 #if defined Xenix && !defined SYSNDIR
60 # define SYSNDIR
61 #endif /* Xenix */
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__ */
86 #if defined HAVE_UNISTD_H || defined __GNU_LIBRARY__
87 # include <unistd.h>
88 #endif
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. */
96 # ifdef USG
98 # include <string.h>
99 # ifdef NEED_MEMORY_H
100 # include <memory.h>
101 # endif
102 # define ANSI_STRING
104 # else /* Not USG. */
106 # ifdef NeXT
108 # include <string.h>
110 # else /* Not NeXT. */
112 # include <strings.h>
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
124 # endif /* NeXT. */
126 # endif /* USG. */
128 extern char *malloc (), *realloc ();
129 extern void free ();
131 #endif /* Standard headers. */
133 #ifndef ANSI_STRING
134 # define memcpy(d, s, n) bcopy((s), (d), (n))
135 # define memmove memcpy
136 #endif /* Not ANSI_STRING. */
138 #ifdef _LIBC
139 # ifndef mempcpy
140 # define mempcpy __mempcpy
141 # endif
142 # define HAVE_MEMPCPY 1
143 #endif
145 #if !defined __alloca && !defined __GNU_LIBRARY__
147 # ifdef __GNUC__
148 # undef alloca
149 # define alloca(n) __builtin_alloca (n)
150 # else /* Not GCC. */
151 # if defined sparc || defined HAVE_ALLOCA_H
152 # include <alloca.h>
153 # else /* Not sparc or HAVE_ALLOCA_H. */
154 # ifndef _AIX
155 extern char *alloca ();
156 # endif /* Not _AIX. */
157 # endif /* sparc or HAVE_ALLOCA_H. */
158 # endif /* GCC. */
160 # define __alloca alloca
162 #endif
164 #if defined HAVE_LIMITS_H || defined STDC_HEADERS || defined __GNU_LIBRARY__
165 # include <limits.h>
166 #else
167 # include <sys/param.h>
168 #endif
170 #ifndef PATH_MAX
171 # ifdef MAXPATHLEN
172 # define PATH_MAX MAXPATHLEN
173 # else
174 # define PATH_MAX 1024
175 # endif
176 #endif
178 #if !defined STDC_HEADERS && !defined __GNU_LIBRARY__
179 # undef size_t
180 # define size_t unsigned int
181 #endif
183 #if !__STDC__ && !defined const
184 # define const
185 #endif
187 #ifndef __GNU_LIBRARY__
188 # define __lstat stat
189 #endif
191 #ifndef _LIBC
192 # define __getcwd getcwd
193 #endif
195 #ifndef GETCWD_RETURN_TYPE
196 # define GETCWD_RETURN_TYPE char *
197 #endif
199 /* Get the pathname of the current working directory, and put it in SIZE
200 bytes of BUF. Returns NULL if the directory couldn't be determined or
201 SIZE was too small. If successful, returns BUF. In GNU, if BUF is
202 NULL, an array is allocated with `malloc'; the array is SIZE bytes long,
203 unless SIZE <= 0, in which case it is as big as necessary. */
205 GETCWD_RETURN_TYPE
206 __getcwd (buf, size)
207 char *buf;
208 size_t size;
210 static const char dots[]
211 = "../../../../../../../../../../../../../../../../../../../../../../../\
212 ../../../../../../../../../../../../../../../../../../../../../../../../../../\
213 ../../../../../../../../../../../../../../../../../../../../../../../../../..";
214 const char *dotp, *dotlist;
215 size_t dotsize;
216 dev_t rootdev, thisdev;
217 ino_t rootino, thisino;
218 char *path;
219 register char *pathp;
220 struct stat st;
221 int prev_errno = errno;
223 if (size == 0)
225 if (buf != NULL)
227 __set_errno (EINVAL);
228 return NULL;
231 size = PATH_MAX + 1;
234 if (buf != NULL)
235 path = buf;
236 else
238 path = malloc (size);
239 if (path == NULL)
240 return NULL;
243 pathp = path + size;
244 *--pathp = '\0';
246 if (__lstat (".", &st) < 0)
247 return NULL;
248 thisdev = st.st_dev;
249 thisino = st.st_ino;
251 if (__lstat ("/", &st) < 0)
252 return NULL;
253 rootdev = st.st_dev;
254 rootino = st.st_ino;
256 dotsize = sizeof (dots) - 1;
257 dotp = &dots[sizeof (dots)];
258 dotlist = dots;
259 while (!(thisdev == rootdev && thisino == rootino))
261 register DIR *dirstream;
262 struct dirent *d;
263 dev_t dotdev;
264 ino_t dotino;
265 char mount_point;
267 /* Look at the parent directory. */
268 if (dotp == dotlist)
270 /* My, what a deep directory tree you have, Grandma. */
271 char *new;
272 if (dotlist == dots)
274 new = malloc (dotsize * 2 + 1);
275 if (new == NULL)
276 return NULL;
277 #ifdef HAVE_MEMPCPY
278 dotp = mempcpy (new, dots, dotsize);
279 #else
280 memcpy (new, dots, dotsize);
281 dotp = &new[dotsize];
282 #endif
284 else
286 new = realloc ((__ptr_t) dotlist, dotsize * 2 + 1);
287 if (new == NULL)
288 goto lose;
289 dotp = &new[dotsize];
291 #ifdef HAVE_MEMPCPY
292 *((char *) mempcpy ((char *) dotp, new, dotsize)) = '\0';
293 dotsize *= 2;
294 #else
295 memcpy ((char *) dotp, new, dotsize);
296 dotsize *= 2;
297 new[dotsize] = '\0';
298 #endif
299 dotlist = new;
302 dotp -= 3;
304 /* Figure out if this directory is a mount point. */
305 if (__lstat (dotp, &st) < 0)
306 goto lose;
307 dotdev = st.st_dev;
308 dotino = st.st_ino;
309 mount_point = dotdev != thisdev;
311 /* Search for the last directory. */
312 dirstream = __opendir (dotp);
313 if (dirstream == NULL)
314 goto lose;
315 /* Clear errno to distinguish EOF from error if readdir returns
316 NULL. */
317 __set_errno (0);
318 while ((d = __readdir (dirstream)) != NULL)
320 if (d->d_name[0] == '.' &&
321 (d->d_name[1] == '\0' ||
322 (d->d_name[1] == '.' && d->d_name[2] == '\0')))
323 continue;
324 if (mount_point || (ino_t) d->d_ino == thisino)
326 char name[dotlist + dotsize - dotp + 1 + _D_ALLOC_NAMLEN (d)];
327 #ifdef HAVE_MEMPCPY
328 char *tmp = mempcpy (name, dotp, dotlist + dotsize - dotp);
329 *tmp++ = '/';
330 strcpy (tmp, d->d_name);
331 #else
332 memcpy (name, dotp, dotlist + dotsize - dotp);
333 name[dotlist + dotsize - dotp] = '/';
334 strcpy (&name[dotlist + dotsize - dotp + 1], d->d_name);
335 #endif
336 /* We don't fail here if we cannot stat() a directory entry.
337 This can happen when (network) filesystems fail. If this
338 entry is in fact the one we are looking for we will find
339 out soon as we reach the end of the directory without
340 having found anything. */
341 if (__lstat (name, &st) >= 0
342 && st.st_dev == thisdev && st.st_ino == thisino)
343 break;
346 if (d == NULL)
348 int save = errno;
349 (void) __closedir (dirstream);
350 if (save == 0)
351 /* EOF on dirstream, which means that the current directory
352 has been removed. */
353 save = ENOENT;
354 __set_errno (save);
355 goto lose;
357 else
359 size_t namlen = _D_EXACT_NAMLEN (d);
361 if ((size_t) (pathp - path) <= namlen)
363 if (buf != NULL)
365 (void) __closedir (dirstream);
366 __set_errno (ERANGE);
367 goto lose;
369 else
371 char *tmp;
373 size *= 2;
374 tmp = realloc (path, size);
375 if (tmp == NULL)
377 (void) __closedir (dirstream);
378 free (path);
379 __set_errno (ENOMEM);/* closedir might have changed it.*/
380 goto lose;
382 pathp = &tmp[pathp - path + size / 2];
383 path = tmp;
384 /* Move current contents up to the end of the buffer.
385 This is guaranteed to be non-overlapping. */
386 memcpy (pathp, pathp - size / 2, path + size - pathp);
389 pathp -= namlen;
390 (void) memcpy (pathp, d->d_name, namlen);
391 *--pathp = '/';
392 (void) __closedir (dirstream);
395 thisdev = dotdev;
396 thisino = dotino;
399 if (pathp == &path[size - 1])
400 *--pathp = '/';
402 if (dotlist != dots)
403 free ((__ptr_t) dotlist);
405 memmove (path, pathp, path + size - pathp);
407 /* Restore errno on successful return. */
408 __set_errno (prev_errno);
410 return path;
412 lose:
413 if (dotlist != dots)
414 free ((__ptr_t) dotlist);
415 return NULL;
418 #if defined _LIBC && !defined __getcwd
419 weak_alias (__getcwd, getcwd)
420 #endif