diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index e4582c7..5fd1c5c 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -216,7 +216,9 @@ jobs: - os: netbsd version: '10.1' display_name: NetBSD - + - os: omnios + version: r151056 + display_name: OmniOS steps: - name: Check out repository @@ -225,7 +227,7 @@ jobs: fetch-tags: true - name: Test on ${{ matrix.display_name }} - uses: cross-platform-actions/action@v0.29.0 + uses: cross-platform-actions/action@v0.32.0 with: operating_system: ${{ matrix.os }} version: ${{ matrix.version }} @@ -320,4 +322,51 @@ jobs: sudo -E python3 -m pytest -s -v -rs tests || rc=$? exit "$rc" ;; + omnios) + # Ensure a proper hostname/FQDN is set (VMs may not have one by default) + pfexec /bin/sh -c 'grep -q "omnios\.local" /etc/hosts || echo "127.0.0.1 omnios.local omnios" >> /etc/hosts' + pfexec hostname omnios.local + hostname + + # Packages + pfexec pkg install developer/versioning/git + pfexec pkg install developer/gcc14 + pfexec pkg set-mediator -V 14 gcc + + # driver + libfuse + pfexec pkg set-publisher -p https://sfe.opencsw.org/localhostomnios localhostomnios + pfexec pkg refresh localhostomnios + pfexec pkg install --accept system/file-system/fusefs + pfexec pkg install --accept system/file-system/libfuse + pkg list system/file-system/fusefs + pkg list system/file-system/libfuse + pkg contents system/file-system/fusefs + pkg contents system/file-system/libfuse + + # Fetch custom build from Tom and install it + modinfo | grep fuse | awk '{print $1}' | while read id; do pfexec modunload -i $id; done + modinfo | grep fuse || true + curl -L https://www.wagner-net.com/~tom/fuse-files-sfe-omnios-r151054-f66c95f374.tar.bz2 -o /tmp/fuse-files.tar.bz2 + pushd / + pfexec tar xvjf /tmp/fuse-files.tar.bz2 + popd + ls -l /usr/gnu/lib/amd64/libfuse.so.2.7.1 /usr/gnu/lib/libfuse.so.2.7.1 /usr/kernel/drv/amd64/fuse + + # Install pip Dependencies + python3 -m pip install pytest pytest-order ioctl-opt + + # Fix PATH + export PATH="/home/runner/.local/bin:$PATH" + echo $PATH + + # Test Installation From Source + python3 -m pip install . + + # Unit Tests (FUSE 2) + python3 -c 'import mfusepy; assert mfusepy.fuse_version_major == 2' + # preserve pytest exit status, always show logs + rc=0 + pfexec python3 -m pytest -v -rs tests || rc=$? + exit "$rc" + ;; esac diff --git a/mfusepy.py b/mfusepy.py index 88b55b9..ced779a 100644 --- a/mfusepy.py +++ b/mfusepy.py @@ -125,6 +125,22 @@ def reg32_get_value(rootkey, keyname, valname): arch = "x64" if sys.maxsize > 0xFFFFFFFF else "x86" _libfuse_path += f"bin\\winfsp-{arch}.dll" # pytype: enable=module-attr + elif _system == 'SunOS': + _libfuse_path = find_library('fuse') or find_library('fuse3') + if not _libfuse_path: + for path in [ + '/usr/gnu/lib/amd64/libfuse.so', + '/usr/gnu/lib/libfuse.so', + '/usr/lib/amd64/libfuse.so.2', + '/usr/lib/libfuse.so.2', + '/usr/lib/amd64/libfuse.so', + '/usr/lib/libfuse.so', + '/lib/amd64/libfuse.so.2', + '/lib/libfuse.so.2', + ]: + if os.path.exists(path): + _libfuse_path = path + break elif _libfuse_name := os.environ.get('FUSE_LIBRARY_NAME'): _libfuse_path = find_library(_libfuse_name) else: @@ -588,6 +604,47 @@ def get_fuse_version(libfuse): ('st_gen', ctypes.c_uint32), ('st_spare', ctypes.c_uint32 * 2), ] +elif _system == 'SunOS': + ENOTSUP = 48 + c_dev_t = ctypes.c_uint64 + c_uid_t = ctypes.c_uint32 + c_gid_t = ctypes.c_uint32 + c_mode_t = ctypes.c_uint32 + c_off_t = ctypes.c_int64 + c_pid_t = ctypes.c_int32 + setxattr_t = ctypes.CFUNCTYPE( + ctypes.c_int, + ctypes.c_char_p, + ctypes.c_char_p, + c_byte_p, + ctypes.c_size_t, + ctypes.c_int, + ) + getxattr_t = ctypes.CFUNCTYPE( + ctypes.c_int, + ctypes.c_char_p, + ctypes.c_char_p, + c_byte_p, + ctypes.c_size_t, + ) + c_fsblkcnt_t = ctypes.c_uint64 + c_fsfilcnt_t = ctypes.c_uint64 + _c_stat__fields_ = [ + ('st_dev', c_dev_t), + ('st_ino', ctypes.c_uint64), + ('st_mode', c_mode_t), + ('st_nlink', ctypes.c_uint32), + ('st_uid', c_uid_t), + ('st_gid', c_gid_t), + ('st_rdev', c_dev_t), + ('st_size', c_off_t), + ('st_atimespec', c_timespec), + ('st_mtimespec', c_timespec), + ('st_ctimespec', c_timespec), + ('st_blksize', ctypes.c_int32), + ('st_blocks', ctypes.c_int64), + ('st_fstype', ctypes.c_char * 16), + ] else: raise NotImplementedError(_system + ' is not supported.') @@ -677,6 +734,23 @@ class c_statvfs(ctypes.Structure): ('f_mntfromname', ctypes.c_char * 1024), ('f_mntfromlabel', ctypes.c_char * 1024), ] + elif _system == 'SunOS': + # Source: /usr/include/sys/statvfs.h + _fields_ = [ + ('f_bsize', ctypes.c_ulong), + ('f_frsize', ctypes.c_ulong), + ('f_blocks', c_fsblkcnt_t), + ('f_bfree', c_fsblkcnt_t), + ('f_bavail', c_fsblkcnt_t), + ('f_files', c_fsfilcnt_t), + ('f_ffree', c_fsfilcnt_t), + ('f_favail', c_fsfilcnt_t), + ('f_fsid', ctypes.c_ulong), + ('f_basetype', ctypes.c_char * 16), + ('f_flag', ctypes.c_ulong), + ('f_namemax', ctypes.c_ulong), + ('f_fstr', ctypes.c_char * 32), + ] else: # https://sourceware.org/git?p=glibc.git;a=blob;f=bits/statvfs.h;h=ea89d9004d834c81874de00b5e3f5617d3096ccc;hb=HEAD#l33 _fields_ = [ @@ -880,12 +954,16 @@ class fuse_context(ctypes.Structure): ('gid', c_gid_t), ('pid', c_pid_t), ('private_data', ctypes.c_void_p), - # Added in 2.8. Note that this is an ABI break because programs compiled against 2.7 - # will allocate a smaller struct leading to out-of-bound accesses when used for a 2.8 - # shared library! It shouldn't hurt the other way around to have a larger struct than - # the shared library expects. The newer members will simply be ignored. - ('umask', c_mode_t), ] + # OpenBSD announces 2.6, but still has the umask struct member. + if fuse_version_major == 3 or (fuse_version_major == 2 and fuse_version_minor >= 8) or _system == 'OpenBSD': + _fields_ += [ + # Added in 2.8. Note that this is an ABI break because programs compiled against 2.7 + # will allocate a smaller struct leading to out-of-bound accesses when used for a 2.8 + # shared library! It shouldn't hurt the other way around to have a larger struct than + # the shared library expects. The newer members will simply be ignored. + ('umask', c_mode_t), + ] _libfuse.fuse_get_context.restype = ctypes.POINTER(fuse_context) diff --git a/tests/test_struct_layout.py b/tests/test_struct_layout.py index 142a92a..f63baee 100644 --- a/tests/test_struct_layout.py +++ b/tests/test_struct_layout.py @@ -85,6 +85,31 @@ if platform.system() != 'NetBSD': STRUCT_NAMES['fuse_file_info'] = ['flags', 'fh', 'lock_owner'] +if platform.system() == 'SunOS': + STRUCT_NAMES['statvfs'] = [ + 'f_bavail', + 'f_bfree', + 'f_blocks', + 'f_bsize', + 'f_favail', + 'f_ffree', + 'f_files', + 'f_flag', + 'f_frsize', + 'f_fsid', + 'f_namemax', + 'f_basetype', # SunOS only + 'f_fstr', # SunOS only + ] + STRUCT_NAMES['fuse_context'] = ['fuse', 'uid', 'gid', 'pid'] # no 'umask' on SunOS + STRUCT_NAMES['fuse_conn_info'] = [ + 'proto_major', + 'proto_minor', + 'max_write', + 'max_readahead', + # 4 attrs not present on SunOS + ] + if mfusepy.fuse_version_major == 3: STRUCT_NAMES['fuse_config'] = [ 'set_gid', @@ -178,6 +203,7 @@ def c_run(name: str, source: str) -> str: '/usr/local/include/osxfuse/fuse', '/usr/local/include/macfuse/fuse', '/usr/include/libfuse', + '/usr/gnu/include/fuse', ] if mfusepy.fuse_version_major == 3: include_paths += ['/usr/local/include/fuse3', '/usr/include/fuse3']