update from main archive 960927
[glibc.git] / sysdeps / posix / getcwd.c
blob825599f3704a5fe7f260c4cab05edb6cb6906f87
1 /* Copyright (C) 1991, 92, 93, 94, 95, 96 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
16 not, write to the Free Software Foundation, Inc., 675 Mass Ave,
17 Cambridge, MA 02139, 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__) \
91 || defined (POSIX))
92 #include <stdlib.h>
93 #include <string.h>
94 #define ANSI_STRING
95 #else /* No standard headers. */
97 #ifdef USG
99 #include <string.h>
100 #ifdef NEED_MEMORY_H
101 #include <memory.h>
102 #endif
103 #define ANSI_STRING
105 #else /* Not USG. */
107 #ifdef NeXT
109 #include <string.h>
111 #else /* Not NeXT. */
113 #include <strings.h>
115 #ifndef bcmp
116 extern int bcmp ();
117 #endif
118 #ifndef bzero
119 extern void bzero ();
120 #endif
121 #ifndef bcopy
122 extern void bcopy ();
123 #endif
125 #endif /* NeXT. */
127 #endif /* USG. */
129 extern char *malloc (), *realloc ();
130 extern void free ();
132 #endif /* Standard headers. */
134 #ifndef ANSI_STRING
135 #define memcpy(d, s, n) bcopy((s), (d), (n))
136 #define memmove memcpy
137 #endif /* Not ANSI_STRING. */
139 #if !defined(__alloca) && !defined(__GNU_LIBRARY__)
141 #ifdef __GNUC__
142 #undef alloca
143 #define alloca(n) __builtin_alloca (n)
144 #else /* Not GCC. */
145 #if defined (sparc) || defined (HAVE_ALLOCA_H)
146 #include <alloca.h>
147 #else /* Not sparc or HAVE_ALLOCA_H. */
148 #ifndef _AIX
149 extern char *alloca ();
150 #endif /* Not _AIX. */
151 #endif /* sparc or HAVE_ALLOCA_H. */
152 #endif /* GCC. */
154 #define __alloca alloca
156 #endif
158 #if (defined (HAVE_LIMITS_H) || defined (STDC_HEADERS) || \
159 defined (__GNU_LIBRARY__))
160 #include <limits.h>
161 #else
162 #include <sys/param.h>
163 #endif
165 #ifndef PATH_MAX
166 #ifdef MAXPATHLEN
167 #define PATH_MAX MAXPATHLEN
168 #else
169 #define PATH_MAX 1024
170 #endif
171 #endif
173 #if !defined (STDC_HEADERS) && !defined (__GNU_LIBRARY__)
174 #undef size_t
175 #define size_t unsigned int
176 #endif
178 #if !__STDC__ && !defined (const)
179 #define const
180 #endif
182 #ifndef __GNU_LIBRARY__
183 #define __lstat stat
184 #endif
186 #ifndef _LIBC
187 #define __getcwd getcwd
188 #endif
190 /* Get the pathname of the current working directory, and put it in SIZE
191 bytes of BUF. Returns NULL if the directory couldn't be determined or
192 SIZE was too small. If successful, returns BUF. In GNU, if BUF is
193 NULL, an array is allocated with `malloc'; the array is SIZE bytes long,
194 unless SIZE <= 0, in which case it is as big as necessary. */
196 char *
197 __getcwd (buf, size)
198 char *buf;
199 size_t size;
201 static const char dots[]
202 = "../../../../../../../../../../../../../../../../../../../../../../../\
203 ../../../../../../../../../../../../../../../../../../../../../../../../../../\
204 ../../../../../../../../../../../../../../../../../../../../../../../../../..";
205 const char *dotp, *dotlist;
206 size_t dotsize;
207 dev_t rootdev, thisdev;
208 ino_t rootino, thisino;
209 char *path;
210 register char *pathp;
211 struct stat st;
213 if (size == 0)
215 if (buf != NULL)
217 __set_errno (EINVAL);
218 return NULL;
221 size = PATH_MAX + 1;
224 if (buf != NULL)
225 path = buf;
226 else
228 path = malloc (size);
229 if (path == NULL)
230 return NULL;
233 pathp = path + size;
234 *--pathp = '\0';
236 if (__lstat (".", &st) < 0)
237 return NULL;
238 thisdev = st.st_dev;
239 thisino = st.st_ino;
241 if (__lstat ("/", &st) < 0)
242 return NULL;
243 rootdev = st.st_dev;
244 rootino = st.st_ino;
246 dotsize = sizeof (dots) - 1;
247 dotp = &dots[sizeof (dots)];
248 dotlist = dots;
249 while (!(thisdev == rootdev && thisino == rootino))
251 register DIR *dirstream;
252 register struct dirent *d;
253 dev_t dotdev;
254 ino_t dotino;
255 char mount_point;
257 /* Look at the parent directory. */
258 if (dotp == dotlist)
260 /* My, what a deep directory tree you have, Grandma. */
261 char *new;
262 if (dotlist == dots)
264 new = malloc (dotsize * 2 + 1);
265 if (new == NULL)
266 return NULL;
267 memcpy (new, dots, dotsize);
269 else
271 new = realloc ((__ptr_t) dotlist, dotsize * 2 + 1);
272 if (new == NULL)
273 goto lose;
275 memcpy (&new[dotsize], new, dotsize);
276 dotp = &new[dotsize];
277 dotsize *= 2;
278 new[dotsize] = '\0';
279 dotlist = new;
282 dotp -= 3;
284 /* Figure out if this directory is a mount point. */
285 if (__lstat (dotp, &st) < 0)
286 goto lose;
287 dotdev = st.st_dev;
288 dotino = st.st_ino;
289 mount_point = dotdev != thisdev;
291 /* Search for the last directory. */
292 dirstream = __opendir (dotp);
293 if (dirstream == NULL)
294 goto lose;
295 while ((d = __readdir (dirstream)) != NULL)
297 if (d->d_name[0] == '.' &&
298 (d->d_name[1] == '\0' ||
299 (d->d_name[1] == '.' && d->d_name[2] == '\0')))
300 continue;
301 if (mount_point || (ino_t) d->d_ino == thisino)
303 char name[dotlist + dotsize - dotp + 1 + _D_ALLOC_NAMLEN (d)];
304 memcpy (name, dotp, dotlist + dotsize - dotp);
305 name[dotlist + dotsize - dotp] = '/';
306 strcpy (&name[dotlist + dotsize - dotp + 1], d->d_name);
307 if (__lstat (name, &st) < 0)
309 int save = errno;
310 (void) __closedir (dirstream);
311 __set_errno (save);
312 goto lose;
314 if (st.st_dev == thisdev && st.st_ino == thisino)
315 break;
318 if (d == NULL)
320 int save = errno;
321 (void) __closedir (dirstream);
322 __set_errno (save);
323 goto lose;
325 else
327 size_t namlen = _D_EXACT_NAMLEN (d);
329 if ((size_t) (pathp - path) < namlen)
331 if (buf != NULL)
333 __set_errno (ERANGE);
334 return NULL;
336 else
338 size *= 2;
339 buf = realloc (path, size);
340 if (buf == NULL)
342 (void) __closedir (dirstream);
343 free (path);
344 __set_errno (ENOMEM);/* closedir might have changed it.*/
345 return NULL;
347 pathp = &buf[pathp - path];
348 path = buf;
351 pathp -= namlen;
352 (void) memcpy (pathp, d->d_name, namlen);
353 *--pathp = '/';
354 (void) __closedir (dirstream);
357 thisdev = dotdev;
358 thisino = dotino;
361 if (pathp == &path[size - 1])
362 *--pathp = '/';
364 if (dotlist != dots)
365 free ((__ptr_t) dotlist);
367 memmove (path, pathp, path + size - pathp);
368 return path;
370 lose:
371 if (dotlist != dots)
372 free ((__ptr_t) dotlist);
373 return NULL;
376 #ifdef _LIBC
377 weak_alias (__getcwd, getcwd)
378 #endif