📄 io.c
字号:
* was a different file altogether,
* since it is larger than the
* remote copy. Re-do it all.
*/
zaction = kConfirmResumeProcSaidOverwrite;
} else {
/* We have a file by the same time,
* but smaller start point. Leave
* the startpoint as is since it
* is most likely valid.
*/
}
} else if (mdtm < st.st_mtime) {
/* Remote file is older than
* local file. Don't overwrite
* our file.
*/
cip->errNo = kErrLocalFileNewer;
return (cip->errNo);
} else /* if (mdtm > st.st_mtime) */ {
/* File has a newer timestamp
* altogether, assume the remote
* file is an entirely new file
* and replace ours with it.
*/
zaction = kConfirmResumeProcSaidOverwrite;
}
} else {
zaction = kConfirmResumeProcSaidOverwrite;
}
}
} else {
zaction = kConfirmResumeProcSaidOverwrite;
}
if (zaction == kConfirmResumeProcSaidCancel) {
/* User wants to cancel this file and any
* remaining in batch.
*/
cip->errNo = kErrUserCanceled;
return (cip->errNo);
} else if (zaction == kConfirmResumeProcSaidSkip) {
/* Nothing done, but not an error. */
if (deleteflag == kDeleteYes)
(void) FTPDelete(cip, file, kRecursiveNo, kGlobNo);
return (kNoErr);
} else if (zaction == kConfirmResumeProcSaidResume) {
/* Resume; proc set the startPoint. */
if (startPoint == expectedSize) {
/* Don't go to all the trouble of downloading nothing. */
/* Nothing done, but not an error. */
if (deleteflag == kDeleteYes)
(void) FTPDelete(cip, file, kRecursiveNo, kGlobNo);
return (kNoErr);
} else if (startPoint > expectedSize) {
/* Cannot set start point past end of remote file */
cip->errNo = result = kErrSetStartPoint;
return (result);
}
fd = Open(dstfile, O_WRONLY|O_APPEND|O_BINARY, 00666);
} else if (zaction == kConfirmResumeProcSaidAppend) {
/* leave startPoint at zero, we will append everything. */
startPoint = (longest_int) 0;
fd = Open(dstfile, O_WRONLY|O_CREAT|O_APPEND|O_BINARY, 00666);
} else /* if (zaction == kConfirmResumeProcSaidOverwrite) */ {
created = 1;
startPoint = (longest_int) 0;
fd = Open(dstfile, O_WRONLY|O_CREAT|O_TRUNC|O_BINARY, 00666);
}
if (fd < 0) {
Error(cip, kDoPerror, "Cannot open local file %s for writing.\n", dstfile);
result = kErrOpenFailed;
cip->errNo = kErrOpenFailed;
return (result);
}
if ((expectedSize == (longest_int) 0) && (startPoint <= (longest_int) 0) && (zaction != kConfirmResumeProcSaidOverwrite)) {
/* Don't go to all the trouble of downloading nothing. */
#if defined(WIN32) || defined(_WINDOWS)
/* Note: Windows doesn't allow zero-size files. */
(void) write(fd, "\r\n", 2);
#endif
(void) close(fd);
if (mdtm != kModTimeUnknown) {
cip->mdtm = mdtm;
(void) time(&ut.actime);
ut.modtime = mdtm;
(void) utime(dstfile, &ut);
}
if (deleteflag == kDeleteYes)
(void) FTPDelete(cip, file, kRecursiveNo, kGlobNo);
return (kNoErr);
}
} else {
fd = fdtouse;
}
if ((cip->numDownloads == 0) && (cip->dataSocketRBufSize > 0)) {
/* If dataSocketSBufSize is non-zero, it means you
* want to explicitly try to set the size of the
* socket's I/O buffer.
*
* If it is zero, it means you want to just use the
* TCP stack's default value, which is typically
* between 8 and 64 kB.
*
* If you try to set the buffer larger than 64 kB,
* the TCP stack should try to use RFC 1323 to
* negotiate "TCP Large Windows" which may yield
* significant performance gains.
*/
if (cip->hasRETRBUFSIZE == kCommandAvailable)
(void) FTPCmd(cip, "SITE RETRBUFSIZE %lu", (unsigned long) cip->dataSocketRBufSize);
else if (cip->hasRBUFSIZ == kCommandAvailable)
(void) FTPCmd(cip, "SITE RBUFSIZ %lu", (unsigned long) cip->dataSocketRBufSize);
else if (cip->hasRBUFSZ == kCommandAvailable)
(void) FTPCmd(cip, "SITE RBUFSZ %lu", (unsigned long) cip->dataSocketRBufSize);
else if (cip->hasBUFSIZE == kCommandAvailable)
(void) FTPCmd(cip, "SITE BUFSIZE %lu", (unsigned long) cip->dataSocketSBufSize);
}
#ifdef NO_SIGNALS
#else /* NO_SIGNALS */
vcip = cip;
vfdtouse = fdtouse;
vfd = fd;
osigpipe = (volatile FTPSigProc) signal(SIGPIPE, BrokenData);
gGotBrokenData = 0;
gCanBrokenDataJmp = 0;
#ifdef HAVE_SIGSETJMP
sj = sigsetjmp(gBrokenDataJmp, 1);
#else
sj = setjmp(gBrokenDataJmp);
#endif /* HAVE_SIGSETJMP */
if (sj != 0) {
(void) signal(SIGPIPE, (FTPSigProc) osigpipe);
if (vfdtouse < 0) {
(void) close(vfd);
}
FTPShutdownHost(vcip);
vcip->errNo = kErrRemoteHostClosedConnection;
return(vcip->errNo);
}
gCanBrokenDataJmp = 1;
#endif /* NO_SIGNALS */
tmpResult = FTPStartDataCmd(cip, kNetReading, xtype, startPoint, "RETR %s", file);
if (tmpResult < 0) {
result = tmpResult;
if (result == kErrGeneric)
result = kErrRETRFailed;
cip->errNo = result;
if (fdtouse < 0) {
(void) close(fd);
if ((created != 0) && (appendflag == kAppendNo) && (cip->startPoint == 0))
(void) unlink(dstfile);
}
#if !defined(NO_SIGNALS)
(void) signal(SIGPIPE, (FTPSigProc) osigpipe);
#endif /* NO_SIGNALS */
return (result);
}
if ((startPoint != 0) && (cip->startPoint == 0)) {
/* Remote could not or would not set the start offset
* to what we wanted.
*
* So now we have to undo our seek.
*/
if (Lseek(fd, (off_t) 0, SEEK_SET) != (off_t) 0) {
cip->errNo = kErrLseekFailed;
if (fdtouse < 0) {
(void) close(fd);
}
#if !defined(NO_SIGNALS)
(void) signal(SIGPIPE, (FTPSigProc) osigpipe);
#endif /* NO_SIGNALS */
return (cip->errNo);
}
startPoint = 0;
}
buf = cip->buf;
bufSize = cip->bufSize;
FTPInitIOTimer(cip);
cip->mdtm = mdtm;
(void) time(&ut.actime);
ut.modtime = mdtm;
cip->expectedSize = expectedSize;
cip->lname = dstfile; /* could be NULL */
cip->rname = file;
if (fdtouse >= 0)
cip->useProgressMeter = 0;
FTPStartIOTimer(cip);
#if ASCII_TRANSLATION
if (xtype == kTypeAscii) {
/* Ascii */
for (;;) {
if (! WaitForRemoteInput(cip)) { /* could set cancelXfer */
cip->errNo = result = kErrDataTimedOut;
Error(cip, kDontPerror, "Remote read timed out.\n");
break;
}
if (cip->cancelXfer > 0) {
FTPAbortDataTransfer(cip);
result = cip->errNo = kErrDataTransferAborted;
break;
}
#ifdef TESTING_ABOR
if (cip->bytesTransferred > 0) {
cip->cancelXfer = 1;
FTPAbortDataTransfer(cip);
result = cip->errNo = kErrDataTransferAborted;
break;
}
#endif /* TESTING_ABOR */
#ifdef NO_SIGNALS
nread = SRead(cip->dataSocket, buf, bufSize, (int) cip->xferTimeout, kFullBufferNotRequired|kNoFirstSelect);
if (nread == kTimeoutErr) {
cip->errNo = result = kErrDataTimedOut;
Error(cip, kDontPerror, "Remote read timed out.\n");
break;
} else if (nread < 0) {
if ((gGotBrokenData != 0) || (errno == EPIPE)) {
result = cip->errNo = kErrSocketReadFailed;
errno = EPIPE;
Error(cip, kDoPerror, "Lost data connection to remote host.\n");
} else if (errno == EINTR) {
continue;
} else {
Error(cip, kDoPerror, "Remote read failed.\n");
result = kErrSocketReadFailed;
cip->errNo = kErrSocketReadFailed;
}
break;
} else if (nread == 0) {
break;
}
#else
gCanBrokenDataJmp = 1;
if (cip->xferTimeout > 0)
(void) alarm(cip->xferTimeout);
nread = read(cip->dataSocket, buf, bufSize);
if (nread < 0) {
if ((gGotBrokenData != 0) || (errno == EPIPE)) {
result = cip->errNo = kErrSocketReadFailed;
errno = EPIPE;
Error(cip, kDoPerror, "Lost data connection to remote host.\n");
(void) shutdown(cip->dataSocket, 2);
} else if (errno == EINTR) {
continue;
} else {
result = cip->errNo = kErrSocketReadFailed;
Error(cip, kDoPerror, "Remote read failed.\n");
(void) shutdown(cip->dataSocket, 2);
}
break;
} else if (nread == 0) {
break;
}
gCanBrokenDataJmp = 0;
#endif /* NO_SIGNALS */
src = buf;
srclim = src + nread;
dst = outbuf;
dstlim = dst + sizeof(outbuf);
while (src < srclim) {
if (*src == '\r') {
src++;
continue;
}
if (dst >= dstlim) {
nwrote = write(fd, outbuf, (size_t) (dst - outbuf));
if (nwrote == (int) (dst - outbuf)) {
/* Success. */
dst = outbuf;
} else if ((gGotBrokenData != 0) || (errno == EPIPE)) {
result = kErrWriteFailed;
cip->errNo = kErrWriteFailed;
errno = EPIPE;
(void) shutdown(cip->dataSocket, 2);
goto brk;
} else {
Error(cip, kDoPerror, "Local write failed.\n");
result = kErrWriteFailed;
cip->errNo = kErrWriteFailed;
(void) shutdown(cip->dataSocket, 2);
goto brk;
}
}
*dst++ = *src++;
}
if (dst > outbuf) {
nwrote = write(fd, outbuf, (size_t) (dst - outbuf));
if (nwrote != (int) (dst - outbuf)) {
if ((gGotBrokenData != 0) || (errno == EPIPE)) {
result = kErrWriteFailed;
cip->errNo = kErrWriteFailed;
errno = EPIPE;
(void) shutdown(cip->dataSocket, 2);
goto brk;
} else {
Error(cip, kDoPerror, "Local write failed.\n");
result = kErrWriteFailed;
cip->errNo = kErrWriteFailed;
(void) shutdown(cip->dataSocket, 2);
goto brk;
}
}
}
if (mdtm != kModTimeUnknown) {
(void) utime(dstfile, &ut);
}
cip->bytesTransferred += (longest_int) nread;
FTPUpdateIOTimer(cip);
}
} else
#endif /* ASCII_TRANSLATION */
{
/* Binary */
for (;;) {
if (! WaitForRemoteInput(cip)) { /* could set cancelXfer */
cip->errNo = result = kErrDataTimedOut;
Error(cip, kDontPerror, "Remote read timed out.\n");
break;
}
if (cip->cancelXfer > 0) {
FTPAbortDataTransfer(cip);
result = cip->errNo = kErrDataTransferAborted;
break;
}
#ifdef TESTING_ABOR
if (cip->bytesTransferred > 0) {
cip->cancelXfer = 1;
FTPAbortDataTransfer(cip);
result = cip->errNo = kErrDataTransferAborted;
break;
}
#endif /* TESTING_ABOR */
#ifdef NO_SIGNALS
nread = SRead(cip->dataSocket, buf, bufSize, (int) cip->xferTimeout, kFullBufferNotRequired|kNoFirstSelect);
if (nread == kTimeoutErr) {
cip->errNo = result = kErrDataTimedOut;
Error(cip, kDontPerror, "Remote read timed out.\n");
break;
} else if (nread < 0) {
if ((gGotBrokenData != 0) || (errno == EPIPE)) {
result = cip->errNo = kErrSocketReadFailed;
errno = EPIPE;
Error(cip, kDoPerror, "Lost data connection to remote host.\n");
} else if (errno == EINTR) {
continue;
} else {
Error(cip, kDoPerror, "Remote read failed.\n");
result = kErrSocketReadFailed;
cip->errNo = kErrSocketReadFailed;
}
break;
} else if (nread == 0) {
break;
}
#else
gCanBrokenDataJmp = 1;
if (cip->xferTimeout > 0)
(void) alarm(cip->xferTimeout);
nread = read(cip->dataSocket, buf, bufSize);
if (nread < 0) {
if ((gGotBrokenData != 0) || (errno == EPIPE)) {
result = cip->errNo = kErrSocketReadFailed;
errno = EPIPE;
Error(cip, kDoPerror, "Lost data connection to remote host.\n");
} else if (errno == EINTR) {
continue;
} else {
result = cip->errNo = kErrSocketReadFailed;
Error(cip, kDoPerror, "Remote read failed.\n");
}
(void) shutdown(cip->dataSocket, 2);
break;
} else if (nread == 0) {
break;
}
gCanBrokenDataJmp = 0;
#endif /* NO_SIGNALS */
nwrote = write(fd, buf, nread);
if (nwrote != nread) {
if ((gGotBrokenData != 0) || (errno == EPIPE)) {
result = kErrWriteFailed;
cip->errNo = kErrWriteFailed;
errno = EPIPE;
} else {
Error(cip, kDoPerror, "Local write failed.\n");
result = kErrWriteFailed;
cip->errNo = kErrWriteFailed;
}
(void) shutdown(cip->dataSocket, 2);
break;
}
/* Ugggh... do this after each write operation
* so it minimizes the chance of a user killing
* the process before we reset the timestamps.
*/
if (mdtm != kModTimeUnknown) {
(void) utime(dstfile, &ut);
}
cip->bytesTransferred += (longest_int) nread;
FTPUpdateIOTimer(cip);
}
}
#if ASCII_TRANSLATION
brk:
#endif
#if !defined(NO_SIGNALS)
if (cip->xferTimeout > 0)
(void) alarm(0);
gCanBrokenDataJmp = 0;
#endif /* NO_SIGNALS */
if (fdtouse < 0) {
/* If they gave us a descriptor (fdtouse >= 0),
* leave it open, otherwise we opened it, so
* we need to close it.
*/
(void) close(fd);
fd = -1;
}
tmpResult = FTPEndDataCmd(cip, 1);
if ((tmpResult < 0) && (result == 0)) {
result = kErrRETRFailed;
cip->errNo = kErrRETRFailed;
}
FTPStopIOTimer(cip);
#if !defined(NO_SIGNALS)
(void) signal(SIGPIPE, (FTPSigProc) osigpipe);
#endif /* NO_SIGNALS */
if ((mdtm != kModTimeUnknown) && (cip->bytesTransferred > 0)) {
(void) utime(dstfile, &ut);
}
if (result == kNoErr) {
cip->numDownloads++;
if (deleteflag == kDeleteYes) {
result = FTPDelete(cip, file, kRecursiveNo, kGlobNo);
}
}
return (result);
} /* FTPGetOneF */
int
FTPGetOneFile3(
const FTPCIPtr cip,
const char *const file,
const char *const dstfile,
const int xtype,
const int fdtouse,
const int resumeflag,
const int appendflag,
const int deleteflag,
const ConfirmResumeDownloadProc resumeProc,
int UNUSED(reserved))
{
int result;
LIBNCFTP_USE_VAR(reserved);
if (cip == NULL)
return (kErrBadParameter);
if (strcmp(cip->magic, kLibraryMagic))
return (kErrBadMagic);
if ((file == NULL) || (file[0] == '\0'))
return (kErrBadParameter);
if (fdtouse < 0) {
if ((dstfile == NULL) || (ds
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -