]> git.ipfire.org Git - thirdparty/bash.git/blob - getcwd.c
Imported from ../bash-2.0.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 #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 */