1 /* getcwd.c -- get pathname of current directory */
3 /* Copyright (C) 1991 Free Software Foundation, Inc.
5 This file is part of GNU Bash, the Bourne Again SHell.
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.
12 Bash is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
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/>.
23 #if !defined (HAVE_GETCWD)
25 #if !defined (__GNUC__) && !defined (HAVE_ALLOCA_H) && defined (_AIX)
27 #endif /* _AIX && RISC6000 && !__GNUC__ */
33 #include <bashtypes.h>
36 #if defined (HAVE_LIMITS_H)
40 #if defined (HAVE_UNISTD_H)
45 #include <posixstat.h>
57 #if !defined (HAVE_LSTAT)
65 /* If the d_fileno member of a struct dirent doesn't return anything useful,
66 we need to check inode number equivalence the hard way. Return 1 if
67 the inode corresponding to PATH/DIR is identical to THISINO. */
68 #if defined (BROKEN_DIRENT_D_INO)
70 _path_checkino (dotp, name, thisino)
80 fullpath = sh_makepath (dotp, name, MP_RMDOT);
81 if (stat (fullpath, &st) < 0)
88 return (st.st_ino == thisino);
92 /* Get the pathname of the current working directory,
93 and put it in SIZE bytes of BUF. Returns NULL if the
94 directory couldn't be determined or SIZE was too small.
95 If successful, returns BUF. In GNU, if BUF is NULL,
96 an array is allocated with `malloc'; the array is SIZE
97 bytes long, unless SIZE <= 0, in which case it is as
99 #if defined (__STDC__)
101 getcwd (char *buf, size_t size)
102 #else /* !__STDC__ */
107 #endif /* !__STDC__ */
109 static const char dots[]
110 = "../../../../../../../../../../../../../../../../../../../../../../../\
111 ../../../../../../../../../../../../../../../../../../../../../../../../../../\
112 ../../../../../../../../../../../../../../../../../../../../../../../../../..";
113 const char *dotp, *dotlist;
115 dev_t rootdev, thisdev;
116 ino_t rootino, thisino;
117 char path[PATH_MAX + 1];
118 register char *pathp;
124 if (buf != NULL && size == 0)
127 return ((char *)NULL);
130 pathsize = sizeof (path);
131 pathp = &path[pathsize];
135 if (stat (".", &st) < 0)
136 return ((char *)NULL);
140 if (stat ("/", &st) < 0)
141 return ((char *)NULL);
147 dotsize = sizeof (dots) - 1;
148 dotp = &dots[sizeof (dots)];
150 while (!(thisdev == rootdev && thisino == rootino))
152 register DIR *dirstream;
153 register struct dirent *d;
159 /* Look at the parent directory. */
162 /* My, what a deep directory tree you have, Grandma. */
166 new = (char *)malloc (dotsize * 2 + 1);
169 memcpy (new, dots, dotsize);
173 new = (char *)realloc ((PTR_T) dotlist, dotsize * 2 + 1);
177 memcpy (&new[dotsize], new, dotsize);
178 dotp = &new[dotsize];
186 /* Figure out if this directory is a mount point. */
187 if (stat (dotp, &st) < 0)
191 mount_point = dotdev != thisdev;
193 /* Search for the last directory. */
194 dirstream = opendir (dotp);
195 if (dirstream == NULL)
197 while ((d = readdir (dirstream)) != NULL)
199 if (d->d_name[0] == '.' &&
200 (d->d_name[1] == '\0' ||
201 (d->d_name[1] == '.' && d->d_name[2] == '\0')))
203 #if !defined (BROKEN_DIRENT_D_INO)
204 if (mount_point || d->d_fileno == thisino)
206 if (mount_point || _path_checkino (dotp, d->d_name, thisino))
211 namlen = D_NAMLEN(d);
213 alloca (dotlist + dotsize - dotp + 1 + namlen + 1);
214 memcpy (name, dotp, dotlist + dotsize - dotp);
215 name[dotlist + dotsize - dotp] = '/';
216 memcpy (&name[dotlist + dotsize - dotp + 1],
217 d->d_name, namlen + 1);
218 if (lstat (name, &st) < 0)
222 (void) closedir (dirstream);
229 if (st.st_dev == thisdev && st.st_ino == thisino)
238 int save = errno ? errno : saved_errno;
240 (void) closedir (dirstream);
248 while ((space = pathp - pathbuf) <= namlen)
254 new = (char *)malloc (pathsize * 2);
260 new = (char *)realloc ((PTR_T) pathbuf, (pathsize * 2));
265 (void) memcpy (new + pathsize + space, pathp, pathsize - space);
266 pathp = new + pathsize + space;
272 (void) memcpy (pathp, d->d_name, namlen);
274 (void) closedir (dirstream);
281 if (pathp == &path[sizeof(path) - 1])
285 free ((PTR_T) dotlist);
288 size_t len = pathbuf + pathsize - pathp;
289 if (buf == NULL && size <= 0)
292 if ((size_t) size < len)
299 buf = (char *) malloc (size);
304 (void) memcpy((PTR_T) buf, (PTR_T) pathp, len);
313 if ((dotlist != dots) && dotlist)
316 free ((PTR_T) dotlist);
321 if ((pathbuf != path) && pathbuf)
324 free ((PTR_T) pathbuf);
327 return ((char *)NULL);
338 if (getcwd(b, sizeof(b)))
345 perror ("cwd: getcwd");
350 #endif /* !HAVE_GETCWD */