home *** CD-ROM | disk | FTP | other *** search
/ Fresh Fish 5 / FreshFish_July-August1994.bin / tools / pitools / ftw.c < prev    next >
C/C++ Source or Header  |  1994-04-07  |  4KB  |  223 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 <errno.h>
  21. #include <limits.h>
  22. #include <stdlib.h>
  23. #include <string.h>
  24. #include <dirent.h>
  25. #include <sys/types.h>
  26. #include <sys/stat.h>
  27. #include "ftw.h"
  28.  
  29. #define NLENGTH(direct) (strlen((direct)->d_name))
  30. #define _STYPES
  31.  
  32. #ifndef PATH_MAX
  33. #define PATH_MAX 1024        /* XXX */
  34. #endif
  35.  
  36.  
  37. /* Traverse one level of a directory tree.  */
  38.  
  39. static int
  40. ftw_dir (dirs, level, descriptors, dir, len, func)
  41. DIR **dirs;
  42. int level;
  43. int descriptors;
  44. char *dir;
  45. size_t len;
  46. int (*func) ();
  47. {
  48.   int got;
  49.   struct dirent *entry;
  50.  
  51.   got = 0;
  52.  
  53.   errno = 0;
  54.  
  55.   while ((entry = readdir (dirs[level])) != NULL)
  56.     {
  57.       struct stat s;
  58.       int flag, ret, newlev;
  59.  
  60.       ++got;
  61.  
  62.       if (entry->d_name[0] == '.'
  63.       && (NLENGTH (entry) == 1 ||
  64.           (NLENGTH (entry) == 2 && entry->d_name[1] == '.')))
  65.     {
  66.       errno = 0;
  67.       continue;
  68.     }
  69.  
  70.       if (NLENGTH (entry) + len + 1 > PATH_MAX)
  71.     {
  72. #ifdef ENAMETOOLONG
  73.       errno = ENAMETOOLONG;
  74. #else
  75.       errno = ENOMEM;
  76. #endif
  77.       return -1;
  78.     }
  79.  
  80.       dir[len] = '/';
  81.       memcpy ((void *) (dir + len + 1), (void *) entry->d_name,
  82.           NLENGTH (entry) + 1);
  83.  
  84.       if (stat (dir, &s) < 0)
  85.     {
  86. #ifndef __amigados__
  87.       if (errno != EACCES)
  88.         return -1;
  89. #endif
  90.       flag = FTW_NS;
  91.     }
  92.       else if (S_ISDIR (s.st_mode))
  93.     {
  94.       newlev = (level + 1) % descriptors;
  95.  
  96.       if (dirs[newlev] != NULL)
  97.         closedir (dirs[newlev]);
  98.  
  99.       dirs[newlev] = opendir (dir);
  100.       if (dirs[newlev] != NULL)
  101.         flag = FTW_D;
  102.       else
  103.         {
  104.           if (errno != EACCES)
  105.         return -1;
  106.           flag = FTW_DNR;
  107.         }
  108.     }
  109.       else
  110.     flag = FTW_F;
  111.  
  112.       ret = (*func) (dir, &s, flag);
  113.  
  114.       if (flag == FTW_D)
  115.     {
  116.       if (ret == 0)
  117.         ret = ftw_dir (dirs, newlev, descriptors, dir,
  118.                NLENGTH (entry) + len + 1, func);
  119.       if (dirs[newlev] != NULL)
  120.         {
  121.           int save;
  122.  
  123.           save = errno;
  124.           closedir (dirs[newlev]);
  125.           errno = save;
  126.           dirs[newlev] = NULL;
  127.         }
  128.     }
  129.  
  130.       if (ret != 0)
  131.     return ret;
  132.  
  133.       if (dirs[level] == NULL)
  134.     {
  135.       int skip;
  136.  
  137.       dir[len] = '\0';
  138.       dirs[level] = opendir (dir);
  139.       if (dirs[level] == NULL)
  140.         return -1;
  141.       skip = got;
  142.       while (skip-- != 0)
  143.         {
  144.           errno = 0;
  145.           if (readdir (dirs[level]) == NULL)
  146.         return errno == 0 ? 0 : -1;
  147.         }
  148.     }
  149.  
  150.       errno = 0;
  151.     }
  152.  
  153.   return errno == 0 ? 0 : -1;
  154. }
  155.  
  156. /* Call a function on every element in a directory tree.  */
  157.  
  158. int
  159. ftw (dir, func, descriptors)
  160. const char *dir;
  161. int (*func) ();
  162. int descriptors;
  163. {
  164.   DIR **dirs;
  165.   size_t len;
  166.   char buf[PATH_MAX + 1];
  167.   struct stat s;
  168.   int flag, ret;
  169.   int i;
  170.  
  171.   if (descriptors <= 0)
  172.     descriptors = 1;
  173.  
  174.   dirs = (DIR **) alloca (descriptors * sizeof (DIR *));
  175.   i = descriptors;
  176.   while (i-- > 0)
  177.     dirs[i] = NULL;
  178.  
  179.   if (stat (dir, &s) < 0)
  180.     {
  181. #ifndef __amigados__
  182.       if (errno != EACCES)
  183.     return -1;
  184. #endif
  185.       flag = FTW_NS;
  186.     }
  187.   else if (S_ISDIR (s.st_mode))
  188.     {
  189.       dirs[0] = opendir (dir);
  190.       if (dirs[0] != NULL)
  191.     flag = FTW_D;
  192.       else
  193.     {
  194.       if (errno != EACCES)
  195.         return -1;
  196.       flag = FTW_DNR;
  197.     }
  198.     }
  199.   else
  200.     flag = FTW_F;
  201.  
  202.   len = strlen (dir);
  203.   memcpy ((void *) buf, (void *) dir, len + 1);
  204.  
  205.   ret = (*func) (buf, &s, flag);
  206.  
  207.   if (flag == FTW_D)
  208.     {
  209.       if (ret == 0)
  210.     ret = ftw_dir (dirs, 0, descriptors, buf, len, func);
  211.       if (dirs[0] != NULL)
  212.     {
  213.       int save;
  214.  
  215.       save = errno;
  216.       closedir (dirs[0]);
  217.       errno = save;
  218.     }
  219.     }
  220.  
  221.   return ret;
  222. }
  223.