home *** CD-ROM | disk | FTP | other *** search
/ ftp.ncftp.com / ftp.ncftp.com.zip / ftp.ncftp.com / ncftp / older_versions / ncftp-3.2.2-src.tar.bz2 / ncftp-3.2.2-src.tar / ncftp-3.2.2 / libncftp / io_getmem.c < prev    next >
C/C++ Source or Header  |  2005-01-04  |  7KB  |  269 lines

  1. /* io_getmem.c
  2.  *
  3.  * Copyright (c) 1996-2005 Mike Gleason, NcFTP Software.
  4.  * All rights reserved.
  5.  *
  6.  */
  7.  
  8. #include "syshdrs.h"
  9. #ifdef PRAGMA_HDRSTOP
  10. #    pragma hdrstop
  11. #endif
  12.  
  13. #ifndef NO_SIGNALS
  14. #    define NO_SIGNALS 1
  15. #endif
  16.  
  17. int
  18. FTPGetFileToMemory(
  19.     const FTPCIPtr cip,
  20.     const char *const file,
  21.     char *memBuf,
  22.     const size_t maxNumberOfBytesToWriteToMemBuf,
  23.     size_t *const numberOfBytesWrittenToMemBuf,
  24.     const longest_int startPoint,
  25.     const int deleteflag
  26.     )
  27. {
  28.     int tmpResult;
  29.     volatile int result;
  30.     int atEOF;
  31.     longest_int expectedSize;
  32.     size_t ntoread;
  33.     read_return_t nread;
  34.     size_t numberOfBytesLeftInMemBuf;
  35. #if !defined(NO_SIGNALS)
  36.     volatile FTPSigProc osigpipe;
  37.     volatile FTPCIPtr vcip;
  38.     int sj;
  39. #endif    /* NO_SIGNALS */
  40.  
  41.     result = kNoErr;
  42.     atEOF = 1;
  43.     cip->usingTAR = 0;
  44.     numberOfBytesLeftInMemBuf = maxNumberOfBytesToWriteToMemBuf;
  45.     if (numberOfBytesWrittenToMemBuf != NULL)
  46.         *numberOfBytesWrittenToMemBuf = 0;
  47.         
  48.     if ((file == NULL) || (file[0] == '\0') || (memBuf == NULL) || (maxNumberOfBytesToWriteToMemBuf == 0)) {
  49.         return (kErrBadParameter);
  50.     }
  51.     
  52.     FTPCheckForRestartModeAvailability(cip); 
  53.     if ((startPoint != 0) && (cip->hasREST == kCommandNotAvailable)) {
  54.         cip->errNo = kErrRESTNotAvailable;
  55.         return (cip->errNo);
  56.     }
  57.  
  58.     (void) FTPFileSize(cip, file, &expectedSize, kTypeBinary);
  59.     if ((expectedSize != (longest_int) 0) && (startPoint > expectedSize)) {
  60.         /* Don't go to all the trouble of downloading nothing. */
  61.         if (deleteflag == kDeleteYes)
  62.             (void) FTPDelete(cip, file, kRecursiveNo, kGlobNo);
  63.         return (kNoErr);
  64.     }
  65.  
  66.     if ((cip->numDownloads == 0) && (cip->dataSocketRBufSize != 0)) {
  67.         /* If dataSocketSBufSize is non-zero, it means you
  68.          * want to explicitly try to set the size of the
  69.          * socket's I/O buffer.
  70.          *
  71.          * If it is zero, it means you want to just use the
  72.          * TCP stack's default value, which is typically
  73.          * between 8 and 64 kB.
  74.          *
  75.          * If you try to set the buffer larger than 64 kB,
  76.          * the TCP stack should try to use RFC 1323 to
  77.          * negotiate "TCP Large Windows" which may yield
  78.          * significant performance gains.
  79.          */
  80.         if (cip->hasSITE_RETRBUFSIZE == kCommandAvailable)
  81.             (void) FTPCmd(cip, "SITE RETRBUFSIZE %lu", (unsigned long) cip->dataSocketRBufSize);
  82.         else if (cip->hasSITE_RBUFSIZ == kCommandAvailable)
  83.             (void) FTPCmd(cip, "SITE RBUFSIZ %lu", (unsigned long) cip->dataSocketRBufSize);
  84.         else if (cip->hasSITE_RBUFSZ == kCommandAvailable)
  85.             (void) FTPCmd(cip, "SITE RBUFSZ %lu", (unsigned long) cip->dataSocketRBufSize);
  86.         else if (cip->hasSITE_BUFSIZE == kCommandAvailable)
  87.             (void) FTPCmd(cip, "SITE BUFSIZE %lu", (unsigned long) cip->dataSocketSBufSize);
  88.     }
  89.  
  90. #ifdef NO_SIGNALS
  91. #else    /* NO_SIGNALS */
  92.     vcip = cip;
  93.     osigpipe = (volatile FTPSigProc) signal(SIGPIPE, BrokenData);
  94.  
  95.     gGotBrokenData = 0;
  96.     gCanBrokenDataJmp = 0;
  97.  
  98. #ifdef HAVE_SIGSETJMP
  99.     sj = sigsetjmp(gBrokenDataJmp, 1);
  100. #else
  101.     sj = setjmp(gBrokenDataJmp);
  102. #endif    /* HAVE_SIGSETJMP */
  103.  
  104.     if (sj != 0) {
  105.         (void) signal(SIGPIPE, (FTPSigProc) osigpipe);
  106.         FTPShutdownHost(vcip);
  107.         vcip->errNo = kErrRemoteHostClosedConnection;
  108.         return(vcip->errNo);
  109.     }
  110.     gCanBrokenDataJmp = 1;
  111. #endif    /* NO_SIGNALS */
  112.  
  113.     tmpResult = FTPStartDataCmd(cip, kNetReading, kTypeBinary, startPoint, "RETR %s", file);
  114.  
  115.     if (tmpResult < 0) {
  116.         result = tmpResult;
  117.         if (result == kErrGeneric)
  118.             result = kErrRETRFailed;
  119.         cip->errNo = result;
  120. #if !defined(NO_SIGNALS)
  121.         (void) signal(SIGPIPE, (FTPSigProc) osigpipe);
  122. #endif    /* NO_SIGNALS */
  123.         return (result);
  124.     }
  125.  
  126.     if ((startPoint != 0) && (cip->startPoint == 0)) {
  127.         /* Remote could not or would not set the start offset
  128.          * to what we wanted.
  129.          */
  130.         cip->errNo = kErrSetStartPoint;
  131. #if !defined(NO_SIGNALS)
  132.         (void) signal(SIGPIPE, (FTPSigProc) osigpipe);
  133. #endif    /* NO_SIGNALS */
  134.         return (cip->errNo);
  135.     }
  136.  
  137.     FTPInitIOTimer(cip);
  138.     cip->expectedSize = expectedSize;
  139.     cip->lname = NULL;    /* could be NULL */
  140.     cip->rname = file;
  141.     FTPStartIOTimer(cip);
  142.  
  143.     /* Binary */
  144.     for (;;) {
  145.         if (! WaitForRemoteInput(cip)) {    /* could set cancelXfer */
  146.             cip->errNo = result = kErrDataTimedOut;
  147.             FTPLogError(cip, kDontPerror, "Remote read timed out.\n");
  148.             break;
  149.         }
  150.         if (cip->cancelXfer > 0) {
  151.             FTPAbortDataTransfer(cip);
  152.             result = cip->errNo = kErrDataTransferAborted;
  153.             break;
  154.         }
  155.  
  156.         ntoread = numberOfBytesLeftInMemBuf;
  157.         if (ntoread > cip->bufSize)
  158.             ntoread = cip->bufSize;    /* Break it up into blocks. */
  159.             
  160. #ifdef NO_SIGNALS
  161.         nread = (read_return_t) SRead(cip->dataSocket, memBuf, ntoread, (int) cip->xferTimeout, kFullBufferNotRequired|kNoFirstSelect);
  162.         if (nread == kTimeoutErr) {
  163.             cip->errNo = result = kErrDataTimedOut;
  164.             FTPLogError(cip, kDontPerror, "Remote read timed out.\n");
  165.             break;
  166.         } else if (nread < 0) {
  167.             if (errno == EPIPE) {
  168.                 result = cip->errNo = kErrSocketReadFailed;
  169.                 errno = EPIPE;
  170.                 FTPLogError(cip, kDoPerror, "Lost data connection to remote host.\n");
  171.             } else if (errno == EINTR) {
  172.                 continue;
  173.             } else {
  174.                 FTPLogError(cip, kDoPerror, "Remote read failed.\n");
  175.                 result = kErrSocketReadFailed;
  176.                 cip->errNo = kErrSocketReadFailed;
  177.             }
  178.             break;
  179.         } else if (nread == 0) {
  180.             break;
  181.         }
  182. #else            
  183.         gCanBrokenDataJmp = 1;
  184.         if (cip->xferTimeout > 0)
  185.             (void) alarm(cip->xferTimeout);
  186.         nread = read(cip->dataSocket, memBuf, (read_size_t) ntoread);
  187.         if (nread < 0) {
  188.             if ((gGotBrokenData != 0) || (errno == EPIPE)) {
  189.                 result = cip->errNo = kErrSocketReadFailed;
  190.                 errno = EPIPE;
  191.                 FTPLogError(cip, kDoPerror, "Lost data connection to remote host.\n");
  192.             } else if (errno == EINTR) {
  193.                 continue;
  194.             } else {
  195.                 result = cip->errNo = kErrSocketReadFailed;
  196.                 FTPLogError(cip, kDoPerror, "Remote read failed.\n");
  197.             }
  198.             (void) shutdown(cip->dataSocket, 2);
  199.             break;
  200.         } else if (nread == 0) {
  201.             /* At EOF. */
  202.             break;
  203.         }
  204.         gCanBrokenDataJmp = 0;
  205. #endif    /* NO_SIGNALS */
  206.  
  207.         memBuf += nread;
  208.         if (numberOfBytesWrittenToMemBuf != NULL)
  209.             *numberOfBytesWrittenToMemBuf += (size_t) nread;
  210.         cip->bytesTransferred += (longest_int) nread;
  211.         FTPUpdateIOTimer(cip);
  212.         
  213.         if ((size_t) nread > numberOfBytesLeftInMemBuf) {
  214.             /* assertion failure */
  215.             result = cip->errNo = kErrBugInLibrary;
  216.             break;
  217.         }
  218.         
  219.         numberOfBytesLeftInMemBuf -= nread;
  220.         if (numberOfBytesLeftInMemBuf == 0) {
  221.             /* Done (but maybe not at EOF of remote file). */
  222.             atEOF = 0;
  223.             if ((cip->bytesTransferred + startPoint) == expectedSize)
  224.                 atEOF = 1;
  225.             break;
  226.         }
  227.     }
  228.  
  229. #if !defined(NO_SIGNALS)
  230.     if (cip->xferTimeout > 0)
  231.         (void) alarm(0);
  232.     gCanBrokenDataJmp = 0;
  233. #endif    /* NO_SIGNALS */
  234.  
  235.     /* If there hasn't been an error, and you limited
  236.     * the number of bytes, we need to abort the
  237.     * remaining data.
  238.     */
  239.     if ((result == kNoErr) && (atEOF == 0)) {
  240.         FTPAbortDataTransfer(cip);
  241.         tmpResult = FTPEndDataCmd(cip, 1);
  242.         if ((tmpResult < 0) && (result == 0) && (tmpResult != kErrDataTransferFailed)) {
  243.             result = kErrRETRFailed;
  244.             cip->errNo = kErrRETRFailed;
  245.         }
  246.     } else {
  247.         tmpResult = FTPEndDataCmd(cip, 1);
  248.         if ((tmpResult < 0) && (result == 0)) {
  249.             result = kErrRETRFailed;
  250.             cip->errNo = kErrRETRFailed;
  251.         }
  252.     }
  253.  
  254.     FTPStopIOTimer(cip);
  255. #if !defined(NO_SIGNALS)
  256.     (void) signal(SIGPIPE, (FTPSigProc) osigpipe);
  257. #endif    /* NO_SIGNALS */
  258.  
  259.     if (result == kNoErr) {
  260.         cip->numDownloads++;
  261.  
  262.         if (deleteflag == kDeleteYes) {
  263.             result = FTPDelete(cip, file, kRecursiveNo, kGlobNo);
  264.         }
  265.     }
  266.  
  267.     return (result);
  268. }    /* FTPGetOneF */
  269.