PageRenderTime 32ms CodeModel.GetById 15ms app.highlight 14ms RepoModel.GetById 0ms app.codeStats 0ms

/ncftp-3.2.5/libncftp/io_getmem.c

#
C | 268 lines | 209 code | 28 blank | 31 comment | 98 complexity | f2aefca7baa65e4454161d6da6f2f25a MD5 | raw file
Possible License(s): AGPL-3.0
  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
 17int
 18FTPGetFileToMemory(
 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 */