mirror of https://github.com/borgbackup/borg.git
Merge pull request #3960 from ThomasWaldmann/acl-fd-based
ACLs fd-based
This commit is contained in:
commit
2dd22df751
|
@ -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:
|
||||
|
|
|
@ -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,11 +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(<bytes>os.fsencode(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)
|
||||
|
@ -127,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:
|
||||
|
@ -138,7 +145,11 @@ def acl_set(path, item, numeric_owner=False):
|
|||
acl = acl_from_text(<bytes>_remove_numeric_id_if_possible(acl_text))
|
||||
if acl == NULL:
|
||||
return
|
||||
if acl_set_link_np(<bytes>os.fsencode(path), ACL_TYPE_EXTENDED, acl):
|
||||
return
|
||||
if isinstance(path, str):
|
||||
path = os.fsencode(path)
|
||||
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)
|
||||
|
|
|
@ -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,25 +106,26 @@ 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
|
||||
"""
|
||||
cdef int flags = ACL_TEXT_APPEND_ID
|
||||
p = os.fsencode(path)
|
||||
ret = lpathconf(p, _PC_ACL_NFS4)
|
||||
if isinstance(path, str):
|
||||
path = os.fsencode(path)
|
||||
ret = lpathconf(path, _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, 'acl_nfs4', flags)
|
||||
_get_acl(path, ACL_TYPE_NFS4, item, 'acl_nfs4', flags, fd=fd)
|
||||
else:
|
||||
_get_acl(p, ACL_TYPE_ACCESS, item, 'acl_access', flags)
|
||||
_get_acl(p, 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:
|
||||
|
@ -129,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)
|
||||
|
||||
|
||||
|
@ -147,13 +156,14 @@ 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
|
||||
of the user/group names
|
||||
"""
|
||||
p = os.fsencode(path)
|
||||
_set_acl(p, ACL_TYPE_NFS4, item, 'acl_nfs4', numeric_owner)
|
||||
_set_acl(p, ACL_TYPE_ACCESS, item, 'acl_access', numeric_owner)
|
||||
_set_acl(p, ACL_TYPE_DEFAULT, item, 'acl_default', numeric_owner)
|
||||
if isinstance(path, str):
|
||||
path = os.fsencode(path)
|
||||
_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)
|
||||
|
|
|
@ -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,26 +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
|
||||
|
||||
p = <bytes>os.fsencode(path)
|
||||
if stat.S_ISLNK(st.st_mode) or acl_extended_file(p) <= 0:
|
||||
if fd is None and isinstance(path, str):
|
||||
path = os.fsencode(path)
|
||||
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(p, 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(p, ACL_TYPE_DEFAULT)
|
||||
if default_acl:
|
||||
default_text = acl_to_text(default_acl, NULL)
|
||||
if default_text:
|
||||
|
@ -252,32 +266,41 @@ 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
|
||||
|
||||
p = <bytes>os.fsencode(path)
|
||||
if fd is None and isinstance(path, str):
|
||||
path = os.fsencode(path)
|
||||
if numeric_owner:
|
||||
converter = posix_acl_use_stored_uid_gid
|
||||
else:
|
||||
converter = acl_use_local_uid_gid
|
||||
access_text = item.get('acl_access')
|
||||
default_text = item.get('acl_default')
|
||||
if access_text:
|
||||
try:
|
||||
access_acl = acl_from_text(<bytes>converter(access_text))
|
||||
if access_acl:
|
||||
acl_set_file(p, 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')
|
||||
if default_text:
|
||||
try:
|
||||
default_acl = acl_from_text(<bytes>converter(default_text))
|
||||
if default_acl:
|
||||
acl_set_file(p, 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)
|
||||
|
||||
|
||||
cdef _sync_file_range(fd, offset, length, flags):
|
||||
assert offset & PAGE_MASK == 0, "offset %d not page-aligned" % offset
|
||||
assert length & PAGE_MASK == 0, "length %d not page-aligned" % length
|
||||
|
|
Loading…
Reference in New Issue