1# cython: language_level=3 2 3import os 4 5from ..helpers import user2uid, group2gid 6from ..helpers import safe_decode, safe_encode 7from .posix import swidth 8 9API_VERSION = '1.1_04' 10 11cdef extern from "sys/acl.h": 12 ctypedef struct _acl_t: 13 pass 14 ctypedef _acl_t *acl_t 15 16 int acl_free(void *obj) 17 acl_t acl_get_link_np(const char *path, int type) 18 int acl_set_link_np(const char *path, int type, acl_t acl) 19 acl_t acl_from_text(const char *buf) 20 char *acl_to_text(acl_t acl, ssize_t *len_p) 21 int ACL_TYPE_EXTENDED 22 23 24def _remove_numeric_id_if_possible(acl): 25 """Replace the user/group field with the local uid/gid if possible 26 """ 27 entries = [] 28 for entry in safe_decode(acl).split('\n'): 29 if entry: 30 fields = entry.split(':') 31 if fields[0] == 'user': 32 if user2uid(fields[2]) is not None: 33 fields[1] = fields[3] = '' 34 elif fields[0] == 'group': 35 if group2gid(fields[2]) is not None: 36 fields[1] = fields[3] = '' 37 entries.append(':'.join(fields)) 38 return safe_encode('\n'.join(entries)) 39 40 41def _remove_non_numeric_identifier(acl): 42 """Remove user and group names from the acl 43 """ 44 entries = [] 45 for entry in safe_decode(acl).split('\n'): 46 if entry: 47 fields = entry.split(':') 48 if fields[0] in ('user', 'group'): 49 fields[2] = '' 50 entries.append(':'.join(fields)) 51 else: 52 entries.append(entry) 53 return safe_encode('\n'.join(entries)) 54 55 56def acl_get(path, item, st, numeric_owner=False): 57 cdef acl_t acl = NULL 58 cdef char *text = NULL 59 try: 60 acl = acl_get_link_np(<bytes>os.fsencode(path), ACL_TYPE_EXTENDED) 61 if acl == NULL: 62 return 63 text = acl_to_text(acl, NULL) 64 if text == NULL: 65 return 66 if numeric_owner: 67 item['acl_extended'] = _remove_non_numeric_identifier(text) 68 else: 69 item['acl_extended'] = text 70 finally: 71 acl_free(text) 72 acl_free(acl) 73 74 75def acl_set(path, item, numeric_owner=False): 76 cdef acl_t acl = NULL 77 acl_text = item.get('acl_extended') 78 if acl_text is not None: 79 try: 80 if numeric_owner: 81 acl = acl_from_text(acl_text) 82 else: 83 acl = acl_from_text(<bytes>_remove_numeric_id_if_possible(acl_text)) 84 if acl == NULL: 85 return 86 if acl_set_link_np(<bytes>os.fsencode(path), ACL_TYPE_EXTENDED, acl): 87 return 88 finally: 89 acl_free(acl) 90