Author: Philip Jenvey <[email protected]>
Branch: py3k
Changeset: r73587:1900e5ea6ec4
Date: 2014-09-17 12:53 -0700
http://bitbucket.org/pypy/pypy/changeset/1900e5ea6ec4/
Log: issue1798: add nt._getfinalpathname. add _getfileinformation as well
diff --git a/pypy/module/posix/__init__.py b/pypy/module/posix/__init__.py
--- a/pypy/module/posix/__init__.py
+++ b/pypy/module/posix/__init__.py
@@ -164,6 +164,11 @@
# not visible via os, inconsistency in nt:
if hasattr(posix, '_getfullpathname'):
interpleveldefs['_getfullpathname'] = 'interp_posix._getfullpathname'
+ if os.name == 'nt':
+ interpleveldefs.update({
+ '_getfileinformation': 'interp_posix._getfileinformation',
+ '_getfinalpathname': 'interp_posix._getfinalpathname',
+ })
if hasattr(os, 'chroot'):
interpleveldefs['chroot'] = 'interp_posix.chroot'
diff --git a/pypy/module/posix/interp_posix.py
b/pypy/module/posix/interp_posix.py
--- a/pypy/module/posix/interp_posix.py
+++ b/pypy/module/posix/interp_posix.py
@@ -5,8 +5,7 @@
from rpython.rlib.objectmodel import specialize
from rpython.rlib.rarithmetic import r_longlong
from rpython.rlib.unroll import unrolling_iterable
-from rpython.rtyper.module import ll_os_stat
-from rpython.rtyper.module.ll_os import RegisterOs
+from rpython.rtyper.module import ll_os, ll_os_stat
from pypy.interpreter.gateway import unwrap_spec, WrappedDefault
from pypy.interpreter.error import OperationError, wrap_oserror, wrap_oserror2
@@ -1205,7 +1204,7 @@
raise wrap_oserror(space, e)
def declare_new_w_star(name):
- if name in RegisterOs.w_star_returning_int:
+ if name in ll_os.RegisterOs.w_star_returning_int:
@unwrap_spec(status=c_int)
def WSTAR(space, status):
return space.wrap(getattr(os, name)(status))
@@ -1217,7 +1216,7 @@
WSTAR.func_name = name
return WSTAR
-for name in RegisterOs.w_star:
+for name in ll_os.RegisterOs.w_star:
if hasattr(os, name):
func = declare_new_w_star(name)
globals()[name] = func
@@ -1383,3 +1382,25 @@
if codeset:
return space.wrap(codeset)
return space.w_None
+
+if _WIN32:
+ @unwrap_spec(fd=c_int)
+ def _getfileinformation(space, fd):
+ try:
+ info = ll_os._getfileinformation(fd)
+ except OSError as e:
+ raise wrap_oserror(space, e)
+ return space.newtuple([space.wrap(info[0]),
+ space.wrap(info[1]),
+ space.wrap(info[2])])
+
+ def _getfinalpathname(space, w_path):
+ path = space.unicode_w(w_path)
+ try:
+ result = ll_os._getfinalpathname(path)
+ except ll_os.LLNotImplemented as e:
+ raise OperationError(space.w_NotImplementedError,
+ space.wrap(e.msg))
+ except OSError as e:
+ raise wrap_oserror2(space, e, w_path)
+ return space.wrap(result)
diff --git a/pypy/module/posix/test/test_posix2.py
b/pypy/module/posix/test/test_posix2.py
--- a/pypy/module/posix/test/test_posix2.py
+++ b/pypy/module/posix/test/test_posix2.py
@@ -1040,6 +1040,21 @@
# just ensure it returns something reasonable
assert encoding is None or type(encoding) is str
+ if os.name == 'nt':
+ def test__getfileinformation(self):
+ import os
+ path = os.path.join(self.pdir, 'file1')
+ with open(path) as fp:
+ info = self.posix._getfileinformation(fp.fileno())
+ assert len(info) == 3
+ assert all(isinstance(obj, int) for obj in info)
+
+ def test__getfinalpathname(self):
+ import os
+ path = os.path.join(self.pdir, 'file1')
+ result = self.posix._getfinalpathname(path)
+ assert os.path.exists(result)
+
class AppTestEnvironment(object):
def setup_class(cls):
diff --git a/rpython/rlib/rdynload.py b/rpython/rlib/rdynload.py
--- a/rpython/rlib/rdynload.py
+++ b/rpython/rlib/rdynload.py
@@ -158,3 +158,4 @@
return res
LoadLibrary = rwin32.LoadLibrary
+ GetModuleHandle = rwin32.GetModuleHandle
diff --git a/rpython/rlib/rwin32.py b/rpython/rlib/rwin32.py
--- a/rpython/rlib/rwin32.py
+++ b/rpython/rlib/rwin32.py
@@ -130,6 +130,7 @@
# is hidden by operations in ll2ctypes. Call it now.
GetLastError()
+ GetModuleHandle = winexternal('GetModuleHandleA', [rffi.CCHARP], HMODULE)
LoadLibrary = winexternal('LoadLibraryA', [rffi.CCHARP], HMODULE)
GetProcAddress = winexternal('GetProcAddress',
[HMODULE, rffi.CCHARP],
diff --git a/rpython/rtyper/lltypesystem/ll2ctypes.py
b/rpython/rtyper/lltypesystem/ll2ctypes.py
--- a/rpython/rtyper/lltypesystem/ll2ctypes.py
+++ b/rpython/rtyper/lltypesystem/ll2ctypes.py
@@ -361,7 +361,9 @@
functype = ctypes.CFUNCTYPE
if sys.platform == 'win32':
from rpython.rlib.clibffi import FFI_STDCALL, FFI_DEFAULT_ABI
- if getattr(T.TO, 'ABI', FFI_DEFAULT_ABI) == FFI_STDCALL:
+ # XXX:
+ #if getattr(T.TO, 'ABI', FFI_DEFAULT_ABI) == FFI_STDCALL:
+ if getattr(T.TO, 'ABI', FFI_DEFAULT_ABI) == 'FFI_STDCALL':
# for win32 system call
functype = ctypes.WINFUNCTYPE
argtypes = [get_ctypes_type(ARG) for ARG in T.TO.ARGS
diff --git a/rpython/rtyper/module/ll_os.py b/rpython/rtyper/module/ll_os.py
--- a/rpython/rtyper/module/ll_os.py
+++ b/rpython/rtyper/module/ll_os.py
@@ -105,6 +105,12 @@
_CYGWIN = sys.platform == 'cygwin'
+# plain NotImplementedError is invalid RPython
+class LLNotImplemented(NotImplementedError):
+
+ def __init__(self, msg):
+ self.msg = msg
+
class CConfig:
"""
Definitions for platform integration.
@@ -1179,7 +1185,7 @@
condition=sys.platform=='win32')
def register_posix__getfullpathname(self, traits):
# this nt function is not exposed via os, but needed
- # to get a correct implementation of os.abspath
+ # to get a correct implementation of os.path.abspath
from rpython.rtyper.module.ll_win32file import
make_getfullpathname_impl
getfullpathname_llimpl = make_getfullpathname_impl(traits)
@@ -1963,10 +1969,12 @@
return OsEnvironController()
# ____________________________________________________________
-# Support for the WindowsError exception
+# Support for the WindowsError exception and misc functions
if sys.platform == 'win32':
from rpython.rlib import rwin32
+ from rpython.rtyper.module.ll_win32file import (
+ make__getfileinformation_impl, make__getfinalpathname_impl)
class RegisterFormatError(BaseLazyRegistering):
def __init__(self):
@@ -1977,3 +1985,6 @@
return extdef([lltype.Signed], str,
"rwin32_FormatError",
llimpl=rwin32.llimpl_FormatError)
+
+ _getfileinformation = make__getfileinformation_impl(UnicodeTraits())
+ _getfinalpathname = make__getfinalpathname_impl(UnicodeTraits())
diff --git a/rpython/rtyper/module/ll_win32file.py
b/rpython/rtyper/module/ll_win32file.py
--- a/rpython/rtyper/module/ll_win32file.py
+++ b/rpython/rtyper/module/ll_win32file.py
@@ -55,6 +55,15 @@
FILE_TYPE_CHAR = platform.ConstantInteger('FILE_TYPE_CHAR')
FILE_TYPE_PIPE = platform.ConstantInteger('FILE_TYPE_PIPE')
+ FILE_WRITE_ATTRIBUTES = platform.ConstantInteger(
+ 'FILE_WRITE_ATTRIBUTES')
+ OPEN_EXISTING = platform.ConstantInteger(
+ 'OPEN_EXISTING')
+ FILE_FLAG_BACKUP_SEMANTICS = platform.ConstantInteger(
+ 'FILE_FLAG_BACKUP_SEMANTICS')
+ VOLUME_NAME_DOS = platform.ConstantInteger('VOLUME_NAME_DOS')
+ VOLUME_NAME_NT = platform.ConstantInteger('VOLUME_NAME_NT')
+
WIN32_FILE_ATTRIBUTE_DATA = platform.Struct(
'WIN32_FILE_ATTRIBUTE_DATA',
[('dwFileAttributes', rwin32.DWORD),
@@ -67,14 +76,15 @@
BY_HANDLE_FILE_INFORMATION = platform.Struct(
'BY_HANDLE_FILE_INFORMATION',
[('dwFileAttributes', rwin32.DWORD),
+ ('ftCreationTime', rwin32.FILETIME),
+ ('ftLastAccessTime', rwin32.FILETIME),
+ ('ftLastWriteTime', rwin32.FILETIME),
+ ('dwVolumeSerialNumber', rwin32.DWORD),
('nFileSizeHigh', rwin32.DWORD),
('nFileSizeLow', rwin32.DWORD),
('nNumberOfLinks', rwin32.DWORD),
('nFileIndexHigh', rwin32.DWORD),
- ('nFileIndexLow', rwin32.DWORD),
- ('ftCreationTime', rwin32.FILETIME),
- ('ftLastAccessTime', rwin32.FILETIME),
- ('ftLastWriteTime', rwin32.FILETIME)])
+ ('nFileIndexLow', rwin32.DWORD)])
config = platform.configure(CConfig)
@@ -92,6 +102,8 @@
INVALID_FILE_ATTRIBUTES
_S_IFDIR _S_IFREG _S_IFCHR _S_IFIFO
FILE_TYPE_UNKNOWN FILE_TYPE_CHAR FILE_TYPE_PIPE
+ FILE_WRITE_ATTRIBUTES OPEN_EXISTING
FILE_FLAG_BACKUP_SEMANTICS
+ VOLUME_NAME_DOS VOLUME_NAME_NT
ERROR_FILE_NOT_FOUND ERROR_NO_MORE_FILES
ERROR_SHARING_VIOLATION
'''.split():
@@ -163,6 +175,13 @@
[traits.CCHARP, traits.CCHARP],
rwin32.BOOL)
+ CreateFile = external(
+ 'CreateFile' + apisuffix,
+ [traits.CCHARP, rwin32.DWORD, rwin32.DWORD,
+ rwin32.LPSECURITY_ATTRIBUTES, rwin32.DWORD, rwin32.DWORD,
+ rwin32.HANDLE],
+ rwin32.HANDLE)
+
DeleteFile = external(
'DeleteFile' + suffix,
[traits.CCHARP],
@@ -173,6 +192,27 @@
[traits.CCHARP, traits.CCHARP],
rwin32.BOOL)
+ # dynamically loaded
+ GetFinalPathNameByHandle = None
+
+ @staticmethod
+ def check_GetFinalPathNameByHandle():
+ if Win32Traits.GetFinalPathNameByHandle:
+ return True
+
+ from rpython.rlib.rdynload import GetModuleHandle, dlsym
+ hKernel32 = GetModuleHandle("KERNEL32")
+ try:
+ func = dlsym(hKernel32, 'GetFinalPathNameByHandle' + suffix)
+ except KeyError:
+ return False
+
+ TYPE = lltype.Ptr(lltype.FuncType(
+ [rwin32.HANDLE, traits.CCHARP, rwin32.DWORD, rwin32.DWORD],
+ rwin32.DWORD, abi='FFI_STDCALL'))
+ Win32Traits.GetFinalPathNameByHandle = rffi.cast(TYPE, func)
+ return True
+
return Win32Traits
#_______________________________________________________________
@@ -336,27 +376,6 @@
win32traits = make_win32_traits(traits)
from rpython.rtyper.module.ll_os_stat import time_t_to_FILE_TIME
- class CConfig:
- _compilation_info_ = ExternalCompilationInfo(
- includes = ['windows.h'],
- )
-
- FILE_WRITE_ATTRIBUTES = platform.ConstantInteger(
- 'FILE_WRITE_ATTRIBUTES')
- OPEN_EXISTING = platform.ConstantInteger(
- 'OPEN_EXISTING')
- FILE_FLAG_BACKUP_SEMANTICS = platform.ConstantInteger(
- 'FILE_FLAG_BACKUP_SEMANTICS')
- globals().update(platform.configure(CConfig))
-
- CreateFile = rffi.llexternal(
- 'CreateFile' + win32traits.apisuffix,
- [traits.CCHARP, rwin32.DWORD, rwin32.DWORD,
- rwin32.LPSECURITY_ATTRIBUTES, rwin32.DWORD, rwin32.DWORD,
- rwin32.HANDLE],
- rwin32.HANDLE,
- calling_conv='win')
-
GetSystemTime = rffi.llexternal(
'GetSystemTime',
[lltype.Ptr(rwin32.SYSTEMTIME)],
@@ -381,10 +400,10 @@
@specialize.argtype(1)
def os_utime_llimpl(path, tp):
- hFile = CreateFile(path,
- FILE_WRITE_ATTRIBUTES, 0,
- None, OPEN_EXISTING,
- FILE_FLAG_BACKUP_SEMANTICS,
+ hFile = win32traits.CreateFile(path,
+ win32traits.FILE_WRITE_ATTRIBUTES, 0,
+ None, win32traits.OPEN_EXISTING,
+ win32traits.FILE_FLAG_BACKUP_SEMANTICS,
rwin32.NULL_HANDLE)
if hFile == rwin32.INVALID_HANDLE_VALUE:
raise rwin32.lastWindowsError()
@@ -413,3 +432,68 @@
lltype.free(mtime, flavor='raw')
return os_utime_llimpl
+
+#_______________________________________________________________
+# _getfileinformation (py3)
+
+def make__getfileinformation_impl(traits):
+ from rpython.rlib import rwin32
+ win32traits = make_win32_traits(traits)
+
+ def _getfileinformation_llimpl(fd):
+ hFile = rwin32.get_osfhandle(fd)
+ with lltype.scoped_alloc(
+ win32traits.BY_HANDLE_FILE_INFORMATION) as info:
+ if win32traits.GetFileInformationByHandle(hFile, info) == 0:
+ raise lastWindowsError("_getfileinformation")
+ return (rffi.cast(lltype.Signed, info.c_dwVolumeSerialNumber),
+ rffi.cast(lltype.Signed, info.c_nFileIndexHigh),
+ rffi.cast(lltype.Signed, info.c_nFileIndexLow))
+
+ return _getfileinformation_llimpl
+
+#_______________________________________________________________
+# _getfinalpathname (py3)
+
+def make__getfinalpathname_impl(traits):
+ from rpython.rlib import rwin32
+ from rpython.rtyper.module.ll_os import LLNotImplemented
+ assert traits.str is unicode, 'Currently only handles unicode paths'
+ win32traits = make_win32_traits(traits)
+
+ def _getfinalpathname_llimpl(path):
+ if not win32traits.check_GetFinalPathNameByHandle():
+ raise LLNotImplemented("GetFinalPathNameByHandle not available on "
+ "this platform")
+
+ hFile = win32traits.CreateFile(path, 0, 0, None,
+ win32traits.OPEN_EXISTING,
+ win32traits.FILE_FLAG_BACKUP_SEMANTICS,
+ rwin32.NULL_HANDLE)
+ if hFile == rwin32.INVALID_HANDLE_VALUE:
+ raise rwin32.lastWindowsError("CreateFile")
+
+ VOLUME_NAME_DOS = rffi.cast(rwin32.DWORD, win32traits.VOLUME_NAME_DOS)
+ try:
+ size = win32traits.GetFinalPathNameByHandle(
+ hFile,
+ lltype.nullptr(traits.CCHARP.TO),
+ rffi.cast(rwin32.DWORD, 0),
+ VOLUME_NAME_DOS)
+ if size == 0:
+ raise rwin32.lastWindowsError("GetFinalPathNameByHandle")
+
+ with lltype.scoped_alloc(traits.CCHARP.TO, size + 1) as
target_path:
+ result = win32traits.GetFinalPathNameByHandle(
+ hFile,
+ target_path,
+ size,
+ VOLUME_NAME_DOS)
+ if result == 0:
+ raise rwin32.lastWindowsError("GetFinalPathNameByHandle")
+ return traits.charpsize2str(target_path,
+ rffi.cast(lltype.Signed, result))
+ finally:
+ rwin32.CloseHandle(hFile)
+
+ return _getfinalpathname_llimpl
diff --git a/rpython/rtyper/module/support.py b/rpython/rtyper/module/support.py
--- a/rpython/rtyper/module/support.py
+++ b/rpython/rtyper/module/support.py
@@ -49,6 +49,7 @@
CHAR = rffi.CHAR
CCHARP = rffi.CCHARP
charp2str = staticmethod(rffi.charp2str)
+ charpsize2str = staticmethod(rffi.charpsize2str)
scoped_str2charp = staticmethod(rffi.scoped_str2charp)
str2charp = staticmethod(rffi.str2charp)
free_charp = staticmethod(rffi.free_charp)
@@ -68,6 +69,7 @@
CHAR = rffi.WCHAR_T
CCHARP = rffi.CWCHARP
charp2str = staticmethod(rffi.wcharp2unicode)
+ charpsize2str = staticmethod(rffi.wcharpsize2unicode)
str2charp = staticmethod(rffi.unicode2wcharp)
scoped_str2charp = staticmethod(rffi.scoped_unicode2wcharp)
free_charp = staticmethod(rffi.free_wcharp)
diff --git a/rpython/rtyper/module/test/test_ll_win32file.py
b/rpython/rtyper/module/test/test_ll_win32file.py
new file mode 100644
--- /dev/null
+++ b/rpython/rtyper/module/test/test_ll_win32file.py
@@ -0,0 +1,26 @@
+import os
+
+import py
+
+from rpython.rtyper.module import ll_os
+
+if not ll_os._WIN32:
+ py.test.skip("requires Windows")
+
+
+def test__getfinalpathname():
+ path = __file__.decode('mbcs')
+ try:
+ result = ll_os._getfinalpathname(path)
+ except ll_os.LLNotImplemented:
+ py.test.skip("_getfinalpathname not supported on this platform")
+ assert os.path.exists(result)
+
+
+def test__getfileinformation():
+ with open(__file__) as fp:
+ stat = os.fstat(fp.fileno())
+ info = ll_os._getfileinformation(fp.fileno())
+ serial, high, low = info
+ assert type(serial) in (int, long)
+ assert (high << 32) + low == stat.st_ino
_______________________________________________
pypy-commit mailing list
[email protected]
https://mail.python.org/mailman/listinfo/pypy-commit