diff options
author | Ondřej Vašík <ovasik@redhat.com> | 2009-09-14 14:12:01 +0100 |
---|---|---|
committer | Pádraig Brady <P@draigBrady.com> | 2009-09-14 14:19:03 +0100 |
commit | cca83fafa69eb26db458714830b77498b88af8a4 (patch) | |
tree | 6802df397ac2c1c59ed50c58aed04d823b0d8e59 /src | |
parent | eb1299481aeda0c1b10d0186e00a088597e603a8 (diff) | |
download | coreutils-cca83fafa69eb26db458714830b77498b88af8a4.tar.xz |
cp,mv: preserve extended attributes even for read-only files
* src/copy.c (copy_reg): Temporarily set u+rw on the destination file
to allow GNU/Linux to set xattrs.
* tests/misc/xattr: Test that change.
* NEWS (Bug fixes): Mention it.
Reported by Ernest N. Mamikonyan.
Diffstat (limited to 'src')
-rw-r--r-- | src/copy.c | 23 |
1 files changed, 18 insertions, 5 deletions
diff --git a/src/copy.c b/src/copy.c index f3ff5a286..ad2060b9c 100644 --- a/src/copy.c +++ b/src/copy.c @@ -834,6 +834,24 @@ copy_reg (char const *src_name, char const *dst_name, } } + /* To allow copying xattrs on read-only files, temporarily chmod u+rw. + This workaround is required as an inode permission check is done + by xattr_permission() in fs/xattr.c of the GNU/Linux kernel tree. */ + if (x->preserve_xattr) + { + bool access_changed = true; + + if (!(sb.st_mode & S_IWUSR) && geteuid() != 0) + access_changed = fchmod_or_lchmod (dest_desc, dst_name, 0600) == 0; + + if (!copy_attr_by_fd (src_name, source_desc, dst_name, dest_desc, x) + && x->require_preserve_xattr) + return_val = false; + + if (access_changed) + fchmod_or_lchmod (dest_desc, dst_name, dst_mode & ~omitted_permissions); + } + if (x->preserve_ownership && ! SAME_OWNER_AND_GROUP (*src_sb, sb)) { switch (set_owner (x, dst_name, dest_desc, src_sb, *new_dst, &sb)) @@ -850,11 +868,6 @@ copy_reg (char const *src_name, char const *dst_name, set_author (dst_name, dest_desc, src_sb); - if (x->preserve_xattr && ! copy_attr_by_fd (src_name, source_desc, - dst_name, dest_desc, x) - && x->require_preserve_xattr) - return_val = false; - if (x->preserve_mode || x->move_mode) { if (copy_acl (src_name, source_desc, dst_name, dest_desc, src_mode) != 0 |