# HG changeset patch # User Tony Tung <tonyt...@merly.org> # Date 1472148645 25200 # Thu Aug 25 11:10:45 2016 -0700 # Node ID 625f3bb4833b47c4d35754fced91f37b077f7866 # 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,38 +1305,53 @@ def checknlink(testfile): '''check whether hardlink count reporting works properly''' - # 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 + f1 = {} + f2 = {} + 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) + 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['fd'], f1['path'] = tempfile.mkstemp(prefix=filename, dir=dirpath) + os.close(f1['fd']) + del f1['fd'] + + f2['fd'], f2['path'] = tempfile.mkstemp(prefix=filename, dir=dirpath) + os.close(f2['fd']) + del f2['fd'] + + # 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. + os.unlink(f2['path']) + oslink(f1['path'], f2['path']) # nlinks() may behave differently for files on Windows shares if # the file is open. - fd = posixfile(f2) - return nlinks(f2) > 1 - except OSError: + f2['handle'] = posixfile(f2['path']) + return nlinks(f2['path']) > 1 + except EnvironmentError: return False finally: - if fd is not None: - fd.close() - for f in (f1, f2): - try: - os.unlink(f) - except OSError: - pass + for fi in (f1, f2): + if 'fd' in fi: + try: + os.close(fi['fd']) + except EnvironmentError: + pass + + if 'handle' in fi: + try: + fi['handle'].close() + except EnvironmentError: + pass + + if 'path' in fi: + try: + os.unlink(fi['path']) + except EnvironmentError: + pass def endswithsep(path): '''Check path ends with os.sep or os.altsep.''' _______________________________________________ Mercurial-devel mailing list Mercurial-devel@mercurial-scm.org https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel