# HG changeset patch # User Adrian Buehlmann # Date 2011-03-27 00:17:48 # Node ID 930efdc6bfa439f5a42aa3266cb59607bd76b8e2 # Parent 1ce0e80799c081be3267b4a67a42bbd72f2215c1 windows: move unlink to win32.py no code change diff --git a/mercurial/win32.py b/mercurial/win32.py --- a/mercurial/win32.py +++ b/mercurial/win32.py @@ -6,7 +6,7 @@ # GNU General Public License version 2 or any later version. import encoding -import ctypes, errno, os, struct, subprocess +import ctypes, errno, os, struct, subprocess, random _kernel32 = ctypes.windll.kernel32 @@ -316,3 +316,43 @@ def spawndetached(args): raise ctypes.WinError() return pi.dwProcessId + +def unlink(f): + '''try to implement POSIX' unlink semantics on Windows''' + + # POSIX allows to unlink and rename open files. Windows has serious + # problems with doing that: + # - Calling os.unlink (or os.rename) on a file f fails if f or any + # hardlinked copy of f has been opened with Python's open(). There is no + # way such a file can be deleted or renamed on Windows (other than + # scheduling the delete or rename for the next reboot). + # - Calling os.unlink on a file that has been opened with Mercurial's + # posixfile (or comparable methods) will delay the actual deletion of + # the file for as long as the file is held open. The filename is blocked + # during that time and cannot be used for recreating a new file under + # that same name ("zombie file"). Directories containing such zombie files + # cannot be removed or moved. + # A file that has been opened with posixfile can be renamed, so we rename + # f to a random temporary name before calling os.unlink on it. This allows + # callers to recreate f immediately while having other readers do their + # implicit zombie filename blocking on a temporary name. + + for tries in xrange(10): + temp = '%s-%08x' % (f, random.randint(0, 0xffffffff)) + try: + os.rename(f, temp) # raises OSError EEXIST if temp exists + break + except OSError, e: + if e.errno != errno.EEXIST: + raise + else: + raise IOError, (errno.EEXIST, "No usable temporary filename found") + + try: + os.unlink(temp) + except: + # Some very rude AV-scanners on Windows may cause this unlink to fail. + # Not aborting here just leaks the temp file, whereas aborting at this + # point may leave serious inconsistencies. Ideally, we would notify + # the user in this case here. + pass diff --git a/mercurial/windows.py b/mercurial/windows.py --- a/mercurial/windows.py +++ b/mercurial/windows.py @@ -7,7 +7,7 @@ from i18n import _ import osutil, error -import errno, msvcrt, os, re, sys, random, subprocess +import errno, msvcrt, os, re, sys, subprocess nulldev = 'NUL:' umask = 002 @@ -293,46 +293,6 @@ def unlinkpath(f): except OSError: pass -def unlink(f): - '''try to implement POSIX' unlink semantics on Windows''' - - # POSIX allows to unlink and rename open files. Windows has serious - # problems with doing that: - # - Calling os.unlink (or os.rename) on a file f fails if f or any - # hardlinked copy of f has been opened with Python's open(). There is no - # way such a file can be deleted or renamed on Windows (other than - # scheduling the delete or rename for the next reboot). - # - Calling os.unlink on a file that has been opened with Mercurial's - # posixfile (or comparable methods) will delay the actual deletion of - # the file for as long as the file is held open. The filename is blocked - # during that time and cannot be used for recreating a new file under - # that same name ("zombie file"). Directories containing such zombie files - # cannot be removed or moved. - # A file that has been opened with posixfile can be renamed, so we rename - # f to a random temporary name before calling os.unlink on it. This allows - # callers to recreate f immediately while having other readers do their - # implicit zombie filename blocking on a temporary name. - - for tries in xrange(10): - temp = '%s-%08x' % (f, random.randint(0, 0xffffffff)) - try: - os.rename(f, temp) # raises OSError EEXIST if temp exists - break - except OSError, e: - if e.errno != errno.EEXIST: - raise - else: - raise IOError, (errno.EEXIST, "No usable temporary filename found") - - try: - os.unlink(temp) - except: - # Some very rude AV-scanners on Windows may cause this unlink to fail. - # Not aborting here just leaks the temp file, whereas aborting at this - # point may leave serious inconsistencies. Ideally, we would notify - # the user in this case here. - pass - def rename(src, dst): '''atomically rename file src to dst, replacing dst if it exists''' try: