diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index c68b003d..601ffe80 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -12,7 +12,7 @@ jobs: - uses: actions/checkout@v2 - uses: actions/setup-java@v2 with: - java-version: 19-ea + java-version: 19 distribution: 'zulu' cache: 'maven' - name: Setup fuse @@ -35,7 +35,7 @@ jobs: - uses: actions/checkout@v2 - uses: actions/setup-java@v2 with: - java-version: 19-ea + java-version: 19 distribution: 'zulu' cache: 'maven' - name: Setup fuse @@ -56,7 +56,7 @@ jobs: - uses: actions/checkout@v2 - uses: actions/setup-java@v2 with: - java-version: 19-ea + java-version: 19 distribution: 'zulu' cache: 'maven' - name: Setup fuse @@ -79,7 +79,7 @@ jobs: fetch-depth: 0 - uses: actions/setup-java@v2 with: - java-version: 19-ea + java-version: 19 distribution: 'zulu' cache: 'maven' - name: Cache SonarCloud packages diff --git a/.github/workflows/publish-central.yml b/.github/workflows/publish-central.yml index aa481b95..23fc7808 100644 --- a/.github/workflows/publish-central.yml +++ b/.github/workflows/publish-central.yml @@ -15,7 +15,7 @@ jobs: ref: "refs/tags/${{ github.event.inputs.tag }}" - uses: actions/setup-java@v2 with: - java-version: 19-ea + java-version: 19 distribution: 'zulu' cache: 'maven' server-id: ossrh # Value of the distributionManagement/repository/id field of the pom.xml diff --git a/.github/workflows/publish-github.yml b/.github/workflows/publish-github.yml index 63f46f8b..55fc586c 100644 --- a/.github/workflows/publish-github.yml +++ b/.github/workflows/publish-github.yml @@ -10,7 +10,7 @@ jobs: - uses: actions/checkout@v2 - uses: actions/setup-java@v2 with: - java-version: 19-ea + java-version: 19 distribution: 'zulu' cache: 'maven' gpg-private-key: ${{ secrets.RELEASES_GPG_PRIVATE_KEY }} # Value of the GPG private key to import diff --git a/.idea/misc.xml b/.idea/misc.xml index 08abb3bb..301d9c4f 100644 --- a/.idea/misc.xml +++ b/.idea/misc.xml @@ -8,7 +8,7 @@ - + \ No newline at end of file diff --git a/jfuse-api/pom.xml b/jfuse-api/pom.xml index 3e9421cd..e5ab7fb8 100644 --- a/jfuse-api/pom.xml +++ b/jfuse-api/pom.xml @@ -5,7 +5,7 @@ org.cryptomator jfuse - 0.2.0 + 0.2.1 4.0.0 jfuse-api diff --git a/jfuse-examples/pom.xml b/jfuse-examples/pom.xml index 95a756c7..c61ce606 100644 --- a/jfuse-examples/pom.xml +++ b/jfuse-examples/pom.xml @@ -5,7 +5,7 @@ org.cryptomator jfuse - 0.2.0 + 0.2.1 4.0.0 jfuse-examples @@ -24,7 +24,7 @@ org.slf4j slf4j-simple - 2.0.0-alpha6 + 2.0.3 @@ -51,8 +51,8 @@ unix - Linux - x86_64 + linux + amd64 @@ -69,7 +69,7 @@ unix - Linux + linux aarch64 diff --git a/jfuse-examples/src/main/java/org/cryptomator/jfuse/examples/AbstractMirrorFileSystem.java b/jfuse-examples/src/main/java/org/cryptomator/jfuse/examples/AbstractMirrorFileSystem.java index 1d021020..1eb78c62 100644 --- a/jfuse-examples/src/main/java/org/cryptomator/jfuse/examples/AbstractMirrorFileSystem.java +++ b/jfuse-examples/src/main/java/org/cryptomator/jfuse/examples/AbstractMirrorFileSystem.java @@ -71,7 +71,6 @@ protected Path resolvePath(String absolutePath) { public Set supportedOperations() { return EnumSet.of( FuseOperations.Operation.ACCESS, - FuseOperations.Operation.CHMOD, FuseOperations.Operation.CREATE, FuseOperations.Operation.DESTROY, FuseOperations.Operation.GET_ATTR, @@ -216,18 +215,6 @@ private long countSubDirs(Path dir) throws IOException { } } - @Override - public int chmod(String path, int mode, FileInfo fi) { - LOG.trace("chmod {}", path); - Path node = resolvePath(path); - try { - Files.setPosixFilePermissions(node, FileModes.toPermissions(mode)); - return 0; - } catch (IOException e) { - return -errno.eio(); - } - } - @Override public int utimens(String path, TimeSpec atime, TimeSpec mtime, FileInfo fi) { LOG.trace("utimens {}", path); diff --git a/jfuse-linux-aarch64/pom.xml b/jfuse-linux-aarch64/pom.xml index 2f64bc68..99f8d6de 100644 --- a/jfuse-linux-aarch64/pom.xml +++ b/jfuse-linux-aarch64/pom.xml @@ -5,7 +5,7 @@ jfuse org.cryptomator - 0.2.0 + 0.2.1 4.0.0 jfuse-linux-aarch64 @@ -91,14 +91,19 @@ fuse_h _FILE_OFFSET_BITS=64 - FUSE_USE_VERSION=35 + FUSE_USE_VERSION=312 + fuse_version fuse_lib_help fuse_new fuse_mount fuse_get_session fuse_loop + fuse_loop_cfg_create + fuse_loop_cfg_set_clone_fd + fuse_loop_cfg_set_max_threads + fuse_loop_cfg_destroy fuse_loop_mt fuse_exit fuse_unmount @@ -115,7 +120,7 @@ timespec fuse_conn_info fuse_args - fuse_loop_config + fuse_loop_config_v1 @@ -126,15 +131,12 @@ ${project.parent.basedir}/libfuse3/include/fuse_lowlevel.h - org.cryptomator.jfuse.linux.aarch64.extr.ll + org.cryptomator.jfuse.linux.aarch64.extr fuse_lowlevel_h _FILE_OFFSET_BITS=64 - FUSE_USE_VERSION=35 + FUSE_USE_VERSION=312 - - fuse_parse_cmdline - fuse_cmdline_opts diff --git a/jfuse-linux-aarch64/src/main/java/org/cryptomator/jfuse/linux/aarch64/FuseArgs.java b/jfuse-linux-aarch64/src/main/java/org/cryptomator/jfuse/linux/aarch64/FuseArgs.java index 9d4014e3..f3257dda 100644 --- a/jfuse-linux-aarch64/src/main/java/org/cryptomator/jfuse/linux/aarch64/FuseArgs.java +++ b/jfuse-linux-aarch64/src/main/java/org/cryptomator/jfuse/linux/aarch64/FuseArgs.java @@ -1,7 +1,7 @@ package org.cryptomator.jfuse.linux.aarch64; import org.cryptomator.jfuse.linux.aarch64.extr.fuse_args; -import org.cryptomator.jfuse.linux.aarch64.extr.ll.fuse_cmdline_opts; +import org.cryptomator.jfuse.linux.aarch64.extr.fuse_cmdline_opts; import java.lang.foreign.MemoryAddress; import java.lang.foreign.MemorySegment; @@ -31,4 +31,16 @@ public MemoryAddress mountPoint() { public boolean multithreaded() { return fuse_cmdline_opts.singlethread$get(cmdLineOpts) == 0; } + + public int cloneFd() { + return fuse_cmdline_opts.clone_fd$get(cmdLineOpts); + } + + public int maxIdleThreads() { + return fuse_cmdline_opts.max_idle_threads$get(cmdLineOpts); + } + + public int maxThreads() { + return fuse_cmdline_opts.max_threads$get(cmdLineOpts); + } } diff --git a/jfuse-linux-aarch64/src/main/java/org/cryptomator/jfuse/linux/aarch64/FuseFunctions.java b/jfuse-linux-aarch64/src/main/java/org/cryptomator/jfuse/linux/aarch64/FuseFunctions.java new file mode 100644 index 00000000..bafc8238 --- /dev/null +++ b/jfuse-linux-aarch64/src/main/java/org/cryptomator/jfuse/linux/aarch64/FuseFunctions.java @@ -0,0 +1,44 @@ +package org.cryptomator.jfuse.linux.aarch64; + +import java.lang.foreign.Addressable; +import java.lang.foreign.FunctionDescriptor; +import java.lang.foreign.Linker; +import java.lang.foreign.SymbolLookup; +import java.lang.invoke.MethodHandle; + +import static java.lang.foreign.ValueLayout.ADDRESS; +import static java.lang.foreign.ValueLayout.JAVA_INT; + +/** + * These method references can not be jextract'ed, partly due to jextract not being able to understand {@code #define}, + * partly due to slight differences in the FUSE API, which applies a versioning scheme via dlvsym, that Panama's default + * {@link java.lang.foreign.SymbolLookup} doesn't support. + */ +class FuseFunctions { + + // see https://github.com/libfuse/libfuse/blob/fuse-3.12.0/include/fuse_lowlevel.h#L1892-L1923 + private static final FunctionDescriptor FUSE_PARSE_CMDLINE = FunctionDescriptor.of(JAVA_INT, ADDRESS, ADDRESS); + + private final MethodHandle fuse_parse_cmdline; + + private FuseFunctions() { + var lookup = SymbolLookup.loaderLookup(); + var linker = Linker.nativeLinker(); + this.fuse_parse_cmdline = lookup.lookup("fuse_parse_cmdline") + .map(symbol -> linker.downcallHandle(symbol, FUSE_PARSE_CMDLINE)) + .orElseThrow(() -> new UnsatisfiedLinkError("unresolved symbol fuse_parse_cmdline")); + } + + private static class Holder { + private static final FuseFunctions INSTANCE = new FuseFunctions(); + } + + public static int fuse_parse_cmdline(Addressable args, Addressable opts) { + try { + return (int) Holder.INSTANCE.fuse_parse_cmdline.invokeExact(args, opts); + } catch (Throwable e) { + throw new AssertionError("should not reach here", e); + } + } + +} diff --git a/jfuse-linux-aarch64/src/main/java/org/cryptomator/jfuse/linux/aarch64/FuseImpl.java b/jfuse-linux-aarch64/src/main/java/org/cryptomator/jfuse/linux/aarch64/FuseImpl.java index b7e084a0..fa20ca02 100644 --- a/jfuse-linux-aarch64/src/main/java/org/cryptomator/jfuse/linux/aarch64/FuseImpl.java +++ b/jfuse-linux-aarch64/src/main/java/org/cryptomator/jfuse/linux/aarch64/FuseImpl.java @@ -8,8 +8,7 @@ import org.cryptomator.jfuse.linux.aarch64.extr.fuse_args; import org.cryptomator.jfuse.linux.aarch64.extr.fuse_h; import org.cryptomator.jfuse.linux.aarch64.extr.fuse_operations; -import org.cryptomator.jfuse.linux.aarch64.extr.ll.fuse_cmdline_opts; -import org.cryptomator.jfuse.linux.aarch64.extr.ll.fuse_lowlevel_h; +import org.cryptomator.jfuse.linux.aarch64.extr.fuse_cmdline_opts; import org.cryptomator.jfuse.linux.aarch64.extr.stat_h; import org.cryptomator.jfuse.linux.aarch64.extr.timespec; import org.jetbrains.annotations.VisibleForTesting; @@ -61,7 +60,7 @@ FuseArgs parseArgs(List cmdLineArgs) throws IllegalArgumentException { fuse_args.allocated$set(args, 0); var opts = fuse_cmdline_opts.allocate(fuseScope); - int parseResult = fuse_lowlevel_h.fuse_parse_cmdline(args, opts); + int parseResult = FuseFunctions.fuse_parse_cmdline(args, opts); if (parseResult != 0) { throw new IllegalArgumentException("fuse_parse_cmdline failed to parse " + String.join(" ", cmdLineArgs)); } diff --git a/jfuse-linux-aarch64/src/main/java/org/cryptomator/jfuse/linux/aarch64/FuseMountImpl.java b/jfuse-linux-aarch64/src/main/java/org/cryptomator/jfuse/linux/aarch64/FuseMountImpl.java index f1dbf07b..6caeeda0 100644 --- a/jfuse-linux-aarch64/src/main/java/org/cryptomator/jfuse/linux/aarch64/FuseMountImpl.java +++ b/jfuse-linux-aarch64/src/main/java/org/cryptomator/jfuse/linux/aarch64/FuseMountImpl.java @@ -2,24 +2,40 @@ import org.cryptomator.jfuse.api.FuseMount; import org.cryptomator.jfuse.linux.aarch64.extr.fuse_h; -import org.cryptomator.jfuse.linux.aarch64.extr.fuse_loop_config; +import org.cryptomator.jfuse.linux.aarch64.extr.fuse_loop_config_v1; import java.lang.foreign.MemoryAddress; import java.lang.foreign.MemorySession; record FuseMountImpl(MemoryAddress fuse, FuseArgs fuseArgs) implements FuseMount { + private static final int FUSE_3_2 = 32; + private static final int FUSE_3_12 = 312; + @Override public int loop() { - if (fuseArgs.multithreaded()) { + // depends on fuse version: https://github.com/libfuse/libfuse/blob/fuse-3.12.0/include/fuse.h#L1011-L1050 + if (!fuseArgs.multithreaded() || fuse_h.fuse_version() < FUSE_3_2) { + // FUSE 3.1: to keep things simple, we just don't support fuse_loop_mt + return fuse_h.fuse_loop(fuse); + } else if (fuse_h.fuse_version() < FUSE_3_12) { + // FUSE 3.2 try (var scope = MemorySession.openConfined()) { - var loopCfg = fuse_loop_config.allocate(scope); - fuse_loop_config.clone_fd$set(loopCfg, 0); - fuse_loop_config.max_idle_threads$set(loopCfg, 10); + var loopCfg = fuse_loop_config_v1.allocate(scope); + fuse_loop_config_v1.clone_fd$set(loopCfg, fuseArgs.cloneFd()); + fuse_loop_config_v1.max_idle_threads$set(loopCfg, fuseArgs.maxIdleThreads()); return fuse_h.fuse_loop_mt(fuse, loopCfg); } } else { - return fuse_h.fuse_loop(fuse); + // FUSE 3.12 + var loopCfg = fuse_h.fuse_loop_cfg_create(); + try { + fuse_h.fuse_loop_cfg_set_clone_fd(loopCfg, fuseArgs.cloneFd()); + fuse_h.fuse_loop_cfg_set_max_threads(loopCfg, fuseArgs.maxThreads()); + return fuse_h.fuse_loop_mt(fuse, loopCfg); + } finally { + fuse_h.fuse_loop_cfg_destroy(loopCfg); + } } } diff --git a/jfuse-linux-aarch64/src/main/java/org/cryptomator/jfuse/linux/aarch64/extr/constants$0.java b/jfuse-linux-aarch64/src/main/java/org/cryptomator/jfuse/linux/aarch64/extr/constants$0.java index 57a7d35a..0a84d9c3 100644 --- a/jfuse-linux-aarch64/src/main/java/org/cryptomator/jfuse/linux/aarch64/extr/constants$0.java +++ b/jfuse-linux-aarch64/src/main/java/org/cryptomator/jfuse/linux/aarch64/extr/constants$0.java @@ -9,47 +9,45 @@ import static java.lang.foreign.ValueLayout.*; class constants$0 { - static final FunctionDescriptor fuse_fill_dir_t$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, - Constants$root.C_POINTER$LAYOUT, - Constants$root.C_POINTER$LAYOUT, - Constants$root.C_POINTER$LAYOUT, - Constants$root.C_LONG_LONG$LAYOUT, - Constants$root.C_INT$LAYOUT + static final FunctionDescriptor fuse_version$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT); + static final MethodHandle fuse_version$MH = RuntimeHelper.downcallHandle( + "fuse_version", + constants$0.fuse_version$FUNC ); - static final MethodHandle fuse_fill_dir_t$MH = RuntimeHelper.downcallHandle( - constants$0.fuse_fill_dir_t$FUNC + static final FunctionDescriptor fuse_loop_cfg_create$FUNC = FunctionDescriptor.of(Constants$root.C_POINTER$LAYOUT); + static final MethodHandle fuse_loop_cfg_create$MH = RuntimeHelper.downcallHandle( + "fuse_loop_cfg_create", + constants$0.fuse_loop_cfg_create$FUNC ); - static final FunctionDescriptor fuse_lib_help$FUNC = FunctionDescriptor.ofVoid( + static final FunctionDescriptor fuse_loop_cfg_destroy$FUNC = FunctionDescriptor.ofVoid( Constants$root.C_POINTER$LAYOUT ); - static final MethodHandle fuse_lib_help$MH = RuntimeHelper.downcallHandle( - "fuse_lib_help", - constants$0.fuse_lib_help$FUNC + static final MethodHandle fuse_loop_cfg_destroy$MH = RuntimeHelper.downcallHandle( + "fuse_loop_cfg_destroy", + constants$0.fuse_loop_cfg_destroy$FUNC ); - static final FunctionDescriptor fuse_new$FUNC = FunctionDescriptor.of(Constants$root.C_POINTER$LAYOUT, - Constants$root.C_POINTER$LAYOUT, + static final FunctionDescriptor fuse_loop_cfg_set_max_threads$FUNC = FunctionDescriptor.ofVoid( Constants$root.C_POINTER$LAYOUT, - Constants$root.C_LONG_LONG$LAYOUT, - Constants$root.C_POINTER$LAYOUT + Constants$root.C_INT$LAYOUT ); - static final MethodHandle fuse_new$MH = RuntimeHelper.downcallHandle( - "fuse_new", - constants$0.fuse_new$FUNC + static final MethodHandle fuse_loop_cfg_set_max_threads$MH = RuntimeHelper.downcallHandle( + "fuse_loop_cfg_set_max_threads", + constants$0.fuse_loop_cfg_set_max_threads$FUNC ); - static final FunctionDescriptor fuse_mount$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, + static final FunctionDescriptor fuse_loop_cfg_set_clone_fd$FUNC = FunctionDescriptor.ofVoid( Constants$root.C_POINTER$LAYOUT, - Constants$root.C_POINTER$LAYOUT + Constants$root.C_INT$LAYOUT ); - static final MethodHandle fuse_mount$MH = RuntimeHelper.downcallHandle( - "fuse_mount", - constants$0.fuse_mount$FUNC + static final MethodHandle fuse_loop_cfg_set_clone_fd$MH = RuntimeHelper.downcallHandle( + "fuse_loop_cfg_set_clone_fd", + constants$0.fuse_loop_cfg_set_clone_fd$FUNC ); - static final FunctionDescriptor fuse_unmount$FUNC = FunctionDescriptor.ofVoid( - Constants$root.C_POINTER$LAYOUT - ); - static final MethodHandle fuse_unmount$MH = RuntimeHelper.downcallHandle( - "fuse_unmount", - constants$0.fuse_unmount$FUNC + static final FunctionDescriptor fuse_fill_dir_t$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, + Constants$root.C_POINTER$LAYOUT, + Constants$root.C_POINTER$LAYOUT, + Constants$root.C_POINTER$LAYOUT, + Constants$root.C_LONG_LONG$LAYOUT, + Constants$root.C_INT$LAYOUT ); } diff --git a/jfuse-linux-aarch64/src/main/java/org/cryptomator/jfuse/linux/aarch64/extr/constants$1.java b/jfuse-linux-aarch64/src/main/java/org/cryptomator/jfuse/linux/aarch64/extr/constants$1.java index 6640ad95..056d3622 100644 --- a/jfuse-linux-aarch64/src/main/java/org/cryptomator/jfuse/linux/aarch64/extr/constants$1.java +++ b/jfuse-linux-aarch64/src/main/java/org/cryptomator/jfuse/linux/aarch64/extr/constants$1.java @@ -9,41 +9,54 @@ import static java.lang.foreign.ValueLayout.*; class constants$1 { - static final FunctionDescriptor fuse_destroy$FUNC = FunctionDescriptor.ofVoid( - Constants$root.C_POINTER$LAYOUT + static final FunctionDescriptor fuse_fill_dir_t$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, + Constants$root.C_POINTER$LAYOUT, + Constants$root.C_POINTER$LAYOUT, + Constants$root.C_POINTER$LAYOUT, + Constants$root.C_LONG_LONG$LAYOUT, + Constants$root.C_INT$LAYOUT ); - static final MethodHandle fuse_destroy$MH = RuntimeHelper.downcallHandle( - "fuse_destroy", - constants$1.fuse_destroy$FUNC + static final MethodHandle fuse_fill_dir_t$MH = RuntimeHelper.downcallHandle( + constants$1.fuse_fill_dir_t$FUNC ); - static final FunctionDescriptor fuse_loop$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, + static final FunctionDescriptor fuse_lib_help$FUNC = FunctionDescriptor.ofVoid( Constants$root.C_POINTER$LAYOUT ); - static final MethodHandle fuse_loop$MH = RuntimeHelper.downcallHandle( - "fuse_loop", - constants$1.fuse_loop$FUNC + static final MethodHandle fuse_lib_help$MH = RuntimeHelper.downcallHandle( + "fuse_lib_help", + constants$1.fuse_lib_help$FUNC ); - static final FunctionDescriptor fuse_exit$FUNC = FunctionDescriptor.ofVoid( + static final FunctionDescriptor fuse_new$FUNC = FunctionDescriptor.of(Constants$root.C_POINTER$LAYOUT, + Constants$root.C_POINTER$LAYOUT, + Constants$root.C_POINTER$LAYOUT, + Constants$root.C_LONG_LONG$LAYOUT, Constants$root.C_POINTER$LAYOUT ); - static final MethodHandle fuse_exit$MH = RuntimeHelper.downcallHandle( - "fuse_exit", - constants$1.fuse_exit$FUNC + static final MethodHandle fuse_new$MH = RuntimeHelper.downcallHandle( + "fuse_new", + constants$1.fuse_new$FUNC ); - static final FunctionDescriptor fuse_loop_mt$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, + static final FunctionDescriptor fuse_mount$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, Constants$root.C_POINTER$LAYOUT, Constants$root.C_POINTER$LAYOUT ); - static final MethodHandle fuse_loop_mt$MH = RuntimeHelper.downcallHandle( - "fuse_loop_mt", - constants$1.fuse_loop_mt$FUNC + static final MethodHandle fuse_mount$MH = RuntimeHelper.downcallHandle( + "fuse_mount", + constants$1.fuse_mount$FUNC + ); + static final FunctionDescriptor fuse_unmount$FUNC = FunctionDescriptor.ofVoid( + Constants$root.C_POINTER$LAYOUT + ); + static final MethodHandle fuse_unmount$MH = RuntimeHelper.downcallHandle( + "fuse_unmount", + constants$1.fuse_unmount$FUNC ); - static final FunctionDescriptor fuse_get_session$FUNC = FunctionDescriptor.of(Constants$root.C_POINTER$LAYOUT, + static final FunctionDescriptor fuse_destroy$FUNC = FunctionDescriptor.ofVoid( Constants$root.C_POINTER$LAYOUT ); - static final MethodHandle fuse_get_session$MH = RuntimeHelper.downcallHandle( - "fuse_get_session", - constants$1.fuse_get_session$FUNC + static final MethodHandle fuse_destroy$MH = RuntimeHelper.downcallHandle( + "fuse_destroy", + constants$1.fuse_destroy$FUNC ); } diff --git a/jfuse-linux-aarch64/src/main/java/org/cryptomator/jfuse/linux/aarch64/extr/constants$2.java b/jfuse-linux-aarch64/src/main/java/org/cryptomator/jfuse/linux/aarch64/extr/constants$2.java new file mode 100644 index 00000000..5020cf17 --- /dev/null +++ b/jfuse-linux-aarch64/src/main/java/org/cryptomator/jfuse/linux/aarch64/extr/constants$2.java @@ -0,0 +1,43 @@ +// Generated by jextract + +package org.cryptomator.jfuse.linux.aarch64.extr; + +import java.lang.invoke.MethodHandle; +import java.lang.invoke.VarHandle; +import java.nio.ByteOrder; +import java.lang.foreign.*; +import static java.lang.foreign.ValueLayout.*; +class constants$2 { + + static final FunctionDescriptor fuse_loop$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, + Constants$root.C_POINTER$LAYOUT + ); + static final MethodHandle fuse_loop$MH = RuntimeHelper.downcallHandle( + "fuse_loop", + constants$2.fuse_loop$FUNC + ); + static final FunctionDescriptor fuse_exit$FUNC = FunctionDescriptor.ofVoid( + Constants$root.C_POINTER$LAYOUT + ); + static final MethodHandle fuse_exit$MH = RuntimeHelper.downcallHandle( + "fuse_exit", + constants$2.fuse_exit$FUNC + ); + static final FunctionDescriptor fuse_loop_mt$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, + Constants$root.C_POINTER$LAYOUT, + Constants$root.C_POINTER$LAYOUT + ); + static final MethodHandle fuse_loop_mt$MH = RuntimeHelper.downcallHandle( + "fuse_loop_mt", + constants$2.fuse_loop_mt$FUNC + ); + static final FunctionDescriptor fuse_get_session$FUNC = FunctionDescriptor.of(Constants$root.C_POINTER$LAYOUT, + Constants$root.C_POINTER$LAYOUT + ); + static final MethodHandle fuse_get_session$MH = RuntimeHelper.downcallHandle( + "fuse_get_session", + constants$2.fuse_get_session$FUNC + ); +} + + diff --git a/jfuse-linux-amd64/src/main/java/org/cryptomator/jfuse/linux/amd64/extr/ll/fuse_cmdline_opts.java b/jfuse-linux-aarch64/src/main/java/org/cryptomator/jfuse/linux/aarch64/extr/fuse_cmdline_opts.java similarity index 90% rename from jfuse-linux-amd64/src/main/java/org/cryptomator/jfuse/linux/amd64/extr/ll/fuse_cmdline_opts.java rename to jfuse-linux-aarch64/src/main/java/org/cryptomator/jfuse/linux/aarch64/extr/fuse_cmdline_opts.java index 56734379..9199946b 100644 --- a/jfuse-linux-amd64/src/main/java/org/cryptomator/jfuse/linux/amd64/extr/ll/fuse_cmdline_opts.java +++ b/jfuse-linux-aarch64/src/main/java/org/cryptomator/jfuse/linux/aarch64/extr/fuse_cmdline_opts.java @@ -1,6 +1,6 @@ // Generated by jextract -package org.cryptomator.jfuse.linux.amd64.extr.ll; +package org.cryptomator.jfuse.linux.aarch64.extr; import java.lang.invoke.MethodHandle; import java.lang.invoke.VarHandle; @@ -18,7 +18,9 @@ public class fuse_cmdline_opts { Constants$root.C_INT$LAYOUT.withName("show_version"), Constants$root.C_INT$LAYOUT.withName("show_help"), Constants$root.C_INT$LAYOUT.withName("clone_fd"), - Constants$root.C_INT$LAYOUT.withName("max_idle_threads") + Constants$root.C_INT$LAYOUT.withName("max_idle_threads"), + Constants$root.C_INT$LAYOUT.withName("max_threads"), + MemoryLayout.paddingLayout(32) ).withName("fuse_cmdline_opts"); public static MemoryLayout $LAYOUT() { return fuse_cmdline_opts.$struct$LAYOUT; @@ -167,6 +169,22 @@ public class fuse_cmdline_opts { public static void max_idle_threads$set(MemorySegment seg, long index, int x) { fuse_cmdline_opts.max_idle_threads$VH.set(seg.asSlice(index*sizeof()), x); } + static final VarHandle max_threads$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("max_threads")); + public static VarHandle max_threads$VH() { + return fuse_cmdline_opts.max_threads$VH; + } + public static int max_threads$get(MemorySegment seg) { + return (int)fuse_cmdline_opts.max_threads$VH.get(seg); + } + public static void max_threads$set( MemorySegment seg, int x) { + fuse_cmdline_opts.max_threads$VH.set(seg, x); + } + public static int max_threads$get(MemorySegment seg, long index) { + return (int)fuse_cmdline_opts.max_threads$VH.get(seg.asSlice(index*sizeof())); + } + public static void max_threads$set(MemorySegment seg, long index, int x) { + fuse_cmdline_opts.max_threads$VH.set(seg.asSlice(index*sizeof()), x); + } public static long sizeof() { return $LAYOUT().byteSize(); } public static MemorySegment allocate(SegmentAllocator allocator) { return allocator.allocate($LAYOUT()); } public static MemorySegment allocateArray(int len, SegmentAllocator allocator) { diff --git a/jfuse-linux-aarch64/src/main/java/org/cryptomator/jfuse/linux/aarch64/extr/fuse_fill_dir_t.java b/jfuse-linux-aarch64/src/main/java/org/cryptomator/jfuse/linux/aarch64/extr/fuse_fill_dir_t.java index b0e952bc..9b199066 100644 --- a/jfuse-linux-aarch64/src/main/java/org/cryptomator/jfuse/linux/aarch64/extr/fuse_fill_dir_t.java +++ b/jfuse-linux-aarch64/src/main/java/org/cryptomator/jfuse/linux/aarch64/extr/fuse_fill_dir_t.java @@ -17,7 +17,7 @@ static fuse_fill_dir_t ofAddress(MemoryAddress addr, MemorySession session) { MemorySegment symbol = MemorySegment.ofAddress(addr, 0, session); return (java.lang.foreign.MemoryAddress _buf, java.lang.foreign.MemoryAddress _name, java.lang.foreign.MemoryAddress _stbuf, long _off, int _flags) -> { try { - return (int)constants$0.fuse_fill_dir_t$MH.invokeExact((Addressable)symbol, (java.lang.foreign.Addressable)_buf, (java.lang.foreign.Addressable)_name, (java.lang.foreign.Addressable)_stbuf, _off, _flags); + return (int)constants$1.fuse_fill_dir_t$MH.invokeExact((Addressable)symbol, (java.lang.foreign.Addressable)_buf, (java.lang.foreign.Addressable)_name, (java.lang.foreign.Addressable)_stbuf, _off, _flags); } catch (Throwable ex$) { throw new AssertionError("should not reach here", ex$); } diff --git a/jfuse-linux-aarch64/src/main/java/org/cryptomator/jfuse/linux/aarch64/extr/fuse_h.java b/jfuse-linux-aarch64/src/main/java/org/cryptomator/jfuse/linux/aarch64/extr/fuse_h.java index c15911bd..abc89ff7 100644 --- a/jfuse-linux-aarch64/src/main/java/org/cryptomator/jfuse/linux/aarch64/extr/fuse_h.java +++ b/jfuse-linux-aarch64/src/main/java/org/cryptomator/jfuse/linux/aarch64/extr/fuse_h.java @@ -18,8 +18,63 @@ public class fuse_h { public static OfFloat C_FLOAT = Constants$root.C_FLOAT$LAYOUT; public static OfDouble C_DOUBLE = Constants$root.C_DOUBLE$LAYOUT; public static OfAddress C_POINTER = Constants$root.C_POINTER$LAYOUT; + public static MethodHandle fuse_version$MH() { + return RuntimeHelper.requireNonNull(constants$0.fuse_version$MH,"fuse_version"); + } + public static int fuse_version () { + var mh$ = fuse_version$MH(); + try { + return (int)mh$.invokeExact(); + } catch (Throwable ex$) { + throw new AssertionError("should not reach here", ex$); + } + } + public static MethodHandle fuse_loop_cfg_create$MH() { + return RuntimeHelper.requireNonNull(constants$0.fuse_loop_cfg_create$MH,"fuse_loop_cfg_create"); + } + public static MemoryAddress fuse_loop_cfg_create () { + var mh$ = fuse_loop_cfg_create$MH(); + try { + return (java.lang.foreign.MemoryAddress)mh$.invokeExact(); + } catch (Throwable ex$) { + throw new AssertionError("should not reach here", ex$); + } + } + public static MethodHandle fuse_loop_cfg_destroy$MH() { + return RuntimeHelper.requireNonNull(constants$0.fuse_loop_cfg_destroy$MH,"fuse_loop_cfg_destroy"); + } + public static void fuse_loop_cfg_destroy ( Addressable config) { + var mh$ = fuse_loop_cfg_destroy$MH(); + try { + mh$.invokeExact(config); + } catch (Throwable ex$) { + throw new AssertionError("should not reach here", ex$); + } + } + public static MethodHandle fuse_loop_cfg_set_max_threads$MH() { + return RuntimeHelper.requireNonNull(constants$0.fuse_loop_cfg_set_max_threads$MH,"fuse_loop_cfg_set_max_threads"); + } + public static void fuse_loop_cfg_set_max_threads ( Addressable config, int value) { + var mh$ = fuse_loop_cfg_set_max_threads$MH(); + try { + mh$.invokeExact(config, value); + } catch (Throwable ex$) { + throw new AssertionError("should not reach here", ex$); + } + } + public static MethodHandle fuse_loop_cfg_set_clone_fd$MH() { + return RuntimeHelper.requireNonNull(constants$0.fuse_loop_cfg_set_clone_fd$MH,"fuse_loop_cfg_set_clone_fd"); + } + public static void fuse_loop_cfg_set_clone_fd ( Addressable config, int value) { + var mh$ = fuse_loop_cfg_set_clone_fd$MH(); + try { + mh$.invokeExact(config, value); + } catch (Throwable ex$) { + throw new AssertionError("should not reach here", ex$); + } + } public static MethodHandle fuse_lib_help$MH() { - return RuntimeHelper.requireNonNull(constants$0.fuse_lib_help$MH,"fuse_lib_help"); + return RuntimeHelper.requireNonNull(constants$1.fuse_lib_help$MH,"fuse_lib_help"); } public static void fuse_lib_help ( Addressable args) { var mh$ = fuse_lib_help$MH(); @@ -30,7 +85,7 @@ public static void fuse_lib_help ( Addressable args) { } } public static MethodHandle fuse_new$MH() { - return RuntimeHelper.requireNonNull(constants$0.fuse_new$MH,"fuse_new"); + return RuntimeHelper.requireNonNull(constants$1.fuse_new$MH,"fuse_new"); } public static MemoryAddress fuse_new ( Addressable args, Addressable op, long op_size, Addressable private_data) { var mh$ = fuse_new$MH(); @@ -41,7 +96,7 @@ public static MemoryAddress fuse_new ( Addressable args, Addressable op, long } } public static MethodHandle fuse_mount$MH() { - return RuntimeHelper.requireNonNull(constants$0.fuse_mount$MH,"fuse_mount"); + return RuntimeHelper.requireNonNull(constants$1.fuse_mount$MH,"fuse_mount"); } public static int fuse_mount ( Addressable f, Addressable mountpoint) { var mh$ = fuse_mount$MH(); @@ -52,7 +107,7 @@ public static int fuse_mount ( Addressable f, Addressable mountpoint) { } } public static MethodHandle fuse_unmount$MH() { - return RuntimeHelper.requireNonNull(constants$0.fuse_unmount$MH,"fuse_unmount"); + return RuntimeHelper.requireNonNull(constants$1.fuse_unmount$MH,"fuse_unmount"); } public static void fuse_unmount ( Addressable f) { var mh$ = fuse_unmount$MH(); @@ -74,7 +129,7 @@ public static void fuse_destroy ( Addressable f) { } } public static MethodHandle fuse_loop$MH() { - return RuntimeHelper.requireNonNull(constants$1.fuse_loop$MH,"fuse_loop"); + return RuntimeHelper.requireNonNull(constants$2.fuse_loop$MH,"fuse_loop"); } public static int fuse_loop ( Addressable f) { var mh$ = fuse_loop$MH(); @@ -85,7 +140,7 @@ public static int fuse_loop ( Addressable f) { } } public static MethodHandle fuse_exit$MH() { - return RuntimeHelper.requireNonNull(constants$1.fuse_exit$MH,"fuse_exit"); + return RuntimeHelper.requireNonNull(constants$2.fuse_exit$MH,"fuse_exit"); } public static void fuse_exit ( Addressable f) { var mh$ = fuse_exit$MH(); @@ -96,7 +151,7 @@ public static void fuse_exit ( Addressable f) { } } public static MethodHandle fuse_loop_mt$MH() { - return RuntimeHelper.requireNonNull(constants$1.fuse_loop_mt$MH,"fuse_loop_mt"); + return RuntimeHelper.requireNonNull(constants$2.fuse_loop_mt$MH,"fuse_loop_mt"); } public static int fuse_loop_mt ( Addressable f, Addressable config) { var mh$ = fuse_loop_mt$MH(); @@ -107,7 +162,7 @@ public static int fuse_loop_mt ( Addressable f, Addressable config) { } } public static MethodHandle fuse_get_session$MH() { - return RuntimeHelper.requireNonNull(constants$1.fuse_get_session$MH,"fuse_get_session"); + return RuntimeHelper.requireNonNull(constants$2.fuse_get_session$MH,"fuse_get_session"); } public static MemoryAddress fuse_get_session ( Addressable f) { var mh$ = fuse_get_session$MH(); diff --git a/jfuse-linux-aarch64/src/main/java/org/cryptomator/jfuse/linux/aarch64/extr/fuse_loop_config.java b/jfuse-linux-aarch64/src/main/java/org/cryptomator/jfuse/linux/aarch64/extr/fuse_loop_config_v1.java similarity index 70% rename from jfuse-linux-aarch64/src/main/java/org/cryptomator/jfuse/linux/aarch64/extr/fuse_loop_config.java rename to jfuse-linux-aarch64/src/main/java/org/cryptomator/jfuse/linux/aarch64/extr/fuse_loop_config_v1.java index 1aeb84c4..469a8435 100644 --- a/jfuse-linux-aarch64/src/main/java/org/cryptomator/jfuse/linux/aarch64/extr/fuse_loop_config.java +++ b/jfuse-linux-aarch64/src/main/java/org/cryptomator/jfuse/linux/aarch64/extr/fuse_loop_config_v1.java @@ -7,46 +7,46 @@ import java.nio.ByteOrder; import java.lang.foreign.*; import static java.lang.foreign.ValueLayout.*; -public class fuse_loop_config { +public class fuse_loop_config_v1 { static final GroupLayout $struct$LAYOUT = MemoryLayout.structLayout( Constants$root.C_INT$LAYOUT.withName("clone_fd"), Constants$root.C_INT$LAYOUT.withName("max_idle_threads") - ).withName("fuse_loop_config"); + ).withName("fuse_loop_config_v1"); public static MemoryLayout $LAYOUT() { - return fuse_loop_config.$struct$LAYOUT; + return fuse_loop_config_v1.$struct$LAYOUT; } static final VarHandle clone_fd$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("clone_fd")); public static VarHandle clone_fd$VH() { - return fuse_loop_config.clone_fd$VH; + return fuse_loop_config_v1.clone_fd$VH; } public static int clone_fd$get(MemorySegment seg) { - return (int)fuse_loop_config.clone_fd$VH.get(seg); + return (int)fuse_loop_config_v1.clone_fd$VH.get(seg); } public static void clone_fd$set( MemorySegment seg, int x) { - fuse_loop_config.clone_fd$VH.set(seg, x); + fuse_loop_config_v1.clone_fd$VH.set(seg, x); } public static int clone_fd$get(MemorySegment seg, long index) { - return (int)fuse_loop_config.clone_fd$VH.get(seg.asSlice(index*sizeof())); + return (int)fuse_loop_config_v1.clone_fd$VH.get(seg.asSlice(index*sizeof())); } public static void clone_fd$set(MemorySegment seg, long index, int x) { - fuse_loop_config.clone_fd$VH.set(seg.asSlice(index*sizeof()), x); + fuse_loop_config_v1.clone_fd$VH.set(seg.asSlice(index*sizeof()), x); } static final VarHandle max_idle_threads$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("max_idle_threads")); public static VarHandle max_idle_threads$VH() { - return fuse_loop_config.max_idle_threads$VH; + return fuse_loop_config_v1.max_idle_threads$VH; } public static int max_idle_threads$get(MemorySegment seg) { - return (int)fuse_loop_config.max_idle_threads$VH.get(seg); + return (int)fuse_loop_config_v1.max_idle_threads$VH.get(seg); } public static void max_idle_threads$set( MemorySegment seg, int x) { - fuse_loop_config.max_idle_threads$VH.set(seg, x); + fuse_loop_config_v1.max_idle_threads$VH.set(seg, x); } public static int max_idle_threads$get(MemorySegment seg, long index) { - return (int)fuse_loop_config.max_idle_threads$VH.get(seg.asSlice(index*sizeof())); + return (int)fuse_loop_config_v1.max_idle_threads$VH.get(seg.asSlice(index*sizeof())); } public static void max_idle_threads$set(MemorySegment seg, long index, int x) { - fuse_loop_config.max_idle_threads$VH.set(seg.asSlice(index*sizeof()), x); + fuse_loop_config_v1.max_idle_threads$VH.set(seg.asSlice(index*sizeof()), x); } public static long sizeof() { return $LAYOUT().byteSize(); } public static MemorySegment allocate(SegmentAllocator allocator) { return allocator.allocate($LAYOUT()); } diff --git a/jfuse-linux-amd64/src/main/java/org/cryptomator/jfuse/linux/amd64/extr/ll/fuse_lowlevel_h.java b/jfuse-linux-aarch64/src/main/java/org/cryptomator/jfuse/linux/aarch64/extr/fuse_lowlevel_h.java similarity index 61% rename from jfuse-linux-amd64/src/main/java/org/cryptomator/jfuse/linux/amd64/extr/ll/fuse_lowlevel_h.java rename to jfuse-linux-aarch64/src/main/java/org/cryptomator/jfuse/linux/aarch64/extr/fuse_lowlevel_h.java index 2c3c67de..a60515de 100644 --- a/jfuse-linux-amd64/src/main/java/org/cryptomator/jfuse/linux/amd64/extr/ll/fuse_lowlevel_h.java +++ b/jfuse-linux-aarch64/src/main/java/org/cryptomator/jfuse/linux/aarch64/extr/fuse_lowlevel_h.java @@ -1,6 +1,6 @@ // Generated by jextract -package org.cryptomator.jfuse.linux.amd64.extr.ll; +package org.cryptomator.jfuse.linux.aarch64.extr; import java.lang.invoke.MethodHandle; import java.lang.invoke.VarHandle; @@ -18,17 +18,6 @@ public class fuse_lowlevel_h { public static OfFloat C_FLOAT = Constants$root.C_FLOAT$LAYOUT; public static OfDouble C_DOUBLE = Constants$root.C_DOUBLE$LAYOUT; public static OfAddress C_POINTER = Constants$root.C_POINTER$LAYOUT; - public static MethodHandle fuse_parse_cmdline$MH() { - return RuntimeHelper.requireNonNull(constants$0.fuse_parse_cmdline$MH,"fuse_parse_cmdline"); - } - public static int fuse_parse_cmdline ( Addressable args, Addressable opts) { - var mh$ = fuse_parse_cmdline$MH(); - try { - return (int)mh$.invokeExact(args, opts); - } catch (Throwable ex$) { - throw new AssertionError("should not reach here", ex$); - } - } } diff --git a/jfuse-linux-aarch64/src/main/java/org/cryptomator/jfuse/linux/aarch64/extr/ll/Constants$root.java b/jfuse-linux-aarch64/src/main/java/org/cryptomator/jfuse/linux/aarch64/extr/ll/Constants$root.java deleted file mode 100644 index 4fc85421..00000000 --- a/jfuse-linux-aarch64/src/main/java/org/cryptomator/jfuse/linux/aarch64/extr/ll/Constants$root.java +++ /dev/null @@ -1,23 +0,0 @@ -// Generated by jextract - -package org.cryptomator.jfuse.linux.aarch64.extr.ll; - -import java.lang.invoke.MethodHandle; -import java.lang.invoke.VarHandle; -import java.nio.ByteOrder; -import java.lang.foreign.*; -import static java.lang.foreign.ValueLayout.*; -public class Constants$root { - - static final OfBoolean C_BOOL$LAYOUT = JAVA_BOOLEAN; - static final OfByte C_CHAR$LAYOUT = JAVA_BYTE; - static final OfShort C_SHORT$LAYOUT = JAVA_SHORT.withBitAlignment(16); - static final OfInt C_INT$LAYOUT = JAVA_INT.withBitAlignment(32); - static final OfLong C_LONG$LAYOUT = JAVA_LONG.withBitAlignment(64); - static final OfLong C_LONG_LONG$LAYOUT = JAVA_LONG.withBitAlignment(64); - static final OfFloat C_FLOAT$LAYOUT = JAVA_FLOAT.withBitAlignment(32); - static final OfDouble C_DOUBLE$LAYOUT = JAVA_DOUBLE.withBitAlignment(64); - static final OfAddress C_POINTER$LAYOUT = ADDRESS.withBitAlignment(64); -} - - diff --git a/jfuse-linux-aarch64/src/main/java/org/cryptomator/jfuse/linux/aarch64/extr/ll/RuntimeHelper.java b/jfuse-linux-aarch64/src/main/java/org/cryptomator/jfuse/linux/aarch64/extr/ll/RuntimeHelper.java deleted file mode 100644 index 89a36033..00000000 --- a/jfuse-linux-aarch64/src/main/java/org/cryptomator/jfuse/linux/aarch64/extr/ll/RuntimeHelper.java +++ /dev/null @@ -1,233 +0,0 @@ -package org.cryptomator.jfuse.linux.aarch64.extr.ll; -// Generated by jextract - -import java.lang.foreign.Addressable; -import java.lang.foreign.Linker; -import java.lang.foreign.FunctionDescriptor; -import java.lang.foreign.GroupLayout; -import java.lang.foreign.SymbolLookup; -import java.lang.foreign.MemoryAddress; -import java.lang.foreign.MemoryLayout; -import java.lang.foreign.MemorySegment; -import java.lang.foreign.MemorySession; -import java.lang.foreign.SegmentAllocator; -import java.lang.foreign.ValueLayout; -import java.lang.invoke.MethodHandle; -import java.lang.invoke.MethodHandles; -import java.lang.invoke.MethodType; -import java.io.File; -import java.nio.file.Path; -import java.nio.charset.StandardCharsets; -import java.util.Arrays; -import java.util.Optional; -import java.util.stream.Stream; - -import static java.lang.foreign.Linker.*; -import static java.lang.foreign.ValueLayout.*; - -final class RuntimeHelper { - - private RuntimeHelper() {} - private final static Linker LINKER = Linker.nativeLinker(); - private final static ClassLoader LOADER = RuntimeHelper.class.getClassLoader(); - private final static MethodHandles.Lookup MH_LOOKUP = MethodHandles.lookup(); - private final static SymbolLookup SYMBOL_LOOKUP; - - final static SegmentAllocator CONSTANT_ALLOCATOR = - (size, align) -> MemorySegment.allocateNative(size, align, MemorySession.openImplicit()); - - static { - - SymbolLookup loaderLookup = SymbolLookup.loaderLookup(); - SYMBOL_LOOKUP = name -> loaderLookup.lookup(name).or(() -> LINKER.defaultLookup().lookup(name)); - } - - static T requireNonNull(T obj, String symbolName) { - if (obj == null) { - throw new UnsatisfiedLinkError("unresolved symbol: " + symbolName); - } - return obj; - } - - private final static SegmentAllocator THROWING_ALLOCATOR = (x, y) -> { throw new AssertionError("should not reach here"); }; - - static final MemorySegment lookupGlobalVariable(String name, MemoryLayout layout) { - return SYMBOL_LOOKUP.lookup(name).map(symbol -> MemorySegment.ofAddress(symbol.address(), layout.byteSize(), MemorySession.openShared())).orElse(null); - } - - static final MethodHandle downcallHandle(String name, FunctionDescriptor fdesc) { - return SYMBOL_LOOKUP.lookup(name). - map(addr -> LINKER.downcallHandle(addr, fdesc)). - orElse(null); - } - - static final MethodHandle downcallHandle(FunctionDescriptor fdesc) { - return LINKER.downcallHandle(fdesc); - } - - static final MethodHandle downcallHandleVariadic(String name, FunctionDescriptor fdesc) { - return SYMBOL_LOOKUP.lookup(name). - map(addr -> VarargsInvoker.make(addr, fdesc)). - orElse(null); - } - - static final MemorySegment upcallStub(Class fi, Z z, FunctionDescriptor fdesc, MemorySession session) { - try { - MethodHandle handle = MH_LOOKUP.findVirtual(fi, "apply", Linker.upcallType(fdesc)); - handle = handle.bindTo(z); - return LINKER.upcallStub(handle, fdesc, session); - } catch (Throwable ex) { - throw new AssertionError(ex); - } - } - - static MemorySegment asArray(MemoryAddress addr, MemoryLayout layout, int numElements, MemorySession session) { - return MemorySegment.ofAddress(addr, numElements * layout.byteSize(), session); - } - - // Internals only below this point - - private static class VarargsInvoker { - private static final MethodHandle INVOKE_MH; - private final MemorySegment symbol; - private final FunctionDescriptor function; - - private VarargsInvoker(MemorySegment symbol, FunctionDescriptor function) { - this.symbol = symbol; - this.function = function; - } - - static { - try { - INVOKE_MH = MethodHandles.lookup().findVirtual(VarargsInvoker.class, "invoke", MethodType.methodType(Object.class, SegmentAllocator.class, Object[].class)); - } catch (ReflectiveOperationException e) { - throw new RuntimeException(e); - } - } - - static MethodHandle make(MemorySegment symbol, FunctionDescriptor function) { - VarargsInvoker invoker = new VarargsInvoker(symbol, function); - MethodHandle handle = INVOKE_MH.bindTo(invoker).asCollector(Object[].class, function.argumentLayouts().size() + 1); - MethodType mtype = MethodType.methodType(function.returnLayout().isPresent() ? carrier(function.returnLayout().get(), true) : void.class); - for (MemoryLayout layout : function.argumentLayouts()) { - mtype = mtype.appendParameterTypes(carrier(layout, false)); - } - mtype = mtype.appendParameterTypes(Object[].class); - if (mtype.returnType().equals(MemorySegment.class)) { - mtype = mtype.insertParameterTypes(0, SegmentAllocator.class); - } else { - handle = MethodHandles.insertArguments(handle, 0, THROWING_ALLOCATOR); - } - return handle.asType(mtype); - } - - static Class carrier(MemoryLayout layout, boolean ret) { - if (layout instanceof ValueLayout valueLayout) { - return (ret || valueLayout.carrier() != MemoryAddress.class) ? - valueLayout.carrier() : Addressable.class; - } else if (layout instanceof GroupLayout) { - return MemorySegment.class; - } else { - throw new AssertionError("Cannot get here!"); - } - } - - private Object invoke(SegmentAllocator allocator, Object[] args) throws Throwable { - // one trailing Object[] - int nNamedArgs = function.argumentLayouts().size(); - assert(args.length == nNamedArgs + 1); - // The last argument is the array of vararg collector - Object[] unnamedArgs = (Object[]) args[args.length - 1]; - - int argsCount = nNamedArgs + unnamedArgs.length; - Class[] argTypes = new Class[argsCount]; - MemoryLayout[] argLayouts = new MemoryLayout[nNamedArgs + unnamedArgs.length]; - - int pos = 0; - for (pos = 0; pos < nNamedArgs; pos++) { - argLayouts[pos] = function.argumentLayouts().get(pos); - } - - assert pos == nNamedArgs; - for (Object o: unnamedArgs) { - argLayouts[pos] = variadicLayout(normalize(o.getClass())); - pos++; - } - assert pos == argsCount; - - FunctionDescriptor f = (function.returnLayout().isEmpty()) ? - FunctionDescriptor.ofVoid(argLayouts) : - FunctionDescriptor.of(function.returnLayout().get(), argLayouts); - MethodHandle mh = LINKER.downcallHandle(symbol, f); - if (mh.type().returnType() == MemorySegment.class) { - mh = mh.bindTo(allocator); - } - // flatten argument list so that it can be passed to an asSpreader MH - Object[] allArgs = new Object[nNamedArgs + unnamedArgs.length]; - System.arraycopy(args, 0, allArgs, 0, nNamedArgs); - System.arraycopy(unnamedArgs, 0, allArgs, nNamedArgs, unnamedArgs.length); - - return mh.asSpreader(Object[].class, argsCount).invoke(allArgs); - } - - private static Class unboxIfNeeded(Class clazz) { - if (clazz == Boolean.class) { - return boolean.class; - } else if (clazz == Void.class) { - return void.class; - } else if (clazz == Byte.class) { - return byte.class; - } else if (clazz == Character.class) { - return char.class; - } else if (clazz == Short.class) { - return short.class; - } else if (clazz == Integer.class) { - return int.class; - } else if (clazz == Long.class) { - return long.class; - } else if (clazz == Float.class) { - return float.class; - } else if (clazz == Double.class) { - return double.class; - } else { - return clazz; - } - } - - private Class promote(Class c) { - if (c == byte.class || c == char.class || c == short.class || c == int.class) { - return long.class; - } else if (c == float.class) { - return double.class; - } else { - return c; - } - } - - private Class normalize(Class c) { - c = unboxIfNeeded(c); - if (c.isPrimitive()) { - return promote(c); - } - if (MemoryAddress.class.isAssignableFrom(c)) { - return MemoryAddress.class; - } - if (MemorySegment.class.isAssignableFrom(c)) { - return MemorySegment.class; - } - throw new IllegalArgumentException("Invalid type for ABI: " + c.getTypeName()); - } - - private MemoryLayout variadicLayout(Class c) { - if (c == long.class) { - return JAVA_LONG; - } else if (c == double.class) { - return JAVA_DOUBLE; - } else if (MemoryAddress.class.isAssignableFrom(c)) { - return ADDRESS; - } else { - throw new IllegalArgumentException("Unhandled variadic argument class: " + c); - } - } - } -} diff --git a/jfuse-linux-aarch64/src/main/java/org/cryptomator/jfuse/linux/aarch64/extr/ll/constants$0.java b/jfuse-linux-aarch64/src/main/java/org/cryptomator/jfuse/linux/aarch64/extr/ll/constants$0.java deleted file mode 100644 index 426dcc26..00000000 --- a/jfuse-linux-aarch64/src/main/java/org/cryptomator/jfuse/linux/aarch64/extr/ll/constants$0.java +++ /dev/null @@ -1,22 +0,0 @@ -// Generated by jextract - -package org.cryptomator.jfuse.linux.aarch64.extr.ll; - -import java.lang.invoke.MethodHandle; -import java.lang.invoke.VarHandle; -import java.nio.ByteOrder; -import java.lang.foreign.*; -import static java.lang.foreign.ValueLayout.*; -class constants$0 { - - static final FunctionDescriptor fuse_parse_cmdline$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, - Constants$root.C_POINTER$LAYOUT, - Constants$root.C_POINTER$LAYOUT - ); - static final MethodHandle fuse_parse_cmdline$MH = RuntimeHelper.downcallHandle( - "fuse_parse_cmdline", - constants$0.fuse_parse_cmdline$FUNC - ); -} - - diff --git a/jfuse-linux-aarch64/src/main/java/org/cryptomator/jfuse/linux/aarch64/extr/stat_h.java b/jfuse-linux-aarch64/src/main/java/org/cryptomator/jfuse/linux/aarch64/extr/stat_h.java index 876229b4..45cb993c 100644 --- a/jfuse-linux-aarch64/src/main/java/org/cryptomator/jfuse/linux/aarch64/extr/stat_h.java +++ b/jfuse-linux-aarch64/src/main/java/org/cryptomator/jfuse/linux/aarch64/extr/stat_h.java @@ -24,15 +24,6 @@ public static long UTIME_NOW() { public static long UTIME_OMIT() { return 1073741822L; } - public static int S_IFDIR() { - return (int)16384L; - } - public static int S_IFREG() { - return (int)32768L; - } - public static int S_IFLNK() { - return (int)40960L; - } } diff --git a/jfuse-linux-aarch64/src/test/java/org/cryptomator/jfuse/linux/aarch64/FuseImplTest.java b/jfuse-linux-aarch64/src/test/java/org/cryptomator/jfuse/linux/aarch64/FuseImplTest.java index 393d1569..120d36ee 100644 --- a/jfuse-linux-aarch64/src/test/java/org/cryptomator/jfuse/linux/aarch64/FuseImplTest.java +++ b/jfuse-linux-aarch64/src/test/java/org/cryptomator/jfuse/linux/aarch64/FuseImplTest.java @@ -4,11 +4,10 @@ import org.cryptomator.jfuse.api.FuseOperations; import org.cryptomator.jfuse.api.MountFailedException; import org.cryptomator.jfuse.api.TimeSpec; +import org.cryptomator.jfuse.linux.aarch64.extr.fuse_cmdline_opts; import org.cryptomator.jfuse.linux.aarch64.extr.fuse_conn_info; import org.cryptomator.jfuse.linux.aarch64.extr.fuse_file_info; import org.cryptomator.jfuse.linux.aarch64.extr.fuse_h; -import org.cryptomator.jfuse.linux.aarch64.extr.ll.fuse_cmdline_opts; -import org.cryptomator.jfuse.linux.aarch64.extr.ll.fuse_lowlevel_h; import org.cryptomator.jfuse.linux.aarch64.extr.timespec; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.Assertions; @@ -20,10 +19,8 @@ import org.junit.jupiter.params.provider.CsvSource; import org.junit.jupiter.params.provider.ValueSource; import org.mockito.Answers; -import org.mockito.Mock; import org.mockito.MockedStatic; import org.mockito.Mockito; -import org.mockito.verification.VerificationMode; import java.lang.foreign.MemoryAddress; import java.lang.foreign.MemorySegment; @@ -85,9 +82,9 @@ public void testFuseMountFails() { @ValueSource(strings = {"--help", "-h"}) public void testParseArgsHelp(String arg) { var args = List.of("fusefs", arg); - try (var fuseLowlevelH = Mockito.mockStatic(fuse_lowlevel_h.class); + try (var fuseFunctionsClass = Mockito.mockStatic(FuseFunctions.class); var fuseH = Mockito.mockStatic(fuse_h.class)) { - fuseLowlevelH.when(() -> fuse_lowlevel_h.fuse_parse_cmdline(Mockito.any(), Mockito.any())).then(invocation -> { + fuseFunctionsClass.when(() -> FuseFunctions.fuse_parse_cmdline(Mockito.any(), Mockito.any())).then(invocation -> { MemorySegment opts = invocation.getArgument(1); fuse_cmdline_opts.show_help$set(opts, 1); return 0; @@ -102,9 +99,9 @@ public void testParseArgsHelp(String arg) { @Test @DisplayName("parseArgs") public void testParseArgs() { - try (var fuseLowlevelH = Mockito.mockStatic(fuse_lowlevel_h.class); + try (var fuseFunctionsClass = Mockito.mockStatic(FuseFunctions.class); var scope = MemorySession.openConfined()) { - fuseLowlevelH.when(() -> fuse_lowlevel_h.fuse_parse_cmdline(Mockito.any(), Mockito.any())).then(invocation -> { + fuseFunctionsClass.when(() -> FuseFunctions.fuse_parse_cmdline(Mockito.any(), Mockito.any())).then(invocation -> { MemorySegment opts = invocation.getArgument(1); fuse_cmdline_opts.singlethread$set(opts, 0); fuse_cmdline_opts.debug$set(opts, 1); diff --git a/jfuse-linux-aarch64/src/test/java/org/cryptomator/jfuse/linux/aarch64/FuseMountImplTest.java b/jfuse-linux-aarch64/src/test/java/org/cryptomator/jfuse/linux/aarch64/FuseMountImplTest.java new file mode 100644 index 00000000..f507e2ba --- /dev/null +++ b/jfuse-linux-aarch64/src/test/java/org/cryptomator/jfuse/linux/aarch64/FuseMountImplTest.java @@ -0,0 +1,88 @@ +package org.cryptomator.jfuse.linux.aarch64; + +import org.cryptomator.jfuse.linux.aarch64.extr.fuse_h; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.ValueSource; +import org.mockito.MockedStatic; +import org.mockito.Mockito; + +import java.lang.foreign.MemoryAddress; + +public class FuseMountImplTest { + + private MockedStatic fuseH; + private FuseArgs fuseArgs = Mockito.mock(FuseArgs.class); + private MemoryAddress fuse = MemoryAddress.ofLong(42L); + private FuseMountImpl fuseMount = new FuseMountImpl(fuse, fuseArgs); + + @BeforeEach + public void setup() { + this.fuseH = Mockito.mockStatic(fuse_h.class); + Mockito.doReturn(1).when(fuseArgs).cloneFd(); + Mockito.doReturn(2).when(fuseArgs).maxIdleThreads(); + Mockito.doReturn(3).when(fuseArgs).maxThreads(); + } + + @AfterEach + public void teardown() { + this.fuseH.close(); + } + + @Test + @DisplayName("mounting singlethreaded calls fuse_loop") + public void testLoopSingleThreaded() { + Mockito.doReturn(false).when(fuseArgs).multithreaded(); + + fuseMount.loop(); + + fuseH.verify(() -> fuse_h.fuse_loop(fuse)); + fuseH.verify(() -> fuse_h.fuse_loop_mt(Mockito.any(), Mockito.any()), Mockito.never()); + } + + @Test + @DisplayName("FUSE 3.1 calls fuse_loop") + public void testLoopMultiThreaded31() { + Mockito.doReturn(true).when(fuseArgs).multithreaded(); + fuseH.when(fuse_h::fuse_version).thenReturn(31); + + fuseMount.loop(); + + fuseH.verify(() -> fuse_h.fuse_loop(fuse)); + fuseH.verify(() -> fuse_h.fuse_loop_mt(Mockito.any(), Mockito.any()), Mockito.never()); + } + + @ParameterizedTest(name = "fuse_version() = {0}") + @ValueSource(ints = {32, 35, 310, 311}) + @DisplayName("FUSE 3.2 - 3.11 calls fuse_loop_mt") + public void testLoopMultiThreaded32(int fuseVersion) { + Mockito.doReturn(true).when(fuseArgs).multithreaded(); + fuseH.when(fuse_h::fuse_version).thenReturn(fuseVersion); + + fuseMount.loop(); + + fuseH.verify(() -> fuse_h.fuse_loop_mt(Mockito.eq(fuse), Mockito.any())); + fuseH.verify(() -> fuse_h.fuse_loop(Mockito.any()), Mockito.never()); + } + + @Test + @DisplayName("FUSE 3.12 calls fuse_loop_mt") + public void testLoopMultiThreaded312() { + var loopCfg = MemoryAddress.ofLong(1337L); + Mockito.doReturn(true).when(fuseArgs).multithreaded(); + fuseH.when(fuse_h::fuse_version).thenReturn(312); + fuseH.when(fuse_h::fuse_loop_cfg_create).thenReturn(loopCfg); + + fuseMount.loop(); + + fuseH.verify(() -> fuse_h.fuse_loop_cfg_set_clone_fd(loopCfg, 1)); + fuseH.verify(() -> fuse_h.fuse_loop_cfg_set_max_threads(loopCfg, 3)); + fuseH.verify(() -> fuse_h.fuse_loop_mt(fuse, loopCfg)); + fuseH.verify(() -> fuse_h.fuse_loop(Mockito.any()), Mockito.never()); + fuseH.verify(() -> fuse_h.fuse_loop_cfg_destroy(loopCfg)); + } + +} \ No newline at end of file diff --git a/jfuse-linux-amd64/pom.xml b/jfuse-linux-amd64/pom.xml index f8daae5b..1ee56df3 100644 --- a/jfuse-linux-amd64/pom.xml +++ b/jfuse-linux-amd64/pom.xml @@ -5,7 +5,7 @@ org.cryptomator jfuse - 0.2.0 + 0.2.1 4.0.0 jfuse-linux-amd64 @@ -91,14 +91,19 @@ fuse_h _FILE_OFFSET_BITS=64 - FUSE_USE_VERSION=35 + FUSE_USE_VERSION=312 + fuse_version fuse_lib_help fuse_new fuse_mount fuse_get_session fuse_loop + fuse_loop_cfg_create + fuse_loop_cfg_set_clone_fd + fuse_loop_cfg_set_max_threads + fuse_loop_cfg_destroy fuse_loop_mt fuse_exit fuse_unmount @@ -115,7 +120,7 @@ timespec fuse_conn_info fuse_args - fuse_loop_config + fuse_loop_config_v1 @@ -126,15 +131,12 @@ ${project.parent.basedir}/libfuse3/include/fuse_lowlevel.h - org.cryptomator.jfuse.linux.amd64.extr.ll + org.cryptomator.jfuse.linux.amd64.extr fuse_lowlevel_h _FILE_OFFSET_BITS=64 - FUSE_USE_VERSION=35 + FUSE_USE_VERSION=312 - - fuse_parse_cmdline - fuse_cmdline_opts diff --git a/jfuse-linux-amd64/src/main/java/org/cryptomator/jfuse/linux/amd64/FuseArgs.java b/jfuse-linux-amd64/src/main/java/org/cryptomator/jfuse/linux/amd64/FuseArgs.java index 4c7c5099..cb1f6ea9 100644 --- a/jfuse-linux-amd64/src/main/java/org/cryptomator/jfuse/linux/amd64/FuseArgs.java +++ b/jfuse-linux-amd64/src/main/java/org/cryptomator/jfuse/linux/amd64/FuseArgs.java @@ -1,7 +1,7 @@ package org.cryptomator.jfuse.linux.amd64; import org.cryptomator.jfuse.linux.amd64.extr.fuse_args; -import org.cryptomator.jfuse.linux.amd64.extr.ll.fuse_cmdline_opts; +import org.cryptomator.jfuse.linux.amd64.extr.fuse_cmdline_opts; import java.lang.foreign.MemoryAddress; import java.lang.foreign.MemorySegment; @@ -32,4 +32,16 @@ public boolean multithreaded() { return fuse_cmdline_opts.singlethread$get(cmdLineOpts) == 0; } + public int cloneFd() { + return fuse_cmdline_opts.clone_fd$get(cmdLineOpts); + } + + public int maxIdleThreads() { + return fuse_cmdline_opts.max_idle_threads$get(cmdLineOpts); + } + + public int maxThreads() { + return fuse_cmdline_opts.max_threads$get(cmdLineOpts); + } + } diff --git a/jfuse-linux-amd64/src/main/java/org/cryptomator/jfuse/linux/amd64/FuseFunctions.java b/jfuse-linux-amd64/src/main/java/org/cryptomator/jfuse/linux/amd64/FuseFunctions.java new file mode 100644 index 00000000..b9ea2dd0 --- /dev/null +++ b/jfuse-linux-amd64/src/main/java/org/cryptomator/jfuse/linux/amd64/FuseFunctions.java @@ -0,0 +1,44 @@ +package org.cryptomator.jfuse.linux.amd64; + +import java.lang.foreign.Addressable; +import java.lang.foreign.FunctionDescriptor; +import java.lang.foreign.Linker; +import java.lang.foreign.SymbolLookup; +import java.lang.invoke.MethodHandle; + +import static java.lang.foreign.ValueLayout.ADDRESS; +import static java.lang.foreign.ValueLayout.JAVA_INT; + +/** + * These method references can not be jextract'ed, partly due to jextract not being able to understand {@code #define}, + * partly due to slight differences in the FUSE API, which applies a versioning scheme via dlvsym, that Panama's default + * {@link java.lang.foreign.SymbolLookup} doesn't support. + */ +class FuseFunctions { + + // see https://github.com/libfuse/libfuse/blob/fuse-3.12.0/include/fuse_lowlevel.h#L1892-L1923 + private static final FunctionDescriptor FUSE_PARSE_CMDLINE = FunctionDescriptor.of(JAVA_INT, ADDRESS, ADDRESS); + + private final MethodHandle fuse_parse_cmdline; + + private FuseFunctions() { + var lookup = SymbolLookup.loaderLookup(); + var linker = Linker.nativeLinker(); + this.fuse_parse_cmdline = lookup.lookup("fuse_parse_cmdline") + .map(symbol -> linker.downcallHandle(symbol, FUSE_PARSE_CMDLINE)) + .orElseThrow(() -> new UnsatisfiedLinkError("unresolved symbol fuse_parse_cmdline")); + } + + private static class Holder { + private static final FuseFunctions INSTANCE = new FuseFunctions(); + } + + public static int fuse_parse_cmdline(Addressable args, Addressable opts) { + try { + return (int) Holder.INSTANCE.fuse_parse_cmdline.invokeExact(args, opts); + } catch (Throwable e) { + throw new AssertionError("should not reach here", e); + } + } + +} diff --git a/jfuse-linux-amd64/src/main/java/org/cryptomator/jfuse/linux/amd64/FuseImpl.java b/jfuse-linux-amd64/src/main/java/org/cryptomator/jfuse/linux/amd64/FuseImpl.java index 55bdb212..44927cef 100644 --- a/jfuse-linux-amd64/src/main/java/org/cryptomator/jfuse/linux/amd64/FuseImpl.java +++ b/jfuse-linux-amd64/src/main/java/org/cryptomator/jfuse/linux/amd64/FuseImpl.java @@ -8,8 +8,7 @@ import org.cryptomator.jfuse.linux.amd64.extr.fuse_args; import org.cryptomator.jfuse.linux.amd64.extr.fuse_h; import org.cryptomator.jfuse.linux.amd64.extr.fuse_operations; -import org.cryptomator.jfuse.linux.amd64.extr.ll.fuse_cmdline_opts; -import org.cryptomator.jfuse.linux.amd64.extr.ll.fuse_lowlevel_h; +import org.cryptomator.jfuse.linux.amd64.extr.fuse_cmdline_opts; import org.cryptomator.jfuse.linux.amd64.extr.stat_h; import org.cryptomator.jfuse.linux.amd64.extr.timespec; import org.jetbrains.annotations.VisibleForTesting; @@ -61,7 +60,7 @@ FuseArgs parseArgs(List cmdLineArgs) throws IllegalArgumentException { fuse_args.allocated$set(args, 0); var opts = fuse_cmdline_opts.allocate(fuseScope); - int parseResult = fuse_lowlevel_h.fuse_parse_cmdline(args, opts); + int parseResult = FuseFunctions.fuse_parse_cmdline(args, opts); if (parseResult != 0) { throw new IllegalArgumentException("fuse_parse_cmdline failed to parse " + String.join(" ", cmdLineArgs)); } diff --git a/jfuse-linux-amd64/src/main/java/org/cryptomator/jfuse/linux/amd64/FuseMountImpl.java b/jfuse-linux-amd64/src/main/java/org/cryptomator/jfuse/linux/amd64/FuseMountImpl.java index 60e9a2da..dd2de259 100644 --- a/jfuse-linux-amd64/src/main/java/org/cryptomator/jfuse/linux/amd64/FuseMountImpl.java +++ b/jfuse-linux-amd64/src/main/java/org/cryptomator/jfuse/linux/amd64/FuseMountImpl.java @@ -2,24 +2,40 @@ import org.cryptomator.jfuse.api.FuseMount; import org.cryptomator.jfuse.linux.amd64.extr.fuse_h; -import org.cryptomator.jfuse.linux.amd64.extr.fuse_loop_config; +import org.cryptomator.jfuse.linux.amd64.extr.fuse_loop_config_v1; import java.lang.foreign.MemoryAddress; import java.lang.foreign.MemorySession; record FuseMountImpl(MemoryAddress fuse, FuseArgs fuseArgs) implements FuseMount { + private static final int FUSE_3_2 = 32; + private static final int FUSE_3_12 = 312; + @Override public int loop() { - if (fuseArgs.multithreaded()) { + // depends on fuse version: https://github.com/libfuse/libfuse/blob/fuse-3.12.0/include/fuse.h#L1011-L1050 + if (!fuseArgs.multithreaded() || fuse_h.fuse_version() < FUSE_3_2) { + // FUSE 3.1: to keep things simple, we just don't support fuse_loop_mt + return fuse_h.fuse_loop(fuse); + } else if (fuse_h.fuse_version() < FUSE_3_12) { + // FUSE 3.2 try (var scope = MemorySession.openConfined()) { - var loopCfg = fuse_loop_config.allocate(scope); - fuse_loop_config.clone_fd$set(loopCfg, 0); - fuse_loop_config.max_idle_threads$set(loopCfg, 10); + var loopCfg = fuse_loop_config_v1.allocate(scope); + fuse_loop_config_v1.clone_fd$set(loopCfg, fuseArgs.cloneFd()); + fuse_loop_config_v1.max_idle_threads$set(loopCfg, fuseArgs.maxIdleThreads()); return fuse_h.fuse_loop_mt(fuse, loopCfg); } } else { - return fuse_h.fuse_loop(fuse); + // FUSE 3.12 + var loopCfg = fuse_h.fuse_loop_cfg_create(); + try { + fuse_h.fuse_loop_cfg_set_clone_fd(loopCfg, fuseArgs.cloneFd()); + fuse_h.fuse_loop_cfg_set_max_threads(loopCfg, fuseArgs.maxThreads()); + return fuse_h.fuse_loop_mt(fuse, loopCfg); + } finally { + fuse_h.fuse_loop_cfg_destroy(loopCfg); + } } } diff --git a/jfuse-linux-amd64/src/main/java/org/cryptomator/jfuse/linux/amd64/extr/constants$0.java b/jfuse-linux-amd64/src/main/java/org/cryptomator/jfuse/linux/amd64/extr/constants$0.java index 8ee42214..a3ea0512 100644 --- a/jfuse-linux-amd64/src/main/java/org/cryptomator/jfuse/linux/amd64/extr/constants$0.java +++ b/jfuse-linux-amd64/src/main/java/org/cryptomator/jfuse/linux/amd64/extr/constants$0.java @@ -9,47 +9,45 @@ import static java.lang.foreign.ValueLayout.*; class constants$0 { - static final FunctionDescriptor fuse_fill_dir_t$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, - Constants$root.C_POINTER$LAYOUT, - Constants$root.C_POINTER$LAYOUT, - Constants$root.C_POINTER$LAYOUT, - Constants$root.C_LONG_LONG$LAYOUT, - Constants$root.C_INT$LAYOUT + static final FunctionDescriptor fuse_version$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT); + static final MethodHandle fuse_version$MH = RuntimeHelper.downcallHandle( + "fuse_version", + constants$0.fuse_version$FUNC ); - static final MethodHandle fuse_fill_dir_t$MH = RuntimeHelper.downcallHandle( - constants$0.fuse_fill_dir_t$FUNC + static final FunctionDescriptor fuse_loop_cfg_create$FUNC = FunctionDescriptor.of(Constants$root.C_POINTER$LAYOUT); + static final MethodHandle fuse_loop_cfg_create$MH = RuntimeHelper.downcallHandle( + "fuse_loop_cfg_create", + constants$0.fuse_loop_cfg_create$FUNC ); - static final FunctionDescriptor fuse_lib_help$FUNC = FunctionDescriptor.ofVoid( + static final FunctionDescriptor fuse_loop_cfg_destroy$FUNC = FunctionDescriptor.ofVoid( Constants$root.C_POINTER$LAYOUT ); - static final MethodHandle fuse_lib_help$MH = RuntimeHelper.downcallHandle( - "fuse_lib_help", - constants$0.fuse_lib_help$FUNC + static final MethodHandle fuse_loop_cfg_destroy$MH = RuntimeHelper.downcallHandle( + "fuse_loop_cfg_destroy", + constants$0.fuse_loop_cfg_destroy$FUNC ); - static final FunctionDescriptor fuse_new$FUNC = FunctionDescriptor.of(Constants$root.C_POINTER$LAYOUT, - Constants$root.C_POINTER$LAYOUT, + static final FunctionDescriptor fuse_loop_cfg_set_max_threads$FUNC = FunctionDescriptor.ofVoid( Constants$root.C_POINTER$LAYOUT, - Constants$root.C_LONG_LONG$LAYOUT, - Constants$root.C_POINTER$LAYOUT + Constants$root.C_INT$LAYOUT ); - static final MethodHandle fuse_new$MH = RuntimeHelper.downcallHandle( - "fuse_new", - constants$0.fuse_new$FUNC + static final MethodHandle fuse_loop_cfg_set_max_threads$MH = RuntimeHelper.downcallHandle( + "fuse_loop_cfg_set_max_threads", + constants$0.fuse_loop_cfg_set_max_threads$FUNC ); - static final FunctionDescriptor fuse_mount$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, + static final FunctionDescriptor fuse_loop_cfg_set_clone_fd$FUNC = FunctionDescriptor.ofVoid( Constants$root.C_POINTER$LAYOUT, - Constants$root.C_POINTER$LAYOUT + Constants$root.C_INT$LAYOUT ); - static final MethodHandle fuse_mount$MH = RuntimeHelper.downcallHandle( - "fuse_mount", - constants$0.fuse_mount$FUNC + static final MethodHandle fuse_loop_cfg_set_clone_fd$MH = RuntimeHelper.downcallHandle( + "fuse_loop_cfg_set_clone_fd", + constants$0.fuse_loop_cfg_set_clone_fd$FUNC ); - static final FunctionDescriptor fuse_unmount$FUNC = FunctionDescriptor.ofVoid( - Constants$root.C_POINTER$LAYOUT - ); - static final MethodHandle fuse_unmount$MH = RuntimeHelper.downcallHandle( - "fuse_unmount", - constants$0.fuse_unmount$FUNC + static final FunctionDescriptor fuse_fill_dir_t$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, + Constants$root.C_POINTER$LAYOUT, + Constants$root.C_POINTER$LAYOUT, + Constants$root.C_POINTER$LAYOUT, + Constants$root.C_LONG_LONG$LAYOUT, + Constants$root.C_INT$LAYOUT ); } diff --git a/jfuse-linux-amd64/src/main/java/org/cryptomator/jfuse/linux/amd64/extr/constants$1.java b/jfuse-linux-amd64/src/main/java/org/cryptomator/jfuse/linux/amd64/extr/constants$1.java index a6d7fef2..b5e94157 100644 --- a/jfuse-linux-amd64/src/main/java/org/cryptomator/jfuse/linux/amd64/extr/constants$1.java +++ b/jfuse-linux-amd64/src/main/java/org/cryptomator/jfuse/linux/amd64/extr/constants$1.java @@ -9,41 +9,54 @@ import static java.lang.foreign.ValueLayout.*; class constants$1 { - static final FunctionDescriptor fuse_destroy$FUNC = FunctionDescriptor.ofVoid( - Constants$root.C_POINTER$LAYOUT + static final FunctionDescriptor fuse_fill_dir_t$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, + Constants$root.C_POINTER$LAYOUT, + Constants$root.C_POINTER$LAYOUT, + Constants$root.C_POINTER$LAYOUT, + Constants$root.C_LONG_LONG$LAYOUT, + Constants$root.C_INT$LAYOUT ); - static final MethodHandle fuse_destroy$MH = RuntimeHelper.downcallHandle( - "fuse_destroy", - constants$1.fuse_destroy$FUNC + static final MethodHandle fuse_fill_dir_t$MH = RuntimeHelper.downcallHandle( + constants$1.fuse_fill_dir_t$FUNC ); - static final FunctionDescriptor fuse_loop$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, + static final FunctionDescriptor fuse_lib_help$FUNC = FunctionDescriptor.ofVoid( Constants$root.C_POINTER$LAYOUT ); - static final MethodHandle fuse_loop$MH = RuntimeHelper.downcallHandle( - "fuse_loop", - constants$1.fuse_loop$FUNC + static final MethodHandle fuse_lib_help$MH = RuntimeHelper.downcallHandle( + "fuse_lib_help", + constants$1.fuse_lib_help$FUNC ); - static final FunctionDescriptor fuse_exit$FUNC = FunctionDescriptor.ofVoid( + static final FunctionDescriptor fuse_new$FUNC = FunctionDescriptor.of(Constants$root.C_POINTER$LAYOUT, + Constants$root.C_POINTER$LAYOUT, + Constants$root.C_POINTER$LAYOUT, + Constants$root.C_LONG_LONG$LAYOUT, Constants$root.C_POINTER$LAYOUT ); - static final MethodHandle fuse_exit$MH = RuntimeHelper.downcallHandle( - "fuse_exit", - constants$1.fuse_exit$FUNC + static final MethodHandle fuse_new$MH = RuntimeHelper.downcallHandle( + "fuse_new", + constants$1.fuse_new$FUNC ); - static final FunctionDescriptor fuse_loop_mt$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, + static final FunctionDescriptor fuse_mount$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, Constants$root.C_POINTER$LAYOUT, Constants$root.C_POINTER$LAYOUT ); - static final MethodHandle fuse_loop_mt$MH = RuntimeHelper.downcallHandle( - "fuse_loop_mt", - constants$1.fuse_loop_mt$FUNC + static final MethodHandle fuse_mount$MH = RuntimeHelper.downcallHandle( + "fuse_mount", + constants$1.fuse_mount$FUNC + ); + static final FunctionDescriptor fuse_unmount$FUNC = FunctionDescriptor.ofVoid( + Constants$root.C_POINTER$LAYOUT + ); + static final MethodHandle fuse_unmount$MH = RuntimeHelper.downcallHandle( + "fuse_unmount", + constants$1.fuse_unmount$FUNC ); - static final FunctionDescriptor fuse_get_session$FUNC = FunctionDescriptor.of(Constants$root.C_POINTER$LAYOUT, + static final FunctionDescriptor fuse_destroy$FUNC = FunctionDescriptor.ofVoid( Constants$root.C_POINTER$LAYOUT ); - static final MethodHandle fuse_get_session$MH = RuntimeHelper.downcallHandle( - "fuse_get_session", - constants$1.fuse_get_session$FUNC + static final MethodHandle fuse_destroy$MH = RuntimeHelper.downcallHandle( + "fuse_destroy", + constants$1.fuse_destroy$FUNC ); } diff --git a/jfuse-linux-amd64/src/main/java/org/cryptomator/jfuse/linux/amd64/extr/constants$2.java b/jfuse-linux-amd64/src/main/java/org/cryptomator/jfuse/linux/amd64/extr/constants$2.java new file mode 100644 index 00000000..5eb1f25a --- /dev/null +++ b/jfuse-linux-amd64/src/main/java/org/cryptomator/jfuse/linux/amd64/extr/constants$2.java @@ -0,0 +1,43 @@ +// Generated by jextract + +package org.cryptomator.jfuse.linux.amd64.extr; + +import java.lang.invoke.MethodHandle; +import java.lang.invoke.VarHandle; +import java.nio.ByteOrder; +import java.lang.foreign.*; +import static java.lang.foreign.ValueLayout.*; +class constants$2 { + + static final FunctionDescriptor fuse_loop$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, + Constants$root.C_POINTER$LAYOUT + ); + static final MethodHandle fuse_loop$MH = RuntimeHelper.downcallHandle( + "fuse_loop", + constants$2.fuse_loop$FUNC + ); + static final FunctionDescriptor fuse_exit$FUNC = FunctionDescriptor.ofVoid( + Constants$root.C_POINTER$LAYOUT + ); + static final MethodHandle fuse_exit$MH = RuntimeHelper.downcallHandle( + "fuse_exit", + constants$2.fuse_exit$FUNC + ); + static final FunctionDescriptor fuse_loop_mt$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, + Constants$root.C_POINTER$LAYOUT, + Constants$root.C_POINTER$LAYOUT + ); + static final MethodHandle fuse_loop_mt$MH = RuntimeHelper.downcallHandle( + "fuse_loop_mt", + constants$2.fuse_loop_mt$FUNC + ); + static final FunctionDescriptor fuse_get_session$FUNC = FunctionDescriptor.of(Constants$root.C_POINTER$LAYOUT, + Constants$root.C_POINTER$LAYOUT + ); + static final MethodHandle fuse_get_session$MH = RuntimeHelper.downcallHandle( + "fuse_get_session", + constants$2.fuse_get_session$FUNC + ); +} + + diff --git a/jfuse-linux-aarch64/src/main/java/org/cryptomator/jfuse/linux/aarch64/extr/ll/fuse_cmdline_opts.java b/jfuse-linux-amd64/src/main/java/org/cryptomator/jfuse/linux/amd64/extr/fuse_cmdline_opts.java similarity index 90% rename from jfuse-linux-aarch64/src/main/java/org/cryptomator/jfuse/linux/aarch64/extr/ll/fuse_cmdline_opts.java rename to jfuse-linux-amd64/src/main/java/org/cryptomator/jfuse/linux/amd64/extr/fuse_cmdline_opts.java index 34c36adb..7e8155a8 100644 --- a/jfuse-linux-aarch64/src/main/java/org/cryptomator/jfuse/linux/aarch64/extr/ll/fuse_cmdline_opts.java +++ b/jfuse-linux-amd64/src/main/java/org/cryptomator/jfuse/linux/amd64/extr/fuse_cmdline_opts.java @@ -1,6 +1,6 @@ // Generated by jextract -package org.cryptomator.jfuse.linux.aarch64.extr.ll; +package org.cryptomator.jfuse.linux.amd64.extr; import java.lang.invoke.MethodHandle; import java.lang.invoke.VarHandle; @@ -18,7 +18,9 @@ public class fuse_cmdline_opts { Constants$root.C_INT$LAYOUT.withName("show_version"), Constants$root.C_INT$LAYOUT.withName("show_help"), Constants$root.C_INT$LAYOUT.withName("clone_fd"), - Constants$root.C_INT$LAYOUT.withName("max_idle_threads") + Constants$root.C_INT$LAYOUT.withName("max_idle_threads"), + Constants$root.C_INT$LAYOUT.withName("max_threads"), + MemoryLayout.paddingLayout(32) ).withName("fuse_cmdline_opts"); public static MemoryLayout $LAYOUT() { return fuse_cmdline_opts.$struct$LAYOUT; @@ -167,6 +169,22 @@ public class fuse_cmdline_opts { public static void max_idle_threads$set(MemorySegment seg, long index, int x) { fuse_cmdline_opts.max_idle_threads$VH.set(seg.asSlice(index*sizeof()), x); } + static final VarHandle max_threads$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("max_threads")); + public static VarHandle max_threads$VH() { + return fuse_cmdline_opts.max_threads$VH; + } + public static int max_threads$get(MemorySegment seg) { + return (int)fuse_cmdline_opts.max_threads$VH.get(seg); + } + public static void max_threads$set( MemorySegment seg, int x) { + fuse_cmdline_opts.max_threads$VH.set(seg, x); + } + public static int max_threads$get(MemorySegment seg, long index) { + return (int)fuse_cmdline_opts.max_threads$VH.get(seg.asSlice(index*sizeof())); + } + public static void max_threads$set(MemorySegment seg, long index, int x) { + fuse_cmdline_opts.max_threads$VH.set(seg.asSlice(index*sizeof()), x); + } public static long sizeof() { return $LAYOUT().byteSize(); } public static MemorySegment allocate(SegmentAllocator allocator) { return allocator.allocate($LAYOUT()); } public static MemorySegment allocateArray(int len, SegmentAllocator allocator) { diff --git a/jfuse-linux-amd64/src/main/java/org/cryptomator/jfuse/linux/amd64/extr/fuse_fill_dir_t.java b/jfuse-linux-amd64/src/main/java/org/cryptomator/jfuse/linux/amd64/extr/fuse_fill_dir_t.java index e7fe2602..fac20ad9 100644 --- a/jfuse-linux-amd64/src/main/java/org/cryptomator/jfuse/linux/amd64/extr/fuse_fill_dir_t.java +++ b/jfuse-linux-amd64/src/main/java/org/cryptomator/jfuse/linux/amd64/extr/fuse_fill_dir_t.java @@ -17,7 +17,7 @@ static fuse_fill_dir_t ofAddress(MemoryAddress addr, MemorySession session) { MemorySegment symbol = MemorySegment.ofAddress(addr, 0, session); return (java.lang.foreign.MemoryAddress _buf, java.lang.foreign.MemoryAddress _name, java.lang.foreign.MemoryAddress _stbuf, long _off, int _flags) -> { try { - return (int)constants$0.fuse_fill_dir_t$MH.invokeExact((Addressable)symbol, (java.lang.foreign.Addressable)_buf, (java.lang.foreign.Addressable)_name, (java.lang.foreign.Addressable)_stbuf, _off, _flags); + return (int)constants$1.fuse_fill_dir_t$MH.invokeExact((Addressable)symbol, (java.lang.foreign.Addressable)_buf, (java.lang.foreign.Addressable)_name, (java.lang.foreign.Addressable)_stbuf, _off, _flags); } catch (Throwable ex$) { throw new AssertionError("should not reach here", ex$); } diff --git a/jfuse-linux-amd64/src/main/java/org/cryptomator/jfuse/linux/amd64/extr/fuse_h.java b/jfuse-linux-amd64/src/main/java/org/cryptomator/jfuse/linux/amd64/extr/fuse_h.java index e188e1d8..d573932e 100644 --- a/jfuse-linux-amd64/src/main/java/org/cryptomator/jfuse/linux/amd64/extr/fuse_h.java +++ b/jfuse-linux-amd64/src/main/java/org/cryptomator/jfuse/linux/amd64/extr/fuse_h.java @@ -18,8 +18,63 @@ public class fuse_h { public static OfFloat C_FLOAT = Constants$root.C_FLOAT$LAYOUT; public static OfDouble C_DOUBLE = Constants$root.C_DOUBLE$LAYOUT; public static OfAddress C_POINTER = Constants$root.C_POINTER$LAYOUT; + public static MethodHandle fuse_version$MH() { + return RuntimeHelper.requireNonNull(constants$0.fuse_version$MH,"fuse_version"); + } + public static int fuse_version () { + var mh$ = fuse_version$MH(); + try { + return (int)mh$.invokeExact(); + } catch (Throwable ex$) { + throw new AssertionError("should not reach here", ex$); + } + } + public static MethodHandle fuse_loop_cfg_create$MH() { + return RuntimeHelper.requireNonNull(constants$0.fuse_loop_cfg_create$MH,"fuse_loop_cfg_create"); + } + public static MemoryAddress fuse_loop_cfg_create () { + var mh$ = fuse_loop_cfg_create$MH(); + try { + return (java.lang.foreign.MemoryAddress)mh$.invokeExact(); + } catch (Throwable ex$) { + throw new AssertionError("should not reach here", ex$); + } + } + public static MethodHandle fuse_loop_cfg_destroy$MH() { + return RuntimeHelper.requireNonNull(constants$0.fuse_loop_cfg_destroy$MH,"fuse_loop_cfg_destroy"); + } + public static void fuse_loop_cfg_destroy ( Addressable config) { + var mh$ = fuse_loop_cfg_destroy$MH(); + try { + mh$.invokeExact(config); + } catch (Throwable ex$) { + throw new AssertionError("should not reach here", ex$); + } + } + public static MethodHandle fuse_loop_cfg_set_max_threads$MH() { + return RuntimeHelper.requireNonNull(constants$0.fuse_loop_cfg_set_max_threads$MH,"fuse_loop_cfg_set_max_threads"); + } + public static void fuse_loop_cfg_set_max_threads ( Addressable config, int value) { + var mh$ = fuse_loop_cfg_set_max_threads$MH(); + try { + mh$.invokeExact(config, value); + } catch (Throwable ex$) { + throw new AssertionError("should not reach here", ex$); + } + } + public static MethodHandle fuse_loop_cfg_set_clone_fd$MH() { + return RuntimeHelper.requireNonNull(constants$0.fuse_loop_cfg_set_clone_fd$MH,"fuse_loop_cfg_set_clone_fd"); + } + public static void fuse_loop_cfg_set_clone_fd ( Addressable config, int value) { + var mh$ = fuse_loop_cfg_set_clone_fd$MH(); + try { + mh$.invokeExact(config, value); + } catch (Throwable ex$) { + throw new AssertionError("should not reach here", ex$); + } + } public static MethodHandle fuse_lib_help$MH() { - return RuntimeHelper.requireNonNull(constants$0.fuse_lib_help$MH,"fuse_lib_help"); + return RuntimeHelper.requireNonNull(constants$1.fuse_lib_help$MH,"fuse_lib_help"); } public static void fuse_lib_help ( Addressable args) { var mh$ = fuse_lib_help$MH(); @@ -30,7 +85,7 @@ public static void fuse_lib_help ( Addressable args) { } } public static MethodHandle fuse_new$MH() { - return RuntimeHelper.requireNonNull(constants$0.fuse_new$MH,"fuse_new"); + return RuntimeHelper.requireNonNull(constants$1.fuse_new$MH,"fuse_new"); } public static MemoryAddress fuse_new ( Addressable args, Addressable op, long op_size, Addressable private_data) { var mh$ = fuse_new$MH(); @@ -41,7 +96,7 @@ public static MemoryAddress fuse_new ( Addressable args, Addressable op, long } } public static MethodHandle fuse_mount$MH() { - return RuntimeHelper.requireNonNull(constants$0.fuse_mount$MH,"fuse_mount"); + return RuntimeHelper.requireNonNull(constants$1.fuse_mount$MH,"fuse_mount"); } public static int fuse_mount ( Addressable f, Addressable mountpoint) { var mh$ = fuse_mount$MH(); @@ -52,7 +107,7 @@ public static int fuse_mount ( Addressable f, Addressable mountpoint) { } } public static MethodHandle fuse_unmount$MH() { - return RuntimeHelper.requireNonNull(constants$0.fuse_unmount$MH,"fuse_unmount"); + return RuntimeHelper.requireNonNull(constants$1.fuse_unmount$MH,"fuse_unmount"); } public static void fuse_unmount ( Addressable f) { var mh$ = fuse_unmount$MH(); @@ -74,7 +129,7 @@ public static void fuse_destroy ( Addressable f) { } } public static MethodHandle fuse_loop$MH() { - return RuntimeHelper.requireNonNull(constants$1.fuse_loop$MH,"fuse_loop"); + return RuntimeHelper.requireNonNull(constants$2.fuse_loop$MH,"fuse_loop"); } public static int fuse_loop ( Addressable f) { var mh$ = fuse_loop$MH(); @@ -85,7 +140,7 @@ public static int fuse_loop ( Addressable f) { } } public static MethodHandle fuse_exit$MH() { - return RuntimeHelper.requireNonNull(constants$1.fuse_exit$MH,"fuse_exit"); + return RuntimeHelper.requireNonNull(constants$2.fuse_exit$MH,"fuse_exit"); } public static void fuse_exit ( Addressable f) { var mh$ = fuse_exit$MH(); @@ -96,7 +151,7 @@ public static void fuse_exit ( Addressable f) { } } public static MethodHandle fuse_loop_mt$MH() { - return RuntimeHelper.requireNonNull(constants$1.fuse_loop_mt$MH,"fuse_loop_mt"); + return RuntimeHelper.requireNonNull(constants$2.fuse_loop_mt$MH,"fuse_loop_mt"); } public static int fuse_loop_mt ( Addressable f, Addressable config) { var mh$ = fuse_loop_mt$MH(); @@ -107,7 +162,7 @@ public static int fuse_loop_mt ( Addressable f, Addressable config) { } } public static MethodHandle fuse_get_session$MH() { - return RuntimeHelper.requireNonNull(constants$1.fuse_get_session$MH,"fuse_get_session"); + return RuntimeHelper.requireNonNull(constants$2.fuse_get_session$MH,"fuse_get_session"); } public static MemoryAddress fuse_get_session ( Addressable f) { var mh$ = fuse_get_session$MH(); diff --git a/jfuse-linux-amd64/src/main/java/org/cryptomator/jfuse/linux/amd64/extr/fuse_loop_config.java b/jfuse-linux-amd64/src/main/java/org/cryptomator/jfuse/linux/amd64/extr/fuse_loop_config_v1.java similarity index 70% rename from jfuse-linux-amd64/src/main/java/org/cryptomator/jfuse/linux/amd64/extr/fuse_loop_config.java rename to jfuse-linux-amd64/src/main/java/org/cryptomator/jfuse/linux/amd64/extr/fuse_loop_config_v1.java index 093a4f0d..02f3b7ed 100644 --- a/jfuse-linux-amd64/src/main/java/org/cryptomator/jfuse/linux/amd64/extr/fuse_loop_config.java +++ b/jfuse-linux-amd64/src/main/java/org/cryptomator/jfuse/linux/amd64/extr/fuse_loop_config_v1.java @@ -7,46 +7,46 @@ import java.nio.ByteOrder; import java.lang.foreign.*; import static java.lang.foreign.ValueLayout.*; -public class fuse_loop_config { +public class fuse_loop_config_v1 { static final GroupLayout $struct$LAYOUT = MemoryLayout.structLayout( Constants$root.C_INT$LAYOUT.withName("clone_fd"), Constants$root.C_INT$LAYOUT.withName("max_idle_threads") - ).withName("fuse_loop_config"); + ).withName("fuse_loop_config_v1"); public static MemoryLayout $LAYOUT() { - return fuse_loop_config.$struct$LAYOUT; + return fuse_loop_config_v1.$struct$LAYOUT; } static final VarHandle clone_fd$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("clone_fd")); public static VarHandle clone_fd$VH() { - return fuse_loop_config.clone_fd$VH; + return fuse_loop_config_v1.clone_fd$VH; } public static int clone_fd$get(MemorySegment seg) { - return (int)fuse_loop_config.clone_fd$VH.get(seg); + return (int)fuse_loop_config_v1.clone_fd$VH.get(seg); } public static void clone_fd$set( MemorySegment seg, int x) { - fuse_loop_config.clone_fd$VH.set(seg, x); + fuse_loop_config_v1.clone_fd$VH.set(seg, x); } public static int clone_fd$get(MemorySegment seg, long index) { - return (int)fuse_loop_config.clone_fd$VH.get(seg.asSlice(index*sizeof())); + return (int)fuse_loop_config_v1.clone_fd$VH.get(seg.asSlice(index*sizeof())); } public static void clone_fd$set(MemorySegment seg, long index, int x) { - fuse_loop_config.clone_fd$VH.set(seg.asSlice(index*sizeof()), x); + fuse_loop_config_v1.clone_fd$VH.set(seg.asSlice(index*sizeof()), x); } static final VarHandle max_idle_threads$VH = $struct$LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("max_idle_threads")); public static VarHandle max_idle_threads$VH() { - return fuse_loop_config.max_idle_threads$VH; + return fuse_loop_config_v1.max_idle_threads$VH; } public static int max_idle_threads$get(MemorySegment seg) { - return (int)fuse_loop_config.max_idle_threads$VH.get(seg); + return (int)fuse_loop_config_v1.max_idle_threads$VH.get(seg); } public static void max_idle_threads$set( MemorySegment seg, int x) { - fuse_loop_config.max_idle_threads$VH.set(seg, x); + fuse_loop_config_v1.max_idle_threads$VH.set(seg, x); } public static int max_idle_threads$get(MemorySegment seg, long index) { - return (int)fuse_loop_config.max_idle_threads$VH.get(seg.asSlice(index*sizeof())); + return (int)fuse_loop_config_v1.max_idle_threads$VH.get(seg.asSlice(index*sizeof())); } public static void max_idle_threads$set(MemorySegment seg, long index, int x) { - fuse_loop_config.max_idle_threads$VH.set(seg.asSlice(index*sizeof()), x); + fuse_loop_config_v1.max_idle_threads$VH.set(seg.asSlice(index*sizeof()), x); } public static long sizeof() { return $LAYOUT().byteSize(); } public static MemorySegment allocate(SegmentAllocator allocator) { return allocator.allocate($LAYOUT()); } diff --git a/jfuse-linux-aarch64/src/main/java/org/cryptomator/jfuse/linux/aarch64/extr/ll/fuse_lowlevel_h.java b/jfuse-linux-amd64/src/main/java/org/cryptomator/jfuse/linux/amd64/extr/fuse_lowlevel_h.java similarity index 61% rename from jfuse-linux-aarch64/src/main/java/org/cryptomator/jfuse/linux/aarch64/extr/ll/fuse_lowlevel_h.java rename to jfuse-linux-amd64/src/main/java/org/cryptomator/jfuse/linux/amd64/extr/fuse_lowlevel_h.java index b6462f4d..5eb7c15a 100644 --- a/jfuse-linux-aarch64/src/main/java/org/cryptomator/jfuse/linux/aarch64/extr/ll/fuse_lowlevel_h.java +++ b/jfuse-linux-amd64/src/main/java/org/cryptomator/jfuse/linux/amd64/extr/fuse_lowlevel_h.java @@ -1,6 +1,6 @@ // Generated by jextract -package org.cryptomator.jfuse.linux.aarch64.extr.ll; +package org.cryptomator.jfuse.linux.amd64.extr; import java.lang.invoke.MethodHandle; import java.lang.invoke.VarHandle; @@ -18,17 +18,6 @@ public class fuse_lowlevel_h { public static OfFloat C_FLOAT = Constants$root.C_FLOAT$LAYOUT; public static OfDouble C_DOUBLE = Constants$root.C_DOUBLE$LAYOUT; public static OfAddress C_POINTER = Constants$root.C_POINTER$LAYOUT; - public static MethodHandle fuse_parse_cmdline$MH() { - return RuntimeHelper.requireNonNull(constants$0.fuse_parse_cmdline$MH,"fuse_parse_cmdline"); - } - public static int fuse_parse_cmdline ( Addressable args, Addressable opts) { - var mh$ = fuse_parse_cmdline$MH(); - try { - return (int)mh$.invokeExact(args, opts); - } catch (Throwable ex$) { - throw new AssertionError("should not reach here", ex$); - } - } } diff --git a/jfuse-linux-amd64/src/main/java/org/cryptomator/jfuse/linux/amd64/extr/ll/Constants$root.java b/jfuse-linux-amd64/src/main/java/org/cryptomator/jfuse/linux/amd64/extr/ll/Constants$root.java deleted file mode 100644 index 1985592f..00000000 --- a/jfuse-linux-amd64/src/main/java/org/cryptomator/jfuse/linux/amd64/extr/ll/Constants$root.java +++ /dev/null @@ -1,23 +0,0 @@ -// Generated by jextract - -package org.cryptomator.jfuse.linux.amd64.extr.ll; - -import java.lang.invoke.MethodHandle; -import java.lang.invoke.VarHandle; -import java.nio.ByteOrder; -import java.lang.foreign.*; -import static java.lang.foreign.ValueLayout.*; -public class Constants$root { - - static final OfBoolean C_BOOL$LAYOUT = JAVA_BOOLEAN; - static final OfByte C_CHAR$LAYOUT = JAVA_BYTE; - static final OfShort C_SHORT$LAYOUT = JAVA_SHORT.withBitAlignment(16); - static final OfInt C_INT$LAYOUT = JAVA_INT.withBitAlignment(32); - static final OfLong C_LONG$LAYOUT = JAVA_LONG.withBitAlignment(64); - static final OfLong C_LONG_LONG$LAYOUT = JAVA_LONG.withBitAlignment(64); - static final OfFloat C_FLOAT$LAYOUT = JAVA_FLOAT.withBitAlignment(32); - static final OfDouble C_DOUBLE$LAYOUT = JAVA_DOUBLE.withBitAlignment(64); - static final OfAddress C_POINTER$LAYOUT = ADDRESS.withBitAlignment(64); -} - - diff --git a/jfuse-linux-amd64/src/main/java/org/cryptomator/jfuse/linux/amd64/extr/ll/RuntimeHelper.java b/jfuse-linux-amd64/src/main/java/org/cryptomator/jfuse/linux/amd64/extr/ll/RuntimeHelper.java deleted file mode 100644 index 626b76e3..00000000 --- a/jfuse-linux-amd64/src/main/java/org/cryptomator/jfuse/linux/amd64/extr/ll/RuntimeHelper.java +++ /dev/null @@ -1,233 +0,0 @@ -package org.cryptomator.jfuse.linux.amd64.extr.ll; -// Generated by jextract - -import java.lang.foreign.Addressable; -import java.lang.foreign.Linker; -import java.lang.foreign.FunctionDescriptor; -import java.lang.foreign.GroupLayout; -import java.lang.foreign.SymbolLookup; -import java.lang.foreign.MemoryAddress; -import java.lang.foreign.MemoryLayout; -import java.lang.foreign.MemorySegment; -import java.lang.foreign.MemorySession; -import java.lang.foreign.SegmentAllocator; -import java.lang.foreign.ValueLayout; -import java.lang.invoke.MethodHandle; -import java.lang.invoke.MethodHandles; -import java.lang.invoke.MethodType; -import java.io.File; -import java.nio.file.Path; -import java.nio.charset.StandardCharsets; -import java.util.Arrays; -import java.util.Optional; -import java.util.stream.Stream; - -import static java.lang.foreign.Linker.*; -import static java.lang.foreign.ValueLayout.*; - -final class RuntimeHelper { - - private RuntimeHelper() {} - private final static Linker LINKER = Linker.nativeLinker(); - private final static ClassLoader LOADER = RuntimeHelper.class.getClassLoader(); - private final static MethodHandles.Lookup MH_LOOKUP = MethodHandles.lookup(); - private final static SymbolLookup SYMBOL_LOOKUP; - - final static SegmentAllocator CONSTANT_ALLOCATOR = - (size, align) -> MemorySegment.allocateNative(size, align, MemorySession.openImplicit()); - - static { - - SymbolLookup loaderLookup = SymbolLookup.loaderLookup(); - SYMBOL_LOOKUP = name -> loaderLookup.lookup(name).or(() -> LINKER.defaultLookup().lookup(name)); - } - - static T requireNonNull(T obj, String symbolName) { - if (obj == null) { - throw new UnsatisfiedLinkError("unresolved symbol: " + symbolName); - } - return obj; - } - - private final static SegmentAllocator THROWING_ALLOCATOR = (x, y) -> { throw new AssertionError("should not reach here"); }; - - static final MemorySegment lookupGlobalVariable(String name, MemoryLayout layout) { - return SYMBOL_LOOKUP.lookup(name).map(symbol -> MemorySegment.ofAddress(symbol.address(), layout.byteSize(), MemorySession.openShared())).orElse(null); - } - - static final MethodHandle downcallHandle(String name, FunctionDescriptor fdesc) { - return SYMBOL_LOOKUP.lookup(name). - map(addr -> LINKER.downcallHandle(addr, fdesc)). - orElse(null); - } - - static final MethodHandle downcallHandle(FunctionDescriptor fdesc) { - return LINKER.downcallHandle(fdesc); - } - - static final MethodHandle downcallHandleVariadic(String name, FunctionDescriptor fdesc) { - return SYMBOL_LOOKUP.lookup(name). - map(addr -> VarargsInvoker.make(addr, fdesc)). - orElse(null); - } - - static final MemorySegment upcallStub(Class fi, Z z, FunctionDescriptor fdesc, MemorySession session) { - try { - MethodHandle handle = MH_LOOKUP.findVirtual(fi, "apply", Linker.upcallType(fdesc)); - handle = handle.bindTo(z); - return LINKER.upcallStub(handle, fdesc, session); - } catch (Throwable ex) { - throw new AssertionError(ex); - } - } - - static MemorySegment asArray(MemoryAddress addr, MemoryLayout layout, int numElements, MemorySession session) { - return MemorySegment.ofAddress(addr, numElements * layout.byteSize(), session); - } - - // Internals only below this point - - private static class VarargsInvoker { - private static final MethodHandle INVOKE_MH; - private final MemorySegment symbol; - private final FunctionDescriptor function; - - private VarargsInvoker(MemorySegment symbol, FunctionDescriptor function) { - this.symbol = symbol; - this.function = function; - } - - static { - try { - INVOKE_MH = MethodHandles.lookup().findVirtual(VarargsInvoker.class, "invoke", MethodType.methodType(Object.class, SegmentAllocator.class, Object[].class)); - } catch (ReflectiveOperationException e) { - throw new RuntimeException(e); - } - } - - static MethodHandle make(MemorySegment symbol, FunctionDescriptor function) { - VarargsInvoker invoker = new VarargsInvoker(symbol, function); - MethodHandle handle = INVOKE_MH.bindTo(invoker).asCollector(Object[].class, function.argumentLayouts().size() + 1); - MethodType mtype = MethodType.methodType(function.returnLayout().isPresent() ? carrier(function.returnLayout().get(), true) : void.class); - for (MemoryLayout layout : function.argumentLayouts()) { - mtype = mtype.appendParameterTypes(carrier(layout, false)); - } - mtype = mtype.appendParameterTypes(Object[].class); - if (mtype.returnType().equals(MemorySegment.class)) { - mtype = mtype.insertParameterTypes(0, SegmentAllocator.class); - } else { - handle = MethodHandles.insertArguments(handle, 0, THROWING_ALLOCATOR); - } - return handle.asType(mtype); - } - - static Class carrier(MemoryLayout layout, boolean ret) { - if (layout instanceof ValueLayout valueLayout) { - return (ret || valueLayout.carrier() != MemoryAddress.class) ? - valueLayout.carrier() : Addressable.class; - } else if (layout instanceof GroupLayout) { - return MemorySegment.class; - } else { - throw new AssertionError("Cannot get here!"); - } - } - - private Object invoke(SegmentAllocator allocator, Object[] args) throws Throwable { - // one trailing Object[] - int nNamedArgs = function.argumentLayouts().size(); - assert(args.length == nNamedArgs + 1); - // The last argument is the array of vararg collector - Object[] unnamedArgs = (Object[]) args[args.length - 1]; - - int argsCount = nNamedArgs + unnamedArgs.length; - Class[] argTypes = new Class[argsCount]; - MemoryLayout[] argLayouts = new MemoryLayout[nNamedArgs + unnamedArgs.length]; - - int pos = 0; - for (pos = 0; pos < nNamedArgs; pos++) { - argLayouts[pos] = function.argumentLayouts().get(pos); - } - - assert pos == nNamedArgs; - for (Object o: unnamedArgs) { - argLayouts[pos] = variadicLayout(normalize(o.getClass())); - pos++; - } - assert pos == argsCount; - - FunctionDescriptor f = (function.returnLayout().isEmpty()) ? - FunctionDescriptor.ofVoid(argLayouts) : - FunctionDescriptor.of(function.returnLayout().get(), argLayouts); - MethodHandle mh = LINKER.downcallHandle(symbol, f); - if (mh.type().returnType() == MemorySegment.class) { - mh = mh.bindTo(allocator); - } - // flatten argument list so that it can be passed to an asSpreader MH - Object[] allArgs = new Object[nNamedArgs + unnamedArgs.length]; - System.arraycopy(args, 0, allArgs, 0, nNamedArgs); - System.arraycopy(unnamedArgs, 0, allArgs, nNamedArgs, unnamedArgs.length); - - return mh.asSpreader(Object[].class, argsCount).invoke(allArgs); - } - - private static Class unboxIfNeeded(Class clazz) { - if (clazz == Boolean.class) { - return boolean.class; - } else if (clazz == Void.class) { - return void.class; - } else if (clazz == Byte.class) { - return byte.class; - } else if (clazz == Character.class) { - return char.class; - } else if (clazz == Short.class) { - return short.class; - } else if (clazz == Integer.class) { - return int.class; - } else if (clazz == Long.class) { - return long.class; - } else if (clazz == Float.class) { - return float.class; - } else if (clazz == Double.class) { - return double.class; - } else { - return clazz; - } - } - - private Class promote(Class c) { - if (c == byte.class || c == char.class || c == short.class || c == int.class) { - return long.class; - } else if (c == float.class) { - return double.class; - } else { - return c; - } - } - - private Class normalize(Class c) { - c = unboxIfNeeded(c); - if (c.isPrimitive()) { - return promote(c); - } - if (MemoryAddress.class.isAssignableFrom(c)) { - return MemoryAddress.class; - } - if (MemorySegment.class.isAssignableFrom(c)) { - return MemorySegment.class; - } - throw new IllegalArgumentException("Invalid type for ABI: " + c.getTypeName()); - } - - private MemoryLayout variadicLayout(Class c) { - if (c == long.class) { - return JAVA_LONG; - } else if (c == double.class) { - return JAVA_DOUBLE; - } else if (MemoryAddress.class.isAssignableFrom(c)) { - return ADDRESS; - } else { - throw new IllegalArgumentException("Unhandled variadic argument class: " + c); - } - } - } -} diff --git a/jfuse-linux-amd64/src/main/java/org/cryptomator/jfuse/linux/amd64/extr/ll/constants$0.java b/jfuse-linux-amd64/src/main/java/org/cryptomator/jfuse/linux/amd64/extr/ll/constants$0.java deleted file mode 100644 index 30f27df1..00000000 --- a/jfuse-linux-amd64/src/main/java/org/cryptomator/jfuse/linux/amd64/extr/ll/constants$0.java +++ /dev/null @@ -1,22 +0,0 @@ -// Generated by jextract - -package org.cryptomator.jfuse.linux.amd64.extr.ll; - -import java.lang.invoke.MethodHandle; -import java.lang.invoke.VarHandle; -import java.nio.ByteOrder; -import java.lang.foreign.*; -import static java.lang.foreign.ValueLayout.*; -class constants$0 { - - static final FunctionDescriptor fuse_parse_cmdline$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, - Constants$root.C_POINTER$LAYOUT, - Constants$root.C_POINTER$LAYOUT - ); - static final MethodHandle fuse_parse_cmdline$MH = RuntimeHelper.downcallHandle( - "fuse_parse_cmdline", - constants$0.fuse_parse_cmdline$FUNC - ); -} - - diff --git a/jfuse-linux-amd64/src/main/java/org/cryptomator/jfuse/linux/amd64/extr/stat_h.java b/jfuse-linux-amd64/src/main/java/org/cryptomator/jfuse/linux/amd64/extr/stat_h.java index ade9b80c..f627067c 100644 --- a/jfuse-linux-amd64/src/main/java/org/cryptomator/jfuse/linux/amd64/extr/stat_h.java +++ b/jfuse-linux-amd64/src/main/java/org/cryptomator/jfuse/linux/amd64/extr/stat_h.java @@ -24,15 +24,6 @@ public static long UTIME_NOW() { public static long UTIME_OMIT() { return 1073741822L; } - public static int S_IFDIR() { - return (int)16384L; - } - public static int S_IFREG() { - return (int)32768L; - } - public static int S_IFLNK() { - return (int)40960L; - } } diff --git a/jfuse-linux-amd64/src/test/java/org/cryptomator/jfuse/linux/amd64/FuseImplTest.java b/jfuse-linux-amd64/src/test/java/org/cryptomator/jfuse/linux/amd64/FuseImplTest.java index 590a5155..bf14492c 100644 --- a/jfuse-linux-amd64/src/test/java/org/cryptomator/jfuse/linux/amd64/FuseImplTest.java +++ b/jfuse-linux-amd64/src/test/java/org/cryptomator/jfuse/linux/amd64/FuseImplTest.java @@ -4,11 +4,10 @@ import org.cryptomator.jfuse.api.FuseOperations; import org.cryptomator.jfuse.api.MountFailedException; import org.cryptomator.jfuse.api.TimeSpec; +import org.cryptomator.jfuse.linux.amd64.extr.fuse_cmdline_opts; import org.cryptomator.jfuse.linux.amd64.extr.fuse_conn_info; import org.cryptomator.jfuse.linux.amd64.extr.fuse_file_info; import org.cryptomator.jfuse.linux.amd64.extr.fuse_h; -import org.cryptomator.jfuse.linux.amd64.extr.ll.fuse_cmdline_opts; -import org.cryptomator.jfuse.linux.amd64.extr.ll.fuse_lowlevel_h; import org.cryptomator.jfuse.linux.amd64.extr.timespec; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.Assertions; @@ -83,9 +82,9 @@ public void testFuseMountFails() { @ValueSource(strings = {"--help", "-h"}) public void testParseArgsHelp(String arg) { var args = List.of("fusefs", arg); - try (var fuseLowlevelH = Mockito.mockStatic(fuse_lowlevel_h.class); + try (var fuseFunctionsClass = Mockito.mockStatic(FuseFunctions.class); var fuseH = Mockito.mockStatic(fuse_h.class)) { - fuseLowlevelH.when(() -> fuse_lowlevel_h.fuse_parse_cmdline(Mockito.any(), Mockito.any())).then(invocation -> { + fuseFunctionsClass.when(() -> FuseFunctions.fuse_parse_cmdline(Mockito.any(), Mockito.any())).then(invocation -> { MemorySegment opts = invocation.getArgument(1); fuse_cmdline_opts.show_help$set(opts, 1); return 0; @@ -100,9 +99,9 @@ public void testParseArgsHelp(String arg) { @Test @DisplayName("parseArgs") public void testParseArgs() { - try (var fuseLowlevelH = Mockito.mockStatic(fuse_lowlevel_h.class); + try (var fuseFunctionsClass = Mockito.mockStatic(FuseFunctions.class); var scope = MemorySession.openConfined()) { - fuseLowlevelH.when(() -> fuse_lowlevel_h.fuse_parse_cmdline(Mockito.any(), Mockito.any())).then(invocation -> { + fuseFunctionsClass.when(() -> FuseFunctions.fuse_parse_cmdline(Mockito.any(), Mockito.any())).then(invocation -> { MemorySegment opts = invocation.getArgument(1); fuse_cmdline_opts.singlethread$set(opts, 0); fuse_cmdline_opts.debug$set(opts, 1); diff --git a/jfuse-linux-amd64/src/test/java/org/cryptomator/jfuse/linux/amd64/FuseMountImplTest.java b/jfuse-linux-amd64/src/test/java/org/cryptomator/jfuse/linux/amd64/FuseMountImplTest.java new file mode 100644 index 00000000..7d836a51 --- /dev/null +++ b/jfuse-linux-amd64/src/test/java/org/cryptomator/jfuse/linux/amd64/FuseMountImplTest.java @@ -0,0 +1,88 @@ +package org.cryptomator.jfuse.linux.amd64; + +import org.cryptomator.jfuse.linux.amd64.extr.fuse_h; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.ValueSource; +import org.mockito.MockedStatic; +import org.mockito.Mockito; + +import java.lang.foreign.MemoryAddress; + +public class FuseMountImplTest { + + private MockedStatic fuseH; + private FuseArgs fuseArgs = Mockito.mock(FuseArgs.class); + private MemoryAddress fuse = MemoryAddress.ofLong(42L); + private FuseMountImpl fuseMount = new FuseMountImpl(fuse, fuseArgs); + + @BeforeEach + public void setup() { + this.fuseH = Mockito.mockStatic(fuse_h.class); + Mockito.doReturn(1).when(fuseArgs).cloneFd(); + Mockito.doReturn(2).when(fuseArgs).maxIdleThreads(); + Mockito.doReturn(3).when(fuseArgs).maxThreads(); + } + + @AfterEach + public void teardown() { + this.fuseH.close(); + } + + @Test + @DisplayName("mounting singlethreaded calls fuse_loop") + public void testLoopSingleThreaded() { + Mockito.doReturn(false).when(fuseArgs).multithreaded(); + + fuseMount.loop(); + + fuseH.verify(() -> fuse_h.fuse_loop(fuse)); + fuseH.verify(() -> fuse_h.fuse_loop_mt(Mockito.any(), Mockito.any()), Mockito.never()); + } + + @Test + @DisplayName("FUSE 3.1 calls fuse_loop") + public void testLoopMultiThreaded31() { + Mockito.doReturn(true).when(fuseArgs).multithreaded(); + fuseH.when(fuse_h::fuse_version).thenReturn(31); + + fuseMount.loop(); + + fuseH.verify(() -> fuse_h.fuse_loop(fuse)); + fuseH.verify(() -> fuse_h.fuse_loop_mt(Mockito.any(), Mockito.any()), Mockito.never()); + } + + @ParameterizedTest(name = "fuse_version() = {0}") + @ValueSource(ints = {32, 35, 310, 311}) + @DisplayName("FUSE 3.2 - 3.11 calls fuse_loop_mt") + public void testLoopMultiThreaded32(int fuseVersion) { + Mockito.doReturn(true).when(fuseArgs).multithreaded(); + fuseH.when(fuse_h::fuse_version).thenReturn(fuseVersion); + + fuseMount.loop(); + + fuseH.verify(() -> fuse_h.fuse_loop_mt(Mockito.eq(fuse), Mockito.any())); + fuseH.verify(() -> fuse_h.fuse_loop(Mockito.any()), Mockito.never()); + } + + @Test + @DisplayName("FUSE 3.12 calls fuse_loop_mt") + public void testLoopMultiThreaded312() { + var loopCfg = MemoryAddress.ofLong(1337L); + Mockito.doReturn(true).when(fuseArgs).multithreaded(); + fuseH.when(fuse_h::fuse_version).thenReturn(312); + fuseH.when(fuse_h::fuse_loop_cfg_create).thenReturn(loopCfg); + + fuseMount.loop(); + + fuseH.verify(() -> fuse_h.fuse_loop_cfg_set_clone_fd(loopCfg, 1)); + fuseH.verify(() -> fuse_h.fuse_loop_cfg_set_max_threads(loopCfg, 3)); + fuseH.verify(() -> fuse_h.fuse_loop_mt(fuse, loopCfg)); + fuseH.verify(() -> fuse_h.fuse_loop(Mockito.any()), Mockito.never()); + fuseH.verify(() -> fuse_h.fuse_loop_cfg_destroy(loopCfg)); + } + +} \ No newline at end of file diff --git a/jfuse-mac/pom.xml b/jfuse-mac/pom.xml index 0b24fae9..b83fe0a4 100644 --- a/jfuse-mac/pom.xml +++ b/jfuse-mac/pom.xml @@ -5,7 +5,7 @@ org.cryptomator jfuse - 0.2.0 + 0.2.1 4.0.0 jfuse-mac diff --git a/jfuse-tests/pom.xml b/jfuse-tests/pom.xml index f995dbad..033974ea 100644 --- a/jfuse-tests/pom.xml +++ b/jfuse-tests/pom.xml @@ -5,7 +5,7 @@ org.cryptomator jfuse - 0.2.0 + 0.2.1 4.0.0 jfuse-tests @@ -37,19 +37,19 @@ org.slf4j slf4j-simple - 2.0.0-alpha6 + 2.0.3 test org.openjdk.jmh jmh-core - 1.34 + 1.35 test org.openjdk.jmh jmh-generator-annprocess - 1.34 + 1.35 test @@ -146,8 +146,8 @@ unix - Linux - x86_64 + linux + amd64 @@ -164,7 +164,7 @@ unix - Linux + linux aarch64 diff --git a/jfuse-tests/src/test/java/org/cryptomator/jfuse/tests/MirrorIT.java b/jfuse-tests/src/test/java/org/cryptomator/jfuse/tests/MirrorIT.java index 2484dda6..cdcce2cc 100644 --- a/jfuse-tests/src/test/java/org/cryptomator/jfuse/tests/MirrorIT.java +++ b/jfuse-tests/src/test/java/org/cryptomator/jfuse/tests/MirrorIT.java @@ -1,6 +1,7 @@ package org.cryptomator.jfuse.tests; import org.cryptomator.jfuse.api.Fuse; +import org.cryptomator.jfuse.api.FuseBuilder; import org.cryptomator.jfuse.api.MountFailedException; import org.cryptomator.jfuse.examples.AbstractMirrorFileSystem; import org.cryptomator.jfuse.examples.PosixMirrorFileSystem; @@ -16,6 +17,7 @@ import org.junit.jupiter.api.Test; import org.junit.jupiter.api.TestInstance; import org.junit.jupiter.api.TestMethodOrder; +import org.junit.jupiter.api.condition.EnabledIf; import org.junit.jupiter.api.condition.OS; import org.junit.jupiter.api.io.TempDir; import org.junit.jupiter.params.ParameterizedTest; @@ -32,6 +34,7 @@ import java.util.List; import java.util.concurrent.TimeUnit; +@EnabledIf("hasSupportedImplementation") @TestInstance(TestInstance.Lifecycle.PER_CLASS) public class MirrorIT { @@ -39,6 +42,16 @@ public class MirrorIT { System.setProperty("org.slf4j.simpleLogger.defaultLogLevel", "TRACE"); } + // skip integration tests, if no implementation is available + static boolean hasSupportedImplementation() { + try { + FuseBuilder.getSupported(); + return true; + } catch (UnsupportedOperationException e) { + return false; + } + } + private Path orig; private Path mirror; private Fuse fuse; diff --git a/jfuse-win-amd64/pom.xml b/jfuse-win-amd64/pom.xml index f5dd7a61..12cee739 100644 --- a/jfuse-win-amd64/pom.xml +++ b/jfuse-win-amd64/pom.xml @@ -5,7 +5,7 @@ org.cryptomator jfuse - 0.2.0 + 0.2.1 4.0.0 jfuse-win-amd64 @@ -92,7 +92,7 @@ fuse_h WINFSP_DLL_INTERNAL - FUSE_USE_VERSION=32 + FUSE_USE_VERSION=31 fuse3_lib_help diff --git a/jfuse-win-amd64/src/main/java/org/cryptomator/jfuse/win/amd64/FuseImpl.java b/jfuse-win-amd64/src/main/java/org/cryptomator/jfuse/win/amd64/FuseImpl.java index 37ff1703..f84a891b 100644 --- a/jfuse-win-amd64/src/main/java/org/cryptomator/jfuse/win/amd64/FuseImpl.java +++ b/jfuse-win-amd64/src/main/java/org/cryptomator/jfuse/win/amd64/FuseImpl.java @@ -259,20 +259,13 @@ private int unlink(MemoryAddress path) { @VisibleForTesting int utimens(MemoryAddress path, MemoryAddress times, MemoryAddress fi) { try (var scope = MemorySession.openConfined()) { - if (MemoryAddress.NULL.equals(times)) { - // set both times to current time (using on-heap memory segments) - var segment = MemorySegment.allocateNative(fuse_timespec.$LAYOUT().byteSize(), scope); - fuse_timespec.tv_sec$set(segment, 0); - fuse_timespec.tv_nsec$set(segment, 0); //FIXME: use hardcoded UTIME_NOW - var time = new TimeSpecImpl(segment); - return delegate.utimens(path.getUtf8String(0), time, time, new FileInfoImpl(fi, scope)); - } else { - var seq = MemoryLayout.sequenceLayout(2, fuse_timespec.$LAYOUT()); - var segment = MemorySegment.ofAddress(times, seq.byteSize(), scope); - var time0 = segment.asSlice(0, fuse_timespec.$LAYOUT().byteSize()); - var time1 = segment.asSlice(fuse_timespec.$LAYOUT().byteSize(), fuse_timespec.$LAYOUT().byteSize()); - return delegate.utimens(path.getUtf8String(0), new TimeSpecImpl(time0), new TimeSpecImpl(time1), new FileInfoImpl(fi, scope)); - } + // On Windows we know for sure that WinFSP will call this function only with + // valid times: https://github.com/winfsp/winfsp/discussions/445 + var seq = MemoryLayout.sequenceLayout(2, fuse_timespec.$LAYOUT()); + var segment = MemorySegment.ofAddress(times, seq.byteSize(), scope); + var time0 = segment.asSlice(0, fuse_timespec.$LAYOUT().byteSize()); + var time1 = segment.asSlice(fuse_timespec.$LAYOUT().byteSize(), fuse_timespec.$LAYOUT().byteSize()); + return delegate.utimens(path.getUtf8String(0), new TimeSpecImpl(time0), new TimeSpecImpl(time1), new FileInfoImpl(fi, scope)); } } diff --git a/jfuse-win-amd64/src/test/java/org/cryptomator/jfuse/win/amd64/FuseImplTest.java b/jfuse-win-amd64/src/test/java/org/cryptomator/jfuse/win/amd64/FuseImplTest.java index fad54afc..8942bfd3 100644 --- a/jfuse-win-amd64/src/test/java/org/cryptomator/jfuse/win/amd64/FuseImplTest.java +++ b/jfuse-win-amd64/src/test/java/org/cryptomator/jfuse/win/amd64/FuseImplTest.java @@ -188,48 +188,28 @@ public void testInit() { } } - @Nested - @DisplayName("utimens") - public class Utimens { - - @DisplayName("utimens(\"/foo\", UTIME_NOW, UTIME_NOW)") - @Test - public void testUtimensNow() { - try (var scope = MemorySession.openConfined()) { - var path = scope.allocateUtf8String("/foo"); - var times = MemoryAddress.NULL; - var fi = scope.allocate(fuse3_file_info.$LAYOUT()); - Mockito.doReturn(42).when(fuseOps).utimens(Mockito.eq("/foo"), Mockito.argThat(t -> t.get().getNano() == 0L), Mockito.argThat(t -> t.get().getNano() == 0L), Mockito.argThat(usesSameMemorySegement(fi))); - - var result = fuseImpl.utimens(path.address(), times, fi.address()); + @DisplayName("utimens(\"/foo\", ...)") + @ParameterizedTest + @CsvSource(value = { + "123456,789, 456789,123", + "111222,333, 444555,666", + }) + public void testUtimens(long sec0, long nsec0, long sec1, long nsec1) { + Instant expectedATime = Instant.ofEpochSecond(sec0, nsec0); + Instant expectedMTime = Instant.ofEpochSecond(sec1, nsec1); + try (var scope = MemorySession.openConfined()) { + var path = scope.allocateUtf8String("/foo"); + var times = fuse_timespec.allocateArray(2, scope); + var fi = scope.allocate(fuse3_file_info.$LAYOUT()); + fuse_timespec.tv_sec$set(times, 0, sec0); + fuse_timespec.tv_nsec$set(times, 0, nsec0); + fuse_timespec.tv_sec$set(times, 1, sec1); + fuse_timespec.tv_nsec$set(times, 1, nsec1); + Mockito.doReturn(42).when(fuseOps).utimens(Mockito.eq("/foo"), Mockito.argThat(t -> expectedATime.equals(t.get())), Mockito.argThat(t -> expectedMTime.equals(t.get())), Mockito.argThat(usesSameMemorySegement(fi))); - Assertions.assertEquals(42, result); - } - } + var result = fuseImpl.utimens(path.address(), times.address(), fi.address()); - @DisplayName("utimens(\"/foo\", ...)") - @ParameterizedTest - @CsvSource(value = { - "123456,789, 456789,123", - "111222,333, 444555,666", - }) - public void testUtimens(long sec0, long nsec0, long sec1, long nsec1) { - Instant expectedATime = Instant.ofEpochSecond(sec0, nsec0); - Instant expectedMTime = Instant.ofEpochSecond(sec1, nsec1); - try (var scope = MemorySession.openConfined()) { - var path = scope.allocateUtf8String("/foo"); - var times = fuse_timespec.allocateArray(2, scope); - var fi = scope.allocate(fuse3_file_info.$LAYOUT()); - fuse_timespec.tv_sec$set(times, 0, sec0); - fuse_timespec.tv_nsec$set(times, 0, nsec0); - fuse_timespec.tv_sec$set(times, 1, sec1); - fuse_timespec.tv_nsec$set(times, 1, nsec1); - Mockito.doReturn(42).when(fuseOps).utimens(Mockito.eq("/foo"), Mockito.argThat(t -> expectedATime.equals(t.get())), Mockito.argThat(t -> expectedMTime.equals(t.get())), Mockito.argThat(usesSameMemorySegement(fi))); - - var result = fuseImpl.utimens(path.address(), times.address(), fi.address()); - - Assertions.assertEquals(42, result); - } + Assertions.assertEquals(42, result); } } diff --git a/libfuse3 b/libfuse3 index 7657ec15..b1290d4c 160000 --- a/libfuse3 +++ b/libfuse3 @@ -1 +1 @@ -Subproject commit 7657ec158becdc59656c59dff40346fefde78cb2 +Subproject commit b1290d4c091a5c590e61a6195e625eab33300673 diff --git a/pom.xml b/pom.xml index 6d2a3207..99bf238d 100644 --- a/pom.xml +++ b/pom.xml @@ -6,7 +6,7 @@ org.cryptomator jfuse pom - 0.2.0 + 0.2.1 jFUSE Java bindings for FUSE using foreign functions & memory API https://github.com/cryptomator/jfuse @@ -210,7 +210,7 @@ unix linux - x86_64 + amd64