Back to index

glibc  2.9
Classes | Defines | Functions | Variables
ftw.c File Reference
#include <errno.h>
#include <fcntl.h>
#include <ftw.h>
#include <limits.h>
#include <search.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <not-cancel.h>
#include <sys/stat.h>
#include <assert.h>
This graph shows which files directly or indirectly include this file:

Go to the source code of this file.

Classes

struct  dir_data
struct  known_object
struct  ftw_data

Defines

#define dirent   direct
#define NAMLEN(dirent)   (dirent)->d_namlen
#define mempcpy(D, S, N)   ((void *) ((char *) memcpy (D, S, N) + (N)))
#define __chdir   chdir
#define __closedir   closedir
#define __fchdir   fchdir
#define __getcwd(P, N)   xgetcwd ()
#define __mempcpy   mempcpy
#define __opendir   opendir
#define __readdir64   readdir
#define __stpcpy   stpcpy
#define __tdestroy   tdestroy
#define __tfind   tfind
#define __tsearch   tsearch
#define internal_function   /* empty */
#define dirent64   dirent
#define MAX(a, b)   ((a) > (b) ? (a) : (b))
#define lstat(Name, Stat_buf)   rpl_lstat(Name, Stat_buf)
#define __set_errno(Val)   errno = (Val)
#define FTW_NAME   ftw
#define NFTW_NAME   nftw
#define NFTW_OLD_NAME   __old_nftw
#define NFTW_NEW_NAME   __new_nftw
#define INO_T   ino_t
#define STAT   stat
#define LXSTAT(V, f, sb)   lstat (f,sb)
#define XSTAT(V, f, sb)   stat (f,sb)
#define FXSTATAT(V, d, f, sb, m)   fstatat (d, f, sb, m)
#define FTW_FUNC_T   __ftw_func_t
#define NFTW_FUNC_T   __nftw_func_t
#define PATH_MAX   1024

Functions

char * alloca ()
char * stpcpy ()
char * xgetcwd (void)
int rpl_lstat (const char *, struct stat *)
static int ftw_dir (struct ftw_data *data, struct STAT *st, struct dir_data *old_dir) internal_function
static int object_compare (const void *p1, const void *p2)
static int add_object (struct ftw_data *data, struct STAT *st)
static int find_object (struct ftw_data *data, struct STAT *st)
static int __attribute ((always_inline))
static int internal_function process_entry (struct ftw_data *data, struct dir_data *dir, const char *name, size_t namlen, int d_type)
static int __attribute ((noinline))

Variables

static const int nftw_arr []
static const int ftw_arr []
int const char * path
FTW_FUNC_T func
int descriptors
int flags

Class Documentation

struct dir_data

Definition at line 165 of file ftw.c.

Class Members
char * content
DIR * stream
int streamfd
struct known_object

Definition at line 172 of file ftw.c.

Class Members
dev_t dev
INO_T ino
struct ftw_data

Definition at line 178 of file ftw.c.

Collaboration diagram for ftw_data:
Class Members
size_t actdir
const int * cvt_arr
dev_t dev
char * dirbuf
size_t dirbufsize
struct dir_data ** dirstreams
int flags
NFTW_FUNC_T func
void * known_objects
size_t maxdir

Define Documentation

#define __chdir   chdir

Definition at line 93 of file ftw.c.

#define __closedir   closedir

Definition at line 95 of file ftw.c.

#define __fchdir   fchdir

Definition at line 97 of file ftw.c.

#define __getcwd (   P,
  N 
)    xgetcwd ()

Definition at line 99 of file ftw.c.

#define __mempcpy   mempcpy

Definition at line 102 of file ftw.c.

#define __opendir   opendir

Definition at line 104 of file ftw.c.

#define __readdir64   readdir

Definition at line 106 of file ftw.c.

#define __set_errno (   Val)    errno = (Val)

Definition at line 133 of file ftw.c.

#define __stpcpy   stpcpy

Definition at line 108 of file ftw.c.

#define __tdestroy   tdestroy

Definition at line 110 of file ftw.c.

#define __tfind   tfind

Definition at line 112 of file ftw.c.

#define __tsearch   tsearch

Definition at line 114 of file ftw.c.

#define dirent   direct

Definition at line 47 of file ftw.c.

#define dirent64   dirent

Definition at line 118 of file ftw.c.

#define FTW_FUNC_T   __ftw_func_t

Definition at line 153 of file ftw.c.

#define FTW_NAME   ftw

Definition at line 138 of file ftw.c.

#define FXSTATAT (   V,
  d,
  f,
  sb,
  m 
)    fstatat (d, f, sb, m)

Definition at line 151 of file ftw.c.

#define INO_T   ino_t

Definition at line 142 of file ftw.c.

#define internal_function   /* empty */

Definition at line 116 of file ftw.c.

#define lstat (   Name,
  Stat_buf 
)    rpl_lstat(Name, Stat_buf)

Definition at line 129 of file ftw.c.

#define LXSTAT (   V,
  f,
  sb 
)    lstat (f,sb)

Definition at line 149 of file ftw.c.

#define MAX (   a,
  b 
)    ((a) > (b) ? (a) : (b))

Definition at line 120 of file ftw.c.

#define mempcpy (   D,
  S,
  N 
)    ((void *) ((char *) memcpy (D, S, N) + (N)))

Definition at line 85 of file ftw.c.

#define NAMLEN (   dirent)    (dirent)->d_namlen

Definition at line 48 of file ftw.c.

#define NFTW_FUNC_T   __nftw_func_t

Definition at line 154 of file ftw.c.

#define NFTW_NAME   nftw

Definition at line 139 of file ftw.c.

#define NFTW_NEW_NAME   __new_nftw

Definition at line 141 of file ftw.c.

#define NFTW_OLD_NAME   __old_nftw

Definition at line 140 of file ftw.c.

#define PATH_MAX   1024

Definition at line 162 of file ftw.c.

#define STAT   stat

Definition at line 143 of file ftw.c.

#define XSTAT (   V,
  f,
  sb 
)    stat (f,sb)

Definition at line 150 of file ftw.c.


Function Documentation

static int __attribute ( (always_inline)  ) [inline, static]

Definition at line 269 of file ftw.c.

{
  int result = 0;

  if (data->dirstreams[data->actdir] != NULL)
    {
      /* Oh, oh.  We must close this stream.  Get all remaining
        entries and store them as a list in the `content' member of
        the `struct dir_data' variable.  */
      size_t bufsize = 1024;
      char *buf = malloc (bufsize);

      if (buf == NULL)
       result = -1;
      else
       {
         DIR *st = data->dirstreams[data->actdir]->stream;
         struct dirent64 *d;
         size_t actsize = 0;

         while ((d = __readdir64 (st)) != NULL)
           {
             size_t this_len = NAMLEN (d);
             if (actsize + this_len + 2 >= bufsize)
              {
                char *newp;
                bufsize += MAX (1024, 2 * this_len);
                newp = (char *) realloc (buf, bufsize);
                if (newp == NULL)
                  {
                    /* No more memory.  */
                    int save_err = errno;
                    free (buf);
                    __set_errno (save_err);
                    return -1;
                  }
                buf = newp;
              }

             *((char *) __mempcpy (buf + actsize, d->d_name, this_len))
              = '\0';
             actsize += this_len + 1;
           }

         /* Terminate the list with an additional NUL byte.  */
         buf[actsize++] = '\0';

         /* Shrink the buffer to what we actually need.  */
         data->dirstreams[data->actdir]->content = realloc (buf, actsize);
         if (data->dirstreams[data->actdir]->content == NULL)
           {
             int save_err = errno;
             free (buf);
             __set_errno (save_err);
             result = -1;
           }
         else
           {
             __closedir (st);
             data->dirstreams[data->actdir]->stream = NULL;
             data->dirstreams[data->actdir]->streamfd = -1;
             data->dirstreams[data->actdir] = NULL;
           }
       }
    }

  /* Open the new stream.  */
  if (result == 0)
    {
      assert (data->dirstreams[data->actdir] == NULL);

      if (dfdp != NULL && *dfdp != -1)
       {
         int fd = openat64_not_cancel_3 (*dfdp, data->dirbuf + data->ftw.base,
                                     O_RDONLY | O_DIRECTORY | O_NDELAY);
         dirp->stream = NULL;
         if (fd != -1 && (dirp->stream = __fdopendir (fd)) == NULL)
           close_not_cancel_no_status (fd);
       }
      else
       {
         const char *name;

         if (data->flags & FTW_CHDIR)
           {
             name = data->dirbuf + data->ftw.base;
             if (name[0] == '\0')
              name = ".";
           }
         else
           name = data->dirbuf;

         dirp->stream = __opendir (name);
       }

      if (dirp->stream == NULL)
       result = -1;
      else
       {
         dirp->streamfd = dirfd (dirp->stream);
         dirp->content = NULL;
         data->dirstreams[data->actdir] = dirp;

         if (++data->actdir == data->maxdir)
           data->actdir = 0;
       }
    }

  return result;
}

Here is the call graph for this function:

static int __attribute ( (noinline)  ) [static]

Definition at line 482 of file ftw.c.

{
  struct dir_data dir;
  struct dirent64 *d;
  int previous_base = data->ftw.base;
  int result;
  char *startp;

  /* Open the stream for this directory.  This might require that
     another stream has to be closed.  */
  result = open_dir_stream (old_dir == NULL ? NULL : &old_dir->streamfd,
                         data, &dir);
  if (result != 0)
    {
      if (errno == EACCES)
       /* We cannot read the directory.  Signal this with a special flag.  */
       result = (*data->func) (data->dirbuf, st, FTW_DNR, &data->ftw);

      return result;
    }

  /* First, report the directory (if not depth-first).  */
  if (!(data->flags & FTW_DEPTH))
    {
      result = (*data->func) (data->dirbuf, st, FTW_D, &data->ftw);
      if (result != 0)
       {
         int save_err;
fail:
         save_err = errno;
         __closedir (dir.stream);
         dir.streamfd = -1;
         __set_errno (save_err);

         if (data->actdir-- == 0)
           data->actdir = data->maxdir - 1;
         data->dirstreams[data->actdir] = NULL;
         return result;
       }
    }

  /* If necessary, change to this directory.  */
  if (data->flags & FTW_CHDIR)
    {
      if (__fchdir (dirfd (dir.stream)) < 0)
       {
         result = -1;
         goto fail;
       }
    }

  /* Next, update the `struct FTW' information.  */
  ++data->ftw.level;
  startp = __rawmemchr (data->dirbuf, '\0');
  /* There always must be a directory name.  */
  assert (startp != data->dirbuf);
  if (startp[-1] != '/')
    *startp++ = '/';
  data->ftw.base = startp - data->dirbuf;

  while (dir.stream != NULL && (d = __readdir64 (dir.stream)) != NULL)
    {
      result = process_entry (data, &dir, d->d_name, NAMLEN (d), d->d_type);
      if (result != 0)
       break;
    }

  if (dir.stream != NULL)
    {
      /* The stream is still open.  I.e., we did not need more
        descriptors.  Simply close the stream now.  */
      int save_err = errno;

      assert (dir.content == NULL);

      __closedir (dir.stream);
      dir.streamfd = -1;
      __set_errno (save_err);

      if (data->actdir-- == 0)
       data->actdir = data->maxdir - 1;
      data->dirstreams[data->actdir] = NULL;
    }
  else
    {
      int save_err;
      char *runp = dir.content;

      while (result == 0 && *runp != '\0')
       {
         char *endp = strchr (runp, '\0');

         // XXX Should store the d_type values as well?!
         result = process_entry (data, &dir, runp, endp - runp, DT_UNKNOWN);

         runp = endp + 1;
       }

      save_err = errno;
      free (dir.content);
      __set_errno (save_err);
    }

  if ((data->flags & FTW_ACTIONRETVAL) && result == FTW_SKIP_SIBLINGS)
    result = 0;

  /* Prepare the return, revert the `struct FTW' information.  */
  data->dirbuf[data->ftw.base - 1] = '\0';
  --data->ftw.level;
  data->ftw.base = previous_base;

  /* Finally, if we process depth-first report the directory.  */
  if (result == 0 && (data->flags & FTW_DEPTH))
    result = (*data->func) (data->dirbuf, st, FTW_DP, &data->ftw);

  if (old_dir
      && (data->flags & FTW_CHDIR)
      && (result == 0
         || ((data->flags & FTW_ACTIONRETVAL)
             && (result != -1 && result != FTW_STOP))))
    {
      /* Change back to the parent directory.  */
      int done = 0;
      if (old_dir->stream != NULL)
       if (__fchdir (dirfd (old_dir->stream)) == 0)
         done = 1;

      if (!done)
       {
         if (data->ftw.base == 1)
           {
             if (__chdir ("/") < 0)
              result = -1;
           }
         else
           if (__chdir ("..") < 0)
             result = -1;
       }
    }

  return result;
}

Here is the call graph for this function:

static int add_object ( struct ftw_data data,
struct STAT st 
) [static]

Definition at line 247 of file ftw.c.

{
  struct known_object *newp = malloc (sizeof (struct known_object));
  if (newp == NULL)
    return -1;
  newp->dev = st->st_dev;
  newp->ino = st->st_ino;
  return __tsearch (newp, &data->known_objects, object_compare) ? 0 : -1;
}

Here is the call graph for this function:

Here is the caller graph for this function:

char* alloca ( )
static int find_object ( struct ftw_data data,
struct STAT st 
) [inline, static]

Definition at line 259 of file ftw.c.

{
  struct known_object obj;
  obj.dev = st->st_dev;
  obj.ino = st->st_ino;
  return __tfind (&obj, &data->known_objects, object_compare) != NULL;
}

Here is the call graph for this function:

Here is the caller graph for this function:

static int ftw_dir ( struct ftw_data data,
struct STAT st,
struct dir_data old_dir 
) [static]

Here is the caller graph for this function:

static int object_compare ( const void *  p1,
const void *  p2 
) [static]

Definition at line 232 of file ftw.c.

{
  /* We don't need a sophisticated and useful comparison.  We are only
     interested in equality.  However, we must be careful not to
     accidentally compare `holes' in the structure.  */
  const struct known_object *kp1 = p1, *kp2 = p2;
  int cmp1;
  cmp1 = (kp1->ino > kp2->ino) - (kp1->ino < kp2->ino);
  if (cmp1 != 0)
    return cmp1;
  return (kp1->dev > kp2->dev) - (kp1->dev < kp2->dev);
}

Here is the caller graph for this function:

static int internal_function process_entry ( struct ftw_data data,
struct dir_data dir,
const char *  name,
size_t  namlen,
int  d_type 
) [static]

Definition at line 384 of file ftw.c.

{
  struct STAT st;
  int result = 0;
  int flag = 0;
  size_t new_buflen;

  if (name[0] == '.' && (name[1] == '\0'
                      || (name[1] == '.' && name[2] == '\0')))
    /* Don't process the "." and ".." entries.  */
    return 0;

  new_buflen = data->ftw.base + namlen + 2;
  if (data->dirbufsize < new_buflen)
    {
      /* Enlarge the buffer.  */
      char *newp;

      data->dirbufsize = 2 * new_buflen;
      newp = (char *) realloc (data->dirbuf, data->dirbufsize);
      if (newp == NULL)
       return -1;
      data->dirbuf = newp;
    }

  *((char *) __mempcpy (data->dirbuf + data->ftw.base, name, namlen)) = '\0';

  int statres;
  if (dir->streamfd != -1)
    statres = FXSTATAT (_STAT_VER, dir->streamfd, name, &st,
                     (data->flags & FTW_PHYS) ? AT_SYMLINK_NOFOLLOW : 0);
  else
    {
      if ((data->flags & FTW_CHDIR) == 0)
       name = data->dirbuf;

      statres = ((data->flags & FTW_PHYS)
               ? LXSTAT (_STAT_VER, name, &st)
               : XSTAT (_STAT_VER, name, &st));
    }

  if (statres < 0)
    {
      if (errno != EACCES && errno != ENOENT)
       result = -1;
      else if (data->flags & FTW_PHYS)
       flag = FTW_NS;
      else if (d_type == DT_LNK)
       flag = FTW_SLN;
      else
       {
         if (dir->streamfd != -1)
           statres = FXSTATAT (_STAT_VER, dir->streamfd, name, &st,
                            AT_SYMLINK_NOFOLLOW);
         else
           statres = LXSTAT (_STAT_VER, name, &st);
         if (statres == 0 && S_ISLNK (st.st_mode))
           flag = FTW_SLN;
         else
           flag = FTW_NS;
       }
    }
  else
    {
      if (S_ISDIR (st.st_mode))
       flag = FTW_D;
      else if (S_ISLNK (st.st_mode))
       flag = FTW_SL;
      else
       flag = FTW_F;
    }

  if (result == 0
      && (flag == FTW_NS
         || !(data->flags & FTW_MOUNT) || st.st_dev == data->dev))
    {
      if (flag == FTW_D)
       {
         if ((data->flags & FTW_PHYS)
             || (!find_object (data, &st)
                /* Remember the object.  */
                && (result = add_object (data, &st)) == 0))
           result = ftw_dir (data, &st, dir);
       }
      else
       result = (*data->func) (data->dirbuf, &st, data->cvt_arr[flag],
                            &data->ftw);
    }

  if ((data->flags & FTW_ACTIONRETVAL) && result == FTW_SKIP_SUBTREE)
    result = 0;

  return result;
}

Here is the call graph for this function:

Here is the caller graph for this function:

int rpl_lstat ( const char *  ,
struct stat  
)
char* stpcpy ( )
char* xgetcwd ( void  )

Variable Documentation

Definition at line 821 of file ftw.c.

Definition at line 832 of file ftw.c.

const int ftw_arr[] [static]
Initial value:
{
  FTW_F, FTW_D, FTW_DNR, FTW_NS, FTW_F, FTW_D, FTW_NS
}

Definition at line 220 of file ftw.c.

Definition at line 820 of file ftw.c.

const int nftw_arr[] [static]
Initial value:
{
  FTW_F, FTW_D, FTW_DNR, FTW_NS, FTW_SL, FTW_DP, FTW_SLN
}

Definition at line 215 of file ftw.c.

int const char* path

Definition at line 819 of file ftw.c.