Imported from ../bash-2.0.tar.gz.
[platform/upstream/bash.git] / getcwd.c
1 /* getcwd.c -- stolen from the GNU C library and modified to work with bash. */
2
3 /* Copyright (C) 1991 Free Software Foundation, Inc.
4    This file is part of the GNU C Library.
5
6    The GNU C Library is free software; you can redistribute it and/or
7    modify it under the terms of the GNU Library General Public License as
8    published by the Free Software Foundation; either version 2 of the
9    License, or (at your option) any later version.
10
11    The GNU C Library is distributed in the hope that it will be useful,
12    but WITHOUT ANY WARRANTY; without even the implied warranty of
13    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14    Library General Public License for more details.
15
16    You should have received a copy of the GNU Library General Public
17    License along with the GNU C Library; see the file COPYING.LIB.  If
18    not, write to the Free Software Foundation, Inc., 675 Mass Ave,
19    Cambridge, MA 02139, USA.  */
20
21 #include "config.h"
22
23 #if !defined (HAVE_GETCWD)
24
25 #include "bashtypes.h"
26 #include <errno.h>
27
28 #if defined (HAVE_LIMITS_H)
29 #  include <limits.h>
30 #endif
31
32 #if defined (HAVE_UNISTD_H)
33 #  include <unistd.h>
34 #endif
35
36 #include "posixdir.h"
37 #include "posixstat.h"
38 #include "maxpath.h"
39 #include "memalloc.h"
40
41 #if defined (HAVE_STDLIB_H)
42 #  include <stdlib.h>
43 #else
44 #  include "ansi_stdlib.h"
45 #endif /* !HAVE_STDLIB_H */
46
47 #if defined (HAVE_STRING_H)
48 #  include <string.h>
49 #else
50 #  include <strings.h>
51 #endif /* !HAVE_STRING_H */
52
53 #if !defined (errno)
54 extern int errno;
55 #endif /* !errno */
56
57 #if defined (__STDC__)
58 #  define CONST const
59 #  define PTR void *
60 #else /* !__STDC__ */
61 #  define CONST
62 #  define PTR char *
63 #endif /* !__STDC__ */
64
65 #if !defined (PATH_MAX)
66 #  if defined (MAXPATHLEN)
67 #    define PATH_MAX MAXPATHLEN
68 #  else /* !MAXPATHLEN */
69 #    define PATH_MAX 1024
70 #  endif /* !MAXPATHLEN */
71 #endif /* !PATH_MAX */
72
73 #if !defined (HAVE_LSTAT)
74 #  define lstat stat
75 #endif
76
77 /* Get the pathname of the current working directory,
78    and put it in SIZE bytes of BUF.  Returns NULL if the
79    directory couldn't be determined or SIZE was too small.
80    If successful, returns BUF.  In GNU, if BUF is NULL,
81    an array is allocated with `malloc'; the array is SIZE
82    bytes long, unless SIZE <= 0, in which case it is as
83    big as necessary.  */
84 #if defined (__STDC__)
85 char *
86 getcwd (char *buf, size_t size)
87 #else /* !__STDC__ */
88 char *
89 getcwd (buf, size)
90      char *buf;
91      size_t size;
92 #endif /* !__STDC__ */
93 {
94   static CONST char dots[]
95     = "../../../../../../../../../../../../../../../../../../../../../../../\
96 ../../../../../../../../../../../../../../../../../../../../../../../../../../\
97 ../../../../../../../../../../../../../../../../../../../../../../../../../..";
98   CONST char *dotp, *dotlist;
99   size_t dotsize;
100   dev_t rootdev, thisdev;
101   ino_t rootino, thisino;
102   char path[PATH_MAX + 1];
103   register char *pathp;
104   char *pathbuf;
105   size_t pathsize;
106   struct stat st;
107
108   if (buf != NULL && size == 0)
109     {
110       errno = EINVAL;
111       return ((char *)NULL);
112     }
113
114   pathsize = sizeof (path);
115   pathp = &path[pathsize];
116   *--pathp = '\0';
117   pathbuf = path;
118
119   if (stat (".", &st) < 0)
120     return ((char *)NULL);
121   thisdev = st.st_dev;
122   thisino = st.st_ino;
123
124   if (stat ("/", &st) < 0)
125     return ((char *)NULL);
126   rootdev = st.st_dev;
127   rootino = st.st_ino;
128
129   dotsize = sizeof (dots) - 1;
130   dotp = &dots[sizeof (dots)];
131   dotlist = dots;
132   while (!(thisdev == rootdev && thisino == rootino))
133     {
134       register DIR *dirstream;
135       register struct dirent *d;
136       dev_t dotdev;
137       ino_t dotino;
138       char mount_point;
139       int namlen;
140
141       /* Look at the parent directory.  */
142       if (dotp == dotlist)
143         {
144           /* My, what a deep directory tree you have, Grandma.  */
145           char *new;
146           if (dotlist == dots)
147             {
148               new = malloc (dotsize * 2 + 1);
149               if (new == NULL)
150                 goto lose;
151               memcpy (new, dots, dotsize);
152             }
153           else
154             {
155               new = realloc ((PTR) dotlist, dotsize * 2 + 1);
156               if (new == NULL)
157                 goto lose;
158             }
159           memcpy (&new[dotsize], new, dotsize);
160           dotp = &new[dotsize];
161           dotsize *= 2;
162           new[dotsize] = '\0';
163           dotlist = new;
164         }
165
166       dotp -= 3;
167
168       /* Figure out if this directory is a mount point.  */
169       if (stat (dotp, &st) < 0)
170         goto lose;
171       dotdev = st.st_dev;
172       dotino = st.st_ino;
173       mount_point = dotdev != thisdev;
174
175       /* Search for the last directory.  */
176       dirstream = opendir (dotp);
177       if (dirstream == NULL)
178         goto lose;
179       while ((d = readdir (dirstream)) != NULL)
180         {
181           if (d->d_name[0] == '.' &&
182               (d->d_name[1] == '\0' ||
183                 (d->d_name[1] == '.' && d->d_name[2] == '\0')))
184             continue;
185           if (mount_point || d->d_fileno == thisino)
186             {
187               char *name;
188
189               namlen = D_NAMLEN(d);
190               name = (char *)
191                 alloca (dotlist + dotsize - dotp + 1 + namlen + 1);
192               memcpy (name, dotp, dotlist + dotsize - dotp);
193               name[dotlist + dotsize - dotp] = '/';
194               memcpy (&name[dotlist + dotsize - dotp + 1],
195                       d->d_name, namlen + 1);
196               if (lstat (name, &st) < 0)
197                 {
198                   int save = errno;
199                   (void) closedir (dirstream);
200                   errno = save;
201                   goto lose;
202                 }
203               if (st.st_dev == thisdev && st.st_ino == thisino)
204                 break;
205             }
206         }
207       if (d == NULL)
208         {
209           int save = errno;
210           (void) closedir (dirstream);
211           errno = save;
212           goto lose;
213         }
214       else
215         {
216           size_t space;
217
218           while ((space = pathp - pathbuf) <= namlen)
219             {
220               char *new;
221
222               if (pathbuf == path)
223                 {
224                   new = malloc (pathsize * 2);
225                   if (!new)
226                     goto lose;
227                 }
228               else
229                 {
230                   new = realloc ((PTR) pathbuf, (pathsize * 2));
231                   if (!new)
232                     goto lose;
233                   pathp = new + space;
234                 }
235               (void) memcpy (new + pathsize + space, pathp, pathsize - space);
236               pathp = new + pathsize + space;
237               pathbuf = new;
238               pathsize *= 2;
239             }
240
241           pathp -= namlen;
242           (void) memcpy (pathp, d->d_name, namlen);
243           *--pathp = '/';
244           (void) closedir (dirstream);
245         }
246
247       thisdev = dotdev;
248       thisino = dotino;
249     }
250
251   if (pathp == &path[sizeof(path) - 1])
252     *--pathp = '/';
253
254   if (dotlist != dots)
255     free ((PTR) dotlist);
256
257   {
258     size_t len = pathbuf + pathsize - pathp;
259     if (buf == NULL)
260       {
261         if (len < (size_t) size)
262           len = size;
263         buf = (char *) malloc (len);
264         if (buf == NULL)
265           goto lose2;
266       }
267     else if ((size_t) size < len)
268       {
269         errno = ERANGE;
270         goto lose2;
271       }
272     (void) memcpy((PTR) buf, (PTR) pathp, len);
273   }
274
275   if (pathbuf != path)
276     free (pathbuf);
277
278   return (buf);
279
280  lose:
281   if ((dotlist != dots) && dotlist)
282     {
283       int e = errno;
284       free ((PTR) dotlist);
285       errno = e;
286     }
287
288  lose2:
289   if ((pathbuf != path) && pathbuf)
290     {
291       int e = errno;
292       free ((PTR) pathbuf);
293       errno = e;
294     }
295   return ((char *)NULL);
296 }
297
298 #if defined (TEST)
299 #  include <stdio.h>
300 main (argc, argv)
301      int argc;
302      char **argv;
303 {
304   char b[PATH_MAX];
305
306   if (getcwd(b, sizeof(b)))
307     {
308       printf ("%s\n", b);
309       exit (0);
310     }
311   else
312     {
313       perror ("cwd: getcwd");
314       exit (1);
315     }
316 }
317 #endif /* TEST */
318 #endif /* !HAVE_GETCWD */