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_gettar.c < prev    next >
C/C++ Source or Header  |  2005-01-01  |  8KB  |  358 lines

  1. /* io_gettar.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. #if (defined(WIN32) || defined(_WINDOWS)) && !defined(__CYGWIN__)
  14. #    define ASCII_TRANSLATION 0
  15. #endif
  16.  
  17. #ifndef ASCII_TRANSLATION
  18. #    define ASCII_TRANSLATION 1
  19. #endif
  20.  
  21. #ifndef NO_SIGNALS
  22. #    define NO_SIGNALS 1
  23. #endif
  24.  
  25. #ifndef O_BINARY
  26.     /* Needed for platforms using different EOLN sequence (i.e. DOS) */
  27. #    ifdef _O_BINARY
  28. #        define O_BINARY _O_BINARY
  29. #    else
  30. #        define O_BINARY 0
  31. #    endif
  32. #endif
  33.  
  34. /* Nice for UNIX, but not necessary otherwise. */
  35. #ifdef TAR
  36.  
  37. static int
  38. OpenTar(const FTPCIPtr cip, const char *const dstdir, int *const pid)
  39. {
  40.     int pipe1[2];
  41.     int pid1;
  42.     int i;
  43.     char *argv[8];
  44.  
  45.     *pid = -1;
  46.  
  47.     if (access(TAR, X_OK) < 0) {
  48.         /* Path to TAR is invalid. */
  49.         return (-1);
  50.     }
  51.  
  52.     if (pipe(pipe1) < 0) {
  53.         FTPLogError(cip, kDoPerror, "pipe to Tar failed");
  54.         return (-1);
  55.     }
  56.  
  57.     pid1 = (int) fork();
  58.     if (pid1 < 0) {
  59.         (void) close(pipe1[0]);
  60.         (void) close(pipe1[1]);
  61.         return (-1);
  62.     } else if (pid1 == 0) {
  63.         /* Child */
  64.         if ((dstdir != NULL) && (dstdir[0] != '\0') && (chdir(dstdir) < 0)) {
  65.             FTPLogError(cip, kDoPerror, "tar chdir to %s failed", dstdir);
  66.             exit(1);
  67.         }
  68.         (void) close(pipe1[1]);        /* close write end */
  69.         (void) dup2(pipe1[0], 0);    /* use read end on stdin */
  70.         (void) close(pipe1[0]);
  71.  
  72.         for (i=3; i<256; i++)
  73.             (void) close(i);
  74.  
  75.         argv[0] = strdup("tar");
  76.         argv[1] = strdup("xpf");
  77.         argv[2] = strdup("-");
  78.         argv[3] = NULL;
  79.  
  80.         (void) execv(TAR, argv);
  81.         exit(1);
  82.     }
  83.  
  84.     /* Parent */
  85.     *pid = pid1;
  86.  
  87.     (void) close(pipe1[0]);        /* close read end */
  88.     return (pipe1[1]);        /* use write end */
  89. }    /* OpenTar */
  90.  
  91.  
  92.  
  93.  
  94. int
  95. FTPGetOneTarF(const FTPCIPtr cip, const char *file, const char *const dstdir)
  96. {
  97.     char *buf;
  98.     size_t bufSize;
  99.     int tmpResult;
  100.     volatile int result;
  101.     read_return_t nread;
  102.     write_return_t nwrote;
  103.     volatile int fd;
  104.     volatile int vfd;
  105.     const char *volatile vfile;
  106. #ifndef NO_SIGNALS
  107.     int sj;
  108.     volatile FTPSigProc osigpipe;
  109.     volatile FTPCIPtr vcip;
  110. #endif
  111.     int pid, status;
  112.     char savedCwd[512];
  113.     char *volatile basecp;
  114.  
  115.     result = kNoErr;
  116.     cip->usingTAR = 0;
  117.  
  118.     if ((file[0] == '\0') || ((file[0] == '/') && (file[1] == '\0'))) {
  119.         /* It was "/"
  120.          * We can't do that, because "get /.tar"
  121.          * or "get .tar" does not work.
  122.          */
  123.         result = kErrOpenFailed;
  124.         cip->errNo = kErrOpenFailed;
  125.         return (result);
  126.     }
  127.  
  128.     if (FTPCmd(cip, "MDTM %s.tar", file) == 2) {
  129.         /* Better not use this method since there is
  130.          * no way to tell if the server would use the
  131.          * existing .tar or do a new one on the fly.
  132.          */
  133.         result = kErrOpenFailed;
  134.         cip->errNo = kErrOpenFailed;
  135.         return (result);
  136.     }
  137.  
  138.     basecp = strrchr(file, '/');
  139.     if (basecp != NULL)
  140.         basecp = strrchr(file, '\\');
  141.     if (basecp != NULL) {
  142.         /* Need to cd to the parent directory and get it
  143.          * from there.
  144.          */
  145.         if (FTPGetCWD(cip, savedCwd, sizeof(savedCwd)) != 0) {
  146.             result = kErrOpenFailed;
  147.             cip->errNo = kErrOpenFailed;
  148.             return (result);
  149.         }
  150.         result = FTPChdir(cip, file);
  151.         if (result != kNoErr) {
  152.             return (result);
  153.         }
  154.         result = FTPChdir(cip, "..");
  155.         if (result != kNoErr) {
  156.             (void) FTPChdir(cip, savedCwd);
  157.             return (result);
  158.         }
  159.         file = basecp + 1;
  160.     }
  161.  
  162.     fd = OpenTar(cip, dstdir, &pid);
  163.     if (fd < 0) {
  164.         result = kErrOpenFailed;
  165.         cip->errNo = kErrOpenFailed;
  166.         if (basecp != NULL)
  167.             (void) FTPChdir(cip, savedCwd);
  168.         return (result);
  169.     }
  170.  
  171.     vfd = fd;
  172.     vfile = file;
  173.  
  174. #ifndef NO_SIGNALS
  175.     vcip = cip;
  176.     osigpipe = (volatile FTPSigProc) signal(SIGPIPE, BrokenData);
  177.  
  178.     gGotBrokenData = 0;
  179.     gCanBrokenDataJmp = 0;
  180.  
  181. #ifdef HAVE_SIGSETJMP
  182.     sj = sigsetjmp(gBrokenDataJmp, 1);
  183. #else
  184.     sj = setjmp(gBrokenDataJmp);
  185. #endif    /* HAVE_SIGSETJMP */
  186.  
  187.     if (sj != 0) {
  188.         (void) signal(SIGPIPE, (FTPSigProc) osigpipe);
  189.         FTPShutdownHost(vcip);
  190.  
  191.         (void) signal(SIGPIPE, SIG_IGN);
  192.         (void) close(vfd);
  193.         for (;;) {
  194. #ifdef HAVE_WAITPID
  195.             if ((waitpid(pid, &status, 0) < 0) && (errno != EINTR))
  196.                 break;
  197. #else
  198.             if ((wait(&status) < 0) && (errno != EINTR))
  199.                 break;
  200. #endif
  201.             if (WIFEXITED(status) || WIFSIGNALED(status))
  202.                 break;        /* done */
  203.         }
  204.         if (basecp != NULL)
  205.             (void) FTPChdir(cip, savedCwd);
  206.         vcip->errNo = kErrRemoteHostClosedConnection;
  207.         return(vcip->errNo);
  208.     }
  209.     gCanBrokenDataJmp = 1;
  210.  
  211. #endif    /* NO_SIGNALS */
  212.  
  213.     tmpResult = FTPStartDataCmd(cip, kNetReading, kTypeBinary, (longest_int) 0, "RETR %s.tar", vfile);
  214.  
  215.     if (tmpResult < 0) {
  216.         result = tmpResult;
  217.         if (result == kErrGeneric)
  218.             result = kErrRETRFailed;
  219.         cip->errNo = result;
  220.  
  221. #ifndef NO_SIGNALS
  222.         (void) signal(SIGPIPE, SIG_IGN);
  223. #endif
  224.         (void) close(vfd);
  225.         for (;;) {
  226. #ifdef HAVE_WAITPID
  227.             if ((waitpid(pid, &status, 0) < 0) && (errno != EINTR))
  228.                 break;
  229. #else
  230.             if ((wait(&status) < 0) && (errno != EINTR))
  231.                 break;
  232. #endif
  233.             if (WIFEXITED(status) || WIFSIGNALED(status))
  234.                 break;        /* done */
  235.         }
  236.  
  237. #ifndef NO_SIGNALS
  238.         (void) signal(SIGPIPE, (FTPSigProc) osigpipe);
  239. #endif
  240.         if (basecp != NULL)
  241.             (void) FTPChdir(cip, savedCwd);
  242.         return (result);
  243.     }
  244.  
  245.     cip->usingTAR = 1;
  246.     buf = cip->buf;
  247.     bufSize = cip->bufSize;
  248.  
  249.     FTPInitIOTimer(cip);
  250.     cip->lname = vfile;    /* could be NULL */
  251.     cip->rname = vfile;
  252.     FTPStartIOTimer(cip);
  253.  
  254.     /* Binary */
  255.     for (;;) {
  256.         if (! WaitForRemoteInput(cip)) {    /* could set cancelXfer */
  257.             cip->errNo = result = kErrDataTimedOut;
  258.             FTPLogError(cip, kDontPerror, "Remote read timed out.\n");
  259.             break;
  260.         }
  261.         if (cip->cancelXfer > 0) {
  262.             FTPAbortDataTransfer(cip);
  263.             result = cip->errNo = kErrDataTransferAborted;
  264.             break;
  265.         }
  266. #if !defined(NO_SIGNALS)
  267.         gCanBrokenDataJmp = 1;
  268.         if (cip->xferTimeout > 0)
  269.             (void) alarm(cip->xferTimeout);
  270. #endif    /* NO_SIGNALS */
  271. #ifdef NO_SIGNALS
  272.         nread = (read_return_t) SRead(cip->dataSocket, buf, bufSize, (int) cip->xferTimeout, kFullBufferNotRequired|kNoFirstSelect);
  273.         if (nread == kTimeoutErr) {
  274.             cip->errNo = result = kErrDataTimedOut;
  275.             FTPLogError(cip, kDontPerror, "Remote read timed out.\n");
  276.             break;
  277.         } else if (nread < 0) {
  278.             if (errno == EINTR)
  279.                 continue;
  280.             FTPLogError(cip, kDoPerror, "Remote read failed.\n");
  281.             result = kErrSocketReadFailed;
  282.             cip->errNo = kErrSocketReadFailed;
  283.             break;
  284.         } else if (nread == 0) {
  285.             break;
  286.         }
  287. #else
  288.         nread = read(cip->dataSocket, buf, (read_size_t) bufSize);
  289.         if (nread < 0) {
  290.             if (errno == EINTR)
  291.                 continue;
  292.             FTPLogError(cip, kDoPerror, "Remote read failed.\n");
  293.             result = kErrSocketReadFailed;
  294.             cip->errNo = kErrSocketReadFailed;
  295.             break;
  296.         } else if (nread == 0) {
  297.             break;
  298.         }
  299.         gCanBrokenDataJmp = 0;
  300. #endif
  301.  
  302.         nwrote = write(fd, buf, (write_size_t) nread);
  303.         if (nwrote != nread) {
  304.             if (errno == EPIPE) {
  305.                 result = kErrWriteFailed;
  306.                 cip->errNo = kErrWriteFailed;
  307.                 errno = EPIPE;
  308.             } else {
  309.                 FTPLogError(cip, kDoPerror, "Local write failed.\n");
  310.                 result = kErrWriteFailed;
  311.                 cip->errNo = kErrWriteFailed;
  312.             }
  313.             break;
  314.         }
  315.         cip->bytesTransferred += (longest_int) nread;
  316.         FTPUpdateIOTimer(cip);
  317.     }
  318.  
  319. #if !defined(NO_SIGNALS)
  320.     if (cip->xferTimeout > 0)
  321.         (void) alarm(0);
  322.     gCanBrokenDataJmp = 0;
  323. #endif    /* NO_SIGNALS */
  324.  
  325.     (void) close(fd);
  326.     for (;;) {
  327. #ifdef HAVE_WAITPID
  328.         if ((waitpid(pid, &status, 0) < 0) && (errno != EINTR))
  329.             break;
  330. #else
  331.         if ((wait(&status) < 0) && (errno != EINTR))
  332.             break;
  333. #endif
  334.         if (WIFEXITED(status) || WIFSIGNALED(status))
  335.             break;        /* done */
  336.     }
  337.  
  338.     tmpResult = FTPEndDataCmd(cip, 1);
  339.     if ((tmpResult < 0) && (result == 0)) {
  340.         result = kErrRETRFailed;
  341.         cip->errNo = kErrRETRFailed;
  342.     }
  343.     FTPStopIOTimer(cip);
  344. #if !defined(NO_SIGNALS)
  345.     (void) signal(SIGPIPE, (FTPSigProc) osigpipe);
  346. #endif
  347.  
  348.     if ((result == 0) && (cip->bytesTransferred == 0)) {
  349.         result = kErrOpenFailed;
  350.         cip->errNo = kErrOpenFailed;
  351.     }
  352.     if (basecp != NULL)
  353.         (void) FTPChdir(cip, savedCwd);
  354.     return (result);
  355. }    /* FTPGetOneTarF */
  356.  
  357. #endif    /* TAR */
  358.