]> git.ipfire.org Git - thirdparty/glibc.git/blame - sysdeps/posix/getcwd.c
update from main archive 970209
[thirdparty/glibc.git] / sysdeps / posix / getcwd.c
CommitLineData
7cc27f44 1/* Copyright (C) 1991, 92, 93, 94, 95, 96, 97 Free Software Foundation, Inc.
47707456 2 This file is part of the GNU C Library.
28f540f4 3
47707456
UD
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.
28f540f4 8
47707456
UD
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.
28f540f4 13
47707456
UD
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. */
28f540f4
RM
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)
46extern int errno;
47#endif
c4029823
UD
48#ifndef __set_errno
49#define __set_errno(val) errno = (val)
50#endif
28f540f4
RM
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
1d8dc429 86#if defined (HAVE_UNISTD_H) || defined (__GNU_LIBRARY__)
28f540f4
RM
87#include <unistd.h>
88#endif
89
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. */
96
97#ifdef USG
98
99#include <string.h>
100#ifdef NEED_MEMORY_H
101#include <memory.h>
102#endif
103#define ANSI_STRING
104
105#else /* Not USG. */
106
107#ifdef NeXT
108
109#include <string.h>
110
111#else /* Not NeXT. */
112
113#include <strings.h>
114
115#ifndef bcmp
116extern int bcmp ();
117#endif
118#ifndef bzero
119extern void bzero ();
120#endif
121#ifndef bcopy
122extern void bcopy ();
123#endif
124
125#endif /* NeXT. */
126
127#endif /* USG. */
128
129extern char *malloc (), *realloc ();
130extern void free ();
131
132#endif /* Standard headers. */
133
134#ifndef ANSI_STRING
135#define memcpy(d, s, n) bcopy((s), (d), (n))
136#define memmove memcpy
137#endif /* Not ANSI_STRING. */
138
139#if !defined(__alloca) && !defined(__GNU_LIBRARY__)
140
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
149extern char *alloca ();
150#endif /* Not _AIX. */
151#endif /* sparc or HAVE_ALLOCA_H. */
152#endif /* GCC. */
153
154#define __alloca alloca
155
156#endif
157
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
164
165#ifndef PATH_MAX
166#ifdef MAXPATHLEN
167#define PATH_MAX MAXPATHLEN
168#else
169#define PATH_MAX 1024
170#endif
171#endif
172
b86199fb 173#if !defined (STDC_HEADERS) && !defined (__GNU_LIBRARY__)
28f540f4
RM
174#undef size_t
175#define size_t unsigned int
176#endif
177
178#if !__STDC__ && !defined (const)
179#define const
180#endif
181
182#ifndef __GNU_LIBRARY__
183#define __lstat stat
184#endif
185\f
7f811679
RM
186#ifndef _LIBC
187#define __getcwd getcwd
188#endif
189
190/* Get the pathname of the current working directory, and put it in SIZE
28f540f4
RM
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. */
195
196char *
7f811679 197__getcwd (buf, size)
28f540f4
RM
198 char *buf;
199 size_t size;
200{
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;
212
213 if (size == 0)
214 {
215 if (buf != NULL)
216 {
c4029823 217 __set_errno (EINVAL);
28f540f4
RM
218 return NULL;
219 }
220
221 size = PATH_MAX + 1;
222 }
223
224 if (buf != NULL)
225 path = buf;
226 else
227 {
228 path = malloc (size);
229 if (path == NULL)
230 return NULL;
231 }
232
233 pathp = path + size;
234 *--pathp = '\0';
235
7f811679 236 if (__lstat (".", &st) < 0)
28f540f4
RM
237 return NULL;
238 thisdev = st.st_dev;
239 thisino = st.st_ino;
240
241 if (__lstat ("/", &st) < 0)
242 return NULL;
243 rootdev = st.st_dev;
244 rootino = st.st_ino;
245
246 dotsize = sizeof (dots) - 1;
247 dotp = &dots[sizeof (dots)];
248 dotlist = dots;
249 while (!(thisdev == rootdev && thisino == rootino))
250 {
251 register DIR *dirstream;
a18f587d 252 struct dirent *d;
28f540f4
RM
253 dev_t dotdev;
254 ino_t dotino;
255 char mount_point;
256
257 /* Look at the parent directory. */
258 if (dotp == dotlist)
259 {
260 /* My, what a deep directory tree you have, Grandma. */
261 char *new;
262 if (dotlist == dots)
263 {
264 new = malloc (dotsize * 2 + 1);
265 if (new == NULL)
266 return NULL;
267 memcpy (new, dots, dotsize);
268 }
269 else
270 {
271 new = realloc ((__ptr_t) dotlist, dotsize * 2 + 1);
272 if (new == NULL)
273 goto lose;
274 }
275 memcpy (&new[dotsize], new, dotsize);
276 dotp = &new[dotsize];
277 dotsize *= 2;
278 new[dotsize] = '\0';
279 dotlist = new;
280 }
281
282 dotp -= 3;
283
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;
290
291 /* Search for the last directory. */
23396375 292 dirstream = __opendir (dotp);
28f540f4
RM
293 if (dirstream == NULL)
294 goto lose;
10dc2a90 295 while ((d = __readdir (dirstream)) != NULL)
28f540f4
RM
296 {
297 if (d->d_name[0] == '.' &&
92777700
RM
298 (d->d_name[1] == '\0' ||
299 (d->d_name[1] == '.' && d->d_name[2] == '\0')))
28f540f4 300 continue;
d68171ed 301 if (mount_point || (ino_t) d->d_ino == thisino)
28f540f4 302 {
92777700 303 char name[dotlist + dotsize - dotp + 1 + _D_ALLOC_NAMLEN (d)];
28f540f4
RM
304 memcpy (name, dotp, dotlist + dotsize - dotp);
305 name[dotlist + dotsize - dotp] = '/';
92777700 306 strcpy (&name[dotlist + dotsize - dotp + 1], d->d_name);
28f540f4
RM
307 if (__lstat (name, &st) < 0)
308 {
309 int save = errno;
23396375 310 (void) __closedir (dirstream);
c4029823 311 __set_errno (save);
28f540f4
RM
312 goto lose;
313 }
314 if (st.st_dev == thisdev && st.st_ino == thisino)
315 break;
316 }
317 }
318 if (d == NULL)
319 {
320 int save = errno;
23396375 321 (void) __closedir (dirstream);
c4029823 322 __set_errno (save);
28f540f4
RM
323 goto lose;
324 }
325 else
326 {
92777700
RM
327 size_t namlen = _D_EXACT_NAMLEN (d);
328
d68171ed 329 if ((size_t) (pathp - path) < namlen)
28f540f4
RM
330 {
331 if (buf != NULL)
332 {
7cc27f44 333 (void) __closedir (dirstream);
c4029823 334 __set_errno (ERANGE);
7cc27f44 335 goto lose;
28f540f4
RM
336 }
337 else
338 {
339 size *= 2;
340 buf = realloc (path, size);
341 if (buf == NULL)
342 {
23396375 343 (void) __closedir (dirstream);
28f540f4 344 free (path);
c4029823 345 __set_errno (ENOMEM);/* closedir might have changed it.*/
7cc27f44 346 goto lose;
28f540f4 347 }
8a523922 348 pathp = &buf[pathp - path + size / 2];
28f540f4 349 path = buf;
8a523922
UD
350 /* Move current contents up to the end of the buffer.
351 This is guaranteed to be non-overlapping. */
352 memcpy (pathp, pathp - size / 2, path + size - pathp);
28f540f4
RM
353 }
354 }
92777700
RM
355 pathp -= namlen;
356 (void) memcpy (pathp, d->d_name, namlen);
28f540f4 357 *--pathp = '/';
23396375 358 (void) __closedir (dirstream);
28f540f4
RM
359 }
360
361 thisdev = dotdev;
362 thisino = dotino;
363 }
364
365 if (pathp == &path[size - 1])
366 *--pathp = '/';
367
368 if (dotlist != dots)
369 free ((__ptr_t) dotlist);
370
371 memmove (path, pathp, path + size - pathp);
372 return path;
373
374 lose:
375 if (dotlist != dots)
376 free ((__ptr_t) dotlist);
377 return NULL;
378}
3ec41e03
RM
379
380#ifdef _LIBC
381weak_alias (__getcwd, getcwd)
382#endif