##// 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,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 for tries in xrange(10):
308 for tries in xrange(10):
306 temp = '%s-%08x' % (dst, random.randint(0, 0xffffffff))
309 temp = '%s-%08x' % (f, random.randint(0, 0xffffffff))
307 try:
310 try:
308 os.rename(dst, temp) # raises OSError EEXIST if temp exists
311 os.rename(f, temp) # raises OSError EEXIST if temp exists
309 break
312 break
310 except OSError, e:
313 except OSError, e:
311 if e.errno != errno.EEXIST:
314 if e.errno != errno.EEXIST:
@@ -316,11 +319,20 b' def rename(src, dst):'
316 try:
319 try:
317 os.unlink(temp)
320 os.unlink(temp)
318 except:
321 except:
319 # Some rude AV-scanners on Windows may cause the unlink to
322 # Some very rude AV-scanners on Windows may cause this unlink to fail.
320 # fail. Not aborting here just leaks the temp file, whereas
323 # Not aborting here just leaks the temp file, whereas aborting at this
321 # aborting at this point may leave serious inconsistencies.
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 pass
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