1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189
|
"""
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.10.1'
from .compat import integer_types
from .lib import (XATTR_NOFOLLOW, XATTR_CREATE, XATTR_REPLACE,
XATTR_NOSECURITY, XATTR_MAXNAMELEN, XATTR_FINDERINFO_NAME,
XATTR_RESOURCEFORK_NAME, _getxattr, _fgetxattr, _setxattr, _fsetxattr,
_removexattr, _fremovexattr, _listxattr, _flistxattr)
__all__ = [
"XATTR_NOFOLLOW", "XATTR_CREATE", "XATTR_REPLACE", "XATTR_NOSECURITY",
"XATTR_MAXNAMELEN", "XATTR_FINDERINFO_NAME", "XATTR_RESOURCEFORK_NAME",
"xattr", "listxattr", "getxattr", "setxattr", "removexattr"
]
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
fileno = getattr(obj, 'fileno', None)
if fileno is not None:
self.value = fileno()
else:
self.value = obj
def __repr__(self):
if isinstance(self.value, integer_types):
flavor = "fd"
else:
flavor = "file"
return "<%s %s=%r>" % (type(self).__name__, flavor, self.value)
def _call(self, name_func, fd_func, *args):
if isinstance(self.value, integer_types):
return fd_func(self.value, *args)
else:
return name_func(self.value, *args)
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._call(_getxattr, _fgetxattr, 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.
"""
return self._call(_setxattr, _fsetxattr, 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.
"""
return self._call(_removexattr, _fremovexattr, name, options | self.options)
def list(self, options=0):
"""
Retrieves the extended attributes currently set as a list
of strings. Raises ``IOError`` on failure.
See x-man-page://2/listxattr for options and possible errors.
"""
res = self._call(_listxattr, _flistxattr, options | self.options).split(b'\x00')
res.pop()
return [s.decode('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, 'items'):
seq = dict(seq)
for k, v in seq.items():
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):
return tuple(xattr(f).list(options=symlink and XATTR_NOFOLLOW or 0))
def getxattr(f, attr, symlink=False):
return xattr(f).get(attr, options=symlink and XATTR_NOFOLLOW or 0)
def setxattr(f, attr, value, options=0, symlink=False):
if symlink:
options |= XATTR_NOFOLLOW
return xattr(f).set(attr, value, options=options)
def removexattr(f, attr, symlink=False):
options = symlink and XATTR_NOFOLLOW or 0
return xattr(f).remove(attr, options=options)
|