home *** CD-ROM | disk | FTP | other *** search
/ InfoMagic Source Code 1993 July / THE_SOURCE_CODE_CD_ROM.iso / gnu / glibc-1.06 / io / ftw.c < prev    next >
Encoding:
C/C++ Source or Header  |  1992-06-04  |  4.2 KB  |  212 lines

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