[PATCH 2 of 2] util: move checknlink away from the dependency of a hard-coded filename

ttung at fb.com ttung at fb.com
Fri Aug 19 16:58:40 EDT 2016


# HG changeset patch
# User Tony Tung <tonytung at merly.org>
# Date 1471639931 25200
#      Fri Aug 19 13:52:11 2016 -0700
# Node ID 4aaeb57d5f4497ef35b48e23b80e43b914afd819
# Parent  2efc5a05d80a6d4253767f2ce0c2fb062ba83cb6
util: move checknlink away from the dependency of a hard-coded filename

This somewhat insulates us against bugs in checknlink when a stale file
left behind could result in checknlink always returning False.

diff --git a/mercurial/util.py b/mercurial/util.py
--- a/mercurial/util.py
+++ b/mercurial/util.py
@@ -1305,34 +1305,33 @@
 def checknlink(testfile):
     '''check whether hardlink count reporting works properly'''
 
+    dirpath, filename = os.path.split(testfile)
+
     # testfile may be open, so we need a separate file for checking to
     # work around issue2543 (or testfile may get lost on Samba shares)
-    f1 = testfile + ".hgtmp1"
-    if os.path.lexists(f1):
-        return False
+    f1handle, f1path = tempfile.mkstemp(prefix=filename, dir=dirpath)
+    os.close(f1handle)
+
+    f2handle, f2path = tempfile.mkstemp(prefix=filename, dir=dirpath)
+    os.close(f2handle)
+    f2handle = None
+
+    # there's a small race condition that another file can jam itself in between
+    # the time we remove f2 and the time we create the hard link.  in the
+    # unlikely scenario that happens, we'll treat it as nlink being unreliable.
     try:
-        posixfile(f1, 'w').close()
-    except IOError:
-        try:
-            os.unlink(f1)
-        except OSError:
-            pass
-        return False
-
-    f2 = testfile + ".hgtmp2"
-    fd = None
-    try:
-        oslink(f1, f2)
+        os.unlink(f2path)
+        oslink(f1path, f2path)
         # nlinks() may behave differently for files on Windows shares if
         # the file is open.
-        fd = posixfile(f2)
-        return nlinks(f2) > 1
+        f2handle = posixfile(f2path)
+        return nlinks(f2path) > 1
     except OSError:
         return False
     finally:
-        if fd is not None:
-            fd.close()
-        for f in (f1, f2):
+        if f2handle is not None:
+            f2handle.close()
+        for f in (f1path, f2path):
             try:
                 os.unlink(f)
             except OSError:


More information about the Mercurial-devel mailing list