>From af51efbe11aeba9fc2609dd69d622cc170b484a6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?P=C3=A1draig=20Brady?= Date: Wed, 1 Apr 2020 12:51:34 +0100 Subject: [PATCH] cp: ensure --attributes-only doesn't remove files * 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 | 7 +++++++ src/copy.c | 9 +++++---- tests/cp/attr-existing.sh | 21 ++++++++++++++++++--- 3 files changed, 30 insertions(+), 7 deletions(-) diff --git a/NEWS b/NEWS index 653e7178b..b8a17c276 100644 --- 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 diff --git a/src/copy.c b/src/copy.c index 6e5efc708..54601ce07 100644 --- a/src/copy.c +++ b/src/copy.c @@ -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) { diff --git a/tests/cp/attr-existing.sh b/tests/cp/attr-existing.sh index 59ce64183..14fc8445c 100755 --- a/tests/cp/attr-existing.sh +++ b/tests/cp/attr-existing.sh @@ -19,11 +19,26 @@ . "${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 -- 2.24.1