Skip to content

Commit 270b705

Browse files
Merge pull request #7442 from ThomasWaldmann/freebsd-xattr-fixes-master
xattrs: fix namespace processing on FreeBSD, fixes #6997
2 parents 800e8dd + 88231a2 commit 270b705

File tree

1 file changed

+43
-25
lines changed

1 file changed

+43
-25
lines changed

src/borg/platform/freebsd.pyx

Lines changed: 43 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -50,59 +50,77 @@ cdef extern from "unistd.h":
5050
int _PC_ACL_NFS4
5151

5252

53-
def listxattr(path, *, follow_symlinks=False):
54-
ns, prefix = EXTATTR_NAMESPACE_USER, b'user.'
53+
# On FreeBSD, borg currently only deals with the USER namespace as it is unclear
54+
# whether (and if so, how exactly) it should deal with the SYSTEM namespace.
55+
NS_ID_MAP = {b"user": EXTATTR_NAMESPACE_USER, }
56+
57+
58+
def split_ns(ns_name, default_ns):
59+
# split ns_name (which is in the form of b"namespace.name") into namespace and name.
60+
# if there is no namespace given in ns_name, default to default_ns.
61+
# note:
62+
# borg < 1.1.10 on FreeBSD did not prefix the namespace to the names, see #3952.
63+
# we also need to deal with "unexpected" namespaces here, they could come
64+
# from borg archives made on other operating systems.
65+
ns_name_tuple = ns_name.split(b".", 1)
66+
if len(ns_name_tuple) == 2:
67+
# we have a namespace prefix in the given name
68+
ns, name = ns_name_tuple
69+
else:
70+
# no namespace given in ns_name (== no dot found), maybe data coming from an old borg archive.
71+
ns, name = default_ns, ns_name
72+
return ns, name
73+
5574

75+
def listxattr(path, *, follow_symlinks=False):
5676
def func(path, buf, size):
5777
if isinstance(path, int):
58-
return c_extattr_list_fd(path, ns, <char *> buf, size)
78+
return c_extattr_list_fd(path, ns_id, <char *> buf, size)
5979
else:
6080
if follow_symlinks:
61-
return c_extattr_list_file(path, ns, <char *> buf, size)
81+
return c_extattr_list_file(path, ns_id, <char *> buf, size)
6282
else:
63-
return c_extattr_list_link(path, ns, <char *> buf, size)
83+
return c_extattr_list_link(path, ns_id, <char *> buf, size)
6484

85+
ns = b"user"
86+
ns_id = NS_ID_MAP[ns]
6587
n, buf = _listxattr_inner(func, path)
66-
return [prefix + name for name in split_lstring(buf[:n]) if name]
88+
return [ns + b"." + name for name in split_lstring(buf[:n]) if name]
6789

6890

6991
def getxattr(path, name, *, follow_symlinks=False):
70-
ns, prefix = EXTATTR_NAMESPACE_USER, b'user.'
71-
7292
def func(path, name, buf, size):
7393
if isinstance(path, int):
74-
return c_extattr_get_fd(path, ns, name, <char *> buf, size)
94+
return c_extattr_get_fd(path, ns_id, name, <char *> buf, size)
7595
else:
7696
if follow_symlinks:
77-
return c_extattr_get_file(path, ns, name, <char *> buf, size)
97+
return c_extattr_get_file(path, ns_id, name, <char *> buf, size)
7898
else:
79-
return c_extattr_get_link(path, ns, name, <char *> buf, size)
99+
return c_extattr_get_link(path, ns_id, name, <char *> buf, size)
80100

81-
# strip namespace if there, but ignore if not there.
82-
# older borg / attic versions did not prefix the namespace to the names.
83-
if name.startswith(prefix):
84-
name = name[len(prefix):]
101+
ns, name = split_ns(name, b"user")
102+
ns_id = NS_ID_MAP[ns] # this will raise a KeyError it the namespace is unsupported
85103
n, buf = _getxattr_inner(func, path, name)
86104
return bytes(buf[:n])
87105

88106

89107
def setxattr(path, name, value, *, follow_symlinks=False):
90-
ns, prefix = EXTATTR_NAMESPACE_USER, b'user.'
91-
92108
def func(path, name, value, size):
93109
if isinstance(path, int):
94-
return c_extattr_set_fd(path, ns, name, <char *> value, size)
110+
return c_extattr_set_fd(path, ns_id, name, <char *> value, size)
95111
else:
96112
if follow_symlinks:
97-
return c_extattr_set_file(path, ns, name, <char *> value, size)
113+
return c_extattr_set_file(path, ns_id, name, <char *> value, size)
98114
else:
99-
return c_extattr_set_link(path, ns, name, <char *> value, size)
115+
return c_extattr_set_link(path, ns_id, name, <char *> value, size)
100116

101-
# strip namespace if there, but ignore if not there.
102-
# older borg / attic versions did not prefix the namespace to the names.
103-
if name.startswith(prefix):
104-
name = name[len(prefix):]
105-
_setxattr_inner(func, path, name, value)
117+
ns, name = split_ns(name, b"user")
118+
try:
119+
ns_id = NS_ID_MAP[ns] # this will raise a KeyError it the namespace is unsupported
120+
except KeyError:
121+
pass
122+
else:
123+
_setxattr_inner(func, path, name, value)
106124

107125

108126
cdef _get_acl(p, type, item, attribute, flags, fd=None):

0 commit comments

Comments
 (0)