diff options
author | Bob Ippolito <bob@redivi.com> | 2016-02-28 11:07:56 -0800 |
---|---|---|
committer | Bob Ippolito <bob@redivi.com> | 2016-02-28 11:07:56 -0800 |
commit | cfddb9f0247000662a407b8a1ca8f4a9df742643 (patch) | |
tree | bc6bfc7bf024d5b4434c7431fade7dffc711817b | |
parent | eb2b09cc34f8f3890e7e4f41f7f47bf3923c5451 (diff) | |
parent | 7b40e00f1ab859f13b349c40d97f6526a6110a0c (diff) | |
download | xattr-cfddb9f0247000662a407b8a1ca8f4a9df742643.tar.gz |
Merge pull request #38 from jmberg/master
options bugfix, pyxattr compatibility
-rw-r--r-- | xattr/lib.py | 32 | ||||
-rw-r--r-- | xattr/pyxattr_compat.py | 110 |
2 files changed, 125 insertions, 17 deletions
diff --git a/xattr/lib.py b/xattr/lib.py index 1df1386..517440c 100644 --- a/xattr/lib.py +++ b/xattr/lib.py @@ -5,10 +5,10 @@ import cffi ffi = cffi.FFI() ffi.cdef(""" -#define XATTR_NOFOLLOW ... -#define XATTR_CREATE ... -#define XATTR_REPLACE ... -#define XATTR_NOSECURITY ... +#define XATTR_XATTR_NOFOLLOW ... +#define XATTR_XATTR_CREATE ... +#define XATTR_XATTR_REPLACE ... +#define XATTR_XATTR_NOSECURITY ... #define XATTR_MAXNAMELEN ... ssize_t xattr_getxattr(const char *, const char *, void *, ssize_t, uint32_t, int); @@ -543,7 +543,7 @@ static ssize_t xattr_fsetxattr(int fd, const char *name, void *value, ssize_t si } else if (options != 0) { return -1; } - if (options & XATTR_XATTR_NOFOLLOW) { + if (nofollow) { return -1; } else { return fsetxattr(fd, name, value, size, options); @@ -582,25 +582,23 @@ static ssize_t xattr_flistxattr(int fd, char *namebuf, size_t size, int options) #define xattr_fsetxattr fsetxattr #define xattr_listxattr listxattr #define xattr_flistxattr flistxattr + +/* define these for use in python (see below) */ +#define XATTR_XATTR_NOFOLLOW XATTR_NOFOLLOW +#define XATTR_XATTR_CREATE XATTR_CREATE +#define XATTR_XATTR_REPLACE XATTR_REPLACE +#define XATTR_XATTR_NOSECURITY XATTR_NOSECURITY #endif #ifndef XATTR_MAXNAMELEN #define XATTR_MAXNAMELEN 127 #endif - -#ifndef XATTR_NOFOLLOW -#define XATTR_NOFOLLOW 0x0001 -#endif - -#ifndef XATTR_NOSECURITY -#define XATTR_NOSECURITY 0x0008 -#endif """, ext_package='xattr') -XATTR_NOFOLLOW = lib.XATTR_NOFOLLOW -XATTR_CREATE = lib.XATTR_CREATE -XATTR_REPLACE = lib.XATTR_REPLACE -XATTR_NOSECURITY = lib.XATTR_NOSECURITY +XATTR_NOFOLLOW = lib.XATTR_XATTR_NOFOLLOW +XATTR_CREATE = lib.XATTR_XATTR_CREATE +XATTR_REPLACE = lib.XATTR_XATTR_REPLACE +XATTR_NOSECURITY = lib.XATTR_XATTR_NOSECURITY XATTR_MAXNAMELEN = lib.XATTR_MAXNAMELEN XATTR_FINDERINFO_NAME = "com.apple.FinderInfo" diff --git a/xattr/pyxattr_compat.py b/xattr/pyxattr_compat.py new file mode 100644 index 0000000..0ef913b --- /dev/null +++ b/xattr/pyxattr_compat.py @@ -0,0 +1,110 @@ +""" +pyxattr and xattr have differing API, for example xattr assumes +that (like on OSX) attribute keys are valid UTF-8, while pyxattr +just passes through the raw bytestring. + +This module provides compatibility for the pyxattr API. +""" + +import sys + +from .lib import (XATTR_NOFOLLOW, XATTR_CREATE, XATTR_REPLACE, + XATTR_NOSECURITY, XATTR_MAXNAMELEN, XATTR_FINDERINFO_NAME, + XATTR_RESOURCEFORK_NAME, _getxattr, _fgetxattr, _setxattr, _fsetxattr, + _removexattr, _fremovexattr, _listxattr, _flistxattr) + +__all__ = [ + "NS_SECURITY", "NS_USER", "NS_SYSTEM", "NS_TRUSTED", + "getxattr", "get", "get_all", "setxattr", "set", + "removexattr", "remove", "listxattr", "list" +] + +NS_SECURITY = "security" +NS_USER = "user" +NS_SYSTEM = "system" +NS_TRUSTED = "trusted" + +_NO_NS = object() + +_fsencoding = sys.getfilesystemencoding() + +def _call(item, name_func, fd_func, *args): + if isinstance(item, int): + return fd_func(item, *args) + elif hasattr(item, 'fileno'): + return fd_func(item.fileno(), *args) + elif isinstance(item, str): + return name_func(item, *args) + elif isinstance(item, unicode): + item = item.encode(_fsencoding) + return name_func(item, *args) + else: + raise TypeError("argument must be string, int or file object") + +def _add_ns(item, ns): + if ns is None: + raise TypeError("namespace must not be None") + if ns == _NO_NS: + return item + return "%s.%s" % (ns, item) + +def getxattr(item, attribute, nofollow=False): + options = nofollow and XATTR_NOFOLLOW or 0 + return _call(item, _getxattr, _fgetxattr, attribute, 0, 0, options) + +def get(item, name, nofollow=False, namespace=_NO_NS): + name = _add_ns(name, namespace) + return getxattr(item, name, nofollow=nofollow) + +def get_all(item, nofollow=False, namespace=_NO_NS): + if namespace is not None and namespace != _NO_NS: + namespace = '%s.' % namespace + l = listxattr(item, nofollow=nofollow) + result = [] + for name in l: + try: + if namespace is not None and namespace != _NO_NS: + if not name.startswith(namespace): + continue + result.append((name[len(namespace):], + getxattr(item, name, nofollow=nofollow))) + else: + result.append((name, getxattr(item, name, nofollow=nofollow))) + except IOError: + pass + return result + +def setxattr(item, name, value, flags=0, nofollow=False): + options = nofollow and XATTR_NOFOLLOW or 0 + options |= flags + return _call(item, _setxattr, _fsetxattr, name, value, 0, options) + +def set(item, name, value, nofollow=False, flags=0, namespace=_NO_NS): + name = _add_ns(name, namespace) + return setxattr(item, name, value, flags=flags, nofollow=nofollow) + +def removexattr(item, name, nofollow=False): + options = nofollow and XATTR_NOFOLLOW or 0 + return _call(item, _removexattr, _fremovexattr, name, options) + +def remove(item, name, nofollow=False, namespace=_NO_NS): + name = _add_ns(name, namespace) + return removexattr(item, name, nofollow=nofollow) + +def listxattr(item, nofollow=False): + options = nofollow and XATTR_NOFOLLOW or 0 + res = _call(item, _listxattr, _flistxattr, options).split(b'\x00') + res.pop() + return res + +def list(item, nofollow=False, namespace=_NO_NS): + if not namespace or namespace == _NO_NS: + return listxattr(item, nofollow=nofollow) + namespace = "%s." % namespace + l = listxattr(item, nofollow=nofollow) + result = [] + for name in l: + if not name.startswith(namespace): + continue + result.append(name[len(namespace):]) + return result |