Пример #1
0
static int fastcopy( const char *from, const char *to, struct stat *sbp ) {
	struct timeval tval[2];
	static u_int blen = MAXPHYS;
	static char *bp = NULL;
	mode_t oldmode;
	int nread, from_fd, to_fd;
	if ( ( from_fd = open( from, O_RDONLY, 0 ) ) < 0 ) {
		warn( "fastcopy: open() failed (from): %s", from );
		return ( 1 );
	}
	if ( bp == NULL && ( bp = malloc( (size_t) blen ) ) == NULL ) {
		warnx( "malloc(%u) failed", blen );
		return ( 1 );
	}
	while ( ( to_fd = open( to, O_CREAT | O_EXCL | O_TRUNC | O_WRONLY, 0 ) ) < 0 ) {
		if ( errno == EEXIST && unlink( to ) == 0 ) continue;
		warn( "fastcopy: open() failed (to): %s", to );
		(void) close( from_fd );
		return ( 1 );
	}
	while ( ( nread = read( from_fd, bp, (size_t) blen ) ) > 0 )
		if ( write( to_fd, bp, (size_t) nread ) != nread ) {
			warn( "fastcopy: write() failed: %s", to );
			goto err;
		}
	if ( nread < 0 ) {
		warn( "fastcopy: read() failed: %s", from );
		err: if ( unlink( to ) ) warn( "%s: remove", to );
		(void) close( from_fd );
		(void) close( to_fd );
		return ( 1 );
	}
	oldmode = sbp->st_mode & ALLPERMS;
	if ( fchown( to_fd, sbp->st_uid, sbp->st_gid ) ) {
		warn( "%s: set owner/group (was: %lu/%lu)", to, (u_long) sbp->st_uid, (u_long) sbp->st_gid );
		if ( oldmode & ( S_ISUID | S_ISGID ) ) {
			warnx( "%s: owner/group changed; clearing suid/sgid (mode was 0%03o)", to, oldmode );
			sbp->st_mode &= ~( S_ISUID | S_ISGID );
		}
	}
	if ( fchmod( to_fd, sbp->st_mode ) ) warn( "%s: set mode (was: 0%03o)", to, oldmode );
	preserve_fd_acls( from_fd, to_fd, from, to );
	(void) close( from_fd );
	errno = 0;
	if ( fchflags( to_fd, sbp->st_flags ) ) if ( errno != EOPNOTSUPP || sbp->st_flags != 0 ) warn( "%s: set flags (was: 0%07o)", to, sbp->st_flags );
	tval[0].tv_sec = sbp->st_atime;
	tval[1].tv_sec = sbp->st_mtime;
	tval[0].tv_usec = tval[1].tv_usec = 0;
	if ( utimes( to, tval ) ) warn( "%s: set times", to );
	if ( close( to_fd ) ) {
		warn( "%s", to );
		return ( 1 );
	}
	if ( unlink( from ) ) {
		warn( "%s: remove", from );
		return ( 1 );
	}
	if ( vflg ) printf( "%s -> %s\n", from, to );
	return ( 0 );
}
Пример #2
0
static int
fastcopy(const char *from, const char *to, struct stat *sbp)
{
	struct timeval tval[2];
	static u_int blen;
	static char *bp;
	mode_t oldmode;
	int nread, from_fd, to_fd;

	if ((from_fd = open(from, O_RDONLY, 0)) < 0) {
		warn("%s", from);
		return (1);
	}
	if (blen < sbp->st_blksize) {
		if (bp != NULL)
			free(bp);
		if ((bp = malloc((size_t)sbp->st_blksize)) == NULL) {
			blen = 0;
			warnx("malloc failed");
			return (1);
		}
		blen = sbp->st_blksize;
	}
	while ((to_fd =
	    open(to, O_CREAT | O_EXCL | O_TRUNC | O_WRONLY, 0)) < 0) {
		if (errno == EEXIST && unlink(to) == 0)
			continue;
		warn("%s", to);
		(void)close(from_fd);
		return (1);
	}
	while ((nread = read(from_fd, bp, (size_t)blen)) > 0)
		if (write(to_fd, bp, (size_t)nread) != nread) {
			warn("%s", to);
			goto err;
		}
	if (nread < 0) {
		warn("%s", from);
err:		if (unlink(to))
			warn("%s: remove", to);
		(void)close(from_fd);
		(void)close(to_fd);
		return (1);
	}

	oldmode = sbp->st_mode & ALLPERMS;
	if (fchown(to_fd, sbp->st_uid, sbp->st_gid)) {
		warn("%s: set owner/group (was: %lu/%lu)", to,
		    (u_long)sbp->st_uid, (u_long)sbp->st_gid);
		if (oldmode & (S_ISUID | S_ISGID)) {
			warnx(
"%s: owner/group changed; clearing suid/sgid (mode was 0%03o)",
			    to, oldmode);
			sbp->st_mode &= ~(S_ISUID | S_ISGID);
		}
	}
	if (fchmod(to_fd, sbp->st_mode))
		warn("%s: set mode (was: 0%03o)", to, oldmode);
	/*
	 * POSIX 1003.2c states that if _POSIX_ACL_EXTENDED is in effect
	 * for dest_file, then its ACLs shall reflect the ACLs of the
	 * source_file.
	 */
	preserve_fd_acls(from_fd, to_fd, from, to);
	(void)close(from_fd);
	/*
	 * XXX
	 * NFS doesn't support chflags; ignore errors unless there's reason
	 * to believe we're losing bits.  (Note, this still won't be right
	 * if the server supports flags and we were trying to *remove* flags
	 * on a file that we copied, i.e., that we didn't create.)
	 */
	errno = 0;
	if (fchflags(to_fd, (u_long)sbp->st_flags))
		if (errno != EOPNOTSUPP || sbp->st_flags != 0)
			warn("%s: set flags (was: 0%07o)", to, sbp->st_flags);

	tval[0].tv_sec = sbp->st_atime;
	tval[1].tv_sec = sbp->st_mtime;
	tval[0].tv_usec = tval[1].tv_usec = 0;
	if (utimes(to, tval))
		warn("%s: set times", to);

	if (close(to_fd)) {
		warn("%s", to);
		return (1);
	}

	if (unlink(from)) {
		warn("%s: remove", from);
		return (1);
	}
	if (vflg)
		printf("%s -> %s\n", from, to);
	return (0);
}
Пример #3
0
int
copy_file(const FTSENT *entp, int dne)
{
	static char *buf = NULL;
	static size_t bufsize;
	struct stat *fs;
	ssize_t wcount;
	size_t wresid;
	off_t wtotal;
	int ch, checkch, from_fd = 0, rcount, rval, to_fd = 0;
	char *bufp;
#ifdef VM_AND_BUFFER_CACHE_SYNCHRONIZED
	char *p;
#endif

	if ((from_fd = open(entp->fts_path, O_RDONLY, 0)) == -1) {
		warn("%s", entp->fts_path);
		return (1);
	}

	fs = entp->fts_statp;

	/*
	 * If the file exists and we're interactive, verify with the user.
	 * If the file DNE, set the mode to be the from file, minus setuid
	 * bits, modified by the umask; arguably wrong, but it makes copying
	 * executables work right and it's been that way forever.  (The
	 * other choice is 666 or'ed with the execute bits on the from file
	 * modified by the umask.)
	 */
	if (!dne) {
#define YESNO "(y/n [n]) "
		if (nflag) {
			if (vflag)
				printf("%s not overwritten\n", to.p_path);
			(void)close(from_fd);
			return (0);
		} else if (iflag) {
			(void)fprintf(stderr, "overwrite %s? %s", 
					to.p_path, YESNO);
			checkch = ch = getchar();
			while (ch != '\n' && ch != EOF)
				ch = getchar();
			if (checkch != 'y' && checkch != 'Y') {
				(void)close(from_fd);
				(void)fprintf(stderr, "not overwritten\n");
				return (1);
			}
		}
		
		if (fflag) {
		    /* remove existing destination file name, 
		     * create a new file  */
		    (void)unlink(to.p_path);
				if (!lflag)
		    	to_fd = open(to.p_path, O_WRONLY | O_TRUNC | O_CREAT,
				  fs->st_mode & ~(S_ISUID | S_ISGID));
		} else {
				if (!lflag)
		    	/* overwrite existing destination file name */
		    	to_fd = open(to.p_path, O_WRONLY | O_TRUNC, 0);
		}
	} else {
		if (!lflag)
			to_fd = open(to.p_path, O_WRONLY | O_TRUNC | O_CREAT,
		  fs->st_mode & ~(S_ISUID | S_ISGID));
	}
	
	if (to_fd == -1) {
		warn("%s", to.p_path);
		(void)close(from_fd);
		return (1);
	}

	rval = 0;

	if (!lflag) {
		/*
		 * Mmap and write if less than 8M (the limit is so we don't totally
		 * trash memory on big files.  This is really a minor hack, but it
		 * wins some CPU back.
		 * Some filesystems, such as smbnetfs, don't support mmap,
		 * so this is a best-effort attempt.
		 */
#ifdef VM_AND_BUFFER_CACHE_SYNCHRONIZED
		if (S_ISREG(fs->st_mode) && fs->st_size > 0 &&
	    	    fs->st_size <= 8 * 1024 * 1024 &&
		    (p = mmap(NULL, (size_t)fs->st_size, PROT_READ,
		    MAP_SHARED, from_fd, (off_t)0)) != MAP_FAILED) {
			wtotal = 0;
			for (bufp = p, wresid = fs->st_size; ;
			bufp += wcount, wresid -= (size_t)wcount) {
				wcount = write(to_fd, bufp, wresid);
				if (wcount <= 0)
					break;
				wtotal += wcount;
				if (info) {
					info = 0;
					(void)fprintf(stderr,
					    "%s -> %s %3d%%\n",
					    entp->fts_path, to.p_path,
					    cp_pct(wtotal, fs->st_size));
				}
				if (wcount >= (ssize_t)wresid)
					break;
			}
			if (wcount != (ssize_t)wresid) {
				warn("%s", to.p_path);
				rval = 1;
			}
			/* Some systems don't unmap on close(2). */
			if (munmap(p, fs->st_size) < 0) {
				warn("%s", entp->fts_path);
				rval = 1;
			}
		} else
#endif
		{
			if (buf == NULL) {
				/*
				 * Note that buf and bufsize are static. If
				 * malloc() fails, it will fail at the start
				 * and not copy only some files. 
				 */ 
				if (sysconf(_SC_PHYS_PAGES) > 
				    PHYSPAGES_THRESHOLD)
					bufsize = MIN(BUFSIZE_MAX, MAXPHYS * 8);
				else
					bufsize = BUFSIZE_SMALL;
				buf = malloc(bufsize);
				if (buf == NULL)
					err(1, "Not enough memory");
			}
			wtotal = 0;
			while ((rcount = read(from_fd, buf, bufsize)) > 0) {
				for (bufp = buf, wresid = rcount; ;
			    	bufp += wcount, wresid -= wcount) {
					wcount = write(to_fd, bufp, wresid);
					if (wcount <= 0)
						break;
					wtotal += wcount;
					if (info) {
						info = 0;
						(void)fprintf(stderr,
						    "%s -> %s %3d%%\n",
						    entp->fts_path, to.p_path,
						    cp_pct(wtotal, fs->st_size));
					}
					if (wcount >= (ssize_t)wresid)
						break;
				}
				if (wcount != (ssize_t)wresid) {
					warn("%s", to.p_path);
					rval = 1;
					break;
				}
			}
			if (rcount < 0) {
				warn("%s", entp->fts_path);
				rval = 1;
			}
		}
	} else {
		if (link(entp->fts_path, to.p_path)) {
			warn("%s", to.p_path);
			rval = 1;
		}
	}
	
	/*
	 * Don't remove the target even after an error.  The target might
	 * not be a regular file, or its attributes might be important,
	 * or its contents might be irreplaceable.  It would only be safe
	 * to remove it if we created it and its length is 0.
	 */

	if (!lflag) {
		if (pflag && setfile(fs, to_fd))
			rval = 1;
		if (pflag && preserve_fd_acls(from_fd, to_fd) != 0)
			rval = 1;
		if (close(to_fd)) {
			warn("%s", to.p_path);
			rval = 1;
		}
	}

	(void)close(from_fd);

	return (rval);
}
Пример #4
0
int copy_file(const FTSENT *entp, int dne) {
	static char *buf = NULL;
	static size_t bufsize;
	struct stat *fs;
	ssize_t wcount;
	size_t wresid;
	off_t wtotal;
	int ch, checkch, from_fd = 0, rcount, rval, to_fd = 0;
	char *bufp;
	#ifdef VM_AND_BUFFER_CACHE_SYNCHRONIZED
		char *p;
	#endif

	if ((from_fd = open(entp->fts_path, O_RDONLY, 0)) == -1) {
		warn("%s", entp->fts_path);
		return (1);
	}
	fs = entp->fts_statp;
	if (!dne) {
		#define YESNO "(y/n [n]) "
		if (nflag) {
			if (vflag)
				printf("%s not overwritten\n", to.p_path);
			(void)close(from_fd);
			return (1);
		} else if (iflag) {
			(void)fprintf(stderr, "overwrite %s? %s", to.p_path, YESNO);
			checkch = ch = getchar();
			while (ch != '\n' && ch != EOF)
				ch = getchar();
			if (checkch != 'y' && checkch != 'Y') {
				(void)close(from_fd);
				(void)fprintf(stderr, "not overwritten\n");
				return (1);
			}
		}
		if (fflag) {
			(void)unlink(to.p_path);
			if (!lflag)
			to_fd = open(to.p_path, O_WRONLY | O_TRUNC | O_CREAT, fs->st_mode & ~(S_ISUID | S_ISGID));
		} else {
			if (!lflag)
				to_fd = open(to.p_path, O_WRONLY | O_TRUNC, 0);
		}
	} else {
		if (!lflag)
			to_fd = open(to.p_path, O_WRONLY | O_TRUNC | O_CREAT, fs->st_mode & ~(S_ISUID | S_ISGID));
	}
	if (to_fd == -1) {
		warn("%s", to.p_path);
		(void)close(from_fd);
		return (1);
	}
	rval = 0;
	if (!lflag) {
		#ifdef VM_AND_BUFFER_CACHE_SYNCHRONIZED
			if (S_ISREG(fs->st_mode) && fs->st_size > 0 && fs->st_size <= 8 * 1024 * 1024 &&
(p = mmap(NULL, (size_t)fs->st_size, PROT_READ, MAP_SHARED, from_fd, (off_t)0)) != MAP_FAILED) {
				wtotal = 0;
				for (bufp = p, wresid = fs->st_size; ; bufp += wcount, wresid -= (size_t)wcount) {
					wcount = write(to_fd, bufp, wresid);
					if (wcount <= 0)
						break;
					wtotal += wcount;
					if (info) {
						info = 0;
						(void)fprintf(stderr, "%s -> %s %3d%%\n", entp->fts_path, to.p_path, cp_pct(wtotal, fs->st_size));
					}
					if (wcount >= (ssize_t)wresid)
						break;
				}
				if (wcount != (ssize_t)wresid) {
					warn("%s", to.p_path);
					rval = 1;
				}
				if (munmap(p, fs->st_size) < 0) {
					warn("%s", entp->fts_path);
					rval = 1;
				}
			} else
		#endif
		{
			if (buf == NULL) {
				if (sysconf(_SC_PHYS_PAGES) > PHYSPAGES_THRESHOLD)
					bufsize = MIN(BUFSIZE_MAX, MAXPHYS * 8);
				else
					bufsize = BUFSIZE_SMALL;
				buf = malloc(bufsize);
				if (buf == NULL)
					err(1, "Not enough memory");
			}
			wtotal = 0;
			while ((rcount = read(from_fd, buf, bufsize)) > 0) {
				for (bufp = buf, wresid = rcount; ; 	bufp += wcount, wresid -= wcount) {
					wcount = write(to_fd, bufp, wresid);
					if (wcount <= 0)
						break;
					wtotal += wcount;
					if (info) {
						info = 0;
						(void)fprintf(stderr, "%s -> %s %3d%%\n", entp->fts_path, to.p_path, cp_pct(wtotal, fs->st_size));
					}
					if (wcount >= (ssize_t)wresid)
						break;
				}
				if (wcount != (ssize_t)wresid) {
					warn("%s", to.p_path);
					rval = 1;
					break;
				}
			}
			if (rcount < 0) {
				warn("%s", entp->fts_path);
				rval = 1;
			}
		}
	} else {
		if (link(entp->fts_path, to.p_path)) {
			warn("%s", to.p_path);
			rval = 1;
		}
	}
	if (!lflag) {
		if (pflag && setfile(fs, to_fd))
			rval = 1;
		if (pflag && preserve_fd_acls(from_fd, to_fd) != 0)
			rval = 1;
		if (close(to_fd)) {
			warn("%s", to.p_path);
			rval = 1;
		}
	}
	(void)close(from_fd);
	return (rval);
}