[PATCH 3 of 5 V2] localrepo: handle rename with hardlinks properly

Jun Wu quark at fb.com
Fri Mar 3 01:13:29 EST 2017


# HG changeset patch
# User Jun Wu <quark at fb.com>
# Date 1488520170 28800
#      Thu Mar 02 21:49:30 2017 -0800
# Node ID 1cf153ec3faaef92c9ad3515372a6d8591195d6e
# Parent  406f94842e3372f241a151a3ee6ea5f39c04758d
# Available At https://bitbucket.org/quark-zju/hg-draft
#              hg pull https://bitbucket.org/quark-zju/hg-draft -r 1cf153ec3faa
localrepo: handle rename with hardlinks properly

In "aftertrans", we rename "journal.*" to "undo.*". We expect "journal.*"
files to disappear after renaming.

However, if "journal.foo" and "undo.foo" refer to a same file (hardlink),
rename may be a no-op, leaving both files on disk, according to Linux
manpage [1]:

    If oldpath and newpath are existing hard links referring to the same
    file, then rename() does nothing, and returns  a  suc‐ cess status.

The POSIX specification [2] is not very clear about what to do.

To be safe, remove "undo.*" before the rename so "journal.*" cannot be left
on disk.

[1]: http://man7.org/linux/man-pages/man2/rename.2.html
[2]: http://pubs.opengroup.org/onlinepubs/9699919799/

diff --git a/mercurial/localrepo.py b/mercurial/localrepo.py
--- a/mercurial/localrepo.py
+++ b/mercurial/localrepo.py
@@ -2000,4 +2000,12 @@ def aftertrans(files):
         for vfs, src, dest in renamefiles:
             try:
+                # if src and dest refer to a same file, vfs.rename is a no-op,
+                # leaving both src and dest on disk. delete dest to make sure
+                # the rename couldn't be such a no-op.
+                vfs.unlink(dest)
+            except OSError as ex:
+                if ex.errno != errno.ENOENT:
+                    raise
+            try:
                 vfs.rename(src, dest)
             except OSError: # journal file does not yet exist


More information about the Mercurial-devel mailing list