1
0
Fork 0
mirror of https://github.com/borgbackup/borg.git synced 2025-02-24 07:01:59 +00:00

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).

they do not have "
This commit is contained in:
Thomas Waldmann 2019-03-18 20:50:22 +01:00
parent 20756bd37f
commit 0686237484
2 changed files with 27 additions and 13 deletions

View file

@ -51,43 +51,57 @@ cdef extern from "unistd.h":
def listxattr(path, *, follow_symlinks=False): def listxattr(path, *, follow_symlinks=False):
ns, prefix = EXTATTR_NAMESPACE_USER, b'user.'
def func(path, buf, size): def func(path, buf, size):
if isinstance(path, int): if isinstance(path, int):
return c_extattr_list_fd(path, EXTATTR_NAMESPACE_USER, <char *> buf, size) return c_extattr_list_fd(path, ns, <char *> buf, size)
else: else:
if follow_symlinks: if follow_symlinks:
return c_extattr_list_file(path, EXTATTR_NAMESPACE_USER, <char *> buf, size) return c_extattr_list_file(path, ns, <char *> buf, size)
else: else:
return c_extattr_list_link(path, EXTATTR_NAMESPACE_USER, <char *> buf, size) return c_extattr_list_link(path, ns, <char *> buf, size)
n, buf = _listxattr_inner(func, path) n, buf = _listxattr_inner(func, path)
return [name for name in split_lstring(buf[:n]) if name] return [prefix + name for name in split_lstring(buf[:n]) if name]
def getxattr(path, name, *, follow_symlinks=False): def getxattr(path, name, *, follow_symlinks=False):
ns, prefix = EXTATTR_NAMESPACE_USER, b'user.'
def func(path, name, buf, size): def func(path, name, buf, size):
if isinstance(path, int): if isinstance(path, int):
return c_extattr_get_fd(path, EXTATTR_NAMESPACE_USER, name, <char *> buf, size) return c_extattr_get_fd(path, ns, name, <char *> buf, size)
else: else:
if follow_symlinks: if follow_symlinks:
return c_extattr_get_file(path, EXTATTR_NAMESPACE_USER, name, <char *> buf, size) return c_extattr_get_file(path, ns, name, <char *> buf, size)
else: else:
return c_extattr_get_link(path, EXTATTR_NAMESPACE_USER, name, <char *> buf, size) return c_extattr_get_link(path, ns, name, <char *> 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) n, buf = _getxattr_inner(func, path, name)
return bytes(buf[:n]) return bytes(buf[:n])
def setxattr(path, name, value, *, follow_symlinks=False): def setxattr(path, name, value, *, follow_symlinks=False):
ns, prefix = EXTATTR_NAMESPACE_USER, b'user.'
def func(path, name, value, size): def func(path, name, value, size):
if isinstance(path, int): if isinstance(path, int):
return c_extattr_set_fd(path, EXTATTR_NAMESPACE_USER, name, <char *> value, size) return c_extattr_set_fd(path, ns, name, <char *> value, size)
else: else:
if follow_symlinks: if follow_symlinks:
return c_extattr_set_file(path, EXTATTR_NAMESPACE_USER, name, <char *> value, size) return c_extattr_set_file(path, ns, name, <char *> value, size)
else: else:
return c_extattr_set_link(path, EXTATTR_NAMESPACE_USER, name, <char *> value, size) return c_extattr_set_link(path, ns, name, <char *> 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) _setxattr_inner(func, path, name, value)

View file

@ -56,13 +56,13 @@ def test_listxattr_buffer_growth(self):
tmp_fn = os.fsencode(self.tmpfile.name) tmp_fn = os.fsencode(self.tmpfile.name)
# make it work even with ext4, which imposes rather low limits # make it work even with ext4, which imposes rather low limits
buffer.resize(size=64, init=True) buffer.resize(size=64, init=True)
# xattr raw key list will be size 9 * (10 + 1), which is > 64 # xattr raw key list will be > 64
keys = [b'user.attr%d' % i for i in range(9)] keys = [b'user.attr%d' % i for i in range(20)]
for key in keys: for key in keys:
setxattr(tmp_fn, key, b'x') setxattr(tmp_fn, key, b'x')
got_keys = listxattr(tmp_fn) got_keys = listxattr(tmp_fn)
self.assert_equal_se(got_keys, keys) 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): def test_getxattr_buffer_growth(self):
tmp_fn = os.fsencode(self.tmpfile.name) tmp_fn = os.fsencode(self.tmpfile.name)