diff options
author | Jim Meyering <jim@meyering.net> | 1999-12-04 17:21:47 +0000 |
---|---|---|
committer | Jim Meyering <jim@meyering.net> | 1999-12-04 17:21:47 +0000 |
commit | 698fd027984026be23a971e368d2ce724b345bfc (patch) | |
tree | 3eea010380220ed8ffcaf355374fa2f2e9a4fab2 | |
parent | 28bac510d9faddfdb05c78563e3989e3a45a42bc (diff) | |
download | coreutils-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.c | 43 |
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)) { |