mirror of
git://git.sv.gnu.org/coreutils
synced 2026-05-22 08:22:04 -04:00
* 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.
This commit is contained in:
+39
-49
@@ -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 (!abandon_move (x, dst_name, &dst_sb)
|
||||
&& unlink (src_name) != 0)
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
if (return_now)
|
||||
return true;
|
||||
|
||||
if (! ok)
|
||||
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 && 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;
|
||||
}
|
||||
}
|
||||
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 (!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. */
|
||||
|
||||
Reference in New Issue
Block a user