Blame io/ftw.c

Packit Service 82fcde
/* File tree walker functions.
Packit Service 82fcde
   Copyright (C) 1996-2018 Free Software Foundation, Inc.
Packit Service 82fcde
   This file is part of the GNU C Library.
Packit Service 82fcde
   Contributed by Ulrich Drepper <drepper@cygnus.com>, 1996.
Packit Service 82fcde
Packit Service 82fcde
   The GNU C Library is free software; you can redistribute it and/or
Packit Service 82fcde
   modify it under the terms of the GNU Lesser General Public
Packit Service 82fcde
   License as published by the Free Software Foundation; either
Packit Service 82fcde
   version 2.1 of the License, or (at your option) any later version.
Packit Service 82fcde
Packit Service 82fcde
   The GNU C Library is distributed in the hope that it will be useful,
Packit Service 82fcde
   but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit Service 82fcde
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Packit Service 82fcde
   Lesser General Public License for more details.
Packit Service 82fcde
Packit Service 82fcde
   You should have received a copy of the GNU Lesser General Public
Packit Service 82fcde
   License along with the GNU C Library; if not, see
Packit Service 82fcde
   <http://www.gnu.org/licenses/>.  */
Packit Service 82fcde
Packit Service 82fcde
#ifdef HAVE_CONFIG_H
Packit Service 82fcde
# include <config.h>
Packit Service 82fcde
#endif
Packit Service 82fcde
Packit Service 82fcde
#if __GNUC__
Packit Service 82fcde
# define alloca __builtin_alloca
Packit Service 82fcde
#else
Packit Service 82fcde
# if HAVE_ALLOCA_H
Packit Service 82fcde
#  include <alloca.h>
Packit Service 82fcde
# else
Packit Service 82fcde
#  ifdef _AIX
Packit Service 82fcde
 #  pragma alloca
Packit Service 82fcde
#  else
Packit Service 82fcde
char *alloca ();
Packit Service 82fcde
#  endif
Packit Service 82fcde
# endif
Packit Service 82fcde
#endif
Packit Service 82fcde
Packit Service 82fcde
#ifdef _LIBC
Packit Service 82fcde
# include <dirent.h>
Packit Service 82fcde
# define NAMLEN(dirent) _D_EXACT_NAMLEN (dirent)
Packit Service 82fcde
#else
Packit Service 82fcde
# if HAVE_DIRENT_H
Packit Service 82fcde
#  include <dirent.h>
Packit Service 82fcde
#  define NAMLEN(dirent) strlen ((dirent)->d_name)
Packit Service 82fcde
# else
Packit Service 82fcde
#  define dirent direct
Packit Service 82fcde
#  define NAMLEN(dirent) (dirent)->d_namlen
Packit Service 82fcde
#  if HAVE_SYS_NDIR_H
Packit Service 82fcde
#   include <sys/ndir.h>
Packit Service 82fcde
#  endif
Packit Service 82fcde
#  if HAVE_SYS_DIR_H
Packit Service 82fcde
#   include <sys/dir.h>
Packit Service 82fcde
#  endif
Packit Service 82fcde
#  if HAVE_NDIR_H
Packit Service 82fcde
#   include <ndir.h>
Packit Service 82fcde
#  endif
Packit Service 82fcde
# endif
Packit Service 82fcde
#endif
Packit Service 82fcde
Packit Service 82fcde
#include <errno.h>
Packit Service 82fcde
#include <fcntl.h>
Packit Service 82fcde
#include <ftw.h>
Packit Service 82fcde
#include <limits.h>
Packit Service 82fcde
#include <search.h>
Packit Service 82fcde
#include <stdlib.h>
Packit Service 82fcde
#include <string.h>
Packit Service 82fcde
#include <unistd.h>
Packit Service 82fcde
#include <not-cancel.h>
Packit Service 82fcde
#include <sys/param.h>
Packit Service 82fcde
#ifdef _LIBC
Packit Service 82fcde
# include <include/sys/stat.h>
Packit Service 82fcde
#else
Packit Service 82fcde
# include <sys/stat.h>
Packit Service 82fcde
#endif
Packit Service 82fcde
Packit Service 82fcde
#if ! _LIBC && !HAVE_DECL_STPCPY && !defined stpcpy
Packit Service 82fcde
char *stpcpy ();
Packit Service 82fcde
#endif
Packit Service 82fcde
Packit Service 82fcde
#if ! _LIBC && ! defined HAVE_MEMPCPY && ! defined mempcpy
Packit Service 82fcde
/* Be CAREFUL that there are no side effects in N.  */
Packit Service 82fcde
# define mempcpy(D, S, N) ((void *) ((char *) memcpy (D, S, N) + (N)))
Packit Service 82fcde
#endif
Packit Service 82fcde
Packit Service 82fcde
/* #define NDEBUG 1 */
Packit Service 82fcde
#include <assert.h>
Packit Service 82fcde
Packit Service 82fcde
#ifndef _LIBC
Packit Service 82fcde
# undef __chdir
Packit Service 82fcde
# define __chdir chdir
Packit Service 82fcde
# undef __closedir
Packit Service 82fcde
# define __closedir closedir
Packit Service 82fcde
# undef __fchdir
Packit Service 82fcde
# define __fchdir fchdir
Packit Service 82fcde
# undef __getcwd
Packit Service 82fcde
# define __getcwd(P, N) xgetcwd ()
Packit Service 82fcde
extern char *xgetcwd (void);
Packit Service 82fcde
# undef __mempcpy
Packit Service 82fcde
# define __mempcpy mempcpy
Packit Service 82fcde
# undef __opendir
Packit Service 82fcde
# define __opendir opendir
Packit Service 82fcde
# undef __readdir64
Packit Service 82fcde
# define __readdir64 readdir
Packit Service 82fcde
# undef __stpcpy
Packit Service 82fcde
# define __stpcpy stpcpy
Packit Service 82fcde
# undef __tdestroy
Packit Service 82fcde
# define __tdestroy tdestroy
Packit Service 82fcde
# undef __tfind
Packit Service 82fcde
# define __tfind tfind
Packit Service 82fcde
# undef __tsearch
Packit Service 82fcde
# define __tsearch tsearch
Packit Service 82fcde
# undef dirent64
Packit Service 82fcde
# define dirent64 dirent
Packit Service 82fcde
# undef MAX
Packit Service 82fcde
# define MAX(a, b) ((a) > (b) ? (a) : (b))
Packit Service 82fcde
#endif
Packit Service 82fcde
Packit Service 82fcde
/* Arrange to make lstat calls go through the wrapper function
Packit Service 82fcde
   on systems with an lstat function that does not dereference symlinks
Packit Service 82fcde
   that are specified with a trailing slash.  */
Packit Service 82fcde
#if ! _LIBC && ! LSTAT_FOLLOWS_SLASHED_SYMLINK
Packit Service 82fcde
int rpl_lstat (const char *, struct stat *);
Packit Service 82fcde
# undef lstat
Packit Service 82fcde
# define lstat(Name, Stat_buf) rpl_lstat(Name, Stat_buf)
Packit Service 82fcde
#endif
Packit Service 82fcde
Packit Service 82fcde
#ifndef __set_errno
Packit Service 82fcde
# define __set_errno(Val) errno = (Val)
Packit Service 82fcde
#endif
Packit Service 82fcde
Packit Service 82fcde
/* Support for the LFS API version.  */
Packit Service 82fcde
#ifndef FTW_NAME
Packit Service 82fcde
# define FTW_NAME ftw
Packit Service 82fcde
# define NFTW_NAME nftw
Packit Service 82fcde
# define NFTW_OLD_NAME __old_nftw
Packit Service 82fcde
# define NFTW_NEW_NAME __new_nftw
Packit Service 82fcde
# define INO_T ino_t
Packit Service 82fcde
# define STAT stat
Packit Service 82fcde
# ifdef _LIBC
Packit Service 82fcde
#  define LXSTAT __lxstat
Packit Service 82fcde
#  define XSTAT __xstat
Packit Service 82fcde
#  define FXSTATAT __fxstatat
Packit Service 82fcde
# else
Packit Service 82fcde
#  define LXSTAT(V,f,sb) lstat (f,sb)
Packit Service 82fcde
#  define XSTAT(V,f,sb) stat (f,sb)
Packit Service 82fcde
#  define FXSTATAT(V,d,f,sb,m) fstatat (d, f, sb, m)
Packit Service 82fcde
# endif
Packit Service 82fcde
# define FTW_FUNC_T __ftw_func_t
Packit Service 82fcde
# define NFTW_FUNC_T __nftw_func_t
Packit Service 82fcde
#endif
Packit Service 82fcde
Packit Service 82fcde
/* We define PATH_MAX if the system does not provide a definition.
Packit Service 82fcde
   This does not artificially limit any operation.  PATH_MAX is simply
Packit Service 82fcde
   used as a guesstimate for the expected maximal path length.
Packit Service 82fcde
   Buffers will be enlarged if necessary.  */
Packit Service 82fcde
#ifndef PATH_MAX
Packit Service 82fcde
# define PATH_MAX 1024
Packit Service 82fcde
#endif
Packit Service 82fcde
Packit Service 82fcde
struct dir_data
Packit Service 82fcde
{
Packit Service 82fcde
  DIR *stream;
Packit Service 82fcde
  int streamfd;
Packit Service 82fcde
  char *content;
Packit Service 82fcde
};
Packit Service 82fcde
Packit Service 82fcde
struct known_object
Packit Service 82fcde
{
Packit Service 82fcde
  dev_t dev;
Packit Service 82fcde
  INO_T ino;
Packit Service 82fcde
};
Packit Service 82fcde
Packit Service 82fcde
struct ftw_data
Packit Service 82fcde
{
Packit Service 82fcde
  /* Array with pointers to open directory streams.  */
Packit Service 82fcde
  struct dir_data **dirstreams;
Packit Service 82fcde
  size_t actdir;
Packit Service 82fcde
  size_t maxdir;
Packit Service 82fcde
Packit Service 82fcde
  /* Buffer containing name of currently processed object.  */
Packit Service 82fcde
  char *dirbuf;
Packit Service 82fcde
  size_t dirbufsize;
Packit Service 82fcde
Packit Service 82fcde
  /* Passed as fourth argument to `nftw' callback.  The `base' member
Packit Service 82fcde
     tracks the content of the `dirbuf'.  */
Packit Service 82fcde
  struct FTW ftw;
Packit Service 82fcde
Packit Service 82fcde
  /* Flags passed to `nftw' function.  0 for `ftw'.  */
Packit Service 82fcde
  int flags;
Packit Service 82fcde
Packit Service 82fcde
  /* Conversion array for flag values.  It is the identity mapping for
Packit Service 82fcde
     `nftw' calls, otherwise it maps the values to those known by
Packit Service 82fcde
     `ftw'.  */
Packit Service 82fcde
  const int *cvt_arr;
Packit Service 82fcde
Packit Service 82fcde
  /* Callback function.  We always use the `nftw' form.  */
Packit Service 82fcde
  NFTW_FUNC_T func;
Packit Service 82fcde
Packit Service 82fcde
  /* Device of starting point.  Needed for FTW_MOUNT.  */
Packit Service 82fcde
  dev_t dev;
Packit Service 82fcde
Packit Service 82fcde
  /* Data structure for keeping fingerprints of already processed
Packit Service 82fcde
     object.  This is needed when not using FTW_PHYS.  */
Packit Service 82fcde
  void *known_objects;
Packit Service 82fcde
};
Packit Service 82fcde
Packit Service 82fcde
Packit Service 82fcde
/* Internally we use the FTW_* constants used for `nftw'.  When invoked
Packit Service 82fcde
   as `ftw', map each flag to the subset of values used by `ftw'.  */
Packit Service 82fcde
static const int nftw_arr[] =
Packit Service 82fcde
{
Packit Service 82fcde
  FTW_F, FTW_D, FTW_DNR, FTW_NS, FTW_SL, FTW_DP, FTW_SLN
Packit Service 82fcde
};
Packit Service 82fcde
Packit Service 82fcde
static const int ftw_arr[] =
Packit Service 82fcde
{
Packit Service 82fcde
  FTW_F, FTW_D, FTW_DNR, FTW_NS, FTW_F, FTW_D, FTW_NS
Packit Service 82fcde
};
Packit Service 82fcde
Packit Service 82fcde
Packit Service 82fcde
/* Forward declarations of local functions.  */
Packit Service 82fcde
static int ftw_dir (struct ftw_data *data, struct STAT *st,
Packit Service 82fcde
		    struct dir_data *old_dir);
Packit Service 82fcde
Packit Service 82fcde
Packit Service 82fcde
static int
Packit Service 82fcde
object_compare (const void *p1, const void *p2)
Packit Service 82fcde
{
Packit Service 82fcde
  /* We don't need a sophisticated and useful comparison.  We are only
Packit Service 82fcde
     interested in equality.  However, we must be careful not to
Packit Service 82fcde
     accidentally compare `holes' in the structure.  */
Packit Service 82fcde
  const struct known_object *kp1 = p1, *kp2 = p2;
Packit Service 82fcde
  int cmp1;
Packit Service 82fcde
  cmp1 = (kp1->ino > kp2->ino) - (kp1->ino < kp2->ino);
Packit Service 82fcde
  if (cmp1 != 0)
Packit Service 82fcde
    return cmp1;
Packit Service 82fcde
  return (kp1->dev > kp2->dev) - (kp1->dev < kp2->dev);
Packit Service 82fcde
}
Packit Service 82fcde
Packit Service 82fcde
Packit Service 82fcde
static int
Packit Service 82fcde
add_object (struct ftw_data *data, struct STAT *st)
Packit Service 82fcde
{
Packit Service 82fcde
  struct known_object *newp = malloc (sizeof (struct known_object));
Packit Service 82fcde
  if (newp == NULL)
Packit Service 82fcde
    return -1;
Packit Service 82fcde
  newp->dev = st->st_dev;
Packit Service 82fcde
  newp->ino = st->st_ino;
Packit Service 82fcde
  return __tsearch (newp, &data->known_objects, object_compare) ? 0 : -1;
Packit Service 82fcde
}
Packit Service 82fcde
Packit Service 82fcde
Packit Service 82fcde
static inline int
Packit Service 82fcde
find_object (struct ftw_data *data, struct STAT *st)
Packit Service 82fcde
{
Packit Service 82fcde
  struct known_object obj;
Packit Service 82fcde
  obj.dev = st->st_dev;
Packit Service 82fcde
  obj.ino = st->st_ino;
Packit Service 82fcde
  return __tfind (&obj, &data->known_objects, object_compare) != NULL;
Packit Service 82fcde
}
Packit Service 82fcde
Packit Service 82fcde
Packit Service 82fcde
static inline int
Packit Service 82fcde
__attribute ((always_inline))
Packit Service 82fcde
open_dir_stream (int *dfdp, struct ftw_data *data, struct dir_data *dirp)
Packit Service 82fcde
{
Packit Service 82fcde
  int result = 0;
Packit Service 82fcde
Packit Service 82fcde
  if (data->dirstreams[data->actdir] != NULL)
Packit Service 82fcde
    {
Packit Service 82fcde
      /* Oh, oh.  We must close this stream.  Get all remaining
Packit Service 82fcde
	 entries and store them as a list in the `content' member of
Packit Service 82fcde
	 the `struct dir_data' variable.  */
Packit Service 82fcde
      size_t bufsize = 1024;
Packit Service 82fcde
      char *buf = malloc (bufsize);
Packit Service 82fcde
Packit Service 82fcde
      if (buf == NULL)
Packit Service 82fcde
	result = -1;
Packit Service 82fcde
      else
Packit Service 82fcde
	{
Packit Service 82fcde
	  DIR *st = data->dirstreams[data->actdir]->stream;
Packit Service 82fcde
	  struct dirent64 *d;
Packit Service 82fcde
	  size_t actsize = 0;
Packit Service 82fcde
Packit Service 82fcde
	  while ((d = __readdir64 (st)) != NULL)
Packit Service 82fcde
	    {
Packit Service 82fcde
	      size_t this_len = NAMLEN (d);
Packit Service 82fcde
	      if (actsize + this_len + 2 >= bufsize)
Packit Service 82fcde
		{
Packit Service 82fcde
		  char *newp;
Packit Service 82fcde
		  bufsize += MAX (1024, 2 * this_len);
Packit Service 82fcde
		  newp = (char *) realloc (buf, bufsize);
Packit Service 82fcde
		  if (newp == NULL)
Packit Service 82fcde
		    {
Packit Service 82fcde
		      /* No more memory.  */
Packit Service 82fcde
		      int save_err = errno;
Packit Service 82fcde
		      free (buf);
Packit Service 82fcde
		      __set_errno (save_err);
Packit Service 82fcde
		      return -1;
Packit Service 82fcde
		    }
Packit Service 82fcde
		  buf = newp;
Packit Service 82fcde
		}
Packit Service 82fcde
Packit Service 82fcde
	      *((char *) __mempcpy (buf + actsize, d->d_name, this_len))
Packit Service 82fcde
		= '\0';
Packit Service 82fcde
	      actsize += this_len + 1;
Packit Service 82fcde
	    }
Packit Service 82fcde
Packit Service 82fcde
	  /* Terminate the list with an additional NUL byte.  */
Packit Service 82fcde
	  buf[actsize++] = '\0';
Packit Service 82fcde
Packit Service 82fcde
	  /* Shrink the buffer to what we actually need.  */
Packit Service 82fcde
	  data->dirstreams[data->actdir]->content = realloc (buf, actsize);
Packit Service 82fcde
	  if (data->dirstreams[data->actdir]->content == NULL)
Packit Service 82fcde
	    {
Packit Service 82fcde
	      int save_err = errno;
Packit Service 82fcde
	      free (buf);
Packit Service 82fcde
	      __set_errno (save_err);
Packit Service 82fcde
	      result = -1;
Packit Service 82fcde
	    }
Packit Service 82fcde
	  else
Packit Service 82fcde
	    {
Packit Service 82fcde
	      __closedir (st);
Packit Service 82fcde
	      data->dirstreams[data->actdir]->stream = NULL;
Packit Service 82fcde
	      data->dirstreams[data->actdir]->streamfd = -1;
Packit Service 82fcde
	      data->dirstreams[data->actdir] = NULL;
Packit Service 82fcde
	    }
Packit Service 82fcde
	}
Packit Service 82fcde
    }
Packit Service 82fcde
Packit Service 82fcde
  /* Open the new stream.  */
Packit Service 82fcde
  if (result == 0)
Packit Service 82fcde
    {
Packit Service 82fcde
      assert (data->dirstreams[data->actdir] == NULL);
Packit Service 82fcde
Packit Service 82fcde
      if (dfdp != NULL && *dfdp != -1)
Packit Service 82fcde
	{
Packit Service 82fcde
	  int fd = __openat64_nocancel (*dfdp, data->dirbuf + data->ftw.base,
Packit Service 82fcde
					O_RDONLY | O_DIRECTORY | O_NDELAY);
Packit Service 82fcde
	  dirp->stream = NULL;
Packit Service 82fcde
	  if (fd != -1 && (dirp->stream = __fdopendir (fd)) == NULL)
Packit Service 82fcde
	    __close_nocancel_nostatus (fd);
Packit Service 82fcde
	}
Packit Service 82fcde
      else
Packit Service 82fcde
	{
Packit Service 82fcde
	  const char *name;
Packit Service 82fcde
Packit Service 82fcde
	  if (data->flags & FTW_CHDIR)
Packit Service 82fcde
	    {
Packit Service 82fcde
	      name = data->dirbuf + data->ftw.base;
Packit Service 82fcde
	      if (name[0] == '\0')
Packit Service 82fcde
		name = ".";
Packit Service 82fcde
	    }
Packit Service 82fcde
	  else
Packit Service 82fcde
	    name = data->dirbuf;
Packit Service 82fcde
Packit Service 82fcde
	  dirp->stream = __opendir (name);
Packit Service 82fcde
	}
Packit Service 82fcde
Packit Service 82fcde
      if (dirp->stream == NULL)
Packit Service 82fcde
	result = -1;
Packit Service 82fcde
      else
Packit Service 82fcde
	{
Packit Service 82fcde
	  dirp->streamfd = __dirfd (dirp->stream);
Packit Service 82fcde
	  dirp->content = NULL;
Packit Service 82fcde
	  data->dirstreams[data->actdir] = dirp;
Packit Service 82fcde
Packit Service 82fcde
	  if (++data->actdir == data->maxdir)
Packit Service 82fcde
	    data->actdir = 0;
Packit Service 82fcde
	}
Packit Service 82fcde
    }
Packit Service 82fcde
Packit Service 82fcde
  return result;
Packit Service 82fcde
}
Packit Service 82fcde
Packit Service 82fcde
Packit Service 82fcde
static int
Packit Service 82fcde
process_entry (struct ftw_data *data, struct dir_data *dir, const char *name,
Packit Service 82fcde
	       size_t namlen, int d_type)
Packit Service 82fcde
{
Packit Service 82fcde
  struct STAT st;
Packit Service 82fcde
  int result = 0;
Packit Service 82fcde
  int flag = 0;
Packit Service 82fcde
  size_t new_buflen;
Packit Service 82fcde
Packit Service 82fcde
  if (name[0] == '.' && (name[1] == '\0'
Packit Service 82fcde
			 || (name[1] == '.' && name[2] == '\0')))
Packit Service 82fcde
    /* Don't process the "." and ".." entries.  */
Packit Service 82fcde
    return 0;
Packit Service 82fcde
Packit Service 82fcde
  new_buflen = data->ftw.base + namlen + 2;
Packit Service 82fcde
  if (data->dirbufsize < new_buflen)
Packit Service 82fcde
    {
Packit Service 82fcde
      /* Enlarge the buffer.  */
Packit Service 82fcde
      char *newp;
Packit Service 82fcde
Packit Service 82fcde
      data->dirbufsize = 2 * new_buflen;
Packit Service 82fcde
      newp = (char *) realloc (data->dirbuf, data->dirbufsize);
Packit Service 82fcde
      if (newp == NULL)
Packit Service 82fcde
	return -1;
Packit Service 82fcde
      data->dirbuf = newp;
Packit Service 82fcde
    }
Packit Service 82fcde
Packit Service 82fcde
  *((char *) __mempcpy (data->dirbuf + data->ftw.base, name, namlen)) = '\0';
Packit Service 82fcde
Packit Service 82fcde
  int statres;
Packit Service 82fcde
  if (dir->streamfd != -1)
Packit Service 82fcde
    statres = FXSTATAT (_STAT_VER, dir->streamfd, name, &st,
Packit Service 82fcde
			(data->flags & FTW_PHYS) ? AT_SYMLINK_NOFOLLOW : 0);
Packit Service 82fcde
  else
Packit Service 82fcde
    {
Packit Service 82fcde
      if ((data->flags & FTW_CHDIR) == 0)
Packit Service 82fcde
	name = data->dirbuf;
Packit Service 82fcde
Packit Service 82fcde
      statres = ((data->flags & FTW_PHYS)
Packit Service 82fcde
		 ? LXSTAT (_STAT_VER, name, &st)
Packit Service 82fcde
		 : XSTAT (_STAT_VER, name, &st);;
Packit Service 82fcde
    }
Packit Service 82fcde
Packit Service 82fcde
  if (statres < 0)
Packit Service 82fcde
    {
Packit Service 82fcde
      if (errno != EACCES && errno != ENOENT)
Packit Service 82fcde
	result = -1;
Packit Service 82fcde
      else if (data->flags & FTW_PHYS)
Packit Service 82fcde
	flag = FTW_NS;
Packit Service 82fcde
      else if (d_type == DT_LNK)
Packit Service 82fcde
	flag = FTW_SLN;
Packit Service 82fcde
      else
Packit Service 82fcde
	{
Packit Service 82fcde
	  if (dir->streamfd != -1)
Packit Service 82fcde
	    statres = FXSTATAT (_STAT_VER, dir->streamfd, name, &st,
Packit Service 82fcde
				AT_SYMLINK_NOFOLLOW);
Packit Service 82fcde
	  else
Packit Service 82fcde
	    statres = LXSTAT (_STAT_VER, name, &st);
Packit Service 82fcde
	  if (statres == 0 && S_ISLNK (st.st_mode))
Packit Service 82fcde
	    flag = FTW_SLN;
Packit Service 82fcde
	  else
Packit Service 82fcde
	    flag = FTW_NS;
Packit Service 82fcde
	}
Packit Service 82fcde
    }
Packit Service 82fcde
  else
Packit Service 82fcde
    {
Packit Service 82fcde
      if (S_ISDIR (st.st_mode))
Packit Service 82fcde
	flag = FTW_D;
Packit Service 82fcde
      else if (S_ISLNK (st.st_mode))
Packit Service 82fcde
	flag = FTW_SL;
Packit Service 82fcde
      else
Packit Service 82fcde
	flag = FTW_F;
Packit Service 82fcde
    }
Packit Service 82fcde
Packit Service 82fcde
  if (result == 0
Packit Service 82fcde
      && (flag == FTW_NS
Packit Service 82fcde
	  || !(data->flags & FTW_MOUNT) || st.st_dev == data->dev))
Packit Service 82fcde
    {
Packit Service 82fcde
      if (flag == FTW_D)
Packit Service 82fcde
	{
Packit Service 82fcde
	  if ((data->flags & FTW_PHYS)
Packit Service 82fcde
	      || (!find_object (data, &st)
Packit Service 82fcde
		  /* Remember the object.  */
Packit Service 82fcde
		  && (result = add_object (data, &st)) == 0))
Packit Service 82fcde
	    result = ftw_dir (data, &st, dir);
Packit Service 82fcde
	}
Packit Service 82fcde
      else
Packit Service 82fcde
	result = (*data->func) (data->dirbuf, &st, data->cvt_arr[flag],
Packit Service 82fcde
				&data->ftw);
Packit Service 82fcde
    }
Packit Service 82fcde
Packit Service 82fcde
  if ((data->flags & FTW_ACTIONRETVAL) && result == FTW_SKIP_SUBTREE)
Packit Service 82fcde
    result = 0;
Packit Service 82fcde
Packit Service 82fcde
  return result;
Packit Service 82fcde
}
Packit Service 82fcde
Packit Service 82fcde
Packit Service 82fcde
static int
Packit Service 82fcde
__attribute ((noinline))
Packit Service 82fcde
ftw_dir (struct ftw_data *data, struct STAT *st, struct dir_data *old_dir)
Packit Service 82fcde
{
Packit Service 82fcde
  struct dir_data dir;
Packit Service 82fcde
  struct dirent64 *d;
Packit Service 82fcde
  int previous_base = data->ftw.base;
Packit Service 82fcde
  int result;
Packit Service 82fcde
  char *startp;
Packit Service 82fcde
Packit Service 82fcde
  /* Open the stream for this directory.  This might require that
Packit Service 82fcde
     another stream has to be closed.  */
Packit Service 82fcde
  result = open_dir_stream (old_dir == NULL ? NULL : &old_dir->streamfd,
Packit Service 82fcde
			    data, &dir;;
Packit Service 82fcde
  if (result != 0)
Packit Service 82fcde
    {
Packit Service 82fcde
      if (errno == EACCES)
Packit Service 82fcde
	/* We cannot read the directory.  Signal this with a special flag.  */
Packit Service 82fcde
	result = (*data->func) (data->dirbuf, st, FTW_DNR, &data->ftw);
Packit Service 82fcde
Packit Service 82fcde
      return result;
Packit Service 82fcde
    }
Packit Service 82fcde
Packit Service 82fcde
  /* First, report the directory (if not depth-first).  */
Packit Service 82fcde
  if (!(data->flags & FTW_DEPTH))
Packit Service 82fcde
    {
Packit Service 82fcde
      result = (*data->func) (data->dirbuf, st, FTW_D, &data->ftw);
Packit Service 82fcde
      if (result != 0)
Packit Service 82fcde
	{
Packit Service 82fcde
	  int save_err;
Packit Service 82fcde
fail:
Packit Service 82fcde
	  save_err = errno;
Packit Service 82fcde
	  __closedir (dir.stream);
Packit Service 82fcde
	  dir.streamfd = -1;
Packit Service 82fcde
	  __set_errno (save_err);
Packit Service 82fcde
Packit Service 82fcde
	  if (data->actdir-- == 0)
Packit Service 82fcde
	    data->actdir = data->maxdir - 1;
Packit Service 82fcde
	  data->dirstreams[data->actdir] = NULL;
Packit Service 82fcde
	  return result;
Packit Service 82fcde
	}
Packit Service 82fcde
    }
Packit Service 82fcde
Packit Service 82fcde
  /* If necessary, change to this directory.  */
Packit Service 82fcde
  if (data->flags & FTW_CHDIR)
Packit Service 82fcde
    {
Packit Service 82fcde
      if (__fchdir (__dirfd (dir.stream)) < 0)
Packit Service 82fcde
	{
Packit Service 82fcde
	  result = -1;
Packit Service 82fcde
	  goto fail;
Packit Service 82fcde
	}
Packit Service 82fcde
    }
Packit Service 82fcde
Packit Service 82fcde
  /* Next, update the `struct FTW' information.  */
Packit Service 82fcde
  ++data->ftw.level;
Packit Service 82fcde
  startp = __rawmemchr (data->dirbuf, '\0');
Packit Service 82fcde
  /* There always must be a directory name.  */
Packit Service 82fcde
  assert (startp != data->dirbuf);
Packit Service 82fcde
  if (startp[-1] != '/')
Packit Service 82fcde
    *startp++ = '/';
Packit Service 82fcde
  data->ftw.base = startp - data->dirbuf;
Packit Service 82fcde
Packit Service 82fcde
  while (dir.stream != NULL && (d = __readdir64 (dir.stream)) != NULL)
Packit Service 82fcde
    {
Packit Service 82fcde
      int d_type = DT_UNKNOWN;
Packit Service 82fcde
#ifdef _DIRENT_HAVE_D_TYPE
Packit Service 82fcde
      d_type = d->d_type;
Packit Service 82fcde
#endif
Packit Service 82fcde
      result = process_entry (data, &dir, d->d_name, NAMLEN (d), d_type);
Packit Service 82fcde
      if (result != 0)
Packit Service 82fcde
	break;
Packit Service 82fcde
    }
Packit Service 82fcde
Packit Service 82fcde
  if (dir.stream != NULL)
Packit Service 82fcde
    {
Packit Service 82fcde
      /* The stream is still open.  I.e., we did not need more
Packit Service 82fcde
	 descriptors.  Simply close the stream now.  */
Packit Service 82fcde
      int save_err = errno;
Packit Service 82fcde
Packit Service 82fcde
      assert (dir.content == NULL);
Packit Service 82fcde
Packit Service 82fcde
      __closedir (dir.stream);
Packit Service 82fcde
      dir.streamfd = -1;
Packit Service 82fcde
      __set_errno (save_err);
Packit Service 82fcde
Packit Service 82fcde
      if (data->actdir-- == 0)
Packit Service 82fcde
	data->actdir = data->maxdir - 1;
Packit Service 82fcde
      data->dirstreams[data->actdir] = NULL;
Packit Service 82fcde
    }
Packit Service 82fcde
  else
Packit Service 82fcde
    {
Packit Service 82fcde
      int save_err;
Packit Service 82fcde
      char *runp = dir.content;
Packit Service 82fcde
Packit Service 82fcde
      while (result == 0 && *runp != '\0')
Packit Service 82fcde
	{
Packit Service 82fcde
	  char *endp = strchr (runp, '\0');
Packit Service 82fcde
Packit Service 82fcde
	  // XXX Should store the d_type values as well?!
Packit Service 82fcde
	  result = process_entry (data, &dir, runp, endp - runp, DT_UNKNOWN);
Packit Service 82fcde
Packit Service 82fcde
	  runp = endp + 1;
Packit Service 82fcde
	}
Packit Service 82fcde
Packit Service 82fcde
      save_err = errno;
Packit Service 82fcde
      free (dir.content);
Packit Service 82fcde
      __set_errno (save_err);
Packit Service 82fcde
    }
Packit Service 82fcde
Packit Service 82fcde
  if ((data->flags & FTW_ACTIONRETVAL) && result == FTW_SKIP_SIBLINGS)
Packit Service 82fcde
    result = 0;
Packit Service 82fcde
Packit Service 82fcde
  /* Prepare the return, revert the `struct FTW' information.  */
Packit Service 82fcde
  data->dirbuf[data->ftw.base - 1] = '\0';
Packit Service 82fcde
  --data->ftw.level;
Packit Service 82fcde
  data->ftw.base = previous_base;
Packit Service 82fcde
Packit Service 82fcde
  /* Finally, if we process depth-first report the directory.  */
Packit Service 82fcde
  if (result == 0 && (data->flags & FTW_DEPTH))
Packit Service 82fcde
    result = (*data->func) (data->dirbuf, st, FTW_DP, &data->ftw);
Packit Service 82fcde
Packit Service 82fcde
  if (old_dir
Packit Service 82fcde
      && (data->flags & FTW_CHDIR)
Packit Service 82fcde
      && (result == 0
Packit Service 82fcde
	  || ((data->flags & FTW_ACTIONRETVAL)
Packit Service 82fcde
	      && (result != -1 && result != FTW_STOP))))
Packit Service 82fcde
    {
Packit Service 82fcde
      /* Change back to the parent directory.  */
Packit Service 82fcde
      int done = 0;
Packit Service 82fcde
      if (old_dir->stream != NULL)
Packit Service 82fcde
	if (__fchdir (__dirfd (old_dir->stream)) == 0)
Packit Service 82fcde
	  done = 1;
Packit Service 82fcde
Packit Service 82fcde
      if (!done)
Packit Service 82fcde
	{
Packit Service 82fcde
	  if (data->ftw.base == 1)
Packit Service 82fcde
	    {
Packit Service 82fcde
	      if (__chdir ("/") < 0)
Packit Service 82fcde
		result = -1;
Packit Service 82fcde
	    }
Packit Service 82fcde
	  else
Packit Service 82fcde
	    if (__chdir ("..") < 0)
Packit Service 82fcde
	      result = -1;
Packit Service 82fcde
	}
Packit Service 82fcde
    }
Packit Service 82fcde
Packit Service 82fcde
  return result;
Packit Service 82fcde
}
Packit Service 82fcde
Packit Service 82fcde
Packit Service 82fcde
static int
Packit Service 82fcde
__attribute ((noinline))
Packit Service 82fcde
ftw_startup (const char *dir, int is_nftw, void *func, int descriptors,
Packit Service 82fcde
	     int flags)
Packit Service 82fcde
{
Packit Service 82fcde
  struct ftw_data data;
Packit Service 82fcde
  struct STAT st;
Packit Service 82fcde
  int result = 0;
Packit Service 82fcde
  int save_err;
Packit Service 82fcde
  int cwdfd = -1;
Packit Service 82fcde
  char *cwd = NULL;
Packit Service 82fcde
  char *cp;
Packit Service 82fcde
Packit Service 82fcde
  /* First make sure the parameters are reasonable.  */
Packit Service 82fcde
  if (dir[0] == '\0')
Packit Service 82fcde
    {
Packit Service 82fcde
      __set_errno (ENOENT);
Packit Service 82fcde
      return -1;
Packit Service 82fcde
    }
Packit Service 82fcde
Packit Service 82fcde
  data.maxdir = descriptors < 1 ? 1 : descriptors;
Packit Service 82fcde
  data.actdir = 0;
Packit Service 82fcde
  data.dirstreams = (struct dir_data **) alloca (data.maxdir
Packit Service 82fcde
						 * sizeof (struct dir_data *));
Packit Service 82fcde
  memset (data.dirstreams, '\0', data.maxdir * sizeof (struct dir_data *));
Packit Service 82fcde
Packit Service 82fcde
  /* PATH_MAX is always defined when we get here.  */
Packit Service 82fcde
  data.dirbufsize = MAX (2 * strlen (dir), PATH_MAX);
Packit Service 82fcde
  data.dirbuf = (char *) malloc (data.dirbufsize);
Packit Service 82fcde
  if (data.dirbuf == NULL)
Packit Service 82fcde
    return -1;
Packit Service 82fcde
  cp = __stpcpy (data.dirbuf, dir);
Packit Service 82fcde
  /* Strip trailing slashes.  */
Packit Service 82fcde
  while (cp > data.dirbuf + 1 && cp[-1] == '/')
Packit Service 82fcde
    --cp;
Packit Service 82fcde
  *cp = '\0';
Packit Service 82fcde
Packit Service 82fcde
  data.ftw.level = 0;
Packit Service 82fcde
Packit Service 82fcde
  /* Find basename.  */
Packit Service 82fcde
  while (cp > data.dirbuf && cp[-1] != '/')
Packit Service 82fcde
    --cp;
Packit Service 82fcde
  data.ftw.base = cp - data.dirbuf;
Packit Service 82fcde
Packit Service 82fcde
  data.flags = flags;
Packit Service 82fcde
Packit Service 82fcde
  /* This assignment might seem to be strange but it is what we want.
Packit Service 82fcde
     The trick is that the first three arguments to the `ftw' and
Packit Service 82fcde
     `nftw' callback functions are equal.  Therefore we can call in
Packit Service 82fcde
     every case the callback using the format of the `nftw' version
Packit Service 82fcde
     and get the correct result since the stack layout for a function
Packit Service 82fcde
     call in C allows this.  */
Packit Service 82fcde
  data.func = (NFTW_FUNC_T) func;
Packit Service 82fcde
Packit Service 82fcde
  /* Since we internally use the complete set of FTW_* values we need
Packit Service 82fcde
     to reduce the value range before calling a `ftw' callback.  */
Packit Service 82fcde
  data.cvt_arr = is_nftw ? nftw_arr : ftw_arr;
Packit Service 82fcde
Packit Service 82fcde
  /* No object known so far.  */
Packit Service 82fcde
  data.known_objects = NULL;
Packit Service 82fcde
Packit Service 82fcde
  /* Now go to the directory containing the initial file/directory.  */
Packit Service 82fcde
  if (flags & FTW_CHDIR)
Packit Service 82fcde
    {
Packit Service 82fcde
      /* We have to be able to go back to the current working
Packit Service 82fcde
	 directory.  The best way to do this is to use a file
Packit Service 82fcde
	 descriptor.  */
Packit Service 82fcde
      cwdfd = __open (".", O_RDONLY | O_DIRECTORY);
Packit Service 82fcde
      if (cwdfd == -1)
Packit Service 82fcde
	{
Packit Service 82fcde
	  /* Try getting the directory name.  This can be needed if
Packit Service 82fcde
	     the current directory is executable but not readable.  */
Packit Service 82fcde
	  if (errno == EACCES)
Packit Service 82fcde
	    /* GNU extension ahead.  */
Packit Service 82fcde
	    cwd =  __getcwd (NULL, 0);
Packit Service 82fcde
Packit Service 82fcde
	  if (cwd == NULL)
Packit Service 82fcde
	    goto out_fail;
Packit Service 82fcde
	}
Packit Service 82fcde
      else if (data.maxdir > 1)
Packit Service 82fcde
	/* Account for the file descriptor we use here.  */
Packit Service 82fcde
	--data.maxdir;
Packit Service 82fcde
Packit Service 82fcde
      if (data.ftw.base > 0)
Packit Service 82fcde
	{
Packit Service 82fcde
	  /* Change to the directory the file is in.  In data.dirbuf
Packit Service 82fcde
	     we have a writable copy of the file name.  Just NUL
Packit Service 82fcde
	     terminate it for now and change the directory.  */
Packit Service 82fcde
	  if (data.ftw.base == 1)
Packit Service 82fcde
	    /* I.e., the file is in the root directory.  */
Packit Service 82fcde
	    result = __chdir ("/");
Packit Service 82fcde
	  else
Packit Service 82fcde
	    {
Packit Service 82fcde
	      char ch = data.dirbuf[data.ftw.base - 1];
Packit Service 82fcde
	      data.dirbuf[data.ftw.base - 1] = '\0';
Packit Service 82fcde
	      result = __chdir (data.dirbuf);
Packit Service 82fcde
	      data.dirbuf[data.ftw.base - 1] = ch;
Packit Service 82fcde
	    }
Packit Service 82fcde
	}
Packit Service 82fcde
    }
Packit Service 82fcde
Packit Service 82fcde
  /* Get stat info for start directory.  */
Packit Service 82fcde
  if (result == 0)
Packit Service 82fcde
    {
Packit Service 82fcde
      const char *name;
Packit Service 82fcde
Packit Service 82fcde
      if (data.flags & FTW_CHDIR)
Packit Service 82fcde
	{
Packit Service 82fcde
	  name = data.dirbuf + data.ftw.base;
Packit Service 82fcde
	  if (name[0] == '\0')
Packit Service 82fcde
	    name = ".";
Packit Service 82fcde
	}
Packit Service 82fcde
      else
Packit Service 82fcde
	name = data.dirbuf;
Packit Service 82fcde
Packit Service 82fcde
      if (((flags & FTW_PHYS)
Packit Service 82fcde
	   ? LXSTAT (_STAT_VER, name, &st)
Packit Service 82fcde
	   : XSTAT (_STAT_VER, name, &st)) < 0)
Packit Service 82fcde
	{
Packit Service 82fcde
	  if (!(flags & FTW_PHYS)
Packit Service 82fcde
	      && errno == ENOENT
Packit Service 82fcde
	      && LXSTAT (_STAT_VER, name, &st) == 0
Packit Service 82fcde
	      && S_ISLNK (st.st_mode))
Packit Service 82fcde
	    result = (*data.func) (data.dirbuf, &st, data.cvt_arr[FTW_SLN],
Packit Service 82fcde
				   &data.ftw);
Packit Service 82fcde
	  else
Packit Service 82fcde
	    /* No need to call the callback since we cannot say anything
Packit Service 82fcde
	       about the object.  */
Packit Service 82fcde
	    result = -1;
Packit Service 82fcde
	}
Packit Service 82fcde
      else
Packit Service 82fcde
	{
Packit Service 82fcde
	  if (S_ISDIR (st.st_mode))
Packit Service 82fcde
	    {
Packit Service 82fcde
	      /* Remember the device of the initial directory in case
Packit Service 82fcde
		 FTW_MOUNT is given.  */
Packit Service 82fcde
	      data.dev = st.st_dev;
Packit Service 82fcde
Packit Service 82fcde
	      /* We know this directory now.  */
Packit Service 82fcde
	      if (!(flags & FTW_PHYS))
Packit Service 82fcde
		result = add_object (&data, &st);
Packit Service 82fcde
Packit Service 82fcde
	      if (result == 0)
Packit Service 82fcde
		result = ftw_dir (&data, &st, NULL);
Packit Service 82fcde
	    }
Packit Service 82fcde
	  else
Packit Service 82fcde
	    {
Packit Service 82fcde
	      int flag = S_ISLNK (st.st_mode) ? FTW_SL : FTW_F;
Packit Service 82fcde
Packit Service 82fcde
	      result = (*data.func) (data.dirbuf, &st, data.cvt_arr[flag],
Packit Service 82fcde
				     &data.ftw);
Packit Service 82fcde
	    }
Packit Service 82fcde
	}
Packit Service 82fcde
Packit Service 82fcde
      if ((flags & FTW_ACTIONRETVAL)
Packit Service 82fcde
	  && (result == FTW_SKIP_SUBTREE || result == FTW_SKIP_SIBLINGS))
Packit Service 82fcde
	result = 0;
Packit Service 82fcde
    }
Packit Service 82fcde
Packit Service 82fcde
  /* Return to the start directory (if necessary).  */
Packit Service 82fcde
  if (cwdfd != -1)
Packit Service 82fcde
    {
Packit Service 82fcde
      int save_err = errno;
Packit Service 82fcde
      __fchdir (cwdfd);
Packit Service 82fcde
      __close_nocancel_nostatus (cwdfd);
Packit Service 82fcde
      __set_errno (save_err);
Packit Service 82fcde
    }
Packit Service 82fcde
  else if (cwd != NULL)
Packit Service 82fcde
    {
Packit Service 82fcde
      int save_err = errno;
Packit Service 82fcde
      __chdir (cwd);
Packit Service 82fcde
      free (cwd);
Packit Service 82fcde
      __set_errno (save_err);
Packit Service 82fcde
    }
Packit Service 82fcde
Packit Service 82fcde
  /* Free all memory.  */
Packit Service 82fcde
 out_fail:
Packit Service 82fcde
  save_err = errno;
Packit Service 82fcde
  __tdestroy (data.known_objects, free);
Packit Service 82fcde
  free (data.dirbuf);
Packit Service 82fcde
  __set_errno (save_err);
Packit Service 82fcde
Packit Service 82fcde
  return result;
Packit Service 82fcde
}
Packit Service 82fcde
Packit Service 82fcde
Packit Service 82fcde
Packit Service 82fcde
/* Entry points.  */
Packit Service 82fcde
Packit Service 82fcde
int
Packit Service 82fcde
FTW_NAME (const char *path, FTW_FUNC_T func, int descriptors)
Packit Service 82fcde
{
Packit Service 82fcde
  return ftw_startup (path, 0, func, descriptors, 0);
Packit Service 82fcde
}
Packit Service 82fcde
Packit Service 82fcde
#ifndef _LIBC
Packit Service 82fcde
int
Packit Service 82fcde
NFTW_NAME (const char *path, NFTW_FUNC_T func, int descriptors, int flags)
Packit Service 82fcde
{
Packit Service 82fcde
  return ftw_startup (path, 1, func, descriptors, flags);
Packit Service 82fcde
}
Packit Service 82fcde
#else
Packit Service 82fcde
Packit Service 82fcde
# include <shlib-compat.h>
Packit Service 82fcde
Packit Service 82fcde
int NFTW_NEW_NAME (const char *, NFTW_FUNC_T, int, int);
Packit Service 82fcde
Packit Service 82fcde
int
Packit Service 82fcde
NFTW_NEW_NAME (const char *path, NFTW_FUNC_T func, int descriptors, int flags)
Packit Service 82fcde
{
Packit Service 82fcde
  if (flags
Packit Service 82fcde
      & ~(FTW_PHYS | FTW_MOUNT | FTW_CHDIR | FTW_DEPTH | FTW_ACTIONRETVAL))
Packit Service 82fcde
    {
Packit Service 82fcde
      __set_errno (EINVAL);
Packit Service 82fcde
      return -1;
Packit Service 82fcde
    }
Packit Service 82fcde
  return ftw_startup (path, 1, func, descriptors, flags);
Packit Service 82fcde
}
Packit Service 82fcde
Packit Service 82fcde
versioned_symbol (libc, NFTW_NEW_NAME, NFTW_NAME, GLIBC_2_3_3);
Packit Service 82fcde
Packit Service 82fcde
# if SHLIB_COMPAT(libc, GLIBC_2_1, GLIBC_2_3_3)
Packit Service 82fcde
Packit Service 82fcde
/* Older nftw* version just ignored all unknown flags.  */
Packit Service 82fcde
Packit Service 82fcde
int NFTW_OLD_NAME (const char *, NFTW_FUNC_T, int, int);
Packit Service 82fcde
Packit Service 82fcde
int
Packit Service 82fcde
attribute_compat_text_section
Packit Service 82fcde
NFTW_OLD_NAME (const char *path, NFTW_FUNC_T func, int descriptors, int flags)
Packit Service 82fcde
{
Packit Service 82fcde
  flags &= (FTW_PHYS | FTW_MOUNT | FTW_CHDIR | FTW_DEPTH);
Packit Service 82fcde
  return ftw_startup (path, 1, func, descriptors, flags);
Packit Service 82fcde
}
Packit Service 82fcde
Packit Service 82fcde
compat_symbol (libc, NFTW_OLD_NAME, NFTW_NAME, GLIBC_2_1);
Packit Service 82fcde
# endif
Packit Service 82fcde
#endif