Show More
@@ -13,6 +13,7 b' posixfile = open' | |||||
13 | nulldev = '/dev/null' |
|
13 | nulldev = '/dev/null' | |
14 | normpath = os.path.normpath |
|
14 | normpath = os.path.normpath | |
15 | samestat = os.path.samestat |
|
15 | samestat = os.path.samestat | |
|
16 | unlink = os.unlink | |||
16 | rename = os.rename |
|
17 | rename = os.rename | |
17 | expandglobs = False |
|
18 | expandglobs = False | |
18 |
|
19 |
@@ -285,27 +285,30 b' def unlinkpath(f):' | |||||
285 | except OSError: |
|
285 | except OSError: | |
286 | pass |
|
286 | pass | |
287 |
|
287 | |||
288 | def rename(src, dst): |
|
288 | def unlink(f): | |
289 | '''atomically rename file src to dst, replacing dst if it exists''' |
|
289 | '''try to implement POSIX' unlink semantics on Windows''' | |
290 | try: |
|
|||
291 | os.rename(src, dst) |
|
|||
292 | except OSError, e: |
|
|||
293 | if e.errno != errno.EEXIST: |
|
|||
294 | raise |
|
|||
295 |
|
290 | |||
296 | # On windows, rename to existing file is not allowed, so we |
|
291 | # POSIX allows to unlink and rename open files. Windows has serious | |
297 | # must delete destination first. But if a file is open, unlink |
|
292 | # problems with doing that: | |
298 | # schedules it for delete but does not delete it. Rename |
|
293 | # - Calling os.unlink (or os.rename) on a file f fails if f or any | |
299 | # happens immediately even for open files, so we rename |
|
294 | # hardlinked copy of f has been opened with Python's open(). There is no | |
300 | # destination to a temporary name, then delete that. Then |
|
295 | # way such a file can be deleted or renamed on Windows (other than | |
301 | # rename is safe to do. |
|
296 | # scheduling the delete or rename for the next reboot). | |
302 | # The temporary name is chosen at random to avoid the situation |
|
297 | # - Calling os.unlink on a file that has been opened with Mercurial's | |
303 | # where a file is left lying around from a previous aborted run. |
|
298 | # posixfile (or comparable methods) will delay the actual deletion of | |
|
299 | # the file for as long as the file is held open. The filename is blocked | |||
|
300 | # during that time and cannot be used for recreating a new file under | |||
|
301 | # that same name ("zombie file"). Directories containing such zombie files | |||
|
302 | # cannot be removed or moved. | |||
|
303 | # A file that has been opened with posixfile can be renamed, so we rename | |||
|
304 | # f to a random temporary name before calling os.unlink on it. This allows | |||
|
305 | # callers to recreate f immediately while having other readers do their | |||
|
306 | # implicit zombie filename blocking on a temporary name. | |||
304 |
|
307 | |||
305 |
|
|
308 | for tries in xrange(10): | |
306 |
|
|
309 | temp = '%s-%08x' % (f, random.randint(0, 0xffffffff)) | |
307 |
|
|
310 | try: | |
308 |
|
|
311 | os.rename(f, temp) # raises OSError EEXIST if temp exists | |
309 |
|
|
312 | break | |
310 |
|
|
313 | except OSError, e: | |
311 |
|
|
314 | if e.errno != errno.EEXIST: | |
@@ -316,11 +319,20 b' def rename(src, dst):' | |||||
316 |
|
|
319 | try: | |
317 |
|
|
320 | os.unlink(temp) | |
318 |
|
|
321 | except: | |
319 |
|
|
322 | # Some very rude AV-scanners on Windows may cause this unlink to fail. | |
320 |
|
|
323 | # Not aborting here just leaks the temp file, whereas aborting at this | |
321 |
|
|
324 | # point may leave serious inconsistencies. Ideally, we would notify | |
322 | # Ideally, we would notify the user here. |
|
325 | # the user in this case here. | |
323 |
|
|
326 | pass | |
|
327 | ||||
|
328 | def rename(src, dst): | |||
|
329 | '''atomically rename file src to dst, replacing dst if it exists''' | |||
|
330 | try: | |||
|
331 | os.rename(src, dst) | |||
|
332 | except OSError, e: | |||
|
333 | if e.errno != errno.EEXIST: | |||
|
334 | raise | |||
|
335 | unlink(dst) | |||
324 | os.rename(src, dst) |
|
336 | os.rename(src, dst) | |
325 |
|
337 | |||
326 | def spawndetached(args): |
|
338 | def spawndetached(args): |
General Comments 0
You need to be logged in to leave comments.
Login now