Browse Source

improve acl_get / acl_set error handling, see #4049

Thomas Waldmann 1 year ago
parent
commit
d4a83edfdd
3 changed files with 33 additions and 16 deletions
  1. 9 3
      src/borg/platform/darwin.pyx
  2. 14 10
      src/borg/platform/freebsd.pyx
  3. 10 3
      src/borg/platform/linux.pyx

+ 9 - 3
src/borg/platform/darwin.pyx

@@ -1,6 +1,7 @@
 import os
 
 from libc.stdint cimport uint32_t
+from libc cimport errno
 
 from .posix import user2uid, group2gid
 from ..helpers import safe_decode, safe_encode
@@ -121,7 +122,10 @@ def acl_get(path, item, st, numeric_ids=False, fd=None):
         else:
             acl = acl_get_link_np(path, ACL_TYPE_EXTENDED)
         if acl == NULL:
-            return
+            if errno.errno == errno.ENOENT:
+                # macOS weirdness: if a file has no ACLs, it sets errno to ENOENT. :-(
+                return
+            raise OSError(errno.errno, os.strerror(errno.errno), os.fsdecode(path))
         text = acl_to_text(acl, NULL)
         if text == NULL:
             return
@@ -148,8 +152,10 @@ def acl_set(path, item, numeric_ids=False, fd=None):
             if isinstance(path, str):
                 path = os.fsencode(path)
             if fd is not None:
-                acl_set_fd_np(fd, acl, ACL_TYPE_EXTENDED)
+                if acl_set_fd_np(fd, acl, ACL_TYPE_EXTENDED) == -1:
+                    raise OSError(errno.errno, os.strerror(errno.errno), os.fsdecode(path))
             else:
-                acl_set_link_np(path, ACL_TYPE_EXTENDED, acl)
+                if acl_set_link_np(path, ACL_TYPE_EXTENDED, acl) == -1:
+                    raise OSError(errno.errno, os.strerror(errno.errno), os.fsdecode(path))
         finally:
             acl_free(acl)

+ 14 - 10
src/borg/platform/freebsd.pyx

@@ -4,11 +4,9 @@ from .posix import posix_acl_use_stored_uid_gid
 from ..helpers import safe_encode, safe_decode
 from .xattr import _listxattr_inner, _getxattr_inner, _setxattr_inner, split_lstring
 
-API_VERSION = '1.4_01'
+from libc cimport errno
 
-cdef extern from "errno.h":
-    int errno
-    int EINVAL
+API_VERSION = '1.4_01'
 
 cdef extern from "sys/extattr.h":
     ssize_t c_extattr_list_file "extattr_list_file" (const char *path, int attrnamespace, void *data, size_t nbytes)
@@ -136,6 +134,8 @@ cdef _get_acl(p, type, item, attribute, flags, fd=None):
             item[attribute] = text
             acl_free(text)
         acl_free(acl)
+    else:
+        raise OSError(errno.errno, os.strerror(errno.errno), os.fsdecode(p))
 
 
 def acl_get(path, item, st, numeric_ids=False, fd=None):
@@ -147,7 +147,7 @@ def acl_get(path, item, st, numeric_ids=False, fd=None):
     if isinstance(path, str):
         path = os.fsencode(path)
     ret = lpathconf(path, _PC_ACL_NFS4)
-    if ret < 0 and errno == EINVAL:
+    if ret < 0 and errno.errno == errno.EINVAL:
         return
     flags |= ACL_TEXT_NUMERIC_IDS if numeric_ids else 0
     if ret > 0:
@@ -167,11 +167,15 @@ cdef _set_acl(p, type, item, attribute, numeric_ids=False, fd=None):
             text = posix_acl_use_stored_uid_gid(text)
         acl = acl_from_text(<bytes>text)
         if acl:
-            if fd is not None:
-                acl_set_fd_np(fd, acl, type)
-            else:
-                acl_set_link_np(p, type, acl)
-            acl_free(acl)
+            try:
+                if fd is not None:
+                    if acl_set_fd_np(fd, acl, type) == -1:
+                        raise OSError(errno.errno, os.strerror(errno.errno), os.fsdecode(p))
+                else:
+                    if acl_set_link_np(p, type, acl) == -1:
+                        raise OSError(errno.errno, os.strerror(errno.errno), os.fsdecode(p))
+            finally:
+                acl_free(acl)
 
 
 cdef _nfs4_use_stored_uid_gid(acl):

+ 10 - 3
src/borg/platform/linux.pyx

@@ -251,9 +251,13 @@ def acl_get(path, item, st, numeric_ids=False, fd=None):
             access_acl = acl_get_fd(fd)
         else:
             access_acl = acl_get_file(path, ACL_TYPE_ACCESS)
+        if access_acl == NULL:
+            raise OSError(errno.errno, os.strerror(errno.errno), os.fsdecode(path))
         if stat.S_ISDIR(st.st_mode):
             # only directories can have a default ACL. there is no fd-based api to get it.
             default_acl = acl_get_file(path, ACL_TYPE_DEFAULT)
+            if default_acl == NULL:
+                raise OSError(errno.errno, os.strerror(errno.errno), os.fsdecode(path))
         if access_acl:
             access_text = acl_to_text(access_acl, NULL)
             if access_text:
@@ -289,9 +293,11 @@ def acl_set(path, item, numeric_ids=False, fd=None):
             access_acl = acl_from_text(<bytes>converter(access_text))
             if access_acl:
                 if fd is not None:
-                    acl_set_fd(fd, access_acl)
+                    if acl_set_fd(fd, access_acl) == -1:
+                        raise OSError(errno.errno, os.strerror(errno.errno), os.fsdecode(path))
                 else:
-                    acl_set_file(path, ACL_TYPE_ACCESS, access_acl)
+                    if acl_set_file(path, ACL_TYPE_ACCESS, access_acl) == -1:
+                        raise OSError(errno.errno, os.strerror(errno.errno), os.fsdecode(path))
         finally:
             acl_free(access_acl)
     default_text = item.get('acl_default')
@@ -300,7 +306,8 @@ def acl_set(path, item, numeric_ids=False, fd=None):
             default_acl = acl_from_text(<bytes>converter(default_text))
             if default_acl:
                 # only directories can get a default ACL. there is no fd-based api to set it.
-                acl_set_file(path, ACL_TYPE_DEFAULT, default_acl)
+                if acl_set_file(path, ACL_TYPE_DEFAULT, default_acl) == -1:
+                    raise OSError(errno.errno, os.strerror(errno.errno), os.fsdecode(path))
         finally:
             acl_free(default_acl)