[PATCH] windows posixfile experiments

Adrian Buehlmann adrian at cadifra.com
Fri May 13 09:44:25 CDT 2011


# HG changeset patch
# User Adrian Buehlmann <adrian at cadifra.com>
# Date 1305284858 -7200
# Node ID b0ca8beae1da571b673f798c8a97d20f818a74b1
# Parent  c322890b03e6f584ec062ebf644b8af063009bd4
windows posixfile experiments

NOT READY FOR INCLUSION YET!!!!

I'm trying to replace osutil.posixfile with a ctypes-based
implementation.

This might bring us a bit closer to getting posixfile on
Windows running with things like pypy.

Just FYI

TODO: Fight CRT dll version hell (see comment in diff for
win32.py)

diff --git a/mercurial/win32.py b/mercurial/win32.py
--- a/mercurial/win32.py
+++ b/mercurial/win32.py
@@ -54,7 +54,20 @@
 _FILE_SHARE_WRITE = 0x00000002
 _FILE_SHARE_DELETE = 0x00000004
 
+_CREATE_ALWAYS = 2
 _OPEN_EXISTING = 3
+_OPEN_ALWAYS = 4
+
+_GENERIC_READ = 0x80000000
+_GENERIC_WRITE = 0x40000000
+
+# _open_osfhandle
+_O_RDONLY = 0x0000
+_O_RDWR = 0x0002
+_O_APPEND = 0x0008
+
+_O_TEXT = 0x4000
+_O_BINARY = 0x8000
 
 # SetFileAttributes
 _FILE_ATTRIBUTE_NORMAL = 0x80
@@ -126,6 +139,10 @@
     err = ctypes.WinError()
     raise OSError(err.errno, '%s: %s' % (name, err.strerror))
 
+def _raiseioerror(name):
+    err = ctypes.WinError()
+    raise IOError(err.errno, '%s: %s' % (name, err.strerror))
+
 def _getfileinfo(name):
     fh = _kernel32.CreateFileA(name, 0,
             _FILE_SHARE_READ | _FILE_SHARE_WRITE | _FILE_SHARE_DELETE,
@@ -374,3 +391,52 @@
     os.mkdir(path)
     if notindexed:
         _kernel32.SetFileAttributesA(path, _FILE_ATTRIBUTE_NOT_CONTENT_INDEXED)
+
+def posixfile(name, mode='r', bufsize=-1):
+    m0 = mode[0]
+    fpmode = m0
+    if 'b' in mode:
+        flags = _O_BINARY
+        fpmode += 'b'
+    else:
+        flags = _O_TEXT
+
+    if m0 is 'r' and not '+' in mode:
+        flags |= _O_RDONLY
+        access = _GENERIC_READ
+    else:
+        # work around http://support.microsoft.com/kb/899149 and
+        # set _O_RDWR for 'w' and 'a', even if mode has no '+'
+        flags |= _O_RDWR
+        access = _GENERIC_READ | _GENERIC_WRITE
+        fpmode += '+'
+
+    if m0 is 'r':
+        creation = _OPEN_EXISTING
+    elif m0 is 'w':
+        creation = _CREATE_ALWAYS
+    elif m0 is 'a':
+        creation = _OPEN_ALWAYS
+        flags |= _O_APPEND
+    else:
+        raise ValueError("invalid mode: %s" % mode)
+
+    fh = _kernel32.CreateFileA(name, access,
+            _FILE_SHARE_READ | _FILE_SHARE_WRITE | _FILE_SHARE_DELETE,
+            None, creation, _FILE_ATTRIBUTE_NORMAL, None)
+    if fh == _INVALID_HANDLE_VALUE:
+        _raiseioerror(name)
+
+    # for CPython we must use the same CRT as Python uses,
+    # or the os.fdopen call below will abort with
+    #   "OSError: [Errno 9] Bad file descriptor"
+    # To find out the name of the CRT used by Python, use
+    #   import ctypes.util
+    #   print ctypes.util.find_msvcrt()
+    # Note: find_msvcrt was introduced with Python 2.6
+    fd = ctypes.cdll.msvcr90._open_osfhandle(fh, flags)
+    if fd == -1:
+        _kernel32.CloseHandle(fh)
+        _raiseioerror(name)
+
+    return os.fdopen(fd, mode, bufsize)
diff --git a/mercurial/windows.py b/mercurial/windows.py
--- a/mercurial/windows.py
+++ b/mercurial/windows.py
@@ -12,14 +12,6 @@
 nulldev = 'NUL:'
 umask = 002
 
-# wrap osutil.posixfile to provide friendlier exceptions
-def posixfile(name, mode='r', buffering=-1):
-    try:
-        return osutil.posixfile(name, mode, buffering)
-    except WindowsError, err:
-        raise IOError(err.errno, '%s: %s' % (name, err.strerror))
-posixfile.__doc__ = osutil.posixfile.__doc__
-
 class winstdout(object):
     '''stdout on windows misbehaves if sent through a pipe'''
 


More information about the Mercurial-devel mailing list