From f6ba9364c2e7c8adc05e08ec305249e5031b8fbe Mon Sep 17 00:00:00 2001 From: Iustin Pop Date: Wed, 11 Dec 2019 20:50:55 +0100 Subject: [PATCH] Implement creating an ACL directly from serialised form --- NEWS | 4 ++++ acl.c | 21 +++++++++++++++++++++ tests/test_acls.py | 13 +++++++++++++ 3 files changed, 38 insertions(+) diff --git a/NEWS b/NEWS index 94e5183..a6a0df1 100644 --- a/NEWS +++ b/NEWS @@ -40,6 +40,10 @@ Important API changes/bug fixes: Minor improvements: +- Added a `data` keyword argument to `ACL()`, which allows restoring an + ACL directly from a serialised form (as given by `__getstate__()`), + which should simplify some uses cases (`a = ACL(); a.__set + state__(…)`). - When available, add the file path to I/O error messages, which should lead to easier debugging. - The test suite has changed to `pytest`, which allows increased diff --git a/acl.c b/acl.c index 2bd05d8..99f3e9a 100644 --- a/acl.c +++ b/acl.c @@ -133,11 +133,17 @@ static int ACL_init(PyObject* obj, PyObject* args, PyObject *keywds) { static char *kwlist[] = { "file", "fd", "text", "acl", "filedef", #ifdef HAVE_LINUX "mode", +#endif +#ifdef HAVE_ACL_COPY_EXT + "data", #endif NULL }; char *format = "|O&OsO!O&" #ifdef HAVE_LINUX "i" +#endif +#ifdef HAVE_ACL_COPY_EXT + "y#" #endif ; int mode = -1; @@ -146,6 +152,8 @@ static int ACL_init(PyObject* obj, PyObject* args, PyObject *keywds) { char *text = NULL; PyObject *fd = NULL; ACL_Object* thesrc = NULL; + const void *buf = NULL; + Py_ssize_t bufsize; if(!PyTuple_Check(args) || PyTuple_Size(args) != 0 || (keywds != NULL && PyDict_Check(keywds) && PyDict_Size(keywds) > 1)) { @@ -159,6 +167,9 @@ static int ACL_init(PyObject* obj, PyObject* args, PyObject *keywds) { PyUnicode_FSConverter, &filedef #ifdef HAVE_LINUX , &mode +#endif +#ifdef HAVE_ACL_COPY_EXT + , &buf, &bufsize #endif )) return -1; @@ -192,6 +203,14 @@ static int ACL_init(PyObject* obj, PyObject* args, PyObject *keywds) { #ifdef HAVE_LINUX else if(mode != -1) self->acl = acl_from_mode(mode); +#endif +#ifdef HAVE_ACL_COPY_EXT + else if(buf != NULL) { + if((self->acl = acl_copy_int(buf)) == NULL) { + PyErr_SetFromErrno(PyExc_IOError); + return -1; + } + } #endif else self->acl = acl_init(0); @@ -1259,6 +1278,8 @@ static char __ACL_Type_doc__[] = " (e.g. ``mode=0644``); this is valid only when the C library\n" " provides the ``acl_from_mode call``, and\n" " note that no validation is done on the given value.\n" + ":param bytes data: creates an ACL from a serialised form,\n" + " as provided by calling ``__getstate__()`` on an existing ACL\n" "\n" "If no parameters are passed, an empty ACL will be created; this\n" "makes sense only when your OS supports ACL modification\n" diff --git a/tests/test_acls.py b/tests/test_acls.py index 8de6aa2..28f55c9 100644 --- a/tests/test_acls.py +++ b/tests/test_acls.py @@ -492,6 +492,19 @@ class TestAclExtensions: with pytest.raises(TypeError): a.__setstate__(None) + @require_copy_ext + def test_acl_init_copy_ext(self): + a = posix1e.ACL(text=BASIC_ACL_TEXT) + b = posix1e.ACL() + c = posix1e.ACL(data=a.__getstate__()) + assert c != b + assert c == a + + @require_copy_ext + def test_acl_init_copy_ext_invalid(self): + with pytest.raises(IOError): + posix1e.ACL(data=b"foobar") + class TestWrite: """Write tests""" -- 2.39.5