Blame sysdeps/posix/getcwd.c

Packit 6c4009
/* Copyright (C) 1991-2018 Free Software Foundation, Inc.
Packit 6c4009
   This file is part of the GNU C Library.
Packit 6c4009
Packit 6c4009
   The GNU C Library is free software; you can redistribute it and/or
Packit 6c4009
   modify it under the terms of the GNU Lesser General Public
Packit 6c4009
   License as published by the Free Software Foundation; either
Packit 6c4009
   version 2.1 of the License, or (at your option) any later version.
Packit 6c4009
Packit 6c4009
   The GNU C Library is distributed in the hope that it will be useful,
Packit 6c4009
   but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit 6c4009
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Packit 6c4009
   Lesser General Public License for more details.
Packit 6c4009
Packit 6c4009
   You should have received a copy of the GNU Lesser General Public
Packit 6c4009
   License along with the GNU C Library; if not, see
Packit 6c4009
   <http://www.gnu.org/licenses/>.  */
Packit 6c4009
Packit 6c4009
/* Wants:
Packit 6c4009
   AC_STDC_HEADERS
Packit 6c4009
   AC_DIR_HEADER
Packit 6c4009
   AC_UNISTD_H
Packit 6c4009
   AC_MEMORY_H
Packit 6c4009
   AC_CONST
Packit 6c4009
   AC_ALLOCA
Packit 6c4009
 */
Packit 6c4009
Packit 6c4009
/* AIX requires this to be the first thing in the file.  */
Packit 6c4009
#if defined _AIX && !defined __GNUC__
Packit 6c4009
 #pragma alloca
Packit 6c4009
#endif
Packit 6c4009
Packit 6c4009
#ifdef	HAVE_CONFIG_H
Packit 6c4009
# include "config.h"
Packit 6c4009
#endif
Packit 6c4009
Packit 6c4009
#include <errno.h>
Packit 6c4009
#include <fcntl.h>
Packit 6c4009
#include <sys/types.h>
Packit 6c4009
#include <sys/stat.h>
Packit 6c4009
Packit 6c4009
#ifdef	STDC_HEADERS
Packit 6c4009
# include <stddef.h>
Packit 6c4009
#endif
Packit 6c4009
Packit 6c4009
#if !defined __GNU_LIBRARY__ && !defined STDC_HEADERS
Packit 6c4009
extern int errno;
Packit 6c4009
#endif
Packit 6c4009
#ifndef __set_errno
Packit 6c4009
# define __set_errno(val) errno = (val)
Packit 6c4009
#endif
Packit 6c4009
Packit 6c4009
#ifndef	NULL
Packit 6c4009
# define NULL	0
Packit 6c4009
#endif
Packit 6c4009
Packit 6c4009
#if defined USGr3 && !defined DIRENT
Packit 6c4009
# define DIRENT
Packit 6c4009
#endif /* USGr3 */
Packit 6c4009
#if defined Xenix && !defined SYSNDIR
Packit 6c4009
# define SYSNDIR
Packit 6c4009
#endif /* Xenix */
Packit 6c4009
Packit 6c4009
#if defined POSIX || defined DIRENT || defined __GNU_LIBRARY__
Packit 6c4009
# include <dirent.h>
Packit 6c4009
# ifndef __GNU_LIBRARY__
Packit 6c4009
#  define D_NAMLEN(d) strlen((d)->d_name)
Packit 6c4009
# else
Packit 6c4009
#  define HAVE_D_NAMLEN
Packit 6c4009
#  define D_NAMLEN(d) ((d)->d_namlen)
Packit 6c4009
# endif
Packit 6c4009
#else /* not POSIX or DIRENT */
Packit 6c4009
# define dirent		direct
Packit 6c4009
# define D_NAMLEN(d)	((d)->d_namlen)
Packit 6c4009
# define HAVE_D_NAMLEN
Packit 6c4009
# if defined USG && !defined sgi
Packit 6c4009
#  if defined SYSNDIR
Packit 6c4009
#   include <sys/ndir.h>
Packit 6c4009
#  else /* Not SYSNDIR */
Packit 6c4009
#   include "ndir.h"
Packit 6c4009
#  endif /* SYSNDIR */
Packit 6c4009
# else /* not USG */
Packit 6c4009
#  include <sys/dir.h>
Packit 6c4009
# endif /* USG */
Packit 6c4009
#endif /* POSIX or DIRENT or __GNU_LIBRARY__ */
Packit 6c4009
Packit 6c4009
#if defined HAVE_UNISTD_H || defined __GNU_LIBRARY__
Packit 6c4009
# include <unistd.h>
Packit 6c4009
#endif
Packit 6c4009
Packit 6c4009
#if defined STDC_HEADERS || defined __GNU_LIBRARY__ || defined POSIX
Packit 6c4009
# include <stdlib.h>
Packit 6c4009
# include <string.h>
Packit 6c4009
# define ANSI_STRING
Packit 6c4009
#else	/* No standard headers.  */
Packit 6c4009
Packit 6c4009
# ifdef	USG
Packit 6c4009
Packit 6c4009
#  include <string.h>
Packit 6c4009
#  ifdef NEED_MEMORY_H
Packit 6c4009
#   include <memory.h>
Packit 6c4009
#  endif
Packit 6c4009
#  define	ANSI_STRING
Packit 6c4009
Packit 6c4009
# else	/* Not USG.  */
Packit 6c4009
Packit 6c4009
#  ifdef NeXT
Packit 6c4009
Packit 6c4009
#   include <string.h>
Packit 6c4009
Packit 6c4009
#  else	/* Not NeXT.  */
Packit 6c4009
Packit 6c4009
#   include <strings.h>
Packit 6c4009
Packit 6c4009
#   ifndef bcmp
Packit 6c4009
extern int bcmp ();
Packit 6c4009
#   endif
Packit 6c4009
#   ifndef bzero
Packit 6c4009
extern void bzero ();
Packit 6c4009
#   endif
Packit 6c4009
#   ifndef bcopy
Packit 6c4009
extern void bcopy ();
Packit 6c4009
#   endif
Packit 6c4009
Packit 6c4009
#  endif /* NeXT. */
Packit 6c4009
Packit 6c4009
# endif	/* USG.  */
Packit 6c4009
Packit 6c4009
extern char *malloc (), *realloc ();
Packit 6c4009
extern void free ();
Packit 6c4009
Packit 6c4009
#endif /* Standard headers.  */
Packit 6c4009
Packit 6c4009
#ifndef	ANSI_STRING
Packit 6c4009
# define memcpy(d, s, n)	bcopy((s), (d), (n))
Packit 6c4009
# define memmove memcpy
Packit 6c4009
#endif	/* Not ANSI_STRING.  */
Packit 6c4009
Packit 6c4009
#ifndef MAX
Packit 6c4009
# define MAX(a, b) ((a) < (b) ? (b) : (a))
Packit 6c4009
#endif
Packit 6c4009
Packit 6c4009
#ifdef _LIBC
Packit 6c4009
# ifndef mempcpy
Packit 6c4009
#  define mempcpy __mempcpy
Packit 6c4009
# endif
Packit 6c4009
# define HAVE_MEMPCPY	1
Packit 6c4009
#endif
Packit 6c4009
Packit 6c4009
#if !defined __alloca && !defined __GNU_LIBRARY__
Packit 6c4009
Packit 6c4009
# ifdef	__GNUC__
Packit 6c4009
#  undef alloca
Packit 6c4009
#  define alloca(n)	__builtin_alloca (n)
Packit 6c4009
# else	/* Not GCC.  */
Packit 6c4009
#  if	defined sparc || defined HAVE_ALLOCA_H
Packit 6c4009
#   include <alloca.h>
Packit 6c4009
#  else	/* Not sparc or HAVE_ALLOCA_H.  */
Packit 6c4009
#   ifndef _AIX
Packit 6c4009
extern char *alloca ();
Packit 6c4009
#   endif /* Not _AIX.  */
Packit 6c4009
#  endif /* sparc or HAVE_ALLOCA_H.  */
Packit 6c4009
# endif	/* GCC.  */
Packit 6c4009
Packit 6c4009
# define __alloca	alloca
Packit 6c4009
Packit 6c4009
#endif
Packit 6c4009
Packit 6c4009
#if defined HAVE_LIMITS_H || defined STDC_HEADERS || defined __GNU_LIBRARY__
Packit 6c4009
# include <limits.h>
Packit 6c4009
#else
Packit 6c4009
# include <sys/param.h>
Packit 6c4009
#endif
Packit 6c4009
Packit 6c4009
#if defined _LIBC
Packit 6c4009
# include <not-cancel.h>
Packit 6c4009
# include <kernel-features.h>
Packit 6c4009
#else
Packit 6c4009
# define __openat64_nocancel(dfd, name, mode) openat64 (dfd, name, mode)
Packit 6c4009
# define __close_nocancel_nostatus(fd) close (fd)
Packit 6c4009
#endif
Packit 6c4009
Packit 6c4009
#ifndef PATH_MAX
Packit 6c4009
# ifdef	MAXPATHLEN
Packit 6c4009
#  define PATH_MAX MAXPATHLEN
Packit 6c4009
# else
Packit 6c4009
#  define PATH_MAX 1024
Packit 6c4009
# endif
Packit 6c4009
#endif
Packit 6c4009
Packit 6c4009
#if !defined STDC_HEADERS && !defined __GNU_LIBRARY__
Packit 6c4009
# undef	size_t
Packit 6c4009
# define size_t	unsigned int
Packit 6c4009
#endif
Packit 6c4009
Packit 6c4009
#ifndef __GNU_LIBRARY__
Packit 6c4009
# define __lstat64	stat64
Packit 6c4009
#endif
Packit 6c4009
Packit 6c4009
#ifndef _LIBC
Packit 6c4009
# define __rewinddir	rewinddir
Packit 6c4009
#endif
Packit 6c4009

Packit 6c4009
#ifndef _LIBC
Packit 6c4009
# define __getcwd getcwd
Packit 6c4009
#endif
Packit 6c4009
Packit 6c4009
#ifndef GETCWD_RETURN_TYPE
Packit 6c4009
# define GETCWD_RETURN_TYPE char *
Packit 6c4009
#endif
Packit 6c4009
Packit 6c4009
#ifdef __ASSUME_ATFCTS
Packit 6c4009
# define __have_atfcts 1
Packit 6c4009
#elif IS_IN (rtld)
Packit 6c4009
static int __rtld_have_atfcts;
Packit 6c4009
# define __have_atfcts __rtld_have_atfcts
Packit 6c4009
#endif
Packit 6c4009
Packit 6c4009
/* Get the pathname of the current working directory, and put it in SIZE
Packit 6c4009
   bytes of BUF.  Returns NULL if the directory couldn't be determined or
Packit 6c4009
   SIZE was too small.  If successful, returns BUF.  In GNU, if BUF is
Packit 6c4009
   NULL, an array is allocated with `malloc'; the array is SIZE bytes long,
Packit 6c4009
   unless SIZE == 0, in which case it is as big as necessary.  */
Packit 6c4009
Packit 6c4009
GETCWD_RETURN_TYPE
Packit 6c4009
__getcwd (char *buf, size_t size)
Packit 6c4009
{
Packit 6c4009
#ifndef __ASSUME_ATFCTS
Packit 6c4009
  static const char dots[]
Packit 6c4009
    = "../../../../../../../../../../../../../../../../../../../../../../../\
Packit 6c4009
../../../../../../../../../../../../../../../../../../../../../../../../../../\
Packit 6c4009
../../../../../../../../../../../../../../../../../../../../../../../../../..";
Packit 6c4009
  const char *dotp = &dots[sizeof (dots)];
Packit 6c4009
  const char *dotlist = dots;
Packit 6c4009
  size_t dotsize = sizeof (dots) - 1;
Packit 6c4009
#endif
Packit 6c4009
  int prev_errno = errno;
Packit 6c4009
  DIR *dirstream = NULL;
Packit 6c4009
  bool fd_needs_closing = false;
Packit 6c4009
  int fd = AT_FDCWD;
Packit 6c4009
Packit 6c4009
  char *path;
Packit 6c4009
#ifndef NO_ALLOCATION
Packit 6c4009
  size_t allocated = size;
Packit 6c4009
  if (size == 0)
Packit 6c4009
    {
Packit 6c4009
      if (buf != NULL)
Packit 6c4009
	{
Packit 6c4009
	  __set_errno (EINVAL);
Packit 6c4009
	  return NULL;
Packit 6c4009
	}
Packit 6c4009
Packit 6c4009
      allocated = PATH_MAX + 1;
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
  if (buf == NULL)
Packit 6c4009
    {
Packit 6c4009
      path = malloc (allocated);
Packit 6c4009
      if (path == NULL)
Packit 6c4009
	return NULL;
Packit 6c4009
    }
Packit 6c4009
  else
Packit 6c4009
#else
Packit 6c4009
# define allocated size
Packit 6c4009
#endif
Packit 6c4009
    path = buf;
Packit 6c4009
Packit 6c4009
  char *pathp = path + allocated;
Packit 6c4009
  *--pathp = '\0';
Packit 6c4009
Packit 6c4009
  struct stat64 st;
Packit 6c4009
  if (__lstat64 (".", &st) < 0)
Packit 6c4009
    goto lose;
Packit 6c4009
  dev_t thisdev = st.st_dev;
Packit 6c4009
  ino_t thisino = st.st_ino;
Packit 6c4009
Packit 6c4009
  if (__lstat64 ("/", &st) < 0)
Packit 6c4009
    goto lose;
Packit 6c4009
  dev_t rootdev = st.st_dev;
Packit 6c4009
  ino_t rootino = st.st_ino;
Packit 6c4009
Packit 6c4009
  while (!(thisdev == rootdev && thisino == rootino))
Packit 6c4009
    {
Packit 6c4009
      if (__have_atfcts >= 0)
Packit 6c4009
	  fd = __openat64_nocancel (fd, "..", O_RDONLY | O_CLOEXEC);
Packit 6c4009
      else
Packit 6c4009
	fd = -1;
Packit 6c4009
      if (fd >= 0)
Packit 6c4009
	{
Packit 6c4009
	  fd_needs_closing = true;
Packit 6c4009
	  if (__fstat64 (fd, &st) < 0)
Packit 6c4009
	    goto lose;
Packit 6c4009
	}
Packit 6c4009
#ifndef __ASSUME_ATFCTS
Packit 6c4009
      else if (errno == ENOSYS)
Packit 6c4009
	{
Packit 6c4009
	  __have_atfcts = -1;
Packit 6c4009
Packit 6c4009
	  /* Look at the parent directory.  */
Packit 6c4009
	  if (dotp == dotlist)
Packit 6c4009
	    {
Packit 6c4009
# ifdef NO_ALLOCATION
Packit 6c4009
	      __set_errno (ENOMEM);
Packit 6c4009
	      goto lose;
Packit 6c4009
# else
Packit 6c4009
	      /* My, what a deep directory tree you have, Grandma.  */
Packit 6c4009
	      char *new;
Packit 6c4009
	      if (dotlist == dots)
Packit 6c4009
		{
Packit 6c4009
		  new = malloc (dotsize * 2 + 1);
Packit 6c4009
		  if (new == NULL)
Packit 6c4009
		    goto lose;
Packit 6c4009
#  ifdef HAVE_MEMPCPY
Packit 6c4009
		  dotp = mempcpy (new, dots, dotsize);
Packit 6c4009
#  else
Packit 6c4009
		  memcpy (new, dots, dotsize);
Packit 6c4009
		  dotp = &new[dotsize];
Packit 6c4009
#  endif
Packit 6c4009
		}
Packit 6c4009
	      else
Packit 6c4009
		{
Packit 6c4009
		  new = realloc ((void *) dotlist, dotsize * 2 + 1);
Packit 6c4009
		  if (new == NULL)
Packit 6c4009
		    goto lose;
Packit 6c4009
		  dotp = &new[dotsize];
Packit 6c4009
		}
Packit 6c4009
#  ifdef HAVE_MEMPCPY
Packit 6c4009
	      *((char *) mempcpy ((char *) dotp, new, dotsize)) = '\0';
Packit 6c4009
	      dotsize *= 2;
Packit 6c4009
#  else
Packit 6c4009
	      memcpy ((char *) dotp, new, dotsize);
Packit 6c4009
	      dotsize *= 2;
Packit 6c4009
	      new[dotsize] = '\0';
Packit 6c4009
#  endif
Packit 6c4009
	      dotlist = new;
Packit 6c4009
# endif
Packit 6c4009
	    }
Packit 6c4009
Packit 6c4009
	  dotp -= 3;
Packit 6c4009
Packit 6c4009
	  /* Figure out if this directory is a mount point.  */
Packit 6c4009
	  if (__lstat64 (dotp, &st) < 0)
Packit 6c4009
	    goto lose;
Packit 6c4009
	}
Packit 6c4009
#endif
Packit 6c4009
      else
Packit 6c4009
	goto lose;
Packit 6c4009
Packit 6c4009
      if (dirstream && __closedir (dirstream) != 0)
Packit 6c4009
	{
Packit 6c4009
	  dirstream = NULL;
Packit 6c4009
	  goto lose;
Packit 6c4009
       }
Packit 6c4009
Packit 6c4009
      dev_t dotdev = st.st_dev;
Packit 6c4009
      ino_t dotino = st.st_ino;
Packit 6c4009
      bool mount_point = dotdev != thisdev;
Packit 6c4009
Packit 6c4009
      /* Search for the last directory.  */
Packit 6c4009
      if (__have_atfcts >= 0)
Packit 6c4009
	dirstream = __fdopendir (fd);
Packit 6c4009
#ifndef __ASSUME_ATFCTS
Packit 6c4009
      else
Packit 6c4009
	dirstream = __opendir (dotp);
Packit 6c4009
#endif
Packit 6c4009
      if (dirstream == NULL)
Packit 6c4009
	goto lose;
Packit 6c4009
      fd_needs_closing = false;
Packit 6c4009
Packit 6c4009
      struct dirent *d;
Packit 6c4009
      bool use_d_ino = true;
Packit 6c4009
      while (1)
Packit 6c4009
	{
Packit 6c4009
	  /* Clear errno to distinguish EOF from error if readdir returns
Packit 6c4009
	     NULL.  */
Packit 6c4009
	  __set_errno (0);
Packit 6c4009
	  d = __readdir (dirstream);
Packit 6c4009
	  if (d == NULL)
Packit 6c4009
	    {
Packit 6c4009
	      if (errno == 0)
Packit 6c4009
		{
Packit 6c4009
		  /* When we've iterated through all directory entries
Packit 6c4009
		     without finding one with a matching d_ino, rewind the
Packit 6c4009
		     stream and consider each name again, but this time, using
Packit 6c4009
		     lstat64.  This is necessary in a chroot on at least one
Packit 6c4009
		     system.  */
Packit 6c4009
		  if (use_d_ino)
Packit 6c4009
		    {
Packit 6c4009
		      use_d_ino = false;
Packit 6c4009
		      __rewinddir (dirstream);
Packit 6c4009
		      continue;
Packit 6c4009
		    }
Packit 6c4009
Packit 6c4009
		  /* EOF on dirstream, which means that the current directory
Packit 6c4009
		     has been removed.  */
Packit 6c4009
		  __set_errno (ENOENT);
Packit 6c4009
		}
Packit 6c4009
	      goto lose;
Packit 6c4009
	    }
Packit 6c4009
Packit 6c4009
#ifdef _DIRENT_HAVE_D_TYPE
Packit 6c4009
	  if (d->d_type != DT_DIR && d->d_type != DT_UNKNOWN)
Packit 6c4009
	    continue;
Packit 6c4009
#endif
Packit 6c4009
	  if (d->d_name[0] == '.'
Packit 6c4009
	      && (d->d_name[1] == '\0'
Packit 6c4009
		  || (d->d_name[1] == '.' && d->d_name[2] == '\0')))
Packit 6c4009
	    continue;
Packit 6c4009
	  if (use_d_ino && !mount_point && (ino_t) d->d_ino != thisino)
Packit 6c4009
	    continue;
Packit 6c4009
Packit 6c4009
	  if (__have_atfcts >= 0)
Packit 6c4009
	    {
Packit 6c4009
	      /* We don't fail here if we cannot stat64() a directory entry.
Packit 6c4009
		 This can happen when (network) filesystems fail.  If this
Packit 6c4009
		 entry is in fact the one we are looking for we will find
Packit 6c4009
		 out soon as we reach the end of the directory without
Packit 6c4009
		 having found anything.  */
Packit 6c4009
	      if (__fstatat64 (fd, d->d_name, &st, AT_SYMLINK_NOFOLLOW) < 0)
Packit 6c4009
		continue;
Packit 6c4009
	    }
Packit 6c4009
#ifndef __ASSUME_ATFCTS
Packit 6c4009
	  else
Packit 6c4009
	    {
Packit 6c4009
	      char name[dotlist + dotsize - dotp + 1 + _D_ALLOC_NAMLEN (d)];
Packit 6c4009
# ifdef HAVE_MEMPCPY
Packit 6c4009
	      char *tmp = mempcpy (name, dotp, dotlist + dotsize - dotp);
Packit 6c4009
	      *tmp++ = '/';
Packit 6c4009
	      strcpy (tmp, d->d_name);
Packit 6c4009
# else
Packit 6c4009
	      memcpy (name, dotp, dotlist + dotsize - dotp);
Packit 6c4009
	      name[dotlist + dotsize - dotp] = '/';
Packit 6c4009
	      strcpy (&name[dotlist + dotsize - dotp + 1], d->d_name);
Packit 6c4009
# endif
Packit 6c4009
	      /* We don't fail here if we cannot stat64() a directory entry.
Packit 6c4009
		 This can happen when (network) filesystems fail.  If this
Packit 6c4009
		 entry is in fact the one we are looking for we will find
Packit 6c4009
		 out soon as we reach the end of the directory without
Packit 6c4009
		 having found anything.  */
Packit 6c4009
	      if (__lstat64 (name, &st) < 0)
Packit 6c4009
		continue;
Packit 6c4009
	    }
Packit 6c4009
#endif
Packit 6c4009
	  if (S_ISDIR (st.st_mode)
Packit 6c4009
	      && st.st_dev == thisdev && st.st_ino == thisino)
Packit 6c4009
	    break;
Packit 6c4009
	}
Packit 6c4009
Packit 6c4009
      size_t namlen = _D_EXACT_NAMLEN (d);
Packit 6c4009
Packit 6c4009
      if ((size_t) (pathp - path) <= namlen)
Packit 6c4009
	{
Packit 6c4009
#ifndef NO_ALLOCATION
Packit 6c4009
	  if (size == 0)
Packit 6c4009
	    {
Packit 6c4009
	      size_t oldsize = allocated;
Packit 6c4009
Packit 6c4009
	      allocated = 2 * MAX (allocated, namlen);
Packit 6c4009
	      char *tmp = realloc (path, allocated);
Packit 6c4009
	      if (tmp == NULL)
Packit 6c4009
		goto lose;
Packit 6c4009
Packit 6c4009
	      /* Move current contents up to the end of the buffer.
Packit 6c4009
		 This is guaranteed to be non-overlapping.  */
Packit 6c4009
	      pathp = memcpy (tmp + allocated - (path + oldsize - pathp),
Packit 6c4009
			      tmp + (pathp - path),
Packit 6c4009
			      path + oldsize - pathp);
Packit 6c4009
	      path = tmp;
Packit 6c4009
	    }
Packit 6c4009
	  else
Packit 6c4009
#endif
Packit 6c4009
	    {
Packit 6c4009
	      __set_errno (ERANGE);
Packit 6c4009
	      goto lose;
Packit 6c4009
	    }
Packit 6c4009
	}
Packit 6c4009
      pathp -= namlen;
Packit 6c4009
      (void) memcpy (pathp, d->d_name, namlen);
Packit 6c4009
      *--pathp = '/';
Packit 6c4009
Packit 6c4009
      thisdev = dotdev;
Packit 6c4009
      thisino = dotino;
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
  if (dirstream != NULL && __closedir (dirstream) != 0)
Packit 6c4009
    {
Packit 6c4009
      dirstream = NULL;
Packit 6c4009
      goto lose;
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
  if (pathp == &path[allocated - 1])
Packit 6c4009
    *--pathp = '/';
Packit 6c4009
Packit 6c4009
#ifndef __ASSUME_ATFCTS
Packit 6c4009
  if (dotlist != dots)
Packit 6c4009
    free ((void *) dotlist);
Packit 6c4009
#endif
Packit 6c4009
Packit 6c4009
  size_t used = path + allocated - pathp;
Packit 6c4009
  memmove (path, pathp, used);
Packit 6c4009
Packit 6c4009
  if (size == 0)
Packit 6c4009
    /* Ensure that the buffer is only as large as necessary.  */
Packit 6c4009
    buf = realloc (path, used);
Packit 6c4009
Packit 6c4009
  if (buf == NULL)
Packit 6c4009
    /* Either buf was NULL all along, or `realloc' failed but
Packit 6c4009
       we still have the original string.  */
Packit 6c4009
    buf = path;
Packit 6c4009
Packit 6c4009
  /* Restore errno on successful return.  */
Packit 6c4009
  __set_errno (prev_errno);
Packit 6c4009
Packit 6c4009
  return buf;
Packit 6c4009
Packit 6c4009
 lose:;
Packit 6c4009
  int save_errno = errno;
Packit 6c4009
#ifndef __ASSUME_ATFCTS
Packit 6c4009
  if (dotlist != dots)
Packit 6c4009
    free ((void *) dotlist);
Packit 6c4009
#endif
Packit 6c4009
  if (dirstream != NULL)
Packit 6c4009
    __closedir (dirstream);
Packit 6c4009
  if (fd_needs_closing)
Packit 6c4009
    __close_nocancel_nostatus (fd);
Packit 6c4009
#ifndef NO_ALLOCATION
Packit 6c4009
  if (buf == NULL)
Packit 6c4009
    free (path);
Packit 6c4009
#endif
Packit 6c4009
  __set_errno (save_errno);
Packit 6c4009
  return NULL;
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
#if defined _LIBC && !defined __getcwd
Packit 6c4009
weak_alias (__getcwd, getcwd)
Packit 6c4009
#endif