xattr: refactor/fix exception handling in get_all

if there is EPERM just for a single attr, it now still collects the
other attrs (previous behaviour: just return empty xattrs dict).
This commit is contained in:
Thomas Waldmann 2018-07-05 18:50:44 +02:00
parent 394d59e6d8
commit 389e806b68
1 changed files with 21 additions and 6 deletions

View File

@ -37,8 +37,8 @@ def get_all(path, follow_symlinks=False):
"""
if isinstance(path, str):
path = os.fsencode(path)
result = {}
try:
result = {}
names = listxattr(path, follow_symlinks=follow_symlinks)
for name in names:
try:
@ -47,14 +47,29 @@ def get_all(path, follow_symlinks=False):
# borg always did it like that...
result[name] = getxattr(path, name, follow_symlinks=follow_symlinks) or None
except OSError as e:
# if we get ENOATTR, a race has happened: xattr names were deleted after list.
# we just ignore the now missing ones. if you want consistency, do snapshots.
if e.errno != ENOATTR:
name_str = name.decode()
if isinstance(path, int):
path_str = '<FD %d>' % path
else:
path_str = os.fsdecode(path)
if e.errno == ENOATTR:
# if we get ENOATTR, a race has happened: xattr names were deleted after list.
# we just ignore the now missing ones. if you want consistency, do snapshots.
pass
elif e.errno == errno.EPERM:
# we were not permitted to read this attribute, still can continue trying to read others
logger.warning('%s: Operation not permitted when reading extended attribute %s' % (
path_str, name_str))
else:
raise
return result
except OSError as e:
if e.errno in (errno.ENOTSUP, errno.EPERM):
return {}
# if xattrs are not supported on the filesystem, we give up.
# EPERM might be raised by listxattr.
pass
else:
raise
return result
def set_all(path, xattrs, follow_symlinks=False):