Skip to content

Commit bf4d5dc

Browse files
NetBSD: copy xattr implementation of FreeBSD, fixes #1332
1 parent 825386a commit bf4d5dc

File tree

3 files changed

+108
-2
lines changed

3 files changed

+108
-2
lines changed

setup.py

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,7 @@
6161
platform_syncfilerange_source = "src/borg/platform/syncfilerange.pyx"
6262
platform_darwin_source = "src/borg/platform/darwin.pyx"
6363
platform_freebsd_source = "src/borg/platform/freebsd.pyx"
64+
platform_netbsd_source = "src/borg/platform/netbsd.pyx"
6465
platform_windows_source = "src/borg/platform/windows.pyx"
6566

6667
cython_sources = [
@@ -76,6 +77,7 @@
7677
platform_linux_source,
7778
platform_syncfilerange_source,
7879
platform_freebsd_source,
80+
platform_netbsd_source,
7981
platform_darwin_source,
8082
platform_windows_source,
8183
]
@@ -197,6 +199,7 @@ def lib_ext_kwargs(pc, prefix_env_var, lib_name, lib_pkg_name, pc_version, lib_s
197199
"borg.platform.syncfilerange", [platform_syncfilerange_source], extra_compile_args=cflags
198200
)
199201
freebsd_ext = Extension("borg.platform.freebsd", [platform_freebsd_source], extra_compile_args=cflags)
202+
netbsd_ext = Extension("borg.platform.netbsd", [platform_netbsd_source], extra_compile_args=cflags)
200203
darwin_ext = Extension("borg.platform.darwin", [platform_darwin_source], extra_compile_args=cflags)
201204
windows_ext = Extension("borg.platform.windows", [platform_windows_source], extra_compile_args=cflags)
202205

@@ -209,6 +212,8 @@ def lib_ext_kwargs(pc, prefix_env_var, lib_name, lib_pkg_name, pc_version, lib_s
209212
ext_modules.append(syncfilerange_ext)
210213
elif sys.platform.startswith("freebsd"):
211214
ext_modules.append(freebsd_ext)
215+
elif sys.platform.startswith("netbsd"):
216+
ext_modules.append(netbsd_ext)
212217
elif sys.platform == "darwin":
213218
ext_modules.append(darwin_ext)
214219

@@ -230,7 +235,9 @@ def lib_ext_kwargs(pc, prefix_env_var, lib_name, lib_pkg_name, pc_version, lib_s
230235

231236
# generate C code from Cython for ALL supported platforms, so we have them in the sdist.
232237
# the sdist does not require Cython at install time, so we need all as C.
233-
cythonize([posix_ext, linux_ext, syncfilerange_ext, freebsd_ext, darwin_ext, windows_ext], **cython_opts)
238+
cythonize(
239+
[posix_ext, linux_ext, syncfilerange_ext, freebsd_ext, netbsd_ext, darwin_ext, windows_ext], **cython_opts
240+
)
234241
# generate C code from Cython for THIS platform (and for all platform-independent Cython parts).
235242
ext_modules = cythonize(ext_modules, **cython_opts)
236243

src/borg/platform/__init__.py

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
Public APIs are documented in platform.base.
55
"""
66

7-
from ..platformflags import is_win32, is_linux, is_freebsd, is_darwin, is_cygwin
7+
from ..platformflags import is_win32, is_linux, is_freebsd, is_netbsd, is_darwin, is_cygwin
88

99
from .base import ENOATTR, API_VERSION
1010
from .base import SaveFile, sync_dir, fdatasync, safe_fadvise
@@ -31,6 +31,16 @@
3131
from .posix import swidth
3232
from .posix import get_errno
3333
from .posix import uid2user, user2uid, gid2group, group2gid, getosusername
34+
elif is_netbsd: # pragma: netbsd only
35+
from .netbsd import API_VERSION as OS_API_VERSION
36+
from .netbsd import listxattr, getxattr, setxattr
37+
from .base import acl_get, acl_set
38+
from .base import set_flags, get_flags
39+
from .base import SyncFile
40+
from .posix import process_alive, local_pid_alive
41+
from .posix import swidth
42+
from .posix import get_errno
43+
from .posix import uid2user, user2uid, gid2group, group2gid, getosusername
3444
elif is_darwin: # pragma: darwin only
3545
from .darwin import API_VERSION as OS_API_VERSION
3646
from .darwin import listxattr, getxattr, setxattr

src/borg/platform/netbsd.pyx

Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
from .xattr import _listxattr_inner, _getxattr_inner, _setxattr_inner, split_lstring
2+
3+
API_VERSION = '1.2_05'
4+
5+
cdef extern from "sys/extattr.h":
6+
ssize_t c_extattr_list_file "extattr_list_file" (const char *path, int attrnamespace, void *data, size_t nbytes)
7+
ssize_t c_extattr_list_link "extattr_list_link" (const char *path, int attrnamespace, void *data, size_t nbytes)
8+
ssize_t c_extattr_list_fd "extattr_list_fd" (int fd, int attrnamespace, void *data, size_t nbytes)
9+
10+
ssize_t c_extattr_get_file "extattr_get_file" (const char *path, int attrnamespace, const char *attrname, void *data, size_t nbytes)
11+
ssize_t c_extattr_get_link "extattr_get_link" (const char *path, int attrnamespace, const char *attrname, void *data, size_t nbytes)
12+
ssize_t c_extattr_get_fd "extattr_get_fd" (int fd, int attrnamespace, const char *attrname, void *data, size_t nbytes)
13+
14+
int c_extattr_set_file "extattr_set_file" (const char *path, int attrnamespace, const char *attrname, const void *data, size_t nbytes)
15+
int c_extattr_set_link "extattr_set_link" (const char *path, int attrnamespace, const char *attrname, const void *data, size_t nbytes)
16+
int c_extattr_set_fd "extattr_set_fd" (int fd, int attrnamespace, const char *attrname, const void *data, size_t nbytes)
17+
18+
int EXTATTR_NAMESPACE_USER
19+
20+
21+
# On NetBSD, Borg currently only deals with the USER namespace, as it is unclear
22+
# whether (and, if so, how exactly) it should deal with the SYSTEM namespace.
23+
NS_ID_MAP = {b"user": EXTATTR_NAMESPACE_USER, }
24+
25+
26+
def split_ns(ns_name, default_ns):
27+
# Split ns_name (which is in the form b"namespace.name") into namespace and name.
28+
# If there is no namespace given in ns_name, default to default_ns.
29+
# We also need to deal with "unexpected" namespaces here — they could come
30+
# from Borg archives made on other operating systems.
31+
ns_name_tuple = ns_name.split(b".", 1)
32+
if len(ns_name_tuple) == 2:
33+
# We have a namespace prefix in the given name.
34+
ns, name = ns_name_tuple
35+
else:
36+
# No namespace given in ns_name (no dot found); maybe data from an old Borg archive.
37+
ns, name = default_ns, ns_name
38+
return ns, name
39+
40+
41+
def listxattr(path, *, follow_symlinks=False):
42+
def func(path, buf, size):
43+
if isinstance(path, int):
44+
return c_extattr_list_fd(path, ns_id, <char *> buf, size)
45+
else:
46+
if follow_symlinks:
47+
return c_extattr_list_file(path, ns_id, <char *> buf, size)
48+
else:
49+
return c_extattr_list_link(path, ns_id, <char *> buf, size)
50+
51+
ns = b"user"
52+
ns_id = NS_ID_MAP[ns]
53+
n, buf = _listxattr_inner(func, path)
54+
return [ns + b"." + name for name in split_lstring(buf[:n]) if name]
55+
56+
57+
def getxattr(path, name, *, follow_symlinks=False):
58+
def func(path, name, buf, size):
59+
if isinstance(path, int):
60+
return c_extattr_get_fd(path, ns_id, name, <char *> buf, size)
61+
else:
62+
if follow_symlinks:
63+
return c_extattr_get_file(path, ns_id, name, <char *> buf, size)
64+
else:
65+
return c_extattr_get_link(path, ns_id, name, <char *> buf, size)
66+
67+
ns, name = split_ns(name, b"user")
68+
ns_id = NS_ID_MAP[ns] # this will raise a KeyError it the namespace is unsupported
69+
n, buf = _getxattr_inner(func, path, name)
70+
return bytes(buf[:n])
71+
72+
73+
def setxattr(path, name, value, *, follow_symlinks=False):
74+
def func(path, name, value, size):
75+
if isinstance(path, int):
76+
return c_extattr_set_fd(path, ns_id, name, <char *> value, size)
77+
else:
78+
if follow_symlinks:
79+
return c_extattr_set_file(path, ns_id, name, <char *> value, size)
80+
else:
81+
return c_extattr_set_link(path, ns_id, name, <char *> value, size)
82+
83+
ns, name = split_ns(name, b"user")
84+
try:
85+
ns_id = NS_ID_MAP[ns] # this will raise a KeyError it the namespace is unsupported
86+
except KeyError:
87+
pass
88+
else:
89+
_setxattr_inner(func, path, name, value)

0 commit comments

Comments
 (0)