summaryrefslogtreecommitdiff
path: root/src/copy.c
diff options
context:
space:
mode:
authorJim Meyering <jim@meyering.net>2004-03-12 11:53:18 +0000
committerJim Meyering <jim@meyering.net>2004-03-12 11:53:18 +0000
commitbcea8e96ea30693a05fcee2ae49aa9aea0e5e7da (patch)
tree21062827a4d04c6d45a160925c771f6d426c7827 /src/copy.c
parent04975d25921447c96db51fc76b02bc31d8848f0a (diff)
downloadcoreutils-bcea8e96ea30693a05fcee2ae49aa9aea0e5e7da.tar.xz
Sometimes, when source and destination partition are different,
mv mistakenly fails to preserve a hard link. Reported by IIDA Yosiaki. When moving a set of N hard-linked files between partitions, via two or more command line arguments where the command line argument containing the Nth link contains no other link to that same file, mv would mistakenly copy the file, rather than hard-linking it to the other(s). That happens because when the final link is processed, its link count has been reduced to 1 since the other links have been `copied' to the destination partition and the source links have been removed. (copy_internal): When in move mode, use the source dev/inode pair to look up destination name even when st_nlink == 1.
Diffstat (limited to 'src/copy.c')
-rw-r--r--src/copy.c25
1 files changed, 19 insertions, 6 deletions
diff --git a/src/copy.c b/src/copy.c
index 8685234e5..51c5f6db8 100644
--- a/src/copy.c
+++ b/src/copy.c
@@ -1099,6 +1099,15 @@ copy_internal (const char *src_path, const char *dst_path,
Sometimes, when preserving links, we have to record dev/ino even
though st_nlink == 1:
+ - when in move_mode, since we may be moving a group of N hard-linked
+ files (via two or more command line arguments) to a different
+ partition; the links may be distributed among the command line
+ arguments (possibly hierarchies) so that the link count of
+ the final, once-linked source file is reduced to 1 when it is
+ considered below. But in this case (for mv) we don't need to
+ incur the expense of recording the dev/ino => name mapping; all we
+ really need is a lookup, to see if the dev/ino pair has already
+ been copied.
- when using -H and processing a command line argument;
that command line argument could be a symlink pointing to another
command line argument. With `cp -H --preserve=link', we hard-link
@@ -1114,12 +1123,16 @@ copy_internal (const char *src_path, const char *dst_path,
command line args. Using the same hash table to preserve hard
links means that it may not be cleared. */
- if ((x->preserve_links
- && (1 < src_sb.st_nlink
- || (command_line_arg
- && x->dereference == DEREF_COMMAND_LINE_ARGUMENTS)
- || x->dereference == DEREF_ALWAYS))
- || (x->recursive && S_ISDIR (src_type)))
+ if (x->move_mode && src_sb.st_nlink == 1)
+ {
+ earlier_file = src_to_dest_lookup (src_sb.st_ino, src_sb.st_dev);
+ }
+ else if ((x->preserve_links
+ && (1 < src_sb.st_nlink
+ || (command_line_arg
+ && x->dereference == DEREF_COMMAND_LINE_ARGUMENTS)
+ || x->dereference == DEREF_ALWAYS))
+ || (x->recursive && S_ISDIR (src_type)))
{
earlier_file = remember_copied (dst_path, src_sb.st_ino, src_sb.st_dev);
}