/* View one or more remote files through your pager. */ int CatCmd(int argc, char **argv) { int i, result, errs; LineList globFiles; LinePtr globFile; MultiLineInit(); for (i=1, errs=0; i<argc; i++) { InitLineList(&globFiles); RemoteGlob(&globFiles, argv[i], kListNoFlags); for (globFile = globFiles.first; globFile != NULL; globFile = globFile->next) { result = DoCat(globFile->line); if (result < 0) --errs; if (gXferAbortFlag == SIGINT) break; /* Don't get rest of files if you interrupted. */ if (argc > 2) MultiLinePrintF("### End of file %s ###\n", globFile->line); } DisposeLineListContents(&globFiles); } return (errs); } /* CatCmd */
/* May need this later. */ static void CheckForLS_d(FTPCIPtr cip) { FTPLineList lines; char *cp; if (cip->hasNLST_d == kCommandAvailabilityUnknown) { if (FTPListToMemory2(cip, ".", &lines, "-d ", 0, (int *) 0) == kNoErr) { if ((lines.first != NULL) && (lines.first == lines.last)) { /* If we have only one item in the list, see if it really was * an error message we would recognize. */ cp = strchr(lines.first->line, ':'); if ((cp != NULL) && STREQ(cp, ": No such file or directory")) { cip->hasNLST_d = kCommandNotAvailable; } else { cip->hasNLST_d = kCommandAvailable; } } else { cip->hasNLST_d = kCommandNotAvailable; } } else { cip->hasNLST_d = kCommandNotAvailable; } DisposeLineListContents(&lines); } } /* CheckForLS_d */
int DoGetWithGlobbingAndRecursion(GetOptionsPtr gopt) { int err; LineList globFiles; LinePtr globFile; char *cp; int fType; int result; longstring rcwd; err = 0; InitLineList(&globFiles); RemoteGlob(&globFiles, gopt->rName, kListNoFlags); for (globFile = globFiles.first; globFile != NULL; globFile = globFile->next) { if (gXferAbortFlag == SIGINT) break; /* Don't get rest of files if you interrupted. */ if (gopt->recursive) { fType = RemoteFileType(globFile->line); if (fType == 'd') { if ((cp = strrchr(globFile->line, '/')) != NULL) { /* If the user said something like * "get -R /pub/a/b/c/d" we want to just write the * contents of the 'd' as a subdirectory of the local * directory, and not create ./pub, ./pub/a, etc. */ STRNCPY(rcwd, gRemoteCWD); *cp++ = '\0'; if (DoChdir(globFile->line) == 0) { GetDir(gopt, cp, gRemoteCWD, gLocalCWD); } /* Restore the directory we were in before. */ (void) DoChdir(rcwd); } else { /* Otherwise, the user gave a simple path, so it was * something like "get -R pub" */ GetDir(gopt, globFile->line, gRemoteCWD, gLocalCWD); } } else if (fType == 'l') { EPrintF("Ignoring symbolic link '%s'\n", globFile->line); } else if (fType == '-') { goto regFile; } } else { regFile: gopt->rName = globFile->line; gopt->lName = NULL; /* Make it later. */ result = DoGet(gopt); if (result < 0) err = -1; } } DisposeLineListContents(&globFiles); return (err); } /* DoGetWithGlobbingAndRecursion */
static int GetSymLinkInfo(char *dst, size_t siz, char *rLink) { LineList fileList; char *cp; int result; result = -1; *dst = '\0'; InitLineList(&fileList); ListToMemory(&fileList, "LIST", kListDirNamesOnlyMode, rLink); if (fileList.first != NULL) { cp = fileList.first->line; *cp++ = '\0'; for (cp += strlen(cp) - 1; ; cp--) { if (*cp == '\0') goto done; if ((cp[0] == '>') && (cp[-1] == '-')) break; } (void) Strncpy(dst, cp + 2, siz); result = 0; } done: DisposeLineListContents(&fileList); return (result); } /* GetSymLinkInfo */
int FTPDelete(const FTPCIPtr cip, const char *const pattern, const int recurse, const int doGlob) { FTPLineList fileList; FTPLinePtr filePtr; char *file; int onceResult, batchResult; if (cip == NULL) return (kErrBadParameter); if (strcmp(cip->magic, kLibraryMagic)) return (kErrBadMagic); batchResult = FTPRemoteGlob(cip, &fileList, pattern, doGlob); if (batchResult != kNoErr) return (batchResult); for (batchResult = kNoErr, filePtr = fileList.first; filePtr != NULL; filePtr = filePtr->next) { file = filePtr->line; if (file == NULL) { batchResult = kErrBadLineList; cip->errNo = kErrBadLineList; break; } onceResult = FTPCmd(cip, "DELE %s", file); if (onceResult < 0) { batchResult = onceResult; break; } if (onceResult != 2) { if (recurse != kRecursiveYes) { batchResult = kErrDELEFailed; cip->errNo = kErrDELEFailed; } else { onceResult = FTPCmd(cip, "RMD %s", file); if (onceResult < 0) { batchResult = onceResult; break; } if (onceResult != 2) { onceResult = FTPRmdirRecursive(cip, file); if (onceResult < 0) { batchResult = kErrRMDFailed; cip->errNo = kErrRMDFailed; } } } } } DisposeLineListContents(&fileList); return (batchResult); } /* FTPDelete */
/* View one or more remote files through your pager. */ int PageCmd(int argc, char **argv) { int i, result, errs; LineList globFiles; LinePtr globFile; char *pagerProg; if (STREQ(argv[1], "-b") && (gWinInit > 0) && (argc > 2)) { /* A hack to let you use the built-in pager like you * can with the lpage command. */ pagerProg = NULL; /* Use built-in */ i = 2; } else { if (gPager[0] == '\0') { EPrintF("You haven't specified a program to use as a pager.\n"); EPrintF("You can set this from the preferences screen (prefs command).\n"); return -1; } pagerProg = gPager; i = 1; } for (errs=0; i<argc; i++) { InitLineList(&globFiles); RemoteGlob(&globFiles, argv[i], kListNoFlags); for (globFile = globFiles.first; globFile != NULL; globFile = globFile->next) { if (pagerProg == NULL) result = DoCat(globFile->line); else result = DoPage(globFile->line); if (result < 0) --errs; if (gXferAbortFlag == SIGINT) break; /* Don't get rest of files if you interrupted. */ } DisposeLineListContents(&globFiles); } return (errs); } /* PageCmd */
int RGlobCmd(int argc, char **argv) { LineList globFiles; LinePtr globFile; int i; MultiLineInit(); for (i=1; i<argc; i++) { InitLineList(&globFiles); RemoteGlob(&globFiles, argv[i], kListNoFlags); for (globFile = globFiles.first; globFile != NULL; globFile = globFile->next) { MultiLinePrintF("%s\n", globFile->line); } DisposeLineListContents(&globFiles); } return (0); } /* RGlobCmd */
int FTPChmod(const FTPCIPtr cip, const char *const pattern, const char *const mode, const int doGlob) { FTPLineList fileList; FTPLinePtr filePtr; char *file; int onceResult, batchResult; if (cip == NULL) return (kErrBadParameter); if (strcmp(cip->magic, kLibraryMagic)) return (kErrBadMagic); batchResult = FTPRemoteGlob(cip, &fileList, pattern, doGlob); if (batchResult != kNoErr) return (batchResult); for (batchResult = kNoErr, filePtr = fileList.first; filePtr != NULL; filePtr = filePtr->next) { file = filePtr->line; if (file == NULL) { batchResult = kErrBadLineList; cip->errNo = kErrBadLineList; break; } onceResult = FTPCmd(cip, "SITE CHMOD %s %s", mode, file); if (onceResult < 0) { batchResult = onceResult; break; } if (onceResult != 2) { batchResult = kErrChmodFailed; cip->errNo = kErrChmodFailed; } } DisposeLineListContents(&fileList); return (batchResult); } /* FTPChmod */
int RemoteFileType(char *fName) { LineList fileList; char *cp; int result; int i; result = 0; InitLineList(&fileList); ListToMemory(&fileList, "LIST", kListDirNamesOnlyMode, fName); if (fileList.first != NULL) { cp = fileList.first->line; /* Do a quick check and see if it looks like a unix ls line. */ for (i=1; i<=3; i++) if ((cp[i] != 'r') && (cp[i] != 'w') && (cp[i] != 'x') && (cp[i] != '-')) goto done; result = (int) cp[0]; } done: DisposeLineListContents(&fileList); return (result); } /* RemoteFileType */
static void FTPDeallocateHost(const FTPCIPtr cip) { /* Requires the cip->bufSize field set, * and the cip->buf set if the * buffer is allocated. */ if (cip->buf != NULL) { (void) memset(cip->buf, 0, cip->bufSize); free(cip->buf); cip->buf = NULL; } if (cip->startingWorkingDirectory != NULL) { free(cip->startingWorkingDirectory); cip->startingWorkingDirectory = NULL; } #if USE_SIO DisposeSReadlineInfo(&cip->ctrlSrl); #endif DisposeLineListContents(&cip->lastFTPCmdResultLL); } /* FTPDeallocateHost */
/* 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 FTPRemoteGlob(FTPCIPtr cip, FTPLineListPtr fileList, const char *pattern, int doGlob) { char *cp; const char *lsflags; FTPLinePtr lp; int result; if (cip == NULL) return (kErrBadParameter); if (strcmp(cip->magic, kLibraryMagic)) return (kErrBadMagic); if (fileList == NULL) return (kErrBadParameter); InitLineList(fileList); if ((pattern == NULL) || (pattern[0] == '\0')) return (kErrBadParameter); /* Note that we do attempt to use glob characters even if the remote * host isn't UNIX. Most non-UNIX remote FTP servers look for UNIX * style wildcards. */ if ((doGlob == 1) && (GLOBCHARSINSTR(pattern))) { /* Use NLST, which lists files one per line. */ lsflags = ""; /* Optimize for "NLST *" case which is same as "NLST". */ if (strcmp(pattern, "*") == 0) { pattern = ""; lsflags = (cip->hasNLST_a == kCommandNotAvailable) ? "" : "-a"; } else if (strcmp(pattern, "**") == 0) { /* Hack; Lets you try "NLST -a" if you're daring. */ /* Need to use "NLST -a" whenever possible, * because wu-ftpd doesn't do NLST right, IMHO. * (It doesn't include directories in the NLST * if you do "NLST /the/dir" without -a.) */ pattern = ""; lsflags = (cip->hasNLST_a == kCommandNotAvailable) ? "" : "-a"; } if ((result = FTPListToMemory2(cip, pattern, fileList, lsflags, 0, (int *) 0)) < 0) { if (*lsflags == '\0') return (result); if (strchr(lsflags, 'a') != NULL) { /* Try again, without "-a" */ cip->hasNLST_a = kCommandNotAvailable; lsflags = ""; if ((result = FTPListToMemory2(cip, pattern, fileList, lsflags, 0, (int *) 0)) < 0) { return (result); } /* else proceed */ } else { return (result); } } #if 0 DisposeLineListContents(fileList); InitLineList(fileList); AddLine(fileList, "../FAKEME1.txt"); AddLine(fileList, "../../FAKEME2.txt"); AddLine(fileList, "..\\FAKEME3.txt"); AddLine(fileList, "..\\..\\FAKEME4.txt"); AddLine(fileList, "...\\FAKEME5.txt"); AddLine(fileList, "/tmp/bad/FAKEME6.txt"); AddLine(fileList, "c:\\temp\\FAKEME7.txt"); AddLine(fileList, "foo/../FAKEME8.txt"); AddLine(fileList, "foo\\bar\\...\\FAKEME9.txt"); #endif if (fileList->first == NULL) { cip->errNo = kErrGlobNoMatch; return (kErrGlobNoMatch); } if (fileList->first == fileList->last) { #define glberr(a) (ISTRNEQ(cp, a, strlen(a))) /* If we have only one item in the list, see if it really was * an error message we would recognize. */ cp = strchr(fileList->first->line, ':'); if (cp != NULL) { if (glberr(": No such file or directory")) { (void) RemoveLine(fileList, fileList->first); cip->errNo = kErrGlobFailed; return (kErrGlobFailed); } else if (glberr(": No match")) { cip->errNo = kErrGlobNoMatch; return (kErrGlobNoMatch); } } } StripUnneccesaryGlobEntries(cip, fileList); RemoteGlobCollapse(cip, pattern, fileList); for (lp=fileList->first; lp != NULL; lp = lp->next) PrintF(cip, " Rglob [%s]\n", lp->line); } else { /* Or, if there were no globbing characters in 'pattern', then the * pattern is really just a filename. So for this case the * file list is really just a single file. */ fileList->first = fileList->last = NULL; (void) AddLine(fileList, pattern); } return (kNoErr); } /* FTPRemoteGlob */
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 */
int GetDir(GetOptionsPtr gopt, char *dName, char *rRoot, char *lRoot) { LineList dirFiles; LinePtr dirFile; char *rd; /* Remote directory path. */ char *ld; /* Local directory path. */ char *rf; /* Complete remote pathname for an item. */ char *lf; /* Complete local pathname for an item. */ char *sl; /* What a symlink points to. */ char *iName; int fType; rd = NULL; ld = NULL; rf = NULL; lf = NULL; if ((rd = StrDup(rRoot)) == NULL) goto fail; if ((rd = PtrCatSlash(rd, dName)) == NULL) goto fail; if ((ld = StrDup(lRoot)) == NULL) goto fail; if ((ld = PtrCatSlash(ld, dName)) == NULL) goto fail; /* Create this directory on the local host first. */ if (MkDirs(ld)) { EPrintF("Could not create directory '%s.'\n", ld); goto fail; } /* Get the names of all files and subdirs. */ InitLineList(&dirFiles); GetFileList(&dirFiles, rd); /* Get all the files first. */ for (dirFile = dirFiles.first; dirFile != NULL; dirFile = dirFile->next) { fType = (int) dirFile->line[0]; if ((fType == '-') || (fType == 'l')) { iName = dirFile->line + 1; if ((rf = StrDup(rd)) == NULL) goto fail; if ((rf = PtrCatSlash(rf, iName)) == NULL) goto fail; if ((lf = StrDup(ld)) == NULL) goto fail; if ((lf = PtrCatSlash(lf, iName)) == NULL) goto fail; if (fType == '-') { gopt->rName = rf; gopt->lName = lf; DoGet(gopt); } else { #ifdef HAVE_SYMLINK sl = (char *) malloc(SZ(512)); if (sl != NULL) { if (GetSymLinkInfo(sl, SZ(512), rf) == 0) (void) symlink(sl, lf); free(sl); } #endif /* HAVE_SYMLINK */ } free(rf); free(lf); rf = NULL; lf = NULL; } if (gXferAbortFlag == SIGINT) break; /* Don't get rest of files if you interrupted. */ } /* Now get subdirectories. */ for (dirFile = dirFiles.first; dirFile != NULL; dirFile = dirFile->next) { if (gXferAbortFlag == SIGINT) break; /* Don't get rest of files if you interrupted. */ fType = (int) dirFile->line[0]; if (fType == 'd') { iName = dirFile->line + 1; if (GetDir(gopt, iName, rd, ld) < 0) break; } } free(ld); free(rd); DisposeLineListContents(&dirFiles); return (0); fail: if (rd != NULL) free(rd); if (ld != NULL) free(ld); if (rf != NULL) free(rf); if (lf != NULL) free(lf); return (-1); } /* GetDir */