Skip to content

Commit

Permalink
Merge branch 'release/0.2.0'
Browse files Browse the repository at this point in the history
  • Loading branch information
infeo committed Sep 19, 2022
2 parents ea354a8 + fb5f448 commit 1f54357
Show file tree
Hide file tree
Showing 137 changed files with 7,258 additions and 3,649 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ jobs:
- name: Setup fuse
run: |
sudo apt-get update
sudo apt-get install fuse libfuse-dev
sudo apt-get install fuse3 libfuse3-dev
- name: Maven build
run: mvn -B verify -Plinux-amd64
- uses: actions/upload-artifact@v2
Expand Down
11 changes: 8 additions & 3 deletions .gitmodules
Original file line number Diff line number Diff line change
@@ -1,7 +1,12 @@
[submodule "libfuse"]
path = libfuse
[submodule "libfuse2"]
path = libfuse2
url = https://github.com/libfuse/libfuse.git
branch = fuse-2_9_bugfix
branch = fuse_2_9_bugfix

[submodule "libfuse3"]
path = libfuse3
url = https://github.com/libfuse/libfuse.git
branch = master

[submodule "winfsp"]
path = winfsp
Expand Down
1 change: 1 addition & 0 deletions .idea/codeStyles/Project.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

12 changes: 12 additions & 0 deletions .idea/runConfigurations/HelloWorldFileSystem__Windows_.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion .idea/runConfigurations/PosixMirrorFileSystem.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

16 changes: 16 additions & 0 deletions .idea/runConfigurations/RandomFileSystem.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

116 changes: 60 additions & 56 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,58 +9,62 @@ Zero-Dependency Java bindings for FUSE using [JEP 424](https://openjdk.org/jeps/

This is currently an experimental library requiring JDK 19. As long as the [Foreign Function & Memory API](https://openjdk.org/jeps/424) is incubating, the required JDK will increase.

Currently, it only provides bindings for [libfuse 2.x](https://github.com/libfuse/libfuse/). Once stable, a new branch for libfuse 3.x will be added.
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.

### Supported `fuse_operations`

Not all `fuse_operations` are supported yet.

| | Status |
|--------|-------|
| getattr | :white_check_mark: |
| readlink | :white_check_mark: |
| ~getdir~ | use readdir |
| ~mknod~ | use create |
| mkdir | :white_check_mark: |
| unlink | :white_check_mark: |
| rmdir | :white_check_mark: |
| symlink | :white_check_mark: |
| rename | :white_check_mark: |
| link | :x: |
| chmod | :white_check_mark: |
| chown | :x: |
| truncate | :white_check_mark: |
| ~utime~ | use utimens |
| open | :white_check_mark: |
| read | :white_check_mark: |
| write | :white_check_mark: |
| statfs | :white_check_mark: |
| flush | :x: |
| release | :white_check_mark: |
| fsync | :x: |
| setxattr | :x: |
| getxattr | :x: |
| listxattr | :x: |
| removexattr | :x: |
| opendir | :white_check_mark: |
| readdir | :white_check_mark: |
| releasedir | :white_check_mark: |
| fsyncdir | :x: |
| init | :white_check_mark: |
| destroy | :white_check_mark: |
| access | :white_check_mark: |
| create | :white_check_mark: |
| ftruncate | :x: |
| fgetattr | :x: |
| lock | :x: |
| utimens | :white_check_mark: |
| bmap | :x: |
| ioctl | :x: |
| poll | :x: |
| write_buf | :x: |
| read_buf | :x: |
| flock | :x: |
| fallocate | :x: |
Not all [`fuse_operations`](https://libfuse.github.io/doxygen/structfuse__operations.html) are supported yet.

| | Status |
|-----------------|-----------------------------------------|
| getattr | :white_check_mark: |
| ~fgetattr~ | use getattr |
| readlink | :white_check_mark: |
| ~getdir~ | use readdir |
| ~mknod~ | use create |
| mkdir | :white_check_mark: |
| unlink | :white_check_mark: |
| rmdir | :white_check_mark: |
| symlink | :white_check_mark: |
| rename | :white_check_mark: |
| link | :x: |
| chmod | :white_check_mark: |
| chown | :x: |
| truncate | :white_check_mark: |
| ~ftruncate~ | use truncate |
| ~utime~ | use utimens |
| open | :white_check_mark: |
| read | :white_check_mark: |
| write | :white_check_mark: |
| statfs | :white_check_mark: |
| flush | :x: |
| release | :white_check_mark: |
| fsync | :x: |
| setxattr | :x: |
| getxattr | :x: |
| listxattr | :x: |
| removexattr | :x: |
| opendir | :white_check_mark: |
| readdir | :white_check_mark: |
| releasedir | :white_check_mark: |
| fsyncdir | :x: |
| init | :white_check_mark: |
| destroy | :white_check_mark: |
| access | :white_check_mark: (ignored on Windows) |
| create | :white_check_mark: |
| lock | :x: |
| utimens | :white_check_mark: |
| bmap | :x: |
| ioctl | :x: |
| poll | :x: |
| write_buf | :x: |
| read_buf | :x: |
| flock | :x: |
| fallocate | :x: |
| copy_file_range | :x: |
| lseek | :x: |

## Usage

Expand All @@ -70,9 +74,9 @@ Usage examples can be found under [`/jfuse-examples/`](jfuse-examples). You basi
var builder = Fuse.builder();
var fs = new MyFileSystem(builder.errno());
try (var fuse = builder.build(fs)) {
int result = fuse.mount("my-awesome-fs", mountPoint);
// thread will now block until unmounted or failed
}
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.:
Expand All @@ -88,10 +92,10 @@ java -p path/to/mods \

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-linux-amd64) | [jfuse-mac](jfuse-mac) | [jfuse-win-amd64](jfuse-win-amd64) |
| arm64 | [jfuse-linux-aarch64](jfuse-linux-aarch64) | [jfuse-mac](jfuse-mac) | |
| | Linux | Mac (macFUSE) | Windows (WinFSP) |
|--------|--------------------------------------------|--------------------------|--------------------------------------|
| x86_64 | [jfuse-linux-amd64](jfuse-linux-amd64) | [jfuse-mac](jfuse-mac) | [jfuse-win-amd64](jfuse-win-amd64) |
| arm64 | [jfuse-linux-aarch64](jfuse-linux-aarch64) | [jfuse-mac](jfuse-mac) | |

## Building

Expand Down
2 changes: 1 addition & 1 deletion jfuse-api/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
<parent>
<groupId>org.cryptomator</groupId>
<artifactId>jfuse</artifactId>
<version>0.1.0</version>
<version>0.2.0</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>jfuse-api</artifactId>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,16 @@ public enum Architecture {
UNKNOWN;

private static final String OS_ARCH = System.getProperty("os.arch").toLowerCase();
public static final Architecture CURRENT = OS_ARCH.contains("x86_64") ? AMD64 //
: OS_ARCH.contains("amd64") ? AMD64 //
: OS_ARCH.contains("aarch64") ? ARM64 //
: UNKNOWN;
public static final Architecture CURRENT = getCurrent();

private static Architecture getCurrent() {
if (OS_ARCH.contains("x86_64") || OS_ARCH.contains("amd64")) {
return AMD64;
} else if (OS_ARCH.contains("aarch64")) {
return ARM64;
} else {
return UNKNOWN;
}
}
}

77 changes: 33 additions & 44 deletions jfuse-api/src/main/java/org/cryptomator/jfuse/api/DirFiller.java
Original file line number Diff line number Diff line change
@@ -1,69 +1,58 @@
package org.cryptomator.jfuse.api;

import org.jetbrains.annotations.Nullable;

import java.io.IOException;
import java.util.stream.Stream;
import java.util.function.Consumer;

public interface DirFiller {

/**
* Inserts a single item into the directory entry buffer.
*
* @param name The file name
* @param stat Currently ignored, future use
* @param offset The offset of the readdir-call plus the number of already filled entries
* @return 0 if readdir should continue to fill in further items, non-zero otherwise (including errors)
* @see <a href="https://libfuse.github.io/doxygen/structfuse__operations.html#adc01d3622754fc7de8e643249e73268d">official readdir docs</a>
* @see <a href="https://www.cs.hmc.edu/~geoff/classes/hmc.cs135.201001/homework/fuse/fuse_doc.html#readdir-details">readdir explanation from Geoff Kuenning</a>
* "Plus" mode: all file attributes are valid.
* <p>
* The attributes are used by the kernel to prefill the inode cache during a readdir.
* <p>
* It is okay to set FUSE_FILL_DIR_PLUS if {@link FuseOperations#FUSE_READDIR_PLUS FUSE_READDIR_PLUS} is not set
* and vice versa.
*/
int fill(String name, @Nullable Stat stat, long offset);
int FUSE_FILL_DIR_PLUS = 1 << 1;

/**
* Convenience wrapper for {@link #fill(String, Stat, long)}, ignoring the offset parameter.
* Function to add an entry in a readdir() operation
* <p>
* The off parameter can be any non-zero value that enables the filesystem to identify the current point in the
* directory stream. It does not need to be the actual physical position. A value of zero is reserved to indicate
* that seeking in directories is not supported.
*
* @param name The file name
* @param stat Currently ignored, future use.
* @throws IOException If {@link #fill(String, Stat, long) fuse_fill_dir_t} returns 1, which indicates an error.
* @param name the file name of the directory entry
* @param stat file attributes, can be NULL
* @param offset offset of the next entry or zero when ignoring the offset parameter
* @param flags fill flags, set to {@link #FUSE_FILL_DIR_PLUS} to cache stats
* @return 1 if buffer is full or an error occured, zero otherwise
* @see <a href="https://libfuse.github.io/doxygen/structfuse__operations.html#adc01d3622754fc7de8e643249e73268d">official readdir docs</a>
* @see <a href="https://www.cs.hmc.edu/~geoff/classes/hmc.cs135.201001/homework/fuse/fuse_doc.html#readdir-details">readdir explanation from Geoff Kuenning</a>
*/
default void fill(String name, @Nullable Stat stat) throws IOException {
if (fill(name, stat, 0) != 0) {
throw new IOException("fuse_fill_dir_t unexpectedly returned 1");
}
}
int fill(String name, Consumer<Stat> stat, long offset, int flags);

/**
* Convenience wrapper for {@link #fill(String, Stat, long)}, using the offset parameter.
* <p>
* <strong>Important:</strong> Note that the complete set of directors entries must contain <code>.</code> and <code>..</code>.
* Convenience wrapper for {@link #fill(String, Consumer, long, int)}, ignoring the offset parameter.
*
* @param children A stream of directory entries offset by the given <code>offset</code>
* @param offset The offset of the stream (as requested by <code>readdir</code>)
* @param name The file name
* @param stat A method to pre-fill the stats of this node
* @throws IOException If {@link #fill(String, Consumer, long, int) fuse_fill_dir_t} returns 1, which indicates an error.
*/
default void fillChildrenFromOffset(Stream<Child> children, long offset) {
var iterator = children.iterator();
for (long i = offset; iterator.hasNext(); i++) {
var child = iterator.next();
if (fill(child.name, child.stat, i + 1) != 0) {
return;
}
default void fill(String name, Consumer<Stat> stat) throws IOException {
if (fill(name, stat, 0, 0) != 0) {
throw new IOException("fuse_fill_dir_t unexpectedly returned 1");
}
}

/**
* Convenience wrapper for {@link #fill(String, Stat, long)}, using the offset parameter.
* <p>
* <strong>Important:</strong> Note that the complete set of directors entries must contain <code>.</code> and <code>..</code>.
* Convenienve wrapper for {@link #fill(String, Consumer, long, int)}, just filling in the name, ignoring stats.
*
* @param childNames A stream of the names of directory entries offset by the given <code>offset</code>
* @param offset The offset of the stream (as requested by <code>readdir</code>)
* @param name The file name
* @throws IOException If {@link #fill(String, Consumer, long, int) fuse_fill_dir_t} returns 1, which indicates an error.
*/
default void fillNamesFromOffset(Stream<String> childNames, long offset) {
var children = childNames.map(name -> new Child(name, null));
fillChildrenFromOffset(children, offset);
}

record Child(String name, @Nullable Stat stat) {
default void fill(String name) throws IOException {
fill(name, stat -> {});
}

}
16 changes: 8 additions & 8 deletions jfuse-api/src/main/java/org/cryptomator/jfuse/api/FileModes.java
Original file line number Diff line number Diff line change
Expand Up @@ -31,14 +31,14 @@ public static Set<PosixFilePermission> toPermissions(int mode) {
public static int fromPermissions(Set<PosixFilePermission> permissions) {
int mode = 0;
// @formatter:off
if (permissions.contains(PosixFilePermission.OWNER_READ)) mode |= 0400;
if (permissions.contains(PosixFilePermission.OWNER_WRITE)) mode |= 0200;
if (permissions.contains(PosixFilePermission.OWNER_EXECUTE)) mode |= 0100;
if (permissions.contains(PosixFilePermission.GROUP_READ)) mode |= 0040;
if (permissions.contains(PosixFilePermission.GROUP_WRITE)) mode |= 0020;
if (permissions.contains(PosixFilePermission.GROUP_EXECUTE)) mode |= 0010;
if (permissions.contains(PosixFilePermission.OTHERS_READ)) mode |= 0004;
if (permissions.contains(PosixFilePermission.OTHERS_WRITE)) mode |= 0002;
if (permissions.contains(PosixFilePermission.OWNER_READ)) mode |= 0400;
if (permissions.contains(PosixFilePermission.OWNER_WRITE)) mode |= 0200;
if (permissions.contains(PosixFilePermission.OWNER_EXECUTE)) mode |= 0100;
if (permissions.contains(PosixFilePermission.GROUP_READ)) mode |= 0040;
if (permissions.contains(PosixFilePermission.GROUP_WRITE)) mode |= 0020;
if (permissions.contains(PosixFilePermission.GROUP_EXECUTE)) mode |= 0010;
if (permissions.contains(PosixFilePermission.OTHERS_READ)) mode |= 0004;
if (permissions.contains(PosixFilePermission.OTHERS_WRITE)) mode |= 0002;
if (permissions.contains(PosixFilePermission.OTHERS_EXECUTE)) mode |= 0001;
// @formatter:on
return mode;
Expand Down
Loading

0 comments on commit 1f54357

Please sign in to comment.