Beispiel #1
0
static void ScandirNCAT(PCStr(path),PCStr(rdir),scanDirCallP func,PCStr(arg))
{	FileStat st;

	stat(path,&st);
	Scandir(rdir,func,arg);
	set_utimes(path,st.st_atime,st.st_mtime);
}
Beispiel #2
0
/*
 * Function: setfile
 *
 * Purpose:
 *   Set the owner/group/permissions for the "to" file to the information
 *   in the stat structure.  If fd is zero, also call set_utimes() to set
 *   the mod/access times.  If fd is non-zero, the caller must do a utimes
 *   itself after close(fd).
 */
int
setfile(struct stat *fs, int fd)
{
	int rval;
#if HAVE_MEMBER_STRUCT_STAT_ST_FLAGS_SYS_STAT_H
	int islink;
#endif

	rval = 0;
#if HAVE_MEMBER_STRUCT_STAT_ST_FLAGS_SYS_STAT_H
	islink = S_ISLNK(fs->st_mode);
#endif
	fs->st_mode &= S_ISUID | S_ISGID | S_IRWXU | S_IRWXG | S_IRWXO;

	/*
	 * Changing the ownership probably won't succeed, unless we're root
	 * or POSIX_CHOWN_RESTRICTED is not set.  Set uid/gid before setting
	 * the mode; current BSD behavior is to remove all setuid bits on
	 * chown.  If chown fails, lose setuid/setgid bits.
	 */
	if (fd ? fchown(fd, fs->st_uid, fs->st_gid) :
	    lchown(to.p_path, fs->st_uid, fs->st_gid)) {
		if (errno != EPERM) {
			warn("chown: %s", to.p_path);
			rval = 1;
		}
		fs->st_mode &= ~(S_ISUID | S_ISGID);
	}
	if (fd ? fchmod(fd, fs->st_mode) : lchmod(to.p_path, fs->st_mode)) {
		warn("chmod: %s", to.p_path);
		rval = 1;
	}

#if HAVE_MEMBER_STRUCT_STAT_ST_FLAGS_SYS_STAT_H
	if (!islink && !Nflag) {
		unsigned long fflags = fs->st_flags;
		/*
		 * 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 ((fd ? fchflags(fd, fflags) :
		    chflags(to.p_path, fflags)) == -1)
			if (errno != EOPNOTSUPP || fs->st_flags != 0) {
				warn("chflags: %s", to.p_path);
				rval = 1;
			}
	}
#endif /* HAVE_MEMBER_STRUCT_STAT_ST_FLAGS_SYS_STAT_H */

	/* if fd is non-zero, caller must call set_utimes() after close() */
	if (fd == 0 && set_utimes(to.p_path, fs))
	    rval = 1;
	return (rval);
}
Beispiel #3
0
int File_copymod(PCStr(src),PCStr(dst))
{	FileStat st;

	if( stat(src,&st) == 0 ){
		if( chmod(dst,st.st_mode) != 0 )
			return -1;
		if( set_utimes(dst,st.st_atime,st.st_mtime) != 0 )
			return -1;
		return 0;
	}
	return -1;
}
Beispiel #4
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);
}
Beispiel #5
0
int
copy_file(FTSENT *entp, int dne)
{
	static unsigned char buf[MAXBSIZE];
	struct stat to_stat, *fs;
	int ch, checkch, rv, rcount, rval, tolnk, wcount, fdin, fdout;
	off_t off;

	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) {
		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')
				return (0);
		}
		rump_sys_unlink(to.p_path);
	}

	rv = rump_sys_open(to.p_path, fs->st_mode & ~(S_ISUID | S_ISGID));
	if (rv == -1 && (fflag || tolnk)) {
		/*
		 * attempt to remove existing destination file name and
		 * create a new file
		 */
		rump_sys_unlink(to.p_path);
		rv = rump_sys_open(to.p_path,
				 fs->st_mode & ~(S_ISUID | S_ISGID));
		if (rv == -1) {
			warn("%s", to.p_path);
			return (1);
		}
	}
	fdout = rv;
	fdin = rump_sys_open(entp->fts_path, O_RDONLY);

	rval = 0;
	/*
	 * There's no reason to do anything other than close the file
	 * now if it's empty, so let's not bother.
	 */
	off = 0;
	if (fs->st_size > 0) {
		while ((rcount = rump_sys_read(fdin, buf, MAXBSIZE)) > 0) {
			wcount = rump_sys_write(fdout, buf, (size_t)rcount);
			if (rcount != wcount || wcount == -1) {
				warn("%s", to.p_path);
				rval = 1;
				break;
			}
			off += rcount;
		}
		if (rcount < 0) {
			warn("%s", entp->fts_path);
			rval = 1;
		}
	}

	if (rval == 1)
		return (1);

	if (pflag && setfile(fs, 0))
		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 (rump_sys_stat(to.p_path, &to_stat)) {
			warn("%s", to.p_path);
			rval = 1;
		} else if (fs->st_gid == to_stat.st_gid &&
			   rump_sys_chmod(to.p_path,
				      fs->st_mode & RETAINBITS & ~myumask)) {
			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);
}
Beispiel #6
0
/*
 * Function: setfile
 *
 * Purpose:
 *   Set the owner/group/permissions for the "to" file to the information
 *   in the stat structure.  If fd is zero, also call set_utimes() to set
 *   the mod/access times.  If fd is non-zero, the caller must do a utimes
 *   itself after close(fd).
 */
int
setfile(struct stat *fs, int fd)
{
	int rval = 0;
#ifdef BSD
	int islink = S_ISLNK(fs->st_mode);
#endif

	fs->st_mode &= S_ISUID | S_ISGID | S_IRWXU | S_IRWXG | S_IRWXO;

	/*
	 * Changing the ownership probably won't succeed, unless we're root
	 * or POSIX_CHOWN_RESTRICTED is not set.  Set uid/gid before setting
	 * the mode; current BSD behavior is to remove all setuid bits on
	 * chown.  If chown fails, lose setuid/setgid bits.
	 */
	if (fd ? fchown(fd, fs->st_uid, fs->st_gid) :
	    lchown(to.p_path, fs->st_uid, fs->st_gid)) {
		if (errno != EPERM) {
			warn("chown: %s", to.p_path);
			rval = 1;
		}
		fs->st_mode &= ~(S_ISUID | S_ISGID);
	}
#ifndef BSD
    if (fd ? fchmod(fd, fs->st_mode) : chmod(to.p_path, fs->st_mode)) {
#else
    if (fd ? fchmod(fd, fs->st_mode) : lchmod(to.p_path, fs->st_mode)) {
#endif
        warn("chmod: %s", to.p_path);
        rval = 1;
    }

#ifdef BSD
	if (!islink && !Nflag) {
		unsigned long fflags = fs->st_flags;
		/*
		 * 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 ((fd ? fchflags(fd, fflags) :
		    chflags(to.p_path, fflags)) == -1)
			if (errno != EOPNOTSUPP || fs->st_flags != 0) {
				warn("chflags: %s", to.p_path);
				rval = 1;
			}
	}
#endif
	/* if fd is non-zero, caller must call set_utimes() after close() */
	if (fd == 0 && set_utimes(to.p_path, fs))
	    rval = 1;
	return (rval);
}

void
cp_usage(void)
{
	(void)fprintf(stderr,
	    "usage: cp [-R [-H | -L | -P]] [-f | -i] [-alNpv] src target\n"
	    "       cp [-R [-H | -L | -P]] [-f | -i] [-alNpv] src1 ... srcN directory\n");
	exit(1);
	/* NOTREACHED */
}