From ed828cd66920ecb1d2d28ce5e6a710940e987a1f Mon Sep 17 00:00:00 2001
From: Iustin Pop <iustin@k1024.org>
Date: Fri, 29 Nov 2019 14:35:11 +0100
Subject: [PATCH] Restore setstate/getstate support

Sigh, another brown-bag issue. One small typo in a place, plus a
missing macro, and this went unseen for ages.

Also add a basic test for it. Probably should add Pickle as well.
---
 NEWS               |  4 ++++
 acl.c              | 14 +++++++++++++-
 setup.py           |  1 +
 tests/test_acls.py | 13 +++++++++++++
 4 files changed, 31 insertions(+), 1 deletion(-)

diff --git a/NEWS b/NEWS
index 005a68d..0105cdc 100644
--- a/NEWS
+++ b/NEWS
@@ -23,6 +23,10 @@ Important API changes/bug fixes:
   paths; this also (implicitly) fixes memory leaks on re-initialisation
   (calling `__init__(…)` on an existing object) and segfaults (!) on
   non-initialised object attribute access.
+- Restore `__setstate__`/`__getstate__` support on Linux; this was
+  inadvertently removed due a typo(!) when adding support for it in
+  FreeBSD. Pickle should work again for ACL instances, although not sure
+  how stable this serialisation format actually is.
 
 Minor improvements:
 
diff --git a/acl.c b/acl.c
index 16004b5..3d0c0f6 100644
--- a/acl.c
+++ b/acl.c
@@ -1256,7 +1256,7 @@ static PyMethodDef ACL_methods[] = {
     {"check", ACL_check, METH_NOARGS, __check_doc__},
     {"equiv_mode", ACL_equiv_mode, METH_NOARGS, __equiv_mode_doc__},
 #endif
-#ifdef HAVE_ACL_COPYEXT
+#ifdef HAVE_ACL_COPY_EXT
     {"__getstate__", ACL_get_state, METH_NOARGS,
      "Dumps the ACL to an external format."},
     {"__setstate__", ACL_set_state, METH_VARARGS,
@@ -1653,6 +1653,8 @@ static char __posix1e_doc__[] =
     "  - :py:data:`HAS_EXTENDED_CHECK` for the module-level\n"
     "    :py:func:`has_extended` function\n"
     "  - :py:data:`HAS_EQUIV_MODE` for the :py:func:`ACL.equiv_mode` method\n"
+    "  - :py:data:`HAS_COPY_EXT` for the :py:func:`ACL.__getstate__` and\n"
+    "    :py:func:`ACL.__setstate__` functions (pickle protocol)\n"
     "\n"
     "Example:\n"
     "\n"
@@ -1722,6 +1724,9 @@ static char __posix1e_doc__[] =
     ".. py:data:: HAS_EQUIV_MODE\n\n"
     "   denotes support for the equiv_mode function\n"
     "\n"
+    ".. py:data:: HAS_COPY_EXT\n\n"
+    "   denotes support for __getstate__()/__setstate__() on an ACL\n"
+    "\n"
     ;
 
 static struct PyModuleDef posix1emodule = {
@@ -1824,5 +1829,12 @@ PyInit_posix1e(void)
     PyModule_AddIntConstant(m, "HAS_EXTENDED_CHECK", LINUX_EXT_VAL);
     PyModule_AddIntConstant(m, "HAS_EQUIV_MODE", LINUX_EXT_VAL);
 
+    PyModule_AddIntConstant(m, "HAS_COPY_EXT",
+#ifdef HAVE_ACL_COPY_EXT
+                            1
+#else
+                            0
+#endif
+                            );
     return m;
 }
diff --git a/setup.py b/setup.py
index 5b258e8..8c3aa63 100755
--- a/setup.py
+++ b/setup.py
@@ -10,6 +10,7 @@ libs = []
 if u_sysname == "Linux":
     macros.append(("HAVE_LINUX", None))
     macros.append(("HAVE_LEVEL2", None))
+    macros.append(("HAVE_ACL_COPY_EXT", None))
     libs.append("acl")
 elif u_sysname == "GNU/kFreeBSD":
     macros.append(("HAVE_LINUX", None))
diff --git a/tests/test_acls.py b/tests/test_acls.py
index b827b8d..c3e693f 100644
--- a/tests/test_acls.py
+++ b/tests/test_acls.py
@@ -169,6 +169,7 @@ require_acl_check = pytest.mark.skipif("not HAS_ACL_CHECK")
 require_acl_entry = pytest.mark.skipif("not HAS_ACL_ENTRY")
 require_extended_check = pytest.mark.skipif("not HAS_EXTENDED_CHECK")
 require_equiv_mode = pytest.mark.skipif("not HAS_EQUIV_MODE")
+require_copy_ext = pytest.mark.skipif("not HAS_COPY_EXT")
 
 # Note: ACLs are valid only for files/directories, not symbolic links
 # themselves, so we only create valid symlinks.
@@ -435,6 +436,18 @@ class TestAclExtensions:
         for entry in acl:
             assert entry.parent is acl
 
+    @require_copy_ext
+    def test_acl_copy_ext(self):
+        a = posix1e.ACL(text=BASIC_ACL_TEXT)
+        b = posix1e.ACL()
+        c = posix1e.ACL(acl=b)
+        assert a != b
+        assert b == c
+        state = a.__getstate__()
+        b.__setstate__(state)
+        assert a == b
+        assert b != c
+
 
 class TestWrite:
     """Write tests"""
-- 
2.39.5