--- a/mercurial/win32.py Sun Mar 27 12:59:25 2011 +0200
+++ b/mercurial/win32.py Sun Mar 27 01:17:48 2011 +0100
@@ -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 @@
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