diff --git a/darc/archive.py b/darc/archive.py index e889fa369..cf6bc9079 100644 --- a/darc/archive.py +++ b/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): diff --git a/darc/crypto.py b/darc/crypto.py index dd3855616..e5e6e69fe 100644 --- a/darc/crypto.py +++ b/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) diff --git a/darc/hashindex.pyx b/darc/hashindex.pyx index 94fac5a05..d9e120dfa 100644 --- a/darc/hashindex.pyx +++ b/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) diff --git a/darc/xattr.py b/darc/xattr.py index ea243021d..a047838a6 100644 --- a/darc/xattr.py +++ b/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 _check(rv, path=None): + if rv < 0: + raise OSError(get_errno(), path) + return rv -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) +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 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 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 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 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 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 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 lsetxattr(path, name, value, flags=0): - rv = libc.lsetxattr(os.fsencode(path), name, value, len(value), flags) - if rv: - raise OSError(get_errno()) + 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 fsetxattr(fd, name, value, flags=0): - rv = libc.fsetxattr(fd, name, value, len(value), flags) - if rv: - raise OSError(get_errno()) + def lsetxattr(path, name, value, flags=0): + _check(libc.lsetxattr(os.fsencode(path), name, value, len(value), flags), path) -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 fsetxattr(fd, name, value, flags=0): + _check(libc.fsetxattr(fd, name, value, len(value), flags)) -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 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')