summary refs log tree commit diff
path: root/sysdeps/posix/getcwd.c
diff options
context:
space:
mode:
authorRoland McGrath <roland@gnu.org>1995-02-18 01:27:10 +0000
committerRoland McGrath <roland@gnu.org>1995-02-18 01:27:10 +0000
commit28f540f45bbacd939bfd07f213bcad2bf730b1bf (patch)
tree15f07c4c43d635959c6afee96bde71fb1b3614ee /sysdeps/posix/getcwd.c
downloadglibc-28f540f45bbacd939bfd07f213bcad2bf730b1bf.tar.gz
glibc-28f540f45bbacd939bfd07f213bcad2bf730b1bf.tar.xz
glibc-28f540f45bbacd939bfd07f213bcad2bf730b1bf.zip
initial import
Diffstat (limited to 'sysdeps/posix/getcwd.c')
-rw-r--r--sysdeps/posix/getcwd.c366
1 files changed, 366 insertions, 0 deletions
diff --git a/sysdeps/posix/getcwd.c b/sysdeps/posix/getcwd.c
new file mode 100644
index 0000000000..7b992a9f43
--- /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;
+}