]> git.ipfire.org Git - thirdparty/bash.git/blob - getcwd.c
Imported from ../bash-2.01.tar.gz.
[thirdparty/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 #include "bashansi.h"
42
43 #if !defined (errno)
44 extern int errno;
45 #endif /* !errno */
46
47 #if defined (__STDC__)
48 # define CONST const
49 # define PTR void *
50 #else /* !__STDC__ */
51 # define CONST
52 # define PTR char *
53 #endif /* !__STDC__ */
54
55 #if !defined (PATH_MAX)
56 # if defined (MAXPATHLEN)
57 # define PATH_MAX MAXPATHLEN
58 # else /* !MAXPATHLEN */
59 # define PATH_MAX 1024
60 # endif /* !MAXPATHLEN */
61 #endif /* !PATH_MAX */
62
63 #if !defined (HAVE_LSTAT)
64 # define lstat stat
65 #endif
66
67 /* Get the pathname of the current working directory,
68 and put it in SIZE bytes of BUF. Returns NULL if the
69 directory couldn't be determined or SIZE was too small.
70 If successful, returns BUF. In GNU, if BUF is NULL,
71 an array is allocated with `malloc'; the array is SIZE
72 bytes long, unless SIZE <= 0, in which case it is as
73 big as necessary. */
74 #if defined (__STDC__)
75 char *
76 getcwd (char *buf, size_t size)
77 #else /* !__STDC__ */
78 char *
79 getcwd (buf, size)
80 char *buf;
81 size_t size;
82 #endif /* !__STDC__ */
83 {
84 static CONST char dots[]
85 = "../../../../../../../../../../../../../../../../../../../../../../../\
86 ../../../../../../../../../../../../../../../../../../../../../../../../../../\
87 ../../../../../../../../../../../../../../../../../../../../../../../../../..";
88 CONST char *dotp, *dotlist;
89 size_t dotsize;
90 dev_t rootdev, thisdev;
91 ino_t rootino, thisino;
92 char path[PATH_MAX + 1];
93 register char *pathp;
94 char *pathbuf;
95 size_t pathsize;
96 struct stat st;
97
98 if (buf != NULL && size == 0)
99 {
100 errno = EINVAL;
101 return ((char *)NULL);
102 }
103
104 pathsize = sizeof (path);
105 pathp = &path[pathsize];
106 *--pathp = '\0';
107 pathbuf = path;
108
109 if (stat (".", &st) < 0)
110 return ((char *)NULL);
111 thisdev = st.st_dev;
112 thisino = st.st_ino;
113
114 if (stat ("/", &st) < 0)
115 return ((char *)NULL);
116 rootdev = st.st_dev;
117 rootino = st.st_ino;
118
119 dotsize = sizeof (dots) - 1;
120 dotp = &dots[sizeof (dots)];
121 dotlist = dots;
122 while (!(thisdev == rootdev && thisino == rootino))
123 {
124 register DIR *dirstream;
125 register struct dirent *d;
126 dev_t dotdev;
127 ino_t dotino;
128 char mount_point;
129 int namlen;
130
131 /* Look at the parent directory. */
132 if (dotp == dotlist)
133 {
134 /* My, what a deep directory tree you have, Grandma. */
135 char *new;
136 if (dotlist == dots)
137 {
138 new = malloc (dotsize * 2 + 1);
139 if (new == NULL)
140 goto lose;
141 memcpy (new, dots, dotsize);
142 }
143 else
144 {
145 new = realloc ((PTR) dotlist, dotsize * 2 + 1);
146 if (new == NULL)
147 goto lose;
148 }
149 memcpy (&new[dotsize], new, dotsize);
150 dotp = &new[dotsize];
151 dotsize *= 2;
152 new[dotsize] = '\0';
153 dotlist = new;
154 }
155
156 dotp -= 3;
157
158 /* Figure out if this directory is a mount point. */
159 if (stat (dotp, &st) < 0)
160 goto lose;
161 dotdev = st.st_dev;
162 dotino = st.st_ino;
163 mount_point = dotdev != thisdev;
164
165 /* Search for the last directory. */
166 dirstream = opendir (dotp);
167 if (dirstream == NULL)
168 goto lose;
169 while ((d = readdir (dirstream)) != NULL)
170 {
171 if (d->d_name[0] == '.' &&
172 (d->d_name[1] == '\0' ||
173 (d->d_name[1] == '.' && d->d_name[2] == '\0')))
174 continue;
175 if (mount_point || d->d_fileno == thisino)
176 {
177 char *name;
178
179 namlen = D_NAMLEN(d);
180 name = (char *)
181 alloca (dotlist + dotsize - dotp + 1 + namlen + 1);
182 memcpy (name, dotp, dotlist + dotsize - dotp);
183 name[dotlist + dotsize - dotp] = '/';
184 memcpy (&name[dotlist + dotsize - dotp + 1],
185 d->d_name, namlen + 1);
186 if (lstat (name, &st) < 0)
187 {
188 int save = errno;
189 (void) closedir (dirstream);
190 errno = save;
191 goto lose;
192 }
193 if (st.st_dev == thisdev && st.st_ino == thisino)
194 break;
195 }
196 }
197 if (d == NULL)
198 {
199 int save = errno;
200 (void) closedir (dirstream);
201 errno = save;
202 goto lose;
203 }
204 else
205 {
206 size_t space;
207
208 while ((space = pathp - pathbuf) <= namlen)
209 {
210 char *new;
211
212 if (pathbuf == path)
213 {
214 new = malloc (pathsize * 2);
215 if (!new)
216 goto lose;
217 }
218 else
219 {
220 new = realloc ((PTR) pathbuf, (pathsize * 2));
221 if (!new)
222 goto lose;
223 pathp = new + space;
224 }
225 (void) memcpy (new + pathsize + space, pathp, pathsize - space);
226 pathp = new + pathsize + space;
227 pathbuf = new;
228 pathsize *= 2;
229 }
230
231 pathp -= namlen;
232 (void) memcpy (pathp, d->d_name, namlen);
233 *--pathp = '/';
234 (void) closedir (dirstream);
235 }
236
237 thisdev = dotdev;
238 thisino = dotino;
239 }
240
241 if (pathp == &path[sizeof(path) - 1])
242 *--pathp = '/';
243
244 if (dotlist != dots)
245 free ((PTR) dotlist);
246
247 {
248 size_t len = pathbuf + pathsize - pathp;
249 if (buf == NULL)
250 {
251 if (len < (size_t) size)
252 len = size;
253 buf = (char *) malloc (len);
254 if (buf == NULL)
255 goto lose2;
256 }
257 else if ((size_t) size < len)
258 {
259 errno = ERANGE;
260 goto lose2;
261 }
262 (void) memcpy((PTR) buf, (PTR) pathp, len);
263 }
264
265 if (pathbuf != path)
266 free (pathbuf);
267
268 return (buf);
269
270 lose:
271 if ((dotlist != dots) && dotlist)
272 {
273 int e = errno;
274 free ((PTR) dotlist);
275 errno = e;
276 }
277
278 lose2:
279 if ((pathbuf != path) && pathbuf)
280 {
281 int e = errno;
282 free ((PTR) pathbuf);
283 errno = e;
284 }
285 return ((char *)NULL);
286 }
287
288 #if defined (TEST)
289 # include <stdio.h>
290 main (argc, argv)
291 int argc;
292 char **argv;
293 {
294 char b[PATH_MAX];
295
296 if (getcwd(b, sizeof(b)))
297 {
298 printf ("%s\n", b);
299 exit (0);
300 }
301 else
302 {
303 perror ("cwd: getcwd");
304 exit (1);
305 }
306 }
307 #endif /* TEST */
308 #endif /* !HAVE_GETCWD */