mercurial/windows.py
changeset 13280 6052bbc7aabd
parent 13278 e9a52ed28157
child 13375 f1fa8f481c7c
equal deleted inserted replaced
13279:eed22340b7aa 13280:6052bbc7aabd
   283     try:
   283     try:
   284         _removedirs(os.path.dirname(f))
   284         _removedirs(os.path.dirname(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:
   291         os.rename(src, dst)
   331         os.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):
   327     # No standard library function really spawns a fully detached
   339     # No standard library function really spawns a fully detached
   328     # process under win32 because they allocate pipes or other objects
   340     # process under win32 because they allocate pipes or other objects