build/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 }

Generated on Wed Feb 13 20:33:06 2008 for rpm by  doxygen 1.5.2