@@ -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
6991def 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
89107def 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
108126cdef _get_acl(p, type , item, attribute, flags, fd = None ):
0 commit comments