home *** CD-ROM | disk | FTP | other *** search
/ ftp.ncftp.com / ftp.ncftp.com.zip / ftp.ncftp.com / ncftp / older_versions / ncftp-3.2.2-src.tar.bz2 / ncftp-3.2.2-src.tar / ncftp-3.2.2 / libncftp / ftw.c < prev    next >
C/C++ Source or Header  |  2006-06-18  |  12KB  |  506 lines

  1. /* Ftw.c
  2.  *
  3.  * Copyright (c) 1996-2005 Mike Gleason, NcFTP Software.
  4.  * All rights reserved.
  5.  *
  6.  */
  7.  
  8. #if defined(SOLARIS) && (SOLARIS >= 250)
  9. #    define _POSIX_PTHREAD_SEMANTICS 1
  10. #endif
  11.  
  12. #include "syshdrs.h"
  13. #ifdef PRAGMA_HDRSTOP
  14. #    pragma hdrstop
  15. #endif
  16.  
  17. /* Internal to ftw.c */
  18. typedef struct FtwSubDirList *FtwSubDirListPtr;
  19. typedef struct FtwSubDirList {
  20.     FtwSubDirListPtr next;
  21.     struct Stat st;
  22.     size_t fnLen;
  23.     char name[1];
  24. } FtwSubDirList;
  25.  
  26. struct dirent *Readdir(DIR *const dir, struct dirent *const dp, const size_t sz);
  27.  
  28.  
  29.  
  30. #if (defined(WIN32) || defined(_WINDOWS)) && !defined(__CYGWIN__)
  31. DIR *opendir(const char *const path)
  32. {
  33.     DIR *p;
  34.     char *dirpath;
  35.     size_t len;
  36.  
  37.     p = (DIR *) malloc(sizeof(DIR));
  38.     if (p == NULL)
  39.         return NULL;
  40.     memset(p, 0, sizeof(DIR));
  41.  
  42.     len = strlen(path);
  43.     dirpath = (char *) malloc(len + 5);
  44.     if (dirpath == NULL)
  45.         return NULL;
  46.     p->dirpath = dirpath;
  47.  
  48.     memcpy(dirpath, path, len + 1);
  49.     if (IsLocalPathDelim(dirpath[len - 1])) {
  50.         --len;
  51.         dirpath[len] = '\0';
  52.     }
  53.     memcpy(dirpath + len, "\\*.*", (size_t) 5);
  54.  
  55.     p->searchHandle = FindFirstFile(dirpath, &p->ffd);
  56.     if (p->searchHandle == INVALID_HANDLE_VALUE) {
  57.         memset(&p->ffd, 0, sizeof(p->ffd));
  58.     }
  59.     return (p);
  60. }    /* opendir */
  61.  
  62.  
  63.  
  64. struct dirent *readdir(DIR *dir)
  65. {
  66.     memcpy(dir->dent.d_name, dir->ffd.cFileName, (size_t) sizeof(dir->dent.d_name));
  67.     if (dir->searchHandle != INVALID_HANDLE_VALUE) {
  68.         if (!FindNextFile(dir->searchHandle, &dir->ffd)) {
  69.             /* no more items, or an error we don't care about */
  70.             FindClose(dir->searchHandle);
  71.             dir->searchHandle = INVALID_HANDLE_VALUE;
  72.             memset(&dir->ffd, 0, sizeof(dir->ffd));
  73.         }
  74.     }
  75.     if (dir->dent.d_name[0] == '\0')
  76.         return NULL;
  77.     return (&dir->dent);
  78. }    /* readdir */
  79.  
  80.  
  81.  
  82. void closedir(DIR *dir)
  83. {
  84.     /* The searchHandle is already closed, but we
  85.      * need to dealloc the structures.
  86.      */
  87.     if ((dir != NULL) && (dir->dirpath != NULL)) {
  88.         free(dir->dirpath);
  89.         memset(dir, 0, sizeof(DIR));
  90.         free(dir);
  91.     }
  92. }    /* closedir */
  93. #endif    /* WIN32 */
  94.  
  95.  
  96.  
  97.  
  98. /*
  99.  * Warning: be sure to use a custom-sized struct dirent, since the
  100.  * real struct dirent on some platforms is just a stub structure
  101.  * with room for only one byte in the filename.
  102.  */
  103. struct dirent *
  104. Readdir(DIR *const dir, struct dirent *const dp, const size_t sz)
  105. {
  106. #if defined(MACOSX)
  107.     struct dirent *p;
  108.     p = readdir(dir);
  109.     if (p != NULL) {
  110.         memcpy(dp, p, sz);
  111.         return (dp);
  112.     }
  113. #elif defined(HAVE_READDIR_R) && ( (defined(SOLARIS) && (SOLARIS < 250)) || (defined(SCO)) || (defined(IRIX) && (IRIX < 6)) )
  114.     struct dirent *p;
  115.     p = readdir_r(dir, dp);
  116.     if (p != NULL)
  117.         return (dp);
  118. #elif defined(HAVE_READDIR_R) && (defined(HPUX) && (HPUX < 1100))
  119.     struct dirent *p;
  120.     if (readdir_r(dir, dp) >= 0)
  121.         return (dp);
  122. #elif defined(HAVE_READDIR_R)
  123.     struct dirent *p;
  124.     p = NULL;
  125.     if ((readdir_r(dir, dp, &p) == 0) && (p != NULL))
  126.         return (dp);
  127. #else
  128.     struct dirent *p;
  129.     p = readdir(dir);
  130.     if (p != NULL) {
  131. #    if (defined(WIN32) || defined(_WINDOWS)) && !defined(__CYGWIN__)
  132.         memset(dp, 0, sz);
  133.         memcpy(dp, p, ((sz < sizeof(struct dirent)) ? sz : sizeof(struct dirent)));
  134. #    else
  135.         memcpy(dp, p, sz);
  136. #    endif
  137.         return (dp);
  138.     }
  139. #endif
  140.  
  141.     memset(dp, 0, sz);
  142.     return (NULL);
  143. }    /* Readdir */
  144.  
  145.  
  146.  
  147. void
  148. FtwInit(FtwInfo *const ftwip)
  149. {
  150.     memset(ftwip, 0, sizeof(FtwInfo));
  151. #if (defined(WIN32) || defined(_WINDOWS)) && !defined(__CYGWIN__)
  152.     ftwip->dirSeparator = '\\';
  153.     ftwip->rootDir[0] = '\\';
  154. #else
  155.     ftwip->dirSeparator = '/';
  156.     ftwip->rootDir[0] = '/';
  157. #endif
  158.     ftwip->init = kFtwMagic;
  159. }    /* FtwInit */
  160.  
  161.  
  162.  
  163. void
  164. FtwDispose(FtwInfo *const ftwip)
  165. {
  166.     if (ftwip->init != kFtwMagic)
  167.         return;
  168.     if ((ftwip->noAutoMallocAndFree == 0) && (ftwip->curPath != NULL))
  169.         free(ftwip->curPath);
  170.     memset(ftwip, 0, sizeof(FtwInfo));
  171. }    /* FtwDispose */
  172.  
  173.  
  174. static int
  175. FtwTraverse(const FtwInfoPtr ftwip, size_t dirPathLen, int depth)
  176. {
  177.     DIR *DIRp;
  178.     char *cp;
  179.     size_t fnLen;
  180.     struct dirent *dentp;
  181.     mode_t m;
  182.     char *filename;
  183.     char *newBuf;
  184.     char *path = ftwip->curPath;
  185.     int nSubdirs;
  186.     FtwSubDirListPtr head = NULL, tail = NULL, sdp, nextsdp;
  187.     int rc = (-1);
  188.     int isRootDir;
  189.  
  190.     isRootDir = ((dirPathLen == 1) && (IsLocalPathDelim(path[0]))) ? 1 : 0;
  191.     if ((DIRp = opendir(dirPathLen ? path : ".")) == NULL) {
  192.         /* Not an error unless the first directory could not be opened. */
  193.         return (0);
  194.     }
  195.  
  196.     nSubdirs = 0;
  197.     ++ftwip->numDirs;
  198.     ftwip->depth = depth;
  199.     if (ftwip->maxDepth < ftwip->depth) {
  200.         ftwip->maxDepth = ftwip->depth;
  201.     }
  202.     filename = path + dirPathLen;
  203.     if (isRootDir == 0) {    /* Root directory is a separator. */
  204.         *filename++ = (char) ftwip->dirSeparator;
  205.         dirPathLen++;
  206.     }
  207.     *filename = '\0';
  208.     /* Path now contains dir/  */
  209.  
  210.     dentp = (struct dirent *) ftwip->direntbuf;
  211.     for (;;) {
  212.         if (Readdir(DIRp, dentp, ftwip->direntbufSize) == NULL)
  213.             break;
  214.         cp = dentp->d_name;
  215.         if ((cp[0] == '.') && ((cp[1] == '\0') || ((cp[1] == '.') && (cp[2] == '\0'))))
  216.             continue;    /* Skip . and .. */
  217.  
  218.         *filename = '\0';
  219.         fnLen = strlen(cp) + 1    /* include \0 */;
  220.         if ((fnLen + dirPathLen) > ftwip->curPathAllocSize) {
  221.             if (ftwip->autoGrow == kFtwNoAutoGrowAndFail) {
  222.                 goto panic;
  223.             } else if (ftwip->autoGrow == kFtwNoAutoGrowButContinue) {
  224.                 continue;
  225.             }
  226.             newBuf = (char *) realloc(ftwip->curPath, fnLen + dirPathLen + 30 + 2 /* room for / and \0 */);
  227.             if (newBuf == NULL)
  228.                 goto panic;
  229.             ftwip->curPath = newBuf;
  230.             ftwip->curPathAllocSize = fnLen + dirPathLen + 30;
  231.             path = ftwip->curPath;
  232.             filename = path + dirPathLen;
  233.             if (isRootDir == 0)    /* Root directory is a separator. */
  234.                 *filename++ = (char) ftwip->dirSeparator;
  235.             *filename = '\0';
  236.         }
  237.         memcpy(filename, cp, fnLen);
  238.         ftwip->curPathLen = dirPathLen + fnLen - 1;
  239.         ftwip->curFile = filename;
  240.         ftwip->curFileLen = fnLen - 1;
  241.         if (Lstat(path, &ftwip->curStat) == 0) {
  242.             m = ftwip->curStat.st_mode;
  243.             if (S_ISREG(m)) {
  244.                 ++ftwip->numFiles;
  245.                 ftwip->curType = '-';
  246.                 if ((*ftwip->proc)(ftwip) < 0) {
  247.                     goto panic;
  248.                 }
  249. #ifdef S_ISLNK
  250.             } else if (S_ISLNK(m)) {
  251.                 ftwip->curType = 'l';
  252.                 ++ftwip->numLinks;
  253.                 if ((*ftwip->proc)(ftwip) < 0) {
  254.                     goto panic;
  255.                 }
  256. #endif    /* S_ISLNK */
  257.             } else if (S_ISDIR(m)) {
  258.                 /* We delay entering the subdirectories
  259.                  * until we have closed this directory.
  260.                  * This will conserve file descriptors
  261.                  * and also have the effect of having
  262.                  * the files processed first.
  263.                  */
  264.                 sdp = (FtwSubDirListPtr) malloc(sizeof(FtwSubDirList) + fnLen);
  265.                 if (sdp == NULL)
  266.                     goto panic;
  267.                 memcpy(&sdp->st, &ftwip->curStat, sizeof(sdp->st));
  268.                 memcpy(sdp->name, cp, fnLen);
  269.                 sdp->fnLen = fnLen;
  270.                 sdp->next = NULL;
  271.                 if (head == NULL) {
  272.                     head = tail = sdp;
  273.                 } else {
  274.                     tail->next = sdp;
  275.                     tail = sdp;
  276.                 }
  277.                 nSubdirs++;
  278.             }
  279.         }
  280.     }
  281.     (void) closedir(DIRp);
  282.     DIRp = NULL;
  283.  
  284.     /* Now enter each subdirectory. */
  285.     for (sdp = head; sdp != NULL; sdp = nextsdp) {
  286.         nextsdp = sdp->next;
  287.         memcpy(&ftwip->curStat, &sdp->st, sizeof(ftwip->curStat));
  288.         fnLen = sdp->fnLen;
  289.         memcpy(filename, sdp->name, fnLen);
  290.         ftwip->curPathLen = dirPathLen + fnLen - 1;
  291.         ftwip->curFile = filename;
  292.         ftwip->curFileLen = fnLen - 1;
  293.         head = nextsdp;
  294.         free(sdp);
  295.  
  296.         ftwip->curType = 'd';
  297.         if ((*ftwip->proc)(ftwip) < 0) {
  298.             goto panic;
  299.         }
  300.         if (FtwTraverse(ftwip, dirPathLen + fnLen - 1, depth + 1) < 0)
  301.             goto panic;
  302.  
  303.         /* Reset these, since buffer could have
  304.          * been reallocated.
  305.          */
  306.         path = ftwip->curPath;
  307.         filename = path + dirPathLen;
  308.         *filename = '\0';
  309.     }
  310.     head = NULL;
  311.     rc = 0;
  312.  
  313. panic:
  314.     if (DIRp != NULL)
  315.         (void) closedir(DIRp);
  316.  
  317.     for (sdp = head; sdp != NULL; sdp = nextsdp) {
  318.         nextsdp = sdp->next;
  319.         free(sdp);
  320.     }
  321.  
  322.     return (rc);
  323. }    /* FtwTraverse */
  324.  
  325.  
  326.  
  327.  
  328. int
  329. Ftw(const FtwInfoPtr ftwip, const char *const path, FtwProc proc)
  330. {
  331.     size_t len, alen;
  332.     int rc;
  333.     char *cp, *endp;
  334.     size_t debufsize = 256;
  335. #ifdef HAVE_PATHCONF
  336.     long nmx;
  337. #endif
  338.  
  339.     if ((ftwip->init != kFtwMagic) || (path == NULL) || (path[0] == '\0') || (proc == (FtwProc) 0)) {
  340.         errno = EINVAL;
  341.         return (-1);
  342.     }
  343.  
  344.     ftwip->rlinkto = NULL;
  345.     ftwip->startPathLen = 0;
  346.     len = strlen(path);
  347.     if (ftwip->curPath == NULL) {
  348.         /* Call FtwSetBuf before calling Ftw for
  349.          * the first time, otherwise you get the
  350.          * default behavior.
  351.          */
  352.         ftwip->autoGrow = kFtwAutoGrow;
  353.         alen = len + 30 /* room to append filenames */ + 2 /* room for / and \0 */;
  354.         if (alen < 256)
  355.             alen = 256;
  356.         ftwip->curPath = (char *) malloc(alen);
  357.         if (ftwip->curPath == NULL)
  358.             return (-1);
  359.         ftwip->curPathAllocSize = alen - 2;
  360.     }
  361.  
  362.     ftwip->curType = 'd';
  363.     memset(ftwip->curPath, 0, ftwip->curPathAllocSize);
  364.     memcpy(ftwip->curPath, path, len + 1);
  365.     cp = ftwip->curPath + strlen(ftwip->curPath);
  366.     --cp;
  367.     while ((cp > ftwip->curPath) && IsLocalPathDelim(*cp))
  368.         *cp-- = '\0';
  369.     endp = cp + 1;
  370.     ftwip->curPathLen = ftwip->startPathLen = len = (size_t) (endp - ftwip->curPath);
  371.     while (cp >= ftwip->curPath) {
  372.         if (IsLocalPathDelim(*cp))
  373.             break;
  374.         --cp;
  375.     }
  376.     ftwip->curFile = ++cp;
  377.     ftwip->curFileLen = (size_t) (endp - cp);
  378.  
  379.     /* Note: we use Stat instead of Lstat here because we allow the
  380.      * top level node (as specified by path) to be a symlink
  381.      * to a directory.
  382.      */
  383.     memset(&ftwip->curStat, 0, sizeof(ftwip->curStat));
  384.     if (Stat(ftwip->curPath, &ftwip->curStat) < 0) {
  385.         return (-1);
  386.     } else if (! S_ISDIR(ftwip->curStat.st_mode)) {
  387.         errno = ENOTDIR;
  388.         return (-1);
  389.     }
  390.  
  391. #ifdef HAVE_PATHCONF
  392.     nmx = pathconf(ftwip->curPath, _PC_NAME_MAX);
  393.     if (nmx >= 256)
  394.         debufsize = nmx;
  395. #endif
  396.     debufsize += sizeof(struct dirent) + 8;
  397.     ftwip->direntbuf = calloc(debufsize, (size_t) 1);
  398.     if (ftwip->direntbuf == NULL) {
  399.         return (-1);
  400.     }
  401.     ftwip->direntbufSize = debufsize;
  402.  
  403.     ftwip->proc = proc;
  404.     if ((*proc)(ftwip) < 0) {
  405.         free(ftwip->direntbuf);
  406.         ftwip->direntbuf = NULL;
  407.         return (-1);
  408.     }
  409.  
  410.     ftwip->depth = ftwip->maxDepth = ftwip->numDirs = ftwip->numFiles = ftwip->numLinks = 0;
  411.     rc = FtwTraverse(ftwip, len, 1);
  412.  
  413.     /* Restore the start path when finished. */
  414.     memset(ftwip->curPath + ftwip->startPathLen, 0, ftwip->curPathAllocSize - ftwip->startPathLen);
  415.     ftwip->curPathLen = ftwip->startPathLen;
  416.  
  417.     /* Clear these out since you shouldn't be using them
  418.      * after Ftw returns.
  419.      */
  420.     memset(&ftwip->curStat, 0, sizeof(ftwip->curStat));
  421.     ftwip->proc = (FtwProc) 0;
  422.     ftwip->curFile = ftwip->curPath;
  423.     ftwip->curFileLen = 0;
  424.     ftwip->cip = 0;
  425.     ftwip->rlinkto = NULL;
  426.     free(ftwip->direntbuf);
  427.     ftwip->direntbuf = NULL;
  428.  
  429.     return (rc);
  430. }    /* Ftw */
  431.  
  432.  
  433.  
  434.  
  435. void
  436. FtwSetBuf(const FtwInfoPtr ftwip, char *const buf, const size_t bufsize, int autogrow)
  437. {
  438.     if (ftwip->init != kFtwMagic)
  439.         return;
  440.     if ((ftwip->noAutoMallocAndFree == 0) && (ftwip->curPath != NULL)) {
  441.         free(ftwip->curPath);
  442.     }
  443.     if (buf == NULL) {
  444.         /* They want us to create it */
  445.         ftwip->noAutoMallocAndFree = 0;
  446.         ftwip->curPath = (char *) malloc(bufsize);
  447.         ftwip->curPathAllocSize = (ftwip->curPath != NULL) ? bufsize : 0;
  448.         ftwip->autoGrow = autogrow;
  449.     } else {
  450.         /* We have been given a buffer to borrow.
  451.          * Note that we won't autogrow a borrowed buffer.
  452.          */
  453.         ftwip->noAutoMallocAndFree = 1;
  454.         ftwip->curPath = buf;
  455.         ftwip->curPathAllocSize = bufsize;
  456.         ftwip->autoGrow = (autogrow == kFtwAutoGrow) ? kFtwNoAutoGrowAndFail : autogrow;
  457.     }
  458. }    /* FtwSetBuf */
  459.  
  460.  
  461.  
  462. #ifdef TEST
  463.  
  464. static int
  465. MyFtwProc(const FtwInfoPtr ftwip)
  466. {
  467.     int m;
  468.  
  469.     m = ftwip->curStat.st_mode;
  470.     if (S_ISREG(m) != 0) {
  471.         /* file */
  472.         printf("%s\n", ftwip->curPath);
  473.     } else if (S_ISDIR(m)) {
  474.         /* directory */
  475.         printf("%s%c\n", ftwip->curPath, ftwip->dirSeparator);
  476.     } else if (S_ISLNK(m)) {
  477.         /* symbolic link */
  478.         printf("%s@\n", ftwip->curPath);
  479.     }
  480.  
  481.     return (0);
  482. }    /* MyFtwProc */
  483.  
  484.  
  485.  
  486.  
  487. int
  488. main(int argc, char *argv[])
  489. {
  490.     int rc;
  491.     FtwInfo ftwi;
  492.  
  493.     if (argc != 2)
  494.         exit(1);
  495.  
  496.     FtwInit(&ftwi);
  497.     rc = Ftw(&ftwi, argv[1], MyFtwProc);
  498.     if (rc < 0)
  499.         perror(argv[1]);
  500.     printf("rc=%d depth=%u dircount=%u filecount=%u\n", rc, ftwi.maxDepth, ftwi.numDirs, ftwi.numFiles);
  501.     FtwDispose(&ftwi);
  502.     exit((rc < 0) ? 1 : 0);
  503. }    /* main */
  504.  
  505. #endif    /* TEST */
  506.