acls: use fd instead of path

This commit is contained in:
Thomas Waldmann 2018-07-06 01:33:32 +02:00
parent 5bf5f12be1
commit 7e47e68e29
4 changed files with 63 additions and 28 deletions

View file

@ -719,7 +719,7 @@ Utilization of max. archive size: {csize_max:.0%}
except OSError:
# some systems don't support calling utime on a symlink
pass
acl_set(path, item, self.numeric_owner)
acl_set(path, item, self.numeric_owner, fd=fd)
# chown removes Linux capabilities, so set the extended attributes at the end, after chown, since they include
# the Linux capabilities in the "security.capability" attribute.
warning = xattr.set_all(fd or path, item.get('xattrs', {}), follow_symlinks=False)
@ -954,7 +954,7 @@ class MetadataCollector:
xattrs = xattr.get_all(fd or path, follow_symlinks=False)
if not self.nobsdflags:
bsdflags = get_flags(path, st)
acl_get(path, attrs, st, self.numeric_owner)
acl_get(path, attrs, st, self.numeric_owner, fd=fd)
if xattrs:
attrs['xattrs'] = StableDict(xattrs)
if bsdflags:

View file

@ -29,7 +29,9 @@ cdef extern from "sys/acl.h":
int acl_free(void *obj)
acl_t acl_get_link_np(const char *path, int type)
acl_t acl_get_fd_np(int fd, int type)
int acl_set_link_np(const char *path, int type, acl_t acl)
int acl_set_fd_np(int fd, acl_t acl, int type)
acl_t acl_from_text(const char *buf)
char *acl_to_text(acl_t acl, ssize_t *len_p)
int ACL_TYPE_EXTENDED
@ -108,13 +110,16 @@ def _remove_non_numeric_identifier(acl):
return safe_encode('\n'.join(entries))
def acl_get(path, item, st, numeric_owner=False):
def acl_get(path, item, st, numeric_owner=False, fd=None):
cdef acl_t acl = NULL
cdef char *text = NULL
if isinstance(path, str):
path = os.fsencode(path)
try:
acl = acl_get_link_np(path, ACL_TYPE_EXTENDED)
if fd is not None:
acl = acl_get_fd_np(fd, ACL_TYPE_EXTENDED)
else:
acl = acl_get_link_np(path, ACL_TYPE_EXTENDED)
if acl == NULL:
return
text = acl_to_text(acl, NULL)
@ -129,7 +134,7 @@ def acl_get(path, item, st, numeric_owner=False):
acl_free(acl)
def acl_set(path, item, numeric_owner=False):
def acl_set(path, item, numeric_owner=False, fd=None):
cdef acl_t acl = NULL
acl_text = item.get('acl_extended')
if acl_text is not None:
@ -142,7 +147,9 @@ def acl_set(path, item, numeric_owner=False):
return
if isinstance(path, str):
path = os.fsencode(path)
if acl_set_link_np(path, ACL_TYPE_EXTENDED, acl):
return
if fd is not None:
acl_set_fd_np(fd, acl, ACL_TYPE_EXTENDED)
else:
acl_set_link_np(path, ACL_TYPE_EXTENDED, acl)
finally:
acl_free(acl)

View file

@ -37,7 +37,9 @@ cdef extern from "sys/acl.h":
int acl_free(void *obj)
acl_t acl_get_link_np(const char *path, int type)
acl_t acl_get_fd_np(int fd, int type)
int acl_set_link_np(const char *path, int type, acl_t acl)
int acl_set_fd_np(int fd, acl_t acl, int type)
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
@ -89,10 +91,13 @@ def setxattr(path, name, value, *, follow_symlinks=True):
_setxattr_inner(func, path, name, value)
cdef _get_acl(p, type, item, attribute, int flags):
cdef _get_acl(p, type, item, attribute, flags, fd=None):
cdef acl_t acl
cdef char *text
acl = acl_get_link_np(p, type)
if fd is not None:
acl = acl_get_fd_np(fd, type)
else:
acl = acl_get_link_np(p, type)
if acl:
text = acl_to_text_np(acl, NULL, flags)
if text:
@ -101,7 +106,7 @@ cdef _get_acl(p, type, item, attribute, int flags):
acl_free(acl)
def acl_get(path, item, st, numeric_owner=False):
def acl_get(path, item, st, numeric_owner=False, fd=None):
"""Saves ACL Entries
If `numeric_owner` is True the user/group field is not preserved only uid/gid
@ -114,13 +119,13 @@ def acl_get(path, item, st, numeric_owner=False):
return
flags |= ACL_TEXT_NUMERIC_IDS if numeric_owner else 0
if ret > 0:
_get_acl(path, ACL_TYPE_NFS4, item, 'acl_nfs4', flags)
_get_acl(path, ACL_TYPE_NFS4, item, 'acl_nfs4', flags, fd=fd)
else:
_get_acl(path, ACL_TYPE_ACCESS, item, 'acl_access', flags)
_get_acl(path, ACL_TYPE_DEFAULT, item, 'acl_default', flags)
_get_acl(path, ACL_TYPE_ACCESS, item, 'acl_access', flags, fd=fd)
_get_acl(path, ACL_TYPE_DEFAULT, item, 'acl_default', flags, fd=fd)
cdef _set_acl(p, type, item, attribute, numeric_owner=False):
cdef _set_acl(p, type, item, attribute, numeric_owner=False, fd=None):
cdef acl_t acl
text = item.get(attribute)
if text:
@ -130,7 +135,10 @@ cdef _set_acl(p, type, item, attribute, numeric_owner=False):
text = posix_acl_use_stored_uid_gid(text)
acl = acl_from_text(<bytes>text)
if acl:
acl_set_link_np(p, type, acl)
if fd is not None:
acl_set_fd_np(fd, acl, type)
else:
acl_set_link_np(p, type, acl)
acl_free(acl)
@ -148,7 +156,7 @@ cdef _nfs4_use_stored_uid_gid(acl):
return safe_encode('\n'.join(entries))
def acl_set(path, item, numeric_owner=False):
def acl_set(path, item, numeric_owner=False, fd=None):
"""Restore ACL Entries
If `numeric_owner` is True the stored uid/gid is used instead
@ -156,6 +164,6 @@ def acl_set(path, item, numeric_owner=False):
"""
if isinstance(path, str):
path = os.fsencode(path)
_set_acl(path, ACL_TYPE_NFS4, item, 'acl_nfs4', numeric_owner)
_set_acl(path, ACL_TYPE_ACCESS, item, 'acl_access', numeric_owner)
_set_acl(path, ACL_TYPE_DEFAULT, item, 'acl_default', numeric_owner)
_set_acl(path, ACL_TYPE_NFS4, item, 'acl_nfs4', numeric_owner, fd=fd)
_set_acl(path, ACL_TYPE_ACCESS, item, 'acl_access', numeric_owner, fd=fd)
_set_acl(path, ACL_TYPE_DEFAULT, item, 'acl_default', numeric_owner, fd=fd)

View file

@ -39,12 +39,15 @@ cdef extern from "sys/acl.h":
int acl_free(void *obj)
acl_t acl_get_file(const char *path, int type)
acl_t acl_get_fd(int fd)
int acl_set_file(const char *path, int type, acl_t acl)
int acl_set_fd(int fd, acl_t acl)
acl_t acl_from_text(const char *buf)
char *acl_to_text(acl_t acl, ssize_t *len)
cdef extern from "acl/libacl.h":
int acl_extended_file(const char *path)
int acl_extended_fd(int fd)
cdef extern from "fcntl.h":
int sync_file_range(int fd, int64_t offset, int64_t nbytes, unsigned int flags)
@ -221,27 +224,37 @@ cdef acl_numeric_ids(acl):
return safe_encode('\n'.join(entries))
def acl_get(path, item, st, numeric_owner=False):
def acl_get(path, item, st, numeric_owner=False, fd=None):
cdef acl_t default_acl = NULL
cdef acl_t access_acl = NULL
cdef char *default_text = NULL
cdef char *access_text = NULL
if isinstance(path, str):
if fd is None and isinstance(path, str):
path = os.fsencode(path)
if stat.S_ISLNK(st.st_mode) or acl_extended_file(path) <= 0:
if stat.S_ISLNK(st.st_mode):
return
if (fd is not None and acl_extended_fd(fd) <= 0
or
fd is None and acl_extended_file(path) <= 0):
return
if numeric_owner:
converter = acl_numeric_ids
else:
converter = acl_append_numeric_ids
try:
access_acl = acl_get_file(path, ACL_TYPE_ACCESS)
if fd is not None:
# we only have a fd for FILES (not other fs objects), so we can get the access_acl:
assert stat.S_ISREG(st.st_mode)
access_acl = acl_get_fd(fd)
else:
# if we have no fd, it can be anything
access_acl = acl_get_file(path, ACL_TYPE_ACCESS)
default_acl = acl_get_file(path, ACL_TYPE_DEFAULT)
if access_acl:
access_text = acl_to_text(access_acl, NULL)
if access_text:
item['acl_access'] = converter(access_text)
default_acl = acl_get_file(path, ACL_TYPE_DEFAULT)
if default_acl:
default_text = acl_to_text(default_acl, NULL)
if default_text:
@ -253,11 +266,11 @@ def acl_get(path, item, st, numeric_owner=False):
acl_free(access_acl)
def acl_set(path, item, numeric_owner=False):
def acl_set(path, item, numeric_owner=False, fd=None):
cdef acl_t access_acl = NULL
cdef acl_t default_acl = NULL
if isinstance(path, str):
if fd is None and isinstance(path, str):
path = os.fsencode(path)
if numeric_owner:
converter = posix_acl_use_stored_uid_gid
@ -268,7 +281,10 @@ def acl_set(path, item, numeric_owner=False):
try:
access_acl = acl_from_text(<bytes>converter(access_text))
if access_acl:
acl_set_file(path, ACL_TYPE_ACCESS, access_acl)
if fd is not None:
acl_set_fd(fd, access_acl)
else:
acl_set_file(path, ACL_TYPE_ACCESS, access_acl)
finally:
acl_free(access_acl)
default_text = item.get('acl_default')
@ -276,7 +292,11 @@ def acl_set(path, item, numeric_owner=False):
try:
default_acl = acl_from_text(<bytes>converter(default_text))
if default_acl:
acl_set_file(path, ACL_TYPE_DEFAULT, default_acl)
# default acls apply only to directories
if False and fd is not None: # Linux API seems to not support this
acl_set_fd(fd, default_acl)
else:
acl_set_file(path, ACL_TYPE_DEFAULT, default_acl)
finally:
acl_free(default_acl)