]> git.ipfire.org Git - thirdparty/glibc.git/blame - sysdeps/posix/getcwd.c
Update.
[thirdparty/glibc.git] / sysdeps / posix / getcwd.c
CommitLineData
50a1b837 1/* Copyright (C) 1991,92,93,94,95,96,97,98 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. */
86187531 29#if defined _AIX && !defined __GNUC__
28f540f4
RM
30 #pragma alloca
31#endif
32
33#ifdef HAVE_CONFIG_H
86187531 34# include "config.h"
28f540f4
RM
35#endif
36
37#include <errno.h>
38#include <sys/types.h>
39#include <sys/stat.h>
40
41#ifdef STDC_HEADERS
86187531 42# include <stddef.h>
28f540f4
RM
43#endif
44
86187531 45#if !defined __GNU_LIBRARY__ && !defined STDC_HEADERS
28f540f4
RM
46extern int errno;
47#endif
c4029823 48#ifndef __set_errno
86187531 49# define __set_errno(val) errno = (val)
c4029823 50#endif
28f540f4
RM
51
52#ifndef NULL
86187531 53# define NULL 0
28f540f4
RM
54#endif
55
86187531
UD
56#if defined USGr3 && !defined DIRENT
57# define DIRENT
28f540f4 58#endif /* USGr3 */
86187531
UD
59#if defined Xenix && !defined SYSNDIR
60# define SYSNDIR
28f540f4
RM
61#endif /* Xenix */
62
86187531
UD
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
28f540f4 71#else /* not POSIX or DIRENT */
86187531
UD
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 */
28f540f4
RM
84#endif /* POSIX or DIRENT or __GNU_LIBRARY__ */
85
86187531
UD
86#if defined HAVE_UNISTD_H || defined __GNU_LIBRARY__
87# include <unistd.h>
28f540f4
RM
88#endif
89
86187531
UD
90#if defined STDC_HEADERS || defined __GNU_LIBRARY__ || defined POSIX
91# include <stdlib.h>
92# include <string.h>
93# define ANSI_STRING
28f540f4
RM
94#else /* No standard headers. */
95
86187531 96# ifdef USG
28f540f4 97
86187531
UD
98# include <string.h>
99# ifdef NEED_MEMORY_H
100# include <memory.h>
101# endif
102# define ANSI_STRING
28f540f4 103
86187531 104# else /* Not USG. */
28f540f4 105
86187531 106# ifdef NeXT
28f540f4 107
86187531 108# include <string.h>
28f540f4 109
86187531 110# else /* Not NeXT. */
28f540f4 111
86187531 112# include <strings.h>
28f540f4 113
86187531 114# ifndef bcmp
28f540f4 115extern int bcmp ();
86187531
UD
116# endif
117# ifndef bzero
28f540f4 118extern void bzero ();
86187531
UD
119# endif
120# ifndef bcopy
28f540f4 121extern void bcopy ();
86187531 122# endif
28f540f4 123
86187531 124# endif /* NeXT. */
28f540f4 125
86187531 126# endif /* USG. */
28f540f4
RM
127
128extern char *malloc (), *realloc ();
129extern void free ();
130
131#endif /* Standard headers. */
132
133#ifndef ANSI_STRING
86187531
UD
134# define memcpy(d, s, n) bcopy((s), (d), (n))
135# define memmove memcpy
28f540f4
RM
136#endif /* Not ANSI_STRING. */
137
cc3fa755 138#ifdef _LIBC
50a1b837
UD
139# ifndef mempcpy
140# define mempcpy __mempcpy
141# endif
cc3fa755
UD
142# define HAVE_MEMPCPY 1
143#endif
144
86187531 145#if !defined __alloca && !defined __GNU_LIBRARY__
28f540f4 146
86187531
UD
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
28f540f4 155extern char *alloca ();
86187531
UD
156# endif /* Not _AIX. */
157# endif /* sparc or HAVE_ALLOCA_H. */
158# endif /* GCC. */
28f540f4 159
86187531 160# define __alloca alloca
28f540f4
RM
161
162#endif
163
86187531
UD
164#if defined HAVE_LIMITS_H || defined STDC_HEADERS || defined __GNU_LIBRARY__
165# include <limits.h>
28f540f4 166#else
86187531 167# include <sys/param.h>
28f540f4
RM
168#endif
169
170#ifndef PATH_MAX
86187531
UD
171# ifdef MAXPATHLEN
172# define PATH_MAX MAXPATHLEN
173# else
174# define PATH_MAX 1024
175# endif
28f540f4
RM
176#endif
177
86187531
UD
178#if !defined STDC_HEADERS && !defined __GNU_LIBRARY__
179# undef size_t
180# define size_t unsigned int
28f540f4
RM
181#endif
182
86187531
UD
183#if !__STDC__ && !defined const
184# define const
28f540f4
RM
185#endif
186
187#ifndef __GNU_LIBRARY__
86187531 188# define __lstat stat
28f540f4
RM
189#endif
190\f
7f811679 191#ifndef _LIBC
86187531 192# define __getcwd getcwd
7f811679
RM
193#endif
194
04be94a8
UD
195#ifndef GETCWD_RETURN_TYPE
196# define GETCWD_RETURN_TYPE char *
fe0ec73e
UD
197#endif
198
7f811679 199/* Get the pathname of the current working directory, and put it in SIZE
28f540f4
RM
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. */
204
04be94a8 205GETCWD_RETURN_TYPE
7f811679 206__getcwd (buf, size)
28f540f4
RM
207 char *buf;
208 size_t size;
209{
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;
f4017d20 221 int prev_errno = errno;
28f540f4
RM
222
223 if (size == 0)
224 {
225 if (buf != NULL)
226 {
c4029823 227 __set_errno (EINVAL);
28f540f4
RM
228 return NULL;
229 }
230
231 size = PATH_MAX + 1;
232 }
233
234 if (buf != NULL)
235 path = buf;
236 else
237 {
238 path = malloc (size);
239 if (path == NULL)
240 return NULL;
241 }
242
243 pathp = path + size;
244 *--pathp = '\0';
245
7f811679 246 if (__lstat (".", &st) < 0)
28f540f4
RM
247 return NULL;
248 thisdev = st.st_dev;
249 thisino = st.st_ino;
250
251 if (__lstat ("/", &st) < 0)
252 return NULL;
253 rootdev = st.st_dev;
254 rootino = st.st_ino;
255
256 dotsize = sizeof (dots) - 1;
257 dotp = &dots[sizeof (dots)];
258 dotlist = dots;
259 while (!(thisdev == rootdev && thisino == rootino))
260 {
261 register DIR *dirstream;
a18f587d 262 struct dirent *d;
28f540f4
RM
263 dev_t dotdev;
264 ino_t dotino;
265 char mount_point;
266
267 /* Look at the parent directory. */
268 if (dotp == dotlist)
269 {
270 /* My, what a deep directory tree you have, Grandma. */
271 char *new;
272 if (dotlist == dots)
273 {
274 new = malloc (dotsize * 2 + 1);
275 if (new == NULL)
276 return NULL;
86187531
UD
277#ifdef HAVE_MEMPCPY
278 dotp = mempcpy (new, dots, dotsize);
279#else
28f540f4 280 memcpy (new, dots, dotsize);
86187531
UD
281 dotp = &new[dotsize];
282#endif
28f540f4
RM
283 }
284 else
285 {
286 new = realloc ((__ptr_t) dotlist, dotsize * 2 + 1);
287 if (new == NULL)
288 goto lose;
86187531 289 dotp = &new[dotsize];
28f540f4 290 }
86187531 291#ifdef HAVE_MEMPCPY
cc3fa755 292 *((char *) mempcpy ((char *) dotp, new, dotsize)) = '\0';
86187531
UD
293 dotsize *= 2;
294#else
cc3fa755 295 memcpy ((char *) dotp, new, dotsize);
28f540f4
RM
296 dotsize *= 2;
297 new[dotsize] = '\0';
86187531 298#endif
28f540f4
RM
299 dotlist = new;
300 }
301
302 dotp -= 3;
303
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;
310
311 /* Search for the last directory. */
23396375 312 dirstream = __opendir (dotp);
28f540f4
RM
313 if (dirstream == NULL)
314 goto lose;
f4017d20
UD
315 /* Clear errno to distinguish EOF from error if readdir returns
316 NULL. */
317 __set_errno (0);
10dc2a90 318 while ((d = __readdir (dirstream)) != NULL)
28f540f4
RM
319 {
320 if (d->d_name[0] == '.' &&
92777700
RM
321 (d->d_name[1] == '\0' ||
322 (d->d_name[1] == '.' && d->d_name[2] == '\0')))
28f540f4 323 continue;
d68171ed 324 if (mount_point || (ino_t) d->d_ino == thisino)
28f540f4 325 {
92777700 326 char name[dotlist + dotsize - dotp + 1 + _D_ALLOC_NAMLEN (d)];
86187531
UD
327#ifdef HAVE_MEMPCPY
328 char *tmp = mempcpy (name, dotp, dotlist + dotsize - dotp);
329 *tmp++ = '/';
330 strcpy (tmp, d->d_name);
331#else
28f540f4
RM
332 memcpy (name, dotp, dotlist + dotsize - dotp);
333 name[dotlist + dotsize - dotp] = '/';
92777700 334 strcpy (&name[dotlist + dotsize - dotp + 1], d->d_name);
86187531 335#endif
28f540f4
RM
336 if (__lstat (name, &st) < 0)
337 {
338 int save = errno;
23396375 339 (void) __closedir (dirstream);
c4029823 340 __set_errno (save);
28f540f4
RM
341 goto lose;
342 }
343 if (st.st_dev == thisdev && st.st_ino == thisino)
344 break;
345 }
346 }
347 if (d == NULL)
348 {
349 int save = errno;
23396375 350 (void) __closedir (dirstream);
f4017d20
UD
351 if (save == 0)
352 /* EOF on dirstream, which means that the current directory
353 has been removed. */
354 save = ENOENT;
c4029823 355 __set_errno (save);
28f540f4
RM
356 goto lose;
357 }
358 else
359 {
92777700
RM
360 size_t namlen = _D_EXACT_NAMLEN (d);
361
9a0a462c 362 if ((size_t) (pathp - path) <= namlen)
28f540f4
RM
363 {
364 if (buf != NULL)
365 {
7cc27f44 366 (void) __closedir (dirstream);
c4029823 367 __set_errno (ERANGE);
7cc27f44 368 goto lose;
28f540f4
RM
369 }
370 else
371 {
8325d82c
UD
372 char *tmp;
373
28f540f4 374 size *= 2;
8325d82c
UD
375 tmp = realloc (path, size);
376 if (tmp == NULL)
28f540f4 377 {
23396375 378 (void) __closedir (dirstream);
28f540f4 379 free (path);
c4029823 380 __set_errno (ENOMEM);/* closedir might have changed it.*/
7cc27f44 381 goto lose;
28f540f4 382 }
8325d82c
UD
383 pathp = &tmp[pathp - path + size / 2];
384 path = tmp;
8a523922
UD
385 /* Move current contents up to the end of the buffer.
386 This is guaranteed to be non-overlapping. */
387 memcpy (pathp, pathp - size / 2, path + size - pathp);
28f540f4
RM
388 }
389 }
92777700
RM
390 pathp -= namlen;
391 (void) memcpy (pathp, d->d_name, namlen);
28f540f4 392 *--pathp = '/';
23396375 393 (void) __closedir (dirstream);
28f540f4
RM
394 }
395
396 thisdev = dotdev;
397 thisino = dotino;
398 }
399
400 if (pathp == &path[size - 1])
401 *--pathp = '/';
402
403 if (dotlist != dots)
404 free ((__ptr_t) dotlist);
405
406 memmove (path, pathp, path + size - pathp);
f4017d20
UD
407
408 /* Restore errno on successful return. */
409 __set_errno (prev_errno);
410
28f540f4
RM
411 return path;
412
413 lose:
414 if (dotlist != dots)
415 free ((__ptr_t) dotlist);
416 return NULL;
417}
3ec41e03 418
fe0ec73e 419#if defined _LIBC && !defined __getcwd
3ec41e03
RM
420weak_alias (__getcwd, getcwd)
421#endif