Zero-Dependency Java bindings for FUSE using JEP 454.
This lib makes use of the Foreign Function & Memory API, requiring at least JDK 22.
Older JDK versions are not supported. Please refer to an older version of this lib, if you are interested in using it with an older JDK (with --enable-preview
). Older versions will not receive patches or any kind of support, though!
We attempt to support libfuse 3.x on Linux and Windows while also remaining compatible with libfuse 2.x on macOS, leading to some compromises in the API.
For libfuse 3 to ensure that the readdir
operation runs in readdirplus mode, you have to add FuseOperations.Operation.INIT
to the set returend by FuseOperations::supportedOperations
method to the supported operations. An implementation of init
is not necessary.
Not all fuse_operations
are supported yet.
Status | |
---|---|
getattr | ✅ |
use getattr | |
readlink | ✅ |
use readdir | |
use create | |
mkdir | ✅ |
unlink | ✅ |
rmdir | ✅ |
symlink | ✅ |
rename | ✅ |
link | ❌ |
chmod | ✅ |
chown | ✅ |
truncate | ✅ |
use truncate | |
use utimens | |
open | ✅ |
read | ✅ |
write | ✅ |
statfs | ✅ |
flush | ✅ |
release | ✅ |
fsync | ✅ |
setxattr | ✅ |
getxattr | ✅ |
listxattr | ✅ |
removexattr | ✅ |
opendir | ✅ |
readdir | ✅ |
releasedir | ✅ |
fsyncdir | ✅ |
init | ✅ |
destroy | ✅ |
access | ✅ (ignored on Windows) |
create | ✅ |
lock | ❌ |
utimens | ✅ |
bmap | ❌ |
ioctl | ❌ |
poll | ❌ |
write_buf | ❌ |
read_buf | ❌ |
flock | ❌ |
fallocate | ❌ |
copy_file_range | ❌ |
lseek | ❌ |
Usage examples can be found under /jfuse-examples/
. You basically need to implement FuseOperations
and pass it to the Fuse.builder()
:
<dependency>
<groupId>org.cryptomator</groupId>
<artifactId>jfuse</artifactId>
<version>x.y.z</version>
</dependency>
var builder = Fuse.builder();
var fs = new MyFileSystem(builder.errno());
try (var fuse = builder.build(fs)) {
fuse.mount("my-awesome-fs", mountPoint);
// wait as long as the mounted volume is in use
} // closing will force-unmount (previous graceful unmount recommended)
During runtime, you will need to add allow native access from platform-specific implementations via --enable-native-access
, e.g.:
java -p path/to/mods \
-m com.example.mymodule/com.example.mymodule \
--enable-native-access=org.cryptomator.jfuse.mac \
Due to slight differences in memory layout, each platform needs its own implementation. Currently, the following operating systems and architectures are supported:
Linux | Mac (macFUSE) | Windows (WinFSP) | |
---|---|---|---|
x86_64 | jfuse-linux-amd64 | jfuse-mac | jfuse-win |
arm64 | jfuse-linux-aarch64 | jfuse-mac | jfuse-win |
Due to the magic of the Foreign Function & Memory API, you can build all modules on any platform that you can find a JDK for.
Each platform has its own module. In rare cases, we need to update jextracted classes.
In most cases this requires you to run the build on the target platform, as you need access to its system-specific header files and (most likely) build tools. See module readme for specific requirements.
In order to run jextract
, use the corresponding Maven profile (e.g. -Pjextract-win
).
Before adding a new module, you might want to change the header search path in one of the existing modules and run jextract. If there is no diff at all, you can most likely add a @SupportedPlatform
annotation to its FuseBuilder
and check if it works.
Otherwise, you'd need to add a copy of the module. Make sure to open it to the api in the module-info.java
, as the api module needs reflective access.
Over the past few years, we relied on jnr-fuse ourselves and can recommend using it for platforms that aren't supported by jFUSE. It has also become the benchmark that we wanted to beat regarding performance and API design.