|
@@ -0,0 +1,100 @@
|
|
|
+import os
|
|
|
+from attic.helpers import posix_acl_use_stored_uid_gid
|
|
|
+
|
|
|
+API_VERSION = 1
|
|
|
+
|
|
|
+cdef extern from "errno.h":
|
|
|
+ int errno
|
|
|
+ int EINVAL
|
|
|
+
|
|
|
+cdef extern from "sys/types.h":
|
|
|
+ int ACL_TYPE_ACCESS
|
|
|
+ int ACL_TYPE_DEFAULT
|
|
|
+ int ACL_TYPE_NFS4
|
|
|
+
|
|
|
+cdef extern from "sys/acl.h":
|
|
|
+ ctypedef struct _acl_t:
|
|
|
+ pass
|
|
|
+ ctypedef _acl_t *acl_t
|
|
|
+
|
|
|
+ int acl_free(void *obj)
|
|
|
+ acl_t acl_get_link_np(const char *path, int type)
|
|
|
+ acl_t acl_set_link_np(const char *path, int type, acl_t acl)
|
|
|
+ acl_t acl_from_text(const char *buf)
|
|
|
+ char *acl_to_text_np(acl_t acl, ssize_t *len, int flags)
|
|
|
+ int ACL_TEXT_NUMERIC_IDS
|
|
|
+ int ACL_TEXT_APPEND_ID
|
|
|
+
|
|
|
+cdef extern from "unistd.h":
|
|
|
+ long lpathconf(const char *path, int name)
|
|
|
+ int _PC_ACL_NFS4
|
|
|
+
|
|
|
+
|
|
|
+cdef _get_acl(p, type, item, attribute, int flags):
|
|
|
+ cdef acl_t acl
|
|
|
+ cdef char *text
|
|
|
+ acl = acl_get_link_np(p, type)
|
|
|
+ if acl:
|
|
|
+ text = acl_to_text_np(acl, NULL, flags)
|
|
|
+ if text:
|
|
|
+ item[attribute] = text
|
|
|
+ acl_free(text)
|
|
|
+ acl_free(acl)
|
|
|
+
|
|
|
+
|
|
|
+def acl_get(path, item, numeric_owner=False):
|
|
|
+ """Saves ACL Entries
|
|
|
+
|
|
|
+ If `numeric_owner` is True the user/group field is not preserved only uid/gid
|
|
|
+ """
|
|
|
+ cdef int flags = ACL_TEXT_APPEND_ID
|
|
|
+ p = os.fsencode(path)
|
|
|
+ ret = lpathconf(p, _PC_ACL_NFS4)
|
|
|
+ if ret < 0 and errno == EINVAL:
|
|
|
+ return
|
|
|
+ flags |= ACL_TEXT_NUMERIC_IDS if numeric_owner else 0
|
|
|
+ if ret > 0:
|
|
|
+ _get_acl(p, ACL_TYPE_NFS4, item, b'acl_nfs4', flags)
|
|
|
+ else:
|
|
|
+ _get_acl(p, ACL_TYPE_ACCESS, item, b'acl_access', flags)
|
|
|
+ _get_acl(p, ACL_TYPE_DEFAULT, item, b'acl_default', flags)
|
|
|
+
|
|
|
+
|
|
|
+cdef _set_acl(p, type, item, attribute, numeric_owner=False):
|
|
|
+ cdef acl_t acl
|
|
|
+ text = item.get(attribute)
|
|
|
+ if text:
|
|
|
+ if numeric_owner and type == ACL_TYPE_NFS4:
|
|
|
+ text = _nfs4_use_stored_uid_gid(text)
|
|
|
+ elif numeric_owner and type in(ACL_TYPE_ACCESS, ACL_TYPE_DEFAULT):
|
|
|
+ text = posix_acl_use_stored_uid_gid(text)
|
|
|
+ acl = acl_from_text(<bytes>text)
|
|
|
+ if acl:
|
|
|
+ acl_set_link_np(p, type, acl)
|
|
|
+ acl_free(acl)
|
|
|
+
|
|
|
+
|
|
|
+cdef _nfs4_use_stored_uid_gid(acl):
|
|
|
+ """Replace the user/group field with the stored uid/gid
|
|
|
+ """
|
|
|
+ entries = []
|
|
|
+ for entry in acl.decode('ascii').split('\n'):
|
|
|
+ if entry:
|
|
|
+ if entry.startswith('user:') or entry.startswith('group:'):
|
|
|
+ fields = entry.split(':')
|
|
|
+ entries.append(':'.join(fields[0], fields[5], *fields[2:-1]))
|
|
|
+ else:
|
|
|
+ entries.append(entry)
|
|
|
+ return ('\n'.join(entries)).encode('ascii')
|
|
|
+
|
|
|
+
|
|
|
+def acl_set(path, item, numeric_owner=False):
|
|
|
+ """Restore ACL Entries
|
|
|
+
|
|
|
+ If `numeric_owner` is True the stored uid/gid is used instead
|
|
|
+ of the user/group names
|
|
|
+ """
|
|
|
+ p = os.fsencode(path)
|
|
|
+ _set_acl(p, ACL_TYPE_NFS4, item, b'acl_nfs4', numeric_owner)
|
|
|
+ _set_acl(p, ACL_TYPE_ACCESS, item, b'acl_access', numeric_owner)
|
|
|
+ _set_acl(p, ACL_TYPE_DEFAULT, item, b'acl_default', numeric_owner)
|