diff --git a/test/fuse_integration/framework.go b/test/fuse_integration/framework.go index 71eaf61873..8424fb1d79 100644 --- a/test/fuse_integration/framework.go +++ b/test/fuse_integration/framework.go @@ -108,6 +108,11 @@ func (f *FuseTestFramework) Setup(config *TestConfig) error { if !mountedAt(existingMount) { return fmt.Errorf("mount point %s is not a mounted filesystem", existingMount) } + // So can a non-FUSE mount like tmpfs: a device boundary alone does + // not make the results FUSE compliance + if !fuseFilesystem(existingMount) { + return fmt.Errorf("mount point %s is not a FUSE filesystem", existingMount) + } // Run inside a private work dir so test files do not pile up in // the shared mount root and cleanup can remove only what it made diff --git a/test/fuse_integration/fuse_mount_bsd.go b/test/fuse_integration/fuse_mount_bsd.go new file mode 100644 index 0000000000..d1d731ad76 --- /dev/null +++ b/test/fuse_integration/fuse_mount_bsd.go @@ -0,0 +1,25 @@ +//go:build darwin || freebsd + +package fuse + +import ( + "strings" + "syscall" +) + +// fuseFilesystem reports whether path sits on a FUSE mount; macFUSE, osxfuse +// and fusefs all carry "fuse" in the filesystem type name. +func fuseFilesystem(path string) bool { + var st syscall.Statfs_t + if err := syscall.Statfs(path, &st); err != nil { + return false + } + name := make([]byte, 0, len(st.Fstypename)) + for _, c := range st.Fstypename { + if c == 0 { + break + } + name = append(name, byte(c)) + } + return strings.Contains(string(name), "fuse") +} diff --git a/test/fuse_integration/fuse_mount_linux.go b/test/fuse_integration/fuse_mount_linux.go new file mode 100644 index 0000000000..2a181cb4ce --- /dev/null +++ b/test/fuse_integration/fuse_mount_linux.go @@ -0,0 +1,17 @@ +//go:build linux + +package fuse + +import "syscall" + +// fuseSuperMagic is statfs f_type for fuse and fuseblk mounts. +const fuseSuperMagic = 0x65735546 + +// fuseFilesystem reports whether path sits on a FUSE mount. +func fuseFilesystem(path string) bool { + var st syscall.Statfs_t + if err := syscall.Statfs(path, &st); err != nil { + return false + } + return st.Type == fuseSuperMagic +} diff --git a/test/fuse_integration/fuse_mount_other.go b/test/fuse_integration/fuse_mount_other.go new file mode 100644 index 0000000000..21022f9a5c --- /dev/null +++ b/test/fuse_integration/fuse_mount_other.go @@ -0,0 +1,9 @@ +//go:build (unix && !linux && !darwin && !freebsd) || (!unix && !windows) + +package fuse + +// fuseFilesystem has no portable check on these platforms; the mount check +// and write verification in Setup stay the only gates. +func fuseFilesystem(path string) bool { + return true +} diff --git a/test/fuse_integration/mounted_unix_test.go b/test/fuse_integration/mounted_linux_test.go similarity index 63% rename from test/fuse_integration/mounted_unix_test.go rename to test/fuse_integration/mounted_linux_test.go index ed47185519..c2184cafff 100644 --- a/test/fuse_integration/mounted_unix_test.go +++ b/test/fuse_integration/mounted_linux_test.go @@ -1,4 +1,4 @@ -//go:build unix +//go:build linux package fuse @@ -17,3 +17,11 @@ func TestMountedAt(t *testing.T) { } } } + +func TestFuseFilesystem(t *testing.T) { + for _, p := range []string{"/proc", t.TempDir()} { + if fuseFilesystem(p) { + t.Errorf("fuseFilesystem(%q) = true, want false", p) + } + } +} diff --git a/test/fuse_integration/mounted_windows.go b/test/fuse_integration/mounted_windows.go index 4a8d199b3a..4855bb647b 100644 --- a/test/fuse_integration/mounted_windows.go +++ b/test/fuse_integration/mounted_windows.go @@ -32,3 +32,9 @@ func mountedAt(path string) bool { data, ok := info.Sys().(*syscall.Win32FileAttributeData) return ok && data.FileAttributes&syscall.FILE_ATTRIBUTE_REPARSE_POINT != 0 } + +// fuseFilesystem is covered by the WinFsp checks in mountedAt: WinFsp is the +// only FUSE provider on the platform. +func fuseFilesystem(path string) bool { + return true +}