diff options
author | An-Cheng Huang <ancheng@vyatta.com> | 2007-11-12 13:06:02 -0800 |
---|---|---|
committer | An-Cheng Huang <ancheng@vyatta.com> | 2007-11-12 13:06:02 -0800 |
commit | b7fc9e0f6d6105ba2203f219743d4b269415e84b (patch) | |
tree | ef6586dfc62798c2b17487b443864699aca55f31 /lib/sh/getcwd.c | |
download | vyatta-bash-b7fc9e0f6d6105ba2203f219743d4b269415e84b.tar.gz vyatta-bash-b7fc9e0f6d6105ba2203f219743d4b269415e84b.zip |
initial import from bash_3.1dfsg.orig.tar.gz
Diffstat (limited to 'lib/sh/getcwd.c')
-rw-r--r-- | lib/sh/getcwd.c | 313 |
1 files changed, 313 insertions, 0 deletions
diff --git a/lib/sh/getcwd.c b/lib/sh/getcwd.c new file mode 100644 index 0000000..cd724f6 --- /dev/null +++ b/lib/sh/getcwd.c @@ -0,0 +1,313 @@ +/* getcwd.c -- stolen from the GNU C library and modified to work with bash. */ + +/* Copyright (C) 1991 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with the GNU C Library; see the file COPYING.LIB. If + not, write to the Free Software Foundation, Inc., + 59 Temple Place, Suite 330, Boston, MA 02111 USA. */ + +#include <config.h> + +#if !defined (HAVE_GETCWD) + +#if !defined (__GNUC__) && !defined (HAVE_ALLOCA_H) && defined (_AIX) + #pragma alloca +#endif /* _AIX && RISC6000 && !__GNUC__ */ + +#include <bashtypes.h> +#include <errno.h> + +#if defined (HAVE_LIMITS_H) +# include <limits.h> +#endif + +#if defined (HAVE_UNISTD_H) +# include <unistd.h> +#endif + +#include <posixdir.h> +#include <posixstat.h> +#include <maxpath.h> +#include <memalloc.h> + +#include <bashansi.h> + +#include <xmalloc.h> + +#if !defined (errno) +extern int errno; +#endif /* !errno */ + +#if !defined (HAVE_LSTAT) +# define lstat stat +#endif + +#if !defined (NULL) +# define NULL 0 +#endif + +/* Get the pathname of the current working directory, + and put it in SIZE bytes of BUF. Returns NULL if the + directory couldn't be determined or SIZE was too small. + If successful, returns BUF. In GNU, if BUF is NULL, + an array is allocated with `malloc'; the array is SIZE + bytes long, unless SIZE <= 0, in which case it is as + big as necessary. */ +#if defined (__STDC__) +char * +getcwd (char *buf, size_t size) +#else /* !__STDC__ */ +char * +getcwd (buf, size) + char *buf; + size_t size; +#endif /* !__STDC__ */ +{ + static const char dots[] + = "../../../../../../../../../../../../../../../../../../../../../../../\ +../../../../../../../../../../../../../../../../../../../../../../../../../../\ +../../../../../../../../../../../../../../../../../../../../../../../../../.."; + const char *dotp, *dotlist; + size_t dotsize; + dev_t rootdev, thisdev; + ino_t rootino, thisino; + char path[PATH_MAX + 1]; + register char *pathp; + char *pathbuf; + size_t pathsize; + struct stat st; + int saved_errno; + + if (buf != NULL && size == 0) + { + errno = EINVAL; + return ((char *)NULL); + } + + pathsize = sizeof (path); + pathp = &path[pathsize]; + *--pathp = '\0'; + pathbuf = path; + + if (stat (".", &st) < 0) + return ((char *)NULL); + thisdev = st.st_dev; + thisino = st.st_ino; + + if (stat ("/", &st) < 0) + return ((char *)NULL); + rootdev = st.st_dev; + rootino = st.st_ino; + + saved_errno = 0; + + dotsize = sizeof (dots) - 1; + dotp = &dots[sizeof (dots)]; + dotlist = dots; + while (!(thisdev == rootdev && thisino == rootino)) + { + register DIR *dirstream; + register struct dirent *d; + dev_t dotdev; + ino_t dotino; + char mount_point; + int namlen; + + /* Look at the parent directory. */ + if (dotp == dotlist) + { + /* My, what a deep directory tree you have, Grandma. */ + char *new; + if (dotlist == dots) + { + new = (char *)malloc (dotsize * 2 + 1); + if (new == NULL) + goto lose; + memcpy (new, dots, dotsize); + } + else + { + new = (char *)realloc ((PTR_T) dotlist, dotsize * 2 + 1); + if (new == NULL) + goto lose; + } + memcpy (&new[dotsize], new, dotsize); + dotp = &new[dotsize]; + dotsize *= 2; + new[dotsize] = '\0'; + dotlist = new; + } + + dotp -= 3; + + /* Figure out if this directory is a mount point. */ + if (stat (dotp, &st) < 0) + goto lose; + dotdev = st.st_dev; + dotino = st.st_ino; + mount_point = dotdev != thisdev; + + /* Search for the last directory. */ + dirstream = opendir (dotp); + if (dirstream == NULL) + goto lose; + while ((d = readdir (dirstream)) != NULL) + { + if (d->d_name[0] == '.' && + (d->d_name[1] == '\0' || + (d->d_name[1] == '.' && d->d_name[2] == '\0'))) + continue; + if (mount_point || d->d_fileno == thisino) + { + char *name; + + namlen = D_NAMLEN(d); + name = (char *) + alloca (dotlist + dotsize - dotp + 1 + namlen + 1); + memcpy (name, dotp, dotlist + dotsize - dotp); + name[dotlist + dotsize - dotp] = '/'; + memcpy (&name[dotlist + dotsize - dotp + 1], + d->d_name, namlen + 1); + if (lstat (name, &st) < 0) + { +#if 0 + int save = errno; + (void) closedir (dirstream); + errno = save; + goto lose; +#else + saved_errno = errno; +#endif + } + if (st.st_dev == thisdev && st.st_ino == thisino) + break; + } + } + if (d == NULL) + { +#if 0 + int save = errno; +#else + int save = errno ? errno : saved_errno; +#endif + (void) closedir (dirstream); + errno = save; + goto lose; + } + else + { + size_t space; + + while ((space = pathp - pathbuf) <= namlen) + { + char *new; + + if (pathbuf == path) + { + new = (char *)malloc (pathsize * 2); + if (!new) + goto lose; + } + else + { + new = (char *)realloc ((PTR_T) pathbuf, (pathsize * 2)); + if (!new) + goto lose; + pathp = new + space; + } + (void) memcpy (new + pathsize + space, pathp, pathsize - space); + pathp = new + pathsize + space; + pathbuf = new; + pathsize *= 2; + } + + pathp -= namlen; + (void) memcpy (pathp, d->d_name, namlen); + *--pathp = '/'; + (void) closedir (dirstream); + } + + thisdev = dotdev; + thisino = dotino; + } + + if (pathp == &path[sizeof(path) - 1]) + *--pathp = '/'; + + if (dotlist != dots) + free ((PTR_T) dotlist); + + { + size_t len = pathbuf + pathsize - pathp; + if (buf == NULL) + { + if (len < (size_t) size) + len = size; + buf = (char *) malloc (len); + if (buf == NULL) + goto lose2; + } + else if ((size_t) size < len) + { + errno = ERANGE; + goto lose2; + } + (void) memcpy((PTR_T) buf, (PTR_T) pathp, len); + } + + if (pathbuf != path) + free (pathbuf); + + return (buf); + + lose: + if ((dotlist != dots) && dotlist) + { + int e = errno; + free ((PTR_T) dotlist); + errno = e; + } + + lose2: + if ((pathbuf != path) && pathbuf) + { + int e = errno; + free ((PTR_T) pathbuf); + errno = e; + } + return ((char *)NULL); +} + +#if defined (TEST) +# include <stdio.h> +main (argc, argv) + int argc; + char **argv; +{ + char b[PATH_MAX]; + + if (getcwd(b, sizeof(b))) + { + printf ("%s\n", b); + exit (0); + } + else + { + perror ("cwd: getcwd"); + exit (1); + } +} +#endif /* TEST */ +#endif /* !HAVE_GETCWD */ |