Skip to content

Commit e1bc1b2

Browse files
committed
[fix] Fix FUSE struct issues on NetBSD
1 parent 1d8e708 commit e1bc1b2

File tree

4 files changed

+238
-126
lines changed

4 files changed

+238
-126
lines changed

.github/workflows/tests.yml

Lines changed: 11 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -132,7 +132,7 @@ jobs:
132132
# https://github.com/pyca/pynacl/issues/839
133133
# https://github.com/pyca/pynacl/pull/848
134134
python3 -m pip install --upgrade git+https://github.com/pyca/pynacl.git
135-
python3 -m pip install --upgrade-strategy eager --upgrade twine build pytest ioctl-opt paramiko types-paramiko
135+
python3 -m pip install --upgrade-strategy eager --upgrade twine build pytest pytest-order ioctl-opt paramiko types-paramiko
136136
137137
- name: Test Installation From Tarball
138138
run: |
@@ -194,18 +194,24 @@ jobs:
194194
timeout-minutes: 10
195195

196196
strategy:
197-
fail-fast: false
198197
matrix:
199198
include:
200199
- os: freebsd
201200
version: '14.3'
202201
display_name: FreeBSD
202+
- os: freebsd
203+
version: '13.5'
204+
display_name: FreeBSD
203205
- os: openbsd
204206
version: '7.7'
205207
display_name: OpenBSD
208+
# OpenBSD 6.9 is not supported because it only has Python 3.8, which is not supported anymore.
206209
- os: netbsd
207210
version: '10.1'
208211
display_name: NetBSD
212+
- os: netbsd
213+
version: '9.4'
214+
display_name: NetBSD
209215

210216
steps:
211217
- name: Check out repository
@@ -241,11 +247,7 @@ jobs:
241247
sudo -E chmod 666 /dev/fuse
242248
243249
# Install pip Dependencies
244-
python3 -m pip install --upgrade pip
245-
python3 -m pip install --upgrade wheel
246-
python3 -m pip install --upgrade setuptools
247-
python3 -m pip install "pynacl==1.5.0"
248-
python3 -m pip install pytest ioctl-opt
250+
python3 -m pip install pytest pytest-order ioctl-opt
249251
250252
# Test Installation From Source
251253
python3 -m pip install .
@@ -267,11 +269,7 @@ jobs:
267269
# Install pip Dependencies
268270
python3 -m venv .venv
269271
source .venv/bin/activate
270-
python3 -m pip install --upgrade pip
271-
python3 -m pip install --upgrade wheel
272-
python3 -m pip install --upgrade setuptools
273-
python3 -m pip install "pynacl==1.5.0"
274-
python3 -m pip install pytest ioctl-opt
272+
python3 -m pip install pytest pytest-order ioctl-opt
275273
276274
# Test Installation From Source
277275
python3 -m pip install .
@@ -305,11 +303,7 @@ jobs:
305303
sudo chmod 777 /var/run
306304
307305
# Install pip Dependencies
308-
python3 -m pip install --upgrade pip
309-
python3 -m pip install --upgrade wheel
310-
python3 -m pip install --upgrade setuptools
311-
python3 -m pip install "pynacl==1.5.0"
312-
python3 -m pip install pytest ioctl-opt
306+
python3 -m pip install pytest pytest-order ioctl-opt
313307
314308
# Test Installation From Source
315309
python3 -m pip install .

mfusepy.py

Lines changed: 56 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@
3434
from typing import TYPE_CHECKING, Any, Optional, Union, get_type_hints
3535

3636
FieldsEntry = Union[tuple[str, type], tuple[str, type, int]]
37+
BitFieldsEntry = tuple[str, type, int]
3738
ReadDirResult = Iterable[Union[str, tuple[str, dict[str, int], int], tuple[str, int, int]]]
3839

3940
if TYPE_CHECKING:
@@ -742,9 +743,60 @@ class c_flock_t(ctypes.Structure): # type: ignore
742743
# - 3.14.1 -> 3.16.2: no change
743744
_fuse_int32 = ctypes.c_int32 if (fuse_version_major, fuse_version_minor) >= (3, 17) else ctypes.c_int
744745
_fuse_uint32 = ctypes.c_uint32 if (fuse_version_major, fuse_version_minor) >= (3, 17) else ctypes.c_uint
745-
if fuse_version_major == 2:
746+
_fuse_file_info_fields_: list[FieldsEntry] = []
747+
_fuse_file_info_fields_bitfield: list[BitFieldsEntry] = []
748+
if _system == 'NetBSD':
749+
# NetBSD has its own FUSE library reimplementation with mismatching struct layouts!
750+
# writepage is a bitfield (as in libFUSE 3.x), but the fh_old member still exists and the reported version is 2.9!
751+
# https://www.netbsd.org/docs/puffs/
752+
# https://github.com/NetBSD/src/blob/netbsd-11/lib/librefuse/fuse.h#L100-L129
753+
# https://github.com/NetBSD/src/blob/netbsd-10/lib/librefuse/fuse.h#L100-L129
754+
# - fuse_file_info is unchanged between 10 and 11
755+
# - FUSE_USE_VERSION is not set, but is set to _REFUSE_VERSION_ (3.10) with a warning if not set!
756+
# - However, the CI prints FUSE version 2.9?!
757+
# - Seems there is no sane way to get the correct compiled version! This is again an absolute shit show!
758+
# https://github.com/NetBSD/src/blob/netbsd-9/lib/librefuse/fuse.h#L51-L61
759+
# - fuse_file_info looks quite different and version is specified as 2.6!
760+
# - #define FUSE_USE_VERSION 26
761+
fuse_version = (fuse_version_major, fuse_version_minor)
762+
_fuse_file_info_fields_ = [
763+
('flags', ctypes.c_int32),
764+
('fh_old', ctypes.c_uint32),
765+
]
766+
767+
if fuse_version >= (2, 9):
768+
_fuse_file_info_fields_bitfield += [('writepage', ctypes.c_int32, 1)]
769+
else:
770+
_fuse_file_info_fields_ += [('writepage', ctypes.c_int32)]
771+
772+
_fuse_file_info_fields_bitfield += [
773+
('direct_io', ctypes.c_uint32, 1), # Introduced in FUSE 2.4
774+
('keep_cache', ctypes.c_uint32, 1), # Introduced in FUSE 2.4
775+
('flush', ctypes.c_uint32, 1), # Introduced in FUSE 2.6
776+
]
777+
if fuse_version >= (2, 9):
778+
_fuse_file_info_fields_bitfield += [
779+
('nonseekable', ctypes.c_uint, 1), # Introduced in FUSE 2.8
780+
('flock_release', ctypes.c_uint, 1), # Introduced in FUSE 2.9
781+
('cache_readdir', ctypes.c_uint, 1), # Introduced in FUSE 3.5
782+
]
783+
784+
_fuse_file_info_flag_count = sum(x[2] for x in _fuse_file_info_fields_bitfield)
785+
assert _fuse_file_info_flag_count < ctypes.sizeof(_fuse_uint32) * 8
786+
787+
_fuse_file_info_fields_ += _fuse_file_info_fields_bitfield
788+
_fuse_file_info_fields_ += [
789+
('padding', _fuse_uint32, ctypes.sizeof(_fuse_uint32) * 8 - _fuse_file_info_flag_count),
790+
('fh', ctypes.c_uint64),
791+
('lock_owner', ctypes.c_uint64),
792+
]
793+
794+
if fuse_version >= (2, 9):
795+
_fuse_file_info_fields_ += [('poll_events', ctypes.c_uint32)]
796+
797+
elif fuse_version_major == 2:
746798
_fh_old_type = ctypes.c_uint if _system == 'OpenBSD' else ctypes.c_ulong
747-
_fuse_file_info_fields_: list[FieldsEntry] = [
799+
_fuse_file_info_fields_ = [
748800
('flags', ctypes.c_int),
749801
('fh_old', _fh_old_type),
750802
('writepage', ctypes.c_int),
@@ -972,7 +1024,8 @@ class fuse_conn_info(ctypes.Structure): # Added in 2.6 (ABI break of "init" fro
9721024
# Another ABI break as discussed here: https://lists.debian.org/debian-devel/2024/03/msg00278.html
9731025
# The break was in 3.14.1 NOT in 3.14.0, but I cannot query the bugfix version.
9741026
# I'd hope that all 3.14.0 installations have been replaced by updates to 3.14.1.
975-
if fuse_version_minor >= 14 and fuse_version_minor < 17:
1027+
# ... they have not. My own system, Ubuntu 24.04 uses fuse 3.14.0. Check for >= 3.15.
1028+
if fuse_version_minor >= 15 and fuse_version_minor < 17:
9761029
_fuse_config_fields_ += [('parallel_direct_writes', ctypes.c_int)]
9771030

9781031
_fuse_config_fields_ += [

tests/requirements-tests.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,3 +9,4 @@ pylint
99
pytest
1010
pytype
1111
mypy
12+
pytest-order

0 commit comments

Comments
 (0)