util: disable hardlink for copyfile if fstype is outside a whitelist
authorJun Wu <quark@fb.com>
Sun, 12 Mar 2017 00:23:07 -0800
changeset 31575 e506e461c7a9
parent 31574 a8e55d6f1d67
child 31576 07f0cddb0594
util: disable hardlink for copyfile if fstype is outside a whitelist Since osutil.getfstype is available, use it to detect filesystem types. The whitelist currently includes common local filesystems on Linux where they should have good hardlink support. We may add new filesystems for other platforms later.
mercurial/util.py
--- a/mercurial/util.py	Tue Mar 21 17:39:49 2017 -0400
+++ b/mercurial/util.py	Sun Mar 12 00:23:07 2017 -0800
@@ -1060,6 +1060,18 @@
 # This is a variable so extensions can opt-in to using them.
 allowhardlinks = False
 
+# a whilelist of known filesystems where hardlink works reliably
+_hardlinkfswhitelist = set([
+    'btrfs',
+    'ext2',
+    'ext3',
+    'ext4',
+    'jfs',
+    'reiserfs',
+    'tmpfs',
+    'xfs',
+])
+
 def copyfile(src, dest, hardlink=False, copystat=False, checkambig=False):
     '''copy a file, preserving mode and optionally other stat info like
     atime/mtime
@@ -1076,6 +1088,13 @@
         if checkambig:
             oldstat = checkambig and filestat(dest)
         unlink(dest)
+    if hardlink:
+        # Hardlinks are problematic on CIFS (issue4546), do not allow hardlinks
+        # unless we are confident that dest is on a whitelisted filesystem.
+        destdir = os.path.dirname(dest)
+        fstype = getattr(osutil, 'getfstype', lambda x: None)(destdir)
+        if fstype not in _hardlinkfswhitelist:
+            hardlink = False
     if allowhardlinks and hardlink:
         try:
             oslink(src, dest)