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