Beispiel #1
0
/* 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 */
Beispiel #2
0
/* 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 */
Beispiel #3
0
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 */