diff --git a/attic/platform_darwin.pyx b/attic/platform_darwin.pyx index c63bb1ff2..a0ea7b929 100644 --- a/attic/platform_darwin.pyx +++ b/attic/platform_darwin.pyx @@ -1,4 +1,6 @@ import os +from attic.helpers import user2uid, group2gid + API_VERSION = 1 cdef extern from "sys/acl.h": @@ -14,6 +16,38 @@ cdef extern from "sys/acl.h": int ACL_TYPE_EXTENDED +def _remove_numeric_id_if_possible(acl): + """Replace the user/group field with the local uid/gid if possible + """ + entries = [] + for entry in acl.decode('ascii').split('\n'): + if entry: + fields = entry.split(':') + if fields[0] == 'user': + if user2uid(fields[2]) is not None: + fields[1] = fields[3] = '' + elif fields[0] == 'group': + if group2gid(fields[2]) is not None: + fields[1] = fields[3] = '' + entries.append(':'.join(fields)) + return ('\n'.join(entries)).encode('ascii') + + +def _remove_non_numeric_identifier(acl): + """Remove user and group names from the acl + """ + entries = [] + for entry in acl.split(b'\n'): + if entry: + fields = entry.split(b':') + if fields[0] in (b'user', b'group'): + fields[2] = b'' + entries.append(b':'.join(fields)) + else: + entries.append(entry) + return b'\n'.join(entries) + + def acl_get(path, item, numeric_owner=False): cdef acl_t acl = NULL cdef char *text = NULL @@ -24,7 +58,10 @@ def acl_get(path, item, numeric_owner=False): text = acl_to_text(acl, NULL) if text == NULL: return - item[b'acl_extended'] = text + if numeric_owner: + item[b'acl_extended'] = _remove_non_numeric_identifier(text) + else: + item[b'acl_extended'] = text finally: acl_free(text) acl_free(acl) @@ -34,7 +71,10 @@ def acl_set(path, item, numeric_owner=False): cdef acl_t acl = NULL try: try: - acl = acl_from_text(item[b'acl_extended']) + if numeric_owner: + acl = acl_from_text(item[b'acl_extended']) + else: + acl = acl_from_text(_remove_numeric_id_if_possible(item[b'acl_extended'])) except KeyError: return if acl == NULL: diff --git a/attic/testsuite/platform.py b/attic/testsuite/platform.py index 7521b2077..f7bf2afd6 100644 --- a/attic/testsuite/platform.py +++ b/attic/testsuite/platform.py @@ -93,8 +93,12 @@ class PlatformDarwinTestCase(AtticTestCase): def test_access_acl(self): file = tempfile.NamedTemporaryFile() + file2 = tempfile.NamedTemporaryFile() self.assert_equal(self.get_acl(file.name), {}) - self.set_acl(file.name, b'!#acl 1\ngroup:ABCDEFAB-CDEF-ABCD-EFAB-CDEF00000014:staff:9999:allow:read\nuser:FFFFEEEE-DDDD-CCCC-BBBB-AAAA00000000:root:0:allow:read\n', numeric_owner=False) + self.set_acl(file.name, b'!#acl 1\ngroup:ABCDEFAB-CDEF-ABCD-EFAB-CDEF00000000:staff:0:allow:read\nuser:FFFFEEEE-DDDD-CCCC-BBBB-AAAA00000000:root:0:allow:read\n', numeric_owner=False) self.assert_in(b'group:ABCDEFAB-CDEF-ABCD-EFAB-CDEF00000014:staff:20:allow:read', self.get_acl(file.name)[b'acl_extended']) self.assert_in(b'user:FFFFEEEE-DDDD-CCCC-BBBB-AAAA00000000:root:0:allow:read', self.get_acl(file.name)[b'acl_extended']) + self.set_acl(file2.name, b'!#acl 1\ngroup:ABCDEFAB-CDEF-ABCD-EFAB-CDEF00000000:staff:0:allow:read\nuser:FFFFEEEE-DDDD-CCCC-BBBB-AAAA00000000:root:0:allow:read\n', numeric_owner=True) + self.assert_in(b'group:ABCDEFAB-CDEF-ABCD-EFAB-CDEF00000000:wheel:0:allow:read', self.get_acl(file2.name)[b'acl_extended']) + self.assert_in(b'group:ABCDEFAB-CDEF-ABCD-EFAB-CDEF00000000::0:allow:read', self.get_acl(file2.name, numeric_owner=True)[b'acl_extended'])