about summary refs log tree commit diff
path: root/REORG.TODO/sysdeps/posix/getcwd.c
diff options
context:
space:
mode:
Diffstat (limited to 'REORG.TODO/sysdeps/posix/getcwd.c')
-rw-r--r--REORG.TODO/sysdeps/posix/getcwd.c535
1 files changed, 535 insertions, 0 deletions
diff --git a/REORG.TODO/sysdeps/posix/getcwd.c b/REORG.TODO/sysdeps/posix/getcwd.c
new file mode 100644
index 0000000000..eb1706aa5c
--- /dev/null
+++ b/REORG.TODO/sysdeps/posix/getcwd.c
@@ -0,0 +1,535 @@
+/* Copyright (C) 1991-2017 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, see
+   <http://www.gnu.org/licenses/>.  */
+
+/* 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 <fcntl.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
+
+#if defined _LIBC
+# include <not-cancel.h>
+# include <kernel-features.h>
+#else
+# define openat64_not_cancel_3(dfd, name, mode) openat64 (dfd, name, mode)
+# define close_not_cancel_no_status(fd) close (fd)
+#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
+
+#ifndef __GNU_LIBRARY__
+# define __lstat64	stat64
+#endif
+
+#ifndef _LIBC
+# define __rewinddir	rewinddir
+#endif
+
+#ifndef _LIBC
+# define __getcwd getcwd
+#endif
+
+#ifndef GETCWD_RETURN_TYPE
+# define GETCWD_RETURN_TYPE char *
+#endif
+
+#ifdef __ASSUME_ATFCTS
+# define __have_atfcts 1
+#elif IS_IN (rtld)
+static int __rtld_have_atfcts;
+# define __have_atfcts __rtld_have_atfcts
+#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
+__getcwd (char *buf, size_t size)
+{
+#ifndef __ASSUME_ATFCTS
+  static const char dots[]
+    = "../../../../../../../../../../../../../../../../../../../../../../../\
+../../../../../../../../../../../../../../../../../../../../../../../../../../\
+../../../../../../../../../../../../../../../../../../../../../../../../../..";
+  const char *dotp = &dots[sizeof (dots)];
+  const char *dotlist = dots;
+  size_t dotsize = sizeof (dots) - 1;
+#endif
+  int prev_errno = errno;
+  DIR *dirstream = NULL;
+  bool fd_needs_closing = false;
+  int fd = AT_FDCWD;
+
+  char *path;
+#ifndef NO_ALLOCATION
+  size_t allocated = size;
+  if (size == 0)
+    {
+      if (buf != NULL)
+	{
+	  __set_errno (EINVAL);
+	  return NULL;
+	}
+
+      allocated = PATH_MAX + 1;
+    }
+
+  if (buf == NULL)
+    {
+      path = malloc (allocated);
+      if (path == NULL)
+	return NULL;
+    }
+  else
+#else
+# define allocated size
+#endif
+    path = buf;
+
+  char *pathp = path + allocated;
+  *--pathp = '\0';
+
+  struct stat64 st;
+  if (__lstat64 (".", &st) < 0)
+    goto lose;
+  dev_t thisdev = st.st_dev;
+  ino_t thisino = st.st_ino;
+
+  if (__lstat64 ("/", &st) < 0)
+    goto lose;
+  dev_t rootdev = st.st_dev;
+  ino_t rootino = st.st_ino;
+
+  while (!(thisdev == rootdev && thisino == rootino))
+    {
+      if (__have_atfcts >= 0)
+	  fd = openat64_not_cancel_3 (fd, "..", O_RDONLY | O_CLOEXEC);
+      else
+	fd = -1;
+      if (fd >= 0)
+	{
+	  fd_needs_closing = true;
+	  if (__fstat64 (fd, &st) < 0)
+	    goto lose;
+	}
+#ifndef __ASSUME_ATFCTS
+      else if (errno == ENOSYS)
+	{
+	  __have_atfcts = -1;
+
+	  /* Look at the parent directory.  */
+	  if (dotp == dotlist)
+	    {
+# ifdef NO_ALLOCATION
+	      __set_errno (ENOMEM);
+	      goto lose;
+# else
+	      /* 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;
+# endif
+	    }
+
+	  dotp -= 3;
+
+	  /* Figure out if this directory is a mount point.  */
+	  if (__lstat64 (dotp, &st) < 0)
+	    goto lose;
+	}
+#endif
+      else
+	goto lose;
+
+      if (dirstream && __closedir (dirstream) != 0)
+	{
+	  dirstream = NULL;
+	  goto lose;
+       }
+
+      dev_t dotdev = st.st_dev;
+      ino_t dotino = st.st_ino;
+      bool mount_point = dotdev != thisdev;
+
+      /* Search for the last directory.  */
+      if (__have_atfcts >= 0)
+	dirstream = __fdopendir (fd);
+#ifndef __ASSUME_ATFCTS
+      else
+	dirstream = __opendir (dotp);
+#endif
+      if (dirstream == NULL)
+	goto lose;
+      fd_needs_closing = false;
+
+      struct dirent *d;
+      bool use_d_ino = true;
+      while (1)
+	{
+	  /* Clear errno to distinguish EOF from error if readdir returns
+	     NULL.  */
+	  __set_errno (0);
+	  d = __readdir (dirstream);
+	  if (d == NULL)
+	    {
+	      if (errno == 0)
+		{
+		  /* When we've iterated through all directory entries
+		     without finding one with a matching d_ino, rewind the
+		     stream and consider each name again, but this time, using
+		     lstat64.  This is necessary in a chroot on at least one
+		     system.  */
+		  if (use_d_ino)
+		    {
+		      use_d_ino = false;
+		      __rewinddir (dirstream);
+		      continue;
+		    }
+
+		  /* EOF on dirstream, which means that the current directory
+		     has been removed.  */
+		  __set_errno (ENOENT);
+		}
+	      goto lose;
+	    }
+
+#ifdef _DIRENT_HAVE_D_TYPE
+	  if (d->d_type != DT_DIR && d->d_type != DT_UNKNOWN)
+	    continue;
+#endif
+	  if (d->d_name[0] == '.'
+	      && (d->d_name[1] == '\0'
+		  || (d->d_name[1] == '.' && d->d_name[2] == '\0')))
+	    continue;
+	  if (use_d_ino && !mount_point && (ino_t) d->d_ino != thisino)
+	    continue;
+
+	  if (__have_atfcts >= 0)
+	    {
+	      /* We don't fail here if we cannot stat64() 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 (__fstatat64 (fd, d->d_name, &st, AT_SYMLINK_NOFOLLOW) < 0)
+		continue;
+	    }
+#ifndef __ASSUME_ATFCTS
+	  else
+	    {
+	      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 stat64() 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 (__lstat64 (name, &st) < 0)
+		continue;
+	    }
+#endif
+	  if (S_ISDIR (st.st_mode)
+	      && st.st_dev == thisdev && st.st_ino == thisino)
+	    break;
+	}
+
+      size_t namlen = _D_EXACT_NAMLEN (d);
+
+      if ((size_t) (pathp - path) <= namlen)
+	{
+#ifndef NO_ALLOCATION
+	  if (size == 0)
+	    {
+	      size_t oldsize = allocated;
+
+	      allocated = 2 * MAX (allocated, namlen);
+	      char *tmp = realloc (path, allocated);
+	      if (tmp == NULL)
+		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;
+	    }
+	  else
+#endif
+	    {
+	      __set_errno (ERANGE);
+	      goto lose;
+	    }
+	}
+      pathp -= namlen;
+      (void) memcpy (pathp, d->d_name, namlen);
+      *--pathp = '/';
+
+      thisdev = dotdev;
+      thisino = dotino;
+    }
+
+  if (dirstream != NULL && __closedir (dirstream) != 0)
+    {
+      dirstream = NULL;
+      goto lose;
+    }
+
+  if (pathp == &path[allocated - 1])
+    *--pathp = '/';
+
+#ifndef __ASSUME_ATFCTS
+  if (dotlist != dots)
+    free ((__ptr_t) dotlist);
+#endif
+
+  size_t used = path + allocated - pathp;
+  memmove (path, pathp, used);
+
+  if (size == 0)
+    /* Ensure that the buffer is only as large as necessary.  */
+    buf = realloc (path, used);
+
+  if (buf == NULL)
+    /* Either buf was NULL all along, or `realloc' failed but
+       we still have the original string.  */
+    buf = path;
+
+  /* Restore errno on successful return.  */
+  __set_errno (prev_errno);
+
+  return buf;
+
+ lose:;
+  int save_errno = errno;
+#ifndef __ASSUME_ATFCTS
+  if (dotlist != dots)
+    free ((__ptr_t) dotlist);
+#endif
+  if (dirstream != NULL)
+    __closedir (dirstream);
+  if (fd_needs_closing)
+    close_not_cancel_no_status (fd);
+#ifndef NO_ALLOCATION
+  if (buf == NULL)
+    free (path);
+#endif
+  __set_errno (save_errno);
+  return NULL;
+}
+
+#if defined _LIBC && !defined __getcwd
+weak_alias (__getcwd, getcwd)
+#endif