summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJim Meyering <jim@meyering.net>1999-12-04 17:21:47 +0000
committerJim Meyering <jim@meyering.net>1999-12-04 17:21:47 +0000
commit698fd027984026be23a971e368d2ce724b345bfc (patch)
tree3eea010380220ed8ffcaf355374fa2f2e9a4fab2
parent28bac510d9faddfdb05c78563e3989e3a45a42bc (diff)
downloadcoreutils-698fd027984026be23a971e368d2ce724b345bfc.tar.xz
(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.
-rw-r--r--src/copy.c43
1 files changed, 31 insertions, 12 deletions
diff --git a/src/copy.c b/src/copy.c
index 9d8c0c070..fda7eaf50 100644
--- a/src/copy.c
+++ b/src/copy.c
@@ -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))
{