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.
--- 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)