new_ftw.c File Reference


Detailed Description

Implementation of the improved new_ftw() and new_nftw() functions.

Definition in file new_ftw.c.

#include <dirent.h>
#include <errno.h>
#include "new_ftw.h"
#include <limits.h>
#include <search.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/stat.h>
#include <assert.h>
#include <stdio.h>

Go to the source code of this file.


Classes

struct  dir_data
struct  known_object
struct  new_ftw_data

Defines

#define dirent   direct
#define NAMLEN(dirent)   (dirent)->d_namlen
#define NAMLEN(dirent)   strlen ((dirent)->d_name)
#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
#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 NEW_FTW_NAME   new_ftw
#define NEW_NFTW_NAME   new_nftw
#define NEW_NFTW_OLD_NAME   __new_old_nftw
#define NEW_NFTW_NEW_NAME   __new_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 NEW_FTW_FUNC_T   __new_ftw_func_t
#define NEW_NFTW_FUNC_T   __new_nftw_func_t
#define PATH_MAX   1024

Functions

char * alloca ()
char * stpcpy ()
char * xgetcwd (void)
int rpl_lstat (const char *, struct stat *)
int ftw_dir (struct new_ftw_data *data, struct STAT *st, struct dir_data *old_dir) internal_function
int object_compare (const void *p1, const void *p2)
int add_object (struct new_ftw_data *data, struct STAT *st)
int find_object (struct new_ftw_data *data, struct STAT *st)
int __attribute ((always_inline))
int internal_function process_entry (struct new_ftw_data *data, struct dir_data *dir, const char *name, size_t namlen)
int __attribute ((noinline))
int NEW_FTW_NAME (char *path, NEW_FTW_FUNC_T func, int descriptors, void *data) const
int NEW_NFTW_NAME (char *path, NEW_NFTW_FUNC_T func, int descriptors, int flags, void *data) const
int rpl_lstat (char *file, struct stat *sbuf) const

Variables

const int nftw_arr []
const int ftw_arr []

Define Documentation

#define dirent   direct
 

Definition at line 53 of file new_ftw.c.

#define NAMLEN dirent   )     (dirent)->d_namlen
 

Definition at line 69 of file new_ftw.c.

Referenced by __attribute().

#define NAMLEN dirent   )     strlen ((dirent)->d_name)
 

Definition at line 69 of file new_ftw.c.

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

Definition at line 93 of file new_ftw.c.

#define __chdir   chdir
 

Definition at line 101 of file new_ftw.c.

Referenced by __attribute().

#define __closedir   closedir
 

Definition at line 103 of file new_ftw.c.

Referenced by __attribute().

#define __fchdir   fchdir
 

Definition at line 105 of file new_ftw.c.

Referenced by __attribute().

#define __getcwd P,
 )     xgetcwd ()
 

Definition at line 107 of file new_ftw.c.

#define __mempcpy   mempcpy
 

Definition at line 110 of file new_ftw.c.

Referenced by __attribute(), and process_entry().

#define __opendir   opendir
 

Definition at line 112 of file new_ftw.c.

Referenced by __attribute().

#define __readdir64   readdir
 

Definition at line 114 of file new_ftw.c.

Referenced by __attribute().

#define __stpcpy   stpcpy
 

Definition at line 116 of file new_ftw.c.

#define __tdestroy   tdestroy
 

Definition at line 118 of file new_ftw.c.

#define __tfind   tfind
 

Definition at line 120 of file new_ftw.c.

Referenced by find_object().

#define __tsearch   tsearch
 

Definition at line 122 of file new_ftw.c.

Referenced by add_object().

#define internal_function
 

Definition at line 124 of file new_ftw.c.

Referenced by process_entry().

#define dirent64   dirent
 

Definition at line 126 of file new_ftw.c.

Referenced by __attribute().

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

Definition at line 128 of file new_ftw.c.

Referenced by __attribute().

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

Definition at line 137 of file new_ftw.c.

Referenced by rpl_lstat().

#define __set_errno Val   )     errno = (Val)
 

Definition at line 141 of file new_ftw.c.

Referenced by __attribute().

#define NEW_FTW_NAME   new_ftw
 

Definition at line 146 of file new_ftw.c.

#define NEW_NFTW_NAME   new_nftw
 

Definition at line 147 of file new_ftw.c.

#define NEW_NFTW_OLD_NAME   __new_old_nftw
 

Definition at line 148 of file new_ftw.c.

#define NEW_NFTW_NEW_NAME   __new_new_nftw
 

Definition at line 149 of file new_ftw.c.

#define INO_T   ino_t
 

Definition at line 150 of file new_ftw.c.

#define STAT   stat
 

Definition at line 151 of file new_ftw.c.

Referenced by process_entry().

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

Definition at line 156 of file new_ftw.c.

Referenced by process_entry().

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

Definition at line 157 of file new_ftw.c.

Referenced by process_entry().

#define NEW_FTW_FUNC_T   __new_ftw_func_t
 

Definition at line 159 of file new_ftw.c.

#define NEW_NFTW_FUNC_T   __new_nftw_func_t
 

Definition at line 160 of file new_ftw.c.

#define PATH_MAX   1024
 

Definition at line 168 of file new_ftw.c.


Function Documentation

char* alloca  ) 
 

char* stpcpy  ) 
 

char * xgetcwd void   ) 
 

Definition at line 741 of file new_ftw.c.

00742 {
00743         char *cwd = getcwd(NULL, 0);
00744         if (!cwd && errno == ENOMEM) {
00745                 fprintf(stderr, "out of memory\n");
00746                 exit(1);
00747         }
00748         return cwd;
00749 }

int rpl_lstat const char *  ,
struct stat * 
 

int ftw_dir struct new_ftw_data data,
struct STAT *  st,
struct dir_data old_dir
[static]
 

Referenced by process_entry().

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

Definition at line 231 of file new_ftw.c.

References known_object::dev, and known_object::ino.

Referenced by add_object(), and find_object().

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

int add_object struct new_ftw_data data,
struct STAT *  st
[inline, static]
 

Definition at line 244 of file new_ftw.c.

References __tsearch, known_object::dev, known_object::ino, new_ftw_data::known_objects, and object_compare().

Referenced by process_entry().

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

int find_object struct new_ftw_data data,
struct STAT *  st
[inline, static]
 

Definition at line 254 of file new_ftw.c.

References __tfind, known_object::dev, known_object::ino, new_ftw_data::known_objects, and object_compare().

Referenced by process_entry().

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

int __attribute (always_inline)   )  [inline, static]
 

Definition at line 262 of file new_ftw.c.

References __closedir, __mempcpy, __opendir, __readdir64, __set_errno, dirent64, MAX, and NAMLEN.

00263 {
00264         int result = 0;
00265 
00266         if (data->dirstreams[data->actdir] != NULL) {
00267                 /* Oh, oh.  We must close this stream.  Get all remaining
00268                    entries and store them as a list in the `content' member of
00269                    the `struct dir_data' variable.  */
00270                 size_t bufsize = 1024;
00271                 char *buf = malloc(bufsize);
00272 
00273                 if (buf == NULL)
00274                         result = -1;
00275                 else {
00276                         DIR *st = data->dirstreams[data->actdir]->stream;
00277                         struct dirent64 *d;
00278                         size_t actsize = 0;
00279 
00280                         while ((d = __readdir64(st)) != NULL) {
00281                                 size_t this_len = NAMLEN(d);
00282                                 if (actsize + this_len + 2 >= bufsize) {
00283                                         char *newp;
00284                                         bufsize += MAX(1024, 2 * this_len);
00285                                         newp = (char *)realloc(buf, bufsize);
00286                                         if (newp == NULL) {
00287                                                 /* No more memory.  */
00288                                                 int save_err = errno;
00289                                                 free(buf);
00290                                                 __set_errno(save_err);
00291                                                 result = -1;
00292                                                 break;
00293                                         }
00294                                         buf = newp;
00295                                 }
00296 
00297                                 *((char *)__mempcpy(buf + actsize, d->d_name, this_len))
00298                                         = '\0';
00299                                 actsize += this_len + 1;
00300                         }
00301 
00302                         /* Terminate the list with an additional NUL byte.  */
00303                         buf[actsize++] = '\0';
00304 
00305                         /* Shrink the buffer to what we actually need.  */
00306                         data->dirstreams[data->actdir]->content = realloc(buf, actsize);
00307                         if (data->dirstreams[data->actdir]->content == NULL) {
00308                                 int save_err = errno;
00309                                 free(buf);
00310                                 __set_errno(save_err);
00311                                 result = -1;
00312                         } else {
00313                                 __closedir(st);
00314                                 data->dirstreams[data->actdir]->stream = NULL;
00315                                 data->dirstreams[data->actdir] = NULL;
00316                         }
00317                 }
00318         }
00319 
00320         /* Open the new stream.  */
00321         if (result == 0) {
00322                 const char *name = ((data->flags & FTW_CHDIR)
00323                                     ? data->dirbuf + data->ftw.base : data->dirbuf);
00324                 assert(data->dirstreams[data->actdir] == NULL);
00325 
00326                 dirp->stream = __opendir(name);
00327                 if (dirp->stream == NULL)
00328                         result = -1;
00329                 else {
00330                         dirp->content = NULL;
00331                         data->dirstreams[data->actdir] = dirp;
00332 
00333                         if (++data->actdir == data->maxdir)
00334                                 data->actdir = 0;
00335                 }
00336         }
00337 
00338         return result;
00339 }

int internal_function process_entry struct new_ftw_data data,
struct dir_data dir,
const char *  name,
size_t  namlen
[static]
 

Definition at line 341 of file new_ftw.c.

References __mempcpy, add_object(), new_ftw_data::cvt_arr, new_ftw_data::data, new_ftw_data::dev, new_ftw_data::dirbuf, new_ftw_data::dirbufsize, find_object(), new_ftw_data::flags, new_ftw_data::ftw, ftw_dir(), FTW_NS, new_ftw_data::func, internal_function, LXSTAT, STAT, and XSTAT.

Referenced by __attribute().

00342 {
00343         struct STAT st;
00344         int result = 0;
00345         int flag = 0;
00346         size_t new_buflen;
00347 
00348         if (name[0] == '.' && (name[1] == '\0' || (name[1] == '.' && name[2] == '\0')))
00349                 /* Don't process the "." and ".." entries.  */
00350                 return 0;
00351 
00352         new_buflen = data->ftw.base + namlen + 2;
00353         if (data->dirbufsize < new_buflen) {
00354                 /* Enlarge the buffer.  */
00355                 char *newp;
00356 
00357                 data->dirbufsize = 2 * new_buflen;
00358                 newp = (char *)realloc(data->dirbuf, data->dirbufsize);
00359                 if (newp == NULL)
00360                         return -1;
00361                 data->dirbuf = newp;
00362         }
00363 
00364         *((char *)__mempcpy(data->dirbuf + data->ftw.base, name, namlen)) = '\0';
00365 
00366         if ((data->flags & FTW_CHDIR) == 0)
00367                 name = data->dirbuf;
00368 
00369         if (((data->flags & FTW_PHYS)
00370              ? LXSTAT(_STAT_VER, name, &st)
00371              : XSTAT(_STAT_VER, name, &st)) < 0) {
00372                 if (errno != EACCES && errno != ENOENT)
00373                         result = -1;
00374                 else if (!(data->flags & FTW_PHYS)
00375                          && LXSTAT(_STAT_VER, name, &st) == 0 && S_ISLNK(st.st_mode))
00376                         flag = FTW_SLN;
00377                 else
00378                         flag = FTW_NS;
00379         } else {
00380                 if (S_ISDIR(st.st_mode))
00381                         flag = FTW_D;
00382                 else if (S_ISLNK(st.st_mode))
00383                         flag = FTW_SL;
00384                 else
00385                         flag = FTW_F;
00386         }
00387 
00388         if (result == 0 && (flag == FTW_NS || !(data->flags & FTW_MOUNT) || st.st_dev == data->dev)) {
00389                 if (flag == FTW_D) {
00390                         if ((data->flags & FTW_PHYS)
00391                             || (!find_object(data, &st)
00392                                 /* Remember the object.  */
00393                                 && (result = add_object(data, &st)) == 0))
00394                                 result = ftw_dir(data, &st, dir);
00395                 } else
00396                         result = (*data->func) (data->dirbuf, &st, data->cvt_arr[flag], &data->ftw, data->data);
00397         }
00398 
00399         if ((data->flags & FTW_ACTIONRETVAL) && result == FTW_SKIP_SUBTREE)
00400                 result = 0;
00401 
00402         return result;
00403 }

int __attribute (noinline)   )  [static]
 

Definition at line 405 of file new_ftw.c.

References __chdir, __closedir, __fchdir, __readdir64, __set_errno, dir_data::content, dirent64, NAMLEN, process_entry(), and dir_data::stream.

00407 {
00408         struct dir_data dir;
00409         struct dirent64 *d;
00410         int previous_base = data->ftw.base;
00411         int result;
00412         char *startp;
00413 
00414         /* Open the stream for this directory.  This might require that
00415            another stream has to be closed.  */
00416         result = open_dir_stream(data, &dir);
00417         if (result != 0) {
00418                 if (errno == EACCES)
00419                         /* We cannot read the directory.  Signal this with a special flag.  */
00420                         result = (*data->func) (data->dirbuf, st, FTW_DNR, &data->ftw, data->data);
00421 
00422                 return result;
00423         }
00424 
00425         /* First, report the directory (if not depth-first).  */
00426         if (!(data->flags & FTW_DEPTH)) {
00427                 result = (*data->func) (data->dirbuf, st, FTW_D, &data->ftw, data->data);
00428                 if (result != 0) {
00429                         int save_err;
00430                       fail:
00431                         save_err = errno;
00432                         __closedir(dir.stream);
00433                         __set_errno(save_err);
00434 
00435                         if (data->actdir-- == 0)
00436                                 data->actdir = data->maxdir - 1;
00437                         data->dirstreams[data->actdir] = NULL;
00438                         return result;
00439                 }
00440         }
00441 
00442         /* If necessary, change to this directory.  */
00443         if (data->flags & FTW_CHDIR) {
00444                 if (__fchdir(dirfd(dir.stream)) < 0) {
00445                         result = -1;
00446                         goto fail;
00447                 }
00448         }
00449 
00450         /* Next, update the `struct FTW' information.  */
00451         ++data->ftw.level;
00452         startp = strchr(data->dirbuf, '\0');
00453         /* There always must be a directory name.  */
00454         assert(startp != data->dirbuf);
00455         if (startp[-1] != '/')
00456                 *startp++ = '/';
00457         data->ftw.base = startp - data->dirbuf;
00458 
00459         while (dir.stream != NULL && (d = __readdir64(dir.stream)) != NULL) {
00460                 result = process_entry(data, &dir, d->d_name, NAMLEN(d));
00461                 if (result != 0)
00462                         break;
00463         }
00464 
00465         if (dir.stream != NULL) {
00466                 /* The stream is still open.  I.e., we did not need more
00467                    descriptors.  Simply close the stream now.  */
00468                 int save_err = errno;
00469 
00470                 assert(dir.content == NULL);
00471 
00472                 __closedir(dir.stream);
00473                 __set_errno(save_err);
00474 
00475                 if (data->actdir-- == 0)
00476                         data->actdir = data->maxdir - 1;
00477                 data->dirstreams[data->actdir] = NULL;
00478         } else {
00479                 int save_err;
00480                 char *runp = dir.content;
00481 
00482                 while (result == 0 && *runp != '\0') {
00483                         char *endp = strchr(runp, '\0');
00484 
00485                         result = process_entry(data, &dir, runp, endp - runp);
00486 
00487                         runp = endp + 1;
00488                 }
00489 
00490                 save_err = errno;
00491                 free(dir.content);
00492                 __set_errno(save_err);
00493         }
00494 
00495         if ((data->flags & FTW_ACTIONRETVAL) && result == FTW_SKIP_SIBLINGS)
00496                 result = 0;
00497 
00498         /* Prepare the return, revert the `struct FTW' information.  */
00499         data->dirbuf[data->ftw.base - 1] = '\0';
00500         --data->ftw.level;
00501         data->ftw.base = previous_base;
00502 
00503         /* Finally, if we process depth-first report the directory.  */
00504         if (result == 0 && (data->flags & FTW_DEPTH))
00505                 result = (*data->func) (data->dirbuf, st, FTW_DP, &data->ftw, data->data);
00506 
00507         if (old_dir && (data->flags & FTW_CHDIR)
00508             && (result == 0 || ((data->flags & FTW_ACTIONRETVAL)
00509                                 && (result != -1 && result != FTW_STOP)))) {
00510                 /* Change back to the parent directory.  */
00511                 int done = 0;
00512                 if (old_dir->stream != NULL)
00513                         if (__fchdir(dirfd(old_dir->stream)) == 0)
00514                                 done = 1;
00515 
00516                 if (!done) {
00517                         if (data->ftw.base == 1) {
00518                                 if (__chdir("/") < 0)
00519                                         result = -1;
00520                         } else if (__chdir("..") < 0)
00521                                 result = -1;
00522                 }
00523         }
00524 
00525         return result;
00526 }

int NEW_FTW_NAME char *  path,
NEW_FTW_FUNC_T  func,
int  descriptors,
void *  data
const
 

Definition at line 665 of file new_ftw.c.

00670 {
00671         return new_ftw_startup(path, 0, func, descriptors, 0, data);
00672 }

int NEW_NFTW_NAME char *  path,
NEW_NFTW_FUNC_T  func,
int  descriptors,
int  flags,
void *  data
const
 

Definition at line 675 of file new_ftw.c.

00681 {
00682         return new_ftw_startup(path, 1, func, descriptors, flags, data);
00683 }

int rpl_lstat char *  file,
struct stat *  sbuf
const
 

Definition at line 727 of file new_ftw.c.

References lstat.

00730 {
00731         if (file && *file == 0) {
00732                 errno = EINVAL;
00733                 return -1;
00734         }
00735 
00736         return lstat(file, sbuf);
00737 }


Variable Documentation

const int nftw_arr[] [static]
 

Initial value:

 {
        FTW_F, FTW_D, FTW_DNR, FTW_NS, FTW_SL, FTW_DP, FTW_SLN
}

Definition at line 220 of file new_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 224 of file new_ftw.c.