summaryrefslogtreecommitdiff
path: root/src/copy.c
diff options
context:
space:
mode:
authorOndřej Vašík <ovasik@redhat.com>2009-09-14 14:12:01 +0100
committerPádraig Brady <P@draigBrady.com>2009-09-14 14:19:03 +0100
commitcca83fafa69eb26db458714830b77498b88af8a4 (patch)
tree6802df397ac2c1c59ed50c58aed04d823b0d8e59 /src/copy.c
parenteb1299481aeda0c1b10d0186e00a088597e603a8 (diff)
downloadcoreutils-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/copy.c')
-rw-r--r--src/copy.c23
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