]> git.ipfire.org Git - thirdparty/bash.git/blob - lib/sh/getcwd.c
Imported from ../bash-2.02.tar.gz.
[thirdparty/bash.git] / lib / sh / 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 int saved_errno;
98
99 if (buf != NULL && size == 0)
100 {
101 errno = EINVAL;
102 return ((char *)NULL);
103 }
104
105 pathsize = sizeof (path);
106 pathp = &path[pathsize];
107 *--pathp = '\0';
108 pathbuf = path;
109
110 if (stat (".", &st) < 0)
111 return ((char *)NULL);
112 thisdev = st.st_dev;
113 thisino = st.st_ino;
114
115 if (stat ("/", &st) < 0)
116 return ((char *)NULL);
117 rootdev = st.st_dev;
118 rootino = st.st_ino;
119
120 saved_errno = 0;
121
122 dotsize = sizeof (dots) - 1;
123 dotp = &dots[sizeof (dots)];
124 dotlist = dots;
125 while (!(thisdev == rootdev && thisino == rootino))
126 {
127 register DIR *dirstream;
128 register struct dirent *d;
129 dev_t dotdev;
130 ino_t dotino;
131 char mount_point;
132 int namlen;
133
134 /* Look at the parent directory. */
135 if (dotp == dotlist)
136 {
137 /* My, what a deep directory tree you have, Grandma. */
138 char *new;
139 if (dotlist == dots)
140 {
141 new = malloc (dotsize * 2 + 1);
142 if (new == NULL)
143 goto lose;
144 memcpy (new, dots, dotsize);
145 }
146 else
147 {
148 new = realloc ((PTR) dotlist, dotsize * 2 + 1);
149 if (new == NULL)
150 goto lose;
151 }
152 memcpy (&new[dotsize], new, dotsize);
153 dotp = &new[dotsize];
154 dotsize *= 2;
155 new[dotsize] = '\0';
156 dotlist = new;
157 }
158
159 dotp -= 3;
160
161 /* Figure out if this directory is a mount point. */
162 if (stat (dotp, &st) < 0)
163 goto lose;
164 dotdev = st.st_dev;
165 dotino = st.st_ino;
166 mount_point = dotdev != thisdev;
167
168 /* Search for the last directory. */
169 dirstream = opendir (dotp);
170 if (dirstream == NULL)
171 goto lose;
172 while ((d = readdir (dirstream)) != NULL)
173 {
174 if (d->d_name[0] == '.' &&
175 (d->d_name[1] == '\0' ||
176 (d->d_name[1] == '.' && d->d_name[2] == '\0')))
177 continue;
178 if (mount_point || d->d_fileno == thisino)
179 {
180 char *name;
181
182 namlen = D_NAMLEN(d);
183 name = (char *)
184 alloca (dotlist + dotsize - dotp + 1 + namlen + 1);
185 memcpy (name, dotp, dotlist + dotsize - dotp);
186 name[dotlist + dotsize - dotp] = '/';
187 memcpy (&name[dotlist + dotsize - dotp + 1],
188 d->d_name, namlen + 1);
189 if (lstat (name, &st) < 0)
190 {
191 #if 0
192 int save = errno;
193 (void) closedir (dirstream);
194 errno = save;
195 goto lose;
196 #else
197 saved_errno = errno;
198 #endif
199 }
200 if (st.st_dev == thisdev && st.st_ino == thisino)
201 break;
202 }
203 }
204 if (d == NULL)
205 {
206 #if 0
207 int save = errno;
208 #else
209 int save = errno ? errno : saved_errno;
210 #endif
211 (void) closedir (dirstream);
212 errno = save;
213 goto lose;
214 }
215 else
216 {
217 size_t space;
218
219 while ((space = pathp - pathbuf) <= namlen)
220 {
221 char *new;
222
223 if (pathbuf == path)
224 {
225 new = malloc (pathsize * 2);
226 if (!new)
227 goto lose;
228 }
229 else
230 {
231 new = realloc ((PTR) pathbuf, (pathsize * 2));
232 if (!new)
233 goto lose;
234 pathp = new + space;
235 }
236 (void) memcpy (new + pathsize + space, pathp, pathsize - space);
237 pathp = new + pathsize + space;
238 pathbuf = new;
239 pathsize *= 2;
240 }
241
242 pathp -= namlen;
243 (void) memcpy (pathp, d->d_name, namlen);
244 *--pathp = '/';
245 (void) closedir (dirstream);
246 }
247
248 thisdev = dotdev;
249 thisino = dotino;
250 }
251
252 if (pathp == &path[sizeof(path) - 1])
253 *--pathp = '/';
254
255 if (dotlist != dots)
256 free ((PTR) dotlist);
257
258 {
259 size_t len = pathbuf + pathsize - pathp;
260 if (buf == NULL)
261 {
262 if (len < (size_t) size)
263 len = size;
264 buf = (char *) malloc (len);
265 if (buf == NULL)
266 goto lose2;
267 }
268 else if ((size_t) size < len)
269 {
270 errno = ERANGE;
271 goto lose2;
272 }
273 (void) memcpy((PTR) buf, (PTR) pathp, len);
274 }
275
276 if (pathbuf != path)
277 free (pathbuf);
278
279 return (buf);
280
281 lose:
282 if ((dotlist != dots) && dotlist)
283 {
284 int e = errno;
285 free ((PTR) dotlist);
286 errno = e;
287 }
288
289 lose2:
290 if ((pathbuf != path) && pathbuf)
291 {
292 int e = errno;
293 free ((PTR) pathbuf);
294 errno = e;
295 }
296 return ((char *)NULL);
297 }
298
299 #if defined (TEST)
300 # include <stdio.h>
301 main (argc, argv)
302 int argc;
303 char **argv;
304 {
305 char b[PATH_MAX];
306
307 if (getcwd(b, sizeof(b)))
308 {
309 printf ("%s\n", b);
310 exit (0);
311 }
312 else
313 {
314 perror ("cwd: getcwd");
315 exit (1);
316 }
317 }
318 #endif /* TEST */
319 #endif /* !HAVE_GETCWD */