##// END OF EJS Templates
reintroduces util.unlink, for POSIX and Windows....
Adrian Buehlmann -
r13280:6052bbc7 default
parent child Browse files
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,6 +285,46 b' def unlinkpath(f):'
285 except OSError:
285 except OSError:
286 pass
286 pass
287
287
288 def unlink(f):
289 '''try to implement POSIX' unlink semantics on Windows'''
290
291 # POSIX allows to unlink and rename open files. Windows has serious
292 # problems with doing that:
293 # - Calling os.unlink (or os.rename) on a file f fails if f or any
294 # hardlinked copy of f has been opened with Python's open(). There is no
295 # way such a file can be deleted or renamed on Windows (other than
296 # scheduling the delete or rename for the next reboot).
297 # - Calling os.unlink on a file that has been opened with Mercurial's
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.
307
308 for tries in xrange(10):
309 temp = '%s-%08x' % (f, random.randint(0, 0xffffffff))
310 try:
311 os.rename(f, temp) # raises OSError EEXIST if temp exists
312 break
313 except OSError, e:
314 if e.errno != errno.EEXIST:
315 raise
316 else:
317 raise IOError, (errno.EEXIST, "No usable temporary filename found")
318
319 try:
320 os.unlink(temp)
321 except:
322 # Some very rude AV-scanners on Windows may cause this unlink to fail.
323 # Not aborting here just leaks the temp file, whereas aborting at this
324 # point may leave serious inconsistencies. Ideally, we would notify
325 # the user in this case here.
326 pass
327
288 def rename(src, dst):
328 def rename(src, dst):
289 '''atomically rename file src to dst, replacing dst if it exists'''
329 '''atomically rename file src to dst, replacing dst if it exists'''
290 try:
330 try:
@@ -292,35 +332,7 b' def rename(src, dst):'
292 except OSError, e:
332 except OSError, e:
293 if e.errno != errno.EEXIST:
333 if e.errno != errno.EEXIST:
294 raise
334 raise
295
335 unlink(dst)
296 # On windows, rename to existing file is not allowed, so we
297 # must delete destination first. But if a file is open, unlink
298 # schedules it for delete but does not delete it. Rename
299 # happens immediately even for open files, so we rename
300 # destination to a temporary name, then delete that. Then
301 # rename is safe to do.
302 # The temporary name is chosen at random to avoid the situation
303 # where a file is left lying around from a previous aborted run.
304
305 for tries in xrange(10):
306 temp = '%s-%08x' % (dst, random.randint(0, 0xffffffff))
307 try:
308 os.rename(dst, temp) # raises OSError EEXIST if temp exists
309 break
310 except OSError, e:
311 if e.errno != errno.EEXIST:
312 raise
313 else:
314 raise IOError, (errno.EEXIST, "No usable temporary filename found")
315
316 try:
317 os.unlink(temp)
318 except:
319 # Some rude AV-scanners on Windows may cause the unlink to
320 # fail. Not aborting here just leaks the temp file, whereas
321 # aborting at this point may leave serious inconsistencies.
322 # Ideally, we would notify the user here.
323 pass
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