comparison mercurial/posix.py @ 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 99b6afff09ae
children 8b2fbe3f59b1 1aa5083cbebb
comparison
equal deleted inserted replaced
26882:c4895f9b8ab1 26883:c750ed59892a
168 168
169 def checklink(path): 169 def checklink(path):
170 """check whether the given path is on a symlink-capable filesystem""" 170 """check whether the given path is on a symlink-capable filesystem"""
171 # mktemp is not racy because symlink creation will fail if the 171 # mktemp is not racy because symlink creation will fail if the
172 # file already exists 172 # file already exists
173 name = tempfile.mktemp(dir=path, prefix='hg-checklink-') 173 while True:
174 try: 174 name = tempfile.mktemp(dir=path, prefix='hg-checklink-')
175 fd = tempfile.NamedTemporaryFile(dir=path, prefix='hg-checklink-')
176 try: 175 try:
177 os.symlink(os.path.basename(fd.name), name) 176 fd = tempfile.NamedTemporaryFile(dir=path, prefix='hg-checklink-')
178 os.unlink(name) 177 try:
179 return True 178 os.symlink(os.path.basename(fd.name), name)
180 finally: 179 os.unlink(name)
181 fd.close() 180 return True
182 except AttributeError: 181 except OSError as inst:
183 return False 182 # link creation might race, try again
184 except OSError as inst: 183 if inst[0] == errno.EEXIST:
185 # sshfs might report failure while successfully creating the link 184 continue
186 if inst[0] == errno.EIO and os.path.exists(name): 185 # sshfs might report failure while successfully creating the link
187 os.unlink(name) 186 if inst[0] == errno.EIO and os.path.exists(name):
188 return False 187 os.unlink(name)
188 return False
189 finally:
190 fd.close()
191 except AttributeError:
192 return False
189 193
190 def checkosfilename(path): 194 def checkosfilename(path):
191 '''Check that the base-relative path is a valid filename on this platform. 195 '''Check that the base-relative path is a valid filename on this platform.
192 Returns None if the path is ok, or a UI string describing the problem.''' 196 Returns None if the path is ok, or a UI string describing the problem.'''
193 pass # on posix platforms, every path is ok 197 pass # on posix platforms, every path is ok