📄 io.c
字号:
#if ASCII_TRANSLATION
if (xtype == kTypeAscii) {
/* ascii */
for (;;) {
#if !defined(NO_SIGNALS)
gCanBrokenDataJmp = 0;
#endif /* NO_SIGNALS */
nread = read(fd, inbuf, sizeof(inbuf));
if (nread < 0) {
if (errno == EINTR) {
continue;
} else {
result = kErrReadFailed;
cip->errNo = kErrReadFailed;
Error(cip, kDoPerror, "Local read failed.\n");
}
break;
} else if (nread == 0) {
break;
}
cip->bytesTransferred += (longest_int) nread;
#if !defined(NO_SIGNALS)
gCanBrokenDataJmp = 1;
#endif /* NO_SIGNALS */
src = inbuf;
srclim = src + nread;
dst = cip->buf; /* must be 2x sizeof inbuf or more. */
while (src < srclim) {
if (*src == '\n')
*dst++ = '\r';
*dst++ = *src++;
}
ntowrite = (size_t) (dst - cip->buf);
cp = cip->buf;
#if !defined(NO_SIGNALS)
if (cip->xferTimeout > 0)
(void) alarm(cip->xferTimeout);
#endif /* NO_SIGNALS */
do {
if (! WaitForRemoteOutput(cip)) { /* could set cancelXfer */
cip->errNo = result = kErrDataTimedOut;
Error(cip, kDontPerror, "Remote write timed out.\n");
goto brk;
}
if (cip->cancelXfer > 0) {
FTPAbortDataTransfer(cip);
result = cip->errNo = kErrDataTransferAborted;
goto brk;
}
#ifdef NO_SIGNALS
nwrote = SWrite(cip->dataSocket, cp, (size_t) ntowrite, (int) cip->xferTimeout, kNoFirstSelect);
if (nwrote < 0) {
if (nwrote == kTimeoutErr) {
cip->errNo = result = kErrDataTimedOut;
Error(cip, kDontPerror, "Remote write timed out.\n");
} else if ((gGotBrokenData != 0) || (errno == EPIPE)) {
cip->errNo = result = kErrSocketWriteFailed;
errno = EPIPE;
Error(cip, kDoPerror, "Lost data connection to remote host.\n");
} else if (errno == EINTR) {
continue;
} else {
cip->errNo = result = kErrSocketWriteFailed;
Error(cip, kDoPerror, "Remote write failed.\n");
}
(void) shutdown(cip->dataSocket, 2);
goto brk;
}
#else /* NO_SIGNALS */
nwrote = write(cip->dataSocket, cp, ntowrite);
if (nwrote < 0) {
if ((gGotBrokenData != 0) || (errno == EPIPE)) {
cip->errNo = result = kErrSocketWriteFailed;
errno = EPIPE;
Error(cip, kDoPerror, "Lost data connection to remote host.\n");
} else if (errno == EINTR) {
continue;
} else {
cip->errNo = result = kErrSocketWriteFailed;
Error(cip, kDoPerror, "Remote write failed.\n");
}
(void) shutdown(cip->dataSocket, 2);
goto brk;
}
#endif /* NO_SIGNALS */
cp += nwrote;
ntowrite -= nwrote;
} while (ntowrite > 0);
FTPUpdateIOTimer(cip);
}
} else
#endif /* ASCII_TRANSLATION */
{
/* binary */
for (;;) {
#if !defined(NO_SIGNALS)
gCanBrokenDataJmp = 0;
#endif /* NO_SIGNALS */
cp = buf;
nread = read(fd, cp, bufSize);
if (nread < 0) {
if (errno == EINTR) {
continue;
} else {
result = kErrReadFailed;
cip->errNo = kErrReadFailed;
Error(cip, kDoPerror, "Local read failed.\n");
}
break;
} else if (nread == 0) {
break;
}
cip->bytesTransferred += (longest_int) nread;
#if !defined(NO_SIGNALS)
gCanBrokenDataJmp = 1;
if (cip->xferTimeout > 0)
(void) alarm(cip->xferTimeout);
#endif /* NO_SIGNALS */
do {
if (! WaitForRemoteOutput(cip)) { /* could set cancelXfer */
cip->errNo = result = kErrDataTimedOut;
Error(cip, kDontPerror, "Remote write timed out.\n");
goto brk;
}
if (cip->cancelXfer > 0) {
FTPAbortDataTransfer(cip);
result = cip->errNo = kErrDataTransferAborted;
goto brk;
}
#ifdef NO_SIGNALS
nwrote = SWrite(cip->dataSocket, cp, (size_t) nread, (int) cip->xferTimeout, kNoFirstSelect);
if (nwrote < 0) {
if (nwrote == kTimeoutErr) {
cip->errNo = result = kErrDataTimedOut;
Error(cip, kDontPerror, "Remote write timed out.\n");
} else if ((gGotBrokenData != 0) || (errno == EPIPE)) {
cip->errNo = result = kErrSocketWriteFailed;
errno = EPIPE;
Error(cip, kDoPerror, "Lost data connection to remote host.\n");
} else if (errno == EINTR) {
continue;
} else {
cip->errNo = result = kErrSocketWriteFailed;
Error(cip, kDoPerror, "Remote write failed.\n");
}
(void) shutdown(cip->dataSocket, 2);
cip->dataSocket = -1;
goto brk;
}
#else /* NO_SIGNALS */
nwrote = write(cip->dataSocket, cp, nread);
if (nwrote < 0) {
if ((gGotBrokenData != 0) || (errno == EPIPE)) {
cip->errNo = result = kErrSocketWriteFailed;
errno = EPIPE;
Error(cip, kDoPerror, "Lost data connection to remote host.\n");
} else if (errno == EINTR) {
continue;
} else {
cip->errNo = result = kErrSocketWriteFailed;
Error(cip, kDoPerror, "Remote write failed.\n");
}
(void) shutdown(cip->dataSocket, 2);
cip->dataSocket = -1;
goto brk;
}
#endif /* NO_SIGNALS */
cp += nwrote;
nread -= nwrote;
} while (nread > 0);
FTPUpdateIOTimer(cip);
}
}
brk:
if (fdtouse < 0) {
(void) Fstat(fd, &st);
}
if (fdtouse < 0) {
if (shutdown(fd, 1) == 0) {
/* This looks very bizarre, since
* we will be checking the socket
* for readability here!
*
* The reason for this is that we
* want to be able to timeout a
* small put. So, we close the
* write end of the socket first,
* which tells the server we're
* done writing. We then wait
* for the server to close down
* the whole socket, which tells
* us that the file was completed.
*/
(void) WaitForRemoteInput(cip); /* Close could block. */
}
}
#if !defined(NO_SIGNALS)
gCanBrokenDataJmp = 0;
if (cip->xferTimeout > 0)
(void) alarm(0);
#endif /* NO_SIGNALS */
tmpResult = FTPEndDataCmd(cip, 1);
if ((tmpResult < 0) && (result == kNoErr)) {
cip->errNo = result = kErrSTORFailed;
}
FTPStopIOTimer(cip);
if (fdtouse < 0) {
/* If they gave us a descriptor (fdtouse >= 0),
* leave it open, otherwise we opened it, so
* we need to dispose of it.
*/
(void) close(fd);
fd = -1;
}
if (result == kNoErr) {
/* The store succeeded; If we were
* uploading to a temporary file,
* move the new file to the new name.
*/
cip->numUploads++;
if ((tmppfx[0] != '\0') || (tmpsfx[0] != '\0')) {
if ((result = FTPRename(cip, dstfile, odstfile)) < 0) {
/* May fail if file was already there,
* so delete the old one so we can move
* over it.
*/
if (FTPDelete(cip, odstfile, kRecursiveNo, kGlobNo) == kNoErr) {
result = FTPRename(cip, dstfile, odstfile);
if (result < 0) {
Error(cip, kDontPerror, "Could not rename %s to %s: %s.\n", dstfile, odstfile, FTPStrError(cip->errNo));
}
} else {
Error(cip, kDontPerror, "Could not delete old %s, so could not rename %s to that: %s\n", odstfile, dstfile, FTPStrError(cip->errNo));
}
}
}
if (FTPUtime(cip, odstfile, st.st_atime, st.st_mtime, st.st_ctime) != kNoErr) {
if (cip->errNo != kErrUTIMENotAvailable)
Error(cip, kDontPerror, "Could not preserve times for %s: %s.\n", odstfile, FTPStrError(cip->errNo));
}
if (deleteflag == kDeleteYes) {
if (unlink(file) < 0) {
result = cip->errNo = kErrLocalDeleteFailed;
}
}
}
#if !defined(NO_SIGNALS)
(void) signal(SIGPIPE, (FTPSigProc) osigpipe);
#endif /* NO_SIGNALS */
return (result);
} /* FTPPutOneF */
int
FTPPutOneFile3(
const FTPCIPtr cip,
const char *const file,
const char *const dstfile,
const int xtype,
const int fdtouse,
const int appendflag,
const char *const tmppfx,
const char *const tmpsfx,
const int resumeflag,
const int deleteflag,
const ConfirmResumeUploadProc resumeProc,
int UNUSED(reserved))
{
int result;
LIBNCFTP_USE_VAR(reserved);
if (cip == NULL)
return (kErrBadParameter);
if (strcmp(cip->magic, kLibraryMagic))
return (kErrBadMagic);
if ((dstfile == NULL) || (dstfile[0] == '\0'))
return (kErrBadParameter);
if (fdtouse < 0) {
if ((file == NULL) || (file[0] == '\0'))
return (kErrBadParameter);
}
result = FTPPutOneF(cip, file, dstfile, xtype, fdtouse, appendflag, tmppfx, tmpsfx, resumeflag, deleteflag, resumeProc);
return (result);
} /* FTPPutOneFile3 */
int
FTPPutFiles3(
const FTPCIPtr cip,
const char *const pattern,
const char *const dstdir1,
const int recurse,
const int doGlob,
const int xtype,
int appendflag,
const char *const tmppfx,
const char *const tmpsfx,
const int resumeflag,
const int deleteflag,
const ConfirmResumeUploadProc resumeProc,
int UNUSED(reserved))
{
LineList globList;
FileInfoList files;
FileInfoPtr filePtr;
int batchResult;
int result;
const char *dstdir;
char dstdir2[512];
LIBNCFTP_USE_VAR(reserved);
if (cip == NULL)
return (kErrBadParameter);
if (strcmp(cip->magic, kLibraryMagic))
return (kErrBadMagic);
if (dstdir1 == NULL) {
dstdir = NULL;
} else {
dstdir = STRNCPY(dstdir2, dstdir1);
StrRemoveTrailingLocalPathDelim(dstdir2);
}
(void) FTPLocalGlob(cip, &globList, pattern, doGlob);
if (recurse == kRecursiveYes) {
appendflag = kAppendNo;
(void) FTPLocalRecursiveFileList(cip, &globList, &files);
if (files.first == NULL) {
cip->errNo = kErrNoValidFilesSpecified;
return (kErrNoValidFilesSpecified);
}
(void) ComputeRNames(&files, dstdir, 0, 1);
} else {
(void) LineListToFileInfoList(&globList, &files);
(void) ComputeLNames(&files, NULL, NULL, 1);
(void) ComputeRNames(&files, dstdir, 0, 0);
}
DisposeLineListContents(&globList);
#if 0
for (filePtr = files.first; filePtr != NULL; filePtr = filePtr->next) {
PrintF(cip, " R=%s, L=%s, 2=%s, size=%d, mdtm=%u, type=%c\n",
filePtr->rname,
filePtr->lname,
filePtr->rlinkto ? filePtr->rlinkto : "",
filePtr->size,
(unsigned int) filePtr->mdtm,
filePtr->type
);
}
#endif
batchResult = kNoErr;
for (filePtr = files.first; filePtr != NULL; filePtr = filePtr->next) {
if (cip->connected == 0) {
if (batchResult == kNoErr)
batchResult = kErrRemoteHostClosedConnection;
break;
}
if (filePtr->type == 'd') {
/* mkdir */
StrRemoveTrailingLocalPathDelim(filePtr->rname);
result = FTPMkdir(cip, filePtr->rname, kRecursiveNo);
if (result != kNoErr)
batchResult = result;
#ifdef HAVE_SYMLINK
} else if (filePtr->type == 'l') {
/* symlink */
/* no RFC way to create the link, though. */
if ((filePtr->rlinkto != NULL) && (filePtr->rlinkto[0] != '\0'))
(void) FTPSymlink(cip, filePtr->rname, filePtr->rlinkto);
#endif
} else if (recurse != kRecursiveYes) {
result = FTPPutOneF(cip, filePtr->lname, filePtr->rname, xtype, -1, appendflag, tmppfx, tmpsfx, resumeflag, deleteflag, resumeProc);
if (files.nFileInfos == 1) {
if (result != kNoErr)
batchResult = result;
} else {
if ((result != kNoErr) && (result != kErrLocalFileNewer) && (result != kErrRemoteFileNewer) && (result != kErrLocalSameAsRemote))
batchResult = result;
}
if (result == kErrUserCanceled)
cip->cancelXfer = 1;
if (cip->cancelXfer > 0)
break;
} else {
result = FTPPutOneF(cip, filePtr->lname, filePtr->rname, xtype, -1, appendflag, tmppfx, tmpsfx, resumeflag, deleteflag, resumeProc);
if (files.nFileInfos == 1) {
if (result != kNoErr)
batchResult = result;
} else {
if ((result != kNoErr) && (result != kErrLocalFileNewer) && (result != kErrRemoteFileNewer) && (result != kErrLocalSameAsRemote))
batchResult = result;
}
if (result == kErrUserCanceled)
cip->cancelXfer = 1;
if (cip->cancelXfer > 0)
break;
}
}
DisposeFileInfoListContents(&files);
if (batchResult < 0)
cip->errNo = batchResult;
return (batchResult);
} /* FTPPutFiles3 */
/* The purpose of this is to provide updates for the progress meters
* during lags. Return zero if the operation timed-out.
*/
static int
WaitForRemoteInput(const FTPCIPtr cip)
{
fd_set ss, ss2;
struct timeval tv;
int result;
int fd;
int wsecs;
int xferTimeout;
int ocancelXfer;
xferTimeout = cip->xferTimeout;
if (xferTimeout < 1)
return (1);
fd = cip->dataSocket;
if (fd < 0)
return (1);
ocancelXfer = cip->cancelXfer;
wsecs = 0;
cip->stalled = 0;
while ((xferTimeout <= 0) || (wsecs < xferTimeout)) {
if ((cip->cancelXfer != 0) && (ocancelXfer == 0)) {
/* leave cip->stalled -- could have been stalled and then canceled. */
return (1);
}
FD_ZERO(&ss);
FD_SET(fd, &ss);
ss2 = ss;
tv.tv_sec = 1;
tv.tv_usec = 0;
result = select(fd + 1, SELECT_TYPE_ARG234 &ss, NULL, SELECT_TYPE_ARG234 &ss2, &tv);
if (result == 1) {
/* ready */
cip->stalled = 0;
return (1);
} else if (result < 0) {
if (result != EINTR) {
perror("select");
cip->stalled = 0;
return (1);
}
} else {
wsecs++;
cip->stalled = wsecs;
}
FTPUpdateIOTimer(cip);
}
#if !defined(NO_SIGNALS)
/* Shouldn't get here -- alarm() should have
* went off by now.
*/
(void) kill(getpid(), SIGALRM);
#endif /* NO_SIGNALS */
cip->dataTimedOut = 1;
return (0); /* timed-out */
} /* WaitForRemoteInput */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -