[PATCH] windows posixfile experiments

Adrian Buehlmann adrian at cadifra.com
Fri May 13 17:25:08 CDT 2011


On 2011-05-13 16:44, Adrian Buehlmann wrote:
> # 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

I currently have

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,55 @@
     os.mkdir(path)
     if notindexed:
         _kernel32.SetFileAttributesA(path,
_FILE_ATTRIBUTE_NOT_CONTENT_INDEXED)
+
+def _crtname():
+    import ctypes.util
+    try:
+        # find_msvcrt was introduced in Python 2.6
+        return ctypes.util.find_msvcrt()
+    except AttributeError:
+        return 'msvcr80.dll' # CPython 2.5
+
+_crt = ctypes.CDLL(_crtname())
+
+def posixfile(name, mode='r', bufsize=-1):
+    m0 = mode[0]
+    if 'b' in mode:
+        flags = _O_BINARY
+    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
+
+    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"
+    fd = _crt._open_osfhandle(fh, flags)
+    if fd == -1:
+        _kernel32.CloseHandle(fh)
+        _raiseioerror(name)
+
+    return os.fdopen(fd, mode, bufsize)


The bad news is, that the returned file's name attribute has the value
<fdopen> and code elsewhere using the name attribute fails now.

The python doc says:

<quote>
file.name
If the file object was created using open(), the name of the file.
Otherwise, some string that indicates the source of the file object, of
the form <...>. This is a read-only attribute and may not be present on
all file-like objects.
</quote>

The users of posixfile rightfully can assume that they used "open", so
the name attribute must be correctly set.

This is fixable, but probably needs a proxy object or similar.


More information about the Mercurial-devel mailing list