From: Pádraig Brady
Date: Sun, 12 May 2024 11:21:19 +0000 (+0100) Subject: cp,mv: ensure -i,f are not overridden by -u X-Git-Tag: v9.6~34 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=a6ab944e19684d0ccd0568fa8c06f71921c1e6c3;p=thirdparty%2Fcoreutils.git cp,mv: ensure -i,f are not overridden by -u Since coreutils 9.3 we had --update={all,older} override -i. In coreutils 9.5 this was expanded to -u (to make it consistent with --update=older). This patch reinstates things so that -i combines with -u instead. I.e. have -i be protective, rather than selective (like -u). The -f option of mv is similarly adjusted in this patch, so now --update does not override any of -f,-i,-n. * NEWS: Mention the bug fix. * src/cp.c (main): Don't have -u disable prompting. * src/mv.c (main): Likewise. * tests/cp/cp-i.sh: Add a test case for -i. * tests/mv/update.sh: Likewise. * tests/mv/i-3.sh. Add a test case for -f. Fixes https://bugs.gnu.org/70887 --- diff --git a/NEWS b/NEWS index 331a063587..3e01536102 100644 --- a/NEWS +++ b/NEWS @@ -8,6 +8,9 @@ GNU coreutils NEWS -*- outline -*- rejected as an invalid option. [bug introduced in coreutils-9.5] + cp,mv --update no longer overrides --interactive or --force. + [bug introduced in coreutils-9.3] + ls and printf fix shell quoted output in the edge case of escaped first and last characters, and single quotes in the string. [bug introduced in coreutils-8.26] diff --git a/src/cp.c b/src/cp.c index 215f810bd5..23c25a9838 100644 --- a/src/cp.c +++ b/src/cp.c @@ -1063,7 +1063,9 @@ main (int argc, char **argv) break; case 'i': - x.interactive = I_ASK_USER; + /* -i overrides -n, but not --update={none,none-fail}. */ + if (no_clobber || x.interactive == I_UNSPECIFIED) + x.interactive = I_ASK_USER; break; case 'l': @@ -1151,7 +1153,8 @@ main (int argc, char **argv) { /* Default cp operation. */ x.update = false; - x.interactive = I_UNSPECIFIED; + if (x.interactive != I_ASK_USER) + x.interactive = I_UNSPECIFIED; } else if (update_opt == UPDATE_NONE) { @@ -1166,7 +1169,8 @@ main (int argc, char **argv) else if (update_opt == UPDATE_OLDER) { x.update = true; - x.interactive = I_UNSPECIFIED; + if (x.interactive != I_ASK_USER) + x.interactive = I_UNSPECIFIED; } } break; diff --git a/src/mv.c b/src/mv.c index 46893a25f5..bbf1e60348 100644 --- a/src/mv.c +++ b/src/mv.c @@ -353,10 +353,18 @@ main (int argc, char **argv) version_control_string = optarg; break; case 'f': - x.interactive = I_ALWAYS_YES; + /* -f overrides -n, or -i, but not --update={none,none-fail}. */ + if (no_clobber + || x.interactive == I_ASK_USER + || x.interactive == I_UNSPECIFIED) + x.interactive = I_ALWAYS_YES; break; case 'i': - x.interactive = I_ASK_USER; + /* -i overrides -n, or -f, but not --update={none,none-fail}. */ + if (no_clobber + || x.interactive == I_ALWAYS_YES + || x.interactive == I_UNSPECIFIED) + x.interactive = I_ASK_USER; break; case 'n': x.interactive = I_ALWAYS_SKIP; @@ -394,7 +402,9 @@ main (int argc, char **argv) { /* Default mv operation. */ x.update = false; - x.interactive = I_UNSPECIFIED; + if (x.interactive != I_ASK_USER + && x.interactive != I_ALWAYS_YES) + x.interactive = I_UNSPECIFIED; } else if (update_opt == UPDATE_NONE) { @@ -409,7 +419,9 @@ main (int argc, char **argv) else if (update_opt == UPDATE_OLDER) { x.update = true; - x.interactive = I_UNSPECIFIED; + if (x.interactive != I_ASK_USER + && x.interactive != I_ALWAYS_YES) + x.interactive = I_UNSPECIFIED; } } break; diff --git a/tests/cp/cp-i.sh b/tests/cp/cp-i.sh index 08da4b31b5..2fd5abea8f 100755 --- a/tests/cp/cp-i.sh +++ b/tests/cp/cp-i.sh @@ -70,4 +70,23 @@ returns_ 1 cp -bn c d 2>/dev/null || fail=1 returns_ 1 cp -b --update=none c d 2>/dev/null || fail=1 returns_ 1 cp -b --update=none-fail c d 2>/dev/null || fail=1 +# Verify -i combines with -u, +echo old > old || framework_failure_ +touch -d yesterday old || framework_failure_ +echo new > new || framework_failure_ +# coreutils 9.3 had --update={all,older} ignore -i +echo n | returns_ 1 cp -vi --update=older new old 2>/dev/null >out8 || fail=1 +compare /dev/null out8 || fail=1 +echo n | returns_ 1 cp -vi --update=all new old 2>/dev/null >out8 || fail=1 +compare /dev/null out8 || fail=1 +# coreutils 9.5 also had -u ignore -i +echo n | returns_ 1 cp -vi -u new old 2>/dev/null >out8 || fail=1 +compare /dev/null out8 || fail=1 +# Don't prompt as not updating +cp -v -i --update=none new old 2>/dev/null >out8 /dev/null >out8 /dev/null 2>&1 \ @@ -59,11 +59,20 @@ retry_delay_ check_overwrite_prompt .1 7 || { fail=1; cat out; } cleanup_ -mv -f h i > out 2>&1 || fail=1 +# Make sure there was no prompt with -f +timeout 10 mv -f h i > out 2>&1 || fail=1 test -f i || fail=1 test -f h && fail=1 +case "$(cat out)" in + '') ;; + *) fail=1 ;; +esac -# Make sure there was no prompt. +# Likewise make sure there was no prompt with -f -u +# coreutils 9.3-9.5 mistakenly did prompt. +timeout 10 mv -f --update=all j k > out 2>&1 || fail=1 +test -f k || fail=1 +test -f j && fail=1 case "$(cat out)" in '') ;; *) fail=1 ;; diff --git a/tests/mv/update.sh b/tests/mv/update.sh index b0b4d4acb7..cc4214724a 100755 --- a/tests/mv/update.sh +++ b/tests/mv/update.sh @@ -38,6 +38,9 @@ for interactive in '' -i; do done done +# This should prompt. coreutils 9.3-9.5 mistakenly did not +echo n | returns_ 1 mv -vi -u new old >/dev/null 2>&1 || fail=1 + # These should accept all options for update_option in '--update' '--update=older' '--update=all' \ '--update=none' '--update=none-fail'; do