PageRenderTime 41ms CodeModel.GetById 23ms app.highlight 15ms RepoModel.GetById 1ms 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
  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
 37static int
 38OpenTar(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
 94int
 95FTPGetOneTarF(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 (cip->hasRETR_tar == kCommandNotAvailable) {
119		result = kErrOpenFailed;
120		cip->errNo = kErrOpenFailed;
121		return (result);
122	}
123
124	if ((file[0] == '\0') || ((file[0] == '/') && (file[1] == '\0'))) {
125		/* It was "/"
126		 * We can't do that, because "get /.tar"
127		 * or "get .tar" does not work.
128		 */
129		result = kErrOpenFailed;
130		cip->errNo = kErrOpenFailed;
131		return (result);
132	}
133
134	if (FTPCmd(cip, "MDTM %s.tar", file) == 2) {
135		/* Better not use this method since there is
136		 * no way to tell if the server would use the
137		 * existing .tar or do a new one on the fly.
138		 */
139		result = kErrOpenFailed;
140		cip->errNo = kErrOpenFailed;
141		return (result);
142	}
143
144	basecp = strrchr(file, '/');
145	if (basecp != NULL)
146		basecp = strrchr(file, '\\');
147	if (basecp != NULL) {
148		/* Need to cd to the parent directory and get it
149		 * from there.
150		 */
151		if (FTPGetCWD(cip, savedCwd, sizeof(savedCwd)) != 0) {
152			result = kErrOpenFailed;
153			cip->errNo = kErrOpenFailed;
154			return (result);
155		}
156		result = FTPChdir(cip, file);
157		if (result != kNoErr) {
158			return (result);
159		}
160		result = FTPChdir(cip, "..");
161		if (result != kNoErr) {
162			(void) FTPChdir(cip, savedCwd);
163			return (result);
164		}
165		file = basecp + 1;
166	}
167
168	fd = OpenTar(cip, dstdir, &pid);
169	if (fd < 0) {
170		result = kErrOpenFailed;
171		cip->errNo = kErrOpenFailed;
172		if (basecp != NULL)
173			(void) FTPChdir(cip, savedCwd);
174		return (result);
175	}
176
177	vfd = fd;
178	vfile = file;
179
180#ifndef NO_SIGNALS
181	vcip = cip;
182	osigpipe = (volatile FTPSigProc) signal(SIGPIPE, BrokenData);
183
184	gGotBrokenData = 0;
185	gCanBrokenDataJmp = 0;
186
187#ifdef HAVE_SIGSETJMP
188	sj = sigsetjmp(gBrokenDataJmp, 1);
189#else
190	sj = setjmp(gBrokenDataJmp);
191#endif	/* HAVE_SIGSETJMP */
192
193	if (sj != 0) {
194		(void) signal(SIGPIPE, (FTPSigProc) osigpipe);
195		FTPShutdownHost(vcip);
196
197		(void) signal(SIGPIPE, SIG_IGN);
198		(void) close(vfd);
199		for (;;) {
200#ifdef HAVE_WAITPID
201			if ((waitpid(pid, &status, 0) < 0) && (errno != EINTR))
202				break;
203#else
204			if ((wait(&status) < 0) && (errno != EINTR))
205				break;
206#endif
207			if (WIFEXITED(status) || WIFSIGNALED(status))
208				break;		/* done */
209		}
210		if (basecp != NULL)
211			(void) FTPChdir(cip, savedCwd);
212		vcip->errNo = kErrRemoteHostClosedConnection;
213		return(vcip->errNo);
214	}
215	gCanBrokenDataJmp = 1;
216
217#endif	/* NO_SIGNALS */
218
219	tmpResult = FTPStartDataCmd(cip, kNetReading, kTypeBinary, (longest_int) 0, "RETR %s.tar", vfile);
220
221	if (tmpResult < 0) {
222		result = tmpResult;
223		if (result == kErrGeneric)
224			result = kErrRETRFailed;
225		cip->errNo = result;
226		if (cip->hasRETR_tar == kCommandAvailabilityUnknown)
227			cip->hasRETR_tar = kCommandNotAvailable;
228
229#ifndef NO_SIGNALS
230		(void) signal(SIGPIPE, SIG_IGN);
231#endif
232		(void) close(vfd);
233		for (;;) {
234#ifdef HAVE_WAITPID
235			if ((waitpid(pid, &status, 0) < 0) && (errno != EINTR))
236				break;
237#else
238			if ((wait(&status) < 0) && (errno != EINTR))
239				break;
240#endif
241			if (WIFEXITED(status) || WIFSIGNALED(status))
242				break;		/* done */
243		}
244
245#ifndef NO_SIGNALS
246		(void) signal(SIGPIPE, (FTPSigProc) osigpipe);
247#endif
248		if (basecp != NULL)
249			(void) FTPChdir(cip, savedCwd);
250		return (result);
251	}
252
253	if (cip->hasRETR_tar == kCommandAvailabilityUnknown)
254		cip->hasRETR_tar = kCommandAvailable;
255	cip->usingTAR = 1;
256	buf = cip->buf;
257	bufSize = cip->bufSize;
258
259	FTPInitIOTimer(cip);
260	cip->lname = vfile;	/* could be NULL */
261	cip->rname = vfile;
262	FTPStartIOTimer(cip);
263
264	/* Binary */
265	for (;;) {
266		if (! WaitForRemoteInput(cip)) {	/* could set cancelXfer */
267			cip->errNo = result = kErrDataTimedOut;
268			FTPLogError(cip, kDontPerror, "Remote read timed out.\n");
269			break;
270		}
271		if (cip->cancelXfer > 0) {
272			FTPAbortDataTransfer(cip);
273			result = cip->errNo = kErrDataTransferAborted;
274			break;
275		}
276#if !defined(NO_SIGNALS)
277		gCanBrokenDataJmp = 1;
278		if (cip->xferTimeout > 0)
279			(void) alarm(cip->xferTimeout);
280#endif	/* NO_SIGNALS */
281#ifdef NO_SIGNALS
282		nread = (read_return_t) SRead(cip->dataSocket, buf, bufSize, (int) cip->xferTimeout, kFullBufferNotRequired|kNoFirstSelect);
283		if (nread == kTimeoutErr) {
284			cip->errNo = result = kErrDataTimedOut;
285			FTPLogError(cip, kDontPerror, "Remote read timed out.\n");
286			break;
287		} else if (nread < 0) {
288			if (errno == EINTR)
289				continue;
290			FTPLogError(cip, kDoPerror, "Remote read failed.\n");
291			result = kErrSocketReadFailed;
292			cip->errNo = kErrSocketReadFailed;
293			break;
294		} else if (nread == 0) {
295			break;
296		}
297#else
298		nread = read(cip->dataSocket, buf, (read_size_t) bufSize);
299		if (nread < 0) {
300			if (errno == EINTR)
301				continue;
302			FTPLogError(cip, kDoPerror, "Remote read failed.\n");
303			result = kErrSocketReadFailed;
304			cip->errNo = kErrSocketReadFailed;
305			break;
306		} else if (nread == 0) {
307			break;
308		}
309		gCanBrokenDataJmp = 0;
310#endif
311
312		nwrote = write(fd, buf, (write_size_t) nread);
313		if (nwrote != nread) {
314			if (errno == EPIPE) {
315				result = kErrWriteFailed;
316				cip->errNo = kErrWriteFailed;
317				errno = EPIPE;
318			} else {
319				FTPLogError(cip, kDoPerror, "Local write failed.\n");
320				result = kErrWriteFailed;
321				cip->errNo = kErrWriteFailed;
322			}
323			break;
324		}
325		cip->bytesTransferred += (longest_int) nread;
326		FTPUpdateIOTimer(cip);
327	}
328
329#if !defined(NO_SIGNALS)
330	if (cip->xferTimeout > 0)
331		(void) alarm(0);
332	gCanBrokenDataJmp = 0;
333#endif	/* NO_SIGNALS */
334
335	(void) close(fd);
336	for (;;) {
337#ifdef HAVE_WAITPID
338		if ((waitpid(pid, &status, 0) < 0) && (errno != EINTR))
339			break;
340#else
341		if ((wait(&status) < 0) && (errno != EINTR))
342			break;
343#endif
344		if (WIFEXITED(status) || WIFSIGNALED(status))
345			break;		/* done */
346	}
347
348	tmpResult = FTPEndDataCmd(cip, 1);
349	if ((tmpResult < 0) && (result == 0)) {
350		result = kErrRETRFailed;
351		cip->errNo = kErrRETRFailed;
352	}
353	FTPStopIOTimer(cip);
354#if !defined(NO_SIGNALS)
355	(void) signal(SIGPIPE, (FTPSigProc) osigpipe);
356#endif
357
358	if ((result == 0) && (cip->bytesTransferred == 0)) {
359		result = kErrOpenFailed;
360		cip->errNo = kErrOpenFailed;
361	}
362	if (basecp != NULL)
363		(void) FTPChdir(cip, savedCwd);
364	return (result);
365}	/* FTPGetOneTarF */
366
367#endif	/* TAR */