mirror of
				https://sourceware.org/git/glibc.git
				synced 2025-11-03 20:53:13 +03:00 
			
		
		
		
	
		
			
				
	
	
		
			429 lines
		
	
	
		
			9.6 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			429 lines
		
	
	
		
			9.6 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
/* 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 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., 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
 | 
						||
 */
 | 
						||
 | 
						||
/* 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
 | 
						||
 | 
						||
/* 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 (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 = 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.  */
 | 
						||
      dirstream = __opendir (dotp);
 | 
						||
      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;
 | 
						||
}
 | 
						||
 | 
						||
#if defined _LIBC && !defined __getcwd
 | 
						||
weak_alias (__getcwd, getcwd)
 | 
						||
#endif
 |