[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