Mercurial > public > mercurial-scm > hg
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 |