Merge pull request #2536 from enkore/issue/2534

fuse: fix crash if empty (None) xattr is read
This commit is contained in:
enkore 2017-05-20 19:31:49 +02:00 committed by GitHub
commit ba07225c91
3 changed files with 41 additions and 5 deletions

View File

@ -288,7 +288,7 @@ class FuseOperations(llfuse.Operations):
def getxattr(self, inode, name, ctx=None):
item = self.get_item(inode)
try:
return item.get('xattrs', {})[name]
return item.get('xattrs', {})[name] or b''
except KeyError:
raise llfuse.FUSEError(llfuse.ENOATTR) from None

View File

@ -326,6 +326,7 @@ class ArchiverTestCaseBase(BaseTestCase):
# into "fakeroot space". Because the xattrs exposed by borgfs are these of an underlying file
# (from fakeroots point of view) they are invisible to the test process inside the fakeroot.
xattr.setxattr(os.path.join(self.input_path, 'fusexattr'), 'user.foo', b'bar')
xattr.setxattr(os.path.join(self.input_path, 'fusexattr'), 'user.empty', b'')
# XXX this always fails for me
# ubuntu 14.04, on a TMP dir filesystem with user_xattr, using fakeroot
# same for newer ubuntu and centos.
@ -1874,8 +1875,10 @@ class ArchiverTestCase(ArchiverTestCaseBase):
in_fn = 'input/fusexattr'
out_fn = os.path.join(mountpoint, 'input', 'fusexattr')
if not xattr.XATTR_FAKEROOT and xattr.is_enabled(self.input_path):
assert no_selinux(xattr.listxattr(out_fn)) == ['user.foo', ]
assert sorted(no_selinux(xattr.listxattr(out_fn))) == ['user.empty', 'user.foo', ]
assert xattr.getxattr(out_fn, 'user.foo') == b'bar'
# Special case: getxattr returns None (not b'') when reading an empty xattr.
assert xattr.getxattr(out_fn, 'user.empty') is None
else:
assert xattr.listxattr(out_fn) == []
try:

View File

@ -35,6 +35,16 @@ def is_enabled(path=None):
def get_all(path, follow_symlinks=True):
"""
Return all extended attributes on *path* as a mapping.
*path* can either be a path (str or bytes) or an open file descriptor (int).
*follow_symlinks* indicates whether symlinks should be followed
and only applies when *path* is not an open file descriptor.
The returned mapping maps xattr names (str) to values (bytes or None).
None indicates, as a xattr value, an empty value, i.e. a value of length zero.
"""
try:
result = {}
names = listxattr(path, follow_symlinks=follow_symlinks)
@ -111,7 +121,7 @@ def split_lstring(buf):
class BufferTooSmallError(Exception):
"""the buffer given to an xattr function was too small for the result."""
"""the buffer given to a xattr function was too small for the result."""
def _check(rv, path=None, detect_buffer_too_small=False):
@ -346,10 +356,33 @@ elif sys.platform.startswith('freebsd'): # pragma: freebsd only
else: # pragma: unknown platform only
def listxattr(path, *, follow_symlinks=True):
"""
Return list of xattr names on a file.
*path* can either be a path (str or bytes) or an open file descriptor (int).
*follow_symlinks* indicates whether symlinks should be followed
and only applies when *path* is not an open file descriptor.
"""
return []
def getxattr(path, name, *, follow_symlinks=True):
pass
"""
Read xattr and return its value (as bytes) or None if its empty.
*path* can either be a path (str or bytes) or an open file descriptor (int).
*name* is the name of the xattr to read (str).
*follow_symlinks* indicates whether symlinks should be followed
and only applies when *path* is not an open file descriptor.
"""
def setxattr(path, name, value, *, follow_symlinks=True):
pass
"""
Write xattr on *path*.
*path* can either be a path (str or bytes) or an open file descriptor (int).
*name* is the name of the xattr to read (str).
*value* is the value to write. It is either bytes or None. The latter
signals that the value shall be empty (size equals zero).
*follow_symlinks* indicates whether symlinks should be followed
and only applies when *path* is not an open file descriptor.
"""