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 >
Wrap
C/C++ Source or Header
|
2005-01-01
|
11KB
|
423 lines
/* rftw.c
*
* Copyright (c) 1996-2005 Mike Gleason, NcFTP Software.
* All rights reserved.
*
*/
#include "syshdrs.h"
#ifdef PRAGMA_HDRSTOP
# pragma hdrstop
#endif
/* Internal to rftw.c */
typedef struct FtwSubDirList *FtwSubDirListPtr;
typedef struct FtwSubDirList {
FtwSubDirListPtr next;
struct Stat st;
size_t fnLen;
char name[1];
} FtwSubDirList;
/* 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
FTPFtw(const FTPCIPtr cip, const FtwInfoPtr ftwip, const char *const path, FtwProc proc)
{
size_t len, alen;
int rc;
MLstItem mli;
char *cp, *endp;
if (cip == NULL)
return (kErrBadParameter);
if (strcmp(cip->magic, kLibraryMagic))
return (kErrBadMagic);
if ((ftwip->init != kFtwMagic) || (path == NULL) || (path[0] == '\0') || (proc == (FtwProc) 0)) {
cip->errNo = kErrBadParameter;
errno = EINVAL;
return (kErrBadParameter);
}
ftwip->rlinkto = NULL;
ftwip->dirSeparator = '/';
ftwip->rootDir[0] = '/';
ftwip->startPathLen = 0;
len = strlen(path);
if (ftwip->curPath == NULL) {
/* Call FtwSetBuf before calling Ftw for
* the first time, otherwise you get the
* default behavior.
*/
ftwip->autoGrow = kFtwAutoGrow;
alen = len + 30 /* room to append filenames */ + 2 /* room for / and \0 */;
if (alen < 256)
alen = 256;
ftwip->curPath = (char *) malloc(alen);
if (ftwip->curPath == NULL)
return (-1);
ftwip->curPathAllocSize = alen - 2;
}
ftwip->cip = (void *) cip;
rc = FTPIsDir(cip, path);
if (rc < 0) {
/* error */
return rc;
} else if (rc == 0) {
rc = cip->errNo = kErrNotADirectory;
errno = ENOTDIR;
return (rc);
}
memset(&ftwip->curStat, 0, sizeof(ftwip->curStat));
ftwip->curStat.st_mode = (S_IFDIR | 00755);
ftwip->curType = 'd';
if (FTPMListOneFile(cip, path, &mli) == 0) {
ftwip->curStat.st_mtime = mli.ftime;
if (mli.mode != (-1)) {
ftwip->curStat.st_mode = S_IFDIR;
ftwip->curStat.st_mode |= (mli.mode & 00777);
}
} else {
(void) FTPFileModificationTime(cip, path, &ftwip->curStat.st_mtime);
}
ftwip->curStat.st_size = (longest_int) -1;
memset(ftwip->curPath, 0, ftwip->curPathAllocSize);
memcpy(ftwip->curPath, path, len + 1);
endp = cp = ftwip->curPath + strlen(ftwip->curPath);
--cp;
while ((cp > ftwip->curPath) && ((*cp == '/') || (*cp == '\\')))
*cp-- = '\0';
ftwip->curPathLen = ftwip->startPathLen = len = (size_t) (endp - ftwip->curPath);
while (cp >= ftwip->curPath) {
if ((*cp == '/') || (*cp == '\\'))
break;
--cp;
}
ftwip->curFile = ++cp;
ftwip->curFileLen = (size_t) (endp - cp);
ftwip->proc = proc;
if ((*proc)(ftwip) < 0) {
return (-1);
}
ftwip->depth = ftwip->maxDepth = ftwip->numDirs = ftwip->numFiles = ftwip->numLinks = 0;
rc = FTPFtwTraverse(ftwip, len, 1);
/* Restore the start path when finished. */
memset(ftwip->curPath + ftwip->startPathLen, 0, ftwip->curPathAllocSize - ftwip->startPathLen);
ftwip->curPathLen = ftwip->startPathLen;
/* Clear these out since you shouldn't be using them
* after Ftw returns.
*/
memset(&ftwip->curStat, 0, sizeof(ftwip->curStat));
ftwip->proc = (FtwProc) 0;
ftwip->curFile = ftwip->curPath;
ftwip->curFileLen = 0;
ftwip->cip = 0;
ftwip->rlinkto = NULL;
return (rc);
} /* FTPFtw */