mercurial/windows.py
changeset 9592 5ebeef7cc201
parent 9591 012f1244cd4c
parent 9549 8b8920209317
child 9594 f0c5c59d878d
equal deleted inserted replaced
9591:012f1244cd4c 9592:5ebeef7cc201
     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, incorporated herein by reference.
     6 # GNU General Public License version 2, incorporated herein by reference.
     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
    10 import errno, msvcrt, os, re, sys, random
    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
   281     try:
   281     try:
   282         _removedirs(os.path.dirname(f))
   282         _removedirs(os.path.dirname(f))
   283     except OSError:
   283     except OSError:
   284         pass
   284         pass
   285 
   285 
       
   286 def rename(src, dst):
       
   287     '''atomically rename file src to dst, replacing dst if it exists'''
       
   288     try:
       
   289         os.rename(src, dst)
       
   290     except OSError, err: # FIXME: check err (EEXIST ?)
       
   291 
       
   292         # On windows, rename to existing file is not allowed, so we
       
   293         # must delete destination first. But if a file is open, unlink
       
   294         # schedules it for delete but does not delete it. Rename
       
   295         # happens immediately even for open files, so we rename
       
   296         # destination to a temporary name, then delete that. Then
       
   297         # rename is safe to do.
       
   298         # The temporary name is chosen at random to avoid the situation
       
   299         # where a file is left lying around from a previous aborted run.
       
   300         # The usual race condition this introduces can't be avoided as
       
   301         # we need the name to rename into, and not the file itself. Due
       
   302         # to the nature of the operation however, any races will at worst
       
   303         # lead to the rename failing and the current operation aborting.
       
   304 
       
   305         def tempname(prefix):
       
   306             for tries in xrange(10):
       
   307                 temp = '%s-%08x' % (prefix, random.randint(0, 0xffffffff))
       
   308                 if not os.path.exists(temp):
       
   309                     return temp
       
   310             raise IOError, (errno.EEXIST, "No usable temporary filename found")
       
   311 
       
   312         temp = tempname(dst)
       
   313         os.rename(dst, temp)
       
   314         try:
       
   315             os.unlink(temp)
       
   316         except:
       
   317             # Some rude AV-scanners on Windows may cause the unlink to
       
   318             # fail. Not aborting here just leaks the temp file, whereas
       
   319             # aborting at this point may leave serious inconsistencies.
       
   320             # Ideally, we would notify the user here.
       
   321             pass
       
   322         os.rename(src, dst)
       
   323 
   286 try:
   324 try:
   287     # override functions with win32 versions if possible
   325     # override functions with win32 versions if possible
   288     from win32 import *
   326     from win32 import *
   289 except ImportError:
   327 except ImportError:
   290     pass
   328     pass