Sometimes, when source and destination partition are different,
authorJim Meyering <jim@meyering.net>
Fri, 12 Mar 2004 11:53:18 +0000 (11:53 +0000)
committerJim Meyering <jim@meyering.net>
Fri, 12 Mar 2004 11:53:18 +0000 (11:53 +0000)
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.

src/copy.c

index 8685234e5ebbc3e665e8c1dc3c89ae0546870996..51c5f6db80fe5db570e90b56604b26e433f62402 100644 (file)
@@ -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);
     }