home *** CD-ROM | disk | FTP | other *** search
/ Serving the Web / ServingTheWeb1995.disc1of1.iso / linux / slacksrce / d / libc / libc-4.6 / libc-4 / libc-linux / io / ftw.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-12-08  |  5.0 KB  |  237 lines

  1. /* Copyright (C) 1992, 1994 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. #ifdef linux
  31. #define d_namlen    d_reclen
  32. #endif
  33.  
  34. /* Traverse one level of a directory tree.  */
  35.  
  36. static int
  37. #ifdef linux
  38. DEFUN (ftw_dir, (dirs, level, descriptors, dir, len, func),
  39.        DIR **dirs AND int level AND int descriptors AND
  40.        char *dir AND size_t len AND
  41.        __ftw_func_t func)
  42. #else
  43. DEFUN (ftw_dir, (dirs, level, descriptors, dir, len, func),
  44.        DIR **dirs AND int level AND int descriptors AND
  45.        char *dir AND size_t len AND
  46.        int EXFUN((*func), (CONST char *file, struct stat *status,
  47.                int flag)))
  48. #endif
  49. {
  50.   int got;
  51.   struct dirent *entry;
  52.  
  53.   got = 0;
  54.  
  55.   errno = 0;
  56.  
  57.   while ((entry = readdir (dirs[level])) != NULL)
  58.     {
  59.       struct stat s;
  60.       int flag, ret, newlev;
  61.  
  62.       ++got;
  63.  
  64.       if (entry->d_name[0] == '.'
  65.       && (entry->d_namlen == 1 ||
  66.           (entry->d_namlen == 2 && entry->d_name[1] == '.')))
  67.     {
  68.       errno = 0;
  69.       continue;
  70.     }
  71.  
  72.       if (entry->d_namlen + len + 1 > PATH_MAX)
  73.     {
  74. #ifdef ENAMETOOLONG
  75.       errno = ENAMETOOLONG;
  76. #else
  77.       errno = ENOMEM;
  78. #endif
  79.       return -1;
  80.     }
  81.  
  82.       dir[len] = '/';
  83.       memcpy ((PTR) (dir + len + 1), (PTR) entry->d_name,
  84.           entry->d_namlen + 1);
  85.  
  86.       if (stat (dir, &s) < 0)
  87.     {
  88.       /* Following POSIX.1 2.4 ENOENT is returned if the file cannot
  89.        * be stat'ed.  This can happen for a file returned by readdir
  90.        * if it's an unresolved symbolic link.  This should be regarded
  91.        * as an forgivable error.  -- Uli.  */
  92.       if (errno != EACCES && errno != ENOENT)
  93.         return -1;
  94.       flag = FTW_NS;
  95.     }
  96.       else if (S_ISDIR (s.st_mode))
  97.     {
  98.       newlev = (level + 1) % descriptors;
  99.  
  100.       if (dirs[newlev] != NULL)
  101.         closedir (dirs[newlev]);
  102.  
  103.       dirs[newlev] = opendir (dir);
  104.       if (dirs[newlev] != NULL)
  105.         flag = FTW_D;
  106.       else
  107.         {
  108.           if (errno != EACCES)
  109.         return -1;
  110.           flag = FTW_DNR;
  111.         }
  112.     }
  113.       else
  114.     flag = FTW_F;
  115.  
  116.       ret = (*func) (dir, &s, flag);
  117.  
  118.       if (flag == FTW_D)
  119.     {
  120.       if (ret == 0)
  121.         ret = ftw_dir (dirs, newlev, descriptors, dir,
  122.                entry->d_namlen + len + 1, func);
  123.       if (dirs[newlev] != NULL)
  124.         {
  125.           int save;
  126.  
  127.           save = errno;
  128.           closedir (dirs[newlev]);
  129.           errno = save;
  130.           dirs[newlev] = NULL;
  131.         }
  132.     }
  133.  
  134.       if (ret != 0)
  135.     return ret;
  136.  
  137.       if (dirs[level] == NULL)
  138.     {
  139.       int skip;
  140.  
  141.       dir[len] = '\0';
  142.       dirs[level] = opendir (dir);
  143.       if (dirs[level] == NULL)
  144.         return -1;
  145.       skip = got;
  146.       while (skip-- != 0)
  147.         {
  148.           errno = 0;
  149.           if (readdir (dirs[level]) == NULL)
  150.         return errno == 0 ? 0 : -1;
  151.         }
  152.     }
  153.  
  154.       errno = 0;
  155.     }
  156.  
  157.   return errno == 0 ? 0 : -1;
  158. }
  159.  
  160. /* Call a function on every element in a directory tree.  */
  161.  
  162.  
  163. int
  164. #ifdef linux
  165. DEFUN(ftw, (dir, func, descriptors),
  166.       CONST char *dir AND
  167.       __ftw_func_t func AND int descriptors)
  168. #else
  169. DEFUN(ftw, (dir, func, descriptors),
  170.       CONST char *dir AND
  171.       *func), (CONST char *file, struct stat *status,
  172.               int flag)) AND
  173.       int descriptors)
  174. #endif
  175. {
  176.   DIR **dirs;
  177.   size_t len;
  178.   char buf[PATH_MAX + 1];
  179.   struct stat s;
  180.   int flag, ret;
  181.   int i;
  182.  
  183.   if (descriptors <= 0)
  184.     descriptors = 1;
  185.  
  186.   dirs = (DIR **) __alloca (descriptors * sizeof (DIR *));
  187.   i = descriptors;
  188.   while (i-- > 0)
  189.     dirs[i] = NULL;
  190.  
  191.   if (stat (dir, &s) < 0)
  192.     {
  193.       /* Following POSIX.1 2.4 ENOENT is returned if the file cannot
  194.        * be stat'ed.  This can happen for a file returned by readdir
  195.        * if it's an unresolved symbolic link.  This should be regarded
  196.        * as an forgivable error.  -- Uli.  */
  197.       if (errno != EACCES && errno != ENOENT)
  198.     return -1;
  199.       flag = FTW_NS;
  200.     }
  201.   else if (S_ISDIR (s.st_mode))
  202.     {
  203.       dirs[0] = opendir (dir);
  204.       if (dirs[0] != NULL)
  205.     flag = FTW_D;
  206.       else
  207.     {
  208.       if (errno != EACCES)
  209.         return -1;
  210.       flag = FTW_DNR;
  211.     }
  212.     }
  213.   else
  214.     flag = FTW_F;
  215.  
  216.   len = strlen (dir);
  217.   memcpy ((PTR) buf, (PTR) dir, len + 1);
  218.  
  219.   ret = (*func) (buf, &s, flag);
  220.  
  221.   if (flag == FTW_D)
  222.     {
  223.       if (ret == 0)
  224.     ret = ftw_dir (dirs, 0, descriptors, buf, len, func);
  225.       if (dirs[0] != NULL)
  226.     {
  227.       int save;
  228.  
  229.       save = errno;
  230.       closedir (dirs[0]);
  231.       errno = save;
  232.     }
  233.     }
  234.  
  235.   return ret;
  236. }
  237.