diff options
author | Roland McGrath <roland@gnu.org> | 1995-02-18 01:27:10 +0000 |
---|---|---|
committer | Roland McGrath <roland@gnu.org> | 1995-02-18 01:27:10 +0000 |
commit | 28f540f45bbacd939bfd07f213bcad2bf730b1bf (patch) | |
tree | 15f07c4c43d635959c6afee96bde71fb1b3614ee /sysdeps/posix/getcwd.c | |
download | glibc-28f540f45bbacd939bfd07f213bcad2bf730b1bf.zip glibc-28f540f45bbacd939bfd07f213bcad2bf730b1bf.tar.gz glibc-28f540f45bbacd939bfd07f213bcad2bf730b1bf.tar.bz2 |
initial import
Diffstat (limited to 'sysdeps/posix/getcwd.c')
-rw-r--r-- | sysdeps/posix/getcwd.c | 366 |
1 files changed, 366 insertions, 0 deletions
diff --git a/sysdeps/posix/getcwd.c b/sysdeps/posix/getcwd.c new file mode 100644 index 0000000..7b992a9 --- /dev/null +++ b/sysdeps/posix/getcwd.c @@ -0,0 +1,366 @@ +/* Copyright (C) 1991, 1992, 1993, 1994 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., 675 Mass Ave, +Cambridge, MA 02139, USA. */ + +/* Wants: + AC_STDC_HEADERS + AC_DIR_HEADER + AC_UNISTD_H + AC_MEMORY_H + AC_CONST + AC_ALLOCA + */ + +/* 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 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__ */ + +#ifdef HAVE_UNISTD_H +#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. */ + +#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 + +#ifndef STDC_HEADERS +#undef size_t +#define size_t unsigned int +#endif + +#if !__STDC__ && !defined (const) +#define const +#endif + +#ifndef __GNU_LIBRARY__ +#define __lstat stat +#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. */ + +char * +getcwd (buf, size) + char *buf; + size_t size; +{ + static const char dots[] + = "../../../../../../../../../../../../../../../../../../../../../../../\ +../../../../../../../../../../../../../../../../../../../../../../../../../../\ +../../../../../../../../../../../../../../../../../../../../../../../../../.."; + const char *dotp, *dotlist; + size_t dotsize; + dev_t rootdev, thisdev; + ino_t rootino, thisino; + char *path; + register char *pathp; + struct stat st; + + if (size == 0) + { + if (buf != NULL) + { + errno = EINVAL; + return NULL; + } + + size = PATH_MAX + 1; + } + + if (buf != NULL) + path = buf; + else + { + path = malloc (size); + if (path == NULL) + return NULL; + } + + pathp = path + size; + *--pathp = '\0'; + + if (__lstat (".", &st) < 0) + return NULL; + thisdev = st.st_dev; + thisino = st.st_ino; + + if (__lstat ("/", &st) < 0) + return NULL; + rootdev = st.st_dev; + rootino = st.st_ino; + + 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; + + /* 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) + return NULL; + memcpy (new, dots, dotsize); + } + else + { + new = 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 (__lstat (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_namlen == 1 || (d->d_namlen == 2 && d->d_name[1] == '.'))) + continue; + if (mount_point || d->d_ino == thisino) + { + char *name = __alloca (dotlist + dotsize - dotp + + 1 + d->d_namlen + 1); + memcpy (name, dotp, dotlist + dotsize - dotp); + name[dotlist + dotsize - dotp] = '/'; + memcpy (&name[dotlist + dotsize - dotp + 1], + d->d_name, d->d_namlen + 1); + if (__lstat (name, &st) < 0) + { + int save = errno; + (void) closedir (dirstream); + errno = save; + goto lose; + } + if (st.st_dev == thisdev && st.st_ino == thisino) + break; + } + } + if (d == NULL) + { + int save = errno; + (void) closedir (dirstream); + errno = save; + goto lose; + } + else + { + if (pathp - path < d->d_namlen + 1) + { + if (buf != NULL) + { + errno = ERANGE; + return NULL; + } + else + { + size *= 2; + buf = realloc (path, size); + if (buf == NULL) + { + (void) closedir (dirstream); + free (path); + errno = ENOMEM; /* closedir might have changed it. */ + return NULL; + } + pathp = &buf[pathp - path]; + path = buf; + } + } + pathp -= d->d_namlen; + (void) memcpy (pathp, d->d_name, d->d_namlen); + *--pathp = '/'; + (void) closedir (dirstream); + } + + thisdev = dotdev; + thisino = dotino; + } + + if (pathp == &path[size - 1]) + *--pathp = '/'; + + if (dotlist != dots) + free ((__ptr_t) dotlist); + + memmove (path, pathp, path + size - pathp); + return path; + + lose: + if (dotlist != dots) + free ((__ptr_t) dotlist); + return NULL; +} |