Jonas Borgström 12 лет назад
Родитель
Сommit
0bc8decb60
4 измененных файлов с 190 добавлено и 86 удалено
  1. 6 3
      darc/archive.py
  2. 3 0
      darc/crypto.py
  3. 2 0
      darc/hashindex.pyx
  4. 179 83
      darc/xattr.py

+ 6 - 3
darc/archive.py

@@ -348,9 +348,12 @@ class Archive(object):
         }
         if self.numeric_owner:
             item[b'user'] = item[b'group'] = None
-        xattrs = xattr.get_all(path)
-        if xattrs:
-            item[b'xattrs'] = xattrs
+        try:
+            xattrs = xattr.get_all(path)
+            if xattrs:
+                item[b'xattrs'] = xattrs
+        except PermissionError:
+            pass
         return item
 
     def process_item(self, path, st):

+ 3 - 0
darc/crypto.py

@@ -3,6 +3,9 @@ from ctypes.util import find_library
 import struct
 
 libcrypto = cdll.LoadLibrary(find_library('crypto'))
+# Default libcrypto on OS X is too old, try the brew version
+if not hasattr(libcrypto, 'PKCS5_PBKDF2_HMAC'):
+    libcrypto = cdll.LoadLibrary('/usr/local/opt/openssl/lib/libcrypto.dylib')
 libcrypto.PKCS5_PBKDF2_HMAC.argtypes = (c_char_p, c_int, c_char_p, c_int, c_int, c_void_p, c_int, c_char_p)
 libcrypto.EVP_sha256.restype = c_void_p
 libcrypto.AES_set_encrypt_key.argtypes = (c_char_p, c_int, c_char_p)

+ 2 - 0
darc/hashindex.pyx

@@ -65,6 +65,8 @@ cdef class NSIndex(IndexBase):
     @classmethod
     def create(cls, path, capacity=16):
         index = hashindex_create(path, capacity, 32, 8)
+        if not index:
+            raise Exception('Failed to create %s' % path)
         hashindex_close(index)
         return cls(path)
 

+ 179 - 83
darc/xattr.py

@@ -1,89 +1,185 @@
 """A basic extended attributes (xattr) implementation for Linux
 """
 import os
-from ctypes import CDLL, create_string_buffer, c_size_t, c_char_p, c_int, get_errno
+import sys
+from ctypes import CDLL, create_string_buffer, c_ssize_t, c_size_t, c_char_p, c_int, c_uint32, get_errno
 from ctypes.util import find_library
 
 libc = CDLL(find_library('c'), use_errno=True)
-libc.llistxattr.argtypes = (c_char_p, c_char_p, c_size_t)
-libc.llistxattr.restype = c_size_t
-libc.flistxattr.argtypes = (c_int, c_char_p, c_size_t)
-libc.flistxattr.restype = c_size_t
-libc.lsetxattr.argtypes = (c_char_p, c_char_p, c_char_p, c_size_t, c_int)
-libc.lsetxattr.restype = c_int
-libc.lgetxattr.argtypes = (c_char_p, c_char_p, c_char_p, c_size_t)
-libc.lgetxattr.restype = c_size_t
-
-
-def set(path_or_fd, name, value):
-    if isinstance(path_or_fd, int):
-        fsetxattr(path_or_fd, b'user.' + name, value)
-    else:
-        lsetxattr(path_or_fd, b'user.' + name, value)
-
-
-def get_all(path_or_fd):
-    """Return a dictionary with all (user) xattrs for "path_or_fd"
-    """
-    if isinstance(path_or_fd, int):
-        return dict((name[5:], fgetxattr(path_or_fd, name)) for name in flistxattr(path_or_fd) if name.startswith(b'user.'))
-    else:
-        return dict((name[5:], lgetxattr(path_or_fd, name)) for name in llistxattr(path_or_fd) if name.startswith(b'user.'))
-
-
-def llistxattr(path):
-    path = os.fsencode(path)
-    n = libc.llistxattr(path, None, 0)
-    if n == 0:
-        []
-    elif n < 0:
-        raise OSError(get_errno())
-    namebuf = create_string_buffer(n)
-    assert libc.llistxattr(path, namebuf, n) == n
-    return namebuf.raw.split(b'\0')[:-1]
-
-
-def flistxattr(fd):
-    n = libc.flistxattr(fd, None, 0)
-    if n == 0:
-        []
-    elif n < 0:
-        raise OSError(get_errno())
-    namebuf = create_string_buffer(n)
-    assert libc.flistxattr(fd, namebuf, n) == n
-    return namebuf.raw.split(b'\0')[:-1]
-
-
-def lsetxattr(path, name, value, flags=0):
-    rv = libc.lsetxattr(os.fsencode(path), name, value, len(value), flags)
-    if rv:
-        raise OSError(get_errno())
-
-
-def fsetxattr(fd, name, value, flags=0):
-    rv = libc.fsetxattr(fd, name, value, len(value), flags)
-    if rv:
-        raise OSError(get_errno())
-
-
-def lgetxattr(path, name):
-    path = os.fsencode(path)
-    n = libc.lgetxattr(path, name, None, 0)
-    if n == 0:
-        return None
-    elif n < 0:
-        raise OSError(get_errno())
-    valuebuf = create_string_buffer(n)
-    assert libc.lgetxattr(path, name, valuebuf, n) == n
-    return valuebuf.raw
-
-
-def fgetxattr(fd, name):
-    n = libc.fgetxattr(fd, name, None, 0)
-    if n == 0:
-        return None
-    elif n < 0:
-        raise OSError(get_errno())
-    valuebuf = create_string_buffer(n)
-    assert libc.fgetxattr(fd, name, valuebuf, n) == n
-    return valuebuf.raw
+
+def _check(rv, path=None):
+    if rv < 0:
+        raise OSError(get_errno(), path)
+    return rv
+
+
+if sys.platform == 'linux':
+    libc.llistxattr.argtypes = (c_char_p, c_char_p, c_size_t)
+    libc.llistxattr.restype = c_ssize_t
+    libc.flistxattr.argtypes = (c_int, c_char_p, c_size_t)
+    libc.flistxattr.restype = c_ssize_t
+    libc.lsetxattr.argtypes = (c_char_p, c_char_p, c_char_p, c_size_t, c_int)
+    libc.lsetxattr.restype = c_int
+    libc.fsetxattr.argtypes = (c_int, c_char_p, c_char_p, c_size_t, c_int)
+    libc.fsetxattr.restype = c_int
+    libc.lgetxattr.argtypes = (c_char_p, c_char_p, c_char_p, c_size_t)
+    libc.lgetxattr.restype = c_ssize_t
+    libc.fgetxattr.argtypes = (c_int, c_char_p, c_char_p, c_size_t)
+    libc.fgetxattr.restype = c_ssize_t
+
+
+    def set(path_or_fd, name, value):
+        if isinstance(path_or_fd, int):
+            fsetxattr(path_or_fd, b'user.' + name, value)
+        else:
+            lsetxattr(path_or_fd, b'user.' + name, value)
+
+
+    def get_all(path_or_fd):
+        """Return a dictionary with all (user) xattrs for "path_or_fd"
+        """
+        if isinstance(path_or_fd, int):
+            return dict((name[5:], fgetxattr(path_or_fd, name)) for name in flistxattr(path_or_fd) if name.startswith(b'user.'))
+        else:
+            return dict((name[5:], lgetxattr(path_or_fd, name)) for name in llistxattr(path_or_fd) if name.startswith(b'user.'))
+
+
+    def llistxattr(path):
+        path = os.fsencode(path)
+        n = _check(libc.llistxattr(path, None, 0), path)
+        if n == 0:
+            []
+        namebuf = create_string_buffer(n)
+        n2 = _check(libc.llistxattr(path, namebuf, n))
+        if n2 != n:
+            raise Exception('llistxattr failed')
+        return namebuf.raw.split(b'\0')[:-1]
+
+
+    def flistxattr(fd):
+        n = _check(libc.flistxattr(fd, None, 0))
+        if n == 0:
+            []
+        namebuf = create_string_buffer(n)
+        n2 = _check(libc.flistxattr(fd, namebuf, n))
+        if n2 != n:
+            raise Exception('flistxattr failed')
+        return namebuf.raw.split(b'\0')[:-1]
+
+
+    def lsetxattr(path, name, value, flags=0):
+        _check(libc.lsetxattr(os.fsencode(path), name, value, len(value), flags), path)
+
+
+    def fsetxattr(fd, name, value, flags=0):
+        _check(libc.fsetxattr(fd, name, value, len(value), flags))
+
+
+    def lgetxattr(path, name):
+        path = os.fsencode(path)
+        n = _check(libc.lgetxattr(path, name, None, 0))
+        if n == 0:
+            return None
+        valuebuf = create_string_buffer(n)
+        n2 = _check(libc.lgetxattr(path, name, valuebuf, n), path)
+        if n2 != n:
+            raise Exception('lgetxattr failed')
+        return valuebuf.raw
+
+
+    def fgetxattr(fd, name):
+        n = _check(libc.fgetxattr(fd, name, None, 0))
+        if n == 0:
+            return None
+        valuebuf = create_string_buffer(n)
+        n2 = _check(libc.fgetxattr(fd, name, valuebuf, n))
+        if n2 != n:
+            raise Exception('fgetxattr failed')
+
+elif sys.platform == 'darwin':
+    libc.listxattr.argtypes = (c_char_p, c_char_p, c_size_t, c_int)
+    libc.listxattr.restype = c_ssize_t
+    libc.flistxattr.argtypes = (c_int, c_char_p, c_size_t)
+    libc.flistxattr.restype = c_ssize_t
+    libc.setxattr.argtypes = (c_char_p, c_char_p, c_char_p, c_size_t, c_uint32, c_int)
+    libc.setxattr.restype = c_int
+    libc.fsetxattr.argtypes = (c_int, c_char_p, c_char_p, c_size_t, c_uint32, c_int)
+    libc.fsetxattr.restype = c_int
+    libc.getxattr.argtypes = (c_char_p, c_char_p, c_char_p, c_size_t, c_uint32, c_int)
+    libc.getxattr.restype = c_ssize_t
+    libc.fgetxattr.argtypes = (c_int, c_char_p, c_char_p, c_size_t, c_uint32, c_int)
+    libc.fgetxattr.restype = c_ssize_t
+
+    XATTR_NOFOLLOW = 0x0001
+
+    def set(path_or_fd, name, value):
+        if isinstance(path_or_fd, int):
+            fsetxattr(path_or_fd, name, value)
+        else:
+            lsetxattr(path_or_fd, name, value)
+
+
+    def get_all(path_or_fd):
+        """Return a dictionary with all (user) xattrs for "path_or_fd"
+        """
+        if isinstance(path_or_fd, int):
+            return dict((name, fgetxattr(path_or_fd, name)) for name in flistxattr(path_or_fd))
+        else:
+            return dict((name, lgetxattr(path_or_fd, name)) for name in llistxattr(path_or_fd))
+
+
+    def llistxattr(path):
+        path = os.fsencode(path)
+        n = _check(libc.listxattr(path, None, 0, XATTR_NOFOLLOW), path)
+        if n == 0:
+            []
+        namebuf = create_string_buffer(n)
+        n2 = _check(libc.listxattr(path, namebuf, n, XATTR_NOFOLLOW))
+        if n2 != n:
+            raise Exception('llistxattr failed')
+        return namebuf.raw.split(b'\0')[:-1]
+
+
+    def flistxattr(fd):
+        n = _check(libc.flistxattr(fd, None, 0, 0))
+        if n == 0:
+            []
+        namebuf = create_string_buffer(n)
+        n2 = _check(libc.flistxattr(fd, namebuf, n, 0))
+        if n2 != n:
+            raise Exception('flistxattr failed')
+        return namebuf.raw.split(b'\0')[:-1]
+
+
+    def lsetxattr(path, name, value, flags=XATTR_NOFOLLOW):
+        rv = _check(libc.setxattr(os.fsencode(path), name, value, len(value), 0, flags), path)
+
+
+    def fsetxattr(fd, name, value, flags=0):
+        rv = _check(libc.fsetxattr(fd, name, value, len(value), 0, flags))
+
+
+    def lgetxattr(path, name):
+        path = os.fsencode(path)
+        n = _check(libc.getxattr(path, name, None, 0, 0, XATTR_NOFOLLOW), path)
+        if n == 0:
+            return None
+        valuebuf = create_string_buffer(n)
+        n2 = _check(libc.getxattr(path, name, valuebuf, n, 0, XATTR_NOFOLLOW))
+        if n2 != n:
+            raise Exception('getxattr failed')
+        return valuebuf.raw
+
+
+    def fgetxattr(fd, name):
+        n = _check(libc.fgetxattr(fd, name, None, 0, 0, 0))
+        if n == 0:
+            return None
+        valuebuf = create_string_buffer(n)
+        n2 = _check(libc.fgetxattr(fd, name, valuebuf, n, 0, 0))
+        if n2 != n:
+            Exception('fgetxattr failed')
+        return valuebuf.raw
+
+else:
+    raise Exception('Unsupported platform')