📄 cmds.c
字号:
cip->errNo = result = kErrSTATwithFileNotAvailable;
DoneWithResponse(cip, rp);
(void) FTPChdir(cip, savedCwd);
return (result);
} else if (
(rp->msg.first->next != NULL) &&
(rp->msg.first->next->line != NULL) &&
(
(strstr(rp->msg.first->next->line, "o such file") != NULL) ||
(strstr(rp->msg.first->next->line, "ot found") != NULL)
)
) {
/* Same special-case of the second line of STAT response. */
cip->STATfileParamWorks = kCommandNotAvailable;
cip->errNo = result = kErrSTATwithFileNotAvailable;
DoneWithResponse(cip, rp);
(void) FTPChdir(cip, savedCwd);
return (result);
}
DoneWithResponse(cip, rp);
cip->STATfileParamWorks = kCommandAvailable;
/* Don't forget to change back to the original directory. */
(void) FTPChdir(cip, savedCwd);
}
rp = InitResponse();
if (rp == NULL) {
result = kErrMallocFailed;
cip->errNo = kErrMallocFailed;
Error(cip, kDontPerror, "Malloc failed.\n");
return (result);
}
result = RCmd(cip, rp, "STAT %s", file);
if (result == 2) {
result = kNoErr;
if (((rp->msg.nLines >= 3) || (rp->msg.nLines == 1))) {
if (
(rp->msg.first->next != NULL) &&
(rp->msg.first->next->line != NULL) &&
(
(strstr(rp->msg.first->next->line, "o such file") != NULL) ||
(strstr(rp->msg.first->next->line, "ot found") != NULL)
)
) {
cip->errNo = kErrSTATFailed;
result = kErrSTATFailed;
} else {
result = kNoErr;
}
} else if (rp->msg.nLines == 2) {
cip->errNo = kErrSTATFailed;
result = kErrSTATFailed;
} else {
result = kNoErr;
}
} else {
cip->errNo = kErrSTATFailed;
result = kErrSTATFailed;
}
DoneWithResponse(cip, rp);
return (result);
} /* FTPFileExistsStat */
/* We only use STAT to see if files or directories exist.
* But since it is so rarely used in the wild, we need to
* make sure the server supports the use where we pass
* a pathname as a parameter.
*/
int
FTPFileExistsNlst(const FTPCIPtr cip, const char *const file)
{
int result;
LineList fileList, rootFileList;
char savedCwd[512];
if (cip == NULL)
return (kErrBadParameter);
if (strcmp(cip->magic, kLibraryMagic))
return (kErrBadMagic);
if (file == NULL)
return (kErrBadParameter);
if (cip->NLSTfileParamWorks == kCommandNotAvailable) {
cip->errNo = result = kErrNLSTwithFileNotAvailable;
return (result);
}
if (cip->NLSTfileParamWorks == kCommandAvailabilityUnknown) {
/* First, make sure that when we NLST a pathname
* that does not exist, that we get an error back.
*
* We also assume that a valid NLST response has
* at least 3 lines of response text, typically
* a "start" line, intermediate data, and then
* a trailing line.
*
* We also can see a one-line case.
*/
if (
((FTPListToMemory2(cip, "NoSuchFile", &fileList, "", 0, (int *) 0)) == kNoErr) &&
(fileList.nLines >= 1) &&
(strstr(fileList.last->line, "o such file") == NULL) &&
(strstr(fileList.last->line, "ot found") == NULL) &&
(strstr(fileList.last->line, "o Such File") == NULL) &&
(strstr(fileList.last->line, "ot Found") == NULL)
) {
cip->NLSTfileParamWorks = kCommandNotAvailable;
cip->errNo = result = kErrNLSTwithFileNotAvailable;
DisposeLineListContents(&fileList);
return (result);
}
DisposeLineListContents(&fileList);
/* We can't assume that we can simply say NLST rootdir/firstfile,
* since the remote host may not be using / as a directory
* delimiter. So we have to change to the root directory
* and then do the NLST on that file.
*/
if (
(FTPGetCWD(cip, savedCwd, sizeof(savedCwd)) != kNoErr) ||
(FTPChdir(cip, cip->startingWorkingDirectory) != kNoErr)
) {
return (cip->errNo);
}
/* OK, we get an error when we list
* a non-existant file, but now we need to
* see if we get a positive reply when
* we stat a file that does exist.
*
* To do this, we list the root directory,
* which we assume has one or more items.
* If it doesn't, the user can't do anything
* anyway. Then we do the first item
* we found to see if NLST says it exists.
*/
if (
((result = FTPListToMemory2(cip, "", &rootFileList, "", 0, (int *) 0)) < 0) ||
(rootFileList.last == NULL) ||
(rootFileList.last->line == NULL)
) {
/* Hmmm... well, in any case we can't use NLST. */
cip->NLSTfileParamWorks = kCommandNotAvailable;
cip->errNo = result = kErrNLSTwithFileNotAvailable;
DisposeLineListContents(&rootFileList);
(void) FTPChdir(cip, savedCwd);
return (result);
}
if (
((FTPListToMemory2(cip, rootFileList.last->line, &fileList, "", 0, (int *) 0)) == kNoErr) &&
(fileList.nLines >= 1) &&
(strstr(fileList.last->line, "o such file") == NULL) &&
(strstr(fileList.last->line, "ot found") == NULL) &&
(strstr(fileList.last->line, "o Such File") == NULL) &&
(strstr(fileList.last->line, "ot Found") == NULL)
) {
/* Good. We listed the item. */
DisposeLineListContents(&fileList);
DisposeLineListContents(&rootFileList);
cip->NLSTfileParamWorks = kCommandAvailable;
/* Don't forget to change back to the original directory. */
(void) FTPChdir(cip, savedCwd);
} else {
cip->NLSTfileParamWorks = kCommandNotAvailable;
cip->errNo = result = kErrNLSTwithFileNotAvailable;
DisposeLineListContents(&fileList);
DisposeLineListContents(&rootFileList);
(void) FTPChdir(cip, savedCwd);
return (result);
}
}
/* Check the requested item. */
InitLineList(&fileList);
if (
((FTPListToMemory2(cip, file, &fileList, "", 0, (int *) 0)) == kNoErr) &&
(fileList.nLines >= 1) &&
(strstr(fileList.last->line, "o such file") == NULL) &&
(strstr(fileList.last->line, "ot found") == NULL) &&
(strstr(fileList.last->line, "o Such File") == NULL) &&
(strstr(fileList.last->line, "ot Found") == NULL)
) {
/* The item existed. */
result = kNoErr;
} else {
cip->errNo = kErrNLSTFailed;
result = kErrNLSTFailed;
}
DisposeLineListContents(&fileList);
return (result);
} /* FTPFileExistsNlst*/
/* This functions goes to a great deal of trouble to try and determine if the
* remote file specified exists. Newer servers support commands that make
* it relatively inexpensive to find the answer, but older servers do not
* provide a standard way. This means we may try a whole bunch of things,
* but the good news is that the library saves information about which things
* worked so if you do this again it uses the methods that work.
*/
int
FTPFileExists2(const FTPCIPtr cip, const char *const file, const int tryMDTM, const int trySIZE, const int tryMLST, const int trySTAT, const int tryNLST)
{
int result;
time_t mdtm;
longest_int size;
MLstItem mlsInfo;
if (tryMDTM != 0) {
result = FTPFileModificationTime(cip, file, &mdtm);
if (result == kNoErr)
return (kNoErr);
if (result == kErrMDTMFailed) {
cip->errNo = kErrNoSuchFileOrDirectory;
return (kErrNoSuchFileOrDirectory);
}
/* else keep going */
}
if (trySIZE != 0) {
result = FTPFileSize(cip, file, &size, kTypeBinary);
if (result == kNoErr)
return (kNoErr);
/* SIZE could fail if the server does
* not support it for directories.
*
* if (result == kErrSIZEFailed)
* return (kErrNoSuchFileOrDirectory);
*/
/* else keep going */
}
if (tryMLST != 0) {
result = FTPMListOneFile(cip, file, &mlsInfo);
if (result == kNoErr)
return (kNoErr);
if (result == kErrMLSTFailed) {
cip->errNo = kErrNoSuchFileOrDirectory;
return (kErrNoSuchFileOrDirectory);
}
/* else keep going */
}
if (trySTAT != 0) {
result = FTPFileExistsStat(cip, file);
if (result == kNoErr)
return (kNoErr);
if (result == kErrSTATFailed) {
cip->errNo = kErrNoSuchFileOrDirectory;
return (kErrNoSuchFileOrDirectory);
}
/* else keep going */
}
if (tryNLST != 0) {
result = FTPFileExistsNlst(cip, file);
if (result == kNoErr)
return (kNoErr);
if (result == kErrNLSTFailed) {
cip->errNo = kErrNoSuchFileOrDirectory;
return (kErrNoSuchFileOrDirectory);
}
/* else keep going */
}
cip->errNo = kErrCantTellIfFileExists;
return (kErrCantTellIfFileExists);
} /* FTPFileExists2 */
int
FTPFileExists(const FTPCIPtr cip, const char *const file)
{
return (FTPFileExists2(cip, file, 1, 1, 1, 1, 1));
} /* FTPFileExists */
int
FTPFileSizeAndModificationTime(const FTPCIPtr cip, const char *const file, longest_int *const size, const int type, time_t *const mdtm)
{
MLstItem mlsInfo;
int result;
if (cip == NULL)
return (kErrBadParameter);
if (strcmp(cip->magic, kLibraryMagic))
return (kErrBadMagic);
if ((mdtm == NULL) || (size == NULL) || (file == NULL))
return (kErrBadParameter);
*mdtm = kModTimeUnknown;
*size = kSizeUnknown;
result = FTPSetTransferType(cip, type);
if (result < 0)
return (result);
result = FTPMListOneFile(cip, file, &mlsInfo);
if (result < 0) {
/* Do it the regular way, where
* we do a SIZE and then a MDTM.
*/
result = FTPFileSize(cip, file, size, type);
if (result < 0)
return (result);
result = FTPFileModificationTime(cip, file, mdtm);
return (result);
} else {
*mdtm = mlsInfo.ftime;
*size = mlsInfo.fsize;
}
return (result);
} /* FTPFileSizeAndModificationTime */
int
FTPFileType(const FTPCIPtr cip, const char *const file, int *const ftype)
{
int result;
MLstItem mlsInfo;
if (cip == NULL)
return (kErrBadParameter);
if (strcmp(cip->magic, kLibraryMagic))
return (kErrBadMagic);
if ((file == NULL) || (file[0] == '\0')) {
cip->errNo = kErrBadParameter;
return (kErrBadParameter);
}
if (ftype == NULL) {
cip->errNo = kErrBadParameter;
return (kErrBadParameter);
}
*ftype = 0;
result = FTPMListOneFile(cip, file, &mlsInfo);
if (result == kNoErr) {
*ftype = mlsInfo.ftype;
return (kNoErr);
}
/* Preserve old working directory. */
(void) FTPGetCWD(cip, cip->buf, cip->bufSize);
result = FTPChdir(cip, file);
if (result == kNoErr) {
*ftype = 'd';
/* Yes it was a directory, now go back to
* where we were.
*/
(void) FTPChdir(cip, cip->buf);
/* Note: This improperly assumes that we
* will be able to chdir back, which is
* not guaranteed.
*/
return (kNoErr);
}
result = FTPFileExists2(cip, file, 1, 1, 0, 1, 1);
if (result != kErrNoSuchFileOrDirectory)
result = kErrFileExistsButCannotDetermineType;
return (result);
} /* FTPFileType */
int
FTPIsDir(const FTPCIPtr cip, const char *const dir)
{
int result, ftype;
if (cip == NULL)
return (kErrBadParameter);
if (strcmp(cip->magic, kLibraryMagic))
return (kErrBadMagic);
if ((dir == NULL) || (dir[0] == '\0')) {
cip->errNo = kErrInvalidDirParam;
return (kErrInvalidDirParam);
}
result = FTPFileType(cip, dir, &ftype);
if ((result == kNoErr) || (result == kErrFileExistsButCannotDetermineType)) {
result = 0;
if (ftype == 'd')
result = 1;
}
return (result);
} /* FTPIsDir */
int
FTPIsRegularFile(const FTPCIPtr cip, const char *const file)
{
int result, ftype;
if (cip == NULL)
return (kErrBadParameter);
if (strcmp(cip->magic, kLibraryMagic))
return (kErrBadMagic);
if ((file == NULL) || (file[0] == '\0')) {
cip->errNo = kErrBadParameter;
return (kErrBadParameter);
}
result = FTPFileType(cip, file, &ftype);
if ((result == kNoErr) || (result == kErrFileExistsButCannotDetermineType)) {
result = 1;
if (ftype == 'd')
result = 0;
}
return (result);
} /* FTPIsRegularFile */
int
FTPSymlink(const FTPCIPtr cip, const char *const lfrom, const char *const lto)
{
if (strcmp(cip->magic, kLibraryMagic))
return (kErrBadMagic);
if ((cip == NULL) || (lfrom == NULL) || (lto == NULL))
return (kErrBadParameter);
if ((lfrom[0] == '\0') || (lto[0] == '\0'))
return (kErrBadParameter);
if (FTPCmd(cip, "SITE SYMLINK %s %s", lfrom, lto) == 2)
return (kNoErr);
return (kErrSYMLINKFailed);
} /* FTPSymlink */
int
FTPUmask(const FTPCIPtr cip, const char *const umsk)
{
if (cip == NULL)
return (kErrBadParameter);
if (strcmp(cip->magic, kLibraryMagic))
return (kErrBadMagic);
if ((umsk == NULL) || (umsk[0] == '\0'))
return (kErrBadParameter);
if (FTPCmd(cip, "SITE UMASK %s", umsk) == 2)
return (kNoErr);
return (kErrUmaskFailed);
} /* FTPUmask */
static void
GmTimeStr(char *const dst, const size_t dstsize, time_t t)
{
char buf[64];
struct tm *gtp;
gtp = gmtime(&t);
if (gtp == NULL) {
dst[0] = '\0';
} else {
#ifdef HAVE_SNPRINTF
buf[sizeof(buf) - 1] = '\0';
(void) snprintf(buf, sizeof(buf) - 1, "%04d%02d%02d%02d%02d%02d",
#else
(void) sprintf(buf, "%04d%02d%02d%02d%02d%02d",
#endif
gtp->tm_year + 1900,
gtp->tm_mon + 1,
gtp->tm_mday,
gtp->tm_hour,
gtp->tm_min,
gtp->tm_sec
);
(void) Strncpy(dst, buf, dstsize);
}
} /* GmTimeStr */
int
FTPUtime(const FTPCIPtr cip, const char *const file, time_t actime, time_t modtime, time_t crtime)
{
char mstr[64], astr[64], cstr[64];
int result;
ResponsePtr rp;
if (cip == NULL)
return (kErrBadParameter);
if (strcmp(cip->magic, kLibraryMagic))
return (kErrBadMagic);
if (cip->hasUTIME == kCommandNotAvailable) {
cip->errNo = kErrUTIMENotAvailable;
result = kErrUTIMENotAvailable;
} else {
if ((actime == (time_t) 0) || (actime == (time_t) -1))
(void) time(&actime);
if ((modtime == (time_t) 0) || (modtime == (time_t) -1))
(void) time(&modtime);
if ((crtime == (time_t) 0) || (crtime == (time_t) -1))
crtime = modtime;
(void) GmTimeStr(astr, sizeof(astr), actime);
(void) GmTimeStr(mstr, sizeof(mstr), modtime);
(void) GmTimeStr(cstr, sizeof(cstr), crtime);
rp = InitResponse();
if (rp == NULL) {
result = kErrMallocFailed;
cip->errNo = kErrMallocFailed;
Error(cip, kDontPerror, "Malloc failed.\n");
} else {
result = RCmd(cip, rp, "SITE UTIME %s %s %s %s UTC", file, astr, mstr, cstr);
if (result < 0) {
DoneWithResponse(cip, rp);
return (result);
} else if (result == 2) {
cip->hasUTIME = kCommandAvailable;
result = kNoErr;
} else if (UNIMPLEMENTED_CMD(rp->code)) {
cip->hasUTIME = kCommandNotAvailable;
cip->errNo = kErrUTIMENotAvailable;
result = kErrUTIMENotAvailable;
} else {
cip->errNo = kErrUTIMEFailed;
result = kErrUTIMEFailed;
}
DoneWithResponse(cip, rp);
}
}
return (result);
} /* FTPUtime */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -