/* Deletes an item from the ls cache. */ static void FlushLsCacheItem(int i) { Trace(1, "flush ls cache item: %s\n", gLsCache[i].itempath); if (gLsCache[i].itempath != NULL) free(gLsCache[i].itempath); gLsCache[i].itempath = NULL; gLsCache[i].expiration = (time_t) 0; DisposeFileInfoListContents(&gLsCache[i].fil); } /* FlushLsCacheItem */
/* This mess is essentially the local version of Ftw with FTP * grafted onto it, so see that and grok that before studying this. */ static int FTPFtwTraverse(const FtwInfoPtr ftwip, size_t dirPathLen, int depth) { char *cp; size_t fnLen; mode_t m; char *filename; char *newBuf; char *path = ftwip->curPath; int nSubdirs; FtwSubDirListPtr head = NULL, tail = NULL, sdp, nextsdp; int rc = (-1); int lsl, mls, unlsrc; FTPCIPtr cip = (FTPCIPtr) ftwip->cip; FTPLineList ll; FTPFileInfoList fil; FTPLinePtr filePtr; FTPFileInfoPtr fip; int result; int isRootDir; longest_int sz; isRootDir = ((dirPathLen == 1) && ((path[0] == '/') || (path[0] == '\\'))) ? 1 : 0; filePtr = NULL; fip = NULL; mls = 0; lsl = 0; if (cip->hasMLSD == kCommandAvailable) { mls = 1; if (((result = FTPListToMemory2(cip, dirPathLen ? path : ".", &ll, "-a", 0, &mls)) < 0) || (ll.first == NULL)) { /* Not an error unless the first directory could not be opened. */ DisposeLineListContents(&ll); return (0); } /* "MLSD" succeeded */ unlsrc = UnMlsD(cip, &fil, &ll); if (unlsrc < 0) { DisposeLineListContents(&ll); return (cip->errNo = kErrInvalidMLSTResponse); } else if (unlsrc == 0) { /* empty */ DisposeLineListContents(&ll); return (0); } fip = fil.first; DisposeLineListContents(&ll); } else { if (((result = FTPListToMemory2(cip, dirPathLen ? path : ".", &ll, "-la", 0, &mls)) < 0) || (ll.first == NULL)) { DisposeLineListContents(&ll); if (((result = FTPListToMemory2(cip, dirPathLen ? path : ".", &ll, (cip->hasNLST_a == kCommandNotAvailable) ? "" : "-a", 0, &mls)) < 0) || (ll.first == NULL)) { DisposeLineListContents(&ll); return (0); } else { /* "NLST -a" succeeded */ RemoteGlobCollapse(cip, path, &ll); filePtr = ll.first; } } else { /* "LIST -a" succeeded */ lsl = 1; unlsrc = UnLslR(cip, &fil, &ll, cip->serverType); if (unlsrc < 0) { DisposeLineListContents(&ll); return (cip->errNo = kErrInvalidMLSTResponse); } else if (unlsrc == 0) { /* empty */ DisposeLineListContents(&ll); return (0); } fip = fil.first; DisposeLineListContents(&ll); } } nSubdirs = 0; ++ftwip->numDirs; ftwip->depth = depth; if (ftwip->maxDepth < ftwip->depth) { ftwip->maxDepth = ftwip->depth; } filename = path + dirPathLen; if (isRootDir == 0) { /* Root directory is a separator. */ *filename++ = (char) ftwip->dirSeparator; dirPathLen++; } *filename = '\0'; /* Path now contains dir/ */ for (;;) { if ((mls != 0) || (lsl != 0)) { if (fip == NULL) break; cp = fip->relname; } else { if (filePtr == NULL) break; cp = filePtr->line; } if ((cp[0] == '.') && ((cp[1] == '\0') || ((cp[1] == '.') && (cp[2] == '\0')))) goto nxt; /* Skip . and .. */ ftwip->rlinkto = NULL; *filename = '\0'; fnLen = strlen(cp) + 1 /* include \0 */; if ((fnLen + dirPathLen) > ftwip->curPathAllocSize) { if (ftwip->autoGrow == kFtwNoAutoGrowAndFail) { goto panic; } else if (ftwip->autoGrow == kFtwNoAutoGrowButContinue) { goto nxt; } newBuf = (char *) realloc(ftwip->curPath, fnLen + dirPathLen + 30 + 2 /* room for / and \0 */); if (newBuf == NULL) goto panic; ftwip->curPath = newBuf; ftwip->curPathAllocSize = fnLen + dirPathLen + 30; path = ftwip->curPath; filename = path + dirPathLen; if (isRootDir == 0) /* Root directory is a separator. */ *filename++ = (char) ftwip->dirSeparator; *filename = '\0'; } memcpy(filename, cp, fnLen); ftwip->curPathLen = dirPathLen + fnLen - 1; ftwip->curFile = filename; ftwip->curFileLen = fnLen - 1; memset(&ftwip->curStat, 0, sizeof(ftwip->curStat)); if (mls != 0) { ftwip->curType = fip->type; if (fip->type == 'd') { ftwip->curStat.st_mode = S_IFDIR; ftwip->curStat.st_size = (longest_int) -1; #ifdef S_IFLNK } else if (fip->type == 'l') { ftwip->curStat.st_mode = S_IFLNK; ftwip->rlinkto = fip->rlinkto; #endif } else if (fip->type == '-') { ftwip->curStat.st_mode = S_IFREG; ftwip->curStat.st_size = fip->size; } else { /* unknown type, skip */ goto nxt; } if (fip->mode != (-1)) ftwip->curStat.st_mode |= (fip->mode & 00777); ftwip->curStat.st_mtime = fip->mdtm; } else if (lsl != 0) { ftwip->curType = fip->type; if (fip->type == 'd') { ftwip->curStat.st_mode = S_IFDIR; ftwip->curStat.st_size = (longest_int) -1; #ifdef S_IFLNK } else if (fip->type == 'l') { ftwip->curStat.st_mode = S_IFLNK; ftwip->rlinkto = fip->rlinkto; #endif } else if (fip->type == '-') { ftwip->curStat.st_mode = S_IFREG; ftwip->curStat.st_size = fip->size; } else { /* unknown type, skip */ goto nxt; } if (fip->mode != (-1)) ftwip->curStat.st_mode |= (fip->mode & 00777); ftwip->curStat.st_mtime = fip->mdtm; /* Override local times in LS output! */ result = FTPFileModificationTime(cip, path, &fip->mdtm); if (fip->mdtm != kModTimeUnknown) { ftwip->curStat.st_mtime = fip->mdtm; } } else { result = FTPIsDir(cip, path); if (result < 0) { /* error */ /* could be just a stat error, so continue */ goto nxt; } else if (result == 1) { /* directory */ ftwip->curType = 'd'; ftwip->curStat.st_mode = S_IFDIR | 00755; result = FTPFileModificationTime(cip, path, &ftwip->curStat.st_mtime); } else { /* file */ ftwip->curType = '-'; ftwip->curStat.st_mode = S_IFREG | 00644; result = FTPFileSizeAndModificationTime(cip, path, &sz, kTypeBinary, &ftwip->curStat.st_mtime); #if defined(TRU64UNIX) || defined(DIGITAL_UNIX) ftwip->curStat.st_size = (off_t) sz; #else ftwip->curStat.st_size = sz; #endif } } { m = ftwip->curStat.st_mode; if (S_ISREG(m)) { ++ftwip->numFiles; ftwip->curType = '-'; if ((*ftwip->proc)(ftwip) < 0) { goto panic; } } else if (S_ISLNK(m)) { ++ftwip->numLinks; ftwip->curType = 'l'; if ((*ftwip->proc)(ftwip) < 0) { goto panic; } } else if (S_ISDIR(m)) { /* We delay entering the subdirectories * until we have closed this directory. * This will conserve file descriptors * and also have the effect of having * the files processed first. */ sdp = (FtwSubDirListPtr) malloc(sizeof(FtwSubDirList) + fnLen); if (sdp == NULL) goto panic; memcpy(&sdp->st, &ftwip->curStat, sizeof(sdp->st)); memcpy(sdp->name, cp, fnLen); sdp->fnLen = fnLen; sdp->next = NULL; if (head == NULL) { head = tail = sdp; } else { tail->next = sdp; tail = sdp; } nSubdirs++; } } nxt: if ((mls != 0) || (lsl != 0)) { fip = fip->next; } else { filePtr = filePtr->next; } } if ((mls != 0) || (lsl != 0)) { DisposeFileInfoListContents(&fil); } else { DisposeLineListContents(&ll); } /* Now enter each subdirectory. */ for (sdp = head; sdp != NULL; sdp = nextsdp) { nextsdp = sdp->next; memcpy(&ftwip->curStat, &sdp->st, sizeof(ftwip->curStat)); fnLen = sdp->fnLen; memcpy(filename, sdp->name, fnLen); ftwip->curFile = filename; ftwip->curFileLen = fnLen - 1; ftwip->curPathLen = dirPathLen + fnLen - 1; head = nextsdp; free(sdp); ftwip->curType = 'd'; if ((*ftwip->proc)(ftwip) < 0) { goto panic; } if (FTPFtwTraverse(ftwip, dirPathLen + fnLen - 1, depth + 1) < 0) goto panic; /* Reset these, since buffer could have * been reallocated. */ path = ftwip->curPath; filename = path + dirPathLen; *filename = '\0'; } head = NULL; rc = 0; panic: if (mls != 0) { DisposeFileInfoListContents(&fil); } else { DisposeLineListContents(&ll); } for (sdp = head; sdp != NULL; sdp = nextsdp) { nextsdp = sdp->next; free(sdp); } return (rc); } /* FTPFtwTraverse */
int FTPPutFiles3( const FTPCIPtr cip, const char *const pattern, const char *const dstdir1, const int recurse, const int doGlob, const int xtype, int appendflag, const char *const tmppfx, const char *const tmpsfx, const int resumeflag, const int deleteflag, const FTPConfirmResumeUploadProc resumeProc, int UNUSED(reserved)) { FTPLineList globList; FTPFileInfoList files; FTPFileInfoPtr filePtr; int batchResult; int result; const char *dstdir; char dstdir2[512]; LIBNCFTP_USE_VAR(reserved); if (cip == NULL) return (kErrBadParameter); if (strcmp(cip->magic, kLibraryMagic)) return (kErrBadMagic); if (dstdir1 == NULL) { dstdir = NULL; } else { dstdir = STRNCPY(dstdir2, dstdir1); StrRemoveTrailingLocalPathDelim(dstdir2); } (void) FTPLocalGlob(cip, &globList, pattern, doGlob); if (recurse == kRecursiveYes) { appendflag = kAppendNo; (void) FTPLocalRecursiveFileList(cip, &globList, &files); if (files.first == NULL) { cip->errNo = kErrNoValidFilesSpecified; return (kErrNoValidFilesSpecified); } (void) ComputeRNames(&files, dstdir, 0, 1); } else { (void) LineListToFileInfoList(&globList, &files); (void) ComputeLNames(&files, NULL, NULL, 1); (void) ComputeRNames(&files, dstdir, 0, 0); } DisposeLineListContents(&globList); #if 0 for (filePtr = files.first; filePtr != NULL; filePtr = filePtr->next) { PrintF(cip, " R=%s, L=%s, 2=%s, size=%lld, mdtm=%u, type=%c\n", filePtr->rname, filePtr->lname, filePtr->rlinkto ? filePtr->rlinkto : "", filePtr->size, (unsigned int) filePtr->mdtm, filePtr->type ); } #endif batchResult = kNoErr; for (filePtr = files.first; filePtr != NULL; filePtr = filePtr->next) { if (cip->connected == 0) { if (batchResult == kNoErr) batchResult = kErrRemoteHostClosedConnection; break; } if (filePtr->type == 'd') { /* mkdir */ StrRemoveTrailingLocalPathDelim(filePtr->rname); result = FTPMkdir(cip, filePtr->rname, kRecursiveNo); if (result != kNoErr) batchResult = result; #ifdef HAVE_SYMLINK } else if (filePtr->type == 'l') { /* symlink */ /* no RFC way to create the link, though. */ if ((filePtr->rlinkto != NULL) && (filePtr->rlinkto[0] != '\0')) (void) FTPSymlink(cip, filePtr->rname, filePtr->rlinkto); #endif } else if (recurse != kRecursiveYes) { result = FTPPutOneF(cip, filePtr->lname, filePtr->rname, xtype, -1, appendflag, tmppfx, tmpsfx, resumeflag, deleteflag, resumeProc); if (files.nFileInfos == 1) { if (result != kNoErr) batchResult = result; } else { if ((result != kNoErr) && (result != kErrLocalFileNewer) && (result != kErrRemoteFileNewer) && (result != kErrRemoteSameAsLocal)) batchResult = result; } if (result == kErrUserCanceled) cip->cancelXfer = 1; if (cip->cancelXfer > 0) break; } else { result = FTPPutOneF(cip, filePtr->lname, filePtr->rname, xtype, -1, appendflag, tmppfx, tmpsfx, resumeflag, deleteflag, resumeProc); if (files.nFileInfos == 1) { if (result != kNoErr) batchResult = result; } else { if ((result != kNoErr) && (result != kErrLocalFileNewer) && (result != kErrRemoteFileNewer) && (result != kErrRemoteSameAsLocal)) batchResult = result; } if (result == kErrUserCanceled) cip->cancelXfer = 1; if (cip->cancelXfer > 0) break; } } DisposeFileInfoListContents(&files); if (batchResult < 0) cip->errNo = batchResult; return (batchResult); } /* FTPPutFiles3 */