diff --git a/borg/archive.py b/borg/archive.py index 2274a2778..094a09c4c 100644 --- a/borg/archive.py +++ b/borg/archive.py @@ -19,7 +19,7 @@ from . import xattr from .helpers import Error, uid2user, user2uid, gid2group, group2gid, bin_to_hex, \ parse_timestamp, to_localtime, format_time, format_timedelta, remove_surrogates, \ Manifest, Statistics, decode_dict, make_path_safe, StableDict, int_to_bigint, bigint_to_int, \ - ProgressIndicatorPercent, IntegrityError + ProgressIndicatorPercent, IntegrityError, set_ec, EXIT_WARNING from .platform import acl_get, acl_set from .chunker import Chunker from .hashindex import ChunkIndex @@ -502,13 +502,19 @@ Number of files: {0.stats.nfiles}'''.format( xattr.setxattr(fd or path, k, v, follow_symlinks=False) except OSError as e: if e.errno == errno.E2BIG: + # xattr is too big logger.warning('%s: Value or key of extended attribute %s is too big for this filesystem' % (path, k.decode())) - elif e.errno not in (errno.ENOTSUP, errno.EACCES): - # only raise if the errno is not on our ignore list: - # ENOTSUP == xattrs not supported here - # EACCES == permission denied to set this specific xattr - # (this may happen related to security.* keys) + set_ec(EXIT_WARNING) + elif e.errno == errno.ENOTSUP: + # xattrs not supported here + logger.warning('%s: Extended attributes are not supported on this filesystem' % path) + set_ec(EXIT_WARNING) + elif e.errno == errno.EACCES: + # permission denied to set this specific xattr (this may happen related to security.* keys) + logger.warning('%s: Permission denied when setting extended attribute %s' % (path, k.decode())) + set_ec(EXIT_WARNING) + else: raise def rename(self, name): diff --git a/borg/testsuite/archiver.py b/borg/testsuite/archiver.py index 5e8a6a0f8..c5e4f2b81 100644 --- a/borg/testsuite/archiver.py +++ b/borg/testsuite/archiver.py @@ -783,18 +783,35 @@ class ArchiverTestCase(ArchiverTestCaseBase): @pytest.mark.skipif(not xattr.XATTR_FAKEROOT, reason='xattr not supported on this system or on this version of' 'fakeroot') - def test_extract_big_xattrs(self): - def patched_setxattr(*args, **kwargs): + def test_extract_xattrs_errors(self): + def patched_setxattr_E2BIG(*args, **kwargs): raise OSError(errno.E2BIG, 'E2BIG') + + def patched_setxattr_ENOTSUP(*args, **kwargs): + raise OSError(errno.ENOTSUP, 'ENOTSUP') + + def patched_setxattr_EACCES(*args, **kwargs): + raise OSError(errno.EACCES, 'EACCES') + self.create_regular_file('file') xattr.setxattr('input/file', 'attribute', 'value') self.cmd('init', self.repository_location, '-e' 'none') self.cmd('create', self.repository_location + '::test', 'input') with changedir('output'): - with patch.object(xattr, 'setxattr', patched_setxattr): + input_abspath = os.path.abspath('input/file') + with patch.object(xattr, 'setxattr', patched_setxattr_E2BIG): out = self.cmd('extract', self.repository_location + '::test', exit_code=EXIT_WARNING) - assert out == (os.path.abspath('input/file') + ': Value or key of extended attribute attribute is too big' - 'for this filesystem\n') + assert out == (input_abspath + ': Value or key of extended attribute attribute is too big for this ' + 'filesystem\n') + os.remove(input_abspath) + with patch.object(xattr, 'setxattr', patched_setxattr_ENOTSUP): + out = self.cmd('extract', self.repository_location + '::test', exit_code=EXIT_WARNING) + assert out == (input_abspath + ': Extended attributes are not supported on this filesystem\n') + os.remove(input_abspath) + with patch.object(xattr, 'setxattr', patched_setxattr_EACCES): + out = self.cmd('extract', self.repository_location + '::test', exit_code=EXIT_WARNING) + assert out == (input_abspath + ': Permission denied when setting extended attribute attribute\n') + assert os.path.isfile(input_abspath) def test_path_normalization(self): self.cmd('init', self.repository_location)