# myftw.c

Go to the documentation of this file.

    00001
    00006 /* Copyright (C) 1992, 1994, 1995 Free Software Foundation, Inc.
    00007 This file is part of the GNU C Library.
    00008 Contributed by Ian Lance Taylor (ian@airs.com).
    00009
    00010 The GNU C Library is free software; you can redistribute it and/or
    00011 modify it under the terms of the GNU Library General Public License as
    00012 published by the Free Software Foundation; either version 2 of the
    00013 License, or (at your option) any later version.
    00014
    00015 The GNU C Library is distributed in the hope that it will be useful,
    00016 but WITHOUT ANY WARRANTY; without even the implied warranty of
    00017 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    00018 Library General Public License for more details.
    00019
    00020 You should have received a copy of the GNU Library General Public
    00021 License along with the GNU C Library; see the file COPYING.LIB.  If
    00022 not, write to the Free Software Foundation, Inc., 675 Mass Ave,
    00023 Cambridge, MA 02139, USA.  */
    00024
    00025 #include "system.h"
    00026
    00027 #include <rpmio.h>
    00028
    00029 #ifndef NAMLEN
    00030 #define NAMLEN(a) strlen((a)->d_name)
    00031 #endif
    00032
    00033 #if !defined(__LCLINT__)
    00034 #ifndef PATH_MAX
    00035 #ifdef _POSIX_VERSION
    00036 #define PATH_MAX _POSIX_PATH_MAX
    00037 #else
    00038 #ifdef MAXPATHLEN
    00039 #define PATH_MAX MAXPATHLEN
    00040 #else
    00041 #define PATH_MAX 1024
    00042 #endif
    00043 #endif
    00044 #endif
    00045 #endif  /* !__LCLINT */
    00046
    00047 #include "myftw.h"
    00048 #include "debug.h"
    00049
    00050 /* Traverse one level of a directory tree.  */
    00051
    00054 /*@-nullstate@*/
    00055 static int
    00056 myftw_dir (DIR **dirs, int level, int descriptors,
    00057            char *dir, size_t len,
    00058            myftwFunc func,
    00059            void *fl)
    00060         /*@globals errno, fileSystem @*/
    00061         /*@modifies *dirs, *dir, errno, fileSystem @*/
    00062 {
    00063   int got;
    00064   struct dirent *entry;
    00065   int d_namlen;
    00066
    00067   got = 0;
    00068
    00069   errno = 0;
    00070
    00071   while ((entry = Readdir (dirs[level])) != NULL)
    00072     {
    00073       struct stat s;
    00074       int flag, retval, newlev = 0;
    00075
    00076       ++got;
    00077
    00078       if (entry->d_name[0] == '.'
    00079           && (entry->d_name [1] == '\0' ||
    00080               (entry->d_name [2] == '\0' && entry->d_name[1] == '.')))
    00081         {
    00082           errno = 0;
    00083           continue;
    00084         }
    00085
    00086       d_namlen = NAMLEN(entry) + 1;
    00087       if (d_namlen + len > PATH_MAX)
    00088         {
    00089 #ifdef ENAMETOOLONG
    00090           errno = ENAMETOOLONG;
    00091 #else
    00092           errno = ENOMEM;
    00093 #endif
    00094           return -1;
    00095         }
    00096
    00097       dir[len] = '/';
    00098       memcpy ((void *) (dir + len + 1), (void *) entry->d_name, d_namlen);
    00099
    00100       if (Lstat (dir, &s) < 0)
    00101         {
    00102           /* Following POSIX.1 2.4 ENOENT is returned if the file cannot
    00103            * be stat'ed.  This can happen for a file returned by Readdir
    00104            * if it's an unresolved symbolic link.  This should be regarded
    00105            * as an forgivable error.  -- Uli.  */
    00106           if (errno != EACCES && errno != ENOENT)
    00107             return -1;
    00108           flag = MYFTW_NS;
    00109         }
    00110       else if (S_ISDIR (s.st_mode))
    00111         {
    00112           newlev = (level + 1) % descriptors;
    00113
    00114           /*@-unqualifiedtrans@*/
    00115           if (dirs[newlev] != NULL)
    00116             (void) Closedir (dirs[newlev]);
    00117           /*@=unqualifiedtrans@*/
    00118
    00119           dirs[newlev] = Opendir (dir);
    00120           if (dirs[newlev] != NULL)
    00121             flag = MYFTW_D;
    00122           else
    00123             {
    00124               if (errno != EACCES)
    00125                 return -1;
    00126               flag = MYFTW_DNR;
    00127             }
    00128         }
    00129       else
    00130         flag = MYFTW_F;
    00131
    00132       retval = (*func) (fl, dir, &s);
    00133
    00134       if (flag == MYFTW_D)
    00135         {
    00136           if (retval == 0)
    00137             retval = myftw_dir (dirs, newlev, descriptors, dir,
    00138                                 d_namlen + len, func, fl);
    00139           if (dirs[newlev] != NULL)
    00140             {
    00141               int save;
    00142
    00143               save = errno;
    00144               (void) Closedir (dirs[newlev]);
    00145               errno = save;
    00146               dirs[newlev] = NULL;
    00147             }
    00148         }
    00149
    00150       if (retval != 0)
    00151         return retval;
    00152
    00153       if (dirs[level] == NULL)
    00154         {
    00155           int skip;
    00156
    00157           dir[len] = '\0';
    00158           dirs[level] = Opendir (dir);
    00159           if (dirs[level] == NULL)
    00160             return -1;
    00161           skip = got;
    00162           while (skip-- != 0)
    00163             {
    00164               errno = 0;
    00165               if (Readdir (dirs[level]) == NULL)
    00166                 return errno == 0 ? 0 : -1;
    00167             }
    00168         }
    00169
    00170       errno = 0;
    00171     }
    00172
    00173   return errno == 0 ? 0 : -1;
    00174 }
    00175 /*@=nullstate@*/
    00176
    00177 /* Call a function on every element in a directory tree.  */
    00178
    00179 int myftw (const char *dir,
    00180            int descriptors,
    00181            myftwFunc func,
    00182            void *fl)
    00183 {
    00184   DIR **dirs;
    00185   size_t len;
    00186   char buf[PATH_MAX + 1];
    00187   struct stat s;
    00188   int flag, retval;
    00189   int i;
    00190
    00191   if (descriptors <= 0)
    00192     descriptors = 1;
    00193
    00194   /*@access DIR@*/
    00195   dirs = (DIR **) alloca (descriptors * sizeof (*dirs));
    00196   i = descriptors;
    00197   while (i-- > 0)
    00198     dirs[i] = NULL;
    00199
    00200   if (Lstat (dir, &s) < 0)
    00201     {
    00202       /* Following POSIX.1 2.4 ENOENT is returned if the file cannot
    00203        * be stat'ed.  This can happen for a file returned by Readdir
    00204        * if it's an unresolved symbolic link.  This should be regarded
    00205        * as an forgivable error.  -- Uli.  */
    00206       if (errno != EACCES && errno != ENOENT)
    00207         return -1;
    00208       flag = MYFTW_NS;
    00209     }
    00210   else if (S_ISDIR (s.st_mode))
    00211     {
    00212       dirs[0] = Opendir (dir);
    00213       if (dirs[0] != NULL)
    00214         flag = MYFTW_D;
    00215       else
    00216         {
    00217           if (errno != EACCES)
    00218             return -1;
    00219           flag = MYFTW_DNR;
    00220         }
    00221     }
    00222   else
    00223     flag = MYFTW_F;
    00224
    00225   len = strlen (dir);
    00226   memcpy ((void *) buf, (void *) dir, len + 1);
    00227
    00228   retval = (*func) (fl, buf, &s);
    00229
    00230   if (flag == MYFTW_D)
    00231     {
    00232       if (retval == 0)
    00233         retval = myftw_dir (dirs, 0, descriptors, buf, len, func, fl);
    00234       if (dirs[0] != NULL)
    00235         {
    00236           int save;
    00237
    00238           save = errno;
    00239           (void) Closedir (dirs[0]);
    00240           /*@-mods@*/
    00241           errno = save;
    00242           /*@=mods@*/
    00243         }
    00244     }
    00245
    00246   return retval;
    00247 }