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

📄 scp.c

📁 OpenSSH 是 SSH (Secure SHell) 协议的免费开源实现。它用安全、加密的网络连接工具代替了 telnet、ftp、 rlogin、rsh 和 rcp 工具。OpenSSH 支持
💻 C
📖 第 1 页 / 共 2 页
字号:
		for (haderr = i = 0; i < stb.st_size; i += bp->cnt) {			amt = bp->cnt;			if (i + amt > stb.st_size)				amt = stb.st_size - i;			if (!haderr) {				result = atomicio(read, fd, bp->buf, amt);				if (result != amt)					haderr = result >= 0 ? EIO : errno;			}			if (haderr)				(void) atomicio(vwrite, remout, bp->buf, amt);			else {				result = atomicio(vwrite, remout, bp->buf, amt);				if (result != amt)					haderr = result >= 0 ? EIO : errno;				statbytes += result;			}			if (limit_rate)				bwlimit(amt);		}		if (showprogress)			stop_progress_meter();		if (close(fd) < 0 && !haderr)			haderr = errno;		if (!haderr)			(void) atomicio(vwrite, remout, "", 1);		else			run_err("%s: %s", name, strerror(haderr));		(void) response();	}}voidrsource(char *name, struct stat *statp){	DIR *dirp;	struct dirent *dp;	char *last, *vect[1], path[1100];	if (!(dirp = opendir(name))) {		run_err("%s: %s", name, strerror(errno));		return;	}	last = strrchr(name, '/');	if (last == 0)		last = name;	else		last++;	if (pflag) {		(void) snprintf(path, sizeof(path), "T%lu 0 %lu 0\n",		    (u_long) statp->st_mtime,		    (u_long) statp->st_atime);		(void) atomicio(vwrite, remout, path, strlen(path));		if (response() < 0) {			closedir(dirp);			return;		}	}	(void) snprintf(path, sizeof path, "D%04o %d %.1024s\n",	    (u_int) (statp->st_mode & FILEMODEMASK), 0, last);	if (verbose_mode)		fprintf(stderr, "Entering directory: %s", path);	(void) atomicio(vwrite, remout, path, strlen(path));	if (response() < 0) {		closedir(dirp);		return;	}	while ((dp = readdir(dirp)) != NULL) {		if (dp->d_ino == 0)			continue;		if (!strcmp(dp->d_name, ".") || !strcmp(dp->d_name, ".."))			continue;		if (strlen(name) + 1 + strlen(dp->d_name) >= sizeof(path) - 1) {			run_err("%s/%s: name too long", name, dp->d_name);			continue;		}		(void) snprintf(path, sizeof path, "%s/%s", name, dp->d_name);		vect[0] = path;		source(1, vect);	}	(void) closedir(dirp);	(void) atomicio(vwrite, remout, "E\n", 2);	(void) response();}voidbwlimit(int amount){	static struct timeval bwstart, bwend;	static int lamt, thresh = 16384;	u_int64_t waitlen;	struct timespec ts, rm;	if (!timerisset(&bwstart)) {		gettimeofday(&bwstart, NULL);		return;	}	lamt += amount;	if (lamt < thresh)		return;	gettimeofday(&bwend, NULL);	timersub(&bwend, &bwstart, &bwend);	if (!timerisset(&bwend))		return;	lamt *= 8;	waitlen = (double)1000000L * lamt / limit_rate;	bwstart.tv_sec = waitlen / 1000000L;	bwstart.tv_usec = waitlen % 1000000L;	if (timercmp(&bwstart, &bwend, >)) {		timersub(&bwstart, &bwend, &bwend);		/* Adjust the wait time */		if (bwend.tv_sec) {			thresh /= 2;			if (thresh < 2048)				thresh = 2048;		} else if (bwend.tv_usec < 100) {			thresh *= 2;			if (thresh > 32768)				thresh = 32768;		}		TIMEVAL_TO_TIMESPEC(&bwend, &ts);		while (nanosleep(&ts, &rm) == -1) {			if (errno != EINTR)				break;			ts = rm;		}	}	lamt = 0;	gettimeofday(&bwstart, NULL);}voidsink(int argc, char **argv){	static BUF buffer;	struct stat stb;	enum {		YES, NO, DISPLAYED	} wrerr;	BUF *bp;	off_t i, j;	int amt, count, exists, first, mask, mode, ofd, omode;	off_t size, statbytes;	int setimes, targisdir, wrerrno = 0;	char ch, *cp, *np, *targ, *why, *vect[1], buf[2048];	struct timeval tv[2];#define	atime	tv[0]#define	mtime	tv[1]#define	SCREWUP(str)	{ why = str; goto screwup; }	setimes = targisdir = 0;	mask = umask(0);	if (!pflag)		(void) umask(mask);	if (argc != 1) {		run_err("ambiguous target");		exit(1);	}	targ = *argv;	if (targetshouldbedirectory)		verifydir(targ);	(void) atomicio(vwrite, remout, "", 1);	if (stat(targ, &stb) == 0 && S_ISDIR(stb.st_mode))		targisdir = 1;	for (first = 1;; first = 0) {		cp = buf;		if (atomicio(read, remin, cp, 1) <= 0)			return;		if (*cp++ == '\n')			SCREWUP("unexpected <newline>");		do {			if (atomicio(read, remin, &ch, sizeof(ch)) != sizeof(ch))				SCREWUP("lost connection");			*cp++ = ch;		} while (cp < &buf[sizeof(buf) - 1] && ch != '\n');		*cp = 0;		if (verbose_mode)			fprintf(stderr, "Sink: %s", buf);		if (buf[0] == '\01' || buf[0] == '\02') {			if (iamremote == 0)				(void) atomicio(vwrite, STDERR_FILENO,				    buf + 1, strlen(buf + 1));			if (buf[0] == '\02')				exit(1);			++errs;			continue;		}		if (buf[0] == 'E') {			(void) atomicio(vwrite, remout, "", 1);			return;		}		if (ch == '\n')			*--cp = 0;		cp = buf;		if (*cp == 'T') {			setimes++;			cp++;			mtime.tv_sec = strtol(cp, &cp, 10);			if (!cp || *cp++ != ' ')				SCREWUP("mtime.sec not delimited");			mtime.tv_usec = strtol(cp, &cp, 10);			if (!cp || *cp++ != ' ')				SCREWUP("mtime.usec not delimited");			atime.tv_sec = strtol(cp, &cp, 10);			if (!cp || *cp++ != ' ')				SCREWUP("atime.sec not delimited");			atime.tv_usec = strtol(cp, &cp, 10);			if (!cp || *cp++ != '\0')				SCREWUP("atime.usec not delimited");			(void) atomicio(vwrite, remout, "", 1);			continue;		}		if (*cp != 'C' && *cp != 'D') {			/*			 * Check for the case "rcp remote:foo\* local:bar".			 * In this case, the line "No match." can be returned			 * by the shell before the rcp command on the remote is			 * executed so the ^Aerror_message convention isn't			 * followed.			 */			if (first) {				run_err("%s", cp);				exit(1);			}			SCREWUP("expected control record");		}		mode = 0;		for (++cp; cp < buf + 5; cp++) {			if (*cp < '0' || *cp > '7')				SCREWUP("bad mode");			mode = (mode << 3) | (*cp - '0');		}		if (*cp++ != ' ')			SCREWUP("mode not delimited");		for (size = 0; isdigit(*cp);)			size = size * 10 + (*cp++ - '0');		if (*cp++ != ' ')			SCREWUP("size not delimited");		if ((strchr(cp, '/') != NULL) || (strcmp(cp, "..") == 0)) {			run_err("error: unexpected filename: %s", cp);			exit(1);		}		if (targisdir) {			static char *namebuf;			static int cursize;			size_t need;			need = strlen(targ) + strlen(cp) + 250;			if (need > cursize) {				if (namebuf)					xfree(namebuf);				namebuf = xmalloc(need);				cursize = need;			}			(void) snprintf(namebuf, need, "%s%s%s", targ,			    strcmp(targ, "/") ? "/" : "", cp);			np = namebuf;		} else			np = targ;		curfile = cp;		exists = stat(np, &stb) == 0;		if (buf[0] == 'D') {			int mod_flag = pflag;			if (!iamrecursive)				SCREWUP("received directory without -r");			if (exists) {				if (!S_ISDIR(stb.st_mode)) {					errno = ENOTDIR;					goto bad;				}				if (pflag)					(void) chmod(np, mode);			} else {				/* Handle copying from a read-only				   directory */				mod_flag = 1;				if (mkdir(np, mode | S_IRWXU) < 0)					goto bad;			}			vect[0] = xstrdup(np);			sink(1, vect);			if (setimes) {				setimes = 0;				if (utimes(vect[0], tv) < 0)					run_err("%s: set times: %s",					    vect[0], strerror(errno));			}			if (mod_flag)				(void) chmod(vect[0], mode);			if (vect[0])				xfree(vect[0]);			continue;		}		omode = mode;		mode |= S_IWRITE;		if ((ofd = open(np, O_WRONLY|O_CREAT, mode)) < 0) {bad:			run_err("%s: %s", np, strerror(errno));			continue;		}		(void) atomicio(vwrite, remout, "", 1);		if ((bp = allocbuf(&buffer, ofd, 4096)) == NULL) {			(void) close(ofd);			continue;		}		cp = bp->buf;		wrerr = NO;		statbytes = 0;		if (showprogress)			start_progress_meter(curfile, size, &statbytes);		for (count = i = 0; i < size; i += 4096) {			amt = 4096;			if (i + amt > size)				amt = size - i;			count += amt;			do {				j = atomicio(read, remin, cp, amt);				if (j <= 0) {					run_err("%s", j ? strerror(errno) :					    "dropped connection");					exit(1);				}				amt -= j;				cp += j;				statbytes += j;			} while (amt > 0);			if (limit_rate)				bwlimit(4096);			if (count == bp->cnt) {				/* Keep reading so we stay sync'd up. */				if (wrerr == NO) {					j = atomicio(vwrite, ofd, bp->buf, count);					if (j != count) {						wrerr = YES;						wrerrno = j >= 0 ? EIO : errno;					}				}				count = 0;				cp = bp->buf;			}		}		if (showprogress)			stop_progress_meter();		if (count != 0 && wrerr == NO &&		    (j = atomicio(vwrite, ofd, bp->buf, count)) != count) {			wrerr = YES;			wrerrno = j >= 0 ? EIO : errno;		}		if (wrerr == NO && ftruncate(ofd, size) != 0) {			run_err("%s: truncate: %s", np, strerror(errno));			wrerr = DISPLAYED;		}		if (pflag) {			if (exists || omode != mode)#ifdef HAVE_FCHMOD				if (fchmod(ofd, omode)) {#else /* HAVE_FCHMOD */				if (chmod(np, omode)) {#endif /* HAVE_FCHMOD */					run_err("%s: set mode: %s",					    np, strerror(errno));					wrerr = DISPLAYED;				}		} else {			if (!exists && omode != mode)#ifdef HAVE_FCHMOD				if (fchmod(ofd, omode & ~mask)) {#else /* HAVE_FCHMOD */				if (chmod(np, omode & ~mask)) {#endif /* HAVE_FCHMOD */					run_err("%s: set mode: %s",					    np, strerror(errno));					wrerr = DISPLAYED;				}		}		if (close(ofd) == -1) {			wrerr = YES;			wrerrno = errno;		}		(void) response();		if (setimes && wrerr == NO) {			setimes = 0;			if (utimes(np, tv) < 0) {				run_err("%s: set times: %s",				    np, strerror(errno));				wrerr = DISPLAYED;			}		}		switch (wrerr) {		case YES:			run_err("%s: %s", np, strerror(wrerrno));			break;		case NO:			(void) atomicio(vwrite, remout, "", 1);			break;		case DISPLAYED:			break;		}	}screwup:	run_err("protocol error: %s", why);	exit(1);}intresponse(void){	char ch, *cp, resp, rbuf[2048];	if (atomicio(read, remin, &resp, sizeof(resp)) != sizeof(resp))		lostconn(0);	cp = rbuf;	switch (resp) {	case 0:		/* ok */		return (0);	default:		*cp++ = resp;		/* FALLTHROUGH */	case 1:		/* error, followed by error msg */	case 2:		/* fatal error, "" */		do {			if (atomicio(read, remin, &ch, sizeof(ch)) != sizeof(ch))				lostconn(0);			*cp++ = ch;		} while (cp < &rbuf[sizeof(rbuf) - 1] && ch != '\n');		if (!iamremote)			(void) atomicio(vwrite, STDERR_FILENO, rbuf, cp - rbuf);		++errs;		if (resp == 1)			return (-1);		exit(1);	}	/* NOTREACHED */}voidusage(void){	(void) fprintf(stderr,	    "usage: scp [-1246BCpqrv] [-c cipher] [-F ssh_config] [-i identity_file]\n"	    "           [-l limit] [-o ssh_option] [-P port] [-S program]\n"	    "           [[user@]host1:]file1 [...] [[user@]host2:]file2\n");	exit(1);}voidrun_err(const char *fmt,...){	static FILE *fp;	va_list ap;	++errs;	if (fp == NULL && !(fp = fdopen(remout, "w")))		return;	(void) fprintf(fp, "%c", 0x01);	(void) fprintf(fp, "scp: ");	va_start(ap, fmt);	(void) vfprintf(fp, fmt, ap);	va_end(ap);	(void) fprintf(fp, "\n");	(void) fflush(fp);	if (!iamremote) {		va_start(ap, fmt);		vfprintf(stderr, fmt, ap);		va_end(ap);		fprintf(stderr, "\n");	}}voidverifydir(char *cp){	struct stat stb;	if (!stat(cp, &stb)) {		if (S_ISDIR(stb.st_mode))			return;		errno = ENOTDIR;	}	run_err("%s: %s", cp, strerror(errno));	exit(1);}intokname(char *cp0){	int c;	char *cp;	cp = cp0;	do {		c = (int)*cp;		if (c & 0200)			goto bad;		if (!isalpha(c) && !isdigit(c)) {			switch (c) {			case '\'':			case '"':			case '`':			case ' ':			case '#':				goto bad;			default:				break;			}		}	} while (*++cp);	return (1);bad:	fprintf(stderr, "%s: invalid user name\n", cp0);	return (0);}BUF *allocbuf(BUF *bp, int fd, int blksize){	size_t size;#ifdef HAVE_STRUCT_STAT_ST_BLKSIZE	struct stat stb;	if (fstat(fd, &stb) < 0) {		run_err("fstat: %s", strerror(errno));		return (0);	}	size = roundup(stb.st_blksize, blksize);	if (size == 0)		size = blksize;#else /* HAVE_STRUCT_STAT_ST_BLKSIZE */	size = blksize;#endif /* HAVE_STRUCT_STAT_ST_BLKSIZE */	if (bp->cnt >= size)		return (bp);	if (bp->buf == NULL)		bp->buf = xmalloc(size);	else		bp->buf = xrealloc(bp->buf, size);	memset(bp->buf, 0, size);	bp->cnt = size;	return (bp);}voidlostconn(int signo){	if (!iamremote)		write(STDERR_FILENO, "lost connection\n", 16);	if (signo)		_exit(1);	else		exit(1);}

⌨️ 快捷键说明

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