From 85b296c1d361d3756b6fa842b2827fe63700e535 Mon Sep 17 00:00:00 2001 From: Julian Raufelder Date: Fri, 30 Sep 2022 12:30:03 +0200 Subject: [PATCH 01/12] Fixes for libfuse v3.12 --- .../jfuse/linux/amd64/FuseSymbolLookup.java | 108 ++++++++++++++++++ .../jfuse/linux/amd64/LinuxFuseBuilder.java | 7 +- .../jfuse/linux/amd64/extr/RuntimeHelper.java | 14 +-- .../jfuse/linux/amd64/extr/constants$0.java | 8 +- .../jfuse/linux/amd64/extr/constants$1.java | 10 +- .../linux/amd64/extr/ll/RuntimeHelper.java | 14 +-- .../linux/amd64/extr/ll/constants$0.java | 2 +- .../org/cryptomator/jfuse/tests/MirrorIT.java | 2 +- 8 files changed, 134 insertions(+), 31 deletions(-) create mode 100644 jfuse-linux-amd64/src/main/java/org/cryptomator/jfuse/linux/amd64/FuseSymbolLookup.java diff --git a/jfuse-linux-amd64/src/main/java/org/cryptomator/jfuse/linux/amd64/FuseSymbolLookup.java b/jfuse-linux-amd64/src/main/java/org/cryptomator/jfuse/linux/amd64/FuseSymbolLookup.java new file mode 100644 index 00000000..7c6c1611 --- /dev/null +++ b/jfuse-linux-amd64/src/main/java/org/cryptomator/jfuse/linux/amd64/FuseSymbolLookup.java @@ -0,0 +1,108 @@ +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.MemoryAddress; +import java.lang.foreign.MemorySegment; +import java.lang.foreign.MemorySession; +import java.lang.foreign.SymbolLookup; +import java.lang.invoke.MethodHandle; +import java.util.Optional; +import java.util.concurrent.atomic.AtomicReference; + +import static java.lang.foreign.ValueLayout.ADDRESS; +import static java.lang.foreign.ValueLayout.JAVA_INT; + +public class FuseSymbolLookup implements SymbolLookup { + + private static final int RTLD_NOW = 0x02; + + // https://man7.org/linux/man-pages/man3/dlopen.3.html + private static final FunctionDescriptor DLOPEN = FunctionDescriptor.of(ADDRESS, ADDRESS, JAVA_INT); + private static final FunctionDescriptor DLCLOSE = FunctionDescriptor.of(JAVA_INT, ADDRESS); + private static final FunctionDescriptor DLERROR = FunctionDescriptor.of(ADDRESS); + + // https://man7.org/linux/man-pages/man3/dlvsym.3.html + private static final FunctionDescriptor DLVSYM = FunctionDescriptor.of(ADDRESS, ADDRESS, ADDRESS, ADDRESS); + private static final FunctionDescriptor DLSYM = FunctionDescriptor.of(ADDRESS, ADDRESS, ADDRESS); + + private final Linker linker = Linker.nativeLinker(); + private final MethodHandle dlopen; + private final MethodHandle dlclose; + private final MethodHandle dlerror; + private final MethodHandle dlvsym; + private final MethodHandle dlsym; + private final AtomicReference libHandle = new AtomicReference<>(); + + private FuseSymbolLookup() { + this.dlopen = linker.downcallHandle(linker.defaultLookup().lookup("dlopen").orElseThrow(() -> new UnsatisfiedLinkError("unresolved symbol dlopen")), DLOPEN); + this.dlclose = linker.downcallHandle(linker.defaultLookup().lookup("dlclose").orElseThrow(() -> new UnsatisfiedLinkError("unresolved symbol dlclose")), DLCLOSE); + this.dlerror = linker.downcallHandle(linker.defaultLookup().lookup("dlerror").orElseThrow(() -> new UnsatisfiedLinkError("unresolved symbol dlerror")), DLERROR); + this.dlvsym = linker.downcallHandle(linker.defaultLookup().lookup("dlvsym").orElseThrow(() -> new UnsatisfiedLinkError("unresolved symbol dlvsym")), DLVSYM); + this.dlsym = linker.downcallHandle(linker.defaultLookup().lookup("dlsym").orElseThrow(() -> new UnsatisfiedLinkError("unresolved symbol dlsym")), DLSYM); + } + + public static FuseSymbolLookup getInstance() { + return Holder.INSTANCE; + } + + private static class Holder { + private static final FuseSymbolLookup INSTANCE = new FuseSymbolLookup(); + } + + public void open(String libPath, MemorySession session) { + try { + MemoryAddress handle = (MemoryAddress) dlopen.invokeExact((Addressable) session.allocateUtf8String(libPath), RTLD_NOW); + libHandle.set(handle); + session.addCloseAction(this::close); + } catch (Throwable e) { + throw new AssertionError(e); + } + } + + private void close() { + try { + dlclose.invokeExact((Addressable) libHandle.getAndSet(null)); + } catch (Throwable e) { + throw new RuntimeException(e); + } + } + + /** + * {@inheritDoc} + * + * @param nameAndVersion the symbol name and version separated by '@'. + */ + @Override + public Optional lookup(String nameAndVersion) { + var handle = libHandle.get(); + if (handle == null) { + return Optional.empty(); + } + var sep = nameAndVersion.indexOf('@'); + try (var session = MemorySession.openConfined()) { + MemoryAddress addr = MemoryAddress.NULL; + if(sep != -1) { + String name = nameAndVersion.substring(0, sep); + String version = nameAndVersion.substring(sep + 1); + addr = (MemoryAddress) dlvsym.invokeExact((Addressable) handle, (Addressable) session.allocateUtf8String(name),(Addressable) session.allocateUtf8String(version)); + } + + if(MemoryAddress.NULL.equals(addr)) { + addr = (MemoryAddress) dlsym.invokeExact((Addressable) handle, (Addressable) session.allocateUtf8String(nameAndVersion)); + } + + if (MemoryAddress.NULL.equals(addr)) { + var error = (MemoryAddress) dlerror.invokeExact(); + System.err.println("dlvsym failed for symbol " + nameAndVersion + ": " + error.getUtf8String(0)); + return Optional.empty(); + } else { + return Optional.of(MemorySegment.ofAddress(addr, 0, MemorySession.global())); + } + } catch (Throwable e) { + return Optional.empty(); + } + } + +} \ No newline at end of file diff --git a/jfuse-linux-amd64/src/main/java/org/cryptomator/jfuse/linux/amd64/LinuxFuseBuilder.java b/jfuse-linux-amd64/src/main/java/org/cryptomator/jfuse/linux/amd64/LinuxFuseBuilder.java index b9dd262e..edc2e370 100644 --- a/jfuse-linux-amd64/src/main/java/org/cryptomator/jfuse/linux/amd64/LinuxFuseBuilder.java +++ b/jfuse-linux-amd64/src/main/java/org/cryptomator/jfuse/linux/amd64/LinuxFuseBuilder.java @@ -8,6 +8,8 @@ import org.cryptomator.jfuse.api.OperatingSystem; import org.cryptomator.jfuse.api.SupportedPlatform; +import java.lang.foreign.MemorySession; + @SupportedPlatform(os = OperatingSystem.LINUX, arch = Architecture.AMD64) public class LinuxFuseBuilder implements FuseBuilder { @@ -27,11 +29,12 @@ public void setLibraryPath(String libraryPath) { @Override public Fuse build(FuseOperations fuseOperations) throws UnsatisfiedLinkError { - if (libraryPath != null) { + FuseSymbolLookup.getInstance().open(libraryPath, MemorySession.global()); + /*if (libraryPath != null) { System.load(libraryPath); } else { System.load(DEFAULT_LIB_PATH); - } + }*/ return new FuseImpl(fuseOperations); } diff --git a/jfuse-linux-amd64/src/main/java/org/cryptomator/jfuse/linux/amd64/extr/RuntimeHelper.java b/jfuse-linux-amd64/src/main/java/org/cryptomator/jfuse/linux/amd64/extr/RuntimeHelper.java index 55cd717c..ec67a6d4 100644 --- a/jfuse-linux-amd64/src/main/java/org/cryptomator/jfuse/linux/amd64/extr/RuntimeHelper.java +++ b/jfuse-linux-amd64/src/main/java/org/cryptomator/jfuse/linux/amd64/extr/RuntimeHelper.java @@ -1,6 +1,8 @@ package org.cryptomator.jfuse.linux.amd64.extr; // Generated by jextract +import org.cryptomator.jfuse.linux.amd64.FuseSymbolLookup; + import java.lang.foreign.Addressable; import java.lang.foreign.Linker; import java.lang.foreign.FunctionDescriptor; @@ -15,14 +17,7 @@ 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 { @@ -39,7 +34,8 @@ private RuntimeHelper() {} static { SymbolLookup loaderLookup = SymbolLookup.loaderLookup(); - SYMBOL_LOOKUP = name -> loaderLookup.lookup(name).or(() -> LINKER.defaultLookup().lookup(name)); + //SYMBOL_LOOKUP = name -> loaderLookup.lookup(name).or(() -> LINKER.defaultLookup().lookup(name)); + SYMBOL_LOOKUP = FuseSymbolLookup.getInstance(); } static T requireNonNull(T obj, String symbolName) { 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..d4bf03bc 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 @@ -23,7 +23,7 @@ class constants$0 { Constants$root.C_POINTER$LAYOUT ); static final MethodHandle fuse_lib_help$MH = RuntimeHelper.downcallHandle( - "fuse_lib_help", + "fuse_lib_help@FUSE_3.1", constants$0.fuse_lib_help$FUNC ); static final FunctionDescriptor fuse_new$FUNC = FunctionDescriptor.of(Constants$root.C_POINTER$LAYOUT, @@ -33,7 +33,7 @@ class constants$0 { Constants$root.C_POINTER$LAYOUT ); static final MethodHandle fuse_new$MH = RuntimeHelper.downcallHandle( - "fuse_new", + "fuse_new@FUSE_3.1", constants$0.fuse_new$FUNC ); static final FunctionDescriptor fuse_mount$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, @@ -41,14 +41,14 @@ class constants$0 { Constants$root.C_POINTER$LAYOUT ); static final MethodHandle fuse_mount$MH = RuntimeHelper.downcallHandle( - "fuse_mount", + "fuse_mount@FUSE_3.0", constants$0.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", + "fuse_unmount@FUSE_3.0", constants$0.fuse_unmount$FUNC ); } 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..29ec16ad 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 @@ -13,21 +13,21 @@ class constants$1 { Constants$root.C_POINTER$LAYOUT ); static final MethodHandle fuse_destroy$MH = RuntimeHelper.downcallHandle( - "fuse_destroy", + "fuse_destroy@FUSE_3.0", constants$1.fuse_destroy$FUNC ); 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", + "fuse_loop@FUSE_3.0", constants$1.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", + "fuse_exit@FUSE_3.0", constants$1.fuse_exit$FUNC ); static final FunctionDescriptor fuse_loop_mt$FUNC = FunctionDescriptor.of(Constants$root.C_INT$LAYOUT, @@ -35,14 +35,14 @@ class constants$1 { Constants$root.C_POINTER$LAYOUT ); static final MethodHandle fuse_loop_mt$MH = RuntimeHelper.downcallHandle( - "fuse_loop_mt", + "fuse_loop_mt@FUSE_3.2", constants$1.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", + "fuse_get_session@FUSE_3.0", constants$1.fuse_get_session$FUNC ); } 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 index 626b76e3..2e90a3f3 100644 --- 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 @@ -1,6 +1,8 @@ package org.cryptomator.jfuse.linux.amd64.extr.ll; // Generated by jextract +import org.cryptomator.jfuse.linux.amd64.FuseSymbolLookup; + import java.lang.foreign.Addressable; import java.lang.foreign.Linker; import java.lang.foreign.FunctionDescriptor; @@ -15,14 +17,7 @@ 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 { @@ -39,7 +34,8 @@ private RuntimeHelper() {} static { SymbolLookup loaderLookup = SymbolLookup.loaderLookup(); - SYMBOL_LOOKUP = name -> loaderLookup.lookup(name).or(() -> LINKER.defaultLookup().lookup(name)); + //SYMBOL_LOOKUP = name -> loaderLookup.lookup(name).or(() -> LINKER.defaultLookup().lookup(name)); + SYMBOL_LOOKUP = FuseSymbolLookup.getInstance(); } static T requireNonNull(T obj, String symbolName) { 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 index 30f27df1..c7e1da3b 100644 --- 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 @@ -14,7 +14,7 @@ class constants$0 { Constants$root.C_POINTER$LAYOUT ); static final MethodHandle fuse_parse_cmdline$MH = RuntimeHelper.downcallHandle( - "fuse_parse_cmdline", + "fuse_parse_cmdline@FUSE_3.0", constants$0.fuse_parse_cmdline$FUNC ); } 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..a97f62c0 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 @@ -50,7 +50,7 @@ public void setup(@TempDir Path tmpDir) throws IOException, InterruptedException Files.createDirectories(orig); AbstractMirrorFileSystem fs; List flags = new ArrayList<>(); - flags.add("-s"); + //flags.add("-s"); mirror = tmpDir.resolve("mirror"); if (OS.WINDOWS.isCurrentOs()) { flags.add("-ouid=-1"); From 53b7bc631ffc14595be1d1fe9ac9ac2f4a7fc85b Mon Sep 17 00:00:00 2001 From: Sebastian Stenzel Date: Sat, 5 Apr 2025 13:11:51 +0200 Subject: [PATCH 02/12] avoid NPE if libraryPath is not set --- .../org/cryptomator/jfuse/linux/amd64/LinuxFuseBuilder.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/jfuse-linux-amd64/src/main/java/org/cryptomator/jfuse/linux/amd64/LinuxFuseBuilder.java b/jfuse-linux-amd64/src/main/java/org/cryptomator/jfuse/linux/amd64/LinuxFuseBuilder.java index f09118b9..5b4cea90 100644 --- a/jfuse-linux-amd64/src/main/java/org/cryptomator/jfuse/linux/amd64/LinuxFuseBuilder.java +++ b/jfuse-linux-amd64/src/main/java/org/cryptomator/jfuse/linux/amd64/LinuxFuseBuilder.java @@ -36,8 +36,8 @@ public void setLibraryPath(String libraryPath) { @Override public Fuse build(FuseOperations fuseOperations) throws UnsatisfiedLinkError { - FuseSymbolLookup.getInstance().open(libraryPath); if (libraryPath != null) { + FuseSymbolLookup.getInstance().open(libraryPath); System.load(libraryPath); } else { System.loadLibrary(DEFAULT_LIBNAME); From ef28e029ec0298a43731ab479ad26b72b259202e Mon Sep 17 00:00:00 2001 From: Sebastian Stenzel Date: Sat, 5 Apr 2025 14:55:50 +0200 Subject: [PATCH 03/12] try linking to `fuse_new@FUSE_3.0` --- .../jfuse/linux/aarch64/FuseFFIHelper.java | 37 ++------ .../jfuse/linux/aarch64/FuseImpl.java | 2 +- .../jfuse/linux/aarch64/FuseSymbolLookup.java | 95 +++++++++++++++++++ .../jfuse/linux/aarch64/FuseImplTest.java | 7 +- .../jfuse/linux/amd64/FuseFFIHelper.java | 38 ++------ .../jfuse/linux/amd64/FuseImpl.java | 2 +- .../jfuse/linux/amd64/FuseSymbolLookup.java | 6 +- .../jfuse/linux/amd64/FuseImplTest.java | 2 +- 8 files changed, 115 insertions(+), 74 deletions(-) create mode 100644 jfuse-linux-aarch64/src/main/java/org/cryptomator/jfuse/linux/aarch64/FuseSymbolLookup.java diff --git a/jfuse-linux-aarch64/src/main/java/org/cryptomator/jfuse/linux/aarch64/FuseFFIHelper.java b/jfuse-linux-aarch64/src/main/java/org/cryptomator/jfuse/linux/aarch64/FuseFFIHelper.java index 858df5ae..3f60cbf1 100644 --- a/jfuse-linux-aarch64/src/main/java/org/cryptomator/jfuse/linux/aarch64/FuseFFIHelper.java +++ b/jfuse-linux-aarch64/src/main/java/org/cryptomator/jfuse/linux/aarch64/FuseFFIHelper.java @@ -5,24 +5,20 @@ import java.lang.foreign.FunctionDescriptor; import java.lang.foreign.Linker; import java.lang.foreign.MemorySegment; -import java.lang.foreign.SymbolLookup; import java.lang.invoke.MethodHandle; /** - * Class for not jextract'able symbols, e.g. fuse_new_31 + * Class for not jextract'able versioned symbols, e.g. fuse_new@FUSE_3.0 */ public class FuseFFIHelper { - static final SymbolLookup SYMBOL_LOOKUP = SymbolLookup.loaderLookup() - .or(Linker.nativeLinker().defaultLookup()); - static MemorySegment findOrThrow(String symbol) { - return SYMBOL_LOOKUP.find(symbol) + return FuseSymbolLookup.getInstance().find(symbol) .orElseThrow(() -> new UnsatisfiedLinkError("unresolved symbol: " + symbol)); } - private static class fuse_new_31 { + private static class fuse_new { public static final FunctionDescriptor DESC = FunctionDescriptor.of( fuse_h.C_POINTER, fuse_h.C_POINTER, @@ -32,38 +28,17 @@ private static class fuse_new_31 { ); public static final MethodHandle HANDLE = Linker.nativeLinker().downcallHandle( - findOrThrow("fuse_new_31"), + findOrThrow("fuse_new@FUSE_3.0"), DESC); } - /** - * Function descriptor for: - * {@snippet lang = c: - * struct fuse *fuse_new(struct fuse_args *args, const struct fuse_operations *op, size_t op_size, void *private_data) - *} - */ - public static FunctionDescriptor fuse_new_31$descriptor() { - return fuse_new_31.DESC; - } - - - /** - * Downcall method handle for: - * {@snippet lang = c: - * struct fuse *fuse_new(struct fuse_args *args, const struct fuse_operations *op, size_t op_size, void *private_data) - *} - */ - public static MethodHandle fuse_new_31$handle() { - return fuse_new_31.HANDLE; - } - /** * {@snippet lang = c: * struct fuse *fuse_new(struct fuse_args *args, const struct fuse_operations *op, size_t op_size, void *private_data) *} */ - public static MemorySegment fuse_new_31(MemorySegment args, MemorySegment op, long op_size, MemorySegment private_data) { - var mh$ = fuse_new_31.HANDLE; + public static MemorySegment fuse_new(MemorySegment args, MemorySegment op, long op_size, MemorySegment private_data) { + var mh$ = fuse_new.HANDLE; try { return (MemorySegment) mh$.invokeExact(args, op, op_size, private_data); } catch (Throwable ex$) { 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 46107004..be6eb47d 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 @@ -37,7 +37,7 @@ protected FuseMount mount(List args) throws FuseMountFailedException { @VisibleForTesting MemorySegment createFuseFS(FuseArgs fuseArgs) throws FuseMountFailedException { - var fuse = FuseFFIHelper.fuse_new_31(fuseArgs.args(), fuseOperationsStruct, fuseOperationsStruct.byteSize(), MemorySegment.NULL); + var fuse = FuseFFIHelper.fuse_new(fuseArgs.args(), fuseOperationsStruct, fuseOperationsStruct.byteSize(), MemorySegment.NULL); if (MemorySegment.NULL.equals(fuse)) { throw new FuseMountFailedException("fuse_new failed"); } diff --git a/jfuse-linux-aarch64/src/main/java/org/cryptomator/jfuse/linux/aarch64/FuseSymbolLookup.java b/jfuse-linux-aarch64/src/main/java/org/cryptomator/jfuse/linux/aarch64/FuseSymbolLookup.java new file mode 100644 index 00000000..36e1a22f --- /dev/null +++ b/jfuse-linux-aarch64/src/main/java/org/cryptomator/jfuse/linux/aarch64/FuseSymbolLookup.java @@ -0,0 +1,95 @@ +package org.cryptomator.jfuse.linux.aarch64; + +import java.lang.foreign.Arena; +import java.lang.foreign.FunctionDescriptor; +import java.lang.foreign.Linker; +import java.lang.foreign.MemorySegment; +import java.lang.foreign.SymbolLookup; +import java.lang.invoke.MethodHandle; +import java.util.Optional; +import java.util.concurrent.atomic.AtomicReference; + +import static java.lang.foreign.ValueLayout.ADDRESS; +import static java.lang.foreign.ValueLayout.JAVA_INT; + +public class FuseSymbolLookup implements SymbolLookup { + + private static final int RTLD_NOW = 0x02; + + // https://man7.org/linux/man-pages/man3/dlopen.3.html + private static final FunctionDescriptor DLOPEN = FunctionDescriptor.of(ADDRESS, ADDRESS, JAVA_INT); + private static final FunctionDescriptor DLCLOSE = FunctionDescriptor.of(JAVA_INT, ADDRESS); + private static final FunctionDescriptor DLERROR = FunctionDescriptor.of(ADDRESS); + + // https://man7.org/linux/man-pages/man3/dlvsym.3.html + private static final FunctionDescriptor DLVSYM = FunctionDescriptor.of(ADDRESS, ADDRESS, ADDRESS, ADDRESS); + private static final FunctionDescriptor DLSYM = FunctionDescriptor.of(ADDRESS, ADDRESS, ADDRESS); + + private final Linker linker = Linker.nativeLinker(); + private final MethodHandle dlopen; + private final MethodHandle dlerror; + private final MethodHandle dlvsym; + private final MethodHandle dlsym; + private final AtomicReference libHandle = new AtomicReference<>(); + + private FuseSymbolLookup() { + this.dlopen = linker.downcallHandle(linker.defaultLookup().find("dlopen").orElseThrow(() -> new UnsatisfiedLinkError("unresolved symbol dlopen")), DLOPEN); + this.dlerror = linker.downcallHandle(linker.defaultLookup().find("dlerror").orElseThrow(() -> new UnsatisfiedLinkError("unresolved symbol dlerror")), DLERROR); + this.dlvsym = linker.downcallHandle(linker.defaultLookup().find("dlvsym").orElseThrow(() -> new UnsatisfiedLinkError("unresolved symbol dlvsym")), DLVSYM); + this.dlsym = linker.downcallHandle(linker.defaultLookup().find("dlsym").orElseThrow(() -> new UnsatisfiedLinkError("unresolved symbol dlsym")), DLSYM); + } + + public static FuseSymbolLookup getInstance() { + return Holder.INSTANCE; + } + + private static class Holder { + private static final FuseSymbolLookup INSTANCE = new FuseSymbolLookup(); + } + + public void open(String libPath) { + try (var session = Arena.ofConfined()) { + MemorySegment handle = (MemorySegment) dlopen.invokeExact(session.allocateFrom(libPath), RTLD_NOW); + libHandle.set(handle); + } catch (Throwable e) { + throw new AssertionError(e); + } + } + + /** + * {@inheritDoc} + * + * @param nameAndVersion the symbol name and version separated by '@'. + */ + @Override + public Optional find(String nameAndVersion) { + var handle = libHandle.get(); + if (handle == null) { + return Optional.empty(); + } + var sep = nameAndVersion.indexOf('@'); + try (var session = Arena.ofConfined()) { + MemorySegment addr = MemorySegment.NULL; + if (sep != -1) { + String name = nameAndVersion.substring(0, sep); + String version = nameAndVersion.substring(sep + 1); + addr = (MemorySegment) dlvsym.invokeExact(handle, session.allocateFrom(name), session.allocateFrom(version)); + } + + if (MemorySegment.NULL.equals(addr)) { + addr = (MemorySegment) dlsym.invokeExact(handle, session.allocateFrom(nameAndVersion)); + } + + if (MemorySegment.NULL.equals(addr)) { + var error = (MemorySegment) dlerror.invokeExact(); + System.err.println("dlvsym failed for symbol " + nameAndVersion + ": " + error.getString(0)); + return Optional.empty(); + } else { + return Optional.of(addr); + } + } catch (Throwable e) { + return Optional.empty(); + } + } + +} \ No newline at end of file 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 dd096f58..b8f91c95 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,15 +4,13 @@ import org.cryptomator.jfuse.api.FuseMountFailedException; import org.cryptomator.jfuse.api.FuseOperations; import org.cryptomator.jfuse.api.TimeSpec; -import org.cryptomator.jfuse.linux.aarch64.extr.fuse3_lowlevel.fuse_cmdline_opts; import org.cryptomator.jfuse.linux.aarch64.extr.fuse3.fuse_config; import org.cryptomator.jfuse.linux.aarch64.extr.fuse3.fuse_conn_info; import org.cryptomator.jfuse.linux.aarch64.extr.fuse3.fuse_file_info; import org.cryptomator.jfuse.linux.aarch64.extr.fuse3.fuse_h; import org.cryptomator.jfuse.linux.aarch64.extr.fuse3.timespec; -import org.junit.jupiter.api.AfterEach; +import org.cryptomator.jfuse.linux.aarch64.extr.fuse3_lowlevel.fuse_cmdline_opts; import org.junit.jupiter.api.Assertions; -import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Nested; import org.junit.jupiter.api.Test; @@ -20,7 +18,6 @@ import org.junit.jupiter.params.provider.CsvSource; import org.junit.jupiter.params.provider.ValueSource; import org.mockito.Answers; -import org.mockito.MockedStatic; import org.mockito.Mockito; import java.lang.foreign.Arena; @@ -45,7 +42,7 @@ public class Mount { @DisplayName("MountFailedException when fuse_new fails") public void testFuseNewFails() { try (var fuseH = Mockito.mockStatic(FuseFFIHelper.class)) { - fuseH.when(() -> FuseFFIHelper.fuse_new_31(Mockito.any(), Mockito.any(), Mockito.anyLong(), Mockito.any())).thenReturn(MemorySegment.NULL); + fuseH.when(() -> FuseFFIHelper.fuse_new(Mockito.any(), Mockito.any(), Mockito.anyLong(), Mockito.any())).thenReturn(MemorySegment.NULL); var thrown = Assertions.assertThrows(FuseMountFailedException.class, () -> fuseImplSpy.createFuseFS(Mockito.mock(FuseArgs.class))); Assertions.assertEquals("fuse_new failed", thrown.getMessage()); } diff --git a/jfuse-linux-amd64/src/main/java/org/cryptomator/jfuse/linux/amd64/FuseFFIHelper.java b/jfuse-linux-amd64/src/main/java/org/cryptomator/jfuse/linux/amd64/FuseFFIHelper.java index 0bb3d97b..1750f24d 100644 --- a/jfuse-linux-amd64/src/main/java/org/cryptomator/jfuse/linux/amd64/FuseFFIHelper.java +++ b/jfuse-linux-amd64/src/main/java/org/cryptomator/jfuse/linux/amd64/FuseFFIHelper.java @@ -5,24 +5,19 @@ import java.lang.foreign.FunctionDescriptor; import java.lang.foreign.Linker; import java.lang.foreign.MemorySegment; -import java.lang.foreign.SymbolLookup; import java.lang.invoke.MethodHandle; /** - * Class for not jextract'able symbols, e.g. fuse_new_31 + * Class for not jextract'able versioned symbols, e.g. fuse_new@FUSE_3.0 */ public class FuseFFIHelper { - - static final SymbolLookup SYMBOL_LOOKUP = SymbolLookup.loaderLookup() - .or(Linker.nativeLinker().defaultLookup()); - static MemorySegment findOrThrow(String symbol) { - return SYMBOL_LOOKUP.find(symbol) + return FuseSymbolLookup.getInstance().find(symbol) .orElseThrow(() -> new UnsatisfiedLinkError("unresolved symbol: " + symbol)); } - private static class fuse_new_31 { + private static class fuse_new { public static final FunctionDescriptor DESC = FunctionDescriptor.of( fuse_h.C_POINTER, fuse_h.C_POINTER, @@ -32,38 +27,17 @@ private static class fuse_new_31 { ); public static final MethodHandle HANDLE = Linker.nativeLinker().downcallHandle( - findOrThrow("fuse_new_31"), + findOrThrow("fuse_new@FUSE_3.0"), DESC); } - /** - * Function descriptor for: - * {@snippet lang = c: - * struct fuse *fuse_new(struct fuse_args *args, const struct fuse_operations *op, size_t op_size, void *private_data) - *} - */ - public static FunctionDescriptor fuse_new_31$descriptor() { - return fuse_new_31.DESC; - } - - - /** - * Downcall method handle for: - * {@snippet lang = c: - * struct fuse *fuse_new(struct fuse_args *args, const struct fuse_operations *op, size_t op_size, void *private_data) - *} - */ - public static MethodHandle fuse_new_31$handle() { - return fuse_new_31.HANDLE; - } - /** * {@snippet lang = c: * struct fuse *fuse_new(struct fuse_args *args, const struct fuse_operations *op, size_t op_size, void *private_data) *} */ - public static MemorySegment fuse_new_31(MemorySegment args, MemorySegment op, long op_size, MemorySegment private_data) { - var mh$ = fuse_new_31.HANDLE; + public static MemorySegment fuse_new(MemorySegment args, MemorySegment op, long op_size, MemorySegment private_data) { + var mh$ = fuse_new.HANDLE; try { return (MemorySegment) mh$.invokeExact(args, op, op_size, private_data); } catch (Throwable ex$) { 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 504d3e13..4a9503b0 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 @@ -37,7 +37,7 @@ protected FuseMount mount(List args) throws FuseMountFailedException { @VisibleForTesting MemorySegment createFuseFS(FuseArgs fuseArgs) throws FuseMountFailedException { - var fuse = FuseFFIHelper.fuse_new_31(fuseArgs.args(), fuseOperationsStruct, fuseOperationsStruct.byteSize(), MemorySegment.NULL); + var fuse = FuseFFIHelper.fuse_new(fuseArgs.args(), fuseOperationsStruct, fuseOperationsStruct.byteSize(), MemorySegment.NULL); if (MemorySegment.NULL.equals(fuse)) { throw new FuseMountFailedException("fuse_new failed"); } diff --git a/jfuse-linux-amd64/src/main/java/org/cryptomator/jfuse/linux/amd64/FuseSymbolLookup.java b/jfuse-linux-amd64/src/main/java/org/cryptomator/jfuse/linux/amd64/FuseSymbolLookup.java index 350cdc40..e0108cb6 100644 --- a/jfuse-linux-amd64/src/main/java/org/cryptomator/jfuse/linux/amd64/FuseSymbolLookup.java +++ b/jfuse-linux-amd64/src/main/java/org/cryptomator/jfuse/linux/amd64/FuseSymbolLookup.java @@ -70,13 +70,13 @@ public Optional find(String nameAndVersion) { var sep = nameAndVersion.indexOf('@'); try (var session = Arena.ofConfined()) { MemorySegment addr = MemorySegment.NULL; - if(sep != -1) { + if (sep != -1) { String name = nameAndVersion.substring(0, sep); String version = nameAndVersion.substring(sep + 1); - addr = (MemorySegment) dlvsym.invokeExact(handle, session.allocateFrom(name),session.allocateFrom(version)); + addr = (MemorySegment) dlvsym.invokeExact(handle, session.allocateFrom(name), session.allocateFrom(version)); } - if(MemorySegment.NULL.equals(addr)) { + if (MemorySegment.NULL.equals(addr)) { addr = (MemorySegment) dlsym.invokeExact(handle, session.allocateFrom(nameAndVersion)); } 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 242d35a2..35db3fa3 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 @@ -42,7 +42,7 @@ public class Mount { @DisplayName("MountFailedException when fuse_new fails") public void testFuseNewFails() { try (var fuseH = Mockito.mockStatic(FuseFFIHelper.class)) { - fuseH.when(() -> FuseFFIHelper.fuse_new_31(Mockito.any(), Mockito.any(), Mockito.anyLong(), Mockito.any())).thenReturn(MemorySegment.NULL); + fuseH.when(() -> FuseFFIHelper.fuse_new(Mockito.any(), Mockito.any(), Mockito.anyLong(), Mockito.any())).thenReturn(MemorySegment.NULL); var thrown = Assertions.assertThrows(FuseMountFailedException.class, () -> fuseImplSpy.createFuseFS(Mockito.mock(FuseArgs.class))); Assertions.assertEquals("fuse_new failed", thrown.getMessage()); } From 5edb152482387dd877bf473883949c84ece6b887 Mon Sep 17 00:00:00 2001 From: Sebastian Stenzel Date: Sat, 5 Apr 2025 15:09:09 +0200 Subject: [PATCH 04/12] try to find error on aarch64 --- .../org/cryptomator/jfuse/linux/aarch64/FuseSymbolLookup.java | 1 + 1 file changed, 1 insertion(+) diff --git a/jfuse-linux-aarch64/src/main/java/org/cryptomator/jfuse/linux/aarch64/FuseSymbolLookup.java b/jfuse-linux-aarch64/src/main/java/org/cryptomator/jfuse/linux/aarch64/FuseSymbolLookup.java index 36e1a22f..136a422f 100644 --- a/jfuse-linux-aarch64/src/main/java/org/cryptomator/jfuse/linux/aarch64/FuseSymbolLookup.java +++ b/jfuse-linux-aarch64/src/main/java/org/cryptomator/jfuse/linux/aarch64/FuseSymbolLookup.java @@ -88,6 +88,7 @@ public Optional find(String nameAndVersion) { return Optional.of(addr); } } catch (Throwable e) { + e.printStackTrace(); return Optional.empty(); } } From 5767b96142a98ec5deb3de6f219b5a9f030f37f1 Mon Sep 17 00:00:00 2001 From: Sebastian Stenzel Date: Sat, 5 Apr 2025 15:27:00 +0200 Subject: [PATCH 05/12] Revert "try to find error on aarch64" This reverts commit 5edb152482387dd877bf473883949c84ece6b887. --- .../org/cryptomator/jfuse/linux/aarch64/FuseSymbolLookup.java | 1 - 1 file changed, 1 deletion(-) diff --git a/jfuse-linux-aarch64/src/main/java/org/cryptomator/jfuse/linux/aarch64/FuseSymbolLookup.java b/jfuse-linux-aarch64/src/main/java/org/cryptomator/jfuse/linux/aarch64/FuseSymbolLookup.java index 136a422f..36e1a22f 100644 --- a/jfuse-linux-aarch64/src/main/java/org/cryptomator/jfuse/linux/aarch64/FuseSymbolLookup.java +++ b/jfuse-linux-aarch64/src/main/java/org/cryptomator/jfuse/linux/aarch64/FuseSymbolLookup.java @@ -88,7 +88,6 @@ public Optional find(String nameAndVersion) { return Optional.of(addr); } } catch (Throwable e) { - e.printStackTrace(); return Optional.empty(); } } From a6a92864aa7f02cc0d37afcda4d799ce3cb8bca2 Mon Sep 17 00:00:00 2001 From: Sebastian Stenzel Date: Sat, 5 Apr 2025 15:32:20 +0200 Subject: [PATCH 06/12] use correct `fuse.lib.path` --- .github/workflows/build.yml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 93c80624..d469416e 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -16,8 +16,10 @@ jobs: include: - os: ubuntu-latest arch: x86_64 + fuseLibPath: /lib/x86_64-linux-gnu/libfuse3.so.3 - os: ubuntu-24.04-arm arch: aarch64 + fuseLibPath: /usr/lib/aarch64-linux-gnu/libfuse3.so.3 runs-on: ${{ matrix.os }} steps: - uses: actions/checkout@v4 @@ -31,7 +33,7 @@ jobs: sudo apt-get update sudo apt-get install fuse3 libfuse3-dev - name: Maven build - run: mvn -B verify -Dfuse.lib.path="/lib/${{ matrix.arch }}-linux-gnu/libfuse3.so.3" --no-transfer-progress + run: mvn -B verify -Dfuse.lib.path="${{ matrix.fuseLibPath }}" --no-transfer-progress - uses: actions/upload-artifact@v4 with: name: coverage-linux-${{ matrix.arch }} From 060e593e09907fe5fd3e1a76681826032ad59be2 Mon Sep 17 00:00:00 2001 From: Sebastian Stenzel Date: Sat, 5 Apr 2025 15:37:37 +0200 Subject: [PATCH 07/12] fix UnsatisfiedLinkError: forgot to dlopen lib --- .../org/cryptomator/jfuse/linux/aarch64/LinuxFuseBuilder.java | 1 + 1 file changed, 1 insertion(+) diff --git a/jfuse-linux-aarch64/src/main/java/org/cryptomator/jfuse/linux/aarch64/LinuxFuseBuilder.java b/jfuse-linux-aarch64/src/main/java/org/cryptomator/jfuse/linux/aarch64/LinuxFuseBuilder.java index c76abf3f..1cde010e 100644 --- a/jfuse-linux-aarch64/src/main/java/org/cryptomator/jfuse/linux/aarch64/LinuxFuseBuilder.java +++ b/jfuse-linux-aarch64/src/main/java/org/cryptomator/jfuse/linux/aarch64/LinuxFuseBuilder.java @@ -37,6 +37,7 @@ public void setLibraryPath(String libraryPath) { @Override public Fuse build(FuseOperations fuseOperations) throws UnsatisfiedLinkError { if (libraryPath != null) { + FuseSymbolLookup.getInstance().open(libraryPath); System.load(libraryPath); } else { System.loadLibrary(DEFAULT_LIBNAME); From cdde9a7e831b867a1801cd82c5df2fd7424c1967 Mon Sep 17 00:00:00 2001 From: Sebastian Stenzel Date: Sat, 5 Apr 2025 15:51:21 +0200 Subject: [PATCH 08/12] cleanup --- .github/workflows/build.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index d469416e..c77d5dab 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -10,17 +10,17 @@ env: jobs: linux: - name: Test jfuse-linux packages strategy: matrix: include: - os: ubuntu-latest arch: x86_64 - fuseLibPath: /lib/x86_64-linux-gnu/libfuse3.so.3 + fuseLibPath: /usr/lib/x86_64-linux-gnu/libfuse3.so.3 - os: ubuntu-24.04-arm arch: aarch64 fuseLibPath: /usr/lib/aarch64-linux-gnu/libfuse3.so.3 runs-on: ${{ matrix.os }} + name: Test jfuse-linux-${{ arch }} steps: - uses: actions/checkout@v4 - uses: actions/setup-java@v4 From b3f1c85e2d71b0f91a10b022abe24f820a5f98ae Mon Sep 17 00:00:00 2001 From: Sebastian Stenzel Date: Sat, 5 Apr 2025 15:52:34 +0200 Subject: [PATCH 09/12] try to remove `dlopen` already loaded lib --- .../jfuse/linux/aarch64/FuseFFIHelper.java | 1 - .../jfuse/linux/aarch64/FuseSymbolLookup.java | 37 +++++-------------- .../jfuse/linux/aarch64/LinuxFuseBuilder.java | 1 - .../jfuse/linux/amd64/FuseSymbolLookup.java | 37 +++++-------------- .../jfuse/linux/amd64/LinuxFuseBuilder.java | 1 - 5 files changed, 18 insertions(+), 59 deletions(-) diff --git a/jfuse-linux-aarch64/src/main/java/org/cryptomator/jfuse/linux/aarch64/FuseFFIHelper.java b/jfuse-linux-aarch64/src/main/java/org/cryptomator/jfuse/linux/aarch64/FuseFFIHelper.java index 3f60cbf1..8745923e 100644 --- a/jfuse-linux-aarch64/src/main/java/org/cryptomator/jfuse/linux/aarch64/FuseFFIHelper.java +++ b/jfuse-linux-aarch64/src/main/java/org/cryptomator/jfuse/linux/aarch64/FuseFFIHelper.java @@ -12,7 +12,6 @@ */ public class FuseFFIHelper { - static MemorySegment findOrThrow(String symbol) { return FuseSymbolLookup.getInstance().find(symbol) .orElseThrow(() -> new UnsatisfiedLinkError("unresolved symbol: " + symbol)); diff --git a/jfuse-linux-aarch64/src/main/java/org/cryptomator/jfuse/linux/aarch64/FuseSymbolLookup.java b/jfuse-linux-aarch64/src/main/java/org/cryptomator/jfuse/linux/aarch64/FuseSymbolLookup.java index 36e1a22f..334b093a 100644 --- a/jfuse-linux-aarch64/src/main/java/org/cryptomator/jfuse/linux/aarch64/FuseSymbolLookup.java +++ b/jfuse-linux-aarch64/src/main/java/org/cryptomator/jfuse/linux/aarch64/FuseSymbolLookup.java @@ -7,36 +7,30 @@ import java.lang.foreign.SymbolLookup; import java.lang.invoke.MethodHandle; import java.util.Optional; -import java.util.concurrent.atomic.AtomicReference; import static java.lang.foreign.ValueLayout.ADDRESS; -import static java.lang.foreign.ValueLayout.JAVA_INT; public class FuseSymbolLookup implements SymbolLookup { - private static final int RTLD_NOW = 0x02; + private static final int RTLD_GLOBAL = 0x00; // defined in /usr/include/dlfcn.h - // https://man7.org/linux/man-pages/man3/dlopen.3.html - private static final FunctionDescriptor DLOPEN = FunctionDescriptor.of(ADDRESS, ADDRESS, JAVA_INT); - private static final FunctionDescriptor DLCLOSE = FunctionDescriptor.of(JAVA_INT, ADDRESS); + // https://man7.org/linux/man-pages/man3/dlerror.3.html private static final FunctionDescriptor DLERROR = FunctionDescriptor.of(ADDRESS); // https://man7.org/linux/man-pages/man3/dlvsym.3.html private static final FunctionDescriptor DLVSYM = FunctionDescriptor.of(ADDRESS, ADDRESS, ADDRESS, ADDRESS); private static final FunctionDescriptor DLSYM = FunctionDescriptor.of(ADDRESS, ADDRESS, ADDRESS); - private final Linker linker = Linker.nativeLinker(); - private final MethodHandle dlopen; private final MethodHandle dlerror; private final MethodHandle dlvsym; private final MethodHandle dlsym; - private final AtomicReference libHandle = new AtomicReference<>(); private FuseSymbolLookup() { - this.dlopen = linker.downcallHandle(linker.defaultLookup().find("dlopen").orElseThrow(() -> new UnsatisfiedLinkError("unresolved symbol dlopen")), DLOPEN); - this.dlerror = linker.downcallHandle(linker.defaultLookup().find("dlerror").orElseThrow(() -> new UnsatisfiedLinkError("unresolved symbol dlerror")), DLERROR); - this.dlvsym = linker.downcallHandle(linker.defaultLookup().find("dlvsym").orElseThrow(() -> new UnsatisfiedLinkError("unresolved symbol dlvsym")), DLVSYM); - this.dlsym = linker.downcallHandle(linker.defaultLookup().find("dlsym").orElseThrow(() -> new UnsatisfiedLinkError("unresolved symbol dlsym")), DLSYM); + var linker = Linker.nativeLinker(); + var defaultLookup = linker.defaultLookup(); + this.dlerror = linker.downcallHandle(defaultLookup.find("dlerror").orElseThrow(() -> new UnsatisfiedLinkError("unresolved symbol dlerror")), DLERROR); + this.dlvsym = linker.downcallHandle(defaultLookup.find("dlvsym").orElseThrow(() -> new UnsatisfiedLinkError("unresolved symbol dlvsym")), DLVSYM); + this.dlsym = linker.downcallHandle(defaultLookup.find("dlsym").orElseThrow(() -> new UnsatisfiedLinkError("unresolved symbol dlsym")), DLSYM); } public static FuseSymbolLookup getInstance() { @@ -47,15 +41,6 @@ private static class Holder { private static final FuseSymbolLookup INSTANCE = new FuseSymbolLookup(); } - public void open(String libPath) { - try (var session = Arena.ofConfined()) { - MemorySegment handle = (MemorySegment) dlopen.invokeExact(session.allocateFrom(libPath), RTLD_NOW); - libHandle.set(handle); - } catch (Throwable e) { - throw new AssertionError(e); - } - } - /** * {@inheritDoc} * @@ -63,21 +48,17 @@ public void open(String libPath) { */ @Override public Optional find(String nameAndVersion) { - var handle = libHandle.get(); - if (handle == null) { - return Optional.empty(); - } var sep = nameAndVersion.indexOf('@'); try (var session = Arena.ofConfined()) { MemorySegment addr = MemorySegment.NULL; if (sep != -1) { String name = nameAndVersion.substring(0, sep); String version = nameAndVersion.substring(sep + 1); - addr = (MemorySegment) dlvsym.invokeExact(handle, session.allocateFrom(name), session.allocateFrom(version)); + addr = (MemorySegment) dlvsym.invokeExact(RTLD_GLOBAL, session.allocateFrom(name), session.allocateFrom(version)); } if (MemorySegment.NULL.equals(addr)) { - addr = (MemorySegment) dlsym.invokeExact(handle, session.allocateFrom(nameAndVersion)); + addr = (MemorySegment) dlsym.invokeExact(RTLD_GLOBAL, session.allocateFrom(nameAndVersion)); } if (MemorySegment.NULL.equals(addr)) { diff --git a/jfuse-linux-aarch64/src/main/java/org/cryptomator/jfuse/linux/aarch64/LinuxFuseBuilder.java b/jfuse-linux-aarch64/src/main/java/org/cryptomator/jfuse/linux/aarch64/LinuxFuseBuilder.java index 1cde010e..c76abf3f 100644 --- a/jfuse-linux-aarch64/src/main/java/org/cryptomator/jfuse/linux/aarch64/LinuxFuseBuilder.java +++ b/jfuse-linux-aarch64/src/main/java/org/cryptomator/jfuse/linux/aarch64/LinuxFuseBuilder.java @@ -37,7 +37,6 @@ public void setLibraryPath(String libraryPath) { @Override public Fuse build(FuseOperations fuseOperations) throws UnsatisfiedLinkError { if (libraryPath != null) { - FuseSymbolLookup.getInstance().open(libraryPath); System.load(libraryPath); } else { System.loadLibrary(DEFAULT_LIBNAME); diff --git a/jfuse-linux-amd64/src/main/java/org/cryptomator/jfuse/linux/amd64/FuseSymbolLookup.java b/jfuse-linux-amd64/src/main/java/org/cryptomator/jfuse/linux/amd64/FuseSymbolLookup.java index e0108cb6..d932454c 100644 --- a/jfuse-linux-amd64/src/main/java/org/cryptomator/jfuse/linux/amd64/FuseSymbolLookup.java +++ b/jfuse-linux-amd64/src/main/java/org/cryptomator/jfuse/linux/amd64/FuseSymbolLookup.java @@ -7,36 +7,30 @@ import java.lang.foreign.SymbolLookup; import java.lang.invoke.MethodHandle; import java.util.Optional; -import java.util.concurrent.atomic.AtomicReference; import static java.lang.foreign.ValueLayout.ADDRESS; -import static java.lang.foreign.ValueLayout.JAVA_INT; public class FuseSymbolLookup implements SymbolLookup { - private static final int RTLD_NOW = 0x02; + private static final int RTLD_GLOBAL = 0x00; // defined in /usr/include/dlfcn.h - // https://man7.org/linux/man-pages/man3/dlopen.3.html - private static final FunctionDescriptor DLOPEN = FunctionDescriptor.of(ADDRESS, ADDRESS, JAVA_INT); - private static final FunctionDescriptor DLCLOSE = FunctionDescriptor.of(JAVA_INT, ADDRESS); + // https://man7.org/linux/man-pages/man3/dlerror.3.html private static final FunctionDescriptor DLERROR = FunctionDescriptor.of(ADDRESS); // https://man7.org/linux/man-pages/man3/dlvsym.3.html private static final FunctionDescriptor DLVSYM = FunctionDescriptor.of(ADDRESS, ADDRESS, ADDRESS, ADDRESS); private static final FunctionDescriptor DLSYM = FunctionDescriptor.of(ADDRESS, ADDRESS, ADDRESS); - private final Linker linker = Linker.nativeLinker(); - private final MethodHandle dlopen; private final MethodHandle dlerror; private final MethodHandle dlvsym; private final MethodHandle dlsym; - private final AtomicReference libHandle = new AtomicReference<>(); private FuseSymbolLookup() { - this.dlopen = linker.downcallHandle(linker.defaultLookup().find("dlopen").orElseThrow(() -> new UnsatisfiedLinkError("unresolved symbol dlopen")), DLOPEN); - this.dlerror = linker.downcallHandle(linker.defaultLookup().find("dlerror").orElseThrow(() -> new UnsatisfiedLinkError("unresolved symbol dlerror")), DLERROR); - this.dlvsym = linker.downcallHandle(linker.defaultLookup().find("dlvsym").orElseThrow(() -> new UnsatisfiedLinkError("unresolved symbol dlvsym")), DLVSYM); - this.dlsym = linker.downcallHandle(linker.defaultLookup().find("dlsym").orElseThrow(() -> new UnsatisfiedLinkError("unresolved symbol dlsym")), DLSYM); + var linker = Linker.nativeLinker(); + var defaultLookup = linker.defaultLookup(); + this.dlerror = linker.downcallHandle(defaultLookup.find("dlerror").orElseThrow(() -> new UnsatisfiedLinkError("unresolved symbol dlerror")), DLERROR); + this.dlvsym = linker.downcallHandle(defaultLookup.find("dlvsym").orElseThrow(() -> new UnsatisfiedLinkError("unresolved symbol dlvsym")), DLVSYM); + this.dlsym = linker.downcallHandle(defaultLookup.find("dlsym").orElseThrow(() -> new UnsatisfiedLinkError("unresolved symbol dlsym")), DLSYM); } public static FuseSymbolLookup getInstance() { @@ -47,15 +41,6 @@ private static class Holder { private static final FuseSymbolLookup INSTANCE = new FuseSymbolLookup(); } - public void open(String libPath) { - try (var session = Arena.ofConfined()) { - MemorySegment handle = (MemorySegment) dlopen.invokeExact(session.allocateFrom(libPath), RTLD_NOW); - libHandle.set(handle); - } catch (Throwable e) { - throw new AssertionError(e); - } - } - /** * {@inheritDoc} * @@ -63,21 +48,17 @@ public void open(String libPath) { */ @Override public Optional find(String nameAndVersion) { - var handle = libHandle.get(); - if (handle == null) { - return Optional.empty(); - } var sep = nameAndVersion.indexOf('@'); try (var session = Arena.ofConfined()) { MemorySegment addr = MemorySegment.NULL; if (sep != -1) { String name = nameAndVersion.substring(0, sep); String version = nameAndVersion.substring(sep + 1); - addr = (MemorySegment) dlvsym.invokeExact(handle, session.allocateFrom(name), session.allocateFrom(version)); + addr = (MemorySegment) dlvsym.invokeExact(RTLD_GLOBAL, session.allocateFrom(name), session.allocateFrom(version)); } if (MemorySegment.NULL.equals(addr)) { - addr = (MemorySegment) dlsym.invokeExact(handle, session.allocateFrom(nameAndVersion)); + addr = (MemorySegment) dlsym.invokeExact(RTLD_GLOBAL, session.allocateFrom(nameAndVersion)); } if (MemorySegment.NULL.equals(addr)) { diff --git a/jfuse-linux-amd64/src/main/java/org/cryptomator/jfuse/linux/amd64/LinuxFuseBuilder.java b/jfuse-linux-amd64/src/main/java/org/cryptomator/jfuse/linux/amd64/LinuxFuseBuilder.java index 5b4cea90..bdfebc18 100644 --- a/jfuse-linux-amd64/src/main/java/org/cryptomator/jfuse/linux/amd64/LinuxFuseBuilder.java +++ b/jfuse-linux-amd64/src/main/java/org/cryptomator/jfuse/linux/amd64/LinuxFuseBuilder.java @@ -37,7 +37,6 @@ public void setLibraryPath(String libraryPath) { @Override public Fuse build(FuseOperations fuseOperations) throws UnsatisfiedLinkError { if (libraryPath != null) { - FuseSymbolLookup.getInstance().open(libraryPath); System.load(libraryPath); } else { System.loadLibrary(DEFAULT_LIBNAME); From 5b82c4098d30890364c8ca5d85ead112676aeb86 Mon Sep 17 00:00:00 2001 From: Sebastian Stenzel Date: Sat, 5 Apr 2025 15:53:12 +0200 Subject: [PATCH 10/12] fix workflow file --- .github/workflows/build.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index c77d5dab..4f5ee08d 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -20,7 +20,7 @@ jobs: arch: aarch64 fuseLibPath: /usr/lib/aarch64-linux-gnu/libfuse3.so.3 runs-on: ${{ matrix.os }} - name: Test jfuse-linux-${{ arch }} + name: Test jfuse-linux-${{ matrix.arch }} steps: - uses: actions/checkout@v4 - uses: actions/setup-java@v4 From d1b5791c0719d96cb49650880b1e33b8607391f2 Mon Sep 17 00:00:00 2001 From: Sebastian Stenzel Date: Sat, 5 Apr 2025 15:58:51 +0200 Subject: [PATCH 11/12] fix type --- .github/workflows/build.yml | 1 + .../org/cryptomator/jfuse/linux/aarch64/FuseSymbolLookup.java | 2 +- .../org/cryptomator/jfuse/linux/amd64/FuseSymbolLookup.java | 2 +- 3 files changed, 3 insertions(+), 2 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 4f5ee08d..655ddc1a 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -11,6 +11,7 @@ env: jobs: linux: strategy: + fail-fast: false matrix: include: - os: ubuntu-latest diff --git a/jfuse-linux-aarch64/src/main/java/org/cryptomator/jfuse/linux/aarch64/FuseSymbolLookup.java b/jfuse-linux-aarch64/src/main/java/org/cryptomator/jfuse/linux/aarch64/FuseSymbolLookup.java index 334b093a..740424d7 100644 --- a/jfuse-linux-aarch64/src/main/java/org/cryptomator/jfuse/linux/aarch64/FuseSymbolLookup.java +++ b/jfuse-linux-aarch64/src/main/java/org/cryptomator/jfuse/linux/aarch64/FuseSymbolLookup.java @@ -12,7 +12,7 @@ public class FuseSymbolLookup implements SymbolLookup { - private static final int RTLD_GLOBAL = 0x00; // defined in /usr/include/dlfcn.h + private static final MemorySegment RTLD_GLOBAL = MemorySegment.ofAddress(0L); // defined in /usr/include/dlfcn.h // https://man7.org/linux/man-pages/man3/dlerror.3.html private static final FunctionDescriptor DLERROR = FunctionDescriptor.of(ADDRESS); diff --git a/jfuse-linux-amd64/src/main/java/org/cryptomator/jfuse/linux/amd64/FuseSymbolLookup.java b/jfuse-linux-amd64/src/main/java/org/cryptomator/jfuse/linux/amd64/FuseSymbolLookup.java index d932454c..79763405 100644 --- a/jfuse-linux-amd64/src/main/java/org/cryptomator/jfuse/linux/amd64/FuseSymbolLookup.java +++ b/jfuse-linux-amd64/src/main/java/org/cryptomator/jfuse/linux/amd64/FuseSymbolLookup.java @@ -12,7 +12,7 @@ public class FuseSymbolLookup implements SymbolLookup { - private static final int RTLD_GLOBAL = 0x00; // defined in /usr/include/dlfcn.h + private static final MemorySegment RTLD_GLOBAL = MemorySegment.ofAddress(0L); // defined in /usr/include/dlfcn.h // https://man7.org/linux/man-pages/man3/dlerror.3.html private static final FunctionDescriptor DLERROR = FunctionDescriptor.of(ADDRESS); From c6606cb77b744b298bb77568f09c4bb01de4c555 Mon Sep 17 00:00:00 2001 From: Sebastian Stenzel Date: Sat, 5 Apr 2025 16:09:36 +0200 Subject: [PATCH 12/12] Revert "try to remove `dlopen` already loaded lib" This reverts commit b3f1c85e2d71b0f91a10b022abe24f820a5f98ae. # Conflicts: # jfuse-linux-aarch64/src/main/java/org/cryptomator/jfuse/linux/aarch64/FuseSymbolLookup.java # jfuse-linux-amd64/src/main/java/org/cryptomator/jfuse/linux/amd64/FuseSymbolLookup.java --- .../jfuse/linux/aarch64/FuseSymbolLookup.java | 27 ++++++++++++++++--- .../jfuse/linux/aarch64/LinuxFuseBuilder.java | 1 + .../jfuse/linux/amd64/FuseSymbolLookup.java | 27 ++++++++++++++++--- .../jfuse/linux/amd64/LinuxFuseBuilder.java | 1 + 4 files changed, 48 insertions(+), 8 deletions(-) diff --git a/jfuse-linux-aarch64/src/main/java/org/cryptomator/jfuse/linux/aarch64/FuseSymbolLookup.java b/jfuse-linux-aarch64/src/main/java/org/cryptomator/jfuse/linux/aarch64/FuseSymbolLookup.java index 740424d7..f9631f41 100644 --- a/jfuse-linux-aarch64/src/main/java/org/cryptomator/jfuse/linux/aarch64/FuseSymbolLookup.java +++ b/jfuse-linux-aarch64/src/main/java/org/cryptomator/jfuse/linux/aarch64/FuseSymbolLookup.java @@ -7,27 +7,33 @@ import java.lang.foreign.SymbolLookup; import java.lang.invoke.MethodHandle; import java.util.Optional; +import java.util.concurrent.atomic.AtomicReference; import static java.lang.foreign.ValueLayout.ADDRESS; +import static java.lang.foreign.ValueLayout.JAVA_INT; public class FuseSymbolLookup implements SymbolLookup { - private static final MemorySegment RTLD_GLOBAL = MemorySegment.ofAddress(0L); // defined in /usr/include/dlfcn.h + private static final int RTLD_NOW = 0x02; - // https://man7.org/linux/man-pages/man3/dlerror.3.html + // https://man7.org/linux/man-pages/man3/dlopen.3.html + private static final FunctionDescriptor DLOPEN = FunctionDescriptor.of(ADDRESS, ADDRESS, JAVA_INT); private static final FunctionDescriptor DLERROR = FunctionDescriptor.of(ADDRESS); // https://man7.org/linux/man-pages/man3/dlvsym.3.html private static final FunctionDescriptor DLVSYM = FunctionDescriptor.of(ADDRESS, ADDRESS, ADDRESS, ADDRESS); private static final FunctionDescriptor DLSYM = FunctionDescriptor.of(ADDRESS, ADDRESS, ADDRESS); + private final MethodHandle dlopen; private final MethodHandle dlerror; private final MethodHandle dlvsym; private final MethodHandle dlsym; + private final AtomicReference libHandle = new AtomicReference<>(); private FuseSymbolLookup() { var linker = Linker.nativeLinker(); var defaultLookup = linker.defaultLookup(); + this.dlopen = linker.downcallHandle(defaultLookup.find("dlopen").orElseThrow(() -> new UnsatisfiedLinkError("unresolved symbol dlopen")), DLOPEN); this.dlerror = linker.downcallHandle(defaultLookup.find("dlerror").orElseThrow(() -> new UnsatisfiedLinkError("unresolved symbol dlerror")), DLERROR); this.dlvsym = linker.downcallHandle(defaultLookup.find("dlvsym").orElseThrow(() -> new UnsatisfiedLinkError("unresolved symbol dlvsym")), DLVSYM); this.dlsym = linker.downcallHandle(defaultLookup.find("dlsym").orElseThrow(() -> new UnsatisfiedLinkError("unresolved symbol dlsym")), DLSYM); @@ -41,6 +47,15 @@ private static class Holder { private static final FuseSymbolLookup INSTANCE = new FuseSymbolLookup(); } + public void open(String libPath) { + try (var session = Arena.ofConfined()) { + MemorySegment handle = (MemorySegment) dlopen.invokeExact(session.allocateFrom(libPath), RTLD_NOW); + libHandle.set(handle); + } catch (Throwable e) { + throw new AssertionError(e); + } + } + /** * {@inheritDoc} * @@ -48,17 +63,21 @@ private static class Holder { */ @Override public Optional find(String nameAndVersion) { + var handle = libHandle.get(); + if (handle == null) { + return Optional.empty(); + } var sep = nameAndVersion.indexOf('@'); try (var session = Arena.ofConfined()) { MemorySegment addr = MemorySegment.NULL; if (sep != -1) { String name = nameAndVersion.substring(0, sep); String version = nameAndVersion.substring(sep + 1); - addr = (MemorySegment) dlvsym.invokeExact(RTLD_GLOBAL, session.allocateFrom(name), session.allocateFrom(version)); + addr = (MemorySegment) dlvsym.invokeExact(handle, session.allocateFrom(name), session.allocateFrom(version)); } if (MemorySegment.NULL.equals(addr)) { - addr = (MemorySegment) dlsym.invokeExact(RTLD_GLOBAL, session.allocateFrom(nameAndVersion)); + addr = (MemorySegment) dlsym.invokeExact(handle, session.allocateFrom(nameAndVersion)); } if (MemorySegment.NULL.equals(addr)) { diff --git a/jfuse-linux-aarch64/src/main/java/org/cryptomator/jfuse/linux/aarch64/LinuxFuseBuilder.java b/jfuse-linux-aarch64/src/main/java/org/cryptomator/jfuse/linux/aarch64/LinuxFuseBuilder.java index c76abf3f..1cde010e 100644 --- a/jfuse-linux-aarch64/src/main/java/org/cryptomator/jfuse/linux/aarch64/LinuxFuseBuilder.java +++ b/jfuse-linux-aarch64/src/main/java/org/cryptomator/jfuse/linux/aarch64/LinuxFuseBuilder.java @@ -37,6 +37,7 @@ public void setLibraryPath(String libraryPath) { @Override public Fuse build(FuseOperations fuseOperations) throws UnsatisfiedLinkError { if (libraryPath != null) { + FuseSymbolLookup.getInstance().open(libraryPath); System.load(libraryPath); } else { System.loadLibrary(DEFAULT_LIBNAME); diff --git a/jfuse-linux-amd64/src/main/java/org/cryptomator/jfuse/linux/amd64/FuseSymbolLookup.java b/jfuse-linux-amd64/src/main/java/org/cryptomator/jfuse/linux/amd64/FuseSymbolLookup.java index 79763405..875c0f20 100644 --- a/jfuse-linux-amd64/src/main/java/org/cryptomator/jfuse/linux/amd64/FuseSymbolLookup.java +++ b/jfuse-linux-amd64/src/main/java/org/cryptomator/jfuse/linux/amd64/FuseSymbolLookup.java @@ -7,27 +7,33 @@ import java.lang.foreign.SymbolLookup; import java.lang.invoke.MethodHandle; import java.util.Optional; +import java.util.concurrent.atomic.AtomicReference; import static java.lang.foreign.ValueLayout.ADDRESS; +import static java.lang.foreign.ValueLayout.JAVA_INT; public class FuseSymbolLookup implements SymbolLookup { - private static final MemorySegment RTLD_GLOBAL = MemorySegment.ofAddress(0L); // defined in /usr/include/dlfcn.h + private static final int RTLD_NOW = 0x02; - // https://man7.org/linux/man-pages/man3/dlerror.3.html + // https://man7.org/linux/man-pages/man3/dlopen.3.html + private static final FunctionDescriptor DLOPEN = FunctionDescriptor.of(ADDRESS, ADDRESS, JAVA_INT); private static final FunctionDescriptor DLERROR = FunctionDescriptor.of(ADDRESS); // https://man7.org/linux/man-pages/man3/dlvsym.3.html private static final FunctionDescriptor DLVSYM = FunctionDescriptor.of(ADDRESS, ADDRESS, ADDRESS, ADDRESS); private static final FunctionDescriptor DLSYM = FunctionDescriptor.of(ADDRESS, ADDRESS, ADDRESS); + private final MethodHandle dlopen; private final MethodHandle dlerror; private final MethodHandle dlvsym; private final MethodHandle dlsym; + private final AtomicReference libHandle = new AtomicReference<>(); private FuseSymbolLookup() { var linker = Linker.nativeLinker(); var defaultLookup = linker.defaultLookup(); + this.dlopen = linker.downcallHandle(defaultLookup.find("dlopen").orElseThrow(() -> new UnsatisfiedLinkError("unresolved symbol dlopen")), DLOPEN); this.dlerror = linker.downcallHandle(defaultLookup.find("dlerror").orElseThrow(() -> new UnsatisfiedLinkError("unresolved symbol dlerror")), DLERROR); this.dlvsym = linker.downcallHandle(defaultLookup.find("dlvsym").orElseThrow(() -> new UnsatisfiedLinkError("unresolved symbol dlvsym")), DLVSYM); this.dlsym = linker.downcallHandle(defaultLookup.find("dlsym").orElseThrow(() -> new UnsatisfiedLinkError("unresolved symbol dlsym")), DLSYM); @@ -41,6 +47,15 @@ private static class Holder { private static final FuseSymbolLookup INSTANCE = new FuseSymbolLookup(); } + public void open(String libPath) { + try (var session = Arena.ofConfined()) { + MemorySegment handle = (MemorySegment) dlopen.invokeExact(session.allocateFrom(libPath), RTLD_NOW); + libHandle.set(handle); + } catch (Throwable e) { + throw new AssertionError(e); + } + } + /** * {@inheritDoc} * @@ -48,17 +63,21 @@ private static class Holder { */ @Override public Optional find(String nameAndVersion) { + var handle = libHandle.get(); + if (handle == null) { + return Optional.empty(); + } var sep = nameAndVersion.indexOf('@'); try (var session = Arena.ofConfined()) { MemorySegment addr = MemorySegment.NULL; if (sep != -1) { String name = nameAndVersion.substring(0, sep); String version = nameAndVersion.substring(sep + 1); - addr = (MemorySegment) dlvsym.invokeExact(RTLD_GLOBAL, session.allocateFrom(name), session.allocateFrom(version)); + addr = (MemorySegment) dlvsym.invokeExact(handle, session.allocateFrom(name), session.allocateFrom(version)); } if (MemorySegment.NULL.equals(addr)) { - addr = (MemorySegment) dlsym.invokeExact(RTLD_GLOBAL, session.allocateFrom(nameAndVersion)); + addr = (MemorySegment) dlsym.invokeExact(handle, session.allocateFrom(nameAndVersion)); } if (MemorySegment.NULL.equals(addr)) { diff --git a/jfuse-linux-amd64/src/main/java/org/cryptomator/jfuse/linux/amd64/LinuxFuseBuilder.java b/jfuse-linux-amd64/src/main/java/org/cryptomator/jfuse/linux/amd64/LinuxFuseBuilder.java index bdfebc18..5b4cea90 100644 --- a/jfuse-linux-amd64/src/main/java/org/cryptomator/jfuse/linux/amd64/LinuxFuseBuilder.java +++ b/jfuse-linux-amd64/src/main/java/org/cryptomator/jfuse/linux/amd64/LinuxFuseBuilder.java @@ -37,6 +37,7 @@ public void setLibraryPath(String libraryPath) { @Override public Fuse build(FuseOperations fuseOperations) throws UnsatisfiedLinkError { if (libraryPath != null) { + FuseSymbolLookup.getInstance().open(libraryPath); System.load(libraryPath); } else { System.loadLibrary(DEFAULT_LIBNAME);