PageRenderTime 40ms CodeModel.GetById 14ms RepoModel.GetById 0ms app.codeStats 0ms

/ncftp-3.2.5/libncftp/io_gettar.c

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