⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 io.c

📁 ReactOS是一些高手根据Windows XP的内核编写出的类XP。内核实现机理和API函数调用几乎相同。甚至可以兼容XP的程序。喜欢研究系统内核的人可以看一看。
💻 C
📖 第 1 页 / 共 5 页
字号:


/* Nice for UNIX, but not necessary otherwise. */
#ifdef TAR

static int
OpenTar(const FTPCIPtr cip, const char *const dstdir, int *const pid)
{
	int pipe1[2];
	int pid1;
	int i;
	char *argv[8];

	*pid = -1;

	if (access(TAR, X_OK) < 0) {
		/* Path to TAR is invalid. */
		return (-1);
	}

	if (pipe(pipe1) < 0) {
		Error(cip, kDoPerror, "pipe to Tar failed");
		return (-1);
	}

	pid1 = (int) fork();
	if (pid1 < 0) {
		(void) close(pipe1[0]);
		(void) close(pipe1[1]);
		return (-1);
	} else if (pid1 == 0) {
		/* Child */
		if ((dstdir != NULL) && (dstdir[0] != '\0') && (chdir(dstdir) < 0)) {
			Error(cip, kDoPerror, "tar chdir to %s failed", dstdir);
			exit(1);
		}
		(void) close(pipe1[1]);		/* close write end */
		(void) dup2(pipe1[0], 0);	/* use read end on stdin */
		(void) close(pipe1[0]);

		for (i=3; i<256; i++)
			(void) close(i);

		argv[0] = (char *) "tar";
		argv[1] = (char *) "xpf";
		argv[2] = (char *) "-";
		argv[3] = NULL;

		(void) execv(TAR, argv);
		exit(1);
	}

	/* Parent */
	*pid = pid1;

	(void) close(pipe1[0]);		/* close read end */
	return (pipe1[1]);		/* use write end */
}	/* OpenTar */




static int
FTPGetOneTarF(const FTPCIPtr cip, const char *file, const char *const dstdir)
{
	char *buf;
	size_t bufSize;
	int tmpResult;
	volatile int result;
	int nread, nwrote;
	volatile int fd;
	volatile int vfd;
	const char *volatile vfile;
#ifndef NO_SIGNALS
	int sj;
	volatile FTPSigProc osigpipe;
	volatile FTPCIPtr vcip;
#endif
	int pid, status;
	char savedCwd[512];
	char *volatile basecp;

	result = kNoErr;
	cip->usingTAR = 0;

	if ((file[0] == '\0') || ((file[0] == '/') && (file[1] == '\0'))) {
		/* It was "/"
		 * We can't do that, because "get /.tar"
		 * or "get .tar" does not work.
		 */
		result = kErrOpenFailed;
		cip->errNo = kErrOpenFailed;
		return (result);
	}

	if (FTPCmd(cip, "MDTM %s.tar", file) == 2) {
		/* Better not use this method since there is
		 * no way to tell if the server would use the
		 * existing .tar or do a new one on the fly.
		 */
		result = kErrOpenFailed;
		cip->errNo = kErrOpenFailed;
		return (result);
	}

	basecp = strrchr(file, '/');
	if (basecp != NULL)
		basecp = strrchr(file, '\\');
	if (basecp != NULL) {
		/* Need to cd to the parent directory and get it
		 * from there.
		 */
		if (FTPGetCWD(cip, savedCwd, sizeof(savedCwd)) != 0) {
			result = kErrOpenFailed;
			cip->errNo = kErrOpenFailed;
			return (result);
		}
		result = FTPChdir(cip, file);
		if (result != kNoErr) {
			return (result);
		}
		result = FTPChdir(cip, "..");
		if (result != kNoErr) {
			(void) FTPChdir(cip, savedCwd);
			return (result);
		}
		file = basecp + 1;
	}

	fd = OpenTar(cip, dstdir, &pid);
	if (fd < 0) {
		result = kErrOpenFailed;
		cip->errNo = kErrOpenFailed;
		if (basecp != NULL)
			(void) FTPChdir(cip, savedCwd);
		return (result);
	}

	vfd = fd;
	vfile = file;

#ifndef NO_SIGNALS
	vcip = cip;
	osigpipe = (volatile FTPSigProc) signal(SIGPIPE, BrokenData);

	gGotBrokenData = 0;
	gCanBrokenDataJmp = 0;

#ifdef HAVE_SIGSETJMP
	sj = sigsetjmp(gBrokenDataJmp, 1);
#else
	sj = setjmp(gBrokenDataJmp);
#endif	/* HAVE_SIGSETJMP */

	if (sj != 0) {
		(void) signal(SIGPIPE, (FTPSigProc) osigpipe);
		FTPShutdownHost(vcip);

		(void) signal(SIGPIPE, SIG_IGN);
		(void) close(vfd);
		for (;;) {
#ifdef HAVE_WAITPID
			if ((waitpid(pid, &status, 0) < 0) && (errno != EINTR))
				break;
#else
			if ((wait(&status) < 0) && (errno != EINTR))
				break;
#endif
			if (WIFEXITED(status) || WIFSIGNALED(status))
				break;		/* done */
		}
		if (basecp != NULL)
			(void) FTPChdir(cip, savedCwd);
		vcip->errNo = kErrRemoteHostClosedConnection;
		return(vcip->errNo);
	}
	gCanBrokenDataJmp = 1;

#endif	/* NO_SIGNALS */

	tmpResult = FTPStartDataCmd(cip, kNetReading, kTypeBinary, (longest_int) 0, "RETR %s.tar", vfile);

	if (tmpResult < 0) {
		result = tmpResult;
		if (result == kErrGeneric)
			result = kErrRETRFailed;
		cip->errNo = result;

#ifndef NO_SIGNALS
		(void) signal(SIGPIPE, SIG_IGN);
#endif
		(void) close(vfd);
		for (;;) {
#ifdef HAVE_WAITPID
			if ((waitpid(pid, &status, 0) < 0) && (errno != EINTR))
				break;
#else
			if ((wait(&status) < 0) && (errno != EINTR))
				break;
#endif
			if (WIFEXITED(status) || WIFSIGNALED(status))
				break;		/* done */
		}

#ifndef NO_SIGNALS
		(void) signal(SIGPIPE, (FTPSigProc) osigpipe);
#endif
		if (basecp != NULL)
			(void) FTPChdir(cip, savedCwd);
		return (result);
	}

	cip->usingTAR = 1;
	buf = cip->buf;
	bufSize = cip->bufSize;

	FTPInitIOTimer(cip);
	cip->lname = vfile;	/* could be NULL */
	cip->rname = vfile;
	FTPStartIOTimer(cip);

	/* Binary */
	for (;;) {
		if (! WaitForRemoteInput(cip)) {	/* could set cancelXfer */
			cip->errNo = result = kErrDataTimedOut;
			Error(cip, kDontPerror, "Remote read timed out.\n");
			break;
		}
		if (cip->cancelXfer > 0) {
			FTPAbortDataTransfer(cip);
			result = cip->errNo = kErrDataTransferAborted;
			break;
		}
#if !defined(NO_SIGNALS)
		gCanBrokenDataJmp = 1;
		if (cip->xferTimeout > 0)
			(void) alarm(cip->xferTimeout);
#endif	/* NO_SIGNALS */
#ifdef NO_SIGNALS
		nread = SRead(cip->dataSocket, buf, bufSize, (int) cip->xferTimeout, kFullBufferNotRequired|kNoFirstSelect);
		if (nread == kTimeoutErr) {
			cip->errNo = result = kErrDataTimedOut;
			Error(cip, kDontPerror, "Remote read timed out.\n");
			break;
		} else if (nread < 0) {
			if (errno == EINTR)
				continue;
			Error(cip, kDoPerror, "Remote read failed.\n");
			result = kErrSocketReadFailed;
			cip->errNo = kErrSocketReadFailed;
			break;
		} else if (nread == 0) {
			break;
		}
#else
		nread = read(cip->dataSocket, buf, bufSize);
		if (nread < 0) {
			if (errno == EINTR)
				continue;
			Error(cip, kDoPerror, "Remote read failed.\n");
			result = kErrSocketReadFailed;
			cip->errNo = kErrSocketReadFailed;
			break;
		} else if (nread == 0) {
			break;
		}
		gCanBrokenDataJmp = 0;
#endif

		nwrote = write(fd, buf, nread);
		if (nwrote != nread) {
			if ((gGotBrokenData != 0) || (errno == EPIPE)) {
				result = kErrWriteFailed;
				cip->errNo = kErrWriteFailed;
				errno = EPIPE;
			} else {
				Error(cip, kDoPerror, "Local write failed.\n");
				result = kErrWriteFailed;
				cip->errNo = kErrWriteFailed;
			}
			break;
		}
		cip->bytesTransferred += (longest_int) nread;
		FTPUpdateIOTimer(cip);
	}

#if !defined(NO_SIGNALS)
	if (cip->xferTimeout > 0)
		(void) alarm(0);
	gCanBrokenDataJmp = 0;
#endif	/* NO_SIGNALS */

	(void) close(fd);
	for (;;) {
#ifdef HAVE_WAITPID
		if ((waitpid(pid, &status, 0) < 0) && (errno != EINTR))
			break;
#else
		if ((wait(&status) < 0) && (errno != EINTR))
			break;
#endif
		if (WIFEXITED(status) || WIFSIGNALED(status))
			break;		/* done */
	}

	tmpResult = FTPEndDataCmd(cip, 1);
	if ((tmpResult < 0) && (result == 0)) {
		result = kErrRETRFailed;
		cip->errNo = kErrRETRFailed;
	}
	FTPStopIOTimer(cip);
#if !defined(NO_SIGNALS)
	(void) signal(SIGPIPE, (FTPSigProc) osigpipe);
#endif

	if ((result == 0) && (cip->bytesTransferred == 0)) {
		result = kErrOpenFailed;
		cip->errNo = kErrOpenFailed;
	}
	if (basecp != NULL)
		(void) FTPChdir(cip, savedCwd);
	return (result);
}	/* FTPGetOneTarF */

#endif	/* TAR */





static int
FTPGetOneF(
	const FTPCIPtr cip,
	const char *const file,
	const char *dstfile,
	int xtype,
	const int fdtouse,
	longest_int expectedSize,
	time_t mdtm,
	const int resumeflag,
	const int appendflag,
	const int deleteflag,
	const ConfirmResumeDownloadProc resumeProc)
{
	char *buf;
	size_t bufSize;
	int tmpResult;
	volatile int result;
	int nread, nwrote;
	volatile int fd;
#if ASCII_TRANSLATION
	char *src, *srclim;
	char *dst, *dstlim;
	char outbuf[512];
#endif
	volatile longest_int startPoint = 0;
	struct utimbuf ut;
	struct Stat st;
#if !defined(NO_SIGNALS)
	volatile FTPSigProc osigpipe;
	volatile FTPCIPtr vcip;
	volatile int vfd, vfdtouse;
	int sj;
#endif	/* NO_SIGNALS */
	volatile int created = 0;
	int zaction = kConfirmResumeProcSaidBestGuess;
	int statrc;
	int noMdtmCheck;
	time_t now;

	if (cip->buf == NULL) {
		Error(cip, kDoPerror, "Transfer buffer not allocated.\n");
		cip->errNo = kErrNoBuf;
		return (cip->errNo);
	}

	result = kNoErr;
	cip->usingTAR = 0;

	if (fdtouse < 0) {
		/* Only ask for extended information
		 * if we have the name of the file
		 * and we didn't already have the
		 * info.
		 *
		 * Always ask for the modification time,
		 * because even if it was passed in it
		 * may not be accurate.  This is often
		 * the case when it came from an ls
		 * listing, in which the local time
		 * zone could be a factor.
		 *
		 */

		AutomaticallyUseASCIIModeDependingOnExtension(cip, file, &xtype);
		if (expectedSize == kSizeUnknown) {
			(void) FTPFileSizeAndModificationTime(cip, file, &expectedSize, xtype, &mdtm);
		} else {
			(void) FTPFileModificationTime(cip, file, &mdtm);
		}

		/* For Get, we can't recover very well if it turns out restart
		 * didn't work, so check beforehand.
		 */
		if ((resumeflag == kResumeYes) || (resumeProc != NoConfirmResumeDownloadProc)) {
			if (cip->hasREST == kCommandAvailabilityUnknown) {
				(void) FTPSetTransferType(cip, kTypeBinary);
				if (SetStartOffset(cip, (longest_int) 1) == kNoErr) {
					/* Now revert -- we still may not end up
					 * doing it.
					 */
					SetStartOffset(cip, (longest_int) -1);
				}
			}
		}

		if (appendflag == kAppendYes) {
			zaction = kConfirmResumeProcSaidAppend;
		} else if (cip->hasREST == kCommandNotAvailable) {
			zaction = kConfirmResumeProcSaidOverwrite;
		} else if (resumeflag == kResumeYes) {
			zaction = kConfirmResumeProcSaidBestGuess;
		} else {
			zaction = kConfirmResumeProcSaidOverwrite;
		}

		statrc = Stat(dstfile, &st);
		if (statrc == 0) {
			if (resumeProc != NULL) {
				zaction = (*resumeProc)(
						&dstfile,
						(longest_int) st.st_size,
						st.st_mtime,
						file,
						expectedSize,
						mdtm,
						&startPoint
				);
			}

			if (zaction == kConfirmResumeProcSaidBestGuess) {
				if (expectedSize != kSizeUnknown) {
					/* We know the size of the remote file,
					 * and we have a local file too.
					 *
					 * Try and decide if we need to get
					 * the entire file, or just part of it.
					 */

					startPoint = (longest_int) st.st_size;
					zaction = kConfirmResumeProcSaidResume;

					/* If the local file exists and has a recent
					 * modification time (< 12 hours) and
					 * the remote file's modtime is not recent,
					 * then heuristically conclude that the
					 * local modtime should not be trusted
					 * (i.e. user killed the process before
					 * the local modtime could be preserved).
					 */
					noMdtmCheck = 0;
					if (mdtm != kModTimeUnknown) {
						time(&now);
						if ((st.st_mtime > now) || (((now - st.st_mtime) < 46200) && ((now - mdtm) >= 46200)))
							noMdtmCheck = 1;
					}

					if ((mdtm == kModTimeUnknown) || (noMdtmCheck != 0)) {
						/* Can't use the timestamps as an aid. */
						if (startPoint == expectedSize) {
							/* Don't go to all the trouble of downloading nothing. */
							cip->errNo = kErrLocalSameAsRemote;
							if (deleteflag == kDeleteYes)
								(void) FTPDelete(cip, file, kRecursiveNo, kGlobNo);
							return (cip->errNo);
						} else if (startPoint > expectedSize) {
							/* Panic;  odds are the file we have
							 * was a different file altogether,
							 * since it is larger than the
							 * remote copy.  Re-do it all.
							 */
							zaction = kConfirmResumeProcSaidOverwrite;
						} /* else resume at startPoint */
					} else if ((mdtm == st.st_mtime) || (mdtm == (st.st_mtime - 1)) || (mdtm == (st.st_mtime + 1))) {
						/* File has the same time.
						 * Note: Windows' file timestamps can be off by one second!
						 */
						if (startPoint == expectedSize) {
							/* Don't go to all the trouble of downloading nothing. */
							cip->errNo = kErrLocalSameAsRemote;
							if (deleteflag == kDeleteYes)
								(void) FTPDelete(cip, file, kRecursiveNo, kGlobNo);
							return (cip->errNo);
						} else if (startPoint > expectedSize) {
							/* Panic;  odds are the file we have

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -