summaryrefslogtreecommitdiffstats
path: root/bin/cp
diff options
context:
space:
mode:
authorjmg <jmg@FreeBSD.org>2003-06-22 07:02:17 +0000
committerjmg <jmg@FreeBSD.org>2003-06-22 07:02:17 +0000
commit89d97224ada27ba909dd891c1d0dbf7099bb7f3b (patch)
tree79227fc88c0c5a535e8b79af14d052fafaa4a29f /bin/cp
parentda04867aac79bd019712c7a10948711290c1740a (diff)
downloadFreeBSD-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.c33
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;
}
OpenPOWER on IntegriCloud