(copy_internal): Be consistent with intra-device behavior

and *do* allow `mv' to move a file onto a symlink to itself when that
symlink is on a separate partition.  With fileutils-4.0j, it would
fail with a diagnostic saying they were the same file.
Reported by Bruno Haible.
This commit is contained in:
Jim Meyering
1999-12-04 17:21:47 +00:00
parent 28bac510d9
commit 698fd02798
+31 -12
View File
@@ -371,6 +371,7 @@ copy_internal (const char *src_path, const char *dst_path,
char *earlier_file;
char *dst_backup = NULL;
int fix_mode = 0;
int force = x->force;
if (move_mode && rename_succeeded)
*rename_succeeded = 0;
@@ -426,14 +427,7 @@ copy_internal (const char *src_path, const char *dst_path,
if (!same
/* If we'll remove DST_PATH first, then this doesn't matter. */
&& ! x->force
/* Allow them to be the same (and don't set `same') if
we're in move mode and the target is a symlink
on the same partition. */
&& !(move_mode
&& S_ISLNK (dst_sb.st_mode)
&& src_sb.st_dev == dst_sb.st_dev)
&& ! force
/* If we're making a backup, we'll detect the problem case in
copy_reg because SRC_PATH will no longer exist. Allowing
@@ -453,7 +447,32 @@ copy_internal (const char *src_path, const char *dst_path,
&& stat (src_path, &src2_sb) == 0
&& SAME_INODE (src2_sb, dst2_sb))
{
same = 1;
/* Be careful in move mode when the target is a symlink
to the source. */
if (move_mode
&& S_ISLNK (dst_sb.st_mode))
{
if (src_sb.st_dev != dst_sb.st_dev)
{
/* This happens when the target is a symlink that
resides on a file system different from the one
on which the source resides. Tell the copying
code (below) that it must unlink the destination
before opening it. Otherwise, we'd end up
destroying SRC when opening it via the symlink. */
force = 1;
}
else
{
/* Don't set `same'.
Since they're on the same partition, rename
will end up removing the destination symlink. */
}
}
else
{
same = 1;
}
}
}
#endif
@@ -464,7 +483,7 @@ copy_internal (const char *src_path, const char *dst_path,
return 0;
if (x->backup_type == none
&& (!x->force || same_name (src_path, dst_path)))
&& (!force || same_name (src_path, dst_path)))
{
error (0, 0, _("`%s' and `%s' are the same file"),
src_path, dst_path);
@@ -486,7 +505,7 @@ copy_internal (const char *src_path, const char *dst_path,
return 0;
}
if (!S_ISDIR (src_type) && !x->force && x->interactive)
if (!S_ISDIR (src_type) && !force && x->interactive)
{
if (euidaccess (dst_path, W_OK) != 0)
{
@@ -554,7 +573,7 @@ copy_internal (const char *src_path, const char *dst_path,
}
new_dst = 1;
}
else if (x->force)
else if (force)
{
if (S_ISDIR (dst_sb.st_mode))
{