From 48e60e12449e0b6d03377e46ed464c370db9732e Mon Sep 17 00:00:00 2001 From: Alex Gaynor Date: Thu, 18 Jul 2013 14:38:17 -0700 Subject: some cleanups --- xattr/__init__.py | 62 +++++++++++++++++++++---------------------------------- 1 file changed, 23 insertions(+), 39 deletions(-) diff --git a/xattr/__init__.py b/xattr/__init__.py index d9431f9..551cad1 100644 --- a/xattr/__init__.py +++ b/xattr/__init__.py @@ -8,25 +8,20 @@ that exposes these extended attributes. """ __version__ = '0.6.4' -from constants import XATTR_NOFOLLOW, XATTR_CREATE, XATTR_REPLACE, \ - XATTR_NOSECURITY, XATTR_MAXNAMELEN, XATTR_FINDERINFO_NAME, \ - XATTR_RESOURCEFORK_NAME + +from .constants import (XATTR_NOFOLLOW, XATTR_CREATE, XATTR_REPLACE, + XATTR_NOSECURITY, XATTR_MAXNAMELEN, XATTR_FINDERINFO_NAME, + XATTR_RESOURCEFORK_NAME) import _xattr -def _pyflakes_api(): - # trick pyflakes into thinking these are used. - return [ - XATTR_NOFOLLOW, XATTR_CREATE, XATTR_REPLACE, - XATTR_NOSECURITY, XATTR_MAXNAMELEN, XATTR_FINDERINFO_NAME, - XATTR_RESOURCEFORK_NAME, - ] +__all__ = [ + "XATTR_NOFOLLOW", "XATTR_CREATE", "XATTR_REPLACE", "XATTR_NOSECURITY", + "XATTR_MAXNAMELEN", "XATTR_FINDERINFO_NAME", "XATTR_RESOURCEFORK_NAME", + "xattr", "listxattr", "getxattr", "setxattr", "removexattr" +] -def _boundfunc(func, first): - def _func(*args): - return func(first, *args) - return _func class xattr(object): """ @@ -45,16 +40,11 @@ class xattr(object): """ self.obj = obj self.options = options - self.flavor = None fileno = getattr(obj, 'fileno', None) if fileno is not None: - obj = fileno() - if isinstance(obj, int): - self.flavor = 'fd' - self._bind_any('f%sxattr', obj, options) + self.value = fileno() else: - self.flavor = 'file' - self._bind_any('%sxattr', obj, options) + self.value = obj def __repr__(self): if self.flavor: @@ -62,17 +52,11 @@ class xattr(object): else: return object.__repr__(self) - def _bind_any(self, fmt, obj, options): - options = self.options - for method in ("get", "set", "remove", "list"): - name = '_' + method - func = getattr(_xattr, fmt % (method,)) - meth = _boundfunc(func, obj) - try: - meth.__name__ = name - except TypeError: - pass - setattr(self, name, meth) + def _call(self, name_func, fd_func, *args): + if isinstance(self.value, int): + return fd_func(self.value, *args) + else: + return name_func(self.value, *args) def get(self, name, options=0): """ @@ -81,7 +65,7 @@ class xattr(object): See x-man-page://2/getxattr for options and possible errors. """ - return self._get(name, 0, 0, options | self.options) + return self._call(_xattr.getxattr, _xattr.fgetxattr, name, 0, 0, options | self.options) def set(self, name, value, options=0): """ @@ -90,7 +74,7 @@ class xattr(object): See x-man-page://2/setxattr for options and possible errors. """ - self._set(name, value, 0, options | self.options) + return self._call(_xattr.setxattr, _xattr.fsetxattr, name, value, 0, options | self.options) def remove(self, name, options=0): """ @@ -99,6 +83,7 @@ class xattr(object): See x-man-page://2/removexattr for options and possible errors. """ + return self._call(_xattr.removexattr, _xattr.fremovexattr, name, options | self.options) self._remove(name, options | self.options) def list(self, options=0): @@ -108,7 +93,7 @@ class xattr(object): See x-man-page://2/listxattr for options and possible errors. """ - res = self._list(options | self.options).split('\x00') + res = self._call(_xattr.listxattr, _xattr.flistxattr, options | self.options).split('\x00') res.pop() return [unicode(s, 'utf-8') for s in res] @@ -186,20 +171,19 @@ class xattr(object): def listxattr(f, symlink=False): - __doc__ = xattr.list.__doc__ return tuple(xattr(f).list(options=symlink and XATTR_NOFOLLOW or 0)) + def getxattr(f, attr, symlink=False): - __doc__ = xattr.get.__doc__ return xattr(f).get(attr, options=symlink and XATTR_NOFOLLOW or 0) + def setxattr(f, attr, value, options=0, symlink=False): - __doc__ = xattr.set.__doc__ if symlink: options |= XATTR_NOFOLLOW return xattr(f).set(attr, value, options=options) + def removexattr(f, attr, symlink=False): - __doc__ = xattr.remove.__doc__ options = symlink and XATTR_NOFOLLOW or 0 return xattr(f).remove(attr, options=options) -- cgit v1.2.1 From 59e9ede4b3e85a7d7995a7861f0605c7bb03bd97 Mon Sep 17 00:00:00 2001 From: Alex Gaynor Date: Thu, 18 Jul 2013 14:39:16 -0700 Subject: fix up repr --- xattr/__init__.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/xattr/__init__.py b/xattr/__init__.py index 551cad1..5a712fa 100644 --- a/xattr/__init__.py +++ b/xattr/__init__.py @@ -47,10 +47,11 @@ class xattr(object): self.value = obj def __repr__(self): - if self.flavor: - return '<%s %s=%r>' % (type(self).__name__, self.flavor, self.obj) + if isinstance(self.value, int): + flavor = "fd" else: - return object.__repr__(self) + flavor = "file" + return "<%s %s=%r>" % (type(self).__name__, flavor, self.value) def _call(self, name_func, fd_func, *args): if isinstance(self.value, int): -- cgit v1.2.1 From decfae5305f707fc14875ead056b4a4f8622b9cd Mon Sep 17 00:00:00 2001 From: Alex Gaynor Date: Thu, 18 Jul 2013 14:43:00 -0700 Subject: cleanups --- _build/_make_constants.py | 20 -------------------- xattr/tool.py | 33 +++++++++++++++++++-------------- 2 files changed, 19 insertions(+), 34 deletions(-) delete mode 100644 _build/_make_constants.py diff --git a/_build/_make_constants.py b/_build/_make_constants.py deleted file mode 100644 index c73e8c1..0000000 --- a/_build/_make_constants.py +++ /dev/null @@ -1,20 +0,0 @@ -infile = '/usr/include/sys/xattr.h' -out = file('Lib/xattr/constants.py', 'w') -for line in file(infile): - line = line.rstrip() - if line.startswith('/*') and line.endswith('*/'): - print >>out, '' - print >>out, '# ' + line[2:-2].strip() - elif line.startswith('#define'): - if lastblank: - print >>out, '' - chunks = line.split(None, 3) - if len(chunks) == 3: - print >>out, '%s = %s' % (chunks[1], chunks[2]) - elif len(chunks) == 4: - comment = chunks[3].replace('/*', '').replace('*/', '').strip() - print >>out, '%s = %s # %s' % (chunks[1], chunks[2], comment) - if not line: - lastblank = True - else: - lastblank = False diff --git a/xattr/tool.py b/xattr/tool.py index 3b1121e..41ea7e1 100755 --- a/xattr/tool.py +++ b/xattr/tool.py @@ -28,9 +28,11 @@ import sys import os import getopt -import xattr import zlib +import xattr + + def usage(e=None): if e: print e @@ -57,34 +59,38 @@ def usage(e=None): else: sys.exit(0) + class NullsInString(Exception): """Nulls in string.""" -_FILTER=''.join([(len(repr(chr(x)))==3) and chr(x) or '.' for x in range(256)]) + +_FILTER = ''.join([(len(repr(chr(x))) == 3) and chr(x) or '.' for x in range(256)]) + def _dump(src, length=16): - result=[] + result = [] for i in xrange(0, len(src), length): s = src[i:i+length] - hexa = ' '.join(["%02X"%ord(x) for x in s]) + hexa = ' '.join(["%02X" % ord(x) for x in s]) printable = s.translate(_FILTER) result.append("%04X %-*s %s\n" % (i, length*3, hexa, printable)) return ''.join(result) + def main(): try: (optargs, args) = getopt.getopt(sys.argv[1:], "hlpwdz", ["help"]) except getopt.GetoptError, e: usage(e) - attr_name = None + attr_name = None long_format = False - read = False - write = False - delete = False - compress = lambda x: x - decompress = compress - status = 0 + read = False + write = False + delete = False + compress = lambda x: x + decompress = compress + status = 0 for opt, arg in optargs: if opt in ("-h", "--help"): @@ -104,7 +110,7 @@ def main(): if read or write: usage("-d not allowed with -p or -w") elif opt == "-z": - compress = zlib.compress + compress = zlib.compress decompress = zlib.decompress if write or delete: @@ -132,7 +138,6 @@ def main(): sys.stderr.write("No such file: %s\n" % (filename,)) else: sys.stderr.write(str(e) + "\n") - status = 1 try: attrs = xattr.xattr(filename) @@ -185,7 +190,7 @@ def main(): if long_format: try: if attr_value.find('\0') >= 0: - raise NullsInString; + raise NullsInString print "".join((file_prefix, "%s: " % (attr_name,), attr_value)) except (UnicodeDecodeError, NullsInString): print "".join((file_prefix, "%s:" % (attr_name,))) -- cgit v1.2.1 From c41037cee7a257aac321f4a53fde976d40ebb332 Mon Sep 17 00:00:00 2001 From: Alex Gaynor Date: Thu, 18 Jul 2013 15:35:41 -0700 Subject: Everything seems to work (weird!) --- .gitignore | 1 + xattr/__init__.py | 15 +- xattr/_xattr.c | 948 ---------------------------------------------- xattr/lib.py | 714 ++++++++++++++++++++++++++++++++++ xattr/tests/test_xattr.py | 24 +- 5 files changed, 736 insertions(+), 966 deletions(-) delete mode 100644 xattr/_xattr.c create mode 100644 xattr/lib.py diff --git a/.gitignore b/.gitignore index b5a500d..5c2ffe4 100644 --- a/.gitignore +++ b/.gitignore @@ -4,3 +4,4 @@ *.pyc *.so .\#* +__pycache__ diff --git a/xattr/__init__.py b/xattr/__init__.py index 5a712fa..7618bc0 100644 --- a/xattr/__init__.py +++ b/xattr/__init__.py @@ -9,11 +9,10 @@ that exposes these extended attributes. __version__ = '0.6.4' -from .constants import (XATTR_NOFOLLOW, XATTR_CREATE, XATTR_REPLACE, +from .lib import (XATTR_NOFOLLOW, XATTR_CREATE, XATTR_REPLACE, XATTR_NOSECURITY, XATTR_MAXNAMELEN, XATTR_FINDERINFO_NAME, - XATTR_RESOURCEFORK_NAME) - -import _xattr + XATTR_RESOURCEFORK_NAME, _getxattr, _fgetxattr, _setxattr, _fsetxattr, + _removexattr, _fremovexattr, _listxattr, _flistxattr) __all__ = [ @@ -66,7 +65,7 @@ class xattr(object): See x-man-page://2/getxattr for options and possible errors. """ - return self._call(_xattr.getxattr, _xattr.fgetxattr, name, 0, 0, options | self.options) + return self._call(_getxattr, _fgetxattr, name, 0, 0, options | self.options) def set(self, name, value, options=0): """ @@ -75,7 +74,7 @@ class xattr(object): See x-man-page://2/setxattr for options and possible errors. """ - return self._call(_xattr.setxattr, _xattr.fsetxattr, name, value, 0, options | self.options) + return self._call(_setxattr, _fsetxattr, name, value, 0, options | self.options) def remove(self, name, options=0): """ @@ -84,7 +83,7 @@ class xattr(object): See x-man-page://2/removexattr for options and possible errors. """ - return self._call(_xattr.removexattr, _xattr.fremovexattr, name, options | self.options) + return self._call(_removexattr, _fremovexattr, name, options | self.options) self._remove(name, options | self.options) def list(self, options=0): @@ -94,7 +93,7 @@ class xattr(object): See x-man-page://2/listxattr for options and possible errors. """ - res = self._call(_xattr.listxattr, _xattr.flistxattr, options | self.options).split('\x00') + res = self._call(_listxattr, _flistxattr, options | self.options).split('\x00') res.pop() return [unicode(s, 'utf-8') for s in res] diff --git a/xattr/_xattr.c b/xattr/_xattr.c deleted file mode 100644 index 606450d..0000000 --- a/xattr/_xattr.c +++ /dev/null @@ -1,948 +0,0 @@ -#include "Python.h" -#ifdef __FreeBSD__ -#include -#elif defined(__SUN__) || defined(__sun__) || defined(sun) -#include -#include -#include -#include -#include -#else -#include -#endif - -#ifdef __FreeBSD__ - -/* FreeBSD compatibility API */ -#define XATTR_XATTR_NOFOLLOW 0x0001 -#define XATTR_XATTR_CREATE 0x0002 -#define XATTR_XATTR_REPLACE 0x0004 -#define XATTR_XATTR_NOSECURITY 0x0008 - - -/* Converts a freebsd format attribute list into a NULL terminated list. - * While the man page on extattr_list_file says it is NULL terminated, - * it is actually the first byte that is the length of the - * following attribute. - */ -static void convert_bsd_list(char *namebuf, size_t size) -{ - size_t offset = 0; - while(offset < size) { - int length = (int) namebuf[offset]; - memmove(namebuf+offset, namebuf+offset+1, length); - namebuf[offset+length] = '\0'; - offset += length+1; - } -} - -static ssize_t xattr_getxattr(const char *path, const char *name, - void *value, ssize_t size, u_int32_t position, - int options) -{ - if (position != 0 || - !(options == 0 || options == XATTR_XATTR_NOFOLLOW)) { - return -1; - } - - if (options & XATTR_XATTR_NOFOLLOW) { - return extattr_get_link(path, EXTATTR_NAMESPACE_USER, - name, value, size); - } - else { - return extattr_get_file(path, EXTATTR_NAMESPACE_USER, - name, value, size); - } -} - -static ssize_t xattr_setxattr(const char *path, const char *name, - void *value, ssize_t size, u_int32_t position, - int options) -{ - int rv = 0; - int nofollow; - - if (position != 0) { - return -1; - } - - nofollow = options & XATTR_XATTR_NOFOLLOW; - options &= ~XATTR_XATTR_NOFOLLOW; - - if (options == XATTR_XATTR_CREATE || - options == XATTR_XATTR_REPLACE) { - - /* meh. FreeBSD doesn't really have this in it's - * API... Oh well. - */ - } - else if (options != 0) { - return -1; - } - - if (nofollow) { - rv = extattr_set_link(path, EXTATTR_NAMESPACE_USER, - name, value, size); - } - else { - rv = extattr_set_file(path, EXTATTR_NAMESPACE_USER, - name, value, size); - } - - /* freebsd returns the written length on success, not zero. */ - if (rv >= 0) { - return 0; - } - else { - return rv; - } -} - -static ssize_t xattr_removexattr(const char *path, const char *name, - int options) -{ - if (!(options == 0 || - options == XATTR_XATTR_NOFOLLOW)) { - return -1; - } - - if (options & XATTR_XATTR_NOFOLLOW) { - return extattr_delete_link(path, EXTATTR_NAMESPACE_USER, name); - } - else { - return extattr_delete_file(path, EXTATTR_NAMESPACE_USER, name); - } -} - - -static ssize_t xattr_listxattr(const char *path, char *namebuf, - size_t size, int options) -{ - ssize_t rv = 0; - if (!(options == 0 || - options == XATTR_XATTR_NOFOLLOW)) { - return -1; - } - - if (options & XATTR_XATTR_NOFOLLOW) { - rv = extattr_list_link(path, EXTATTR_NAMESPACE_USER, namebuf, size); - } - else { - rv = extattr_list_file(path, EXTATTR_NAMESPACE_USER, namebuf, size); - } - - if (rv > 0 && namebuf) { - convert_bsd_list(namebuf, rv); - } - - return rv; -} - -static ssize_t xattr_fgetxattr(int fd, const char *name, void *value, - ssize_t size, u_int32_t position, int options) -{ - if (position != 0 || - !(options == 0 || options == XATTR_XATTR_NOFOLLOW)) { - return -1; - } - - if (options & XATTR_XATTR_NOFOLLOW) { - return -1; - } - else { - return extattr_get_fd(fd, EXTATTR_NAMESPACE_USER, name, value, size); - } -} - -static ssize_t xattr_fsetxattr(int fd, const char *name, void *value, - ssize_t size, u_int32_t position, int options) -{ - int rv = 0; - int nofollow; - - if (position != 0) { - return -1; - } - - nofollow = options & XATTR_XATTR_NOFOLLOW; - options &= ~XATTR_XATTR_NOFOLLOW; - - if (options == XATTR_XATTR_CREATE || - options == XATTR_XATTR_REPLACE) { - /* freebsd noop */ - } - else if (options != 0) { - return -1; - } - - if (nofollow) { - return -1; - } - else { - rv = extattr_set_fd(fd, EXTATTR_NAMESPACE_USER, - name, value, size); - } - - /* freebsd returns the written length on success, not zero. */ - if (rv >= 0) { - return 0; - } - else { - return rv; - } -} - -static ssize_t xattr_fremovexattr(int fd, const char *name, int options) -{ - - if (!(options == 0 || - options == XATTR_XATTR_NOFOLLOW)) { - return -1; - } - - if (options & XATTR_XATTR_NOFOLLOW) { - return -1; - } - else { - return extattr_delete_fd(fd, EXTATTR_NAMESPACE_USER, name); - } -} - - -static ssize_t xattr_flistxattr(int fd, char *namebuf, size_t size, int options) -{ - ssize_t rv = 0; - - if (!(options == 0 || - options == XATTR_XATTR_NOFOLLOW)) { - return -1; - } - - if (options & XATTR_XATTR_NOFOLLOW) { - return -1; - } - else { - rv = extattr_list_fd(fd, EXTATTR_NAMESPACE_USER, namebuf, size); - } - - if (rv > 0 && namebuf) { - convert_bsd_list(namebuf, rv); - } - - return rv; -} - -#elif defined(__SUN__) || defined(__sun__) || defined(sun) - -/* Solaris 9 and later compatibility API */ -#define XATTR_XATTR_NOFOLLOW 0x0001 -#define XATTR_XATTR_CREATE 0x0002 -#define XATTR_XATTR_REPLACE 0x0004 -#define XATTR_XATTR_NOSECURITY 0x0008 - -#ifndef u_int32_t -#define u_int32_t uint32_t -#endif - -static ssize_t xattr_fgetxattr(int fd, const char *name, void *value, - ssize_t size, u_int32_t position, int options) -{ - int xfd; - ssize_t bytes; - struct stat statbuf; - - /* XXX should check that name does not have / characters in it */ - xfd = openat(fd, name, O_RDONLY | O_XATTR); - if (xfd == -1) { - return -1; - } - if (lseek(xfd, position, SEEK_SET) == -1) { - close(xfd); - return -1; - } - if (value == NULL) { - if (fstat(xfd, &statbuf) == -1) { - close(xfd); - return -1; - } - close(xfd); - return statbuf.st_size; - } - /* XXX should keep reading until the buffer is exhausted or EOF */ - bytes = read(xfd, value, size); - close(xfd); - return bytes; -} - -static ssize_t xattr_getxattr(const char *path, const char *name, - void *value, ssize_t size, u_int32_t position, - int options) -{ - int fd; - ssize_t bytes; - - if (position != 0 || - !(options == 0 || options == XATTR_XATTR_NOFOLLOW)) { - return -1; - } - - fd = open(path, - O_RDONLY | - ((options & XATTR_XATTR_NOFOLLOW) ? O_NOFOLLOW : 0)); - if (fd == -1) { - return -1; - } - bytes = xattr_fgetxattr(fd, name, value, size, position, options); - close(fd); - return bytes; -} - -static ssize_t xattr_fsetxattr(int fd, const char *name, void *value, - ssize_t size, u_int32_t position, int options) -{ - int xfd; - ssize_t bytes = 0; - - /* XXX should check that name does not have / characters in it */ - xfd = openat(fd, name, O_XATTR | O_TRUNC | - ((options & XATTR_XATTR_CREATE) ? O_EXCL : 0) | - ((options & XATTR_XATTR_NOFOLLOW) ? O_NOFOLLOW : 0) | - ((options & XATTR_XATTR_REPLACE) ? O_RDWR : O_WRONLY|O_CREAT), - 0644); - if (xfd == -1) { - return -1; - } - while (size > 0) { - bytes = write(xfd, value, size); - if (bytes == -1) { - close(xfd); - return -1; - } - size -= bytes; - value += bytes; - } - close(xfd); - return 0; -} - -static ssize_t xattr_setxattr(const char *path, const char *name, - void *value, ssize_t size, u_int32_t position, - int options) -{ - int fd; - ssize_t bytes; - - if (position != 0) { - return -1; - } - - fd = open(path, - O_RDONLY | (options & XATTR_XATTR_NOFOLLOW) ? O_NOFOLLOW : 0); - if (fd == -1) { - return -1; - } - bytes = xattr_fsetxattr(fd, name, value, size, position, options); - close(fd); - return bytes; -} - -static ssize_t xattr_fremovexattr(int fd, const char *name, int options) -{ - int xfd, status; - /* XXX should check that name does not have / characters in it */ - if (!(options == 0 || options == XATTR_XATTR_NOFOLLOW)) { - return -1; - } - if (options & XATTR_XATTR_NOFOLLOW) { - return -1; - } - xfd = openat(fd, ".", O_XATTR, 0644); - if (xfd == -1) { - return -1; - } - status = unlinkat(xfd, name, 0); - close(xfd); - return status; -} - -static ssize_t xattr_removexattr(const char *path, const char *name, - int options) -{ - int fd; - ssize_t status; - - fd = open(path, - O_RDONLY | ((options & XATTR_XATTR_NOFOLLOW) ? O_NOFOLLOW : 0)); - if (fd == -1) { - return -1; - } - status = xattr_fremovexattr(fd, name, options); - close(fd); - return status; -} - -static ssize_t xattr_xflistxattr(int xfd, char *namebuf, size_t size, int options) -{ - int esize; - DIR *dirp; - struct dirent *entry; - ssize_t nsize = 0; - - dirp = fdopendir(xfd); - if (dirp == NULL) { - return (-1); - } - while (entry = readdir(dirp)) { - if (strcmp(entry->d_name, ".") == 0 || - strcmp(entry->d_name, "..") == 0) - continue; - esize = strlen(entry->d_name); - if (nsize + esize + 1 <= size) { - snprintf((char *)(namebuf + nsize), esize + 1, - entry->d_name); - } - nsize += esize + 1; /* +1 for \0 */ - } - closedir(dirp); - return nsize; -} -static ssize_t xattr_flistxattr(int fd, char *namebuf, size_t size, int options) -{ - int xfd; - - xfd = openat(fd, ".", O_RDONLY); - return xattr_xflistxattr(xfd, namebuf, size, options); -} - -static ssize_t xattr_listxattr(const char *path, char *namebuf, - size_t size, int options) -{ - int xfd; - - xfd = attropen(path, ".", O_RDONLY); - return xattr_xflistxattr(xfd, namebuf, size, options); -} - -#elif !defined(XATTR_NOFOLLOW) -/* Linux compatibility API */ -#define XATTR_XATTR_NOFOLLOW 0x0001 -#define XATTR_XATTR_CREATE 0x0002 -#define XATTR_XATTR_REPLACE 0x0004 -#define XATTR_XATTR_NOSECURITY 0x0008 -static ssize_t xattr_getxattr(const char *path, const char *name, void *value, ssize_t size, u_int32_t position, int options) { - if (position != 0 || !(options == 0 || options == XATTR_XATTR_NOFOLLOW)) { - return -1; - } - if (options & XATTR_XATTR_NOFOLLOW) { - return lgetxattr(path, name, value, size); - } else { - return getxattr(path, name, value, size); - } -} - -static ssize_t xattr_setxattr(const char *path, const char *name, void *value, ssize_t size, u_int32_t position, int options) { - int nofollow; - if (position != 0) { - return -1; - } - nofollow = options & XATTR_XATTR_NOFOLLOW; - options &= ~XATTR_XATTR_NOFOLLOW; - if (options == XATTR_XATTR_CREATE) { - options = XATTR_CREATE; - } else if (options == XATTR_XATTR_REPLACE) { - options = XATTR_REPLACE; - } else if (options != 0) { - return -1; - } - if (nofollow) { - return lsetxattr(path, name, value, size, options); - } else { - return setxattr(path, name, value, size, options); - } -} - -static ssize_t xattr_removexattr(const char *path, const char *name, int options) { - if (!(options == 0 || options == XATTR_XATTR_NOFOLLOW)) { - return -1; - } - if (options & XATTR_XATTR_NOFOLLOW) { - return lremovexattr(path, name); - } else { - return removexattr(path, name); - } -} - - -static ssize_t xattr_listxattr(const char *path, char *namebuf, size_t size, int options) { - if (!(options == 0 || options == XATTR_XATTR_NOFOLLOW)) { - return -1; - } - if (options & XATTR_XATTR_NOFOLLOW) { - return llistxattr(path, namebuf, size); - } else { - return listxattr(path, namebuf, size); - } -} - -static ssize_t xattr_fgetxattr(int fd, const char *name, void *value, ssize_t size, u_int32_t position, int options) { - if (position != 0 || !(options == 0 || options == XATTR_XATTR_NOFOLLOW)) { - return -1; - } - if (options & XATTR_XATTR_NOFOLLOW) { - return -1; - } else { - return fgetxattr(fd, name, value, size); - } -} - -static ssize_t xattr_fsetxattr(int fd, const char *name, void *value, ssize_t size, u_int32_t position, int options) { - int nofollow; - if (position != 0) { - return -1; - } - nofollow = options & XATTR_XATTR_NOFOLLOW; - options &= ~XATTR_XATTR_NOFOLLOW; - if (options == XATTR_XATTR_CREATE) { - options = XATTR_CREATE; - } else if (options == XATTR_XATTR_REPLACE) { - options = XATTR_REPLACE; - } else if (options != 0) { - return -1; - } - if (options & XATTR_XATTR_NOFOLLOW) { - return -1; - } else { - return fsetxattr(fd, name, value, size, options); - } -} - -static ssize_t xattr_fremovexattr(int fd, const char *name, int options) { - if (!(options == 0 || options == XATTR_XATTR_NOFOLLOW)) { - return -1; - } - if (options & XATTR_XATTR_NOFOLLOW) { - return -1; - } else { - return fremovexattr(fd, name); - } -} - - -static ssize_t xattr_flistxattr(int fd, char *namebuf, size_t size, int options) { - if (!(options == 0 || options == XATTR_XATTR_NOFOLLOW)) { - return -1; - } - if (options & XATTR_XATTR_NOFOLLOW) { - return -1; - } else { - return flistxattr(fd, namebuf, size); - } -} - -#else /* Mac OS X assumed */ -#define xattr_getxattr getxattr -#define xattr_fgetxattr fgetxattr -#define xattr_removexattr removexattr -#define xattr_fremovexattr fremovexattr -#define xattr_setxattr setxattr -#define xattr_fsetxattr fsetxattr -#define xattr_listxattr listxattr -#define xattr_flistxattr flistxattr -#endif - -static PyObject *xattr_error(void); -static PyObject *xattr_error_with_filename(char *name); - -static PyObject * -xattr_error(void) -{ - return PyErr_SetFromErrno(PyExc_IOError); -} - -static PyObject * -xattr_error_with_filename(char *name) -{ - return PyErr_SetFromErrnoWithFilename(PyExc_IOError, name); -} - -PyDoc_STRVAR(pydoc_getxattr, - "getxattr(path, name, size=0, position=0, options=0) -> str\n" - "\n" - "..." -); -static PyObject* -py_getxattr(PyObject* self __attribute__((__unused__)), PyObject *args) /* , PyObject *kwds) */ -{ - /* static char *keywords[] = { "path", "name", "size", "position", "options", NULL }; */ - char *path; - char *name; - PyObject *buffer; - int options = 0; - size_t size = 0; - u_int32_t position = 0; - ssize_t res; - if (!PyArg_ParseTuple(args, /* AndKeywords(args, kwds, */ - "etet|IIi:getxattr", /* keywords, */ - Py_FileSystemDefaultEncoding, &path, - Py_FileSystemDefaultEncoding, &name, - &size, - &position, - &options)) { - return NULL; - } - if (size == 0) { - Py_BEGIN_ALLOW_THREADS - res = xattr_getxattr((const char *)path, (const char *)name, NULL, 0, position, options); - Py_END_ALLOW_THREADS - if (res == -1) { - PyObject *tmp = xattr_error_with_filename(path); - PyMem_Free(path); - PyMem_Free(name); - return tmp; - } - size = res; - } - buffer = PyString_FromStringAndSize((char *)NULL, size); - if (buffer == NULL) { - PyMem_Free(path); - PyMem_Free(name); - return NULL; - } - Py_BEGIN_ALLOW_THREADS - res = xattr_getxattr((const char *)path, (const char *)name, (void *)PyString_AS_STRING(buffer), size, position, options); - Py_END_ALLOW_THREADS - if (res == -1) { - PyObject *tmp = xattr_error_with_filename(path); - Py_DECREF(buffer); - PyMem_Free(path); - PyMem_Free(name); - return tmp; - } - PyMem_Free(path); - PyMem_Free(name); - if (res != size) { - _PyString_Resize(&buffer, (int)res); - } - return buffer; -} - -PyDoc_STRVAR(pydoc_fgetxattr, - "fgetxattr(fd, name, size=0, position=0, options=0) -> str\n" - "\n" - "..." -); -static PyObject* -py_fgetxattr(PyObject* self __attribute__((__unused__)), PyObject *args) /* , PyObject *kwds) */ -{ - /* static char *keywords[] = { "fd", "name", "size", "position", "options", NULL }; */ - int fd; - char *name; - PyObject *buffer; - int options = 0; - size_t size = 0; - u_int32_t position = 0; - ssize_t res; - if (!PyArg_ParseTuple(args, /* AndKeywords(args, kwds, */ - "iet|IIi:fgetxattr", /* keywords, */ - &fd, - Py_FileSystemDefaultEncoding, &name, - &size, - &position, - &options)) { - return NULL; - } - if (size == 0) { - Py_BEGIN_ALLOW_THREADS - res = xattr_fgetxattr(fd, (const char *)name, NULL, 0, position, options); - Py_END_ALLOW_THREADS - if (res == -1) { - PyMem_Free(name); - return xattr_error(); - } - size = res; - } - buffer = PyString_FromStringAndSize((char *)NULL, size); - if (buffer == NULL) { - PyMem_Free(name); - return NULL; - } - Py_BEGIN_ALLOW_THREADS - res = xattr_fgetxattr(fd, (const char *)name, (void *)PyString_AS_STRING(buffer), size, position, options); - Py_END_ALLOW_THREADS - PyMem_Free(name); - if (res == -1) { - Py_DECREF(buffer); - return xattr_error(); - } - if (res != size) { - _PyString_Resize(&buffer, (int)res); - } - return buffer; -} - -PyDoc_STRVAR(pydoc_setxattr, - "setxattr(path, name, value, position=0, options=0) -> None\n" - "\n" - "..." -); -static PyObject* -py_setxattr(PyObject* self __attribute__((__unused__)), PyObject *args) /* , PyObject *kwds) */ -{ - /* static char *keywords[] = { "path", "name", "value", "position", "options", NULL }; */ - PyObject *result; - char *path; - char *name; - int options = 0; - char *value; - int size; - u_int32_t position = 0; - int res; - if (!PyArg_ParseTuple(args, /* AndKeywords(args, kwds, */ - "etets#|Ii:setxattr", /* keywords, */ - Py_FileSystemDefaultEncoding, &path, - Py_FileSystemDefaultEncoding, &name, - &value, &size, - &position, - &options)) { - return NULL; - } - Py_BEGIN_ALLOW_THREADS - res = xattr_setxattr((const char *)path, (const char *)name, (void *)value, size, position, options); - Py_END_ALLOW_THREADS - if (res) { - result = xattr_error_with_filename(path); - } else { - Py_INCREF(Py_None); - result = Py_None; - } - PyMem_Free(path); - PyMem_Free(name); - return result; -} - -PyDoc_STRVAR(pydoc_fsetxattr, - "fsetxattr(fd, name, value, position=0, options=0) -> None\n" - "\n" - "..." -); -static PyObject* -py_fsetxattr(PyObject* self __attribute__((__unused__)), PyObject *args) /* , PyObject *kwds) */ -{ - /* static char *keywords[] = { "fd", "name", "value", "position", "options", NULL }; */ - int fd; - char *name; - int options = 0; - char *value; - int size; - u_int32_t position = 0; - int res; - if (!PyArg_ParseTuple(args, /* AndKeywords(args, kwds, */ - "iets#|Ii:fsetxattr", /* keywords, */ - &fd, - Py_FileSystemDefaultEncoding, &name, - &value, &size, - &position, - &options)) { - return NULL; - } - Py_BEGIN_ALLOW_THREADS - res = xattr_fsetxattr(fd, (const char *)name, (void *)value, size, position, options); - Py_END_ALLOW_THREADS - PyMem_Free(name); - if (res) { - return xattr_error(); - } - Py_INCREF(Py_None); - return Py_None; -} - -PyDoc_STRVAR(pydoc_removexattr, - "removexattr(path, name, options=0) -> None\n" - "\n" - "..." -); -static PyObject* -py_removexattr(PyObject* self __attribute__((__unused__)), PyObject *args) /* , PyObject *kwds) */ -{ - /* static char *keywords[] = { "path", "name", "options", NULL }; */ - char *path; - char *name; - int options = 0; - int res; - PyObject *result; - if (!PyArg_ParseTuple(args, /* AndKeywords(args, kwds, */ - "etet|i:removexattr", /* keywords, */ - Py_FileSystemDefaultEncoding, &path, - Py_FileSystemDefaultEncoding, &name, - &options)) { - return NULL; - } - Py_BEGIN_ALLOW_THREADS - res = xattr_removexattr((const char *)path, (const char *)name, options); - Py_END_ALLOW_THREADS - if (res) { - result = xattr_error_with_filename(path); - } else { - Py_INCREF(Py_None); - result = Py_None; - } - PyMem_Free(path); - PyMem_Free(name); - return result; -} - -PyDoc_STRVAR(pydoc_fremovexattr, - "fremovexattr(fd, name, options=0) -> None\n" - "\n" - "..." -); -static PyObject* -py_fremovexattr(PyObject* self __attribute__((__unused__)), PyObject *args) /* , PyObject *kwds) */ -{ - /* static char *keywords[] = { "fd", "name", "options", NULL }; */ - int fd; - char *name; - int options = 0; - int res; - if (!PyArg_ParseTuple(args, /* AndKeywords(args, kwds, */ - "iet|i:fremovexattr", /* keywords, */ - &fd, - Py_FileSystemDefaultEncoding, &name, - &options)) { - return NULL; - } - Py_BEGIN_ALLOW_THREADS - res = xattr_fremovexattr(fd, (const char *)name, options); - Py_END_ALLOW_THREADS - PyMem_Free(name); - if (res) { - return xattr_error(); - } - Py_INCREF(Py_None); - return Py_None; -} - -PyDoc_STRVAR(pydoc_listxattr, - "listxattr(path, options=0) -> str\n" - "\n" - "..." -); -static PyObject* -py_listxattr(PyObject* self __attribute__((__unused__)), PyObject *args) /* , PyObject *kwds) */ -{ - /* static char *keywords[] = { "path", "options", NULL }; */ - PyObject *buffer; - char *path; - int options = 0; - ssize_t res; - if (!PyArg_ParseTuple(args, /* AndKeywords(args, kwds, */ - "et|i:listxattr", /* keywords, */ - Py_FileSystemDefaultEncoding, &path, - &options)) { - return NULL; - } - Py_BEGIN_ALLOW_THREADS - res = xattr_listxattr((const char *)path, NULL, 0, options); - Py_END_ALLOW_THREADS - if (res == -1) { - PyObject *tmp = xattr_error_with_filename(path); - PyMem_Free(path); - return tmp; - } - buffer = PyString_FromStringAndSize((char *)NULL, (int)res); - if (buffer == NULL) { - PyMem_Free(path); - return NULL; - } - /* avoid 2nd listxattr call if the first one returns 0 */ - if (res == 0) { - PyMem_Free(path); - return buffer; - } - Py_BEGIN_ALLOW_THREADS - res = xattr_listxattr((const char *)path, (void *)PyString_AS_STRING(buffer), (size_t)PyString_GET_SIZE(buffer), options); - Py_END_ALLOW_THREADS - if (res == -1) { - PyObject *tmp = xattr_error_with_filename(path); - Py_DECREF(buffer); - PyMem_Free(path); - return tmp; - } - PyMem_Free(path); - if (res != (ssize_t)PyString_GET_SIZE(buffer)) { - _PyString_Resize(&buffer, (int)res); - } - return buffer; -} - -PyDoc_STRVAR(pydoc_flistxattr, - "flistxattr(fd, options=0) -> str\n" - "\n" - "..." -); -static PyObject* -py_flistxattr(PyObject* self __attribute__((__unused__)), PyObject *args) /* , PyObject *kwds) */ -{ - /* static char *keywords[] = { "fd", "options", NULL }; */ - PyObject *buffer; - int fd; - int options = 0; - ssize_t res; - if (!PyArg_ParseTuple(args, /* AndKeywords(args, kwds, */ - "i|i:flistxattr", /* keywords, */ - &fd, - &options)) { - return NULL; - } - Py_BEGIN_ALLOW_THREADS - res = xattr_flistxattr(fd, NULL, 0, options); - Py_END_ALLOW_THREADS - if (res == -1) { - return xattr_error(); - } - buffer = PyString_FromStringAndSize((char *)NULL, (int)res); - if (buffer == NULL) { - return NULL; - } - Py_BEGIN_ALLOW_THREADS - res = xattr_flistxattr(fd, (void *)PyString_AS_STRING(buffer), (size_t)PyString_GET_SIZE(buffer), options); - Py_END_ALLOW_THREADS - if (res == -1) { - Py_DECREF(buffer); - return xattr_error(); - } - if (res != (ssize_t)PyString_GET_SIZE(buffer)) { - _PyString_Resize(&buffer, (int)res); - } - return buffer; -} - - -#define DEFN(n) \ - { \ - #n, \ - (PyCFunction)py_ ##n, \ - METH_VARARGS /* | METH_KEYWORDS */, \ - pydoc_ ##n \ - } -static PyMethodDef xattr_methods[] = { - DEFN(getxattr), - DEFN(fgetxattr), - DEFN(setxattr), - DEFN(fsetxattr), - DEFN(removexattr), - DEFN(fremovexattr), - DEFN(listxattr), - DEFN(flistxattr), - {} -}; -#undef DEFN - -void init_xattr(void); - -void -init_xattr(void) -{ - PyObject *m; - m = Py_InitModule4("_xattr", xattr_methods, NULL, NULL, PYTHON_API_VERSION); -} diff --git a/xattr/lib.py b/xattr/lib.py new file mode 100644 index 0000000..11af84c --- /dev/null +++ b/xattr/lib.py @@ -0,0 +1,714 @@ +import os +import sys + +import cffi + +ffi = cffi.FFI() +ffi.cdef(""" +#define XATTR_NOFOLLOW ... +#define XATTR_CREATE ... +#define XATTR_REPLACE ... +#define XATTR_NOSECURITY ... +#define XATTR_MAXNAMELEN ... +#define XATTR_FINDERINFO_NAME ... +#define XATTR_RESOURCEFORK_NAME ... + +ssize_t xattr_getxattr(const char *, const char *, void *, ssize_t, uint32_t, int); +ssize_t xattr_fgetxattr(int, const char *, void *, ssize_t, uint32_t, int); + +ssize_t xattr_setxattr(const char *, const char *, void *, ssize_t, uint32_t, int); +ssize_t xattr_fsetxattr(int, const char *, void *, ssize_t, uint32_t, int); + +ssize_t xattr_removexattr(const char *, const char *, int); +ssize_t xattr_fremovexattr(int, const char *, int); + +ssize_t xattr_listxattr(const char *, char *, size_t, int); +ssize_t xattr_flistxattr(int, char *, size_t, int); + +""") + +lib = ffi.verify(""" +#include "Python.h" +#ifdef __FreeBSD__ +#include +#elif defined(__SUN__) || defined(__sun__) || defined(sun) +#include +#include +#include +#include +#include +#else +#include +#endif + +#ifdef __FreeBSD__ + +/* FreeBSD compatibility API */ +#define XATTR_XATTR_NOFOLLOW 0x0001 +#define XATTR_XATTR_CREATE 0x0002 +#define XATTR_XATTR_REPLACE 0x0004 +#define XATTR_XATTR_NOSECURITY 0x0008 + + +/* Converts a freebsd format attribute list into a NULL terminated list. + * While the man page on extattr_list_file says it is NULL terminated, + * it is actually the first byte that is the length of the + * following attribute. + */ +static void convert_bsd_list(char *namebuf, size_t size) +{ + size_t offset = 0; + while(offset < size) { + int length = (int) namebuf[offset]; + memmove(namebuf+offset, namebuf+offset+1, length); + namebuf[offset+length] = '\0'; + offset += length+1; + } +} + +static ssize_t xattr_getxattr(const char *path, const char *name, + void *value, ssize_t size, u_int32_t position, + int options) +{ + if (position != 0 || + !(options == 0 || options == XATTR_XATTR_NOFOLLOW)) { + return -1; + } + + if (options & XATTR_XATTR_NOFOLLOW) { + return extattr_get_link(path, EXTATTR_NAMESPACE_USER, + name, value, size); + } + else { + return extattr_get_file(path, EXTATTR_NAMESPACE_USER, + name, value, size); + } +} + +static ssize_t xattr_setxattr(const char *path, const char *name, + void *value, ssize_t size, u_int32_t position, + int options) +{ + int rv = 0; + int nofollow; + + if (position != 0) { + return -1; + } + + nofollow = options & XATTR_XATTR_NOFOLLOW; + options &= ~XATTR_XATTR_NOFOLLOW; + + if (options == XATTR_XATTR_CREATE || + options == XATTR_XATTR_REPLACE) { + + /* meh. FreeBSD doesn't really have this in it's + * API... Oh well. + */ + } + else if (options != 0) { + return -1; + } + + if (nofollow) { + rv = extattr_set_link(path, EXTATTR_NAMESPACE_USER, + name, value, size); + } + else { + rv = extattr_set_file(path, EXTATTR_NAMESPACE_USER, + name, value, size); + } + + /* freebsd returns the written length on success, not zero. */ + if (rv >= 0) { + return 0; + } + else { + return rv; + } +} + +static ssize_t xattr_removexattr(const char *path, const char *name, + int options) +{ + if (!(options == 0 || + options == XATTR_XATTR_NOFOLLOW)) { + return -1; + } + + if (options & XATTR_XATTR_NOFOLLOW) { + return extattr_delete_link(path, EXTATTR_NAMESPACE_USER, name); + } + else { + return extattr_delete_file(path, EXTATTR_NAMESPACE_USER, name); + } +} + + +static ssize_t xattr_listxattr(const char *path, char *namebuf, + size_t size, int options) +{ + ssize_t rv = 0; + if (!(options == 0 || + options == XATTR_XATTR_NOFOLLOW)) { + return -1; + } + + if (options & XATTR_XATTR_NOFOLLOW) { + rv = extattr_list_link(path, EXTATTR_NAMESPACE_USER, namebuf, size); + } + else { + rv = extattr_list_file(path, EXTATTR_NAMESPACE_USER, namebuf, size); + } + + if (rv > 0 && namebuf) { + convert_bsd_list(namebuf, rv); + } + + return rv; +} + +static ssize_t xattr_fgetxattr(int fd, const char *name, void *value, + ssize_t size, u_int32_t position, int options) +{ + if (position != 0 || + !(options == 0 || options == XATTR_XATTR_NOFOLLOW)) { + return -1; + } + + if (options & XATTR_XATTR_NOFOLLOW) { + return -1; + } + else { + return extattr_get_fd(fd, EXTATTR_NAMESPACE_USER, name, value, size); + } +} + +static ssize_t xattr_fsetxattr(int fd, const char *name, void *value, + ssize_t size, u_int32_t position, int options) +{ + int rv = 0; + int nofollow; + + if (position != 0) { + return -1; + } + + nofollow = options & XATTR_XATTR_NOFOLLOW; + options &= ~XATTR_XATTR_NOFOLLOW; + + if (options == XATTR_XATTR_CREATE || + options == XATTR_XATTR_REPLACE) { + /* freebsd noop */ + } + else if (options != 0) { + return -1; + } + + if (nofollow) { + return -1; + } + else { + rv = extattr_set_fd(fd, EXTATTR_NAMESPACE_USER, + name, value, size); + } + + /* freebsd returns the written length on success, not zero. */ + if (rv >= 0) { + return 0; + } + else { + return rv; + } +} + +static ssize_t xattr_fremovexattr(int fd, const char *name, int options) +{ + + if (!(options == 0 || + options == XATTR_XATTR_NOFOLLOW)) { + return -1; + } + + if (options & XATTR_XATTR_NOFOLLOW) { + return -1; + } + else { + return extattr_delete_fd(fd, EXTATTR_NAMESPACE_USER, name); + } +} + + +static ssize_t xattr_flistxattr(int fd, char *namebuf, size_t size, int options) +{ + ssize_t rv = 0; + + if (!(options == 0 || + options == XATTR_XATTR_NOFOLLOW)) { + return -1; + } + + if (options & XATTR_XATTR_NOFOLLOW) { + return -1; + } + else { + rv = extattr_list_fd(fd, EXTATTR_NAMESPACE_USER, namebuf, size); + } + + if (rv > 0 && namebuf) { + convert_bsd_list(namebuf, rv); + } + + return rv; +} + +#elif defined(__SUN__) || defined(__sun__) || defined(sun) + +/* Solaris 9 and later compatibility API */ +#define XATTR_XATTR_NOFOLLOW 0x0001 +#define XATTR_XATTR_CREATE 0x0002 +#define XATTR_XATTR_REPLACE 0x0004 +#define XATTR_XATTR_NOSECURITY 0x0008 + +#ifndef u_int32_t +#define u_int32_t uint32_t +#endif + +static ssize_t xattr_fgetxattr(int fd, const char *name, void *value, + ssize_t size, u_int32_t position, int options) +{ + int xfd; + ssize_t bytes; + struct stat statbuf; + + /* XXX should check that name does not have / characters in it */ + xfd = openat(fd, name, O_RDONLY | O_XATTR); + if (xfd == -1) { + return -1; + } + if (lseek(xfd, position, SEEK_SET) == -1) { + close(xfd); + return -1; + } + if (value == NULL) { + if (fstat(xfd, &statbuf) == -1) { + close(xfd); + return -1; + } + close(xfd); + return statbuf.st_size; + } + /* XXX should keep reading until the buffer is exhausted or EOF */ + bytes = read(xfd, value, size); + close(xfd); + return bytes; +} + +static ssize_t xattr_getxattr(const char *path, const char *name, + void *value, ssize_t size, u_int32_t position, + int options) +{ + int fd; + ssize_t bytes; + + if (position != 0 || + !(options == 0 || options == XATTR_XATTR_NOFOLLOW)) { + return -1; + } + + fd = open(path, + O_RDONLY | + ((options & XATTR_XATTR_NOFOLLOW) ? O_NOFOLLOW : 0)); + if (fd == -1) { + return -1; + } + bytes = xattr_fgetxattr(fd, name, value, size, position, options); + close(fd); + return bytes; +} + +static ssize_t xattr_fsetxattr(int fd, const char *name, void *value, + ssize_t size, u_int32_t position, int options) +{ + int xfd; + ssize_t bytes = 0; + + /* XXX should check that name does not have / characters in it */ + xfd = openat(fd, name, O_XATTR | O_TRUNC | + ((options & XATTR_XATTR_CREATE) ? O_EXCL : 0) | + ((options & XATTR_XATTR_NOFOLLOW) ? O_NOFOLLOW : 0) | + ((options & XATTR_XATTR_REPLACE) ? O_RDWR : O_WRONLY|O_CREAT), + 0644); + if (xfd == -1) { + return -1; + } + while (size > 0) { + bytes = write(xfd, value, size); + if (bytes == -1) { + close(xfd); + return -1; + } + size -= bytes; + value += bytes; + } + close(xfd); + return 0; +} + +static ssize_t xattr_setxattr(const char *path, const char *name, + void *value, ssize_t size, u_int32_t position, + int options) +{ + int fd; + ssize_t bytes; + + if (position != 0) { + return -1; + } + + fd = open(path, + O_RDONLY | (options & XATTR_XATTR_NOFOLLOW) ? O_NOFOLLOW : 0); + if (fd == -1) { + return -1; + } + bytes = xattr_fsetxattr(fd, name, value, size, position, options); + close(fd); + return bytes; +} + +static ssize_t xattr_fremovexattr(int fd, const char *name, int options) +{ + int xfd, status; + /* XXX should check that name does not have / characters in it */ + if (!(options == 0 || options == XATTR_XATTR_NOFOLLOW)) { + return -1; + } + if (options & XATTR_XATTR_NOFOLLOW) { + return -1; + } + xfd = openat(fd, ".", O_XATTR, 0644); + if (xfd == -1) { + return -1; + } + status = unlinkat(xfd, name, 0); + close(xfd); + return status; +} + +static ssize_t xattr_removexattr(const char *path, const char *name, + int options) +{ + int fd; + ssize_t status; + + fd = open(path, + O_RDONLY | ((options & XATTR_XATTR_NOFOLLOW) ? O_NOFOLLOW : 0)); + if (fd == -1) { + return -1; + } + status = xattr_fremovexattr(fd, name, options); + close(fd); + return status; +} + +static ssize_t xattr_xflistxattr(int xfd, char *namebuf, size_t size, int options) +{ + int esize; + DIR *dirp; + struct dirent *entry; + ssize_t nsize = 0; + + dirp = fdopendir(xfd); + if (dirp == NULL) { + return (-1); + } + while (entry = readdir(dirp)) { + if (strcmp(entry->d_name, ".") == 0 || + strcmp(entry->d_name, "..") == 0) + continue; + esize = strlen(entry->d_name); + if (nsize + esize + 1 <= size) { + snprintf((char *)(namebuf + nsize), esize + 1, + entry->d_name); + } + nsize += esize + 1; /* +1 for \0 */ + } + closedir(dirp); + return nsize; +} +static ssize_t xattr_flistxattr(int fd, char *namebuf, size_t size, int options) +{ + int xfd; + + xfd = openat(fd, ".", O_RDONLY); + return xattr_xflistxattr(xfd, namebuf, size, options); +} + +static ssize_t xattr_listxattr(const char *path, char *namebuf, + size_t size, int options) +{ + int xfd; + + xfd = attropen(path, ".", O_RDONLY); + return xattr_xflistxattr(xfd, namebuf, size, options); +} + +#elif !defined(XATTR_NOFOLLOW) +/* Linux compatibility API */ +#define XATTR_XATTR_NOFOLLOW 0x0001 +#define XATTR_XATTR_CREATE 0x0002 +#define XATTR_XATTR_REPLACE 0x0004 +#define XATTR_XATTR_NOSECURITY 0x0008 +static ssize_t xattr_getxattr(const char *path, const char *name, void *value, ssize_t size, u_int32_t position, int options) { + if (position != 0 || !(options == 0 || options == XATTR_XATTR_NOFOLLOW)) { + return -1; + } + if (options & XATTR_XATTR_NOFOLLOW) { + return lgetxattr(path, name, value, size); + } else { + return getxattr(path, name, value, size); + } +} + +static ssize_t xattr_setxattr(const char *path, const char *name, void *value, ssize_t size, u_int32_t position, int options) { + int nofollow; + if (position != 0) { + return -1; + } + nofollow = options & XATTR_XATTR_NOFOLLOW; + options &= ~XATTR_XATTR_NOFOLLOW; + if (options == XATTR_XATTR_CREATE) { + options = XATTR_CREATE; + } else if (options == XATTR_XATTR_REPLACE) { + options = XATTR_REPLACE; + } else if (options != 0) { + return -1; + } + if (nofollow) { + return lsetxattr(path, name, value, size, options); + } else { + return setxattr(path, name, value, size, options); + } +} + +static ssize_t xattr_removexattr(const char *path, const char *name, int options) { + if (!(options == 0 || options == XATTR_XATTR_NOFOLLOW)) { + return -1; + } + if (options & XATTR_XATTR_NOFOLLOW) { + return lremovexattr(path, name); + } else { + return removexattr(path, name); + } +} + + +static ssize_t xattr_listxattr(const char *path, char *namebuf, size_t size, int options) { + if (!(options == 0 || options == XATTR_XATTR_NOFOLLOW)) { + return -1; + } + if (options & XATTR_XATTR_NOFOLLOW) { + return llistxattr(path, namebuf, size); + } else { + return listxattr(path, namebuf, size); + } +} + +static ssize_t xattr_fgetxattr(int fd, const char *name, void *value, ssize_t size, u_int32_t position, int options) { + if (position != 0 || !(options == 0 || options == XATTR_XATTR_NOFOLLOW)) { + return -1; + } + if (options & XATTR_XATTR_NOFOLLOW) { + return -1; + } else { + return fgetxattr(fd, name, value, size); + } +} + +static ssize_t xattr_fsetxattr(int fd, const char *name, void *value, ssize_t size, u_int32_t position, int options) { + int nofollow; + if (position != 0) { + return -1; + } + nofollow = options & XATTR_XATTR_NOFOLLOW; + options &= ~XATTR_XATTR_NOFOLLOW; + if (options == XATTR_XATTR_CREATE) { + options = XATTR_CREATE; + } else if (options == XATTR_XATTR_REPLACE) { + options = XATTR_REPLACE; + } else if (options != 0) { + return -1; + } + if (options & XATTR_XATTR_NOFOLLOW) { + return -1; + } else { + return fsetxattr(fd, name, value, size, options); + } +} + +static ssize_t xattr_fremovexattr(int fd, const char *name, int options) { + if (!(options == 0 || options == XATTR_XATTR_NOFOLLOW)) { + return -1; + } + if (options & XATTR_XATTR_NOFOLLOW) { + return -1; + } else { + return fremovexattr(fd, name); + } +} + + +static ssize_t xattr_flistxattr(int fd, char *namebuf, size_t size, int options) { + if (!(options == 0 || options == XATTR_XATTR_NOFOLLOW)) { + return -1; + } + if (options & XATTR_XATTR_NOFOLLOW) { + return -1; + } else { + return flistxattr(fd, namebuf, size); + } +} + +#else /* Mac OS X assumed */ +#define xattr_getxattr getxattr +#define xattr_fgetxattr fgetxattr +#define xattr_removexattr removexattr +#define xattr_fremovexattr fremovexattr +#define xattr_setxattr setxattr +#define xattr_fsetxattr fsetxattr +#define xattr_listxattr listxattr +#define xattr_flistxattr flistxattr +#endif +""") + +XATTR_NOFOLLOW = lib.XATTR_NOFOLLOW +XATTR_CREATE = lib.XATTR_CREATE +XATTR_REPLACE = lib.XATTR_REPLACE +XATTR_NOSECURITY = lib.XATTR_NOSECURITY +XATTR_MAXNAMELEN = lib.XATTR_MAXNAMELEN +XATTR_FINDERINFO_NAME = lib.XATTR_FINDERINFO_NAME +XATTR_RESOURCEFORK_NAME = lib.XATTR_RESOURCEFORK_NAME + + +def fs_encode(val): + if isinstance(val, bytes): + return val.encode(sys.getfilesystemencoding()) + else: + return val + + +def error(path=None): + errno = ffi.errno + strerror = os.strerror(ffi.errno) + if path: + raise IOError(errno, strerror, path) + else: + raise IOError(errno, strerror) + + +def _getxattr(path, name, size=0, position=0, options=0): + """ + getxattr(path, name, size=0, position=0, options=0) -> str + """ + path = fs_encode(path) + name = fs_encode(name) + if size == 0: + res = lib.xattr_getxattr(path, name, ffi.NULL, 0, position, options) + if res == -1: + raise error(path) + size = res + buf = ffi.new("char[]", size) + res = lib.xattr_getxattr(path, name, buf, size, position, options) + if res == -1: + raise error(path) + return ffi.buffer(buf)[:res] + + +def _fgetxattr(fd, name, size=0, position=0, options=0): + """ + fgetxattr(fd, name, size=0, position=0, options=0) -> str + """ + name = fs_encode(name) + if size == 0: + res = lib.xattr_fgetxattr(fd, name, ffi.NULL, 0, position, options) + if res == -1: + raise error() + size = res + buf = ffi.new("char[]", size) + res = lib.xattr_fgetxattr(fd, name, buf, size, position, options) + if res == -1: + raise error() + return ffi.buffer(buf)[:res] + + +def _setxattr(path, name, value, position=0, options=0): + """ + setxattr(path, name, value, position=0, options=0) -> None + """ + path = fs_encode(path) + name = fs_encode(name) + res = lib.xattr_setxattr(path, name, value, len(value), position, options) + if res: + raise error(path) + + +def _fsetxattr(fd, name, value, position=0, options=0): + """ + fsetxattr(fd, name, value, position=0, options=0) -> None + """ + name = fs_encode(name) + res = lib.xattr_fsetxattr(fd, name, value, len(value), position, options) + if res: + raise error() + + +def _removexattr(path, name, options=0): + """ + removexattr(path, name, options=0) -> None + """ + path = fs_encode(path) + name = fs_encode(name) + res = lib.xattr_removexattr(path, name, options) + if res: + raise error(path) + + +def _fremovexattr(fd, name, options=0): + """ + fremovexattr(fd, name, options=0) -> None + """ + name = fs_encode(name) + res = lib.xattr_fremovexattr(fd, name, options) + if res: + raise error() + + +def _listxattr(path, options=0): + """ + listxattr(path, options=0) -> str + """ + path = fs_encode(path) + res = lib.xattr_listxattr(path, ffi.NULL, 0, options) + if res == -1: + raise error(path) + elif res == 0: + return b"" + buf = ffi.new("char[]", res) + res = lib.xattr_listxattr(path, buf, res, options) + if res == -1: + raise error(path) + return ffi.buffer(buf)[:res] + + +def _flistxattr(fd, options=0): + """ + flistxattr(fd, options=0) -> str + """ + res = lib.xattr_flistxattr(fd, ffi.NULL, 0, options) + if res == 1: + raise error() + buf = ffi.new("char[]", res) + res = lib.xattr_flistxattr(fd, buf, res, options) + if res == -1: + raise error() + return ffi.buffer(buf)[:res] diff --git a/xattr/tests/test_xattr.py b/xattr/tests/test_xattr.py index 3a920ec..d75d7ee 100644 --- a/xattr/tests/test_xattr.py +++ b/xattr/tests/test_xattr.py @@ -4,15 +4,9 @@ from tempfile import mkdtemp, NamedTemporaryFile import xattr -class TestFile(TestCase): - def setUp(self): - self.tempfile = NamedTemporaryFile() - self.tempfilename = self.tempfile.name - - def tearDown(self): - self.tempfile.close() - def testAttr(self): +class BaseTestXattr(object): + def test_attr(self): x = xattr.xattr(self.tempfile) self.assertEqual(x.keys(), []) self.assertEqual(dict(x), {}) @@ -33,7 +27,7 @@ class TestFile(TestCase): x = xattr.xattr(self.tempfile) self.assertTrue('user.sop.foo' not in x) - def testSymlinkAttrs(self): + def test_symlink_attrs(self): symlinkPath = self.tempfilename + '.link' os.symlink(self.tempfilename, symlinkPath) try: @@ -45,7 +39,17 @@ class TestFile(TestCase): finally: os.remove(symlinkPath) -class TestDir(TestFile): + +class TestFile(TestCase, BaseTestXattr): + def setUp(self): + self.tempfile = NamedTemporaryFile() + self.tempfilename = self.tempfile.name + + def tearDown(self): + self.tempfile.close() + + +class TestDir(TestCase, BaseTestXattr): def setUp(self): self.tempfile = mkdtemp() self.tempfilename = self.tempfile -- cgit v1.2.1 From a779afd2e8847c57fb4b4fe9d768d613ab79528e Mon Sep 17 00:00:00 2001 From: Alex Gaynor Date: Thu, 18 Jul 2013 15:42:05 -0700 Subject: update the setup.py --- ez_setup.py | 284 ------------------------------------------------------------ setup.py | 10 +-- 2 files changed, 5 insertions(+), 289 deletions(-) delete mode 100644 ez_setup.py diff --git a/ez_setup.py b/ez_setup.py deleted file mode 100644 index b74adc0..0000000 --- a/ez_setup.py +++ /dev/null @@ -1,284 +0,0 @@ -#!python -"""Bootstrap setuptools installation - -If you want to use setuptools in your package's setup.py, just include this -file in the same directory with it, and add this to the top of your setup.py:: - - from ez_setup import use_setuptools - use_setuptools() - -If you want to require a specific version of setuptools, set a download -mirror, or use an alternate download directory, you can do so by supplying -the appropriate options to ``use_setuptools()``. - -This file can also be run as a script to install or upgrade setuptools. -""" -import sys -DEFAULT_VERSION = "0.6c11" -DEFAULT_URL = "http://pypi.python.org/packages/%s/s/setuptools/" % sys.version[:3] - -md5_data = { - 'setuptools-0.6b1-py2.3.egg': '8822caf901250d848b996b7f25c6e6ca', - 'setuptools-0.6b1-py2.4.egg': 'b79a8a403e4502fbb85ee3f1941735cb', - 'setuptools-0.6b2-py2.3.egg': '5657759d8a6d8fc44070a9d07272d99b', - 'setuptools-0.6b2-py2.4.egg': '4996a8d169d2be661fa32a6e52e4f82a', - 'setuptools-0.6b3-py2.3.egg': 'bb31c0fc7399a63579975cad9f5a0618', - 'setuptools-0.6b3-py2.4.egg': '38a8c6b3d6ecd22247f179f7da669fac', - 'setuptools-0.6b4-py2.3.egg': '62045a24ed4e1ebc77fe039aa4e6f7e5', - 'setuptools-0.6b4-py2.4.egg': '4cb2a185d228dacffb2d17f103b3b1c4', - 'setuptools-0.6c1-py2.3.egg': 'b3f2b5539d65cb7f74ad79127f1a908c', - 'setuptools-0.6c1-py2.4.egg': 'b45adeda0667d2d2ffe14009364f2a4b', - 'setuptools-0.6c10-py2.3.egg': 'ce1e2ab5d3a0256456d9fc13800a7090', - 'setuptools-0.6c10-py2.4.egg': '57d6d9d6e9b80772c59a53a8433a5dd4', - 'setuptools-0.6c10-py2.5.egg': 'de46ac8b1c97c895572e5e8596aeb8c7', - 'setuptools-0.6c10-py2.6.egg': '58ea40aef06da02ce641495523a0b7f5', - 'setuptools-0.6c11-py2.3.egg': '2baeac6e13d414a9d28e7ba5b5a596de', - 'setuptools-0.6c11-py2.4.egg': 'bd639f9b0eac4c42497034dec2ec0c2b', - 'setuptools-0.6c11-py2.5.egg': '64c94f3bf7a72a13ec83e0b24f2749b2', - 'setuptools-0.6c11-py2.6.egg': 'bfa92100bd772d5a213eedd356d64086', - 'setuptools-0.6c2-py2.3.egg': 'f0064bf6aa2b7d0f3ba0b43f20817c27', - 'setuptools-0.6c2-py2.4.egg': '616192eec35f47e8ea16cd6a122b7277', - 'setuptools-0.6c3-py2.3.egg': 'f181fa125dfe85a259c9cd6f1d7b78fa', - 'setuptools-0.6c3-py2.4.egg': 'e0ed74682c998bfb73bf803a50e7b71e', - 'setuptools-0.6c3-py2.5.egg': 'abef16fdd61955514841c7c6bd98965e', - 'setuptools-0.6c4-py2.3.egg': 'b0b9131acab32022bfac7f44c5d7971f', - 'setuptools-0.6c4-py2.4.egg': '2a1f9656d4fbf3c97bf946c0a124e6e2', - 'setuptools-0.6c4-py2.5.egg': '8f5a052e32cdb9c72bcf4b5526f28afc', - 'setuptools-0.6c5-py2.3.egg': 'ee9fd80965da04f2f3e6b3576e9d8167', - 'setuptools-0.6c5-py2.4.egg': 'afe2adf1c01701ee841761f5bcd8aa64', - 'setuptools-0.6c5-py2.5.egg': 'a8d3f61494ccaa8714dfed37bccd3d5d', - 'setuptools-0.6c6-py2.3.egg': '35686b78116a668847237b69d549ec20', - 'setuptools-0.6c6-py2.4.egg': '3c56af57be3225019260a644430065ab', - 'setuptools-0.6c6-py2.5.egg': 'b2f8a7520709a5b34f80946de5f02f53', - 'setuptools-0.6c7-py2.3.egg': '209fdf9adc3a615e5115b725658e13e2', - 'setuptools-0.6c7-py2.4.egg': '5a8f954807d46a0fb67cf1f26c55a82e', - 'setuptools-0.6c7-py2.5.egg': '45d2ad28f9750e7434111fde831e8372', - 'setuptools-0.6c8-py2.3.egg': '50759d29b349db8cfd807ba8303f1902', - 'setuptools-0.6c8-py2.4.egg': 'cba38d74f7d483c06e9daa6070cce6de', - 'setuptools-0.6c8-py2.5.egg': '1721747ee329dc150590a58b3e1ac95b', - 'setuptools-0.6c9-py2.3.egg': 'a83c4020414807b496e4cfbe08507c03', - 'setuptools-0.6c9-py2.4.egg': '260a2be2e5388d66bdaee06abec6342a', - 'setuptools-0.6c9-py2.5.egg': 'fe67c3e5a17b12c0e7c541b7ea43a8e6', - 'setuptools-0.6c9-py2.6.egg': 'ca37b1ff16fa2ede6e19383e7b59245a', -} - -import sys, os -try: from hashlib import md5 -except ImportError: from md5 import md5 - -def _validate_md5(egg_name, data): - if egg_name in md5_data: - digest = md5(data).hexdigest() - if digest != md5_data[egg_name]: - print >>sys.stderr, ( - "md5 validation of %s failed! (Possible download problem?)" - % egg_name - ) - sys.exit(2) - return data - -def use_setuptools( - version=DEFAULT_VERSION, download_base=DEFAULT_URL, to_dir=os.curdir, - download_delay=15 -): - """Automatically find/download setuptools and make it available on sys.path - - `version` should be a valid setuptools version number that is available - as an egg for download under the `download_base` URL (which should end with - a '/'). `to_dir` is the directory where setuptools will be downloaded, if - it is not already available. If `download_delay` is specified, it should - be the number of seconds that will be paused before initiating a download, - should one be required. If an older version of setuptools is installed, - this routine will print a message to ``sys.stderr`` and raise SystemExit in - an attempt to abort the calling script. - """ - was_imported = 'pkg_resources' in sys.modules or 'setuptools' in sys.modules - def do_download(): - egg = download_setuptools(version, download_base, to_dir, download_delay) - sys.path.insert(0, egg) - import setuptools; setuptools.bootstrap_install_from = egg - try: - import pkg_resources - except ImportError: - return do_download() - try: - pkg_resources.require("setuptools>="+version); return - except pkg_resources.VersionConflict, e: - if was_imported: - print >>sys.stderr, ( - "The required version of setuptools (>=%s) is not available, and\n" - "can't be installed while this script is running. Please install\n" - " a more recent version first, using 'easy_install -U setuptools'." - "\n\n(Currently using %r)" - ) % (version, e.args[0]) - sys.exit(2) - except pkg_resources.DistributionNotFound: - pass - - del pkg_resources, sys.modules['pkg_resources'] # reload ok - return do_download() - -def download_setuptools( - version=DEFAULT_VERSION, download_base=DEFAULT_URL, to_dir=os.curdir, - delay = 15 -): - """Download setuptools from a specified location and return its filename - - `version` should be a valid setuptools version number that is available - as an egg for download under the `download_base` URL (which should end - with a '/'). `to_dir` is the directory where the egg will be downloaded. - `delay` is the number of seconds to pause before an actual download attempt. - """ - import urllib2, shutil - egg_name = "setuptools-%s-py%s.egg" % (version,sys.version[:3]) - url = download_base + egg_name - saveto = os.path.join(to_dir, egg_name) - src = dst = None - if not os.path.exists(saveto): # Avoid repeated downloads - try: - from distutils import log - if delay: - log.warn(""" ---------------------------------------------------------------------------- -This script requires setuptools version %s to run (even to display -help). I will attempt to download it for you (from -%s), but -you may need to enable firewall access for this script first. -I will start the download in %d seconds. - -(Note: if this machine does not have network access, please obtain the file - - %s - -and place it in this directory before rerunning this script.) ----------------------------------------------------------------------------""", - version, download_base, delay, url - ); from time import sleep; sleep(delay) - log.warn("Downloading %s", url) - src = urllib2.urlopen(url) - # Read/write all in one block, so we don't create a corrupt file - # if the download is interrupted. - data = _validate_md5(egg_name, src.read()) - dst = open(saveto,"wb"); dst.write(data) - finally: - if src: src.close() - if dst: dst.close() - return os.path.realpath(saveto) - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -def main(argv, version=DEFAULT_VERSION): - """Install or upgrade setuptools and EasyInstall""" - try: - import setuptools - except ImportError: - egg = None - try: - egg = download_setuptools(version, delay=0) - sys.path.insert(0,egg) - from setuptools.command.easy_install import main - return main(list(argv)+[egg]) # we're done here - finally: - if egg and os.path.exists(egg): - os.unlink(egg) - else: - if setuptools.__version__ == '0.0.1': - print >>sys.stderr, ( - "You have an obsolete version of setuptools installed. Please\n" - "remove it from your system entirely before rerunning this script." - ) - sys.exit(2) - - req = "setuptools>="+version - import pkg_resources - try: - pkg_resources.require(req) - except pkg_resources.VersionConflict: - try: - from setuptools.command.easy_install import main - except ImportError: - from easy_install import main - main(list(argv)+[download_setuptools(delay=0)]) - sys.exit(0) # try to force an exit - else: - if argv: - from setuptools.command.easy_install import main - main(argv) - else: - print "Setuptools version",version,"or greater has been installed." - print '(Run "ez_setup.py -U setuptools" to reinstall or upgrade.)' - -def update_md5(filenames): - """Update our built-in md5 registry""" - - import re - - for name in filenames: - base = os.path.basename(name) - f = open(name,'rb') - md5_data[base] = md5(f.read()).hexdigest() - f.close() - - data = [" %r: %r,\n" % it for it in md5_data.items()] - data.sort() - repl = "".join(data) - - import inspect - srcfile = inspect.getsourcefile(sys.modules[__name__]) - f = open(srcfile, 'rb'); src = f.read(); f.close() - - match = re.search("\nmd5_data = {\n([^}]+)}", src) - if not match: - print >>sys.stderr, "Internal error!" - sys.exit(2) - - src = src[:match.start(1)] + repl + src[match.end(1):] - f = open(srcfile,'w') - f.write(src) - f.close() - - -if __name__=='__main__': - if len(sys.argv)>2 and sys.argv[1]=='--md5update': - update_md5(sys.argv[2:]) - else: - main(sys.argv[1:]) - - - - - - diff --git a/setup.py b/setup.py index 2dea527..fb3fc35 100644 --- a/setup.py +++ b/setup.py @@ -1,9 +1,9 @@ #!/usr/bin/env python -import ez_setup -ez_setup.use_setuptools() +from setuptools import setup + +from xattr import lib -from setuptools import setup, Extension VERSION = '0.6.4' DESCRIPTION = "Python wrapper for extended filesystem attributes" @@ -16,7 +16,7 @@ Extended attributes are currently only available on Darwin 8.0+ (Mac OS X 10.4) and Linux 2.6+. Experimental support is included for Solaris and FreeBSD. """ -CLASSIFIERS = filter(None, map(str.strip, +CLASSIFIERS = filter(bool, map(str.strip, """ Environment :: Console Intended Audience :: Developers @@ -42,7 +42,7 @@ setup( packages=['xattr'], platforms=['MacOS X', 'Linux', 'FreeBSD', 'Solaris'], ext_modules=[ - Extension("xattr._xattr", ["xattr/_xattr.c"]), + lib.ffi.verifier.get_extension() ], entry_points={ 'console_scripts': [ -- cgit v1.2.1 From 709fb668dc641464a55a82216f36e677e7f17c79 Mon Sep 17 00:00:00 2001 From: Alex Gaynor Date: Thu, 18 Jul 2013 15:56:50 -0700 Subject: remove constants file --- xattr/constants.py | 16 ---------------- xattr/tests/__init__.py | 6 +++--- 2 files changed, 3 insertions(+), 19 deletions(-) delete mode 100644 xattr/constants.py diff --git a/xattr/constants.py b/xattr/constants.py deleted file mode 100644 index 8ee1c3b..0000000 --- a/xattr/constants.py +++ /dev/null @@ -1,16 +0,0 @@ - -# Options for pathname based xattr calls -XATTR_NOFOLLOW = 0x0001 # Don't follow symbolic links - -# Options for setxattr calls -XATTR_CREATE = 0x0002 # set the value, fail if attr already exists -XATTR_REPLACE = 0x0004 # set the value, fail if attr does not exist - -# Set this to bypass authorization checking (eg. if doing auth-related work) -XATTR_NOSECURITY = 0x0008 - -XATTR_MAXNAMELEN = 127 - -XATTR_FINDERINFO_NAME = "com.apple.FinderInfo" - -XATTR_RESOURCEFORK_NAME = "com.apple.ResourceFork" diff --git a/xattr/tests/__init__.py b/xattr/tests/__init__.py index 2391ae6..739dd58 100644 --- a/xattr/tests/__init__.py +++ b/xattr/tests/__init__.py @@ -1,3 +1,5 @@ +import os +import sys import unittest @@ -15,7 +17,5 @@ def main(): if __name__ == '__main__': - import os - import sys sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))) - main() \ No newline at end of file + main() -- cgit v1.2.1 From 635aeb0ec9db53f0df13ab5e42b95938a789b79f Mon Sep 17 00:00:00 2001 From: Alex Gaynor Date: Fri, 19 Jul 2013 05:57:30 -0700 Subject: fix up warnings --- xattr/lib.py | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/xattr/lib.py b/xattr/lib.py index 11af84c..86adae0 100644 --- a/xattr/lib.py +++ b/xattr/lib.py @@ -10,8 +10,6 @@ ffi.cdef(""" #define XATTR_REPLACE ... #define XATTR_NOSECURITY ... #define XATTR_MAXNAMELEN ... -#define XATTR_FINDERINFO_NAME ... -#define XATTR_RESOURCEFORK_NAME ... ssize_t xattr_getxattr(const char *, const char *, void *, ssize_t, uint32_t, int); ssize_t xattr_fgetxattr(int, const char *, void *, ssize_t, uint32_t, int); @@ -586,8 +584,9 @@ XATTR_CREATE = lib.XATTR_CREATE XATTR_REPLACE = lib.XATTR_REPLACE XATTR_NOSECURITY = lib.XATTR_NOSECURITY XATTR_MAXNAMELEN = lib.XATTR_MAXNAMELEN -XATTR_FINDERINFO_NAME = lib.XATTR_FINDERINFO_NAME -XATTR_RESOURCEFORK_NAME = lib.XATTR_RESOURCEFORK_NAME + +XATTR_FINDERINFO_NAME = "com.apple.FinderInfo" +XATTR_RESOURCEFORK_NAME = "com.apple.ResourceFork" def fs_encode(val): -- cgit v1.2.1 From 55dccf038770ccfdc1dd7e2396fc1b07a7b3ddb5 Mon Sep 17 00:00:00 2001 From: Alex Gaynor Date: Fri, 19 Jul 2013 07:58:51 -0700 Subject: Make sure the dependency is installed. --- setup.py | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/setup.py b/setup.py index fb3fc35..367f371 100644 --- a/setup.py +++ b/setup.py @@ -2,7 +2,12 @@ from setuptools import setup -from xattr import lib +try: + from xattr import lib +except ImportError: + ext_modules = [] +else: + ext_modules = [lib.ffi.verifier.get_extension()] VERSION = '0.6.4' @@ -41,14 +46,14 @@ setup( license="MIT License", packages=['xattr'], platforms=['MacOS X', 'Linux', 'FreeBSD', 'Solaris'], - ext_modules=[ - lib.ffi.verifier.get_extension() - ], + ext_modules=ext_modules, entry_points={ 'console_scripts': [ "xattr = xattr.tool:main", ], }, + install_requires=["cffi"], + setup_requires=["cffi"], test_suite="xattr.tests.all_tests_suite", zip_safe=False, ) -- cgit v1.2.1 From 6c5421c586a69ef775a667b389075eab330a22a0 Mon Sep 17 00:00:00 2001 From: Alex Gaynor Date: Fri, 19 Jul 2013 09:32:28 -0700 Subject: Improve the building (still doesn't work) --- setup.py | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/setup.py b/setup.py index 367f371..a3a5d0f 100644 --- a/setup.py +++ b/setup.py @@ -1,7 +1,16 @@ #!/usr/bin/env python +import os +import sys + from setuptools import setup +# HACK for setup.py build, this way it can find cffi and thus make the +# extension +for path in os.listdir("."): + if path.endswith(".egg"): + sys.path.append(path) + try: from xattr import lib except ImportError: -- cgit v1.2.1 From 9bd1640c8c6ca6052cf1a115151d15eaa9577c4d Mon Sep 17 00:00:00 2001 From: Bob Ippolito Date: Fri, 19 Jul 2013 11:12:24 -0700 Subject: #11 maybe fix build, add requirements.txt --- .gitignore | 1 + CHANGES.txt | 5 +++++ requirements.txt | 1 + setup.py | 33 ++++++++++++++++----------------- xattr/__init__.py | 2 +- xattr/lib.py | 2 +- 6 files changed, 25 insertions(+), 19 deletions(-) create mode 100644 requirements.txt diff --git a/.gitignore b/.gitignore index 5c2ffe4..0a151a0 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,7 @@ /xattr.egg-info /build /dist +/*.egg *.pyc *.so .\#* diff --git a/CHANGES.txt b/CHANGES.txt index bfcb0ad..4e5f24a 100644 --- a/CHANGES.txt +++ b/CHANGES.txt @@ -1,3 +1,8 @@ +Version 0.7.0 released 2013-07-19 + +* Rewritten to use cffi + https://github.com/xattr/xattr/pull/11 + Version 0.6.4 released 2012-02-01 * Updated README.txt to match setup.py description diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..08c056b --- /dev/null +++ b/requirements.txt @@ -0,0 +1 @@ +cffi>=0.4 diff --git a/setup.py b/setup.py index a3a5d0f..76c0280 100644 --- a/setup.py +++ b/setup.py @@ -4,22 +4,20 @@ import os import sys from setuptools import setup +from distutils.command.build import build -# HACK for setup.py build, this way it can find cffi and thus make the -# extension -for path in os.listdir("."): - if path.endswith(".egg"): - sys.path.append(path) +class cffi_build(build): + """This is a shameful hack to ensure that cffi is present when + we specify ext_modules. We can't do this eagerly because + setup_requires hasn't run yet. + """ + def finalize_options(self): + from xattr.lib import ffi + self.distribution.ext_modules = [ffi.verifier.get_extension()] + self.distribution.ext_modules.append(ext) + build.finalize_options(self) -try: - from xattr import lib -except ImportError: - ext_modules = [] -else: - ext_modules = [lib.ffi.verifier.get_extension()] - - -VERSION = '0.6.4' +VERSION = '0.7.0' DESCRIPTION = "Python wrapper for extended filesystem attributes" LONG_DESCRIPTION = """ Extended attributes extend the basic attributes of files and directories @@ -54,15 +52,16 @@ setup( url="http://github.com/xattr/xattr", license="MIT License", packages=['xattr'], + ext_package='xattr', platforms=['MacOS X', 'Linux', 'FreeBSD', 'Solaris'], - ext_modules=ext_modules, entry_points={ 'console_scripts': [ "xattr = xattr.tool:main", ], }, - install_requires=["cffi"], - setup_requires=["cffi"], + install_requires=["cffi>=0.4"], + setup_requires=["cffi>=0.4"], test_suite="xattr.tests.all_tests_suite", zip_safe=False, + cmdclass={'build': cffi_build}, ) diff --git a/xattr/__init__.py b/xattr/__init__.py index 7618bc0..a452f66 100644 --- a/xattr/__init__.py +++ b/xattr/__init__.py @@ -7,7 +7,7 @@ The xattr type wraps a path or file descriptor with a dict-like interface that exposes these extended attributes. """ -__version__ = '0.6.4' +__version__ = '0.7.0' from .lib import (XATTR_NOFOLLOW, XATTR_CREATE, XATTR_REPLACE, XATTR_NOSECURITY, XATTR_MAXNAMELEN, XATTR_FINDERINFO_NAME, diff --git a/xattr/lib.py b/xattr/lib.py index 86adae0..b72a1ff 100644 --- a/xattr/lib.py +++ b/xattr/lib.py @@ -577,7 +577,7 @@ static ssize_t xattr_flistxattr(int fd, char *namebuf, size_t size, int options) #define xattr_listxattr listxattr #define xattr_flistxattr flistxattr #endif -""") +""", ext_package='xattr') XATTR_NOFOLLOW = lib.XATTR_NOFOLLOW XATTR_CREATE = lib.XATTR_CREATE -- cgit v1.2.1 From 8368608472bc3db5755ed4b3904d56902f8fe69d Mon Sep 17 00:00:00 2001 From: Bob Ippolito Date: Fri, 19 Jul 2013 11:15:31 -0700 Subject: fix stupid mistake --- setup.py | 1 - 1 file changed, 1 deletion(-) diff --git a/setup.py b/setup.py index 76c0280..d33c099 100644 --- a/setup.py +++ b/setup.py @@ -14,7 +14,6 @@ class cffi_build(build): def finalize_options(self): from xattr.lib import ffi self.distribution.ext_modules = [ffi.verifier.get_extension()] - self.distribution.ext_modules.append(ext) build.finalize_options(self) VERSION = '0.7.0' -- cgit v1.2.1