Ejemplo n.º 1
0
Archivo: mv.c Proyecto: antoineL/netbsd
static int
fastcopy(char *from, char *to, struct stat *sbp)
{
#if defined(__NetBSD__)
	struct timespec ts[2];
#else
	struct timeval tval[2];
#endif
	static blksize_t blen;
	static char *bp;
	int nread, from_fd, to_fd;

	if ((from_fd = open(from, O_RDONLY, 0)) < 0) {
		warn("%s", from);
		return (1);
	}
	if ((to_fd =
	    open(to, O_CREAT | O_TRUNC | O_WRONLY, sbp->st_mode)) < 0) {
		warn("%s", to);
		(void)close(from_fd);
		return (1);
	}
	if (!blen && !(bp = malloc(blen = sbp->st_blksize))) {
		warn(NULL);
		blen = 0;
		(void)close(from_fd);
		(void)close(to_fd);
		return (1);
	}
	while ((nread = read(from_fd, bp, blen)) > 0)
		if (write(to_fd, bp, 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);
	}

	if (fcpxattr(from_fd, to_fd) == -1)
		warn("%s: error copying extended attributes", to);

	(void)close(from_fd);
#ifdef BSD4_4
#if defined(__NetBSD__)
	ts[0] = sbp->st_atimespec;
	ts[1] = sbp->st_mtimespec;
#else
	TIMESPEC_TO_TIMEVAL(&tval[0], &sbp->st_atimespec);
	TIMESPEC_TO_TIMEVAL(&tval[1], &sbp->st_mtimespec);
#endif
#else
	tval[0].tv_sec = sbp->st_atime;
	tval[1].tv_sec = sbp->st_mtime;
	tval[0].tv_usec = 0;
	tval[1].tv_usec = 0;
#endif
#ifdef __SVR4
	if (utimes(to, tval))
#else
#if defined(__NetBSD__)
	if (futimens(to_fd, ts))
#else
	if (futimes(to_fd, tval))
#endif
#endif
		warn("%s: set times", to);
	if (fchown(to_fd, sbp->st_uid, sbp->st_gid)) {
		if (errno != EPERM)
			warn("%s: set owner/group", to);
		sbp->st_mode &= ~(S_ISUID | S_ISGID);
	}
	if (fchmod(to_fd, sbp->st_mode))
		warn("%s: set mode", to);
	if (fchflags(to_fd, sbp->st_flags) && (errno != EOPNOTSUPP))
		warn("%s: set flags (was: 0%07o)", to, sbp->st_flags);

	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);
}
Ejemplo n.º 2
0
int
copy_file(FTSENT *entp, int dne)
{
	static char buf[MAXBSIZE];
	struct stat to_stat, *fs;
	int ch, checkch, from_fd, rcount, rval, to_fd, tolnk, wcount;
	char *p;
	off_t ptotal = 0;
	
	if ((from_fd = open(entp->fts_path, O_RDONLY, 0)) == -1) {
		warn("%s", entp->fts_path);
		return (1);
	}

	to_fd = -1;
	fs = entp->fts_statp;
	tolnk = ((Rflag && !(Lflag || Hflag)) || Pflag);

	/*
	 * 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) {
		struct stat sb;
		int sval;

		if (iflag) {
			(void)fprintf(stderr, "overwrite %s? ", to.p_path);
			checkch = ch = getchar();
			while (ch != '\n' && ch != EOF)
				ch = getchar();
			if (checkch != 'y' && checkch != 'Y') {
				(void)close(from_fd);
				return (0);
			}
		}

		sval = tolnk ?
			lstat(to.p_path, &sb) : stat(to.p_path, &sb);
		if (sval == -1) {
			warn("stat: %s", to.p_path);
			(void)close(from_fd);
			return (1);
		}

		if (!(tolnk && S_ISLNK(sb.st_mode)))
			to_fd = open(to.p_path, O_WRONLY | O_TRUNC, 0);
	} else
		to_fd = open(to.p_path, O_WRONLY | O_TRUNC | O_CREAT,
		    fs->st_mode & ~(S_ISUID | S_ISGID));

	if (to_fd == -1 && (fflag || tolnk)) {
		/*
		 * attempt to remove existing destination file name and
		 * create a new file
		 */
		(void)unlink(to.p_path);
		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 hard linking then simply close the open fds, link and return */
	if (lflag) {
		(void)close(from_fd);
		(void)close(to_fd);
		(void)unlink(to.p_path);
		if (link(entp->fts_path, to.p_path)) {
			warn("%s", to.p_path);
			return (1);
		}
		return (0);
	}

	/*
	 * There's no reason to do anything other than close the file
	 * now if it's empty, so let's not bother.
	 */
	if (fs->st_size > 0) {
		struct finfo fi;

		fi.from = entp->fts_path;
		fi.to = to.p_path;
		fi.size = fs->st_size;

		/*
		 * 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.
		 */
		bool use_read;

		use_read = true;
		if (fs->st_size <= MMAP_MAX_SIZE) {
			size_t fsize = (size_t)fs->st_size;
			p = mmap(NULL, fsize, PROT_READ, MAP_FILE|MAP_SHARED,
			    from_fd, (off_t)0);
			if (p != MAP_FAILED) {
				size_t remainder;

				use_read = false;

				(void) madvise(p, (size_t)fs->st_size,
				     MADV_SEQUENTIAL);

				/*
				 * Write out the data in small chunks to
				 * avoid locking the output file for a
				 * long time if the reading the data from
				 * the source is slow.
				 */
				remainder = fsize;
				do {
					ssize_t chunk;

					chunk = (remainder > MMAP_MAX_WRITE) ?
					    MMAP_MAX_WRITE : remainder;
					if (write(to_fd, &p[fsize - remainder],
					    chunk) != chunk) {
						warn("%s", to.p_path);
						rval = 1;
						break;
					}
					remainder -= chunk;
					ptotal += chunk;
					if (pinfo)
						progress(&fi, ptotal);
				} while (remainder > 0);

				if (munmap(p, fsize) < 0) {
					warn("%s", entp->fts_path);
					rval = 1;
				}
			}
		}

		if (use_read) {
			while ((rcount = read(from_fd, buf, MAXBSIZE)) > 0) {
				wcount = write(to_fd, buf, (size_t)rcount);
				if (rcount != wcount || wcount == -1) {
					warn("%s", to.p_path);
					rval = 1;
					break;
				}
				ptotal += wcount;
				if (pinfo)
					progress(&fi, ptotal);
			}
			if (rcount < 0) {
				warn("%s", entp->fts_path);
				rval = 1;
			}
		}
	}

	if (pflag && (fcpxattr(from_fd, to_fd) != 0))
		warn("%s: error copying extended attributes", to.p_path);

	(void)close(from_fd);

	if (rval == 1) {
		(void)close(to_fd);
		return (1);
	}

	if (pflag && setfile(fs, to_fd))
		rval = 1;
	/*
	 * If the source was setuid or setgid, lose the bits unless the
	 * copy is owned by the same user and group.
	 */
#define	RETAINBITS \
	(S_ISUID | S_ISGID | S_ISVTX | S_IRWXU | S_IRWXG | S_IRWXO)
	if (!pflag && dne
	    && fs->st_mode & (S_ISUID | S_ISGID) && fs->st_uid == myuid) {
		if (fstat(to_fd, &to_stat)) {
			warn("%s", to.p_path);
			rval = 1;
		} else if (fs->st_gid == to_stat.st_gid &&
		    fchmod(to_fd, fs->st_mode & RETAINBITS & ~myumask)) {
			warn("%s", to.p_path);
			rval = 1;
		}
	}
	if (close(to_fd)) {
		warn("%s", to.p_path);
		rval = 1;
	}
	/* set the mod/access times now after close of the fd */
	if (pflag && set_utimes(to.p_path, fs)) { 
	    rval = 1;
	}
	return (rval);
}