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
This commit is contained in:
Pádraig Brady 2020-04-01 12:51:34 +01:00
parent 271b217045
commit 7b5f0fa47c
3 changed files with 30 additions and 7 deletions

7
NEWS
View File

@ -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

View 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)
{

View File

@ -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