| /* Copyright (C) 1991,92,93,94,95,96,97,98,99 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 Lesser General Public |
| License as published by the Free Software Foundation; either |
| version 2.1 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 |
| Lesser General Public License for more details. |
| |
| You should have received a copy of the GNU Lesser General Public |
| License along with the GNU C Library; if not, write to the Free |
| Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA |
| 02111-1307 USA. */ |
| |
| /* Wants: |
| AC_STDC_HEADERS |
| AC_DIR_HEADER |
| AC_UNISTD_H |
| AC_MEMORY_H |
| AC_CONST |
| AC_ALLOCA |
| */ |
| |
| /* |
| * $Id: /var/cvsroot/gentoo-src/portage/src/sandbox-1.1/Attic/getcwd.c,v 1.1.2.1 2004/10/22 16:53:30 carpaski Exp $ |
| */ |
| |
| /* Modified: 26 July 2003; Martin Schlemmer <azarah@gentoo.org> |
| * |
| * Cleaned up unneeded stuff. Add a wrapper to try and detect when |
| * we have a kernel whose getcwd system call do not handle directory |
| * names longer than PATH_MAX, and if so, use our generic version. |
| * To work truly with > PATH_MAX lengh CWDs, I had to increase the |
| * size of the dots[] array. Also prepended a 'e' to functions that |
| * I did not rip out. |
| * |
| */ |
| |
| /* AIX requires this to be the first thing in the file. */ |
| #if defined _AIX && !defined __GNUC__ |
| #pragma alloca |
| #endif |
| |
| #ifdef HAVE_CONFIG_H |
| # include "config.h" |
| #endif |
| |
| #include <errno.h> |
| #include <sys/types.h> |
| #include <sys/stat.h> |
| |
| #ifdef STDC_HEADERS |
| # include <stddef.h> |
| #endif |
| |
| #if !defined __GNU_LIBRARY__ && !defined STDC_HEADERS |
| extern int errno; |
| #endif |
| #ifndef __set_errno |
| # define __set_errno(val) errno = (val) |
| #endif |
| |
| #ifndef NULL |
| # define NULL 0 |
| #endif |
| |
| #if defined USGr3 && !defined DIRENT |
| # define DIRENT |
| #endif /* USGr3 */ |
| #if defined Xenix && !defined SYSNDIR |
| # define SYSNDIR |
| #endif /* Xenix */ |
| |
| #if defined POSIX || defined DIRENT || defined __GNU_LIBRARY__ |
| # include <dirent.h> |
| # ifndef __GNU_LIBRARY__ |
| # define D_NAMLEN(d) strlen((d)->d_name) |
| # else |
| # define HAVE_D_NAMLEN |
| # define D_NAMLEN(d) ((d)->d_namlen) |
| # endif |
| #else /* not POSIX or DIRENT */ |
| # define dirent direct |
| # define D_NAMLEN(d) ((d)->d_namlen) |
| # define HAVE_D_NAMLEN |
| # if defined USG && !defined sgi |
| # if defined SYSNDIR |
| # include <sys/ndir.h> |
| # else /* Not SYSNDIR */ |
| # include "ndir.h" |
| # endif /* SYSNDIR */ |
| # else /* not USG */ |
| # include <sys/dir.h> |
| # endif /* USG */ |
| #endif /* POSIX or DIRENT or __GNU_LIBRARY__ */ |
| |
| #if defined HAVE_UNISTD_H || defined __GNU_LIBRARY__ |
| # include <unistd.h> |
| #endif |
| |
| #if defined STDC_HEADERS || defined __GNU_LIBRARY__ || defined POSIX |
| # include <stdlib.h> |
| # include <string.h> |
| # define ANSI_STRING |
| #else /* No standard headers. */ |
| |
| # ifdef USG |
| |
| # include <string.h> |
| # ifdef NEED_MEMORY_H |
| # include <memory.h> |
| # endif |
| # define ANSI_STRING |
| |
| # else /* Not USG. */ |
| |
| # ifdef NeXT |
| |
| # include <string.h> |
| |
| # else /* Not NeXT. */ |
| |
| # include <strings.h> |
| |
| # ifndef bcmp |
| extern int bcmp(); |
| # endif |
| # ifndef bzero |
| extern void bzero(); |
| # endif |
| # ifndef bcopy |
| extern void bcopy(); |
| # endif |
| |
| # endif /* NeXT. */ |
| |
| # endif /* USG. */ |
| |
| extern char *malloc(), *realloc(); |
| extern void free(); |
| |
| #endif /* Standard headers. */ |
| |
| #ifndef ANSI_STRING |
| # define memcpy(d, s, n) bcopy((s), (d), (n)) |
| # define memmove memcpy |
| #endif /* Not ANSI_STRING. */ |
| |
| #ifndef MAX |
| # define MAX(a, b) ((a) < (b) ? (b) : (a)) |
| #endif |
| |
| #ifdef _LIBC |
| # ifndef mempcpy |
| # define mempcpy __mempcpy |
| # endif |
| # define HAVE_MEMPCPY 1 |
| #endif |
| |
| #if !defined __alloca && !defined __GNU_LIBRARY__ |
| |
| # ifdef __GNUC__ |
| # undef alloca |
| # define alloca(n) __builtin_alloca (n) |
| # else /* Not GCC. */ |
| # if defined sparc || defined HAVE_ALLOCA_H |
| # include <alloca.h> |
| # else /* Not sparc or HAVE_ALLOCA_H. */ |
| # ifndef _AIX |
| extern char *alloca(); |
| # endif /* Not _AIX. */ |
| # endif /* sparc or HAVE_ALLOCA_H. */ |
| # endif /* GCC. */ |
| |
| # define __alloca alloca |
| |
| #endif |
| |
| #if defined HAVE_LIMITS_H || defined STDC_HEADERS || defined __GNU_LIBRARY__ |
| # include <limits.h> |
| #else |
| # include <sys/param.h> |
| #endif |
| |
| #ifndef PATH_MAX |
| # ifdef MAXPATHLEN |
| # define PATH_MAX MAXPATHLEN |
| # else |
| # define PATH_MAX 1024 |
| # endif |
| #endif |
| |
| #if !defined STDC_HEADERS && !defined __GNU_LIBRARY__ |
| # undef size_t |
| # define size_t unsigned int |
| #endif |
| |
| #if !__STDC__ && !defined const |
| # define const |
| #endif |
| |
| #ifndef __GNU_LIBRARY__ |
| # define __lstat stat |
| #endif |
| |
| #ifndef _LIBC |
| # define __getcwd getcwd |
| #endif |
| |
| #ifndef GETCWD_RETURN_TYPE |
| # define GETCWD_RETURN_TYPE char * |
| #endif |
| |
| #ifndef SB_PATH_MAX |
| # include "localdecls.h" |
| # define OUTSIDE_LIBSANDBOX |
| #endif |
| |
| #ifndef __LIBC |
| # define __lstat lstat |
| # define __readdir readdir |
| # define __closedir closedir |
| #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. */ |
| |
| GETCWD_RETURN_TYPE |
| __egetcwd(buf, size) |
| char *buf; |
| size_t size; |
| { |
| static const char dots[] |
| = "../../../../../../../../../../../../../../../../../../../../../../../\ |
| ../../../../../../../../../../../../../../../../../../../../../../../../../../\ |
| ../../../../../../../../../../../../../../../../../../../../../../../../../../\ |
| ../../../../../../../../../../../../../../../../../../../../../../../../../../\ |
| ../../../../../../../../../../../../../../../../../../../../../../../../../../\ |
| ../../../../../../../../../../../../../../../../../../../../../../../../../../\ |
| ../../../../../../../../../../../../../../../../../../../../../../../../../../\ |
| ../../../../../../../../../../../../../../../../../../../../../../../../../../\ |
| ../../../../../../../../../../../../../../../../../../../../../../../../../../\ |
| ../../../../../../../../../../../../../../../../../../../../../../../../../../\ |
| ../../../../../../../../../../../../../../../../../../../../../../../../../../\ |
| ../../../../../../../../../../../../../../../../../../../../../../../../../../\ |
| ../../../../../../../../../../../../../../../../../../../../../../../../../../\ |
| ../../../../../../../../../../../../../../../../../../../../../../../../../../\ |
| ../../../../../../../../../../../../../../../../../../../../../../../../../../\ |
| ../../../../../../../../../../../../../../../../../../../../../../../../../../\ |
| ../../../../../../../../../../../../../../../../../../../../../../../../../../\ |
| ../../../../../../../../../../../../../../../../../../../../../../../../../../\ |
| ../../../../../../../../../../../../../../../../../../../../../../../../../../\ |
| ../../../../../../../../../../../../../../../../../../../../../../../../../../\ |
| ../../../../../../../../../../../../../../../../../../../../../../../../../../\ |
| ../../../../../../../../../../../../../../../../../../../../../../../../../../\ |
| ../../../../../../../../../../../../../../../../../../../../../../../../../../\ |
| ../../../../../../../../../../../../../../../../../../../../../../../../../../\ |
| ../../../../../../../../../../../../../../../../../../../../../../../../../../\ |
| ../../../../../../../../../../../../../../../../../../../../../../../../../../\ |
| ../../../../../../../../../../../../../../../../../../../../../../../../../../\ |
| ../../../../../../../../../../../../../../../../../../../../../../../../../../\ |
| ../../../../../../../../../../../../../../../../../../../../../../../../../../\ |
| ../../../../../../../../../../../../../../../../../../../../../../../../../../\ |
| ../../../../../../../../../../../../../../../../../../../../../../../../../../\ |
| ../../../../../../../../../../../../../../../../../../../../../../../../../../\ |
| ../../../../../../../../../../../../../../../../../../../../../../../../../../\ |
| ../../../../../../../../../../../../../../../../../../../../../../../../../../\ |
| ../../../../../../../../../../../../../../../../../../../../../../../../../../\ |
| ../../../../../../../../../../../../../../../../../../../../../../../../../../\ |
| ../../../../../../../../../../../../../../../../../../../../../../../../../../\ |
| ../../../../../../../../../../../../../../../../../../../../../../../../../../\ |
| ../../../../../../../../../../../../../../../../../../../../../../../../../../\ |
| ../../../../../../../../../../../../../../../../../../../../../../../../../../\ |
| ../../../../../../../../../../../../../../../../../../../../../../../../../../\ |
| ../../../../../../../../../../../../../../../../../../../../../../../../../.."; |
| const char *dotp = &dots[sizeof (dots)]; |
| const char *dotlist = dots; |
| size_t dotsize = sizeof (dots) - 1; |
| dev_t rootdev, thisdev; |
| ino_t rootino, thisino; |
| char *path; |
| register char *pathp; |
| struct stat st; |
| int prev_errno = errno; |
| size_t allocated = size; |
| |
| if (size == 0) { |
| if (buf != NULL) { |
| __set_errno(EINVAL); |
| return NULL; |
| } |
| |
| allocated = SB_PATH_MAX + 1; |
| } |
| |
| if (buf != NULL) |
| path = buf; |
| else { |
| path = malloc(allocated); |
| if (path == NULL) |
| return NULL; |
| } |
| |
| pathp = path + allocated; |
| *--pathp = '\0'; |
| |
| if (__lstat(".", &st) < 0) |
| goto lose2; |
| thisdev = st.st_dev; |
| thisino = st.st_ino; |
| |
| if (__lstat("/", &st) < 0) |
| goto lose2; |
| rootdev = st.st_dev; |
| rootino = st.st_ino; |
| |
| while (!(thisdev == rootdev && thisino == rootino)) { |
| register DIR *dirstream; |
| struct dirent *d; |
| dev_t dotdev; |
| ino_t dotino; |
| char mount_point; |
| |
| /* Look at the parent directory. */ |
| if (dotp == dotlist) { |
| /* My, what a deep directory tree you have, Grandma. */ |
| char *new; |
| if (dotlist == dots) { |
| new = malloc(dotsize * 2 + 1); |
| if (new == NULL) |
| goto lose; |
| #ifdef HAVE_MEMPCPY |
| dotp = mempcpy(new, dots, dotsize); |
| #else |
| memcpy(new, dots, dotsize); |
| dotp = &new[dotsize]; |
| #endif |
| } else { |
| new = realloc((__ptr_t) dotlist, dotsize * 2 + 1); |
| if (new == NULL) |
| goto lose; |
| dotp = &new[dotsize]; |
| } |
| #ifdef HAVE_MEMPCPY |
| *((char *) mempcpy((char *) dotp, new, dotsize)) = '\0'; |
| dotsize *= 2; |
| #else |
| memcpy((char *) dotp, new, dotsize); |
| dotsize *= 2; |
| new[dotsize] = '\0'; |
| #endif |
| dotlist = new; |
| } |
| |
| dotp -= 3; |
| |
| /* Figure out if this directory is a mount point. */ |
| if (__lstat(dotp, &st) < 0) |
| goto lose; |
| dotdev = st.st_dev; |
| dotino = st.st_ino; |
| mount_point = dotdev != thisdev; |
| |
| /* Search for the last directory. */ |
| #ifdef OUTSIDE_LIBSANDBOX |
| dirstream = opendir(dotp); |
| #else |
| dirstream = true_opendir(dotp); |
| #endif |
| if (dirstream == NULL) |
| goto lose; |
| /* Clear errno to distinguish EOF from error if readdir returns |
| NULL. */ |
| __set_errno(0); |
| 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 || (ino_t) d->d_ino == thisino) { |
| char name[dotlist + dotsize - dotp + 1 + _D_ALLOC_NAMLEN(d)]; |
| #ifdef HAVE_MEMPCPY |
| char *tmp = mempcpy(name, dotp, |
| dotlist + dotsize - dotp); |
| *tmp++ = '/'; |
| strcpy(tmp, d->d_name); |
| #else |
| memcpy(name, dotp, dotlist + dotsize - dotp); |
| name[dotlist + dotsize - dotp] = '/'; |
| strcpy(&name[dotlist + dotsize - dotp + 1], d->d_name); |
| #endif |
| /* We don't fail here if we cannot stat() a directory entry. |
| This can happen when (network) filesystems fail. If this |
| entry is in fact the one we are looking for we will find |
| out soon as we reach the end of the directory without |
| having found anything. */ |
| if (__lstat(name, &st) >= 0 && st.st_dev == thisdev |
| && st.st_ino == thisino) |
| break; |
| } |
| } |
| if (d == NULL) { |
| int save = errno; |
| (void) __closedir(dirstream); |
| if (save == 0) |
| /* EOF on dirstream, which means that the current directory |
| has been removed. */ |
| save = ENOENT; |
| __set_errno(save); |
| goto lose; |
| } else { |
| size_t namlen = _D_EXACT_NAMLEN(d); |
| |
| if ((size_t) (pathp - path) <= namlen) { |
| if (size != 0) { |
| (void) __closedir(dirstream); |
| __set_errno(ERANGE); |
| goto lose; |
| } else { |
| char *tmp; |
| size_t oldsize = allocated; |
| |
| allocated = 2 * MAX(allocated, namlen); |
| tmp = realloc(path, allocated); |
| if (tmp == NULL) { |
| (void) __closedir(dirstream); |
| __set_errno(ENOMEM); /* closedir might have changed it. */ |
| goto lose; |
| } |
| |
| /* Move current contents up to the end of the buffer. |
| This is guaranteed to be non-overlapping. */ |
| pathp = |
| memcpy(tmp + allocated - |
| (path + oldsize - pathp), |
| tmp + (pathp - path), path + oldsize - pathp); |
| path = tmp; |
| } |
| } |
| pathp -= namlen; |
| (void) memcpy(pathp, d->d_name, namlen); |
| *--pathp = '/'; |
| (void) __closedir(dirstream); |
| } |
| |
| thisdev = dotdev; |
| thisino = dotino; |
| } |
| |
| if (pathp == &path[allocated - 1]) |
| *--pathp = '/'; |
| |
| if (dotlist != dots) |
| free((__ptr_t) dotlist); |
| |
| memmove(path, pathp, path + allocated - pathp); |
| |
| /* Restore errno on successful return. */ |
| __set_errno(prev_errno); |
| |
| return path; |
| |
| lose: |
| if (dotlist != dots) |
| free((__ptr_t) dotlist); |
| lose2: |
| if (buf == NULL) |
| free(path); |
| return NULL; |
| } |
| |
| GETCWD_RETURN_TYPE |
| egetcwd(buf, size) |
| char *buf; |
| size_t size; |
| { |
| struct stat st; |
| char *tmpbuf; |
| |
| __set_errno(0); |
| tmpbuf = getcwd(buf, size); |
| |
| if (tmpbuf) { |
| __lstat(buf, &st); |
| } else { |
| return tmpbuf; |
| } |
| |
| if (errno) { |
| /* If lstat() failed with eerror = ENOENT, then its |
| * possible that we are running on an older kernel, |
| * so use our generic version which *should* not fail. |
| */ |
| if (errno == ENOENT) { |
| return __egetcwd(buf, size); |
| } else { |
| return tmpbuf; |
| } |
| } |
| |
| return tmpbuf; |
| } |
| |
| // vim:expandtab noai:cindent ai |