From 98198b34d9bc24dd14b1af590e7f5be4d1ace632 Mon Sep 17 00:00:00 2001 From: Thomas Waldmann Date: Mon, 18 Mar 2019 20:50:22 +0100 Subject: [PATCH] make freebsd xattr platform code api compatible with linux, fixes #3952 i.e. prefix the keys with the namespace, so it is ns.key like on linux. still only dealing with the "user" namespace, like before. in the "system" namespaces there are ACLs (we deal with them via the acl api, so no problem) and stuff from pnfsd (not sure what exactly). this change is needed because FreeBSD's FUSE code expects the xattr keys to be in that format. it is also needed for cross-platform data exchange, so e.g. if one wants to: - create archive on linux, extract on freebsd - with "user.xxx" xattrs. - or vice versa. archives made with older borg versions on freebsd will still extract correctly on freebsd (not on linux though) even though they do not have the namespace prefixes in the archived metadata (it will be interpreted in same way as if they were prefixed by "user." as we do not support any other namespace anyway). (cherry picked from commit 068623748428b80e92c247a7bd692e5a2261c94e) --- src/borg/testsuite/xattr.py | 6 +++--- src/borg/xattr.py | 11 ++++++++++- 2 files changed, 13 insertions(+), 4 deletions(-) diff --git a/src/borg/testsuite/xattr.py b/src/borg/testsuite/xattr.py index 709d773e0..4802637e4 100644 --- a/src/borg/testsuite/xattr.py +++ b/src/borg/testsuite/xattr.py @@ -44,13 +44,13 @@ class XattrTestCase(BaseTestCase): def test_listxattr_buffer_growth(self): # make it work even with ext4, which imposes rather low limits buffer.resize(size=64, init=True) - # xattr raw key list will be size 9 * (10 + 1), which is > 64 - keys = ['user.attr%d' % i for i in range(9)] + # xattr raw key list will be > 64 + keys = ['user.attr%d' % i for i in range(20)] for key in keys: setxattr(self.tmpfile.name, key, b'x') got_keys = listxattr(self.tmpfile.name) self.assert_equal_se(got_keys, keys) - self.assert_equal(len(buffer), 128) + self.assert_true(len(buffer) > 64) def test_getxattr_buffer_growth(self): # make it work even with ext4, which imposes rather low limits diff --git a/src/borg/xattr.py b/src/borg/xattr.py index 4d23df943..abe8e587f 100644 --- a/src/borg/xattr.py +++ b/src/borg/xattr.py @@ -323,6 +323,7 @@ elif sys.platform.startswith('freebsd'): # pragma: freebsd only libc.extattr_set_file.argtypes = (c_char_p, c_int, c_char_p, c_char_p, c_size_t) libc.extattr_set_file.restype = c_int ns = EXTATTR_NAMESPACE_USER = 0x0001 + prefix = 'user.' def listxattr(path, *, follow_symlinks=True): def func(path, buf, size): @@ -335,7 +336,7 @@ elif sys.platform.startswith('freebsd'): # pragma: freebsd only return libc.extattr_list_link(path, ns, buf, size) n, buf = _listxattr_inner(func, path) - return [os.fsdecode(name) for name in split_lstring(buf[:n]) if name] + return [prefix + os.fsdecode(name) for name in split_lstring(buf[:n]) if name] def getxattr(path, name, *, follow_symlinks=True): def func(path, name, buf, size): @@ -347,6 +348,10 @@ elif sys.platform.startswith('freebsd'): # pragma: freebsd only else: return libc.extattr_get_link(path, ns, name, buf, size) + # strip namespace if there, but ignore if not there. + # older borg / attic versions did not prefix the namespace to the names. + if name.startswith(prefix): + name = name[len(prefix):] n, buf = _getxattr_inner(func, path, name) return buf[:n] or None @@ -360,6 +365,10 @@ elif sys.platform.startswith('freebsd'): # pragma: freebsd only else: return libc.extattr_set_link(path, ns, name, value, size) + # strip namespace if there, but ignore if not there. + # older borg / attic versions did not prefix the namespace to the names. + if name.startswith(prefix): + name = name[len(prefix):] _setxattr_inner(func, path, name, value) else: # pragma: unknown platform only