| 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)
|
|---|
| 255 | {
|
|---|
| 256 | if (len < (size_t) size)
|
|---|
| 257 | len = size;
|
|---|
| 258 | buf = (char *) malloc (len);
|
|---|
| 259 | if (buf == NULL)
|
|---|
| 260 | goto lose2;
|
|---|
| 261 | }
|
|---|
| 262 | else if ((size_t) size < len)
|
|---|
| 263 | {
|
|---|
| 264 | errno = ERANGE;
|
|---|
| 265 | goto lose2;
|
|---|
| 266 | }
|
|---|
| 267 | (void) memcpy((PTR_T) buf, (PTR_T) pathp, len);
|
|---|
| 268 | }
|
|---|
| 269 |
|
|---|
| 270 | if (pathbuf != path)
|
|---|
| 271 | free (pathbuf);
|
|---|
| 272 |
|
|---|
| 273 | return (buf);
|
|---|
| 274 |
|
|---|
| 275 | lose:
|
|---|
| 276 | if ((dotlist != dots) && dotlist)
|
|---|
| 277 | {
|
|---|
| 278 | int e = errno;
|
|---|
| 279 | free ((PTR_T) dotlist);
|
|---|
| 280 | errno = e;
|
|---|
| 281 | }
|
|---|
| 282 |
|
|---|
| 283 | lose2:
|
|---|
| 284 | if ((pathbuf != path) && pathbuf)
|
|---|
| 285 | {
|
|---|
| 286 | int e = errno;
|
|---|
| 287 | free ((PTR_T) pathbuf);
|
|---|
| 288 | errno = e;
|
|---|
| 289 | }
|
|---|
| 290 | return ((char *)NULL);
|
|---|
| 291 | }
|
|---|
| 292 |
|
|---|
| 293 | #if defined (TEST)
|
|---|
| 294 | # include <stdio.h>
|
|---|
| 295 | main (argc, argv)
|
|---|
| 296 | int argc;
|
|---|
| 297 | char **argv;
|
|---|
| 298 | {
|
|---|
| 299 | char b[PATH_MAX];
|
|---|
| 300 |
|
|---|
| 301 | if (getcwd(b, sizeof(b)))
|
|---|
| 302 | {
|
|---|
| 303 | printf ("%s\n", b);
|
|---|
| 304 | exit (0);
|
|---|
| 305 | }
|
|---|
| 306 | else
|
|---|
| 307 | {
|
|---|
| 308 | perror ("cwd: getcwd");
|
|---|
| 309 | exit (1);
|
|---|
| 310 | }
|
|---|
| 311 | }
|
|---|
| 312 | #endif /* TEST */
|
|---|
| 313 | #endif /* !HAVE_GETCWD */
|
|---|