Author: Ronan Lamy <[email protected]>
Branch:
Changeset: r93648:f560bd567d72
Date: 2018-01-10 20:34 +0000
http://bitbucket.org/pypy/pypy/changeset/f560bd567d72/
Log: Backport rpython/ changes made on the py3.5 branch
diff --git a/rpython/annotator/binaryop.py b/rpython/annotator/binaryop.py
--- a/rpython/annotator/binaryop.py
+++ b/rpython/annotator/binaryop.py
@@ -381,16 +381,14 @@
class __extend__(pairtype(SomeChar, SomeUnicodeCodePoint),
pairtype(SomeUnicodeCodePoint, SomeChar)):
def union((uchr1, uchr2)):
- return SomeUnicodeCodePoint()
+ no_nul = uchr1.no_nul and uchr2.no_nul
+ return SomeUnicodeCodePoint(no_nul=no_nul)
class __extend__(pairtype(SomeUnicodeCodePoint, SomeUnicodeCodePoint)):
def union((uchr1, uchr2)):
no_nul = uchr1.no_nul and uchr2.no_nul
return SomeUnicodeCodePoint(no_nul=no_nul)
- def add((chr1, chr2)):
- return SomeUnicodeString()
-
class __extend__(pairtype(SomeString, SomeUnicodeString),
pairtype(SomeUnicodeString, SomeString)):
def mod((str, unistring)):
diff --git a/rpython/rlib/rdynload.py b/rpython/rlib/rdynload.py
--- a/rpython/rlib/rdynload.py
+++ b/rpython/rlib/rdynload.py
@@ -228,7 +228,9 @@
res = rwin32.LoadLibrary(name)
if not res:
err = rwin32.GetLastError_saved()
- raise DLOpenError(rwin32.FormatError(err))
+ ustr = rwin32.FormatErrorW(err)
+ # DLOpenError unicode msg breaks translation of cpyext
create_extension_module
+ raise DLOpenError(ustr.encode('utf-8'))
return res
def dlclose(handle):
diff --git a/rpython/rlib/rposix.py b/rpython/rlib/rposix.py
--- a/rpython/rlib/rposix.py
+++ b/rpython/rlib/rposix.py
@@ -2574,3 +2574,160 @@
"""Passes offset==NULL; not support on all OSes"""
res = c_sendfile(out_fd, in_fd, lltype.nullptr(_OFF_PTR_T.TO), count)
return handle_posix_error('sendfile', res)
+
+# ____________________________________________________________
+# Support for *xattr functions
+
+if sys.platform.startswith('linux'):
+
+ class CConfig:
+ _compilation_info_ = ExternalCompilationInfo(
+ includes=['sys/xattr.h', 'linux/limits.h'],)
+ XATTR_SIZE_MAX = rffi_platform.DefinedConstantInteger('XATTR_SIZE_MAX')
+ XATTR_CREATE = rffi_platform.DefinedConstantInteger('XATTR_CREATE')
+ XATTR_REPLACE = rffi_platform.DefinedConstantInteger('XATTR_REPLACE')
+
+ cConfig = rffi_platform.configure(CConfig)
+ globals().update(cConfig)
+ c_fgetxattr = external('fgetxattr',
+ [rffi.INT, rffi.CCHARP, rffi.VOIDP, rffi.SIZE_T], rffi.SSIZE_T,
+ compilation_info=CConfig._compilation_info_,
+ save_err=rffi.RFFI_SAVE_ERRNO)
+ c_getxattr = external('getxattr',
+ [rffi.CCHARP, rffi.CCHARP, rffi.VOIDP, rffi.SIZE_T], rffi.SSIZE_T,
+ compilation_info=CConfig._compilation_info_,
+ save_err=rffi.RFFI_SAVE_ERRNO)
+ c_lgetxattr = external('lgetxattr',
+ [rffi.CCHARP, rffi.CCHARP, rffi.VOIDP, rffi.SIZE_T], rffi.SSIZE_T,
+ compilation_info=CConfig._compilation_info_,
+ save_err=rffi.RFFI_SAVE_ERRNO)
+ c_fsetxattr = external('fsetxattr',
+ [rffi.INT, rffi.CCHARP, rffi.CCHARP, rffi.SIZE_T, rffi.INT],
+ rffi.INT,
+ compilation_info=CConfig._compilation_info_,
+ save_err=rffi.RFFI_SAVE_ERRNO)
+ c_setxattr = external('setxattr',
+ [rffi.CCHARP, rffi.CCHARP, rffi.CCHARP, rffi.SIZE_T, rffi.INT],
+ rffi.INT,
+ compilation_info=CConfig._compilation_info_,
+ save_err=rffi.RFFI_SAVE_ERRNO)
+ c_lsetxattr = external('lsetxattr',
+ [rffi.CCHARP, rffi.CCHARP, rffi.CCHARP, rffi.SIZE_T, rffi.INT],
+ rffi.INT,
+ compilation_info=CConfig._compilation_info_,
+ save_err=rffi.RFFI_SAVE_ERRNO)
+ c_fremovexattr = external('fremovexattr',
+ [rffi.INT, rffi.CCHARP], rffi.INT,
+ compilation_info=CConfig._compilation_info_,
+ save_err=rffi.RFFI_SAVE_ERRNO)
+ c_removexattr = external('removexattr',
+ [rffi.CCHARP, rffi.CCHARP], rffi.INT,
+ compilation_info=CConfig._compilation_info_,
+ save_err=rffi.RFFI_SAVE_ERRNO)
+ c_lremovexattr = external('lremovexattr',
+ [rffi.CCHARP, rffi.CCHARP], rffi.INT,
+ compilation_info=CConfig._compilation_info_,
+ save_err=rffi.RFFI_SAVE_ERRNO)
+ c_flistxattr = external('flistxattr',
+ [rffi.INT, rffi.CCHARP, rffi.SIZE_T], rffi.SSIZE_T,
+ compilation_info=CConfig._compilation_info_,
+ save_err=rffi.RFFI_SAVE_ERRNO)
+ c_listxattr = external('listxattr',
+ [rffi.CCHARP, rffi.CCHARP, rffi.SIZE_T], rffi.SSIZE_T,
+ compilation_info=CConfig._compilation_info_,
+ save_err=rffi.RFFI_SAVE_ERRNO)
+ c_llistxattr = external('llistxattr',
+ [rffi.CCHARP, rffi.CCHARP, rffi.SIZE_T], rffi.SSIZE_T,
+ compilation_info=CConfig._compilation_info_,
+ save_err=rffi.RFFI_SAVE_ERRNO)
+ buf_sizes = [256, XATTR_SIZE_MAX]
+
+ def fgetxattr(fd, name):
+ for size in buf_sizes:
+ with rffi.scoped_alloc_buffer(size) as buf:
+ void_buf = rffi.cast(rffi.VOIDP, buf.raw)
+ res = c_fgetxattr(fd, name, void_buf, size)
+ if res < 0:
+ err = get_saved_errno()
+ if err != errno.ERANGE:
+ raise OSError(err, 'fgetxattr failed')
+ else:
+ return buf.str(res)
+ else:
+ raise OSError(errno.ERANGE, 'fgetxattr failed')
+
+ def getxattr(path, name, follow_symlinks=True):
+ for size in buf_sizes:
+ with rffi.scoped_alloc_buffer(size) as buf:
+ void_buf = rffi.cast(rffi.VOIDP, buf.raw)
+ if follow_symlinks:
+ res = c_getxattr(path, name, void_buf, size)
+ else:
+ res = c_lgetxattr(path, name, void_buf, size)
+ if res < 0:
+ err = get_saved_errno()
+ if err != errno.ERANGE:
+ c_name = 'getxattr' if follow_symlinks else 'lgetxattr'
+ raise OSError(err, c_name + 'failed')
+ else:
+ return buf.str(res)
+ else:
+ c_name = 'getxattr' if follow_symlinks else 'lgetxattr'
+ raise OSError(errno.ERANGE, c_name + 'failed')
+
+ def fsetxattr(fd, name, value, flags=0):
+ return handle_posix_error(
+ 'fsetxattr', c_fsetxattr(fd, name, value, len(value), flags))
+
+ def setxattr(path, name, value, flags=0, follow_symlinks=True):
+ if follow_symlinks:
+ return handle_posix_error(
+ 'setxattr', c_setxattr(path, name, value, len(value), flags))
+ else:
+ return handle_posix_error(
+ 'lsetxattr', c_lsetxattr(path, name, value, len(value), flags))
+
+ def fremovexattr(fd, name):
+ return handle_posix_error('fremovexattr', c_fremovexattr(fd, name))
+
+ def removexattr(path, name, follow_symlinks=True):
+ if follow_symlinks:
+ return handle_posix_error('removexattr', c_removexattr(path, name))
+ else:
+ return handle_posix_error('lremovexattr', c_lremovexattr(path,
name))
+
+ def _unpack_attrs(attr_string):
+ result = attr_string.split('\0')
+ del result[-1]
+ return result
+
+ def flistxattr(fd):
+ for size in buf_sizes:
+ with rffi.scoped_alloc_buffer(size) as buf:
+ res = c_flistxattr(fd, buf.raw, size)
+ if res < 0:
+ err = get_saved_errno()
+ if err != errno.ERANGE:
+ raise OSError(err, 'flistxattr failed')
+ else:
+ return _unpack_attrs(buf.str(res))
+ else:
+ raise OSError(errno.ERANGE, 'flistxattr failed')
+
+ def listxattr(path, follow_symlinks=True):
+ for size in buf_sizes:
+ with rffi.scoped_alloc_buffer(size) as buf:
+ if follow_symlinks:
+ res = c_listxattr(path, buf.raw, size)
+ else:
+ res = c_llistxattr(path, buf.raw, size)
+ if res < 0:
+ err = get_saved_errno()
+ if err != errno.ERANGE:
+ c_name = 'listxattr' if follow_symlinks else
'llistxattr'
+ raise OSError(err, c_name + 'failed')
+ else:
+ return _unpack_attrs(buf.str(res))
+ else:
+ c_name = 'listxattr' if follow_symlinks else 'llistxattr'
+ raise OSError(errno.ERANGE, c_name + 'failed')
diff --git a/rpython/rlib/rposix_scandir.py b/rpython/rlib/rposix_scandir.py
--- a/rpython/rlib/rposix_scandir.py
+++ b/rpython/rlib/rposix_scandir.py
@@ -1,56 +1,126 @@
from rpython.rlib import rposix, rwin32
from rpython.rlib.objectmodel import specialize
from rpython.rtyper.lltypesystem import lltype, rffi
+from rpython.rlib.rarithmetic import intmask
[email protected](0)
-def opendir(path):
- path = rposix._as_bytes0(path)
- return opendir_bytes(path)
-
-def opendir_bytes(path):
- dirp = rposix.c_opendir(path)
- if not dirp:
- raise OSError(rposix.get_saved_errno(), "opendir failed")
- return dirp
-
-def closedir(dirp):
- rposix.c_closedir(dirp)
-
if not rwin32.WIN32:
+ @specialize.argtype(0)
+ def opendir(path):
+ path = rposix._as_bytes0(path)
+ return opendir_bytes(path)
+
+ def opendir_bytes(path):
+ dirp = rposix.c_opendir(path)
+ if not dirp:
+ raise OSError(rposix.get_saved_errno(), "opendir failed")
+ return dirp
+
+ def closedir(dirp):
+ rposix.c_closedir(dirp)
+
NULL_DIRP = lltype.nullptr(rposix.DIRP.TO)
-def nextentry(dirp):
- """Read the next entry and returns an opaque object.
- Use the methods has_xxx() and get_xxx() to read from that
- opaque object. The opaque object is valid until the next
- time nextentry() or closedir() is called. This may raise
- OSError, or return a NULL pointer when exhausted. Note
- that this doesn't filter out the "." and ".." entries.
- """
- direntp = rposix.c_readdir(dirp)
- if direntp:
- error = rposix.get_saved_errno()
- if error:
- raise OSError(error, "readdir failed")
- return direntp
+ def nextentry(dirp):
+ """Read the next entry and returns an opaque object.
+ Use the methods has_xxx() and get_xxx() to read from that
+ opaque object. The opaque object is valid until the next
+ time nextentry() or closedir() is called. This may raise
+ OSError, or return a NULL pointer when exhausted. Note
+ that this doesn't filter out the "." and ".." entries.
+ """
+ direntp = rposix.c_readdir(dirp)
+ if direntp:
+ error = rposix.get_saved_errno()
+ if error:
+ raise OSError(error, "readdir failed")
+ return direntp
-def has_name_bytes(direntp):
- return True
+ def get_name_bytes(direntp):
+ namep = rffi.cast(rffi.CCHARP, direntp.c_d_name)
+ return rffi.charp2str(namep)
-def get_name_bytes(direntp):
- namep = rffi.cast(rffi.CCHARP, direntp.c_d_name)
- return rffi.charp2str(namep)
+ DT_UNKNOWN = rposix.dirent_config.get('DT_UNKNOWN', 0)
+ DT_REG = rposix.dirent_config.get('DT_REG', 255)
+ DT_DIR = rposix.dirent_config.get('DT_DIR', 255)
+ DT_LNK = rposix.dirent_config.get('DT_LNK', 255)
-DT_UNKNOWN = rposix.dirent_config.get('DT_UNKNOWN', 0)
-DT_REG = rposix.dirent_config.get('DT_REG', 255)
-DT_DIR = rposix.dirent_config.get('DT_DIR', 255)
-DT_LNK = rposix.dirent_config.get('DT_LNK', 255)
+ def get_known_type(direntp):
+ if rposix.HAVE_D_TYPE:
+ return rffi.getintfield(direntp, 'c_d_type')
+ return DT_UNKNOWN
-def get_known_type(direntp):
- if rposix.HAVE_D_TYPE:
- return rffi.getintfield(direntp, 'c_d_type')
- return DT_UNKNOWN
+ def get_inode(direntp):
+ return rffi.getintfield(direntp, 'c_d_ino')
-def get_inode(direntp):
- return rffi.getintfield(direntp, 'c_d_ino')
+else:
+ # ----- Win32 version -----
+ import stat
+ from rpython.rlib._os_support import unicode_traits
+ from rpython.rlib.rwin32file import make_win32_traits
+ from rpython.rlib import rposix_stat
+
+ win32traits = make_win32_traits(unicode_traits)
+
+
+ SCANDIRP = lltype.Ptr(lltype.Struct('SCANDIRP',
+ ('filedata', win32traits.WIN32_FIND_DATA),
+ ('hFindFile', rwin32.HANDLE),
+ ('first_time', lltype.Bool),
+ ))
+ NULL_DIRP = lltype.nullptr(SCANDIRP.TO)
+
+
+ # must only be called with unicode!
+ def opendir(path):
+ if len(path) == 0:
+ path = u'.'
+ if path[-1] not in (u'\\', u'/', u':'):
+ mask = path + u'\\*.*'
+ else:
+ mask = path + u'*.*'
+ dirp = lltype.malloc(SCANDIRP.TO, flavor='raw')
+ hFindFile = win32traits.FindFirstFile(mask, dirp.filedata)
+ if hFindFile == rwin32.INVALID_HANDLE_VALUE:
+ error = rwin32.GetLastError_saved()
+ lltype.free(dirp, flavor='raw')
+ raise WindowsError(error, "FindFirstFileW failed")
+ dirp.hFindFile = hFindFile
+ dirp.first_time = True
+ return dirp
+
+ def closedir(dirp):
+ if dirp.hFindFile != rwin32.INVALID_HANDLE_VALUE:
+ win32traits.FindClose(dirp.hFindFile)
+ lltype.free(dirp, flavor='raw')
+
+ def nextentry(dirp):
+ """Read the next entry and returns an opaque object.
+ Use the methods has_xxx() and get_xxx() to read from that
+ opaque object. The opaque object is valid until the next
+ time nextentry() or closedir() is called. This may raise
+ WindowsError, or return NULL when exhausted. Note
+ that this doesn't filter out the "." and ".." entries.
+ """
+ if dirp.first_time:
+ dirp.first_time = False
+ else:
+ if not win32traits.FindNextFile(dirp.hFindFile, dirp.filedata):
+ # error or no more files
+ error = rwin32.GetLastError_saved()
+ if error == win32traits.ERROR_NO_MORE_FILES:
+ return lltype.nullptr(win32traits.WIN32_FIND_DATA)
+ raise WindowsError(error, "FindNextFileW failed")
+ return dirp.filedata
+
+ def get_name_unicode(filedata):
+ return unicode_traits.charp2str(rffi.cast(unicode_traits.CCHARP,
+ filedata.c_cFileName))
+
+ def get_known_type(filedata):
+ attr = filedata.c_dwFileAttributes
+ st_mode = rposix_stat.win32_attributes_to_mode(win32traits, attr)
+ return stat.S_IFMT(st_mode)
+
+ def get_inode(filedata):
+ return None
diff --git a/rpython/rlib/rtime.py b/rpython/rlib/rtime.py
--- a/rpython/rlib/rtime.py
+++ b/rpython/rlib/rtime.py
@@ -165,7 +165,7 @@
'QueryPerformanceCounter', [rffi.CArrayPtr(lltype.SignedLongLong)],
lltype.Void, releasegil=False)
QueryPerformanceFrequency = external(
- 'QueryPerformanceFrequency', [rffi.CArrayPtr(lltype.SignedLongLong)],
+ 'QueryPerformanceFrequency', [rffi.CArrayPtr(lltype.SignedLongLong)],
rffi.INT, releasegil=False)
class State(object):
divisor = 0.0
@@ -267,9 +267,10 @@
else:
void = lltype.nullptr(rffi.VOIDP.TO)
with lltype.scoped_alloc(TIMEVAL) as t:
- frac = math.fmod(secs, 1.0)
+ frac = int(math.fmod(secs, 1.0) * 1000000.)
+ assert frac >= 0
rffi.setintfield(t, 'c_tv_sec', int(secs))
- rffi.setintfield(t, 'c_tv_usec', int(frac*1000000.0))
+ rffi.setintfield(t, 'c_tv_usec', frac)
if rffi.cast(rffi.LONG, c_select(0, void, void, void, t)) != 0:
errno = rposix.get_saved_errno()
diff --git a/rpython/rlib/rwin32file.py b/rpython/rlib/rwin32file.py
--- a/rpython/rlib/rwin32file.py
+++ b/rpython/rlib/rwin32file.py
@@ -148,7 +148,7 @@
save_err=rffi.RFFI_SAVE_LASTERROR)
FindClose = external('FindClose',
[rwin32.HANDLE],
- rwin32.BOOL)
+ rwin32.BOOL, releasegil=False)
GetFileAttributes = external(
'GetFileAttributes' + suffix,
diff --git a/rpython/rlib/rwinreg.py b/rpython/rlib/rwinreg.py
--- a/rpython/rlib/rwinreg.py
+++ b/rpython/rlib/rwinreg.py
@@ -47,7 +47,7 @@
HKEY = rwin32.HANDLE
PHKEY = rffi.CArrayPtr(HKEY)
REGSAM = rwin32.DWORD
-suffix = 'A'
+suffix = 'W'
RegSetValue = external(
'RegSetValue' + suffix,
diff --git a/rpython/rlib/test/test_rposix.py b/rpython/rlib/test/test_rposix.py
--- a/rpython/rlib/test/test_rposix.py
+++ b/rpython/rlib/test/test_rposix.py
@@ -1,3 +1,6 @@
+from hypothesis import given, strategies as st, assume
+import pytest
+
from rpython.rtyper.test.test_llinterp import interpret
from rpython.translator.c.test.test_genc import compile
from rpython.tool.pytest.expecttest import ExpectTest
@@ -8,10 +11,10 @@
import py
def rposix_requires(funcname):
- return py.test.mark.skipif(not hasattr(rposix, funcname),
+ return pytest.mark.skipif(not hasattr(rposix, funcname),
reason="Requires rposix.%s()" % funcname)
-win_only = py.test.mark.skipif("os.name != 'nt'")
+win_only = pytest.mark.skipif("os.name != 'nt'")
class TestPosixFunction:
def test_access(self):
@@ -827,3 +830,61 @@
rposix.lockf(fd, rposix.F_ULOCK, 4)
finally:
os.close(fd)
+
+def check_working_xattr():
+ fname = str(udir.join('xattr_test0.txt'))
+ with open(fname, 'wb'):
+ pass
+ try:
+ rposix.setxattr(fname, 'user.foo', '')
+ except OSError:
+ return False
+ else:
+ return True
+
[email protected](not (hasattr(rposix, 'getxattr') and
check_working_xattr()),
+ reason="Requires working rposix.getxattr()")
+@given(
+ name=st.text(
+ alphabet=st.characters(min_codepoint=1), min_size=1, max_size=10),
+ value=st.binary(max_size=10),
+ follow_symlinks=st.booleans(), use_fd=st.booleans())
+def test_xattr(name, value, follow_symlinks, use_fd):
+ assume(follow_symlinks or not use_fd)
+ name = 'user.' + name.encode('utf-8')
+ fname = str(udir.join('xattr_test.txt'))
+ try:
+ os.unlink(fname)
+ except OSError:
+ pass
+ with open(fname, 'wb'):
+ pass
+ if use_fd:
+ file_id = os.open(fname, os.O_CREAT, 0777)
+ read, write, delete = rposix.fgetxattr, rposix.fsetxattr,
rposix.fremovexattr
+ all_names = rposix.flistxattr
+ else:
+ file_id = fname
+ if follow_symlinks:
+ read, write, delete = rposix.getxattr, rposix.setxattr,
rposix.removexattr
+ all_names = rposix.listxattr
+ else:
+ read = lambda *args, **kwargs: rposix.getxattr(*args,
follow_symlinks=False, **kwargs)
+ write = lambda *args, **kwargs: rposix.setxattr(*args,
follow_symlinks=False, **kwargs)
+ delete = lambda *args, **kwargs: rposix.removexattr(*args,
follow_symlinks=False, **kwargs)
+ all_names = lambda *args, **kwargs: rposix.listxattr(*args,
follow_symlinks=False, **kwargs)
+ try:
+ init_names = all_names(file_id)
+ with pytest.raises(OSError):
+ read(file_id, name)
+ write(file_id, name, value)
+ assert read(file_id, name) == value
+ assert set(all_names(file_id)) == set(init_names + [name])
+ assert '' not in all_names(file_id)
+ delete(file_id, name)
+ with pytest.raises(OSError):
+ read(file_id, name)
+ assert set(all_names(file_id)) == set(init_names)
+ finally:
+ if use_fd:
+ os.close(file_id)
_______________________________________________
pypy-commit mailing list
[email protected]
https://mail.python.org/mailman/listinfo/pypy-commit