void CommandShell(void) { int tUsed, bUsed; ArgvInfo ai; char prompt[64]; char *lineRead; #if defined(WIN32) || defined(_WINDOWS) #else int sj; #endif time_t cmdStart, cmdStop; /* Execution may jump back to this point to restart the shell. */ #if defined(WIN32) || defined(_WINDOWS) #elif defined(HAVE_SIGSETJMP) sj = sigsetjmp(gBackToTopJmp, 1); #else /* HAVE_SIGSETJMP */ sj = setjmp(gBackToTopJmp); #endif /* HAVE_SIGSETJMP */ #if defined(WIN32) || defined(_WINDOWS) #else if (sj != 0) { Trace(0, "Caught signal %d, back at top.\n", gGotSig); if (gGotSig == SIGALRM) { (void) printf("\nRemote host was not responding, closing down the session."); FTPShutdownHost(&gConn); } else{ (void) printf("\nInterrupted.\n"); if (gCancelCtrl != 0) { gCancelCtrl = 0; (void) printf("Closing down the current FTP session: "); FTPShutdownHost(&gConn); (void) sleep(1); (void) printf("done.\n"); } } } gMayBackToTopJmp = 1; #endif ++gEventNumber; while (gDoneApplication == 0) { #if defined(WIN32) || defined(_WINDOWS) #else (void) NcSignal(SIGINT, BackToTop); (void) NcSignal(SIGPIPE, BackToTop); (void) NcSignal(SIGALRM, BackToTop); #endif MakePrompt(prompt, sizeof(prompt)); if (gConn.connected == 0) { SetXtermTitle("DEFAULT"); } else { SetXtermTitle("%s - NcFTP", gConn.host); } lineRead = Readline(prompt); if (lineRead == NULL) { /* EOF, Control-D */ (void) printf("\n"); break; } Trace(0, "> %s\n", lineRead); AddHistory(lineRead); for (tUsed = 0;;) { (void) memset(&ai, 0, sizeof(ai)); bUsed = MakeArgv(lineRead + tUsed, &ai.cargc, ai.cargv, (int) (sizeof(ai.cargv) / sizeof(char *)), ai.argbuf, sizeof(ai.argbuf), ai.noglobargv, 0); if (bUsed <= 0) break; tUsed += bUsed; if (ai.cargc == 0) continue; gRunningCommand = 1; (void) time(&cmdStart); if (DoCommand(&ai) < 0) { (void) time(&cmdStop); gRunningCommand = 0; break; } (void) time(&cmdStop); gRunningCommand = 0; if ((cmdStop - cmdStart) > kBeepAfterCmdTime) { /* Let the user know that a time-consuming * operation has completed. */ #if defined(WIN32) || defined(_WINDOWS) MessageBeep(MB_OK); #else (void) fprintf(stderr, "\007"); #endif } ++gEventNumber; } free(lineRead); } CloseHost(); gMayBackToTopJmp = 0; } /* Shell */
int FTPPutFileFromMemory( const FTPCIPtr cip, const char *volatile dstfile, const char *volatile src, const size_t srcLen, const int appendflag) { const char *cp; const char *cmd; int tmpResult, result; read_return_t nread; write_return_t nwrote; size_t bufSize; const char *srcLim; const char *volatile srcp; #if !defined(NO_SIGNALS) int sj; volatile FTPSigProc osigpipe; volatile FTPCIPtr vcip; #endif /* NO_SIGNALS */ if (cip->buf == NULL) { FTPLogError(cip, kDoPerror, "Transfer buffer not allocated.\n"); cip->errNo = kErrNoBuf; return (cip->errNo); } cip->usingTAR = 0; /* For Put, we can't recover very well if it turns out restart * didn't work, so check beforehand. */ FTPCheckForRestartModeAvailability(cip); FTPSetUploadSocketBufferSize(cip); #ifdef NO_SIGNALS #else /* NO_SIGNALS */ vcip = cip; 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); FTPShutdownHost(vcip); vcip->errNo = kErrRemoteHostClosedConnection; return(vcip->errNo); } gCanBrokenDataJmp = 1; #endif /* NO_SIGNALS */ cmd = appendflag == kAppendYes ? "APPE" : "STOR"; tmpResult = FTPStartDataCmd( cip, kNetWriting, kTypeBinary, (longest_int) 0, "%s %s", cmd, dstfile ); if (tmpResult < 0) { cip->errNo = tmpResult; #if !defined(NO_SIGNALS) (void) signal(SIGPIPE, (FTPSigProc) osigpipe); #endif /* NO_SIGNALS */ return (cip->errNo); } result = kNoErr; bufSize = cip->bufSize; FTPInitIOTimer(cip); cip->expectedSize = (longest_int) srcLen; cip->lname = NULL; /* could be NULL */ cip->rname = dstfile; srcp = src; srcLim = src + srcLen; FTPStartIOTimer(cip); { /* binary */ for (;;) { #if !defined(NO_SIGNALS) gCanBrokenDataJmp = 0; #endif /* NO_SIGNALS */ nread = (read_return_t) bufSize; if ((size_t) (srcLim - srcp) < bufSize) { nread = (read_return_t) (srcLim - srcp); if (nread == 0) { result = kNoErr; break; } } cip->bytesTransferred += (longest_int) nread; cp = srcp; srcp += 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; FTPLogError(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 = (write_return_t) SWrite(cip->dataSocket, cp, (size_t) nread, (int) cip->xferTimeout, kNoFirstSelect); if (nwrote < 0) { if (nwrote == kTimeoutErr) { cip->errNo = result = kErrDataTimedOut; FTPLogError(cip, kDontPerror, "Remote write timed out.\n"); } else if (errno == EPIPE) { cip->errNo = result = kErrSocketWriteFailed; errno = EPIPE; FTPLogError(cip, kDoPerror, "Lost data connection to remote host.\n"); } else if (errno == EINTR) { continue; } else { cip->errNo = result = kErrSocketWriteFailed; FTPLogError(cip, kDoPerror, "Remote write failed.\n"); } (void) shutdown(cip->dataSocket, 2); goto brk; } #else /* NO_SIGNALS */ nwrote = write(cip->dataSocket, cp, (write_size_t) nread); if (nwrote < 0) { if ((gGotBrokenData != 0) || (errno == EPIPE)) { cip->errNo = result = kErrSocketWriteFailed; errno = EPIPE; FTPLogError(cip, kDoPerror, "Lost data connection to remote host.\n"); } else if (errno == EINTR) { continue; } else { cip->errNo = result = kErrSocketWriteFailed; FTPLogError(cip, kDoPerror, "Remote write failed.\n"); } (void) shutdown(cip->dataSocket, 2); goto brk; } #endif /* NO_SIGNALS */ cp += nwrote; nread -= nwrote; } while (nread > 0); FTPUpdateIOTimer(cip); } } brk: /* 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 (we know this * when the socket is ready for * reading an EOF), which tells * us that the file was completed. */ (void) shutdown(cip->dataSocket, 1); (void) WaitForRemoteInput(cip); #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 (result == kNoErr) { /* The store succeeded; If we were * uploading to a temporary file, * move the new file to the new name. */ cip->numUploads++; } #if !defined(NO_SIGNALS) (void) signal(SIGPIPE, (FTPSigProc) osigpipe); #endif /* NO_SIGNALS */ return (result); } /* FTPPutFileFromMemory */
int FTPGetFileToMemory( const FTPCIPtr cip, const char *const file, char *memBuf, const size_t maxNumberOfBytesToWriteToMemBuf, size_t *const numberOfBytesWrittenToMemBuf, const longest_int startPoint, const int deleteflag ) { int tmpResult; volatile int result; int atEOF; longest_int expectedSize; size_t ntoread; read_return_t nread; size_t numberOfBytesLeftInMemBuf; #if !defined(NO_SIGNALS) volatile FTPSigProc osigpipe; volatile FTPCIPtr vcip; int sj; #endif /* NO_SIGNALS */ result = kNoErr; atEOF = 1; cip->usingTAR = 0; numberOfBytesLeftInMemBuf = maxNumberOfBytesToWriteToMemBuf; if (numberOfBytesWrittenToMemBuf != NULL) *numberOfBytesWrittenToMemBuf = 0; if ((file == NULL) || (file[0] == '\0') || (memBuf == NULL) || (maxNumberOfBytesToWriteToMemBuf == 0)) { return (kErrBadParameter); } FTPCheckForRestartModeAvailability(cip); if ((startPoint != 0) && (cip->hasREST == kCommandNotAvailable)) { cip->errNo = kErrRESTNotAvailable; return (cip->errNo); } (void) FTPFileSize(cip, file, &expectedSize, kTypeBinary); if ((expectedSize != (longest_int) 0) && (startPoint > expectedSize)) { /* Don't go to all the trouble of downloading nothing. */ if (deleteflag == kDeleteYes) (void) FTPDelete(cip, file, kRecursiveNo, kGlobNo); return (kNoErr); } 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->hasSITE_RETRBUFSIZE == kCommandAvailable) (void) FTPCmd(cip, "SITE RETRBUFSIZE %lu", (unsigned long) cip->dataSocketRBufSize); else if (cip->hasSITE_RBUFSIZ == kCommandAvailable) (void) FTPCmd(cip, "SITE RBUFSIZ %lu", (unsigned long) cip->dataSocketRBufSize); else if (cip->hasSITE_RBUFSZ == kCommandAvailable) (void) FTPCmd(cip, "SITE RBUFSZ %lu", (unsigned long) cip->dataSocketRBufSize); else if (cip->hasSITE_BUFSIZE == kCommandAvailable) (void) FTPCmd(cip, "SITE BUFSIZE %lu", (unsigned long) cip->dataSocketSBufSize); } #ifdef NO_SIGNALS #else /* NO_SIGNALS */ vcip = cip; 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); FTPShutdownHost(vcip); vcip->errNo = kErrRemoteHostClosedConnection; return(vcip->errNo); } gCanBrokenDataJmp = 1; #endif /* NO_SIGNALS */ tmpResult = FTPStartDataCmd(cip, kNetReading, kTypeBinary, startPoint, "RETR %s", file); if (tmpResult < 0) { result = tmpResult; if (result == kErrGeneric) result = kErrRETRFailed; cip->errNo = result; #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. */ cip->errNo = kErrSetStartPoint; #if !defined(NO_SIGNALS) (void) signal(SIGPIPE, (FTPSigProc) osigpipe); #endif /* NO_SIGNALS */ return (cip->errNo); } FTPInitIOTimer(cip); cip->expectedSize = expectedSize; cip->lname = NULL; /* could be NULL */ cip->rname = file; FTPStartIOTimer(cip); /* Binary */ for (;;) { if (! WaitForRemoteInput(cip)) { /* could set cancelXfer */ cip->errNo = result = kErrDataTimedOut; FTPLogError(cip, kDontPerror, "Remote read timed out.\n"); break; } if (cip->cancelXfer > 0) { FTPAbortDataTransfer(cip); result = cip->errNo = kErrDataTransferAborted; break; } ntoread = numberOfBytesLeftInMemBuf; if (ntoread > cip->bufSize) ntoread = cip->bufSize; /* Break it up into blocks. */ #ifdef NO_SIGNALS nread = (read_return_t) SRead(cip->dataSocket, memBuf, ntoread, (int) cip->xferTimeout, kFullBufferNotRequired|kNoFirstSelect); if (nread == kTimeoutErr) { cip->errNo = result = kErrDataTimedOut; FTPLogError(cip, kDontPerror, "Remote read timed out.\n"); break; } else if (nread < 0) { if (errno == EPIPE) { result = cip->errNo = kErrSocketReadFailed; errno = EPIPE; FTPLogError(cip, kDoPerror, "Lost data connection to remote host.\n"); } else if (errno == EINTR) { continue; } else { FTPLogError(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, memBuf, (read_size_t) ntoread); if (nread < 0) { if ((gGotBrokenData != 0) || (errno == EPIPE)) { result = cip->errNo = kErrSocketReadFailed; errno = EPIPE; FTPLogError(cip, kDoPerror, "Lost data connection to remote host.\n"); } else if (errno == EINTR) { continue; } else { result = cip->errNo = kErrSocketReadFailed; FTPLogError(cip, kDoPerror, "Remote read failed.\n"); } (void) shutdown(cip->dataSocket, 2); break; } else if (nread == 0) { /* At EOF. */ break; } gCanBrokenDataJmp = 0; #endif /* NO_SIGNALS */ memBuf += nread; if (numberOfBytesWrittenToMemBuf != NULL) *numberOfBytesWrittenToMemBuf += (size_t) nread; cip->bytesTransferred += (longest_int) nread; FTPUpdateIOTimer(cip); if ((size_t) nread > numberOfBytesLeftInMemBuf) { /* assertion failure */ result = cip->errNo = kErrBugInLibrary; break; } numberOfBytesLeftInMemBuf -= nread; if (numberOfBytesLeftInMemBuf == 0) { /* Done (but maybe not at EOF of remote file). */ atEOF = 0; if ((cip->bytesTransferred + startPoint) == expectedSize) atEOF = 1; break; } } #if !defined(NO_SIGNALS) if (cip->xferTimeout > 0) (void) alarm(0); gCanBrokenDataJmp = 0; #endif /* NO_SIGNALS */ /* If there hasn't been an error, and you limited * the number of bytes, we need to abort the * remaining data. */ if ((result == kNoErr) && (atEOF == 0)) { FTPAbortDataTransfer(cip); tmpResult = FTPEndDataCmd(cip, 1); if ((tmpResult < 0) && (result == 0) && (tmpResult != kErrDataTransferFailed)) { result = kErrRETRFailed; cip->errNo = kErrRETRFailed; } } else { 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 (result == kNoErr) { cip->numDownloads++; if (deleteflag == kDeleteYes) { result = FTPDelete(cip, file, kRecursiveNo, kGlobNo); } } return (result); } /* FTPGetOneF */