Mercurial > hg-stable
changeset 26883:c750ed59892a stable
posix: retry on symlink race in checklink
Multiple threads might attempt to check links with the same temporary
name. This would cause one side to get an EEXIST error and wrongly
fail the support check. Here, we simply retry if our temporary name
exists.
author | Matt Mackall <mpm@selenic.com> |
---|---|
date | Fri, 06 Nov 2015 15:23:10 -0600 |
parents | c4895f9b8ab1 |
children | 762bf510b42c |
files | mercurial/posix.py |
diffstat | 1 files changed, 19 insertions(+), 15 deletions(-) [+] |
line wrap: on
line diff
--- a/mercurial/posix.py Fri Nov 06 13:01:15 2015 -0500 +++ b/mercurial/posix.py Fri Nov 06 15:23:10 2015 -0600 @@ -170,22 +170,26 @@ """check whether the given path is on a symlink-capable filesystem""" # mktemp is not racy because symlink creation will fail if the # file already exists - name = tempfile.mktemp(dir=path, prefix='hg-checklink-') - try: - fd = tempfile.NamedTemporaryFile(dir=path, prefix='hg-checklink-') + while True: + name = tempfile.mktemp(dir=path, prefix='hg-checklink-') try: - os.symlink(os.path.basename(fd.name), name) - os.unlink(name) - return True - finally: - fd.close() - except AttributeError: - return False - except OSError as inst: - # sshfs might report failure while successfully creating the link - if inst[0] == errno.EIO and os.path.exists(name): - os.unlink(name) - return False + fd = tempfile.NamedTemporaryFile(dir=path, prefix='hg-checklink-') + try: + os.symlink(os.path.basename(fd.name), name) + os.unlink(name) + return True + except OSError as inst: + # link creation might race, try again + if inst[0] == errno.EEXIST: + continue + # sshfs might report failure while successfully creating the link + if inst[0] == errno.EIO and os.path.exists(name): + os.unlink(name) + return False + finally: + fd.close() + except AttributeError: + return False def checkosfilename(path): '''Check that the base-relative path is a valid filename on this platform.