home *** CD-ROM | disk | FTP | other *** search
/ Big Green CD 8 / BGCD_8_Dev.iso / NEXTSTEP / UNIX / Networking / wu-ftpd-2.4.2b13-MIHS / support / arpa / ftw.c < prev    next >
Encoding:
C/C++ Source or Header  |  1997-03-03  |  7.1 KB  |  361 lines

  1. /*
  2.  * Copyright (c) 1988 Regents of the University of California.
  3.  * All rights reserved.
  4.  *
  5.  * Redistribution and use in source and binary forms are permitted
  6.  * provided that the above copyright notice and this paragraph are
  7.  * duplicated in all such forms and that any documentation,
  8.  * advertising materials, and other materials related to such
  9.  * distribution and use acknowledge that the software was developed
  10.  * by the University of California, Berkeley.  The name of the
  11.  * University may not be used to endorse or promote products derived
  12.  * from this software without specific prior written permission.
  13.  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
  14.  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
  15.  * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
  16.  */
  17.  
  18. #if defined(LIBC_SCCS) && !defined(lint)
  19. static char sccsid[] = "@(#)ftw.c    5.3 (Berkeley) 8/5/88";
  20.  
  21. #endif /* LIBC_SCCS and not lint */
  22.  
  23. #include "../src/config.h"
  24.  
  25. #ifdef HAVE_DIRENT
  26. #include <dirent.h>
  27. #else
  28. #include <sys/dir.h>
  29. #endif
  30.  
  31. #include <errno.h>
  32.  
  33. #include <sys/param.h>
  34. #include <sys/stat.h>
  35. #include <sys/stat.h>
  36.  
  37. #include "ftw.h"
  38.  
  39. #define    NODESC    -1
  40.  
  41. #ifdef HAVE_SYMLINK
  42. # define    ISLINK(sb)    ((sb.st_mode&S_IFMT) == S_IFLNK)
  43. #else
  44. # define lstat stat
  45. #endif
  46.  
  47. #define    ISDIR(sb)    ((sb.st_mode&S_IFMT) == S_IFDIR)
  48. #define    ISDOT(dp) \
  49.     (dp->d_name[0] == '.' && (!dp->d_name[1] || \
  50.         (dp->d_name[1] == '.' && !dp->d_name[2])))
  51.  
  52. extern int errno;
  53. static int g_fds,
  54.   (*g_fn) (),
  55.   g_opts;
  56. static char *bp;
  57.  
  58. #ifdef __STDC__
  59. int treewalk(char *path, int (*fn) ( /* ??? */ ), int maxfds, int opts);
  60. #else
  61. int treewalk();
  62. #endif
  63.  
  64. /*
  65.  * cycle through the directories at the top of the tree, otherwise, once
  66.  * you run out of descriptors you have to keep reusing the same one and
  67.  * it gets *real* slow.
  68.  */
  69. typedef struct d_fd {
  70.     struct d_fd *next;
  71.     DIR *dirp;
  72.     off_t off;
  73. } FD;
  74.  
  75. static FD *freep,
  76.  *node;
  77.  
  78. static int
  79. walk(register char *name)
  80. {
  81. #ifdef HAVE_DIRENT
  82.     register struct dirent *dp;
  83. #else
  84.     register struct direct *dp;
  85. #endif
  86.     register int rval;
  87.     struct stat sb;
  88.     FD cur;
  89.     char *save,
  90. #ifdef __STDC__
  91.      *strcpy(char *, const char *);
  92. #else
  93.      *strcpy();
  94. #endif
  95.  
  96.     if (!freep)
  97.         freep = &cur;
  98.     else
  99.         node->next = &cur;
  100.     node = &cur;
  101.     cur.off = 0;
  102.  
  103.   getfd:if (!g_fds) {
  104.         freep->off = telldir(freep->dirp);
  105.         closedir(freep->dirp);
  106.         freep = freep->next;
  107.         ++g_fds;
  108.     }
  109.     if ( !(cur.dirp = opendir(bp)) ) {
  110.         if (errno == EMFILE) {
  111.             g_fds = 0;
  112.             goto getfd;
  113.         }
  114.         return (errno == EACCES ? (*g_fn) (bp, &sb, FTW_DNR) : -1);
  115.     } else
  116.         --g_fds;
  117.  
  118.     for (; *name; ++name) ;
  119.     *name++ = '/';
  120.     for (rval = 0, dp = readdir(cur.dirp); dp; dp = readdir(cur.dirp)) {
  121.         if (ISDOT(dp))
  122.             continue;
  123.         (void) strcpy(name, dp->d_name);
  124.         if (lstat(bp, &sb)) {
  125.             rval = errno == EACCES ?
  126.                 (*g_fn) (bp, &sb, FTW_NS) : -1;
  127.             if (rval)
  128.                 break;
  129.         }
  130. #ifdef HAVE_SYMLINK
  131.         if (ISLINK(sb) && g_opts & FTW_SYMLINK)
  132.             if (stat(bp, &sb))
  133.                 continue;
  134. #endif
  135.         if (!ISDIR(sb)) {
  136.             rval = (*g_fn) (bp, &sb, FTW_F);
  137.             if (rval)
  138.                 break;
  139.             continue;
  140.         }
  141.         if (g_opts & FTW_DIRLAST)
  142. #ifdef HAVE_D_NAMLEN
  143.             save = name + dp->d_namlen;
  144. #else
  145.             save = name + strlen(dp->d_name);
  146. #endif
  147.         rval = (*g_fn) (bp, &sb, FTW_D);
  148.         if ( (rval && rval != NODESC) || (rval = walk(name)))
  149.             break;
  150.         if (g_opts & FTW_DIRLAST) {
  151.             *save = '\0';
  152.             rval = (*g_fn) (dp->d_name, &sb, FTW_D2);
  153.             if (rval)
  154.                 if (rval == NODESC)
  155.                     rval = 0;
  156.                 else
  157.                     break;
  158.         }
  159.         if (cur.off) {
  160.             *name = NULL;
  161.             if ( (cur.dirp = opendir(bp)) ) {
  162.                 seekdir(cur.dirp, cur.off);
  163.                 /* tricky; if we have to reset the directory pointer we know
  164.                  * it's the next one to reuse */
  165.                 freep = &cur;
  166.                 --g_fds;
  167.             }
  168.             /* directory moved from under us!!! */
  169.             else {
  170.                 rval = -1;
  171.                 break;
  172.             }
  173.         }
  174.     }
  175.     closedir(cur.dirp);
  176.     ++g_fds;
  177.     return (rval);
  178. }
  179.  
  180. static int
  181. chwalk(register char *name)
  182. {
  183. #ifdef HAVE_DIRENT
  184.     register struct dirent *dp;
  185. #else
  186.     register struct direct *dp;
  187. #endif
  188.  
  189.     register int rval;
  190.     struct stat sb;
  191.     FD cur;
  192.     char *pwd,
  193.      *getwd(char *),
  194. #ifndef NO_MALLOC_PROTO
  195.      *malloc(size_t),
  196. #endif
  197.      *strcpy(char *, const char *);
  198.  
  199.     if (!freep)
  200.         freep = &cur;
  201.     else
  202.         node->next = &cur;
  203.     node = &cur;
  204.     cur.off = 0;
  205.  
  206.     if (chdir(name))
  207.         return (errno == EACCES ? (*g_fn) (name, &sb, FTW_DNR) : -1);
  208.  
  209.   getfd:if (!g_fds) {
  210.         freep->off = telldir(freep->dirp);
  211.         closedir(freep->dirp);
  212.         freep = freep->next;
  213.         ++g_fds;
  214.     }
  215.     if ( !(cur.dirp = opendir(".")) )  {
  216.         if (errno == EMFILE) {
  217.             g_fds = 0;
  218.             goto getfd;
  219.         }
  220.         return (errno == EACCES ? (*g_fn) (".", &sb, FTW_DNR) : -1);
  221.     } else
  222.         --g_fds;
  223.  
  224.     for (rval = 0, dp = readdir(cur.dirp); dp; dp = readdir(cur.dirp)) {
  225.         if (ISDOT(dp))
  226.             continue;
  227.         if (lstat(dp->d_name, &sb)) {
  228.             rval = errno == EACCES ?
  229.                 (*g_fn) (dp->d_name, &sb, FTW_NS) : -1;
  230.             if (rval)
  231.                 break;
  232.         }
  233.         pwd = NULL;
  234. #ifdef HAVE_SYMLINK
  235.         if (ISLINK(sb) && g_opts & FTW_SYMLINK) {
  236.             if (stat(dp->d_name, &sb))
  237.                 continue;
  238.             if (ISDIR(sb)) {
  239.                 /* NOSTRICT */
  240.                 if (!(pwd = malloc((u_int) MAXPATHLEN))) {
  241.                     rval = -1;
  242.                     break;
  243.                 }
  244.                 if (!getwd(pwd)) {
  245.                     rval = -1;
  246.                     break;
  247.                 }
  248.             }
  249.         }
  250. #endif
  251.         if (!ISDIR(sb)) {
  252.             rval = (*g_fn) (dp->d_name, &sb, FTW_F);
  253.             if (rval)
  254.                 break;
  255.             continue;
  256.         }
  257.         rval = (*g_fn) (dp->d_name, &sb, FTW_D);
  258.         if ((rval && rval != NODESC) || (rval = chwalk(dp->d_name)))
  259.             break;
  260.         if (g_opts & FTW_DIRLAST) {
  261.             rval = (*g_fn) (dp->d_name, &sb, FTW_D2);
  262.             if (rval)
  263.                 if (rval == NODESC)
  264.                     rval = 0;
  265.                 else
  266.                     break;
  267.         }
  268.         if (pwd && chdir(pwd)) {
  269.             rval = -1;
  270.             break;
  271.         }
  272.         if (cur.off) {
  273.             if ( (cur.dirp = opendir(".")) ) {
  274.                 seekdir(cur.dirp, cur.off);
  275.                 /* tricky; if we have to reset the directory pointer we know
  276.                  * it's the next one to reuse */
  277.                 freep = &cur;
  278.                 --g_fds;
  279.             }
  280.             /* directory moved from under us!!! */
  281.             else {
  282.                 rval = -1;
  283.                 break;
  284.             }
  285.         }
  286.     }
  287.     closedir(cur.dirp);
  288.     ++g_fds;
  289.     if (chdir(".."))
  290.         return (-1);
  291.     return (rval);
  292. }
  293.  
  294. /* S5 compatible ftw(BA_LIB) */
  295. int
  296. ftw(char *path, int (*fn) ( /* ??? */ ), int maxfds)
  297. {
  298.     return (treewalk(path, fn, maxfds, 0));
  299. }
  300.  
  301. int
  302. treewalk(char *path, int (*fn) ( /* ??? */ ), int maxfds, int opts)
  303. {
  304.     struct stat sb;
  305.     int rval;
  306.     char *pwd,
  307.      *getwd(char *),
  308. #ifndef NO_MALLOC_PROTO
  309.      *malloc(size_t),
  310. #endif
  311.      *strcpy(char *, const char *);
  312.  
  313.     if (lstat(path, &sb))
  314.         return (errno == EACCES ? (*fn) (path, &sb, FTW_NS) : -1);
  315.  
  316.     pwd = NULL;
  317. #ifdef HAVE_SYMLINK
  318.     if (ISLINK(sb) && opts & FTW_SYMLINK) {
  319.         if (stat(path, &sb))
  320.             return (0);
  321.         if (ISDIR(sb)) {
  322.             /* NOSTRICT */
  323.             if (!(pwd = malloc((u_int) MAXPATHLEN)))
  324.                 return (-1);
  325.             if (!getwd(pwd))
  326.                 return (-1);
  327.         }
  328.     }
  329. #endif
  330.     if (!ISDIR(sb))
  331.         return ((*fn) (path, &sb, FTW_F));
  332.  
  333.     if (!maxfds)
  334.         return (-1);
  335.     g_fds = maxfds == -1 ? getdtablesize(): maxfds;
  336.     g_fn = fn;
  337.     g_opts = opts;
  338.  
  339.     if (!(opts & FTW_CHDIR) && !(bp = malloc((u_int) MAXPATHLEN))) {
  340.         errno = ENOMEM;
  341.         return (-1);
  342.     }
  343.     rval = (*fn) (path, &sb, FTW_D);
  344.     if (rval == NODESC)
  345.         rval = 0;
  346.     else if (!rval) {
  347.         if (opts & FTW_CHDIR)
  348.             rval = chwalk(path);
  349.         else
  350.             rval = walk(strcpy(bp, path));
  351.         if (!rval && opts & FTW_DIRLAST) {
  352.             rval = (*fn) (path, &sb, FTW_D2);
  353.             if (rval == NODESC)
  354.                 rval = 0;
  355.         }
  356.     }
  357.     if (pwd && chdir(pwd))
  358.         return (-1);
  359.     return (rval);
  360. }
  361.