📄 cmds.c
字号:
if (cp == NULL)
cp = strrchr(dir, '\\');
if (cp == NULL) {
cp = dir + strlen(dir) - 1;
if (dir[0] == '\0') {
result = kErrMKDFailed;
cip->errNo = kErrMKDFailed;
return (result);
}
/* Note: below we will refer to cp + 1
* which is why we set cp to point to
* the byte before the array begins!
*/
cp = dir - 1;
break;
}
if (cp == dir) {
result = kErrMKDFailed;
cip->errNo = kErrMKDFailed;
return (result);
}
*cp = '\0';
result = FTPChdir(cip, dir);
if (result == 0) {
break; /* Found a valid parent dir. */
/* from this point, we need to preserve old dir. */
}
}
newTreeStart = dir2 + ((cp + 1) - dir);
for (cp = newTreeStart; ; ) {
cp2 = cp;
cp = strchr(cp2, '/');
c = '/';
if (cp == NULL)
cp = strchr(cp2, '\\');
if (cp != NULL) {
c = *cp;
*cp = '\0';
if (cp[1] == '\0') {
/* Done, if they did "mkdir /tmp/dir/" */
break;
}
}
result = FTPCmd(cip, "MKD %s", newTreeStart);
if (result < 0) {
return (result);
}
if (result != 2) {
Error(cip, kDontPerror, "Cwd=%s; MKD %s failed; [%s]\n", cip->buf, newTreeStart, cip->lastFTPCmdResultStr);
result = kErrMKDFailed;
cip->errNo = kErrMKDFailed;
goto goback;
}
if (cp == NULL)
break; /* No more to make, done. */
*cp++ = c;
}
result = kNoErr;
goback:
result2 = FTPChdir(cip, ((curDir == NULL) || (curDir[0] == '\0')) ? cip->buf : curDir);
if ((result == 0) && (result2 < 0)) {
result = kErrCannotGoToPrevDir;
cip->errNo = kErrCannotGoToPrevDir;
}
}
return (result);
} /* FTPMkdir2 */
int
FTPMkdir(const FTPCIPtr cip, const char *const newDir, const int recurse)
{
return (FTPMkdir2(cip, newDir, recurse, NULL));
} /* FTPMkdir */
int
FTPFileModificationTime(const FTPCIPtr cip, const char *const file, time_t *const mdtm)
{
int result;
ResponsePtr rp;
if (cip == NULL)
return (kErrBadParameter);
if (strcmp(cip->magic, kLibraryMagic))
return (kErrBadMagic);
if ((mdtm == NULL) || (file == NULL))
return (kErrBadParameter);
*mdtm = kModTimeUnknown;
if (cip->hasMDTM == kCommandNotAvailable) {
cip->errNo = kErrMDTMNotAvailable;
result = kErrMDTMNotAvailable;
} else {
rp = InitResponse();
if (rp == NULL) {
result = kErrMallocFailed;
cip->errNo = kErrMallocFailed;
Error(cip, kDontPerror, "Malloc failed.\n");
} else {
result = RCmd(cip, rp, "MDTM %s", file);
if (result < 0) {
DoneWithResponse(cip, rp);
return (result);
} else if (strncmp(rp->msg.first->line, "19100", 5) == 0) {
Error(cip, kDontPerror, "Warning: Server has Y2K Bug in \"MDTM\" command.\n");
cip->errNo = kErrMDTMFailed;
result = kErrMDTMFailed;
} else if (result == 2) {
*mdtm = UnMDTMDate(rp->msg.first->line);
cip->hasMDTM = kCommandAvailable;
result = kNoErr;
} else if (UNIMPLEMENTED_CMD(rp->code)) {
cip->hasMDTM = kCommandNotAvailable;
cip->errNo = kErrMDTMNotAvailable;
result = kErrMDTMNotAvailable;
} else {
cip->errNo = kErrMDTMFailed;
result = kErrMDTMFailed;
}
DoneWithResponse(cip, rp);
}
}
return (result);
} /* FTPFileModificationTime */
int
FTPRename(const FTPCIPtr cip, const char *const oldname, const char *const newname)
{
int result;
if (cip == NULL)
return (kErrBadParameter);
if (strcmp(cip->magic, kLibraryMagic))
return (kErrBadMagic);
if ((oldname == NULL) || (oldname[0] == '\0'))
return (kErrBadParameter);
if ((newname == NULL) || (oldname[0] == '\0'))
return (kErrBadParameter);
result = FTPCmd(cip, "RNFR %s", oldname);
if (result < 0)
return (result);
if (result != 3) {
cip->errNo = kErrRenameFailed;
return (cip->errNo);
}
result = FTPCmd(cip, "RNTO %s", newname);
if (result < 0)
return (result);
if (result != 2) {
cip->errNo = kErrRenameFailed;
return (cip->errNo);
}
return (kNoErr);
} /* FTPRename */
int
FTPRemoteHelp(const FTPCIPtr cip, const char *const pattern, const LineListPtr llp)
{
int result;
ResponsePtr rp;
if ((cip == NULL) || (llp == NULL))
return (kErrBadParameter);
if (strcmp(cip->magic, kLibraryMagic))
return (kErrBadMagic);
InitLineList(llp);
rp = InitResponse();
if (rp == NULL) {
result = kErrMallocFailed;
cip->errNo = kErrMallocFailed;
Error(cip, kDontPerror, "Malloc failed.\n");
} else {
if ((pattern == NULL) || (*pattern == '\0'))
result = RCmd(cip, rp, "HELP");
else
result = RCmd(cip, rp, "HELP %s", pattern);
if (result < 0) {
DoneWithResponse(cip, rp);
return (result);
} else if (result == 2) {
if (CopyLineList(llp, &rp->msg) < 0) {
result = kErrMallocFailed;
cip->errNo = kErrMallocFailed;
Error(cip, kDontPerror, "Malloc failed.\n");
} else {
result = kNoErr;
}
} else {
cip->errNo = kErrHELPFailed;
result = kErrHELPFailed;
}
DoneWithResponse(cip, rp);
}
return (result);
} /* FTPRemoteHelp */
int
FTPRmdir(const FTPCIPtr cip, const char *const pattern, const int recurse, const int doGlob)
{
LineList fileList;
LinePtr 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, "RMD %s", file);
if (onceResult < 0) {
batchResult = onceResult;
break;
}
if (onceResult != 2) {
if (recurse == kRecursiveYes) {
onceResult = FTPRmdirRecursive(cip, file);
if (onceResult < 0) {
batchResult = kErrRMDFailed;
cip->errNo = kErrRMDFailed;
}
} else {
batchResult = kErrRMDFailed;
cip->errNo = kErrRMDFailed;
}
}
}
DisposeLineListContents(&fileList);
return (batchResult);
} /* FTPRmdir */
int
FTPSetTransferType(const FTPCIPtr cip, int type)
{
int result;
if (cip == NULL)
return (kErrBadParameter);
if (strcmp(cip->magic, kLibraryMagic))
return (kErrBadMagic);
if (cip->curTransferType != type) {
switch (type) {
case kTypeAscii:
case kTypeBinary:
case kTypeEbcdic:
break;
case 'i':
case 'b':
case 'B':
type = kTypeBinary;
break;
case 'e':
type = kTypeEbcdic;
break;
case 'a':
type = kTypeAscii;
break;
default:
/* Yeah, we don't support Tenex. Who cares? */
Error(cip, kDontPerror, "Bad transfer type [%c].\n", type);
cip->errNo = kErrBadTransferType;
return (kErrBadTransferType);
}
result = FTPCmd(cip, "TYPE %c", type);
if (result != 2) {
result = kErrTYPEFailed;
cip->errNo = kErrTYPEFailed;
return (result);
}
cip->curTransferType = type;
}
return (kNoErr);
} /* FTPSetTransferType */
/* If the remote host supports the SIZE command, we can find out the exact
* size of a remote file, depending on the transfer type in use. SIZE
* returns different values for ascii and binary modes!
*/
int
FTPFileSize(const FTPCIPtr cip, const char *const file, longest_int *const size, const int type)
{
int result;
ResponsePtr rp;
if (cip == NULL)
return (kErrBadParameter);
if (strcmp(cip->magic, kLibraryMagic))
return (kErrBadMagic);
if ((size == NULL) || (file == NULL))
return (kErrBadParameter);
*size = kSizeUnknown;
result = FTPSetTransferType(cip, type);
if (result < 0)
return (result);
if (cip->hasSIZE == kCommandNotAvailable) {
cip->errNo = kErrSIZENotAvailable;
result = kErrSIZENotAvailable;
} else {
rp = InitResponse();
if (rp == NULL) {
result = kErrMallocFailed;
cip->errNo = kErrMallocFailed;
Error(cip, kDontPerror, "Malloc failed.\n");
} else {
result = RCmd(cip, rp, "SIZE %s", file);
if (result < 0) {
DoneWithResponse(cip, rp);
return (result);
} else if (result == 2) {
#if defined(HAVE_LONG_LONG) && defined(SCANF_LONG_LONG)
(void) sscanf(rp->msg.first->line, SCANF_LONG_LONG, size);
#elif defined(HAVE_LONG_LONG) && defined(HAVE_STRTOQ)
*size = (longest_int) strtoq(rp->msg.first->line, NULL, 0);
#else
(void) sscanf(rp->msg.first->line, "%ld", size);
#endif
cip->hasSIZE = kCommandAvailable;
result = kNoErr;
} else if (UNIMPLEMENTED_CMD(rp->code)) {
cip->hasSIZE = kCommandNotAvailable;
cip->errNo = kErrSIZENotAvailable;
result = kErrSIZENotAvailable;
} else {
cip->errNo = kErrSIZEFailed;
result = kErrSIZEFailed;
}
DoneWithResponse(cip, rp);
}
}
return (result);
} /* FTPFileSize */
int
FTPMListOneFile(const FTPCIPtr cip, const char *const file, const MLstItemPtr mlip)
{
int result;
ResponsePtr rp;
/* We do a special check for older versions of NcFTPd which
* are based off of an incompatible previous version of IETF
* extensions.
*
* Roxen also seems to be way outdated, where MLST was on the
* data connection among other things.
*
*/
if (
(cip->hasMLST == kCommandNotAvailable) ||
((cip->serverType == kServerTypeNcFTPd) && (cip->ietfCompatLevel < 19981201)) ||
(cip->serverType == kServerTypeRoxen)
) {
cip->errNo = kErrMLSTNotAvailable;
return (cip->errNo);
}
rp = InitResponse();
if (rp == NULL) {
result = cip->errNo = kErrMallocFailed;
Error(cip, kDontPerror, "Malloc failed.\n");
} else {
result = RCmd(cip, rp, "MLST %s", file);
if (
(result == 2) &&
(rp->msg.first->line != NULL) &&
(rp->msg.first->next != NULL) &&
(rp->msg.first->next->line != NULL)
) {
result = UnMlsT(rp->msg.first->next->line, mlip);
if (result < 0) {
cip->errNo = result = kErrInvalidMLSTResponse;
}
} else if (UNIMPLEMENTED_CMD(rp->code)) {
cip->hasMLST = kCommandNotAvailable;
cip->errNo = kErrMLSTNotAvailable;
result = kErrMLSTNotAvailable;
} else {
cip->errNo = kErrMLSTFailed;
result = kErrMLSTFailed;
}
DoneWithResponse(cip, rp);
}
return (result);
} /* FTPMListOneFile */
/* 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
FTPFileExistsStat(const FTPCIPtr cip, const char *const file)
{
int result;
ResponsePtr rp;
LineList fileList;
char savedCwd[512];
if (cip == NULL)
return (kErrBadParameter);
if (strcmp(cip->magic, kLibraryMagic))
return (kErrBadMagic);
if (file == NULL)
return (kErrBadParameter);
if (cip->STATfileParamWorks == kCommandNotAvailable) {
cip->errNo = result = kErrSTATwithFileNotAvailable;
return (result);
}
if (cip->STATfileParamWorks == kCommandAvailabilityUnknown) {
rp = InitResponse();
if (rp == NULL) {
result = kErrMallocFailed;
cip->errNo = kErrMallocFailed;
Error(cip, kDontPerror, "Malloc failed.\n");
return (result);
}
/* First, make sure that when we STAT a pathname
* that does not exist, that we get an error back.
*
* We also assume that a valid STAT 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.
*/
result = RCmd(cip, rp, "STAT %s", "NoSuchFile");
if ((result == 2) && ((rp->msg.nLines >= 3) || (rp->msg.nLines == 1))) {
/* Hmmm.... it gave back a positive
* response. So STAT <file> does not
* work correctly.
*/
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)
)
) {
/* OK, while we didn't want a 200
* level response, some servers,
* like wu-ftpd print an error
* message "No such file or
* directory" which we can special
* case.
*/
result = kNoErr;
} else {
cip->STATfileParamWorks = kCommandNotAvailable;
cip->errNo = result = kErrSTATwithFileNotAvailable;
DoneWithResponse(cip, rp);
return (result);
}
}
DoneWithResponse(cip, rp);
/* We can't assume that we can simply say STAT 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 STAT 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 stat
* 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 stat the first item
* we found to see if STAT says it exists.
*/
if (
((result = FTPListToMemory2(cip, "", &fileList, "", 0, (int *) 0)) < 0) ||
(fileList.last == NULL) ||
(fileList.last->line == NULL)
) {
/* Hmmm... well, in any case we can't use STAT. */
cip->STATfileParamWorks = kCommandNotAvailable;
cip->errNo = result = kErrSTATwithFileNotAvailable;
DisposeLineListContents(&fileList);
(void) FTPChdir(cip, savedCwd);
return (result);
}
rp = InitResponse();
if (rp == NULL) {
result = kErrMallocFailed;
cip->errNo = kErrMallocFailed;
Error(cip, kDontPerror, "Malloc failed.\n");
DisposeLineListContents(&fileList);
(void) FTPChdir(cip, savedCwd);
return (result);
}
result = RCmd(cip, rp, "STAT %s", fileList.last->line);
DisposeLineListContents(&fileList);
if ((result != 2) || (rp->msg.nLines == 2)) {
/* Hmmm.... it gave back a negative
* response. So STAT <file> does not
* work correctly.
*/
cip->STATfileParamWorks = kCommandNotAvailable;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -