home *** CD-ROM | disk | FTP | other *** search
/ The CDPD Public Domain Collection for CDTV 4 / CDPD_IV.bin / networking / tcpip / amitcp-support / wustl-ftpdaemon / support / ftw.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-06-29  |  7.4 KB  |  370 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. #include <stdio.h>
  33.  
  34. #include <sys/param.h>
  35. #include <sys/stat.h>
  36. #include <sys/stat.h>
  37.  
  38. #ifdef AMIGA
  39. #include <bsdsocket.h>
  40. #endif
  41.  
  42. #include "ftw.h"
  43.  
  44. #define    NODESC    -1
  45.  
  46. #ifdef HAVE_SYMLINK
  47. # define    ISLINK(sb)    ((sb.st_mode&S_IFMT) == S_IFLNK)
  48. #else
  49. # define lstat stat
  50. #endif
  51.  
  52. #define    ISDIR(sb)    ((sb.st_mode&S_IFMT) == S_IFDIR)
  53. #define    ISDOT(dp) \
  54.     (dp->d_name[0] == '.' && (!dp->d_name[1] || \
  55.         (dp->d_name[1] == '.' && !dp->d_name[2])))
  56.  
  57. extern int errno;
  58. static int g_fds,
  59.   (*g_fn) (char *, struct stat *, int),
  60.   g_opts;
  61. static char *bp;
  62.  
  63. int treewalk(char *path, int (*fn) (char *, struct stat *, int), int maxfds, int opts);
  64.  
  65. /*
  66.  * cycle through the directories at the top of the tree, otherwise, once
  67.  * you run out of descriptors you have to keep reusing the same one and
  68.  * it gets *real* slow.
  69.  */
  70. typedef struct d_fd {
  71.     struct d_fd *next;
  72.     DIR *dirp;
  73.     off_t off;
  74. } FD;
  75.  
  76. static FD *freep,
  77.  *node;
  78.  
  79. static int
  80. walk(register char *name)
  81. {
  82. #ifdef HAVE_DIRENT
  83.     register struct dirent *dp;
  84. #else
  85.     register struct direct *dp;
  86. #endif
  87.     register int rval;
  88.     struct stat sb;
  89.     FD cur;
  90.     char *save,
  91.      *strcpy(char *, const char *);
  92.  
  93.     if (!freep)
  94.         freep = &cur;
  95.     else
  96.         node->next = &cur;
  97.     node = &cur;
  98.     cur.off = 0;
  99.  
  100.   getfd:if (!g_fds) {
  101.         freep->off = telldir(freep->dirp);
  102.         closedir(freep->dirp);
  103.         freep = freep->next;
  104.         ++g_fds;
  105.     }
  106.     if ( !(cur.dirp = opendir(bp)) ) {
  107.         if (errno == EMFILE) {
  108.             g_fds = 0;
  109.             goto getfd;
  110.         }
  111.         return (errno == EACCES ? (*g_fn) (bp, &sb, FTW_DNR) : -1);
  112.     } else
  113.         --g_fds;
  114.  
  115.     for (; *name; ++name) ;
  116.     *name++ = '/';
  117.     for (rval = 0, dp = readdir(cur.dirp); dp; dp = readdir(cur.dirp)) {
  118.         if (ISDOT(dp))
  119.             continue;
  120.         (void) strcpy(name, dp->d_name);
  121.         if (lstat(bp, &sb)) {
  122.             rval = errno == EACCES ?
  123.                 (*g_fn) (bp, &sb, FTW_NS) : -1;
  124.             if (rval)
  125.                 break;
  126.         }
  127. #ifdef HAVE_SYMLINK
  128.         if (ISLINK(sb) && g_opts & FTW_SYMLINK)
  129.             if (stat(bp, &sb))
  130.                 continue;
  131. #endif
  132.         if (!ISDIR(sb)) {
  133.             rval = (*g_fn) (bp, &sb, FTW_F);
  134.             if (rval)
  135.                 break;
  136.             continue;
  137.         }
  138.         if (g_opts & FTW_DIRLAST)
  139. #ifdef HAVE_D_NAMLEN
  140.             save = name + dp->d_namlen;
  141. #else
  142.             save = name + strlen(dp->d_name);
  143. #endif
  144.         rval = (*g_fn) (bp, &sb, FTW_D);
  145.         if ( (rval && rval != NODESC) || (rval = walk(name)))
  146.             break;
  147.         if (g_opts & FTW_DIRLAST) {
  148.             *save = '\0';
  149.             rval = (*g_fn) (dp->d_name, &sb, FTW_D2);
  150.             if (rval)
  151.                 if (rval == NODESC)
  152.                     rval = 0;
  153.                 else
  154.                     break;
  155.         }
  156.         if (cur.off) {
  157.             *name = NULL;
  158.             if ( (cur.dirp = opendir(bp)) ) {
  159.                 seekdir(cur.dirp, cur.off);
  160.                 /* tricky; if we have to reset the directory pointer we know
  161.                  * it's the next one to reuse */
  162.                 freep = &cur;
  163.                 --g_fds;
  164.             }
  165.             /* directory moved from under us!!! */
  166.             else {
  167.                 rval = -1;
  168.                 break;
  169.             }
  170.         }
  171.     }
  172.     closedir(cur.dirp);
  173.     ++g_fds;
  174.     return (rval);
  175. }
  176.  
  177. static int
  178. chwalk(register char *name)
  179. {
  180. #ifdef HAVE_DIRENT
  181.     register struct dirent *dp;
  182. #else
  183.     register struct direct *dp;
  184. #endif
  185.  
  186.     register int rval;
  187.     struct stat sb;
  188.     FD cur;
  189.     char *pwd,
  190. #ifndef HAVE_GETCWD
  191.      *getwd(char *),
  192. #endif
  193. #ifndef NO_MALLOC_PROTO
  194.      *malloc(size_t),
  195. #endif
  196.      *strcpy(char *, const char *);
  197.  
  198.     if (!freep)
  199.         freep = &cur;
  200.     else
  201.         node->next = &cur;
  202.     node = &cur;
  203.     cur.off = 0;
  204.  
  205.     if (chdir(name))
  206.         return (errno == EACCES ? (*g_fn) (name, &sb, FTW_DNR) : -1);
  207.  
  208.   getfd:if (!g_fds) {
  209.         freep->off = telldir(freep->dirp);
  210.         closedir(freep->dirp);
  211.         freep = freep->next;
  212.         ++g_fds;
  213.     }
  214.     if ( !(cur.dirp = opendir(".")) )  {
  215.         if (errno == EMFILE) {
  216.             g_fds = 0;
  217.             goto getfd;
  218.         }
  219.         return (errno == EACCES ? (*g_fn) (".", &sb, FTW_DNR) : -1);
  220.     } else
  221.         --g_fds;
  222.  
  223.     for (rval = 0, dp = readdir(cur.dirp); dp; dp = readdir(cur.dirp)) {
  224.         if (ISDOT(dp))
  225.             continue;
  226.         if (lstat(dp->d_name, &sb)) {
  227.             rval = errno == EACCES ?
  228.                 (*g_fn) (dp->d_name, &sb, FTW_NS) : -1;
  229.             if (rval)
  230.                 break;
  231.         }
  232.         pwd = NULL;
  233. #ifdef HAVE_SYMLINK
  234.         if (ISLINK(sb) && g_opts & FTW_SYMLINK) {
  235.             if (stat(dp->d_name, &sb))
  236.                 continue;
  237.             if (ISDIR(sb)) {
  238.                 /* NOSTRICT */
  239.                 if (!(pwd = malloc((u_int) MAXPATHLEN))) {
  240.                     rval = -1;
  241.                     break;
  242.                 }
  243. #ifdef HAVE_GETCWD
  244.                 if (!getcwd(pwd,MAXPATHLEN)) {
  245. #else
  246.                 if (!getwd(pwd)) {
  247. #endif
  248.                     rval = -1;
  249.                     break;
  250.                 }
  251.             }
  252.         }
  253. #endif
  254.         if (!ISDIR(sb)) {
  255.             rval = (*g_fn) (dp->d_name, &sb, FTW_F);
  256.             if (rval)
  257.                 break;
  258.             continue;
  259.         }
  260.         rval = (*g_fn) (dp->d_name, &sb, FTW_D);
  261.         if ((rval && rval != NODESC) || (rval = chwalk(dp->d_name)))
  262.             break;
  263.         if (g_opts & FTW_DIRLAST) {
  264.             rval = (*g_fn) (dp->d_name, &sb, FTW_D2);
  265.             if (rval)
  266.                 if (rval == NODESC)
  267.                     rval = 0;
  268.                 else
  269.                     break;
  270.         }
  271.         if (pwd && chdir(pwd)) {
  272.             rval = -1;
  273.             break;
  274.         }
  275.         if (cur.off) {
  276.             if ( (cur.dirp = opendir(".")) ) {
  277.                 seekdir(cur.dirp, cur.off);
  278.                 /* tricky; if we have to reset the directory pointer we know
  279.                  * it's the next one to reuse */
  280.                 freep = &cur;
  281.                 --g_fds;
  282.             }
  283.             /* directory moved from under us!!! */
  284.             else {
  285.                 rval = -1;
  286.                 break;
  287.             }
  288.         }
  289.     }
  290.     closedir(cur.dirp);
  291.     ++g_fds;
  292.     if (chdir(".."))
  293.         return (-1);
  294.     return (rval);
  295. }
  296.  
  297. /* S5 compatible ftw(BA_LIB) */
  298. int
  299. ftw(char *path, int (*fn) (char *, struct stat *, int), int maxfds)
  300. {
  301.     return (treewalk(path, fn, maxfds, 0));
  302. }
  303.  
  304. int
  305. treewalk(char *path, int (*fn) (char *, struct stat *, int), int maxfds, int opts)
  306. {
  307.     struct stat sb;
  308.     int rval;
  309.     char *pwd,
  310. #ifndef HAVE_GETCWD
  311.      *getwd(char *),
  312. #endif
  313. #ifndef NO_MALLOC_PROTO
  314.      *malloc(size_t),
  315. #endif
  316.      *strcpy(char *, const char *);
  317.  
  318.     if (lstat(path, &sb))
  319.         return (errno == EACCES ? (*fn) (path, &sb, FTW_NS) : -1);
  320.  
  321.     pwd = NULL;
  322. #ifdef HAVE_SYMLINK
  323.     if (ISLINK(sb) && opts & FTW_SYMLINK) {
  324.         if (stat(path, &sb))
  325.             return (0);
  326.         if (ISDIR(sb)) {
  327.             /* NOSTRICT */
  328.             if (!(pwd = malloc((u_int) MAXPATHLEN)))
  329.                 return (-1);
  330. #ifdef HAVE_GETCWD
  331.             if (!getcwd(pwd,MAXPATHLEN))
  332. #else
  333.             if (!getwd(pwd))
  334. #endif
  335.                 return (-1);
  336.         }
  337.     }
  338. #endif
  339.     if (!ISDIR(sb))
  340.         return ((*fn) (path, &sb, FTW_F));
  341.  
  342.     if (!maxfds)
  343.         return (-1);
  344.     g_fds = maxfds == -1 ? getdtablesize(): maxfds;
  345.     g_fn = fn;
  346.     g_opts = opts;
  347.  
  348.     if (!(opts & FTW_CHDIR) && !(bp = malloc((u_int) MAXPATHLEN))) {
  349.         errno = ENOMEM;
  350.         return (-1);
  351.     }
  352.     rval = (*fn) (path, &sb, FTW_D);
  353.     if (rval == NODESC)
  354.         rval = 0;
  355.     else if (!rval) {
  356.         if (opts & FTW_CHDIR)
  357.             rval = chwalk(path);
  358.         else
  359.             rval = walk(strcpy(bp, path));
  360.         if (!rval && opts & FTW_DIRLAST) {
  361.             rval = (*fn) (path, &sb, FTW_D2);
  362.             if (rval == NODESC)
  363.                 rval = 0;
  364.         }
  365.     }
  366.     if (pwd && chdir(pwd))
  367.         return (-1);
  368.     return (rval);
  369. }
  370.