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 / rftw.c < prev    next >
C/C++ Source or Header  |  2005-01-01  |  11KB  |  423 lines

  1. /* rftw.c
  2.  *
  3.  * Copyright (c) 1996-2005 Mike Gleason, NcFTP Software.
  4.  * All rights reserved.
  5.  *
  6.  */
  7.  
  8. #include "syshdrs.h"
  9. #ifdef PRAGMA_HDRSTOP
  10. #    pragma hdrstop
  11. #endif
  12.  
  13. /* Internal to rftw.c */
  14. typedef struct FtwSubDirList *FtwSubDirListPtr;
  15. typedef struct FtwSubDirList {
  16.     FtwSubDirListPtr next;
  17.     struct Stat st;
  18.     size_t fnLen;
  19.     char name[1];
  20. } FtwSubDirList;
  21.  
  22. /* This mess is essentially the local version of Ftw with FTP
  23.  * grafted onto it, so see that and grok that before studying this.
  24.  */
  25. static int
  26. FTPFtwTraverse(const FtwInfoPtr ftwip, size_t dirPathLen, int depth)
  27. {
  28.     char *cp;
  29.     size_t fnLen;
  30.     mode_t m;
  31.     char *filename;
  32.     char *newBuf;
  33.     char *path = ftwip->curPath;
  34.     int nSubdirs;
  35.     FtwSubDirListPtr head = NULL, tail = NULL, sdp, nextsdp;
  36.     int rc = (-1);
  37.     int lsl, mls, unlsrc;
  38.     FTPCIPtr cip = (FTPCIPtr) ftwip->cip;
  39.     FTPLineList ll;
  40.     FTPFileInfoList fil;
  41.     FTPLinePtr filePtr;
  42.     FTPFileInfoPtr fip;
  43.     int result;
  44.     int isRootDir;
  45.     longest_int sz;
  46.  
  47.     isRootDir = ((dirPathLen == 1) && ((path[0] == '/') || (path[0] == '\\'))) ? 1 : 0;
  48.     filePtr = NULL;
  49.     fip = NULL;
  50.     mls = 0;
  51.     lsl = 0;
  52.  
  53.     if (cip->hasMLSD == kCommandAvailable) {
  54.         mls = 1;
  55.         if (((result = FTPListToMemory2(cip, dirPathLen ? path : ".", &ll, "-a", 0, &mls)) < 0) || (ll.first == NULL)) {
  56.             /* Not an error unless the first directory could not be opened. */
  57.             DisposeLineListContents(&ll);
  58.             return (0);
  59.         }
  60.  
  61.         /* "MLSD" succeeded */
  62.         unlsrc = UnMlsD(cip, &fil, &ll);
  63.         if (unlsrc < 0) {
  64.             DisposeLineListContents(&ll);
  65.             return (cip->errNo = kErrInvalidMLSTResponse);
  66.         } else if (unlsrc == 0) {
  67.             /* empty */
  68.             DisposeLineListContents(&ll);
  69.             return (0);
  70.         }
  71.         fip = fil.first;
  72.         DisposeLineListContents(&ll);
  73.     } else {
  74.         if (((result = FTPListToMemory2(cip, dirPathLen ? path : ".", &ll, "-la", 0, &mls)) < 0) || (ll.first == NULL)) {
  75.             DisposeLineListContents(&ll);
  76.             if (((result = FTPListToMemory2(cip, dirPathLen ? path : ".", &ll, (cip->hasNLST_a == kCommandNotAvailable) ? "" : "-a", 0, &mls)) < 0) || (ll.first == NULL)) {
  77.                 DisposeLineListContents(&ll);
  78.                 return (0);
  79.             } else {
  80.                 /* "NLST -a" succeeded */
  81.                 RemoteGlobCollapse(cip, path, &ll);
  82.                 filePtr = ll.first;
  83.             }
  84.         } else {
  85.             /* "LIST -a" succeeded */
  86.             lsl = 1;
  87.             unlsrc = UnLslR(cip, &fil, &ll, cip->serverType);
  88.             if (unlsrc < 0) {
  89.                 DisposeLineListContents(&ll);
  90.                 return (cip->errNo = kErrInvalidMLSTResponse);
  91.             } else if (unlsrc == 0) {
  92.                 /* empty */
  93.                 DisposeLineListContents(&ll);
  94.                 return (0);
  95.             }
  96.             fip = fil.first;
  97.             DisposeLineListContents(&ll);
  98.         }
  99.     }
  100.  
  101.     nSubdirs = 0;
  102.     ++ftwip->numDirs;
  103.     ftwip->depth = depth;
  104.     if (ftwip->maxDepth < ftwip->depth) {
  105.         ftwip->maxDepth = ftwip->depth;
  106.     }
  107.     filename = path + dirPathLen;
  108.     if (isRootDir == 0) {    /* Root directory is a separator. */
  109.         *filename++ = (char) ftwip->dirSeparator;
  110.         dirPathLen++;
  111.     }
  112.     *filename = '\0';
  113.     /* Path now contains dir/  */
  114.  
  115.     for (;;) {
  116.         if ((mls != 0) || (lsl != 0)) {
  117.             if (fip == NULL)
  118.                 break;
  119.             cp = fip->relname;
  120.         } else {
  121.             if (filePtr == NULL)
  122.                 break;
  123.             cp = filePtr->line;
  124.         }
  125.         if ((cp[0] == '.') && ((cp[1] == '\0') || ((cp[1] == '.') && (cp[2] == '\0'))))
  126.             goto nxt;    /* Skip . and .. */
  127.  
  128.         ftwip->rlinkto = NULL;
  129.         *filename = '\0';
  130.         fnLen = strlen(cp) + 1    /* include \0 */;
  131.         if ((fnLen + dirPathLen) > ftwip->curPathAllocSize) {
  132.             if (ftwip->autoGrow == kFtwNoAutoGrowAndFail) {
  133.                 goto panic;
  134.             } else if (ftwip->autoGrow == kFtwNoAutoGrowButContinue) {
  135.                 goto nxt;
  136.             }
  137.             newBuf = (char *) realloc(ftwip->curPath, fnLen + dirPathLen + 30 + 2 /* room for / and \0 */);
  138.             if (newBuf == NULL)
  139.                 goto panic;
  140.             ftwip->curPath = newBuf;
  141.             ftwip->curPathAllocSize = fnLen + dirPathLen + 30;
  142.             path = ftwip->curPath;
  143.             filename = path + dirPathLen;
  144.             if (isRootDir == 0)    /* Root directory is a separator. */
  145.                 *filename++ = (char) ftwip->dirSeparator;
  146.             *filename = '\0';
  147.         }
  148.         memcpy(filename, cp, fnLen);
  149.         ftwip->curPathLen = dirPathLen + fnLen - 1;
  150.         ftwip->curFile = filename;
  151.         ftwip->curFileLen = fnLen - 1;
  152.  
  153.         memset(&ftwip->curStat, 0, sizeof(ftwip->curStat));
  154.         if (mls != 0) {
  155.             ftwip->curType = fip->type;
  156.             if (fip->type == 'd') {
  157.                 ftwip->curStat.st_mode = S_IFDIR;
  158.                 ftwip->curStat.st_size = (longest_int) -1;
  159. #ifdef S_IFLNK
  160.             } else if (fip->type == 'l') {
  161.                 ftwip->curStat.st_mode = S_IFLNK;
  162.                 ftwip->rlinkto = fip->rlinkto;
  163. #endif
  164.             } else if (fip->type == '-') {
  165.                 ftwip->curStat.st_mode = S_IFREG;
  166.                 ftwip->curStat.st_size = fip->size;
  167.             } else {
  168.                 /* unknown type, skip */
  169.                 goto nxt;
  170.             }
  171.             if (fip->mode != (-1))
  172.                 ftwip->curStat.st_mode |= (fip->mode & 00777);
  173.             ftwip->curStat.st_mtime = fip->mdtm;
  174.         } else if (lsl != 0) {
  175.             ftwip->curType = fip->type;
  176.             if (fip->type == 'd') {
  177.                 ftwip->curStat.st_mode = S_IFDIR;
  178.                 ftwip->curStat.st_size = (longest_int) -1;
  179. #ifdef S_IFLNK
  180.             } else if (fip->type == 'l') {
  181.                 ftwip->curStat.st_mode = S_IFLNK;
  182.                 ftwip->rlinkto = fip->rlinkto;
  183. #endif
  184.             } else if (fip->type == '-') {
  185.                 ftwip->curStat.st_mode = S_IFREG;
  186.                 ftwip->curStat.st_size = fip->size;
  187.             } else {
  188.                 /* unknown type, skip */
  189.                 goto nxt;
  190.             }
  191.             if (fip->mode != (-1))
  192.                 ftwip->curStat.st_mode |= (fip->mode & 00777);
  193.             ftwip->curStat.st_mtime = fip->mdtm;
  194.  
  195.             /* Override local times in LS output! */
  196.             result = FTPFileModificationTime(cip, path, &fip->mdtm);
  197.             if (fip->mdtm != kModTimeUnknown) {
  198.                 ftwip->curStat.st_mtime = fip->mdtm;
  199.             }
  200.         } else {
  201.             result = FTPIsDir(cip, path);
  202.             if (result < 0) {
  203.                 /* error */
  204.                 /* could be just a stat error, so continue */
  205.                 goto nxt;
  206.             } else if (result == 1) {
  207.                 /* directory */
  208.                 ftwip->curType = 'd';
  209.                 ftwip->curStat.st_mode = S_IFDIR | 00755;
  210.                 result = FTPFileModificationTime(cip, path, &ftwip->curStat.st_mtime);
  211.             } else {
  212.                 /* file */
  213.                 ftwip->curType = '-';
  214.                 ftwip->curStat.st_mode = S_IFREG | 00644;
  215.                 result = FTPFileSizeAndModificationTime(cip, path, &sz, kTypeBinary, &ftwip->curStat.st_mtime);
  216. #if defined(TRU64UNIX) || defined(DIGITAL_UNIX)
  217.                 ftwip->curStat.st_size = (off_t) sz;
  218. #else
  219.                 ftwip->curStat.st_size = sz;
  220. #endif
  221.             }
  222.         }
  223.  
  224.         {
  225.             m = ftwip->curStat.st_mode;
  226.             if (S_ISREG(m)) {
  227.                 ++ftwip->numFiles;
  228.                 ftwip->curType = '-';
  229.                 if ((*ftwip->proc)(ftwip) < 0) {
  230.                     goto panic;
  231.                 }
  232.             } else if (S_ISLNK(m)) {
  233.                 ++ftwip->numLinks;
  234.                 ftwip->curType = 'l';
  235.                 if ((*ftwip->proc)(ftwip) < 0) {
  236.                     goto panic;
  237.                 }
  238.             } else if (S_ISDIR(m)) {
  239.                 /* We delay entering the subdirectories
  240.                  * until we have closed this directory.
  241.                  * This will conserve file descriptors
  242.                  * and also have the effect of having
  243.                  * the files processed first.
  244.                  */
  245.                 sdp = (FtwSubDirListPtr) malloc(sizeof(FtwSubDirList) + fnLen);
  246.                 if (sdp == NULL)
  247.                     goto panic;
  248.                 memcpy(&sdp->st, &ftwip->curStat, sizeof(sdp->st));
  249.                 memcpy(sdp->name, cp, fnLen);
  250.                 sdp->fnLen = fnLen;
  251.                 sdp->next = NULL;
  252.                 if (head == NULL) {
  253.                     head = tail = sdp;
  254.                 } else {
  255.                     tail->next = sdp;
  256.                     tail = sdp;
  257.                 }
  258.                 nSubdirs++;
  259.             }
  260.         }
  261. nxt:
  262.         if ((mls != 0) || (lsl != 0)) {
  263.             fip = fip->next;
  264.         } else {
  265.             filePtr = filePtr->next;
  266.         }
  267.     }
  268.  
  269.     if ((mls != 0) || (lsl != 0)) {
  270.         DisposeFileInfoListContents(&fil);
  271.     } else {
  272.         DisposeLineListContents(&ll);
  273.     }
  274.  
  275.     /* Now enter each subdirectory. */
  276.     for (sdp = head; sdp != NULL; sdp = nextsdp) {
  277.         nextsdp = sdp->next;
  278.         memcpy(&ftwip->curStat, &sdp->st, sizeof(ftwip->curStat));
  279.         fnLen = sdp->fnLen;
  280.         memcpy(filename, sdp->name, fnLen);
  281.         ftwip->curFile = filename;
  282.         ftwip->curFileLen = fnLen - 1;
  283.         ftwip->curPathLen = dirPathLen + fnLen - 1;
  284.         head = nextsdp;
  285.         free(sdp);
  286.  
  287.         ftwip->curType = 'd';
  288.         if ((*ftwip->proc)(ftwip) < 0) {
  289.             goto panic;
  290.         }
  291.         if (FTPFtwTraverse(ftwip, dirPathLen + fnLen - 1, depth + 1) < 0)
  292.             goto panic;
  293.  
  294.         /* Reset these, since buffer could have
  295.          * been reallocated.
  296.          */
  297.         path = ftwip->curPath;
  298.         filename = path + dirPathLen;
  299.         *filename = '\0';
  300.     }
  301.     head = NULL;
  302.     rc = 0;
  303.  
  304. panic:
  305.     if (mls != 0) {
  306.         DisposeFileInfoListContents(&fil);
  307.     } else {
  308.         DisposeLineListContents(&ll);
  309.     }
  310.  
  311.     for (sdp = head; sdp != NULL; sdp = nextsdp) {
  312.         nextsdp = sdp->next;
  313.         free(sdp);
  314.     }
  315.  
  316.     return (rc);
  317. }    /* FTPFtwTraverse */
  318.  
  319.  
  320. int
  321. FTPFtw(const FTPCIPtr cip, const FtwInfoPtr ftwip, const char *const path, FtwProc proc)
  322. {
  323.     size_t len, alen;
  324.     int rc;
  325.     MLstItem mli;
  326.     char *cp, *endp;
  327.  
  328.     if (cip == NULL)
  329.         return (kErrBadParameter);
  330.     if (strcmp(cip->magic, kLibraryMagic))
  331.         return (kErrBadMagic);
  332.  
  333.     if ((ftwip->init != kFtwMagic) || (path == NULL) || (path[0] == '\0') || (proc == (FtwProc) 0)) {
  334.         cip->errNo = kErrBadParameter;
  335.         errno = EINVAL;
  336.         return (kErrBadParameter);
  337.     }
  338.  
  339.     ftwip->rlinkto = NULL;
  340.     ftwip->dirSeparator = '/';
  341.     ftwip->rootDir[0] = '/';
  342.     ftwip->startPathLen = 0;
  343.  
  344.     len = strlen(path);
  345.     if (ftwip->curPath == NULL) {
  346.         /* Call FtwSetBuf before calling Ftw for
  347.          * the first time, otherwise you get the
  348.          * default behavior.
  349.          */
  350.         ftwip->autoGrow = kFtwAutoGrow;
  351.         alen = len + 30 /* room to append filenames */ + 2 /* room for / and \0 */;
  352.         if (alen < 256)
  353.             alen = 256;
  354.         ftwip->curPath = (char *) malloc(alen);
  355.         if (ftwip->curPath == NULL)
  356.             return (-1);
  357.         ftwip->curPathAllocSize = alen - 2;
  358.     }
  359.  
  360.     ftwip->cip = (void *) cip;
  361.  
  362.     rc = FTPIsDir(cip, path);
  363.     if (rc < 0) {
  364.         /* error */
  365.         return rc;
  366.     } else if (rc == 0) {
  367.         rc = cip->errNo = kErrNotADirectory;
  368.         errno = ENOTDIR;
  369.         return (rc);
  370.     }
  371.     memset(&ftwip->curStat, 0, sizeof(ftwip->curStat));
  372.     ftwip->curStat.st_mode = (S_IFDIR | 00755);
  373.     ftwip->curType = 'd';
  374.     if (FTPMListOneFile(cip, path, &mli) == 0) {
  375.         ftwip->curStat.st_mtime = mli.ftime;
  376.         if (mli.mode != (-1)) {
  377.             ftwip->curStat.st_mode = S_IFDIR;
  378.             ftwip->curStat.st_mode |= (mli.mode & 00777);
  379.         }
  380.     } else {
  381.         (void) FTPFileModificationTime(cip, path, &ftwip->curStat.st_mtime);
  382.     }
  383.     ftwip->curStat.st_size = (longest_int) -1;
  384.  
  385.     memset(ftwip->curPath, 0, ftwip->curPathAllocSize);
  386.     memcpy(ftwip->curPath, path, len + 1);
  387.     endp = cp = ftwip->curPath + strlen(ftwip->curPath);
  388.     --cp;
  389.     while ((cp > ftwip->curPath) && ((*cp == '/') || (*cp == '\\')))
  390.         *cp-- = '\0';
  391.     ftwip->curPathLen = ftwip->startPathLen = len = (size_t) (endp - ftwip->curPath);
  392.     while (cp >= ftwip->curPath) {
  393.         if ((*cp == '/') || (*cp == '\\'))
  394.             break;
  395.         --cp;
  396.     }
  397.     ftwip->curFile = ++cp;
  398.     ftwip->curFileLen = (size_t) (endp - cp);
  399.     ftwip->proc = proc;
  400.     if ((*proc)(ftwip) < 0) {
  401.         return (-1);
  402.     }
  403.  
  404.     ftwip->depth = ftwip->maxDepth = ftwip->numDirs = ftwip->numFiles = ftwip->numLinks = 0;
  405.     rc = FTPFtwTraverse(ftwip, len, 1);
  406.  
  407.     /* Restore the start path when finished. */
  408.     memset(ftwip->curPath + ftwip->startPathLen, 0, ftwip->curPathAllocSize - ftwip->startPathLen);
  409.     ftwip->curPathLen = ftwip->startPathLen;
  410.  
  411.     /* Clear these out since you shouldn't be using them
  412.      * after Ftw returns.
  413.      */
  414.     memset(&ftwip->curStat, 0, sizeof(ftwip->curStat));
  415.     ftwip->proc = (FtwProc) 0;
  416.     ftwip->curFile = ftwip->curPath;
  417.     ftwip->curFileLen = 0;
  418.     ftwip->cip = 0;
  419.     ftwip->rlinkto = NULL;
  420.  
  421.     return (rc);
  422. }    /* FTPFtw */
  423.