diff options
-rw-r--r-- | ChangeLog | 11 | ||||
-rw-r--r-- | NEWS | 2 | ||||
-rw-r--r-- | src/copy.c | 82 | ||||
-rw-r--r-- | tests/cp/Makefile.am | 2 | ||||
-rwxr-xr-x | tests/cp/cp-i | 51 | ||||
-rw-r--r-- | tests/mv/Makefile.am | 2 | ||||
-rwxr-xr-x | tests/mv/i-5 | 51 |
7 files changed, 153 insertions, 48 deletions
@@ -1,3 +1,14 @@ +2006-09-20 Paul Eggert <eggert@cs.ucla.edu> + + * NEWS: Document fix for cp -i and mv -i. + * src/copy.c (copy_internal): With -i, prompt even if the source + is a directory and the destination is not. This is required by + POSIX and gives the user a chance to bail out before failing. + * tests/cp/Makefile.am (TESTS): Add cp-i. + * tests/cp/cp-i: New file. + * tests/mv/Makefile.am (TESTS): Add i-5. + * tests/mv/i-5: New file. + 2006-09-20 Jim Meyering <jim@meyering.net> * NEWS: Mention the chmod bug fix. @@ -9,6 +9,8 @@ GNU coreutils NEWS -*- outline -*- preceding command line argument. This bug also affects chgrp, but it is harder to demonstrate. It does not affect chown. + cp -i and mv -i occasionally neglected to prompt when the copy or + move action was bound to fail. * Major changes in release 6.2 (2006-09-18) [stable candidate] diff --git a/src/copy.c b/src/copy.c index f8b0ee678..c1f374049 100644 --- a/src/copy.c +++ b/src/copy.c @@ -1036,31 +1036,52 @@ copy_internal (char const *src_name, char const *dst_name, that it is XSTAT'able. */ bool return_now; bool unlink_src; - bool ok = same_file_ok (src_name, &src_sb, dst_name, &dst_sb, - x, &return_now, &unlink_src); - if (unlink_src) + + if (! same_file_ok (src_name, &src_sb, dst_name, &dst_sb, + x, &return_now, &unlink_src)) + { + error (0, 0, _("%s and %s are the same file"), + quote_n (0, src_name), quote_n (1, dst_name)); + return false; + } + + /* When there is an existing destination file, we may end up + returning early, and hence not copying/moving the file. + This may be due to an interactive `negative' reply to the + prompt about the existing file. It may also be due to the + use of the --reply=no option. + + cp and mv treat -i and -f differently. */ + if (x->move_mode) { - if (!abandon_move (x, dst_name, &dst_sb) - && unlink (src_name) != 0) + if (abandon_move (x, dst_name, &dst_sb) + || (unlink_src && unlink (src_name) == 0)) + { + /* Pretend the rename succeeded, so the caller (mv) + doesn't end up removing the source file. */ + if (rename_succeeded) + *rename_succeeded = true; + return true; + } + if (unlink_src) { error (0, errno, _("cannot remove %s"), quote (src_name)); return false; } - /* Tell the caller that there's no need to remove src_name. */ - if (rename_succeeded) - *rename_succeeded = true; + } + else + { + if (! S_ISDIR (src_mode) + && (x->interactive == I_ALWAYS_NO + || (x->interactive == I_ASK_USER + && (overwrite_prompt (dst_name, &dst_sb), 1) + && ! yesno ()))) + return true; } if (return_now) return true; - if (! ok) - { - error (0, 0, _("%s and %s are the same file"), - quote_n (0, src_name), quote_n (1, dst_name)); - return false; - } - if (!S_ISDIR (dst_sb.st_mode)) { if (S_ISDIR (src_type)) @@ -1140,37 +1161,6 @@ copy_internal (char const *src_name, char const *dst_name, } } - /* When there is an existing destination file, we may end up - returning early, and hence not copying/moving the file. - This may be due to an interactive `negative' reply to the - prompt about the existing file. It may also be due to the - use of the --reply=no option. */ - if (!S_ISDIR (src_type)) - { - /* cp and mv treat -i and -f differently. */ - if (x->move_mode) - { - if (abandon_move (x, dst_name, &dst_sb)) - { - /* Pretend the rename succeeded, so the caller (mv) - doesn't end up removing the source file. */ - if (rename_succeeded) - *rename_succeeded = true; - return true; - } - } - else - { - if (x->interactive == I_ALWAYS_NO - || (x->interactive == I_ASK_USER - && (overwrite_prompt (dst_name, &dst_sb), 1) - && ! yesno ())) - { - return true; - } - } - } - if (x->move_mode) { /* Don't allow user to move a directory onto a non-directory. */ diff --git a/tests/cp/Makefile.am b/tests/cp/Makefile.am index 0b42f3a8a..832bb328e 100644 --- a/tests/cp/Makefile.am +++ b/tests/cp/Makefile.am @@ -29,7 +29,7 @@ TESTS = \ preserve-2 r-vs-symlink link-preserve \ backup-1 no-deref-link1 no-deref-link2 no-deref-link3 backup-is-src \ same-file cp-mv-backup symlink-slash slink-2-slink fail-perm dir-slash \ - perm cp-HL special-bits link dir-rm-dest cp-parents deref-slink \ + perm cp-HL cp-i special-bits link dir-rm-dest cp-parents deref-slink \ dir-vs-file into-self EXTRA_DIST = $(TESTS) trailing-slash TESTS_ENVIRONMENT = \ diff --git a/tests/cp/cp-i b/tests/cp/cp-i new file mode 100755 index 000000000..119d8c862 --- /dev/null +++ b/tests/cp/cp-i @@ -0,0 +1,51 @@ +#!/bin/sh +# Test whether cp -i prompts in the right place. + +# Copyright (C) 2006 Free Software Foundation, Inc. + +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. + +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +# 02110-1301, USA. + +if test "$VERBOSE" = yes; then + set -x + cp --version +fi + +. $srcdir/../envvar-check +. $srcdir/../lang-default + +pwd=`pwd` +t0=`echo "$0"|sed 's,.*/,,'`.tmp; tmp=$t0/$$ +trap 'status=$?; cd $pwd; chmod -R u+rwx $t0; rm -rf $t0 && exit $status' 0 +trap '(exit $?); exit $?' 1 2 13 15 + +framework_failure=0 +mkdir -p $tmp || framework_failure=1 +cd $tmp || framework_failure=1 + +mkdir -p a b/a/c || framework_failure=1 +touch a/c || framework_failure=1 + +if test $framework_failure = 1; then + echo "$0: failure in testing framework" 1>&2 + (exit 1); exit 1 +fi + +fail=0 + +# coreutils 6.2 cp would neglect to prompt in this case. +echo n | cp -iR a b 2>/dev/null || fail=1 + +(exit $fail); exit $fail diff --git a/tests/mv/Makefile.am b/tests/mv/Makefile.am index b5294b4e2..01db2285c 100644 --- a/tests/mv/Makefile.am +++ b/tests/mv/Makefile.am @@ -36,7 +36,7 @@ TESTS = \ perm-1 \ i-link-no \ part-fail \ - dup-source childproof i-4 update i-2 mv-special-1 \ + dup-source childproof i-4 i-5 update i-2 mv-special-1 \ into-self into-self-2 into-self-3 into-self-4 \ backup-is-src \ i-1 hard-link-1 force partition-perm to-symlink dir-file diag \ diff --git a/tests/mv/i-5 b/tests/mv/i-5 new file mode 100755 index 000000000..8b29545d8 --- /dev/null +++ b/tests/mv/i-5 @@ -0,0 +1,51 @@ +#!/bin/sh +# Make sure `mv -i dir file' prompts before failing. + +# Copyright (C) 2006 Free Software Foundation, Inc. + +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. + +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +# 02110-1301, USA. + +if test "$VERBOSE" = yes; then + set -x + mv --version +fi + +. $srcdir/../envvar-check +. $srcdir/../lang-default + +pwd=`pwd` +t0=`echo "$0"|sed 's,.*/,,'`.tmp; tmp=$t0/$$ +trap 'status=$?; cd $pwd; chmod -R u+rwx $t0; rm -rf $t0 && exit $status' 0 +trap '(exit $?); exit $?' 1 2 13 15 + +framework_failure=0 +mkdir -p $tmp || framework_failure=1 +cd $tmp || framework_failure=1 + +mkdir a || framework_failure=1 +touch b || framework_failure=1 + +if test $framework_failure = 1; then + echo 'failure in testing framework' + exit 1 +fi + +fail=0 + +# coreutils 6.2 mv would neglect to prompt in this case. +echo n | mv -i a b 2>/dev/null || fail=1 + +(exit $fail); exit $fail |