Updated from GMP 1.906.7
[kopensolaris-gnu/glibc.git] / sysdeps / posix / getcwd.c
1 /* Copyright (C) 1991, 1992, 1993, 1994, 1995 Free Software Foundation, Inc.
2 This file is part of the GNU C Library.
3
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.
8
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.
13
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.  */
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)
46 extern int errno;
47 #endif
48
49 #ifndef NULL
50 #define NULL    0
51 #endif
52
53 #if defined (USGr3) && !defined (DIRENT)
54 #define DIRENT
55 #endif /* USGr3 */
56 #if defined (Xenix) && !defined (SYSNDIR)
57 #define SYSNDIR
58 #endif /* Xenix */
59
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__ */
82
83 #ifdef  HAVE_UNISTD_H
84 #include <unistd.h>
85 #endif
86
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.  */
93
94 #ifdef  USG
95
96 #include <string.h>
97 #ifdef  NEED_MEMORY_H
98 #include <memory.h>
99 #endif
100 #define ANSI_STRING
101
102 #else   /* Not USG.  */
103
104 #ifdef  NeXT
105
106 #include <string.h>
107
108 #else   /* Not NeXT.  */
109
110 #include <strings.h>
111
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
121
122 #endif  /* NeXT. */
123
124 #endif  /* USG.  */
125
126 extern char *malloc (), *realloc ();
127 extern void free ();
128
129 #endif /* Standard headers.  */
130
131 #ifndef ANSI_STRING
132 #define memcpy(d, s, n) bcopy((s), (d), (n))
133 #define memmove memcpy
134 #endif  /* Not ANSI_STRING.  */
135
136 #if     !defined(__alloca) && !defined(__GNU_LIBRARY__)
137
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.  */
150
151 #define __alloca        alloca
152
153 #endif
154
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
161
162 #ifndef PATH_MAX
163 #ifdef  MAXPATHLEN
164 #define PATH_MAX MAXPATHLEN
165 #else
166 #define PATH_MAX 1024
167 #endif
168 #endif
169
170 #ifndef STDC_HEADERS
171 #undef  size_t
172 #define size_t  unsigned int
173 #endif
174
175 #if !__STDC__ && !defined (const)
176 #define const
177 #endif
178
179 #ifndef __GNU_LIBRARY__
180 #define __lstat stat
181 #endif
182 \f
183 #ifndef _LIBC
184 #define __getcwd getcwd
185 #endif
186
187 /* Get the pathname of the current working directory, and put it in SIZE
188    bytes of BUF.  Returns NULL if the directory couldn't be determined or
189    SIZE was too small.  If successful, returns BUF.  In GNU, if BUF is
190    NULL, an array is allocated with `malloc'; the array is SIZE bytes long,
191    unless SIZE <= 0, in which case it is as big as necessary.  */
192
193 char *
194 __getcwd (buf, size)
195      char *buf;
196      size_t size;
197 {
198   static const char dots[]
199     = "../../../../../../../../../../../../../../../../../../../../../../../\
200 ../../../../../../../../../../../../../../../../../../../../../../../../../../\
201 ../../../../../../../../../../../../../../../../../../../../../../../../../..";
202   const char *dotp, *dotlist;
203   size_t dotsize;
204   dev_t rootdev, thisdev;
205   ino_t rootino, thisino;
206   char *path;
207   register char *pathp;
208   struct stat st;
209
210   if (size == 0)
211     {
212       if (buf != NULL)
213         {
214           errno = EINVAL;
215           return NULL;
216         }
217
218       size = PATH_MAX + 1;
219     }
220
221   if (buf != NULL)
222     path = buf;
223   else
224     {
225       path = malloc (size);
226       if (path == NULL)
227         return NULL;
228     }
229
230   pathp = path + size;
231   *--pathp = '\0';
232
233   if (__lstat (".", &st) < 0)
234     return NULL;
235   thisdev = st.st_dev;
236   thisino = st.st_ino;
237
238   if (__lstat ("/", &st) < 0)
239     return NULL;
240   rootdev = st.st_dev;
241   rootino = st.st_ino;
242
243   dotsize = sizeof (dots) - 1;
244   dotp = &dots[sizeof (dots)];
245   dotlist = dots;
246   while (!(thisdev == rootdev && thisino == rootino))
247     {
248       register DIR *dirstream;
249       register struct dirent *d;
250       dev_t dotdev;
251       ino_t dotino;
252       char mount_point;
253
254       /* Look at the parent directory.  */
255       if (dotp == dotlist)
256         {
257           /* My, what a deep directory tree you have, Grandma.  */
258           char *new;
259           if (dotlist == dots)
260             {
261               new = malloc (dotsize * 2 + 1);
262               if (new == NULL)
263                 return NULL;
264               memcpy (new, dots, dotsize);
265             }
266           else
267             {
268               new = realloc ((__ptr_t) dotlist, dotsize * 2 + 1);
269               if (new == NULL)
270                 goto lose;
271             }
272           memcpy (&new[dotsize], new, dotsize);
273           dotp = &new[dotsize];
274           dotsize *= 2;
275           new[dotsize] = '\0';
276           dotlist = new;
277         }
278
279       dotp -= 3;
280
281       /* Figure out if this directory is a mount point.  */
282       if (__lstat (dotp, &st) < 0)
283         goto lose;
284       dotdev = st.st_dev;
285       dotino = st.st_ino;
286       mount_point = dotdev != thisdev;
287
288       /* Search for the last directory.  */
289       dirstream = opendir (dotp);
290       if (dirstream == NULL)
291         goto lose;
292       while ((d = readdir (dirstream)) != NULL)
293         {
294           if (d->d_name[0] == '.' &&
295               (d->d_namlen == 1 || (d->d_namlen == 2 && d->d_name[1] == '.')))
296             continue;
297           if (mount_point || d->d_ino == thisino)
298             {
299               char *name = __alloca (dotlist + dotsize - dotp +
300                                      1 + d->d_namlen + 1);
301               memcpy (name, dotp, dotlist + dotsize - dotp);
302               name[dotlist + dotsize - dotp] = '/';
303               memcpy (&name[dotlist + dotsize - dotp + 1],
304                       d->d_name, d->d_namlen + 1);
305               if (__lstat (name, &st) < 0)
306                 {
307                   int save = errno;
308                   (void) closedir (dirstream);
309                   errno = save;
310                   goto lose;
311                 }
312               if (st.st_dev == thisdev && st.st_ino == thisino)
313                 break;
314             }
315         }
316       if (d == NULL)
317         {
318           int save = errno;
319           (void) closedir (dirstream);
320           errno = save;
321           goto lose;
322         }
323       else
324         {
325           if (pathp - path < d->d_namlen + 1)
326             {
327               if (buf != NULL)
328                 {
329                   errno = ERANGE;
330                   return NULL;
331                 }
332               else
333                 {
334                   size *= 2;
335                   buf = realloc (path, size);
336                   if (buf == NULL)
337                     {
338                       (void) closedir (dirstream);
339                       free (path);
340                       errno = ENOMEM; /* closedir might have changed it.  */
341                       return NULL;
342                     }
343                   pathp = &buf[pathp - path];
344                   path = buf;
345                 }
346             }
347           pathp -= d->d_namlen;
348           (void) memcpy (pathp, d->d_name, d->d_namlen);
349           *--pathp = '/';
350           (void) closedir (dirstream);
351         }
352
353       thisdev = dotdev;
354       thisino = dotino;
355     }
356
357   if (pathp == &path[size - 1])
358     *--pathp = '/';
359
360   if (dotlist != dots)
361     free ((__ptr_t) dotlist);
362
363   memmove (path, pathp, path + size - pathp);
364   return path;
365
366  lose:
367   if (dotlist != dots)
368     free ((__ptr_t) dotlist);
369   return NULL;
370 }
371
372 #ifdef _LIBC
373 weak_alias (__getcwd, getcwd)
374 #endif