From: Jim Meyering Date: Sat, 4 Dec 1999 17:21:47 +0000 (+0000) Subject: (copy_internal): Be consistent with intra-device behavior X-Git-Tag: FILEUTILS-4_0k~15 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=698fd027984026be23a971e368d2ce724b345bfc;p=platform%2Fupstream%2Fcoreutils.git (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. --- diff --git a/src/copy.c b/src/copy.c index 9d8c0c0..fda7eaf 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)) {