📄 glob.c
字号:
#else
static void
Traverse(FTPCIPtr cip, char *fullpath, struct Stat *st, char *relpath, FileInfoListPtr filp)
{
char *dname;
struct dirent *dirp;
mode_t m;
DIR *dp;
char *cp;
char *c2;
FileInfo fi;
if (relpath[0] != '\0') {
fi.relname = StrDup(relpath);
fi.rname = NULL;
fi.lname = StrDup(fullpath);
fi.rlinkto = NULL;
fi.plug = NULL;
fi.mdtm = st->st_mtime;
fi.size = (longest_int) st->st_size;
fi.type = 'd';
(void) AddFileInfo(filp, &fi);
}
/* Handle directory entry first. */
cp = fullpath + strlen(fullpath);
*cp++ = '/';
*cp = '\0';
c2 = relpath + strlen(relpath);
*c2++ = '/';
*c2 = '\0';
if ((dp = opendir(fullpath)) == NULL) {
cp[-1] = '\0';
c2[-1] = '\0';
Error(cip, kDoPerror, "could not opendir %s.\n", fullpath);
return;
}
while ((dirp = readdir(dp)) != NULL) {
dname = dirp->d_name;
if ((dname[0] == '.') && ((dname[1] == '\0') || ((dname[1] == '.') && (dname[2] == '\0'))))
continue; /* skip "." and ".." directories. */
(void) strcpy(cp, dirp->d_name); /* append name after slash */
(void) strcpy(c2, dirp->d_name);
if (Lstat(fullpath, st) < 0) {
Error(cip, kDoPerror, "could not stat %s.\n", fullpath);
continue;
}
fi.relname = StrDup(relpath + (((relpath[0] == '/') || (relpath[0] == '\\')) ? 1 : 0));
fi.rname = NULL;
fi.lname = StrDup(fullpath);
fi.mdtm = st->st_mtime;
fi.size = (longest_int) st->st_size;
fi.rlinkto = NULL;
fi.plug = NULL;
m = st->st_mode;
if (S_ISREG(m) != 0) {
/* file */
fi.type = '-';
(void) AddFileInfo(filp, &fi);
} else if (S_ISDIR(m)) {
Traverse(cip, fullpath, st, relpath, filp);
#ifdef S_ISLNK
} else if (S_ISLNK(m)) {
fi.type = 'l';
fi.rlinkto = calloc(128, 1);
if (fi.rlinkto != NULL) {
if (readlink(fullpath, fi.rlinkto, 127) < 0) {
free(fi.rlinkto);
} else {
(void) AddFileInfo(filp, &fi);
}
}
#endif /* S_ISLNK */
}
}
cp[-1] = '\0';
c2[-1] = '\0';
(void) closedir(dp);
} /* Traverse */
#endif
int
FTPLocalRecursiveFileList2(FTPCIPtr cip, LineListPtr fileList, FileInfoListPtr files, int erelative)
{
LinePtr filePtr, nextFilePtr;
#if defined(WIN32) || defined(_WINDOWS)
char fullpath[_MAX_PATH + 1];
char relpath[_MAX_PATH + 1];
#else
char fullpath[512];
char relpath[512];
#endif
struct Stat st;
FileInfo fi;
char *cp;
InitFileInfoList(files);
for (filePtr = fileList->first;
filePtr != NULL;
filePtr = nextFilePtr)
{
nextFilePtr = filePtr->next;
(void) STRNCPY(fullpath, filePtr->line); /* initialize fullpath */
if ((erelative != 0) || (strcmp(filePtr->line, ".") == 0) || (filePtr->line[0] == '\0'))
(void) STRNCPY(relpath, "");
else if ((cp = StrRFindLocalPathDelim(filePtr->line)) == NULL)
(void) STRNCPY(relpath, filePtr->line);
else
(void) STRNCPY(relpath, cp + 1);
if (Lstat(fullpath, &st) < 0) {
Error(cip, kDoPerror, "could not stat %s.\n", fullpath);
continue;
}
if (S_ISDIR(st.st_mode) == 0) {
fi.relname = StrDup(relpath);
fi.rname = NULL;
fi.lname = StrDup(fullpath);
fi.mdtm = st.st_mtime;
fi.size = (longest_int) st.st_size;
fi.rlinkto = NULL;
fi.plug = NULL;
fi.type = '-';
(void) AddFileInfo(files, &fi);
continue; /* wasn't a directory */
}
/* Paths collected must be relative. */
Traverse(cip, fullpath, &st, relpath, files);
}
return (kNoErr);
} /* FTPLocalRecursiveFileList */
int
FTPLocalRecursiveFileList(FTPCIPtr cip, LineListPtr fileList, FileInfoListPtr files)
{
return (FTPLocalRecursiveFileList2(cip, fileList, files, 0));
} /* FTPLocalRecursiveFileList */
int
FTPRemoteGlob(FTPCIPtr cip, LineListPtr fileList, const char *pattern, int doGlob)
{
char *cp;
const char *lsflags;
LinePtr 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 = "";
} else if (strcmp(pattern, "**") == 0) {
/* Hack; Lets you try "NLST -a" if you're daring. */
pattern = "";
lsflags = "-a";
}
if ((result = FTPListToMemory2(cip, pattern, fileList, lsflags, 0, (int *) 0)) < 0) {
if (*lsflags == '\0')
return (result);
/* Try again, without "-a" */
lsflags = "";
if ((result = FTPListToMemory2(cip, pattern, fileList, lsflags, 0, (int *) 0)) < 0) {
return (result);
}
}
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);
}
}
}
RemoteGlobCollapse(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 */
/* This does "tilde-expansion." Examples:
* ~/pub --> /usr/gleason/pub
* ~pdietz/junk --> /usr/pdietz/junk
*/
static void
ExpandTilde(char *pattern, size_t siz)
{
string pat;
char *cp, *rest, *firstent;
#if defined(WIN32) || defined(_WINDOWS)
#else
struct passwd *pw;
#endif
string hdir;
if ((pattern[0] == '~') &&
(isalnum((int) pattern[1]) || IsLocalPathDelim(pattern[1]) || (pattern[1] == '\0'))) {
(void) STRNCPY(pat, pattern);
if ((cp = StrFindLocalPathDelim(pat)) != NULL) {
*cp = 0;
rest = cp + 1; /* Remember stuff after the ~/ part. */
} else {
rest = NULL; /* Was just a ~ or ~username. */
}
if (pat[1] == '\0') {
/* Was just a ~ or ~/rest type. */
GetHomeDir(hdir, sizeof(hdir));
firstent = hdir;
} else {
#if defined(WIN32) || defined(_WINDOWS)
return;
#else
/* Was just a ~username or ~username/rest type. */
pw = getpwnam(pat + 1);
if (pw != NULL)
firstent = pw->pw_dir;
else
return; /* Bad user -- leave it alone. */
#endif
}
(void) Strncpy(pattern, firstent, siz);
if (rest != NULL) {
(void) Strncat(pattern, LOCAL_PATH_DELIM_STR, siz);
(void) Strncat(pattern, rest, siz);
}
}
} /* ExpandTilde */
#if defined(WIN32) || defined(_WINDOWS)
static int
WinLocalGlob(FTPCIPtr cip, LineListPtr fileList, const char *const srcpat)
{
char pattern[_MAX_PATH];
WIN32_FIND_DATA ffd;
HANDLE searchHandle;
DWORD dwErr;
char *cp;
const char *file;
int result;
STRNCPY(pattern, srcpat);
/* Get rid of trailing slashes. */
cp = pattern + strlen(pattern) - 1;
while ((cp >= pattern) && IsLocalPathDelim(*cp))
*cp-- = '\0';
memset(&ffd, 0, sizeof(ffd));
/* "Open" the directory. */
searchHandle = FindFirstFile(pattern, &ffd);
if (searchHandle == INVALID_HANDLE_VALUE) {
dwErr = GetLastError();
return ((dwErr == 0) ? 0 : -1);
}
/* Get rid of basename. */
cp = StrRFindLocalPathDelim(pattern);
if (cp == NULL)
cp = pattern;
else
cp++;
*cp = '\0';
for (result = 0;;) {
file = ffd.cFileName;
if ((file[0] == '.') && ((file[1] == '\0') || ((file[1] == '.') && (file[2] == '\0')))) {
/* skip */
} else {
Strncpy(cp, ffd.cFileName, sizeof(pattern) - (cp - pattern));
PrintF(cip, " Lglob [%s]\n", pattern);
(void) AddLine(fileList, pattern);
}
if (!FindNextFile(searchHandle, &ffd)) {
dwErr = GetLastError();
if (dwErr != ERROR_NO_MORE_FILES) {
result = ((dwErr == 0) ? 0 : -1);
}
break;
}
}
return (result);
} // WinLocalGlob
#else
static int
LazyUnixLocalGlob(FTPCIPtr cip, LineListPtr fileList, const char *const pattern)
{
string cmd;
longstring gfile;
FILE *fp;
FTPSigProc sp;
/* Do it the easy way and have the shell do the dirty
* work for us.
*/
#ifdef HAVE_SNPRINTF
(void) snprintf(cmd, sizeof(cmd) - 1, "%s -c \"%s %s %s\"", "/bin/sh", "/bin/ls",
"-d", pattern);
cmd[sizeof(cmd) - 1] = '\0';
#else
(void) sprintf(cmd, "%s -c \"%s %s %s\"", "/bin/sh", "/bin/ls",
"-d", pattern);
#endif
fp = (FILE *) popen(cmd, "r");
if (fp == NULL) {
Error(cip, kDoPerror, "Could not Lglob: [%s]\n", cmd);
cip->errNo = kErrGlobFailed;
return (kErrGlobFailed);
}
sp = NcSignal(SIGPIPE, (FTPSigProc) SIG_IGN);
while (FGets(gfile, sizeof(gfile), (FILE *) fp) != NULL) {
PrintF(cip, " Lglob [%s]\n", gfile);
(void) AddLine(fileList, gfile);
}
(void) pclose(fp);
(void) NcSignal(SIGPIPE, sp);
return (kNoErr);
} /* LazyUnixLocalGlob */
#endif
int
FTPLocalGlob(FTPCIPtr cip, LineListPtr fileList, const char *pattern, int doGlob)
{
string pattern2;
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);
(void) STRNCPY(pattern2, pattern); /* Don't nuke the original. */
/* Pre-process for ~'s. */
ExpandTilde(pattern2, sizeof(pattern2));
InitLineList(fileList);
result = kNoErr;
if ((doGlob == 1) && (GLOBCHARSINSTR(pattern2))) {
#if defined(WIN32) || defined(_WINDOWS)
result = WinLocalGlob(cip, fileList, pattern2);
#else
result = LazyUnixLocalGlob(cip, fileList, pattern2);
#endif
} else {
/* Or, if there were no globbing characters in 'pattern', then
* the pattern is really just a single pathname.
*/
(void) AddLine(fileList, pattern2);
}
return (result);
} /* FTPLocalGlob */
static int
FTPFtwL2(const FTPCIPtr cip, char *dir, char *end, size_t dirsize, FTPFtwProc proc, int maxdepth)
{
LineList fileList;
LinePtr filePtr;
char *file, *cp;
int result;
if (maxdepth <= 0) {
result = cip->errNo = kErrRecursionLimitReached;
return (result);
}
result = FTPRemoteGlob(cip, &fileList, "**", kGlobYes);
if (result != kNoErr) {
if (result == kErrGlobNoMatch)
result = kNoErr; /* empty directory is okay. */
return (result);
}
for (filePtr = fileList.first;
filePtr != NULL;
filePtr = filePtr->next)
{
file = filePtr->line;
if (file == NULL) {
cip->errNo = kErrBadLineList;
break;
}
if ((file[0] == '.') && ((file[1] == '\0') || ((file[1] == '.') && (file[2] == '\0'))))
continue; /* Skip . and .. */
result = FTPIsDir(cip, file);
if (result < 0) {
/* error */
/* could be just a stat error, so continue */
continue;
} else if (result == 1) {
/* directory */
cp = Strnpcat(dir, file, dirsize);
result = (*proc)(cip, dir, kFtwDir);
if (result != kNoErr)
break;
if ((strchr(dir, '/') == NULL) && (strrchr(dir, '\\') != NULL))
*cp++ = '\\';
else
*cp++ = '/';
*cp = '\0';
result = FTPChdir(cip, file);
if (result == kNoErr) {
result = FTPFtwL2(cip, dir, cp, dirsize, proc, maxdepth - 1);
if (result != kNoErr)
break;
if (FTPChdir(cip, "..") < 0) {
result = kErrCannotGoToPrevDir;
cip->errNo = kErrCannotGoToPrevDir;
break;
}
}
*end = '\0';
if (result != 0)
break;
} else {
/* file */
cp = Strnpcat(dir, file, dirsize);
result = (*proc)(cip, dir, kFtwFile);
*end = '\0';
if (result != 0)
break;
}
}
DisposeLineListContents(&fileList);
return (result);
} /* FTPFtwL2 */
int
FTPFtw(const FTPCIPtr cip, const char *const dir, FTPFtwProc proc, int maxdepth)
{
int result, result2;
char *cp;
char savedcwd[1024];
char curcwd[2048];
result = FTPIsDir(cip, dir);
if (result < 0) {
/* error */
return result;
} else if (result == 0) {
result = cip->errNo = kErrNotADirectory;
return (result);
}
/* Preserve old working directory. */
(void) FTPGetCWD(cip, savedcwd, sizeof(savedcwd));
result = FTPChdir(cip, dir);
if (result != kNoErr) {
return (result);
}
/* Get full working directory we just changed to. */
result = FTPGetCWD(cip, curcwd, sizeof(curcwd) - 3);
if (result != kNoErr) {
if (FTPChdir(cip, savedcwd) != kNoErr) {
result = kErrCannotGoToPrevDir;
cip->errNo = kErrCannotGoToPrevDir;
}
return (result);
}
result2 = (*proc)(cip, curcwd, kFtwDir);
if (result2 == kNoErr) {
cp = curcwd + strlen(curcwd);
if ((strchr(curcwd, '/') == NULL) && (strrchr(curcwd, '\\') != NULL))
*cp++ = '\\';
else
*cp++ = '/';
*cp = '\0';
result = FTPFtwL2(cip, curcwd, cp, sizeof(curcwd), proc, maxdepth - 1);
}
if (FTPChdir(cip, savedcwd) != kNoErr) {
/* Could not cd back to the original user directory -- bad. */
result = kErrCannotGoToPrevDir;
cip->errNo = kErrCannotGoToPrevDir;
return (result);
}
if ((result2 != kNoErr) && (result == kNoErr))
result = result2;
return (result);
} /* FTPFtw */
/* eof */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -