diff options
author | jmg <jmg@FreeBSD.org> | 2003-06-22 07:02:17 +0000 |
---|---|---|
committer | jmg <jmg@FreeBSD.org> | 2003-06-22 07:02:17 +0000 |
commit | 89d97224ada27ba909dd891c1d0dbf7099bb7f3b (patch) | |
tree | 79227fc88c0c5a535e8b79af14d052fafaa4a29f /bin/cp | |
parent | da04867aac79bd019712c7a10948711290c1740a (diff) | |
download | FreeBSD-src-89d97224ada27ba909dd891c1d0dbf7099bb7f3b.zip FreeBSD-src-89d97224ada27ba909dd891c1d0dbf7099bb7f3b.tar.gz |
support saving both user/group and permissions on symlinks (from PR)
also fix a slight bogon that assumed an fd of 0 was not valid. Changed
it to be -1.
PR: bin/25017
Submitted by: Martin Kammerhofer
Diffstat (limited to 'bin/cp')
-rw-r--r-- | bin/cp/utils.c | 33 |
1 files changed, 20 insertions, 13 deletions
diff --git a/bin/cp/utils.c b/bin/cp/utils.c index aa1559e..e8c542c 100644 --- a/bin/cp/utils.c +++ b/bin/cp/utils.c @@ -233,7 +233,7 @@ copy_link(const FTSENT *p, int exists) warn("symlink: %s", llink); return (1); } - return (0); + return (pflag ? setfile(p->fts_statp, -1) : 0); } int @@ -247,7 +247,7 @@ copy_fifo(struct stat *from_stat, int exists) warn("mkfifo: %s", to.p_path); return (1); } - return (pflag ? setfile(from_stat, 0) : 0); + return (pflag ? setfile(from_stat, -1) : 0); } int @@ -261,7 +261,7 @@ copy_special(struct stat *from_stat, int exists) warn("mknod: %s", to.p_path); return (1); } - return (pflag ? setfile(from_stat, 0) : 0); + return (pflag ? setfile(from_stat, -1) : 0); } int @@ -269,20 +269,22 @@ setfile(struct stat *fs, int fd) { static struct timeval tv[2]; struct stat ts; - int rval; - int gotstat; + int rval, gotstat, islink, fdval; rval = 0; + fdval = fd != -1; + islink = !fdval && S_ISLNK(fs->st_mode); fs->st_mode &= S_ISUID | S_ISGID | S_ISVTX | S_IRWXU | S_IRWXG | S_IRWXO; TIMESPEC_TO_TIMEVAL(&tv[0], &fs->st_atimespec); TIMESPEC_TO_TIMEVAL(&tv[1], &fs->st_mtimespec); - if (utimes(to.p_path, tv)) { - warn("utimes: %s", to.p_path); + if (islink ? lutimes(to.p_path, tv) : utimes(to.p_path, tv)) { + warn("%sutimes: %s", islink ? "l" : "", to.p_path); rval = 1; } - if (fd ? fstat(fd, &ts) : stat(to.p_path, &ts)) + if (fdval ? fstat(fd, &ts) : + (islink ? lstat(to.p_path, &ts) : stat(to.p_path, &ts))) gotstat = 0; else { gotstat = 1; @@ -296,8 +298,9 @@ setfile(struct stat *fs, int fd) * chown. If chown fails, lose setuid/setgid bits. */ if (!gotstat || fs->st_uid != ts.st_uid || fs->st_gid != ts.st_gid) - if (fd ? fchown(fd, fs->st_uid, fs->st_gid) : - chown(to.p_path, fs->st_uid, fs->st_gid)) { + if (fdval ? fchown(fd, fs->st_uid, fs->st_gid) : + (islink ? lchown(to.p_path, fs->st_uid, fs->st_gid) : + chown(to.p_path, fs->st_uid, fs->st_gid))) { if (errno != EPERM) { warn("chown: %s", to.p_path); rval = 1; @@ -306,14 +309,18 @@ setfile(struct stat *fs, int fd) } if (!gotstat || fs->st_mode != ts.st_mode) - if (fd ? fchmod(fd, fs->st_mode) : chmod(to.p_path, fs->st_mode)) { + if (fdval ? fchmod(fd, fs->st_mode) : + (islink ? lchmod(to.p_path, fs->st_mode) : + chmod(to.p_path, fs->st_mode))) { warn("chmod: %s", to.p_path); rval = 1; } if (!gotstat || fs->st_flags != ts.st_flags) - if (fd ? - fchflags(fd, fs->st_flags) : chflags(to.p_path, fs->st_flags)) { + if (fdval ? + fchflags(fd, fs->st_flags) : + (islink ? (errno = ENOSYS) : + chflags(to.p_path, fs->st_flags))) { warn("chflags: %s", to.p_path); rval = 1; } |