mercurial/windows.py
changeset 13775 930efdc6bfa4
parent 13379 67743d5f49b6
child 13777 f6e5035dc81a
equal deleted inserted replaced
13774:1ce0e80799c0 13775:930efdc6bfa4
     5 # This software may be used and distributed according to the terms of the
     5 # This software may be used and distributed according to the terms of the
     6 # GNU General Public License version 2 or any later version.
     6 # GNU General Public License version 2 or any later version.
     7 
     7 
     8 from i18n import _
     8 from i18n import _
     9 import osutil, error
     9 import osutil, error
    10 import errno, msvcrt, os, re, sys, random, subprocess
    10 import errno, msvcrt, os, re, sys, subprocess
    11 
    11 
    12 nulldev = 'NUL:'
    12 nulldev = 'NUL:'
    13 umask = 002
    13 umask = 002
    14 
    14 
    15 # wrap osutil.posixfile to provide friendlier exceptions
    15 # wrap osutil.posixfile to provide friendlier exceptions
   291     try:
   291     try:
   292         _removedirs(os.path.dirname(f))
   292         _removedirs(os.path.dirname(f))
   293     except OSError:
   293     except OSError:
   294         pass
   294         pass
   295 
   295 
   296 def unlink(f):
       
   297     '''try to implement POSIX' unlink semantics on Windows'''
       
   298 
       
   299     # POSIX allows to unlink and rename open files. Windows has serious
       
   300     # problems with doing that:
       
   301     # - Calling os.unlink (or os.rename) on a file f fails if f or any
       
   302     #   hardlinked copy of f has been opened with Python's open(). There is no
       
   303     #   way such a file can be deleted or renamed on Windows (other than
       
   304     #   scheduling the delete or rename for the next reboot).
       
   305     # - Calling os.unlink on a file that has been opened with Mercurial's
       
   306     #   posixfile (or comparable methods) will delay the actual deletion of
       
   307     #   the file for as long as the file is held open. The filename is blocked
       
   308     #   during that time and cannot be used for recreating a new file under
       
   309     #   that same name ("zombie file"). Directories containing such zombie files
       
   310     #   cannot be removed or moved.
       
   311     # A file that has been opened with posixfile can be renamed, so we rename
       
   312     # f to a random temporary name before calling os.unlink on it. This allows
       
   313     # callers to recreate f immediately while having other readers do their
       
   314     # implicit zombie filename blocking on a temporary name.
       
   315 
       
   316     for tries in xrange(10):
       
   317         temp = '%s-%08x' % (f, random.randint(0, 0xffffffff))
       
   318         try:
       
   319             os.rename(f, temp)  # raises OSError EEXIST if temp exists
       
   320             break
       
   321         except OSError, e:
       
   322             if e.errno != errno.EEXIST:
       
   323                 raise
       
   324     else:
       
   325         raise IOError, (errno.EEXIST, "No usable temporary filename found")
       
   326 
       
   327     try:
       
   328         os.unlink(temp)
       
   329     except:
       
   330         # Some very rude AV-scanners on Windows may cause this unlink to fail.
       
   331         # Not aborting here just leaks the temp file, whereas aborting at this
       
   332         # point may leave serious inconsistencies. Ideally, we would notify
       
   333         # the user in this case here.
       
   334         pass
       
   335 
       
   336 def rename(src, dst):
   296 def rename(src, dst):
   337     '''atomically rename file src to dst, replacing dst if it exists'''
   297     '''atomically rename file src to dst, replacing dst if it exists'''
   338     try:
   298     try:
   339         os.rename(src, dst)
   299         os.rename(src, dst)
   340     except OSError, e:
   300     except OSError, e: