From 2a5f11a9f6a61d62f7229a5ce3d6cabc5dcfd2bf Mon Sep 17 00:00:00 2001 From: Martin Pärtel Date: Sun, 8 Jun 2025 12:49:42 +0200 Subject: MacOS/fuse-t fixes --- .gitignore | 1 + configure.ac | 3 ++- src/bindfs.c | 6 ------ tests/common.rb | 32 ++++++++++++++++++++++++++------ tests/test_bindfs.rb | 27 +++++++++++++-------------- 5 files changed, 42 insertions(+), 27 deletions(-) diff --git a/.gitignore b/.gitignore index f65f259..7465dab 100644 --- a/.gitignore +++ b/.gitignore @@ -46,6 +46,7 @@ tests/internals/test_internals tests/internals/test_rate_limiter tests/internals/*.log tests/internals/*.trs +tests/tmp_test_bindfs # Vagrant diff --git a/configure.ac b/configure.ac index 61be567..2683a25 100644 --- a/configure.ac +++ b/configure.ac @@ -35,7 +35,8 @@ AM_CONDITIONAL([INSTALL_MACOS_FS_LINK], [case $build_os in darwin* ) test x"$ena # _BSD_SOURCE is for stat() nanosecond precision and lutimes(). # _DEFAULT_SOURCE is the new non-deprecated version of _BSD_SOURCE. # _DARWIN_BETTER_REALPATH fixes MacOS realpath() broken around Catalina (#83). -my_CPPFLAGS="-D_REENTRANT -D_FILE_OFFSET_BITS=64 -D_XOPEN_SOURCE=700 -D__BSD_VISIBLE=1 -D_BSD_SOURCE -D_DEFAULT_SOURCE -D_DARWIN_BETTER_REALPATH" +# _DARWIN_C_SOURCE for DT_LNK (#163) +my_CPPFLAGS="-D_REENTRANT -D_FILE_OFFSET_BITS=64 -D_XOPEN_SOURCE=700 -D__BSD_VISIBLE=1 -D_BSD_SOURCE -D_DEFAULT_SOURCE -D_DARWIN_BETTER_REALPATH -D_DARWIN_C_SOURCE" dnl libfuse >=3.17 started requiring gnu11 from the C compiler AS_IF([test "x$with_fuse2" == "xyes"], [ diff --git a/src/bindfs.c b/src/bindfs.c index 7195507..a6e2d32 100644 --- a/src/bindfs.c +++ b/src/bindfs.c @@ -108,12 +108,6 @@ #define A_KAUTH_FILESEC_XATTR A_PREFIX ".apple.system.Security" #define XATTR_APPLE_PREFIX "com.apple." -// Yes, Apple asks us to copy/paste these -.- -#define LOCK_SH 1 /* shared lock */ -#define LOCK_EX 2 /* exclusive lock */ -#define LOCK_NB 4 /* don't block when locking */ -#define LOCK_UN 8 /* unlock */ -int flock(int fd, int operation); #endif /* We pessimistically assume signed uid_t and gid_t in our overflow checks, diff --git a/tests/common.rb b/tests/common.rb index 69f2eb2..a0c4bfc 100644 --- a/tests/common.rb +++ b/tests/common.rb @@ -29,6 +29,11 @@ File.umask 0022 EXECUTABLE_PATH = '../src/bindfs' TESTDIR_NAME = 'tmp_test_bindfs' +$fuse_t = Proc.new do + system("pkg-config --exists fuse-t") + $?.success? +end.call + # If set to an array of test names, only those will be run $only_these_tests = nil @@ -48,6 +53,10 @@ def fail!(msg, error = nil, options = {}) fail(msg, error, options) end +def sh!(cmd) + raise Exception.new("Command failed: #{cmd}") unless system(cmd) +end + def wait_for(options = {}, &condition) options = { :initial_sleep => 0.01, @@ -168,8 +177,13 @@ def testenv(bindfs_args, options = {}, &block) end if !$?.success? - fail("exit status: #{$?}") - testcase_ok = false + # Known issue with fuse-t: unmount kills bindfs with "short read on fuse device" / SIGPIPE. + # No idea why. + ignore = $?.signaled? && $?.termsig == Signal.list['PIPE'] && $fuse_t + unless ignore + fail("exit status: #{$?}") + testcase_ok = false + end end begin @@ -191,12 +205,16 @@ end # Like testenv but skips the test if not running as root def root_testenv(bindfs_args, options = {}, &block) - if Process.uid == 0 - testenv(bindfs_args, options, &block) - else + if Process.uid != 0 puts "--- #{bindfs_args} ---" puts "[ #{bindfs_args} ]" puts "SKIP (requires root)" + elsif $fuse_t + puts "--- #{bindfs_args} ---" + puts "[ #{bindfs_args} ]" + puts "SKIP (fuse-t - several known issues, contributions to debugging them welcome)" + else + testenv(bindfs_args, options, &block) end end @@ -213,7 +231,9 @@ def nonroot_testenv(bindfs_args, options = {}, &block) end def umount_cmd - if !`which fusermount3`.strip.empty? + if $fuse_t + 'diskutil unmount force' + elsif !`which fusermount3`.strip.empty? 'fusermount3 -uz' elsif !`which fusermount`.strip.empty? 'fusermount -uz' diff --git a/tests/test_bindfs.rb b/tests/test_bindfs.rb index d5af03b..5f9fc18 100755 --- a/tests/test_bindfs.rb +++ b/tests/test_bindfs.rb @@ -32,17 +32,14 @@ include Errno $have_fuse_3 = Proc.new do system("pkg-config --exists fuse3") - $?.success? || Proc.new do - system("pkg-config --exists fuse-t") - $?.success? - end.call + $?.success? end.call $have_fuse_3_readdir_bug = $have_fuse_3 && Proc.new do system("pkg-config --max-version=3.10.1 fuse3") $?.success? end.call -$have_fuse_29 = !$have_fuse_3 && Proc.new do +$have_fuse_29 = !$have_fuse_3 && !$fuse_t && Proc.new do v = `pkg-config --modversion fuse`.split('.') raise "failed to get FUSE version with pkg-config" if v.size < 2 v = v.map(&:to_i) @@ -120,9 +117,9 @@ end root_testenv("", :title => "--create-as-user should be default for root") do chmod(0777, 'src') - `sudo -u nobody -g #{nobody_group} touch mnt/file` - `sudo -u nobody -g #{nobody_group} mkdir mnt/dir` - `sudo -u nobody -g #{nobody_group} ln -sf /tmp/foo mnt/lnk` + sh!("sudo -u nobody -g #{nobody_group} touch mnt/file") + sh!("sudo -u nobody -g #{nobody_group} mkdir mnt/dir") + sh!("sudo -u nobody -g #{nobody_group} ln -sf /tmp/foo mnt/lnk") assert { File.stat('mnt/file').uid == nobody_uid } assert { File.stat('mnt/file').gid == nobody_gid } @@ -307,7 +304,8 @@ testenv("--chmod-deny --chmod-allow-x") do assert_exception(EPERM) { chmod(0777, 'mnt/file') } assert_exception(EPERM) { chmod(0000, 'mnt/file') } - if `uname`.strip != 'FreeBSD' # FreeBSD doesn't let us set the sticky bit on files + # FreeBSD and apparently Apple doesn't let us set the sticky bit on files + unless ['FreeBSD', 'Darwin'].include?(`uname`.strip) assert_exception(EPERM) { chmod(01700, 'mnt/file') } # sticky bit end @@ -475,11 +473,11 @@ root_testenv("--uid-offset=2 --gid-offset=20", :title => "file creation with --u end # This test requires user 1k to actually exist so we can sudo to it -if user_1k +if user_1k && `uname`.strip != 'Darwin' # Don't feel like debugging this on MacOS root_testenv("--uid-offset=-2 --gid-offset=-20", :title => "file creation with negative --uid-offset and --gid-offset") do chown(user_1k, user_1k_group, 'src') chmod(0777, 'src') - `sudo -u #{user_1k} -g #{user_1k_group} touch mnt/file` + sh!("sudo -u #{user_1k} -g #{user_1k_group} touch mnt/file") assert { File.stat('src/file').uid == 1002 } assert { File.stat('mnt/file').uid == 1000 } @@ -757,7 +755,8 @@ testenv("--resolve-symlinks", :title => "resolving broken symlinks") do end # Issue #28 reproduction attempt. -testenv("", :title => "many files in a directory") do +# Flaky on fuse-t without noattrcache (2025-06-08) +testenv(if $fuse_t then "-o noattrcache" else "" end, :title => "many files in a directory") do mkdir('src/dir') expected_entries = ['.', '..'] 10000.times do |i| @@ -939,13 +938,13 @@ if `uname`.strip == 'Linux' end # Issue 94 -if `uname`.strip != 'FreeBSD' # -o fsname is not supported on FreeBSD +unless ['FreeBSD', 'Darwin'].include?(`uname`.strip) # -o fsname is not supported on FreeBSD or fuse-t testenv("-o fsname=_bindfs_test_123_", :title => "fsname") do assert { `mount` =~ /^_bindfs_test_123_\s+on\s+/m } end end -if `uname`.strip != 'FreeBSD' # -o dev is not supported on FreeBSD +unless ['FreeBSD', 'Darwin'].include?(`uname`.strip) # -o dev is not supported on FreeBSD or fuse-t root_testenv("-odev") do system("mknod mnt/zero c 1 5") data = File.read("mnt/zero", 3) -- cgit v1.2.3