diff --git a/jfuse-api/pom.xml b/jfuse-api/pom.xml
index fbc7e93a..e3472271 100644
--- a/jfuse-api/pom.xml
+++ b/jfuse-api/pom.xml
@@ -5,7 +5,7 @@
org.cryptomator
jfuse-parent
- 0.6.2
+ 0.6.3
4.0.0
jfuse-api
diff --git a/jfuse-api/src/main/java/module-info.java b/jfuse-api/src/main/java/module-info.java
index 45a46b4f..16df27ab 100644
--- a/jfuse-api/src/main/java/module-info.java
+++ b/jfuse-api/src/main/java/module-info.java
@@ -10,6 +10,7 @@
exports org.cryptomator.jfuse.api;
exports org.cryptomator.jfuse.api.platforms to org.cryptomator.jfuse.linux.aarch64, org.cryptomator.jfuse.linux.amd64, org.cryptomator.jfuse.mac, org.cryptomator.jfuse.win;
+ exports org.cryptomator.jfuse.api.util to org.cryptomator.jfuse.linux.aarch64, org.cryptomator.jfuse.linux.amd64, org.cryptomator.jfuse.mac, org.cryptomator.jfuse.win;
uses FuseBuilder;
}
\ No newline at end of file
diff --git a/jfuse-api/src/main/java/org/cryptomator/jfuse/api/util/MemoryUtils.java b/jfuse-api/src/main/java/org/cryptomator/jfuse/api/util/MemoryUtils.java
new file mode 100644
index 00000000..100c3b73
--- /dev/null
+++ b/jfuse-api/src/main/java/org/cryptomator/jfuse/api/util/MemoryUtils.java
@@ -0,0 +1,18 @@
+package org.cryptomator.jfuse.api.util;
+
+import org.jetbrains.annotations.Nullable;
+
+import java.lang.foreign.MemorySegment;
+
+public class MemoryUtils {
+
+ @Nullable
+ public static String toUtf8StringOrNull(MemorySegment string, long offset) {
+ return MemorySegment.NULL.equals(string) ? null : string.getUtf8String(offset);
+ }
+
+ @Nullable
+ public static String toUtf8StringOrNull(MemorySegment string) {
+ return toUtf8StringOrNull(string, 0);
+ }
+}
diff --git a/jfuse-api/src/test/java/org/cryptomator/jfuse/api/FuseTest.java b/jfuse-api/src/test/java/org/cryptomator/jfuse/api/FuseTest.java
index fa1ea532..b2630bb0 100644
--- a/jfuse-api/src/test/java/org/cryptomator/jfuse/api/FuseTest.java
+++ b/jfuse-api/src/test/java/org/cryptomator/jfuse/api/FuseTest.java
@@ -50,7 +50,7 @@ public void testWaitForMountingToComplete() throws IOException {
@Test
@DisplayName("waitForMountingToComplete() waits returns immediately if fuse_loop fails")
- public void testPrematurelyFuseLoopReturn() throws IOException {
+ public void testPrematurelyFuseLoopReturn() {
Path probePath = Mockito.mock(Path.class, "/mnt/jfuse_mount_probe");
FileSystem fs = Mockito.mock(FileSystem.class);
FileSystemProvider fsProv = Mockito.mock(FileSystemProvider.class);
@@ -76,7 +76,13 @@ public void testMountThrowsIllegalStateIfClosed() {
@Test
@DisplayName("Already mounted fuseMount throws IllegalStateException on mount")
public void testMountThrowsIllegalStateIfAlreadyMounted() throws InterruptedException {
+ // mount probe succeeds immediately...
Mockito.doNothing().when(fuse).waitForMountingToComplete(Mockito.eq(mountPoint), Mockito.any());
+ // ... before fuse_loop returns
+ Mockito.doAnswer(invocation -> {
+ Thread.sleep(1000);
+ return 0;
+ }).when(fuseMount).loop();
Assertions.assertDoesNotThrow(() -> fuse.mount("test3000", mountPoint));
Assertions.assertThrows(IllegalStateException.class, () -> fuse.mount("test3000", mountPoint));
}
@@ -84,10 +90,12 @@ public void testMountThrowsIllegalStateIfAlreadyMounted() throws InterruptedExce
@Test
@DisplayName("If fuse_loop instantly returns with non-zero result, throw FuseMountFailedException")
public void testMountThrowsFuseMountFailedIfLoopReturnsNonZero() throws InterruptedException {
+ // mount probe takes a while...
Mockito.doAnswer(invocation -> {
Thread.sleep(1000);
return null;
}).when(fuse).waitForMountingToComplete(Mockito.eq(mountPoint), Mockito.any());
+ // ... but fuse_loop returns immediately (with error)
Mockito.doReturn(1).when(fuseMount).loop();
Assertions.assertThrows(FuseMountFailedException.class, () -> fuse.mount("test3000", mountPoint));
}
diff --git a/jfuse-api/src/test/java/org/cryptomator/jfuse/api/util/MemoryUtilsTest.java b/jfuse-api/src/test/java/org/cryptomator/jfuse/api/util/MemoryUtilsTest.java
new file mode 100644
index 00000000..ad4c2ab8
--- /dev/null
+++ b/jfuse-api/src/test/java/org/cryptomator/jfuse/api/util/MemoryUtilsTest.java
@@ -0,0 +1,41 @@
+package org.cryptomator.jfuse.api.util;
+
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.DisplayName;
+import org.junit.jupiter.api.Test;
+
+import java.lang.foreign.Arena;
+import java.lang.foreign.MemorySegment;
+
+public class MemoryUtilsTest {
+
+
+ @Test
+ @DisplayName("On MemorySegment != NULL pointer, method returns utf8 string in the memory region")
+ void testValidSegmentReturnsString() {
+ try (var arena = Arena.ofConfined()) {
+ var address = arena.allocate(4);
+ address.setUtf8String(0, "abc");
+ String result = MemoryUtils.toUtf8StringOrNull(address);
+ Assertions.assertEquals("abc", result);
+ }
+ }
+
+ @Test
+ @DisplayName("With offset, on MemorySegment != NULL pointer, method returns utf8 string in the memory region")
+ void testValidSegmentReturnsStringAtOffset() {
+ try (var arena = Arena.ofConfined()) {
+ var address = arena.allocate(10);
+ address.setUtf8String(5, "abc");
+ String result = MemoryUtils.toUtf8StringOrNull(address, 5);
+ Assertions.assertEquals("abc", result);
+ }
+ }
+
+ @Test
+ @DisplayName("When MemorySegment == NULL pointer, method returns null")
+ void testNullPointerSegmentReturnsNull() {
+ String result = MemoryUtils.toUtf8StringOrNull(MemorySegment.NULL, 0);
+ Assertions.assertNull(result);
+ }
+}
diff --git a/jfuse-examples/pom.xml b/jfuse-examples/pom.xml
index 436493d6..ef8549a9 100644
--- a/jfuse-examples/pom.xml
+++ b/jfuse-examples/pom.xml
@@ -5,7 +5,7 @@
org.cryptomator
jfuse-parent
- 0.6.2
+ 0.6.3
4.0.0
jfuse-examples
diff --git a/jfuse-linux-aarch64/pom.xml b/jfuse-linux-aarch64/pom.xml
index 8f0c896d..a5d3b388 100644
--- a/jfuse-linux-aarch64/pom.xml
+++ b/jfuse-linux-aarch64/pom.xml
@@ -5,7 +5,7 @@
jfuse-parent
org.cryptomator
- 0.6.2
+ 0.6.3
4.0.0
jfuse-linux-aarch64
diff --git a/jfuse-linux-aarch64/src/main/java/org/cryptomator/jfuse/linux/aarch64/FileInfoImpl.java b/jfuse-linux-aarch64/src/main/java/org/cryptomator/jfuse/linux/aarch64/FileInfoImpl.java
index 9f83c786..e3017038 100644
--- a/jfuse-linux-aarch64/src/main/java/org/cryptomator/jfuse/linux/aarch64/FileInfoImpl.java
+++ b/jfuse-linux-aarch64/src/main/java/org/cryptomator/jfuse/linux/aarch64/FileInfoImpl.java
@@ -3,6 +3,7 @@
import org.cryptomator.jfuse.api.FileInfo;
import org.cryptomator.jfuse.linux.aarch64.extr.fcntl.fcntl_h;
import org.cryptomator.jfuse.linux.aarch64.extr.fuse3.fuse_file_info;
+import org.jetbrains.annotations.Nullable;
import java.lang.foreign.Arena;
import java.lang.foreign.MemorySegment;
@@ -22,6 +23,18 @@ record FileInfoImpl(MemorySegment segment) implements FileInfo {
private static final int O_SYNC = fcntl_h.O_SYNC();
private static final int O_DSYNC = fcntl_h.O_DSYNC();
+ /**
+ * Factory method to map native memory to an {@link FileInfo} object
+ *
+ * @param address the {@link MemorySegment} representing the starting address
+ * @param scope the {@link Arena} in which this object will be alive
+ * @return an {@link FileInfo} object or {@code null} if {@code address} is a NULL pointer
+ */
+ @Nullable
+ public static FileInfoImpl of(MemorySegment address, Arena scope) {
+ return MemorySegment.NULL.equals(address) ? null : new FileInfoImpl(address, scope);
+ }
+
public FileInfoImpl(MemorySegment address, Arena scope) {
this(fuse_file_info.ofAddress(address, scope));
}
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 5442c7f0..f2a91ace 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
@@ -5,6 +5,7 @@
import org.cryptomator.jfuse.api.FuseMount;
import org.cryptomator.jfuse.api.FuseMountFailedException;
import org.cryptomator.jfuse.api.FuseOperations;
+import org.cryptomator.jfuse.api.util.MemoryUtils;
import org.cryptomator.jfuse.linux.aarch64.extr.fuse3.fuse_args;
import org.cryptomator.jfuse.linux.aarch64.extr.fuse3.fuse_h;
import org.cryptomator.jfuse.linux.aarch64.extr.fuse3.fuse_operations;
@@ -116,14 +117,14 @@ private int access(MemorySegment path, int mask) {
private int chmod(MemorySegment path, int mode, MemorySegment fi) {
try (var arena = Arena.ofConfined()) {
- return fuseOperations.chmod(path.getUtf8String(0), mode, new FileInfoImpl(fi, arena));
+ return fuseOperations.chmod(path.getUtf8String(0), mode, FileInfoImpl.of(fi, arena));
}
}
@VisibleForTesting
int chown(MemorySegment path, int uid, int gid, MemorySegment fi) {
try (var arena = Arena.ofConfined()) {
- return fuseOperations.chown(path.getUtf8String(0), uid, gid, new FileInfoImpl(fi, arena));
+ return fuseOperations.chown(path.getUtf8String(0), uid, gid, FileInfoImpl.of(fi, arena));
}
}
@@ -154,13 +155,13 @@ int fsync(MemorySegment path, int datasync, MemorySegment fi) {
@VisibleForTesting
int fsyncdir(MemorySegment path, int datasync, MemorySegment fi) {
try (var arena = Arena.ofConfined()) {
- return fuseOperations.fsyncdir(path.getUtf8String(0), datasync, new FileInfoImpl(fi, arena));
+ return fuseOperations.fsyncdir(MemoryUtils.toUtf8StringOrNull(path), datasync, new FileInfoImpl(fi, arena));
}
}
private int getattr(MemorySegment path, MemorySegment stat, MemorySegment fi) {
try (var arena = Arena.ofConfined()) {
- return fuseOperations.getattr(path.getUtf8String(0), new StatImpl(stat, arena), new FileInfoImpl(fi, arena));
+ return fuseOperations.getattr(path.getUtf8String(0), new StatImpl(stat, arena), FileInfoImpl.of(fi, arena));
}
}
@@ -229,7 +230,7 @@ private int release(MemorySegment path, MemorySegment fi) {
private int releasedir(MemorySegment path, MemorySegment fi) {
try (var arena = Arena.ofConfined()) {
- return fuseOperations.releasedir(path.getUtf8String(0), new FileInfoImpl(fi, arena));
+ return fuseOperations.releasedir(MemoryUtils.toUtf8StringOrNull(path), new FileInfoImpl(fi, arena));
}
}
@@ -253,7 +254,7 @@ private int symlink(MemorySegment linkname, MemorySegment target) {
private int truncate(MemorySegment path, long size, MemorySegment fi) {
try (var arena = Arena.ofConfined()) {
- return fuseOperations.truncate(path.getUtf8String(0), size, new FileInfoImpl(fi, arena));
+ return fuseOperations.truncate(path.getUtf8String(0), size, FileInfoImpl.of(fi, arena));
}
}
@@ -271,11 +272,11 @@ int utimens(MemorySegment path, MemorySegment times, MemorySegment fi) {
timespec.tv_sec$set(segment, 0);
timespec.tv_nsec$set(segment, stat_h.UTIME_NOW());
var time = new TimeSpecImpl(segment);
- return fuseOperations.utimens(path.getUtf8String(0), time, time, new FileInfoImpl(fi, arena));
+ return fuseOperations.utimens(path.getUtf8String(0), time, time, FileInfoImpl.of(fi, arena));
} else {
var time0 = times.asSlice(0, timespec.$LAYOUT().byteSize());
var time1 = times.asSlice(timespec.$LAYOUT().byteSize(), timespec.$LAYOUT().byteSize());
- return fuseOperations.utimens(path.getUtf8String(0), new TimeSpecImpl(time0), new TimeSpecImpl(time1), new FileInfoImpl(fi, arena));
+ return fuseOperations.utimens(path.getUtf8String(0), new TimeSpecImpl(time0), new TimeSpecImpl(time1), FileInfoImpl.of(fi, arena));
}
}
}
diff --git a/jfuse-linux-amd64/pom.xml b/jfuse-linux-amd64/pom.xml
index a21062a0..93623607 100644
--- a/jfuse-linux-amd64/pom.xml
+++ b/jfuse-linux-amd64/pom.xml
@@ -5,7 +5,7 @@
org.cryptomator
jfuse-parent
- 0.6.2
+ 0.6.3
4.0.0
jfuse-linux-amd64
diff --git a/jfuse-linux-amd64/src/main/java/org/cryptomator/jfuse/linux/amd64/FileInfoImpl.java b/jfuse-linux-amd64/src/main/java/org/cryptomator/jfuse/linux/amd64/FileInfoImpl.java
index eda24c72..e687f6fa 100644
--- a/jfuse-linux-amd64/src/main/java/org/cryptomator/jfuse/linux/amd64/FileInfoImpl.java
+++ b/jfuse-linux-amd64/src/main/java/org/cryptomator/jfuse/linux/amd64/FileInfoImpl.java
@@ -3,6 +3,7 @@
import org.cryptomator.jfuse.api.FileInfo;
import org.cryptomator.jfuse.linux.amd64.extr.fcntl.fcntl_h;
import org.cryptomator.jfuse.linux.amd64.extr.fuse3.fuse_file_info;
+import org.jetbrains.annotations.Nullable;
import java.lang.foreign.Arena;
import java.lang.foreign.MemorySegment;
@@ -22,6 +23,18 @@ record FileInfoImpl(MemorySegment segment) implements FileInfo {
private static final int O_SYNC = fcntl_h.O_SYNC();
private static final int O_DSYNC = fcntl_h.O_DSYNC();
+ /**
+ * Factory method to map native memory to an {@link FileInfo} object
+ *
+ * @param address the {@link MemorySegment} representing the starting address
+ * @param scope the {@link Arena} in which this object will be alive
+ * @return an {@link FileInfo} object or {@code null} if {@code address} is a NULL pointer
+ */
+ @Nullable
+ public static FileInfoImpl of(MemorySegment address, Arena scope) {
+ return MemorySegment.NULL.equals(address) ? null : new FileInfoImpl(address, scope);
+ }
+
public FileInfoImpl(MemorySegment address, Arena scope) {
this(fuse_file_info.ofAddress(address, scope));
}
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 e6dfe26c..dc4ef78c 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
@@ -5,6 +5,7 @@
import org.cryptomator.jfuse.api.FuseMount;
import org.cryptomator.jfuse.api.FuseMountFailedException;
import org.cryptomator.jfuse.api.FuseOperations;
+import org.cryptomator.jfuse.api.util.MemoryUtils;
import org.cryptomator.jfuse.linux.amd64.extr.fuse3.fuse_args;
import org.cryptomator.jfuse.linux.amd64.extr.fuse3.fuse_h;
import org.cryptomator.jfuse.linux.amd64.extr.fuse3.fuse_operations;
@@ -116,14 +117,14 @@ private int access(MemorySegment path, int mask) {
private int chmod(MemorySegment path, int mode, MemorySegment fi) {
try (var arena = Arena.ofConfined()) {
- return fuseOperations.chmod(path.getUtf8String(0), mode, new FileInfoImpl(fi, arena));
+ return fuseOperations.chmod(path.getUtf8String(0), mode, FileInfoImpl.of(fi, arena));
}
}
@VisibleForTesting
int chown(MemorySegment path, int uid, int gid, MemorySegment fi) {
try (var arena = Arena.ofConfined()) {
- return fuseOperations.chown(path.getUtf8String(0), uid, gid, new FileInfoImpl(fi, arena));
+ return fuseOperations.chown(path.getUtf8String(0), uid, gid, FileInfoImpl.of(fi, arena));
}
}
@@ -154,13 +155,13 @@ int fsync(MemorySegment path, int datasync, MemorySegment fi) {
@VisibleForTesting
int fsyncdir(MemorySegment path, int datasync, MemorySegment fi) {
try (var arena = Arena.ofConfined()) {
- return fuseOperations.fsyncdir(path.getUtf8String(0), datasync, new FileInfoImpl(fi, arena));
+ return fuseOperations.fsyncdir(MemoryUtils.toUtf8StringOrNull(path), datasync, new FileInfoImpl(fi, arena));
}
}
private int getattr(MemorySegment path, MemorySegment stat, MemorySegment fi) {
try (var arena = Arena.ofConfined()) {
- return fuseOperations.getattr(path.getUtf8String(0), new StatImpl(stat, arena), new FileInfoImpl(fi, arena));
+ return fuseOperations.getattr(path.getUtf8String(0), new StatImpl(stat, arena), FileInfoImpl.of(fi, arena));
}
}
@@ -229,7 +230,7 @@ private int release(MemorySegment path, MemorySegment fi) {
private int releasedir(MemorySegment path, MemorySegment fi) {
try (var arena = Arena.ofConfined()) {
- return fuseOperations.releasedir(path.getUtf8String(0), new FileInfoImpl(fi, arena));
+ return fuseOperations.releasedir(MemoryUtils.toUtf8StringOrNull(path), new FileInfoImpl(fi, arena));
}
}
@@ -253,7 +254,7 @@ private int symlink(MemorySegment linkname, MemorySegment target) {
private int truncate(MemorySegment path, long size, MemorySegment fi) {
try (var arena = Arena.ofConfined()) {
- return fuseOperations.truncate(path.getUtf8String(0), size, new FileInfoImpl(fi, arena));
+ return fuseOperations.truncate(path.getUtf8String(0), size, FileInfoImpl.of(fi, arena));
}
}
@@ -270,11 +271,11 @@ int utimens(MemorySegment path, MemorySegment times, MemorySegment fi) {
timespec.tv_sec$set(segment, 0);
timespec.tv_nsec$set(segment, stat_h.UTIME_NOW());
var time = new TimeSpecImpl(segment);
- return fuseOperations.utimens(path.getUtf8String(0), time, time, new FileInfoImpl(fi, arena));
+ return fuseOperations.utimens(path.getUtf8String(0), time, time, FileInfoImpl.of(fi, arena));
} else {
var time0 = times.asSlice(0, timespec.$LAYOUT().byteSize());
var time1 = times.asSlice(timespec.$LAYOUT().byteSize(), timespec.$LAYOUT().byteSize());
- return fuseOperations.utimens(path.getUtf8String(0), new TimeSpecImpl(time0), new TimeSpecImpl(time1), new FileInfoImpl(fi, arena));
+ return fuseOperations.utimens(path.getUtf8String(0), new TimeSpecImpl(time0), new TimeSpecImpl(time1), FileInfoImpl.of(fi, arena));
}
}
}
diff --git a/jfuse-mac/pom.xml b/jfuse-mac/pom.xml
index 38a0b02e..17807d3c 100644
--- a/jfuse-mac/pom.xml
+++ b/jfuse-mac/pom.xml
@@ -5,7 +5,7 @@
org.cryptomator
jfuse-parent
- 0.6.2
+ 0.6.3
4.0.0
jfuse-mac
diff --git a/jfuse-mac/src/main/java/org/cryptomator/jfuse/mac/FuseImpl.java b/jfuse-mac/src/main/java/org/cryptomator/jfuse/mac/FuseImpl.java
index 5bf21d69..58232d94 100644
--- a/jfuse-mac/src/main/java/org/cryptomator/jfuse/mac/FuseImpl.java
+++ b/jfuse-mac/src/main/java/org/cryptomator/jfuse/mac/FuseImpl.java
@@ -4,6 +4,7 @@
import org.cryptomator.jfuse.api.FuseMount;
import org.cryptomator.jfuse.api.FuseMountFailedException;
import org.cryptomator.jfuse.api.FuseOperations;
+import org.cryptomator.jfuse.api.util.MemoryUtils;
import org.cryptomator.jfuse.mac.extr.fuse.fuse_args;
import org.cryptomator.jfuse.mac.extr.fuse.fuse_h;
import org.cryptomator.jfuse.mac.extr.fuse.fuse_operations;
@@ -154,7 +155,7 @@ int fsync(MemorySegment path, int datasync, MemorySegment fi) {
@VisibleForTesting
int fsyncdir(MemorySegment path, int datasync, MemorySegment fi) {
try (var arena = Arena.ofConfined()) {
- return fuseOperations.fsyncdir(path.getUtf8String(0), datasync, new FileInfoImpl(fi, arena));
+ return fuseOperations.fsyncdir(MemoryUtils.toUtf8StringOrNull(path), datasync, new FileInfoImpl(fi, arena));
}
}
@@ -237,7 +238,7 @@ private int release(MemorySegment path, MemorySegment fi) {
private int releasedir(MemorySegment path, MemorySegment fi) {
try (var arena = Arena.ofConfined()) {
- return fuseOperations.releasedir(path.getUtf8String(0), new FileInfoImpl(fi, arena));
+ return fuseOperations.releasedir(MemoryUtils.toUtf8StringOrNull(path), new FileInfoImpl(fi, arena));
}
}
diff --git a/jfuse-tests/pom.xml b/jfuse-tests/pom.xml
index 40528870..3fcace78 100644
--- a/jfuse-tests/pom.xml
+++ b/jfuse-tests/pom.xml
@@ -5,7 +5,7 @@
org.cryptomator
jfuse-parent
- 0.6.2
+ 0.6.3
4.0.0
jfuse-tests
diff --git a/jfuse-win/pom.xml b/jfuse-win/pom.xml
index 2921aace..8dca5bc9 100644
--- a/jfuse-win/pom.xml
+++ b/jfuse-win/pom.xml
@@ -5,7 +5,7 @@
org.cryptomator
jfuse-parent
- 0.6.2
+ 0.6.3
4.0.0
jfuse-win
diff --git a/jfuse-win/src/main/java/org/cryptomator/jfuse/win/FileInfoImpl.java b/jfuse-win/src/main/java/org/cryptomator/jfuse/win/FileInfoImpl.java
index 33e9c17f..dd9f18bf 100644
--- a/jfuse-win/src/main/java/org/cryptomator/jfuse/win/FileInfoImpl.java
+++ b/jfuse-win/src/main/java/org/cryptomator/jfuse/win/FileInfoImpl.java
@@ -3,6 +3,7 @@
import org.cryptomator.jfuse.api.FileInfo;
import org.cryptomator.jfuse.win.extr.fcntl.fcntl_h;
import org.cryptomator.jfuse.win.extr.fuse3.fuse3_file_info;
+import org.jetbrains.annotations.Nullable;
import java.lang.foreign.Arena;
import java.lang.foreign.MemorySegment;
@@ -20,6 +21,18 @@ record FileInfoImpl(MemorySegment segment) implements FileInfo {
private static final int O_TRUNC = fcntl_h.O_TRUNC();
private static final int O_EXCL = fcntl_h.O_EXCL();
+ /**
+ * Factory method to map native memory to an {@link FileInfo} object
+ *
+ * @param address the {@link MemorySegment} representing the starting address
+ * @param scope the {@link Arena} in which this object will be alive
+ * @return an {@link FileInfo} object or {@code null} if {@code address} is a NULL pointer
+ */
+ @Nullable
+ public static FileInfoImpl of(MemorySegment address, Arena scope) {
+ return MemorySegment.NULL.equals(address) ? null : new FileInfoImpl(address, scope);
+ }
+
public FileInfoImpl(MemorySegment address, Arena scope) {
this(fuse3_file_info.ofAddress(address, scope));
}
diff --git a/jfuse-win/src/main/java/org/cryptomator/jfuse/win/FuseImpl.java b/jfuse-win/src/main/java/org/cryptomator/jfuse/win/FuseImpl.java
index bce9878d..3a6f59b0 100644
--- a/jfuse-win/src/main/java/org/cryptomator/jfuse/win/FuseImpl.java
+++ b/jfuse-win/src/main/java/org/cryptomator/jfuse/win/FuseImpl.java
@@ -5,6 +5,7 @@
import org.cryptomator.jfuse.api.FuseMount;
import org.cryptomator.jfuse.api.FuseMountFailedException;
import org.cryptomator.jfuse.api.FuseOperations;
+import org.cryptomator.jfuse.api.util.MemoryUtils;
import org.cryptomator.jfuse.win.extr.fuse2.fuse2_h;
import org.cryptomator.jfuse.win.extr.fuse2.fuse_args;
import org.cryptomator.jfuse.win.extr.fuse3.fuse3_operations;
@@ -125,14 +126,14 @@ MemorySegment init(MemorySegment conn, MemorySegment cfg) {
private int chmod(MemorySegment path, int mode, MemorySegment fi) {
try (var arena = Arena.ofConfined()) {
- return fuseOperations.chmod(path.getUtf8String(0), mode, new FileInfoImpl(fi, arena));
+ return fuseOperations.chmod(path.getUtf8String(0), mode, FileInfoImpl.of(fi, arena));
}
}
@VisibleForTesting
int chown(MemorySegment path, int uid, int gid, MemorySegment fi) {
try (var arena = Arena.ofConfined()) {
- return fuseOperations.chown(path.getUtf8String(0), uid, gid, new FileInfoImpl(fi, arena));
+ return fuseOperations.chown(path.getUtf8String(0), uid, gid, FileInfoImpl.of(fi, arena));
}
}
@@ -163,14 +164,14 @@ int fsync(MemorySegment path, int datasync, MemorySegment fi) {
@VisibleForTesting
int fsyncdir(MemorySegment path, int datasync, MemorySegment fi) {
try (var arena = Arena.ofConfined()) {
- return fuseOperations.fsyncdir(path.getUtf8String(0), datasync, new FileInfoImpl(fi, arena));
+ return fuseOperations.fsyncdir(MemoryUtils.toUtf8StringOrNull(path), datasync, new FileInfoImpl(fi, arena));
}
}
@VisibleForTesting
int getattr(MemorySegment path, MemorySegment stat, MemorySegment fi) {
try (var arena = Arena.ofConfined()) {
- return fuseOperations.getattr(path.getUtf8String(0), new StatImpl(stat, arena), new FileInfoImpl(fi, arena));
+ return fuseOperations.getattr(path.getUtf8String(0), new StatImpl(stat, arena), FileInfoImpl.of(fi, arena));
}
}
@@ -239,7 +240,7 @@ private int release(MemorySegment path, MemorySegment fi) {
private int releasedir(MemorySegment path, MemorySegment fi) {
try (var arena = Arena.ofConfined()) {
- return fuseOperations.releasedir(path.getUtf8String(0), new FileInfoImpl(fi, arena));
+ return fuseOperations.releasedir(MemoryUtils.toUtf8StringOrNull(path), new FileInfoImpl(fi, arena));
}
}
@@ -264,7 +265,7 @@ private int symlink(MemorySegment linkname, MemorySegment target) {
@VisibleForTesting
int truncate(MemorySegment path, long size, MemorySegment fi) {
try (var arena = Arena.ofConfined()) {
- return fuseOperations.truncate(path.getUtf8String(0), size, new FileInfoImpl(fi, arena));
+ return fuseOperations.truncate(path.getUtf8String(0), size, FileInfoImpl.of(fi, arena));
}
}
@@ -281,7 +282,7 @@ int utimens(MemorySegment path, MemorySegment times, MemorySegment fi) {
var segment = times.reinterpret(seq.byteSize());
var time0 = segment.asSlice(0, fuse_timespec.$LAYOUT().byteSize());
var time1 = segment.asSlice(fuse_timespec.$LAYOUT().byteSize(), fuse_timespec.$LAYOUT().byteSize());
- return fuseOperations.utimens(path.getUtf8String(0), new TimeSpecImpl(time0), new TimeSpecImpl(time1), new FileInfoImpl(fi, arena));
+ return fuseOperations.utimens(path.getUtf8String(0), new TimeSpecImpl(time0), new TimeSpecImpl(time1), FileInfoImpl.of(fi, arena));
}
}
diff --git a/jfuse/pom.xml b/jfuse/pom.xml
index 4760d518..d0456ba0 100644
--- a/jfuse/pom.xml
+++ b/jfuse/pom.xml
@@ -5,7 +5,7 @@
org.cryptomator
jfuse-parent
- 0.6.2
+ 0.6.3
4.0.0
jfuse
diff --git a/pom.xml b/pom.xml
index 3b70e9c2..27206973 100644
--- a/pom.xml
+++ b/pom.xml
@@ -6,7 +6,7 @@
org.cryptomator
jfuse-parent
pom
- 0.6.2
+ 0.6.3
jFUSE
Java bindings for FUSE using foreign functions & memory API
https://github.com/cryptomator/jfuse
@@ -66,7 +66,7 @@
org.mockito
mockito-core
- 5.5.0
+ 5.6.0
test