home *** CD-ROM | disk | FTP | other *** search
/ Chip 1998 February / CHIP_2_98.iso / misc / src / rpm / build / myftw.c < prev    next >
C/C++ Source or Header  |  1997-09-17  |  5KB  |  244 lines

  1. /* Modified ftw() -- uses lstat() instead of stat() */
  2.  
  3. /* Copyright (C) 1992, 1994, 1995 Free Software Foundation, Inc.
  4. This file is part of the GNU C Library.
  5. Contributed by Ian Lance Taylor (ian@airs.com).
  6.  
  7. The GNU C Library is free software; you can redistribute it and/or
  8. modify it under the terms of the GNU Library General Public License as
  9. published by the Free Software Foundation; either version 2 of the
  10. License, or (at your option) any later version.
  11.  
  12. The GNU C Library is distributed in the hope that it will be useful,
  13. but WITHOUT ANY WARRANTY; without even the implied warranty of
  14. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  15. Library General Public License for more details.
  16.  
  17. You should have received a copy of the GNU Library General Public
  18. License along with the GNU C Library; see the file COPYING.LIB.  If
  19. not, write to the Free Software Foundation, Inc., 675 Mass Ave,
  20. Cambridge, MA 02139, USA.  */
  21.  
  22. #include "config.h"
  23.  
  24. #if HAVE_ALLOCA_H
  25. # include <alloca.h>
  26. #endif
  27.  
  28. #include <errno.h>
  29. #include <limits.h>
  30. #include <stdlib.h>
  31. #include <string.h>
  32. #include <dirent.h>
  33. #include <sys/types.h>
  34. #include <sys/stat.h>
  35.  
  36. #ifndef NAMLEN
  37. #define NAMLEN(a) strlen((a)->d_name)
  38. #endif
  39.  
  40. #ifndef PATH_MAX
  41. #ifdef _POSIX_VERSION
  42. #define PATH_MAX _POSIX_PATH_MAX
  43. #else
  44. #ifdef MAXPATHLEN
  45. #define PATH_MAX MAXPATHLEN
  46. #else
  47. #define PATH_MAX 1024
  48. #endif
  49. #endif
  50. #endif
  51.  
  52. #include "myftw.h"
  53.  
  54. /* Traverse one level of a directory tree.  */
  55.  
  56. static int
  57. myftw_dir (DIR **dirs, int level, int descriptors,
  58.        char *dir, size_t len, 
  59.        int (*func) (const char *file,
  60.             struct stat *status,
  61.             int flag))
  62. {
  63.   int got;
  64.   struct dirent *entry;
  65.   int d_namlen;
  66.  
  67.   got = 0;
  68.  
  69.   errno = 0;
  70.  
  71.   while ((entry = readdir (dirs[level])) != NULL)
  72.     {
  73.       struct stat s;
  74.       int flag, retval, newlev = 0;
  75.  
  76.       ++got;
  77.  
  78.       if (entry->d_name[0] == '.'
  79.       && (entry->d_name [1] == '\0' ||
  80.           (entry->d_name [2] == '\0' && entry->d_name[1] == '.')))
  81.     {
  82.       errno = 0;
  83.       continue;
  84.     }
  85.  
  86.       d_namlen = NAMLEN(entry) + 1;
  87.       if (d_namlen + len > PATH_MAX)
  88.     {
  89. #ifdef ENAMETOOLONG
  90.       errno = ENAMETOOLONG;
  91. #else
  92.       errno = ENOMEM;
  93. #endif
  94.       return -1;
  95.     }
  96.  
  97.       dir[len] = '/';
  98.       memcpy ((void *) (dir + len + 1), (void *) entry->d_name, d_namlen);
  99.  
  100.       if (lstat (dir, &s) < 0)
  101.     {
  102.       /* Following POSIX.1 2.4 ENOENT is returned if the file cannot
  103.        * be stat'ed.  This can happen for a file returned by readdir
  104.        * if it's an unresolved symbolic link.  This should be regarded
  105.        * as an forgivable error.  -- Uli.  */
  106.       if (errno != EACCES && errno != ENOENT)
  107.         return -1;
  108.       flag = MYFTW_NS;
  109.     }
  110.       else if (S_ISDIR (s.st_mode))
  111.     {
  112.       newlev = (level + 1) % descriptors;
  113.  
  114.       if (dirs[newlev] != NULL)
  115.         closedir (dirs[newlev]);
  116.  
  117.       dirs[newlev] = opendir (dir);
  118.       if (dirs[newlev] != NULL)
  119.         flag = MYFTW_D;
  120.       else
  121.         {
  122.           if (errno != EACCES)
  123.         return -1;
  124.           flag = MYFTW_DNR;
  125.         }
  126.     }
  127.       else
  128.     flag = MYFTW_F;
  129.  
  130.       retval = (*func) (dir, &s, flag);
  131.  
  132.       if (flag == MYFTW_D)
  133.     {
  134.       if (retval == 0)
  135.         retval = myftw_dir (dirs, newlev, descriptors, dir,
  136.                 d_namlen + len, func);
  137.       if (dirs[newlev] != NULL)
  138.         {
  139.           int save;
  140.  
  141.           save = errno;
  142.           closedir (dirs[newlev]);
  143.           errno = save;
  144.           dirs[newlev] = NULL;
  145.         }
  146.     }
  147.  
  148.       if (retval != 0)
  149.     return retval;
  150.  
  151.       if (dirs[level] == NULL)
  152.     {
  153.       int skip;
  154.  
  155.       dir[len] = '\0';
  156.       dirs[level] = opendir (dir);
  157.       if (dirs[level] == NULL)
  158.         return -1;
  159.       skip = got;
  160.       while (skip-- != 0)
  161.         {
  162.           errno = 0;
  163.           if (readdir (dirs[level]) == NULL)
  164.         return errno == 0 ? 0 : -1;
  165.         }
  166.     }
  167.  
  168.       errno = 0;
  169.     }
  170.  
  171.   return errno == 0 ? 0 : -1;
  172. }
  173.  
  174. /* Call a function on every element in a directory tree.  */
  175.  
  176.  
  177. int myftw (const char *dir,
  178.        int (*func) (const char *file,
  179.             struct stat *status,
  180.             int flag),
  181.        int descriptors)
  182. {
  183.   DIR **dirs;
  184.   size_t len;
  185.   char buf[PATH_MAX + 1];
  186.   struct stat s;
  187.   int flag, retval;
  188.   int i;
  189.  
  190.   if (descriptors <= 0)
  191.     descriptors = 1;
  192.  
  193.   dirs = (DIR **) alloca (descriptors * sizeof (DIR *));
  194.   i = descriptors;
  195.   while (i-- > 0)
  196.     dirs[i] = NULL;
  197.  
  198.   if (lstat (dir, &s) < 0)
  199.     {
  200.       /* Following POSIX.1 2.4 ENOENT is returned if the file cannot
  201.        * be stat'ed.  This can happen for a file returned by readdir
  202.        * if it's an unresolved symbolic link.  This should be regarded
  203.        * as an forgivable error.  -- Uli.  */
  204.       if (errno != EACCES && errno != ENOENT)
  205.     return -1;
  206.       flag = MYFTW_NS;
  207.     }
  208.   else if (S_ISDIR (s.st_mode))
  209.     {
  210.       dirs[0] = opendir (dir);
  211.       if (dirs[0] != NULL)
  212.     flag = MYFTW_D;
  213.       else
  214.     {
  215.       if (errno != EACCES)
  216.         return -1;
  217.       flag = MYFTW_DNR;
  218.     }
  219.     }
  220.   else
  221.     flag = MYFTW_F;
  222.  
  223.   len = strlen (dir);
  224.   memcpy ((void *) buf, (void *) dir, len + 1);
  225.  
  226.   retval = (*func) (buf, &s, flag);
  227.  
  228.   if (flag == MYFTW_D)
  229.     {
  230.       if (retval == 0)
  231.     retval = myftw_dir (dirs, 0, descriptors, buf, len, func);
  232.       if (dirs[0] != NULL)
  233.     {
  234.       int save;
  235.  
  236.       save = errno;
  237.       closedir (dirs[0]);
  238.       errno = save;
  239.     }
  240.     }
  241.  
  242.   return retval;
  243. }
  244.