[pypy-commit] pypy py3.5-xattr: wip
rlamy
pypy.commits at gmail.com
Tue Dec 19 10:13:33 EST 2017
Author: Ronan Lamy <ronan.lamy at gmail.com>
Branch: py3.5-xattr
Changeset: r93491:61730fb1f196
Date: 2017-12-19 15:11 +0000
http://bitbucket.org/pypy/pypy/changeset/61730fb1f196/
Log: wip
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
@@ -122,7 +122,7 @@
else:
path_b = path.as_bytes
assert path_b is not None
- return func(path.as_bytes, *args)
+ return func(path_b, *args)
class Path(object):
@@ -2283,7 +2283,9 @@
This function will not follow symbolic links.
Equivalent to chflags(path, flags, follow_symlinks=False)."""
-def getxattr():
+ at unwrap_spec(path=path_or_fd(), attribute=path_or_fd(allow_fd=False),
+ follow_symlinks=bool)
+def getxattr(space, path, attribute, __kwonly__, follow_symlinks=True):
"""getxattr(path, attribute, *, follow_symlinks=True) -> value
Return the value of extended attribute attribute on path.
@@ -2292,8 +2294,29 @@
If follow_symlinks is False, and the last element of the path is a symbolic
link, getxattr will examine the symbolic link itself instead of the file
the link points to."""
+ if path.as_fd != -1:
+ if not follow_symlinks:
+ raise oefmt(space.w_ValueError,
+ "getxattr: cannot use fd and follow_symlinks together")
+ try:
+ result = rposix.fgetxattr(path.as_fd, attribute.as_bytes)
+ except OSError as e:
+ raise wrap_oserror(space, e, eintr_retry=False)
+ else:
+ try:
+ if follow_symlinks:
+ result = rposix.getxattr(path.as_bytes, attribute.as_bytes)
+ else:
+ result = rposix.lgetxattr(path.as_bytes, attribute.as_bytes)
+ except OSError as e:
+ raise wrap_oserror(space, e, eintr_retry=False)
+ return space.newbytes(result)
-def setxattr():
+ at unwrap_spec(path=path_or_fd(), attribute=path_or_fd(allow_fd=False),
+ flags=c_int,
+ follow_symlinks=bool)
+def setxattr(space, path, attribute, w_value, flags=0,
+ __kwonly__=None, follow_symlinks=True):
"""setxattr(path, attribute, value, flags=0, *, follow_symlinks=True)
Set extended attribute attribute on path to value.
@@ -2301,9 +2324,28 @@
If follow_symlinks is False, and the last element of the path is a symbolic
link, setxattr will modify the symbolic link itself instead of the file
the link points to."""
+ value = space.charbuf_w(w_value)
+ if path.as_fd != -1:
+ if not follow_symlinks:
+ raise oefmt(space.w_ValueError,
+ "setxattr: cannot use fd and follow_symlinks together")
+ try:
+ rposix.fsetxattr(path.as_fd, attribute.as_bytes, value)
+ except OSError as e:
+ raise wrap_oserror(space, e, eintr_retry=False)
+ else:
+ try:
+ if follow_symlinks:
+ rposix.setxattr(path.as_bytes, attribute.as_bytes, value)
+ else:
+ rposix.lsetxattr(path.as_bytes, attribute.as_bytes, value)
+ except OSError as e:
+ raise wrap_oserror(space, e, eintr_retry=False)
-def removexattr():
+ at unwrap_spec(path=path_or_fd(), attribute=path_or_fd(allow_fd=False),
+ follow_symlinks=bool)
+def removexattr(space, path, attribute, __kwonly__, follow_symlinks=True):
"""removexattr(path, attribute, *, follow_symlinks=True)
Remove extended attribute attribute on path.
@@ -2311,8 +2353,27 @@
If follow_symlinks is False, and the last element of the path is a symbolic
link, removexattr will modify the symbolic link itself instead of the file
the link points to."""
+ if path.as_fd != -1:
+ if not follow_symlinks:
+ raise oefmt(space.w_ValueError,
+ "removexattr: cannot use fd and follow_symlinks together")
+ try:
+ rposix.fremovexattr(path.as_fd, attribute.as_bytes)
+ except OSError as e:
+ raise wrap_oserror(space, e, eintr_retry=False)
+ else:
+ try:
+ if follow_symlinks:
+ rposix.removexattr(path.as_bytes, attribute.as_bytes)
+ else:
+ rposix.lremovexattr(path.as_bytes, attribute.as_bytes)
+ except OSError as e:
+ raise wrap_oserror(space, e, eintr_retry=False)
-def listxattr():
+
+ at unwrap_spec(path=path_or_fd(), attribute=path_or_fd(allow_fd=False),
+ follow_symlinks=bool)
+def listxattr(space, path, __kwonly__, follow_symlinks=True):
"""listxattr(path='.', *, follow_symlinks=True)
Return a list of extended attributes on path.
@@ -2322,6 +2383,23 @@
If follow_symlinks is False, and the last element of the path is a symbolic
link, listxattr will examine the symbolic link itself instead of the file
the link points to."""
+ if path.as_fd != -1:
+ if not follow_symlinks:
+ raise oefmt(space.w_ValueError,
+ "listxattr: cannot use fd and follow_symlinks together")
+ try:
+ result = rposix.flistxattr(path.as_fd, attribute.as_bytes)
+ except OSError as e:
+ raise wrap_oserror(space, e, eintr_retry=False)
+ else:
+ try:
+ if follow_symlinks:
+ result = rposix.listxattr(path.as_bytes, attribute.as_bytes)
+ else:
+ result = rposix.llistxattr(path.as_bytes, attribute.as_bytes)
+ except OSError as e:
+ raise wrap_oserror(space, e, eintr_retry=False)
+ return xxx
have_functions = []
@@ -2449,8 +2527,8 @@
@unwrap_spec(policy=int)
def sched_get_priority_max(space, policy):
- """returns the maximum priority value that
- can be used with the scheduling algorithm
+ """returns the maximum priority value that
+ can be used with the scheduling algorithm
identified by policy
"""
while True:
@@ -2464,7 +2542,7 @@
@unwrap_spec(policy=int)
def sched_get_priority_min(space, policy):
"""returns the minimum priority value that
- can be used with the scheduling algorithm
+ can be used with the scheduling algorithm
identified by policy
"""
while True:
@@ -2477,7 +2555,7 @@
@unwrap_spec(fd=c_int, cmd=c_int, length=r_longlong)
def lockf(space, fd, cmd, length):
- """apply, test or remove a POSIX lock on an
+ """apply, test or remove a POSIX lock on an
open file.
"""
while True:
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,112 @@
"""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.SSIZE_T,
+ 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.SSIZE_T,
+ 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.SSIZE_T,
+ compilation_info=CConfig._compilation_info_,
+ save_err=rffi.RFFI_SAVE_ERRNO)
+ c_fremovexattr = external('fremovexattr',
+ [rffi.INT, rffi.CCHARP], rffi.SSIZE_T,
+ compilation_info=CConfig._compilation_info_,
+ save_err=rffi.RFFI_SAVE_ERRNO)
+ c_removexattr = external('removexattr',
+ [rffi.CCHARP, rffi.CCHARP], rffi.SSIZE_T,
+ compilation_info=CConfig._compilation_info_,
+ save_err=rffi.RFFI_SAVE_ERRNO)
+ c_lremovexattr = external('lremovexattr',
+ [rffi.CCHARP, rffi.CCHARP], 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))
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,47 @@
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.getxattr(fname, 'foo')
+ except OSError as e:
+ return e.errno != errno.ENOTSUP
+ else:
+ raise RuntimeError('getxattr() succeeded unexpectedly!?!')
+
+ at pytest.mark.skipif(not (hasattr(rposix, 'getxattr') and check_working_xattr()),
+ reason="Requires working rposix.getxattr()")
+ at given(name=st.binary(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):
+ use_fd = False
+ assume(follow_symlinks or not use_fd)
+ fname = str(udir.join('xattr_test.txt'))
+ 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
+ else:
+ file_id = fname
+ if follow_symlinks:
+ read, write, delete = rposix.getxattr, rposix.setxattr, rposix.removexattr
+ 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)
+ try:
+ with pytest.raises(OSError):
+ read(file_id, name)
+ write(file_id, name, value)
+ assert read(file_id, name) == value
+ delete(file_id, name)
+ with pytest.raises(OSError):
+ read(file_id, name)
+ finally:
+ if use_fd:
+ os.close(file_id)
More information about the pypy-commit
mailing list