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