bug-coreutils
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: mv silently does nothing for hard links


From: Jim Meyering
Subject: Re: mv silently does nothing for hard links
Date: Fri, 04 Apr 2003 23:25:01 +0200

Jim Meyering <address@hidden> wrote:
> After the coreutils-5.0 release, I'll look at this again.
> I will probably end up writing yet another rename wrapper
> and autoconf test to detect and work around this failure.
>
> I've added it to the TODO list.

[redirected from bug-fileutils to bug-coreutils]

Hi Ed,

I didn't need a wrapper to fix this after all.
In any case, using a rename wrapper isn't an option,
due to the overhead it'd incur.

Here's a patch that solves the problem at zero-to-negligible cost.

Thanks again for reporting that.

Jim

Index: src/copy.c
===================================================================
RCS file: /fetish/cu/src/copy.c,v
retrieving revision 1.141
diff -u -p -u -p -r1.141 copy.c
--- src/copy.c  2 Mar 2003 06:09:28 -0000       1.141
+++ src/copy.c  4 Apr 2003 20:22:44 -0000
@@ -424,12 +424,22 @@ close_src_desc:
    making the `copy' operation remove both copies of the file
    in that case, while still allowing the user to e.g., move or
    copy a regular file onto a symlink that points to it.
-   Try to minimize the cost of this function in the common case.  */
+   Try to minimize the cost of this function in the common case.
+   Set *RETURN_NOW if we've determined that the caller has no more
+   work to do and should return successfully, right away.
+
+   Set *UNLINK_SRC if we've determined that the caller wants to do
+   `rename (a, b)' where `a' and `b' are hard links to the same file.
+   In that case, the caller should try to unlink `a' and then return
+   successfully.  Ideally, we wouldn't have to do that, and we'd be
+   able to rely on rename to remove the source file.  However, POSIX
+   mistakenly requires that such a rename call do *nothing* and return
+   successfully.  */
 
 static int
 same_file_ok (const char *src_path, const struct stat *src_sb,
              const char *dst_path, const struct stat *dst_sb,
-             const struct cp_options *x, int *return_now)
+             const struct cp_options *x, int *return_now, int *unlink_src)
 {
   const struct stat *src_sb_link;
   const struct stat *dst_sb_link;
@@ -440,6 +450,7 @@ same_file_ok (const char *src_path, cons
   int same = (SAME_INODE (*src_sb, *dst_sb));
 
   *return_now = 0;
+  *unlink_src = 0;
 
   /* FIXME: this should (at the very least) be moved into the following
      if-block.  More likely, it should be removed, because it inhibits
@@ -548,10 +559,21 @@ same_file_ok (const char *src_path, cons
      destination file before opening it -- via `rename' if they're on
      the same file system, via `unlink (DST_PATH)' otherwise.
      It's also ok if they're distinct hard links to the same file.  */
-  if ((x->move_mode || x->unlink_dest_before_opening)
-      && (S_ISLNK (dst_sb_link->st_mode)
-         || (same_link && !same_name (src_path, dst_path))))
-    return 1;
+  if (x->move_mode || x->unlink_dest_before_opening)
+    {
+      if (S_ISLNK (dst_sb_link->st_mode))
+       return 1;
+
+      if (same_link && !same_name (src_path, dst_path))
+       {
+         if (x->move_mode)
+           {
+             *unlink_src = 1;
+             *return_now = 1;
+           }
+         return 1;
+       }
+    }
 
   /* If neither is a symlink, then it's ok as long as they aren't
      hard links to the same file.  */
@@ -856,8 +878,21 @@ copy_internal (const char *src_path, con
       else
        {
          int return_now;
+         int unlink_src;
          int ok = same_file_ok (src_path, &src_sb, dst_path, &dst_sb,
-                                x, &return_now);
+                                x, &return_now, &unlink_src);
+         if (unlink_src)
+           {
+             if (unlink (src_path))
+               {
+                 error (0, errno, _("cannot remove %s"), quote (src_path));
+                 return 1;
+               }
+             /* Tell the caller that there's no need to remove src_path.  */
+             if (rename_succeeded)
+               *rename_succeeded = 1;
+           }
+
          if (return_now)
            return 0;
 




reply via email to

[Prev in Thread] Current Thread [Next in Thread]