From: Pádraig Brady
Date: Sun, 3 Jun 2018 23:19:20 +0000 (-0700) Subject: cp: preserve existing permissions with --no-preserve=mode X-Git-Tag: v8.30~28 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=5e7b8928b76e6d661a6babd884dc812348255f59;p=thirdparty%2Fcoreutils.git cp: preserve existing permissions with --no-preserve=mode 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 --- diff --git a/NEWS b/NEWS index 4c63b6d7cb..101afc0809 100644 --- a/NEWS +++ b/NEWS @@ -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 diff --git a/src/copy.c b/src/copy.c index f4c92d7d7f..eccf67cdb2 100644 --- a/src/copy.c +++ b/src/copy.c @@ -1379,7 +1379,7 @@ preserve_metadata: 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; @@ -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; diff --git a/tests/cp/preserve-mode.sh b/tests/cp/preserve-mode.sh index 3b0aca8e77..f5bf9d2cc2 100755 --- a/tests/cp/preserve-mode.sh +++ b/tests/cp/preserve-mode.sh @@ -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