xattr-0.6.4/0000755000076500000240000000000011712311410012537 5ustar bobstaff00000000000000xattr-0.6.4/.gitignore0000644000076500000240000000005511707315151014541 0ustar bobstaff00000000000000/xattr.egg-info /build /dist *.pyc *.so .\#* xattr-0.6.4/_build/0000755000076500000240000000000011712311410013775 5ustar bobstaff00000000000000xattr-0.6.4/_build/_make_constants.py0000644000076500000240000000133311622646721017537 0ustar bobstaff00000000000000infile = '/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 xattr-0.6.4/CHANGES.txt0000644000076500000240000000060211712311211014345 0ustar bobstaff00000000000000Version 0.6.4 released 2012-02-01 * Updated README.txt to match setup.py description https://github.com/xattr/xattr/issues/5 * Bug fixes for Solaris port https://github.com/xattr/xattr/pull/2 Version 0.6.3 released 2012-01-23 * Fix tests for Linux, allow xattr on symlinks https://github.com/xattr/xattr/pull/4 Version 0.6.2 released 2011-08-17 * Bug fix in Solaris support xattr-0.6.4/ez_setup.py0000644000076500000240000002400011622650053014754 0ustar bobstaff00000000000000#!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:]) xattr-0.6.4/INSTALLING.txt0000644000076500000240000000014011622646721014757 0ustar bobstaff00000000000000Installing ========== From the xattr source directory, type: sudo python setup.py install xattr-0.6.4/LICENSE.txt0000644000076500000240000000222411622646721014402 0ustar bobstaff00000000000000This is the MIT license. This software may also be distributed under the same terms as Python (the PSF license). Copyright (c) 2004 Bob Ippolito. Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. xattr-0.6.4/PKG-INFO0000644000076500000240000000220411712311410013632 0ustar bobstaff00000000000000Metadata-Version: 1.0 Name: xattr Version: 0.6.4 Summary: Python wrapper for extended filesystem attributes Home-page: http://github.com/xattr/xattr Author: Bob Ippolito Author-email: bob@redivi.com License: MIT License Description: Extended attributes extend the basic attributes of files and directories in the file system. They are stored as name:data pairs associated with file system objects (files, directories, symlinks, etc). 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. Platform: MacOS X Platform: Linux Platform: FreeBSD Platform: Solaris Classifier: Environment :: Console Classifier: Intended Audience :: Developers Classifier: License :: OSI Approved :: MIT License Classifier: Natural Language :: English Classifier: Operating System :: MacOS :: MacOS X Classifier: Operating System :: POSIX :: Linux Classifier: Operating System :: POSIX :: BSD :: FreeBSD Classifier: Programming Language :: Python Classifier: Topic :: Software Development :: Libraries :: Python Modules xattr-0.6.4/README.txt0000644000076500000240000000064411712310733014250 0ustar bobstaff00000000000000xattr is a Python wrapper for extended filesystem attributes. Extended attributes extend the basic attributes of files and directories in the file system. They are stored as name:data pairs associated with file system objects (files, directories, symlinks, etc). 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. xattr-0.6.4/setup.cfg0000644000076500000240000000007311712311410014360 0ustar bobstaff00000000000000[egg_info] tag_build = tag_date = 0 tag_svn_revision = 0 xattr-0.6.4/setup.py0000644000076500000240000000305411712311260014256 0ustar bobstaff00000000000000#!/usr/bin/env python import ez_setup ez_setup.use_setuptools() from setuptools import setup, Extension VERSION = '0.6.4' DESCRIPTION = "Python wrapper for extended filesystem attributes" LONG_DESCRIPTION = """ Extended attributes extend the basic attributes of files and directories in the file system. They are stored as name:data pairs associated with file system objects (files, directories, symlinks, etc). 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, """ Environment :: Console Intended Audience :: Developers License :: OSI Approved :: MIT License Natural Language :: English Operating System :: MacOS :: MacOS X Operating System :: POSIX :: Linux Operating System :: POSIX :: BSD :: FreeBSD Programming Language :: Python Topic :: Software Development :: Libraries :: Python Modules """.splitlines())) setup( name="xattr", version=VERSION, description=DESCRIPTION, long_description=LONG_DESCRIPTION, classifiers=CLASSIFIERS, author="Bob Ippolito", author_email="bob@redivi.com", url="http://github.com/xattr/xattr", license="MIT License", packages=['xattr'], platforms=['MacOS X', 'Linux', 'FreeBSD', 'Solaris'], ext_modules=[ Extension("xattr._xattr", ["xattr/_xattr.c"]), ], entry_points={ 'console_scripts': [ "xattr = xattr.tool:main", ], }, test_suite="xattr.tests.all_tests_suite", zip_safe=False, ) xattr-0.6.4/TODO.txt0000644000076500000240000000003711622646721014065 0ustar bobstaff00000000000000* Write tests * Write examples xattr-0.6.4/xattr/0000755000076500000240000000000011712311410013701 5ustar bobstaff00000000000000xattr-0.6.4/xattr/__init__.py0000644000076500000240000001311111712311240016010 0ustar bobstaff00000000000000""" Extended attributes extend the basic attributes of files and directories in the file system. They are stored as name:data pairs associated with file system objects (files, directories, symlinks, etc). The xattr type wraps a path or file descriptor with a dict-like interface 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 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, ] def _boundfunc(func, first): def _func(*args): return func(first, *args) return _func class xattr(object): """ A wrapper for paths or file descriptors to access their extended attributes with a dict-like interface """ def __init__(self, obj, options=0): """ obj should be a path, a file descriptor, or an object that implements fileno() and returns a file descriptor. options should be 0 or XATTR_NOFOLLOW. If set, it will be OR'ed with the options passed to getxattr, setxattr, etc. """ 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) else: self.flavor = 'file' self._bind_any('%sxattr', obj, options) def __repr__(self): if self.flavor: return '<%s %s=%r>' % (type(self).__name__, self.flavor, self.obj) 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 get(self, name, options=0): """ Retrieve the extended attribute ``name`` as a ``str``. Raises ``IOError`` on failure. See x-man-page://2/getxattr for options and possible errors. """ return self._get(name, 0, 0, options | self.options) def set(self, name, value, options=0): """ Set the extended attribute ``name`` to ``value`` Raises ``IOError`` on failure. See x-man-page://2/setxattr for options and possible errors. """ self._set(name, value, 0, options | self.options) def remove(self, name, options=0): """ Remove the extended attribute ``name`` Raises ``IOError`` on failure. See x-man-page://2/removexattr for options and possible errors. """ self._remove(name, options | self.options) def list(self, options=0): """ Retrieves the extended attributes currently set as a list of unicode strings. Raises ``IOError`` on failure. See x-man-page://2/listxattr for options and possible errors. """ res = self._list(options | self.options).split('\x00') res.pop() return [unicode(s, 'utf-8') for s in res] # dict-like methods def __len__(self): return len(self.list()) def __delitem__(self, item): try: self.remove(item) except IOError: raise KeyError(item) def __setitem__(self, item, value): self.set(item, value) def __getitem__(self, item): try: return self.get(item) except IOError: raise KeyError(item) def iterkeys(self): return iter(self.list()) __iter__ = iterkeys def has_key(self, item): try: self.get(item) except IOError: return False else: return True __contains__ = has_key def clear(self): for k in self.keys(): del self[k] def update(self, seq): if not hasattr(seq, 'iteritems'): seq = dict(seq) for k, v in seq.iteritems(): self[k] = v def copy(self): return dict(self.iteritems()) def setdefault(self, k, d=''): try: d = self.get(k) except IOError: self[k] = d return d def keys(self): return self.list() def itervalues(self): for k, v in self.iteritems(): yield v def values(self): return list(self.itervalues()) def iteritems(self): for k in self.list(): yield k, self.get(k) def items(self): return list(self.iteritems()) 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) xattr-0.6.4/xattr/_xattr.c0000644000076500000240000006066611712311217015371 0ustar bobstaff00000000000000#include "Python.h" #ifdef __FreeBSD__ #include #elif 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__) /* 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 #define u_int32_t unsigned int 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); } xattr-0.6.4/xattr/constants.py0000644000076500000240000000075111622646721016312 0ustar bobstaff00000000000000 # 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" xattr-0.6.4/xattr/tests/0000755000076500000240000000000011712311410015043 5ustar bobstaff00000000000000xattr-0.6.4/xattr/tests/__init__.py0000644000076500000240000000065411707313675017204 0ustar bobstaff00000000000000import unittest def all_tests_suite(): suite = unittest.TestLoader().loadTestsFromNames([ 'xattr.tests.test_xattr', ]) return suite def main(): runner = unittest.TextTestRunner() suite = all_tests_suite() runner.run(suite) 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()xattr-0.6.4/xattr/tests/test_xattr.py0000644000076500000240000000301211707314315017625 0ustar bobstaff00000000000000import os from unittest import TestCase 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): x = xattr.xattr(self.tempfile) self.assertEqual(x.keys(), []) self.assertEqual(dict(x), {}) x['user.sopal'] = 'foo' x['user.sop.foo'] = 'bar' del x x = xattr.xattr(self.tempfile) self.assertTrue('user.sopal' in x) self.assertEqual(x['user.sopal'], 'foo') self.assertTrue('user.sop.foo' in x) self.assertEqual(x['user.sop.foo'], 'bar') del x['user.sop.foo'] del x x = xattr.xattr(self.tempfile) self.assertTrue('user.sop.foo' not in x) def testSymlinkAttrs(self): symlinkPath = self.tempfilename + '.link' os.symlink(self.tempfilename, symlinkPath) try: symlink = xattr.xattr(symlinkPath, options=xattr.XATTR_NOFOLLOW) realfile = xattr.xattr(self.tempfilename) symlink['user.islink'] = 'true' self.assertEqual(dict(realfile), {}) self.assertEqual(symlink['user.islink'], 'true') finally: os.remove(symlinkPath) class TestDir(TestFile): def setUp(self): self.tempfile = mkdtemp() self.tempfilename = self.tempfile def tearDown(self): os.rmdir(self.tempfile) xattr-0.6.4/xattr/tool.py0000755000076500000240000001451111622646721015255 0ustar bobstaff00000000000000#!/usr/bin/env python ## # Copyright (c) 2007 Apple Inc. # # This is the MIT license. This software may also be distributed under the # same terms as Python (the PSF license). # # Permission is hereby granted, free of charge, to any person obtaining a # copy of this software and associated documentation files (the "Software"), # to deal in the Software without restriction, including without limitation # the rights to use, copy, modify, merge, publish, distribute, sublicense, # and/or sell copies of the Software, and to permit persons to whom the # Software is furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING # FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS # IN THE SOFTWARE. ## import sys import os import getopt import xattr import zlib def usage(e=None): if e: print e print "" name = os.path.basename(sys.argv[0]) print "usage: %s [-lz] file [file ...]" % (name,) print " %s -p [-lz] attr_name file [file ...]" % (name,) print " %s -w [-z] attr_name attr_value file [file ...]" % (name,) print " %s -d attr_name file [file ...]" % (name,) print "" print "The first form lists the names of all xattrs on the given file(s)." print "The second form (-p) prints the value of the xattr attr_name." print "The third form (-w) sets the value of the xattr attr_name to attr_value." print "The fourth form (-d) deletes the xattr attr_name." print "" print "options:" print " -h: print this help" print " -l: print long format (attr_name: attr_value)" print " -z: compress or decompress (if compressed) attribute value in zip format" if e: sys.exit(64) 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)]) def _dump(src, length=16): result=[] for i in xrange(0, len(src), length): s = src[i:i+length] 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 long_format = False read = False write = False delete = False compress = lambda x: x decompress = compress status = 0 for opt, arg in optargs: if opt in ("-h", "--help"): usage() elif opt == "-l": long_format = True elif opt == "-p": read = True if write or delete: usage("-p not allowed with -w or -d") elif opt == "-w": write = True if read or delete: usage("-w not allowed with -p or -d") elif opt == "-d": delete = True if read or write: usage("-d not allowed with -p or -w") elif opt == "-z": compress = zlib.compress decompress = zlib.decompress if write or delete: if long_format: usage("-l not allowed with -w or -p") if read or write or delete: if not args: usage("No attr_name") attr_name = args.pop(0) if write: if not args: usage("No attr_value") attr_value = args.pop(0) if len(args) > 1: multiple_files = True else: multiple_files = False for filename in args: def onError(e): if not os.path.exists(filename): sys.stderr.write("No such file: %s\n" % (filename,)) else: sys.stderr.write(str(e) + "\n") status = 1 try: attrs = xattr.xattr(filename) except (IOError, OSError), e: onError(e) continue if write: try: attrs[attr_name] = compress(attr_value) except (IOError, OSError), e: onError(e) continue elif delete: try: del attrs[attr_name] except (IOError, OSError), e: onError(e) continue except KeyError: onError("No such xattr: %s" % (attr_name,)) continue else: try: if read: attr_names = (attr_name,) else: attr_names = attrs.keys() except (IOError, OSError), e: onError(e) continue if multiple_files: file_prefix = "%s: " % (filename,) else: file_prefix = "" for attr_name in attr_names: try: try: attr_value = decompress(attrs[attr_name]) except zlib.error: attr_value = attrs[attr_name] except KeyError: onError("%sNo such xattr: %s" % (file_prefix, attr_name)) continue if long_format: try: if attr_value.find('\0') >= 0: raise NullsInString; print "".join((file_prefix, "%s: " % (attr_name,), attr_value)) except (UnicodeDecodeError, NullsInString): print "".join((file_prefix, "%s:" % (attr_name,))) print _dump(attr_value) else: if read: print "".join((file_prefix, attr_value)) else: print "".join((file_prefix, attr_name)) sys.exit(status) if __name__ == "__main__": main() xattr-0.6.4/xattr.egg-info/0000755000076500000240000000000011712311410015373 5ustar bobstaff00000000000000xattr-0.6.4/xattr.egg-info/dependency_links.txt0000644000076500000240000000000111712311405021445 0ustar bobstaff00000000000000 xattr-0.6.4/xattr.egg-info/entry_points.txt0000644000076500000240000000005311712311405020673 0ustar bobstaff00000000000000[console_scripts] xattr = xattr.tool:main xattr-0.6.4/xattr.egg-info/not-zip-safe0000644000076500000240000000000111622760267017643 0ustar bobstaff00000000000000 xattr-0.6.4/xattr.egg-info/PKG-INFO0000644000076500000240000000220411712311405016472 0ustar bobstaff00000000000000Metadata-Version: 1.0 Name: xattr Version: 0.6.4 Summary: Python wrapper for extended filesystem attributes Home-page: http://github.com/xattr/xattr Author: Bob Ippolito Author-email: bob@redivi.com License: MIT License Description: Extended attributes extend the basic attributes of files and directories in the file system. They are stored as name:data pairs associated with file system objects (files, directories, symlinks, etc). 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. Platform: MacOS X Platform: Linux Platform: FreeBSD Platform: Solaris Classifier: Environment :: Console Classifier: Intended Audience :: Developers Classifier: License :: OSI Approved :: MIT License Classifier: Natural Language :: English Classifier: Operating System :: MacOS :: MacOS X Classifier: Operating System :: POSIX :: Linux Classifier: Operating System :: POSIX :: BSD :: FreeBSD Classifier: Programming Language :: Python Classifier: Topic :: Software Development :: Libraries :: Python Modules xattr-0.6.4/xattr.egg-info/SOURCES.txt0000644000076500000240000000064211712311405017265 0ustar bobstaff00000000000000.gitignore CHANGES.txt INSTALLING.txt LICENSE.txt README.txt TODO.txt ez_setup.py setup.cfg setup.py _build/_make_constants.py xattr/__init__.py xattr/_xattr.c xattr/constants.py xattr/tool.py xattr.egg-info/PKG-INFO xattr.egg-info/SOURCES.txt xattr.egg-info/dependency_links.txt xattr.egg-info/entry_points.txt xattr.egg-info/not-zip-safe xattr.egg-info/top_level.txt xattr/tests/__init__.py xattr/tests/test_xattr.pyxattr-0.6.4/xattr.egg-info/top_level.txt0000644000076500000240000000000611712311405020125 0ustar bobstaff00000000000000xattr