Skip to content

Commit

Permalink
cp: preserve existing permissions with --no-preserve=mode
Browse files Browse the repository at this point in the history
This issue was introduced in commit v8.19-145-g24ebca6

* src/copy.c (copy_internal): With --no-preserve=mode,
only reset permissions for newly created files.
(copy_reg): Likewise.
* NEWS: Mention the fix.
* tests/cp/preserve-mode.sh: Add a test case.
Fixes https://bugs.gnu.org/31675
  • Loading branch information
pixelb committed Jun 3, 2018
1 parent c8eb21c commit 5e7b892
Show file tree
Hide file tree
Showing 3 changed files with 18 additions and 16 deletions.
6 changes: 4 additions & 2 deletions NEWS
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,10 @@ GNU coreutils NEWS -*- outline -*-
[bug introduced with coreutils-7.1]

'cp -a --no-preserve=mode' now sets appropriate default permissions
for non regular files like fifos and character device nodes etc.
Previously it would have set executable bits on created special files.
for non regular files like fifos and character device nodes etc.,
and leaves mode bits of existing files unchanged.
Previously it would have set executable bits on created special files,
and set mode bits for existing files as if they had been created.
[bug introduced with coreutils-8.20]

'cp --remove-destination file symlink' now removes the symlink
Expand Down
4 changes: 2 additions & 2 deletions src/copy.c
Original file line number Diff line number Diff line change
Expand Up @@ -1379,7 +1379,7 @@ copy_reg (char const *src_name, char const *dst_name,
if (set_acl (dst_name, dest_desc, x->mode) != 0)
return_val = false;
}
else if (x->explicit_no_preserve_mode)
else if (x->explicit_no_preserve_mode && *new_dst)
{
if (set_acl (dst_name, dest_desc, MODE_RW_UGO & ~cached_umask ()) != 0)
return_val = false;
Expand Down Expand Up @@ -2862,7 +2862,7 @@ copy_internal (char const *src_name, char const *dst_name,
if (set_acl (dst_name, -1, x->mode) != 0)
return false;
}
else if (x->explicit_no_preserve_mode)
else if (x->explicit_no_preserve_mode && new_dst)
{
int default_permissions = S_ISDIR (src_mode) || S_ISSOCK (src_mode)
? S_IRWXUGO : MODE_RW_UGO;
Expand Down
24 changes: 12 additions & 12 deletions tests/cp/preserve-mode.sh
Original file line number Diff line number Diff line change
Expand Up @@ -21,29 +21,29 @@ print_ver_ cp

get_mode() { stat -c%f "$1"; }

rm -f a b c
umask 0022
touch a
touch b
chmod 600 b
umask 0022 || framework_failure_

#regular file test
touch a b || framework_failure_
chmod 600 b || framework_failure_
cp --no-preserve=mode b c || fail=1
test "$(get_mode a)" = "$(get_mode c)" || fail=1

rm -rf d1 d2 d3
mkdir d1 d2
chmod 705 d2
#existing destination test
chmod 600 c || framework_failure_
cp --no-preserve=mode a b || fail=1
test "$(get_mode b)" = "$(get_mode c)" || fail=1

#directory test
mkdir d1 d2 || framework_failure_
chmod 705 d2 || framework_failure_
cp --no-preserve=mode -r d2 d3 || fail=1
test "$(get_mode d1)" = "$(get_mode d3)" || fail=1

rm -f a b c
touch a
chmod 600 a

#contradicting options test
rm -f a b || framework_failure_
touch a || framework_failure_
chmod 600 a || framework_failure_
cp --no-preserve=mode --preserve=all a b || fail=1
test "$(get_mode a)" = "$(get_mode b)" || fail=1

Expand Down

0 comments on commit 5e7b892

Please sign in to comment.