Ondrej Vasik 6a4350
From cca83fafa69eb26db458714830b77498b88af8a4 Mon Sep 17 00:00:00 2001
Ondrej Vasik 6a4350
From: Ondřej Vašík <ovasik@redhat.com>
Ondrej Vasik 6a4350
Date: Mon, 14 Sep 2009 13:12:01 +0000
Ondrej Vasik 6a4350
Subject: cp,mv: preserve extended attributes even for read-only files
Ondrej Vasik 6a4350
Ondrej Vasik 6a4350
* src/copy.c (copy_reg): Temporarily set u+rw on the destination file
Ondrej Vasik 6a4350
to allow GNU/Linux to set xattrs.
Ondrej Vasik 6a4350
* tests/misc/xattr: Test that change.
Ondrej Vasik 6a4350
Reported by Ernest N. Mamikonyan.
Ondrej Vasik 6a4350
---
Ondrej Vasik 6a4350
diff --git a/src/copy.c b/src/copy.c
Ondrej Vasik 6a4350
index f3ff5a2..ad2060b 100644
Ondrej Vasik 6a4350
--- a/src/copy.c
Ondrej Vasik 6a4350
+++ b/src/copy.c
Ondrej Vasik 6a4350
@@ -834,6 +834,24 @@ copy_reg (char const *src_name, char const *dst_name,
Ondrej Vasik 6a4350
         }
Ondrej Vasik 6a4350
     }
Ondrej Vasik 6a4350
 
Ondrej Vasik 6a4350
+  /* To allow copying xattrs on read-only files, temporarily chmod u+rw.
Ondrej Vasik 6a4350
+     This workaround is required as an inode permission check is done
Ondrej Vasik 6a4350
+     by xattr_permission() in fs/xattr.c of the GNU/Linux kernel tree.  */
Ondrej Vasik 6a4350
+  if (x->preserve_xattr)
Ondrej Vasik 6a4350
+    {
Ondrej Vasik 6a4350
+      bool access_changed = false;
Ondrej Vasik 6a4350
+
Ondrej Vasik 6a4350
+      if (!(sb.st_mode & S_IWUSR) && geteuid() != 0)
Ondrej Vasik 6a4350
+        access_changed = fchmod_or_lchmod (dest_desc, dst_name, 0600) == 0;
Ondrej Vasik 6a4350
+
Ondrej Vasik 6a4350
+      if (!copy_attr_by_fd (src_name, source_desc, dst_name, dest_desc, x)
Ondrej Vasik 6a4350
+          && x->require_preserve_xattr)
Ondrej Vasik 6a4350
+        return_val = false;
Ondrej Vasik 6a4350
+
Ondrej Vasik 6a4350
+      if (access_changed)
Ondrej Vasik 6a4350
+        fchmod_or_lchmod (dest_desc, dst_name, dst_mode & ~omitted_permissions);
Ondrej Vasik 6a4350
+    }
Ondrej Vasik 6a4350
+
Ondrej Vasik 6a4350
   if (x->preserve_ownership && ! SAME_OWNER_AND_GROUP (*src_sb, sb))
Ondrej Vasik 6a4350
     {
Ondrej Vasik 6a4350
       switch (set_owner (x, dst_name, dest_desc, src_sb, *new_dst, &sb))
Ondrej Vasik 6a4350
@@ -850,11 +868,6 @@ copy_reg (char const *src_name, char const *dst_name,
Ondrej Vasik 6a4350
 
Ondrej Vasik 6a4350
   set_author (dst_name, dest_desc, src_sb);
Ondrej Vasik 6a4350
 
Ondrej Vasik 6a4350
-  if (x->preserve_xattr && ! copy_attr_by_fd (src_name, source_desc,
Ondrej Vasik 6a4350
-                                              dst_name, dest_desc, x)
Ondrej Vasik 6a4350
-      && x->require_preserve_xattr)
Ondrej Vasik 6a4350
-    return_val = false;
Ondrej Vasik 6a4350
-
Ondrej Vasik 6a4350
   if (x->preserve_mode || x->move_mode)
Ondrej Vasik 6a4350
     {
Ondrej Vasik 6a4350
       if (copy_acl (src_name, source_desc, dst_name, dest_desc, src_mode) != 0
Ondrej Vasik 6a4350
diff --git a/tests/misc/xattr b/tests/misc/xattr
Ondrej Vasik 6a4350
index a27e1f6..fcf7ceb 100755
Ondrej Vasik 6a4350
--- a/tests/misc/xattr
Ondrej Vasik 6a4350
+++ b/tests/misc/xattr
Ondrej Vasik 6a4350
@@ -29,7 +29,7 @@ fi
Ondrej Vasik 6a4350
 
Ondrej Vasik 6a4350
 # Skip this test if cp was built without xattr support:
Ondrej Vasik 6a4350
 touch src dest || framework_failure
Ondrej Vasik 6a4350
-cp --preserve=xattr -n src dest 2>/dev/null \
Ondrej Vasik 6a4350
+cp --preserve=xattr -n src dest \
Ondrej Vasik 6a4350
   || skip_test_ "coreutils built without xattr support"
Ondrej Vasik 6a4350
 
Ondrej Vasik 6a4350
 # this code was taken from test mv/backup-is-src
Ondrej Vasik 6a4350
@@ -46,13 +46,13 @@ xattr_pair="$xattr_name=\"$xattr_value\""
Ondrej Vasik 6a4350
 # create new file and check its xattrs
Ondrej Vasik 6a4350
 touch a || framework_failure
Ondrej Vasik 6a4350
 getfattr -d a >out_a || skip_test_ "failed to get xattr of file"
Ondrej Vasik 6a4350
-grep -F "$xattr_pair" out_a >/dev/null && framework_failure
Ondrej Vasik 6a4350
+grep -F "$xattr_pair" out_a && framework_failure
Ondrej Vasik 6a4350
 
Ondrej Vasik 6a4350
 # try to set user xattr on file
Ondrej Vasik 6a4350
 setfattr -n "$xattr_name" -v "$xattr_value" a >out_a \
Ondrej Vasik 6a4350
   || skip_test_ "failed to set xattr of file"
Ondrej Vasik 6a4350
 getfattr -d a >out_a || skip_test_ "failed to get xattr of file"
Ondrej Vasik 6a4350
-grep -F "$xattr_pair" out_a >/dev/null \
Ondrej Vasik 6a4350
+grep -F "$xattr_pair" out_a \
Ondrej Vasik 6a4350
   || skip_test_ "failed to set xattr of file"
Ondrej Vasik 6a4350
 
Ondrej Vasik 6a4350
 fail=0
Ondrej Vasik 6a4350
@@ -60,36 +60,50 @@ fail=0
Ondrej Vasik 6a4350
 # cp should not preserve xattr by default
Ondrej Vasik 6a4350
 cp a b || fail=1
Ondrej Vasik 6a4350
 getfattr -d b >out_b || skip_test_ "failed to get xattr of file"
Ondrej Vasik 6a4350
-grep -F "$xattr_pair" out_b >/dev/null && fail=1
Ondrej Vasik 6a4350
+grep -F "$xattr_pair" out_b && fail=1
Ondrej Vasik 6a4350
 
Ondrej Vasik 6a4350
 # test if --preserve=xattr option works
Ondrej Vasik 6a4350
 cp --preserve=xattr a b || fail=1
Ondrej Vasik 6a4350
 getfattr -d b >out_b || skip_test_ "failed to get xattr of file"
Ondrej Vasik 6a4350
-grep -F "$xattr_pair" out_b >/dev/null || fail=1
Ondrej Vasik 6a4350
+grep -F "$xattr_pair" out_b || fail=1
Ondrej Vasik 6a4350
 
Ondrej Vasik 6a4350
 #test if --preserve=all option works
Ondrej Vasik 6a4350
 cp --preserve=all a c || fail=1
Ondrej Vasik 6a4350
 getfattr -d c >out_c || skip_test_ "failed to get xattr of file"
Ondrej Vasik 6a4350
-grep -F "$xattr_pair" out_c >/dev/null || fail=1
Ondrej Vasik 6a4350
+grep -F "$xattr_pair" out_c || fail=1
Ondrej Vasik 6a4350
 
Ondrej Vasik 6a4350
 #test if -a option works without any diagnostics
Ondrej Vasik 6a4350
 cp -a a d 2>err && test -s err && fail=1
Ondrej Vasik 6a4350
 getfattr -d d >out_d || skip_test_ "failed to get xattr of file"
Ondrej Vasik 6a4350
-grep -F "$xattr_pair" out_d >/dev/null || fail=1
Ondrej Vasik 6a4350
+grep -F "$xattr_pair" out_d || fail=1
Ondrej Vasik 6a4350
+
Ondrej Vasik 6a4350
+#test if --preserve=xattr works even for files without write access
Ondrej Vasik 6a4350
+chmod a-w a || framework_failure
Ondrej Vasik 6a4350
+rm -f e
Ondrej Vasik 6a4350
+cp --preserve=xattr a e || fail=1
Ondrej Vasik 6a4350
+getfattr -d e >out_e || skip_test_ "failed to get xattr of file"
Ondrej Vasik 6a4350
+grep -F "$xattr_pair" out_e || fail=1
Ondrej Vasik 6a4350
+
Ondrej Vasik 6a4350
+#Ensure that permission bits are preserved, too.
Ondrej Vasik 6a4350
+src_perm=$(stat --format=%a a)
Ondrej Vasik 6a4350
+dst_perm=$(stat --format=%a e)
Ondrej Vasik 6a4350
+test "$dst_perm" = "$src_perm" || fail=1
Ondrej Vasik 6a4350
+
Ondrej Vasik 6a4350
+chmod u+w a || framework_failure
Ondrej Vasik 6a4350
 
Ondrej Vasik 6a4350
 rm b || framework_failure
Ondrej Vasik 6a4350
 
Ondrej Vasik 6a4350
 # install should never preserve xattr
Ondrej Vasik 6a4350
 ginstall a b || fail=1
Ondrej Vasik 6a4350
 getfattr -d b >out_b || skip_test_ "failed to get xattr of file"
Ondrej Vasik 6a4350
-grep -F "$xattr_pair" out_b >/dev/null && fail=1
Ondrej Vasik 6a4350
+grep -F "$xattr_pair" out_b && fail=1
Ondrej Vasik 6a4350
 
Ondrej Vasik 6a4350
 # mv should preserve xattr when renaming within a file system.
Ondrej Vasik 6a4350
 # This is implicitly done by rename () and doesn't need explicit
Ondrej Vasik 6a4350
 # xattr support in mv.
Ondrej Vasik 6a4350
 mv a b || fail=1
Ondrej Vasik 6a4350
 getfattr -d b >out_b || skip_test_ "failed to get xattr of file"
Ondrej Vasik 6a4350
-grep -F "$xattr_pair" out_b >/dev/null || cat >&2 <
Ondrej Vasik 6a4350
+grep -F "$xattr_pair" out_b || cat >&2 <
Ondrej Vasik 6a4350
 =================================================================
Ondrej Vasik 6a4350
 $0: WARNING!!!
Ondrej Vasik 6a4350
 rename () does not preserve extended attributes
Ondrej Vasik 6a4350
@@ -99,18 +113,18 @@ EOF
Ondrej Vasik 6a4350
 # try to set user xattr on file on other partition
Ondrej Vasik 6a4350
 test_mv=1
Ondrej Vasik 6a4350
 touch "$b_other" || framework_failure
Ondrej Vasik 6a4350
-setfattr -n "$xattr_name" -v "$xattr_value" "$b_other" >out_a 2>/dev/null \
Ondrej Vasik 6a4350
+setfattr -n "$xattr_name" -v "$xattr_value" "$b_other" >out_a \
Ondrej Vasik 6a4350
   || test_mv=0
Ondrej Vasik 6a4350
-getfattr -d "$b_other" >out_b 2>/dev/null || test_mv=0
Ondrej Vasik 6a4350
-grep -F "$xattr_pair" out_b >/dev/null || test_mv=0
Ondrej Vasik 6a4350
+getfattr -d "$b_other" >out_b || test_mv=0
Ondrej Vasik 6a4350
+grep -F "$xattr_pair" out_b || test_mv=0
Ondrej Vasik 6a4350
 rm -f "$b_other" || framework_failure
Ondrej Vasik 6a4350
 
Ondrej Vasik 6a4350
 if test $test_mv -eq 1; then
Ondrej Vasik 6a4350
   # mv should preserve xattr when copying content from one partition to another
Ondrej Vasik 6a4350
   mv b "$b_other" || fail=1
Ondrej Vasik 6a4350
-  getfattr -d "$b_other" >out_b 2>/dev/null ||
Ondrej Vasik 6a4350
+  getfattr -d "$b_other" >out_b ||
Ondrej Vasik 6a4350
     skip_test_ "failed to get xattr of file"
Ondrej Vasik 6a4350
-  grep -F "$xattr_pair" out_b >/dev/null || fail=1
Ondrej Vasik 6a4350
+  grep -F "$xattr_pair" out_b || fail=1
Ondrej Vasik 6a4350
 else
Ondrej Vasik 6a4350
   cat >&2 <
Ondrej Vasik 6a4350
 =================================================================
Ondrej Vasik 6a4350
--
Ondrej Vasik 6a4350
cgit v0.8.2.1