]> git.ipfire.org Git - thirdparty/glibc.git/blame - sysdeps/posix/getcwd.c
Update.
[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. */
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
UD
138#ifdef _LIBC
139# define mempcpy __mempcpy
140# define HAVE_MEMPCPY 1
141#endif
142
86187531 143#if !defined __alloca && !defined __GNU_LIBRARY__
28f540f4 144
86187531
UD
145# ifdef __GNUC__
146# undef alloca
147# define alloca(n) __builtin_alloca (n)
148# else /* Not GCC. */
149# if defined sparc || defined HAVE_ALLOCA_H
150# include <alloca.h>
151# else /* Not sparc or HAVE_ALLOCA_H. */
152# ifndef _AIX
28f540f4 153extern char *alloca ();
86187531
UD
154# endif /* Not _AIX. */
155# endif /* sparc or HAVE_ALLOCA_H. */
156# endif /* GCC. */
28f540f4 157
86187531 158# define __alloca alloca
28f540f4
RM
159
160#endif
161
86187531
UD
162#if defined HAVE_LIMITS_H || defined STDC_HEADERS || defined __GNU_LIBRARY__
163# include <limits.h>
28f540f4 164#else
86187531 165# include <sys/param.h>
28f540f4
RM
166#endif
167
168#ifndef PATH_MAX
86187531
UD
169# ifdef MAXPATHLEN
170# define PATH_MAX MAXPATHLEN
171# else
172# define PATH_MAX 1024
173# endif
28f540f4
RM
174#endif
175
86187531
UD
176#if !defined STDC_HEADERS && !defined __GNU_LIBRARY__
177# undef size_t
178# define size_t unsigned int
28f540f4
RM
179#endif
180
86187531
UD
181#if !__STDC__ && !defined const
182# define const
28f540f4
RM
183#endif
184
185#ifndef __GNU_LIBRARY__
86187531 186# define __lstat stat
28f540f4
RM
187#endif
188\f
7f811679 189#ifndef _LIBC
86187531 190# define __getcwd getcwd
7f811679
RM
191#endif
192
04be94a8
UD
193#ifndef GETCWD_RETURN_TYPE
194# define GETCWD_RETURN_TYPE char *
fe0ec73e
UD
195#endif
196
7f811679 197/* Get the pathname of the current working directory, and put it in SIZE
28f540f4
RM
198 bytes of BUF. Returns NULL if the directory couldn't be determined or
199 SIZE was too small. If successful, returns BUF. In GNU, if BUF is
200 NULL, an array is allocated with `malloc'; the array is SIZE bytes long,
201 unless SIZE <= 0, in which case it is as big as necessary. */
202
04be94a8 203GETCWD_RETURN_TYPE
7f811679 204__getcwd (buf, size)
28f540f4
RM
205 char *buf;
206 size_t size;
207{
208 static const char dots[]
209 = "../../../../../../../../../../../../../../../../../../../../../../../\
210../../../../../../../../../../../../../../../../../../../../../../../../../../\
211../../../../../../../../../../../../../../../../../../../../../../../../../..";
212 const char *dotp, *dotlist;
213 size_t dotsize;
214 dev_t rootdev, thisdev;
215 ino_t rootino, thisino;
216 char *path;
217 register char *pathp;
218 struct stat st;
f4017d20 219 int prev_errno = errno;
28f540f4
RM
220
221 if (size == 0)
222 {
223 if (buf != NULL)
224 {
c4029823 225 __set_errno (EINVAL);
28f540f4
RM
226 return NULL;
227 }
228
229 size = PATH_MAX + 1;
230 }
231
232 if (buf != NULL)
233 path = buf;
234 else
235 {
236 path = malloc (size);
237 if (path == NULL)
238 return NULL;
239 }
240
241 pathp = path + size;
242 *--pathp = '\0';
243
7f811679 244 if (__lstat (".", &st) < 0)
28f540f4
RM
245 return NULL;
246 thisdev = st.st_dev;
247 thisino = st.st_ino;
248
249 if (__lstat ("/", &st) < 0)
250 return NULL;
251 rootdev = st.st_dev;
252 rootino = st.st_ino;
253
254 dotsize = sizeof (dots) - 1;
255 dotp = &dots[sizeof (dots)];
256 dotlist = dots;
257 while (!(thisdev == rootdev && thisino == rootino))
258 {
259 register DIR *dirstream;
a18f587d 260 struct dirent *d;
28f540f4
RM
261 dev_t dotdev;
262 ino_t dotino;
263 char mount_point;
264
265 /* Look at the parent directory. */
266 if (dotp == dotlist)
267 {
268 /* My, what a deep directory tree you have, Grandma. */
269 char *new;
270 if (dotlist == dots)
271 {
272 new = malloc (dotsize * 2 + 1);
273 if (new == NULL)
274 return NULL;
86187531
UD
275#ifdef HAVE_MEMPCPY
276 dotp = mempcpy (new, dots, dotsize);
277#else
28f540f4 278 memcpy (new, dots, dotsize);
86187531
UD
279 dotp = &new[dotsize];
280#endif
28f540f4
RM
281 }
282 else
283 {
284 new = realloc ((__ptr_t) dotlist, dotsize * 2 + 1);
285 if (new == NULL)
286 goto lose;
86187531 287 dotp = &new[dotsize];
28f540f4 288 }
86187531 289#ifdef HAVE_MEMPCPY
cc3fa755 290 *((char *) mempcpy ((char *) dotp, new, dotsize)) = '\0';
86187531
UD
291 dotsize *= 2;
292#else
cc3fa755 293 memcpy ((char *) dotp, new, dotsize);
28f540f4
RM
294 dotsize *= 2;
295 new[dotsize] = '\0';
86187531 296#endif
28f540f4
RM
297 dotlist = new;
298 }
299
300 dotp -= 3;
301
302 /* Figure out if this directory is a mount point. */
303 if (__lstat (dotp, &st) < 0)
304 goto lose;
305 dotdev = st.st_dev;
306 dotino = st.st_ino;
307 mount_point = dotdev != thisdev;
308
309 /* Search for the last directory. */
23396375 310 dirstream = __opendir (dotp);
28f540f4
RM
311 if (dirstream == NULL)
312 goto lose;
f4017d20
UD
313 /* Clear errno to distinguish EOF from error if readdir returns
314 NULL. */
315 __set_errno (0);
10dc2a90 316 while ((d = __readdir (dirstream)) != NULL)
28f540f4
RM
317 {
318 if (d->d_name[0] == '.' &&
92777700
RM
319 (d->d_name[1] == '\0' ||
320 (d->d_name[1] == '.' && d->d_name[2] == '\0')))
28f540f4 321 continue;
d68171ed 322 if (mount_point || (ino_t) d->d_ino == thisino)
28f540f4 323 {
92777700 324 char name[dotlist + dotsize - dotp + 1 + _D_ALLOC_NAMLEN (d)];
86187531
UD
325#ifdef HAVE_MEMPCPY
326 char *tmp = mempcpy (name, dotp, dotlist + dotsize - dotp);
327 *tmp++ = '/';
328 strcpy (tmp, d->d_name);
329#else
28f540f4
RM
330 memcpy (name, dotp, dotlist + dotsize - dotp);
331 name[dotlist + dotsize - dotp] = '/';
92777700 332 strcpy (&name[dotlist + dotsize - dotp + 1], d->d_name);
86187531 333#endif
28f540f4
RM
334 if (__lstat (name, &st) < 0)
335 {
336 int save = errno;
23396375 337 (void) __closedir (dirstream);
c4029823 338 __set_errno (save);
28f540f4
RM
339 goto lose;
340 }
341 if (st.st_dev == thisdev && st.st_ino == thisino)
342 break;
343 }
344 }
345 if (d == NULL)
346 {
347 int save = errno;
23396375 348 (void) __closedir (dirstream);
f4017d20
UD
349 if (save == 0)
350 /* EOF on dirstream, which means that the current directory
351 has been removed. */
352 save = ENOENT;
c4029823 353 __set_errno (save);
28f540f4
RM
354 goto lose;
355 }
356 else
357 {
92777700
RM
358 size_t namlen = _D_EXACT_NAMLEN (d);
359
9a0a462c 360 if ((size_t) (pathp - path) <= namlen)
28f540f4
RM
361 {
362 if (buf != NULL)
363 {
7cc27f44 364 (void) __closedir (dirstream);
c4029823 365 __set_errno (ERANGE);
7cc27f44 366 goto lose;
28f540f4
RM
367 }
368 else
369 {
370 size *= 2;
371 buf = realloc (path, size);
372 if (buf == NULL)
373 {
23396375 374 (void) __closedir (dirstream);
28f540f4 375 free (path);
c4029823 376 __set_errno (ENOMEM);/* closedir might have changed it.*/
7cc27f44 377 goto lose;
28f540f4 378 }
8a523922 379 pathp = &buf[pathp - path + size / 2];
28f540f4 380 path = buf;
8a523922
UD
381 /* Move current contents up to the end of the buffer.
382 This is guaranteed to be non-overlapping. */
383 memcpy (pathp, pathp - size / 2, path + size - pathp);
28f540f4
RM
384 }
385 }
92777700
RM
386 pathp -= namlen;
387 (void) memcpy (pathp, d->d_name, namlen);
28f540f4 388 *--pathp = '/';
23396375 389 (void) __closedir (dirstream);
28f540f4
RM
390 }
391
392 thisdev = dotdev;
393 thisino = dotino;
394 }
395
396 if (pathp == &path[size - 1])
397 *--pathp = '/';
398
399 if (dotlist != dots)
400 free ((__ptr_t) dotlist);
401
402 memmove (path, pathp, path + size - pathp);
f4017d20
UD
403
404 /* Restore errno on successful return. */
405 __set_errno (prev_errno);
406
28f540f4
RM
407 return path;
408
409 lose:
410 if (dotlist != dots)
411 free ((__ptr_t) dotlist);
412 return NULL;
413}
3ec41e03 414
fe0ec73e 415#if defined _LIBC && !defined __getcwd
3ec41e03
RM
416weak_alias (__getcwd, getcwd)
417#endif