]> git.ipfire.org Git - thirdparty/coreutils.git/commitdiff
cp: ensure --attributes-only doesn't remove files
authorPádraig Brady <P@draigBrady.com>
Wed, 1 Apr 2020 11:51:34 +0000 (12:51 +0100)
committerPádraig Brady <P@draigBrady.com>
Thu, 2 Apr 2020 14:44:55 +0000 (15:44 +0100)
* src/copy.c (copy_internal): Ensure we don't unlink the destination
unless explicitly requested.
* tests/cp/attr-existing.sh: Add test cases.
* NEWS: Mention the bug fix.
Fixes https://bugs.gnu.org/40352

NEWS
src/copy.c
tests/cp/attr-existing.sh

diff --git a/NEWS b/NEWS
index 653e7178b28ee9922b82a7010dc806e6b57ea1a6..b8a17c27635d44ab2ae1bbf87fd34c42a68b63a1 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -2,6 +2,13 @@ GNU coreutils NEWS                                    -*- outline -*-
 
 * Noteworthy changes in release ?.? (????-??-??) [?]
 
+** Bug fixes
+
+  cp -a --attributes-only now never removes destination files,
+  even if the destination files are hardlinked, or the source
+  is a non regular file.
+  [bug introduced in coreutils-8.6]
+
 ** Changes in behavior
 
   On GNU/Linux systems, ls no longer issues an error message on
index 6e5efc70839c4891ee58a21f369e902496e24e97..54601ce07293791008ecd3f85dc24bacdb588724 100644 (file)
@@ -2211,10 +2211,11 @@ copy_internal (char const *src_name, char const *dst_name,
                    /* Never unlink dst_name when in move mode.  */
                    && ! x->move_mode
                    && (x->unlink_dest_before_opening
-                       || (x->preserve_links && 1 < dst_sb.st_nlink)
-                       || (x->dereference == DEREF_NEVER
-                           && ! S_ISREG (src_sb.st_mode))
-                       ))
+                       || (x->data_copy_required
+                           && ((x->preserve_links && 1 < dst_sb.st_nlink)
+                               || (x->dereference == DEREF_NEVER
+                                   && ! S_ISREG (src_sb.st_mode))))
+                      ))
             {
               if (unlink (dst_name) != 0 && errno != ENOENT)
                 {
index 59ce64183213bf75ff419b41f3ffdb2c3ec2f40c..14fc8445cfe576233a7f620206ea1e2b33fcd9d4 100755 (executable)
 . "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
 print_ver_ cp
 
-printf '1' > file1
-printf '2' > file2
-printf '2' > file2.exp
+printf '1' > file1 || framework_failure_
+printf '2' > file2 || framework_failure_
+printf '2' > file2.exp || framework_failure_
 
 cp --attributes-only file1 file2 || fail=1
 cmp file2 file2.exp || fail=1
 
+# coreutils v8.32 and before would remove destination files
+# if hardlinked or the source was not a regular file.
+ln file2 link2 || framework_failure_
+cp -a --attributes-only file1 file2 || fail=1
+cmp file2 file2.exp || fail=1
+
+ln -s file1 sym1 || framework_failure_
+returns_ 1 cp -a --attributes-only sym1 file2 || fail=1
+cmp file2 file2.exp || fail=1
+
+# One can still force removal though
+cp -a --remove-destination --attributes-only sym1 file2 || fail=1
+test -L file2 || fail=1
+cmp file1 file2 || fail=1
+
 Exit $fail