Wed Aug 9 14:25:35 1995 Miles Bader <miles@geech.gnu.ai.mit.edu>
[glibc.git] / sysdeps / posix / getcwd.c
blob7b992a9f43a041be724f8e579bad2fa516e27e64
1 /* Copyright (C) 1991, 1992, 1993, 1994 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
49 #ifndef NULL
50 #define NULL 0
51 #endif
53 #if defined (USGr3) && !defined (DIRENT)
54 #define DIRENT
55 #endif /* USGr3 */
56 #if defined (Xenix) && !defined (SYSNDIR)
57 #define SYSNDIR
58 #endif /* Xenix */
60 #if defined (POSIX) || defined (DIRENT) || defined (__GNU_LIBRARY__)
61 #include <dirent.h>
62 #ifndef __GNU_LIBRARY__
63 #define D_NAMLEN(d) strlen((d)->d_name)
64 #else
65 #define HAVE_D_NAMLEN
66 #define D_NAMLEN(d) ((d)->d_namlen)
67 #endif
68 #else /* not POSIX or DIRENT */
69 #define dirent direct
70 #define D_NAMLEN(d) ((d)->d_namlen)
71 #define HAVE_D_NAMLEN
72 #if defined (USG) && !defined (sgi)
73 #if defined (SYSNDIR)
74 #include <sys/ndir.h>
75 #else /* Not SYSNDIR */
76 #include "ndir.h"
77 #endif /* SYSNDIR */
78 #else /* not USG */
79 #include <sys/dir.h>
80 #endif /* USG */
81 #endif /* POSIX or DIRENT or __GNU_LIBRARY__ */
83 #ifdef HAVE_UNISTD_H
84 #include <unistd.h>
85 #endif
87 #if (defined (STDC_HEADERS) || defined (__GNU_LIBRARY__) \
88 || defined (POSIX))
89 #include <stdlib.h>
90 #include <string.h>
91 #define ANSI_STRING
92 #else /* No standard headers. */
94 #ifdef USG
96 #include <string.h>
97 #ifdef NEED_MEMORY_H
98 #include <memory.h>
99 #endif
100 #define ANSI_STRING
102 #else /* Not USG. */
104 #ifdef NeXT
106 #include <string.h>
108 #else /* Not NeXT. */
110 #include <strings.h>
112 #ifndef bcmp
113 extern int bcmp ();
114 #endif
115 #ifndef bzero
116 extern void bzero ();
117 #endif
118 #ifndef bcopy
119 extern void bcopy ();
120 #endif
122 #endif /* NeXT. */
124 #endif /* USG. */
126 extern char *malloc (), *realloc ();
127 extern void free ();
129 #endif /* Standard headers. */
131 #ifndef ANSI_STRING
132 #define memcpy(d, s, n) bcopy((s), (d), (n))
133 #define memmove memcpy
134 #endif /* Not ANSI_STRING. */
136 #if !defined(__alloca) && !defined(__GNU_LIBRARY__)
138 #ifdef __GNUC__
139 #undef alloca
140 #define alloca(n) __builtin_alloca (n)
141 #else /* Not GCC. */
142 #if defined (sparc) || defined (HAVE_ALLOCA_H)
143 #include <alloca.h>
144 #else /* Not sparc or HAVE_ALLOCA_H. */
145 #ifndef _AIX
146 extern char *alloca ();
147 #endif /* Not _AIX. */
148 #endif /* sparc or HAVE_ALLOCA_H. */
149 #endif /* GCC. */
151 #define __alloca alloca
153 #endif
155 #if (defined (HAVE_LIMITS_H) || defined (STDC_HEADERS) || \
156 defined (__GNU_LIBRARY__))
157 #include <limits.h>
158 #else
159 #include <sys/param.h>
160 #endif
162 #ifndef PATH_MAX
163 #ifdef MAXPATHLEN
164 #define PATH_MAX MAXPATHLEN
165 #else
166 #define PATH_MAX 1024
167 #endif
168 #endif
170 #ifndef STDC_HEADERS
171 #undef size_t
172 #define size_t unsigned int
173 #endif
175 #if !__STDC__ && !defined (const)
176 #define const
177 #endif
179 #ifndef __GNU_LIBRARY__
180 #define __lstat stat
181 #endif
183 /* Get the pathname of the current working directory, and put it in SIZE
184 bytes of BUF. Returns NULL if the directory couldn't be determined or
185 SIZE was too small. If successful, returns BUF. In GNU, if BUF is
186 NULL, an array is allocated with `malloc'; the array is SIZE bytes long,
187 unless SIZE <= 0, in which case it is as big as necessary. */
189 char *
190 getcwd (buf, size)
191 char *buf;
192 size_t size;
194 static const char dots[]
195 = "../../../../../../../../../../../../../../../../../../../../../../../\
196 ../../../../../../../../../../../../../../../../../../../../../../../../../../\
197 ../../../../../../../../../../../../../../../../../../../../../../../../../..";
198 const char *dotp, *dotlist;
199 size_t dotsize;
200 dev_t rootdev, thisdev;
201 ino_t rootino, thisino;
202 char *path;
203 register char *pathp;
204 struct stat st;
206 if (size == 0)
208 if (buf != NULL)
210 errno = EINVAL;
211 return NULL;
214 size = PATH_MAX + 1;
217 if (buf != NULL)
218 path = buf;
219 else
221 path = malloc (size);
222 if (path == NULL)
223 return NULL;
226 pathp = path + size;
227 *--pathp = '\0';
229 if (__lstat (".", &st) < 0)
230 return NULL;
231 thisdev = st.st_dev;
232 thisino = st.st_ino;
234 if (__lstat ("/", &st) < 0)
235 return NULL;
236 rootdev = st.st_dev;
237 rootino = st.st_ino;
239 dotsize = sizeof (dots) - 1;
240 dotp = &dots[sizeof (dots)];
241 dotlist = dots;
242 while (!(thisdev == rootdev && thisino == rootino))
244 register DIR *dirstream;
245 register struct dirent *d;
246 dev_t dotdev;
247 ino_t dotino;
248 char mount_point;
250 /* Look at the parent directory. */
251 if (dotp == dotlist)
253 /* My, what a deep directory tree you have, Grandma. */
254 char *new;
255 if (dotlist == dots)
257 new = malloc (dotsize * 2 + 1);
258 if (new == NULL)
259 return NULL;
260 memcpy (new, dots, dotsize);
262 else
264 new = realloc ((__ptr_t) dotlist, dotsize * 2 + 1);
265 if (new == NULL)
266 goto lose;
268 memcpy (&new[dotsize], new, dotsize);
269 dotp = &new[dotsize];
270 dotsize *= 2;
271 new[dotsize] = '\0';
272 dotlist = new;
275 dotp -= 3;
277 /* Figure out if this directory is a mount point. */
278 if (__lstat (dotp, &st) < 0)
279 goto lose;
280 dotdev = st.st_dev;
281 dotino = st.st_ino;
282 mount_point = dotdev != thisdev;
284 /* Search for the last directory. */
285 dirstream = opendir (dotp);
286 if (dirstream == NULL)
287 goto lose;
288 while ((d = readdir (dirstream)) != NULL)
290 if (d->d_name[0] == '.' &&
291 (d->d_namlen == 1 || (d->d_namlen == 2 && d->d_name[1] == '.')))
292 continue;
293 if (mount_point || d->d_ino == thisino)
295 char *name = __alloca (dotlist + dotsize - dotp +
296 1 + d->d_namlen + 1);
297 memcpy (name, dotp, dotlist + dotsize - dotp);
298 name[dotlist + dotsize - dotp] = '/';
299 memcpy (&name[dotlist + dotsize - dotp + 1],
300 d->d_name, d->d_namlen + 1);
301 if (__lstat (name, &st) < 0)
303 int save = errno;
304 (void) closedir (dirstream);
305 errno = save;
306 goto lose;
308 if (st.st_dev == thisdev && st.st_ino == thisino)
309 break;
312 if (d == NULL)
314 int save = errno;
315 (void) closedir (dirstream);
316 errno = save;
317 goto lose;
319 else
321 if (pathp - path < d->d_namlen + 1)
323 if (buf != NULL)
325 errno = ERANGE;
326 return NULL;
328 else
330 size *= 2;
331 buf = realloc (path, size);
332 if (buf == NULL)
334 (void) closedir (dirstream);
335 free (path);
336 errno = ENOMEM; /* closedir might have changed it. */
337 return NULL;
339 pathp = &buf[pathp - path];
340 path = buf;
343 pathp -= d->d_namlen;
344 (void) memcpy (pathp, d->d_name, d->d_namlen);
345 *--pathp = '/';
346 (void) closedir (dirstream);
349 thisdev = dotdev;
350 thisino = dotino;
353 if (pathp == &path[size - 1])
354 *--pathp = '/';
356 if (dotlist != dots)
357 free ((__ptr_t) dotlist);
359 memmove (path, pathp, path + size - pathp);
360 return path;
362 lose:
363 if (dotlist != dots)
364 free ((__ptr_t) dotlist);
365 return NULL;