From d80a638d5f7875a3248ea39a08ade6752c5aff24 Mon Sep 17 00:00:00 2001 From: Sebastian Stenzel Date: Mon, 9 Oct 2023 11:57:22 +0200 Subject: [PATCH 01/13] cleanup --- .../src/test/java/org/cryptomator/jfuse/api/FuseTest.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) 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..ae0d8402 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 @@ -33,10 +33,10 @@ public void testWaitForMountingToComplete() throws IOException { Mockito.doReturn(fs).when(probePath).getFileSystem(); Mockito.doReturn(fsProv).when(fs).provider(); Mockito.doReturn(attrView).when(fsProv).getFileAttributeView(probePath, BasicFileAttributeView.class); - Mockito.doAnswer(invocation -> { + Mockito.doAnswer(_ -> { // first attempt: not yet mounted throw new NoSuchFileException("/mnt/jfuse_mount_probe not found"); - }).doAnswer(invocation -> { + }).doAnswer(_ -> { // second attempt: simulate hitting getattr fuse.fuseOperations.getattr("/jfuse_mount_probe", Mockito.mock(Stat.class), Mockito.mock(FileInfo.class)); throw new NoSuchFileException("/mnt/jfuse_mount_probe still not found"); @@ -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); @@ -84,7 +84,7 @@ public void testMountThrowsIllegalStateIfAlreadyMounted() throws InterruptedExce @Test @DisplayName("If fuse_loop instantly returns with non-zero result, throw FuseMountFailedException") public void testMountThrowsFuseMountFailedIfLoopReturnsNonZero() throws InterruptedException { - Mockito.doAnswer(invocation -> { + Mockito.doAnswer(_ -> { Thread.sleep(1000); return null; }).when(fuse).waitForMountingToComplete(Mockito.eq(mountPoint), Mockito.any()); From 20431b6455a561bd7a1b8d072b4f4d673be561a3 Mon Sep 17 00:00:00 2001 From: Sebastian Stenzel Date: Mon, 9 Oct 2023 11:57:34 +0200 Subject: [PATCH 02/13] improve test reliability --- .../src/test/java/org/cryptomator/jfuse/api/FuseTest.java | 8 ++++++++ 1 file changed, 8 insertions(+) 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 ae0d8402..0e9e9a68 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 @@ -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(_ -> { + 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(_ -> { 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)); } From 2b9a3cf61df9d1390adc0ccf6e4077305c7d921d Mon Sep 17 00:00:00 2001 From: Sebastian Stenzel Date: Mon, 9 Oct 2023 12:39:33 +0200 Subject: [PATCH 03/13] partially undo d80a638 due to surefire error https://issues.apache.org/jira/browse/SUREFIRE-2200 --- .../src/test/java/org/cryptomator/jfuse/api/FuseTest.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) 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 0e9e9a68..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 @@ -33,10 +33,10 @@ public void testWaitForMountingToComplete() throws IOException { Mockito.doReturn(fs).when(probePath).getFileSystem(); Mockito.doReturn(fsProv).when(fs).provider(); Mockito.doReturn(attrView).when(fsProv).getFileAttributeView(probePath, BasicFileAttributeView.class); - Mockito.doAnswer(_ -> { + Mockito.doAnswer(invocation -> { // first attempt: not yet mounted throw new NoSuchFileException("/mnt/jfuse_mount_probe not found"); - }).doAnswer(_ -> { + }).doAnswer(invocation -> { // second attempt: simulate hitting getattr fuse.fuseOperations.getattr("/jfuse_mount_probe", Mockito.mock(Stat.class), Mockito.mock(FileInfo.class)); throw new NoSuchFileException("/mnt/jfuse_mount_probe still not found"); @@ -79,7 +79,7 @@ public void testMountThrowsIllegalStateIfAlreadyMounted() throws InterruptedExce // mount probe succeeds immediately... Mockito.doNothing().when(fuse).waitForMountingToComplete(Mockito.eq(mountPoint), Mockito.any()); // ... before fuse_loop returns - Mockito.doAnswer(_ -> { + Mockito.doAnswer(invocation -> { Thread.sleep(1000); return 0; }).when(fuseMount).loop(); @@ -91,7 +91,7 @@ public void testMountThrowsIllegalStateIfAlreadyMounted() throws InterruptedExce @DisplayName("If fuse_loop instantly returns with non-zero result, throw FuseMountFailedException") public void testMountThrowsFuseMountFailedIfLoopReturnsNonZero() throws InterruptedException { // mount probe takes a while... - Mockito.doAnswer(_ -> { + Mockito.doAnswer(invocation -> { Thread.sleep(1000); return null; }).when(fuse).waitForMountingToComplete(Mockito.eq(mountPoint), Mockito.any()); From 91e7b65a0733e8100a0083f6ae9a61d7550e02d8 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 9 Oct 2023 10:48:25 +0000 Subject: [PATCH 04/13] Bump the maven-dependencies group with 1 update (#38) --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index b7e33b4e..91790c97 100644 --- a/pom.xml +++ b/pom.xml @@ -66,7 +66,7 @@ org.mockito mockito-core - 5.5.0 + 5.6.0 test From fa282c37cf811e9c23dfba1ab057131542e0e406 Mon Sep 17 00:00:00 2001 From: Armin Schrenk Date: Thu, 19 Oct 2023 12:10:46 +0200 Subject: [PATCH 05/13] fix sigsev when resolving NULL ptr in releasedir() --- jfuse-api/src/main/java/module-info.java | 1 + .../org/cryptomator/jfuse/api/util/MemoryUtils.java | 13 +++++++++++++ .../cryptomator/jfuse/linux/aarch64/FuseImpl.java | 3 ++- .../org/cryptomator/jfuse/linux/amd64/FuseImpl.java | 3 ++- .../java/org/cryptomator/jfuse/mac/FuseImpl.java | 3 ++- .../java/org/cryptomator/jfuse/win/FuseImpl.java | 3 ++- 6 files changed, 22 insertions(+), 4 deletions(-) create mode 100644 jfuse-api/src/main/java/org/cryptomator/jfuse/api/util/MemoryUtils.java 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..4150eb64 --- /dev/null +++ b/jfuse-api/src/main/java/org/cryptomator/jfuse/api/util/MemoryUtils.java @@ -0,0 +1,13 @@ +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) { + return MemorySegment.NULL.equals(string)? null: string.getUtf8String(0); + } +} 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..56a3266f 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; @@ -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)); } } 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..b6bb72a4 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; @@ -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)); } } 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..91471cd4 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; @@ -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-win/src/main/java/org/cryptomator/jfuse/win/FuseImpl.java b/jfuse-win/src/main/java/org/cryptomator/jfuse/win/FuseImpl.java index bce9878d..5eba956a 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; @@ -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)); } } From d42fd6d9669052514b45b8f6755f0e66d8f9715e Mon Sep 17 00:00:00 2001 From: Armin Schrenk Date: Thu, 19 Oct 2023 12:19:39 +0200 Subject: [PATCH 06/13] add overloaded method --- .../java/org/cryptomator/jfuse/api/util/MemoryUtils.java | 5 +++++ 1 file changed, 5 insertions(+) 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 index 4150eb64..9f092ed6 100644 --- 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 @@ -6,6 +6,11 @@ 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 MemorySegment.NULL.equals(string)? null: string.getUtf8String(0); From 9267c072374138d7f0507e93e42b9b4bd3fb6f84 Mon Sep 17 00:00:00 2001 From: Armin Schrenk Date: Thu, 19 Oct 2023 12:19:59 +0200 Subject: [PATCH 07/13] fix possible sigsev in fsyncdir() --- .../main/java/org/cryptomator/jfuse/api/util/MemoryUtils.java | 4 ++-- .../java/org/cryptomator/jfuse/linux/aarch64/FuseImpl.java | 2 +- .../main/java/org/cryptomator/jfuse/linux/amd64/FuseImpl.java | 2 +- .../src/main/java/org/cryptomator/jfuse/mac/FuseImpl.java | 2 +- .../src/main/java/org/cryptomator/jfuse/win/FuseImpl.java | 2 +- 5 files changed, 6 insertions(+), 6 deletions(-) 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 index 9f092ed6..0f72b33e 100644 --- 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 @@ -8,11 +8,11 @@ public class MemoryUtils { @Nullable public static String toUtf8StringOrNull(MemorySegment string, long offset) { - return MemorySegment.NULL.equals(string)? null: string.getUtf8String(offset); + return MemorySegment.NULL.equals(string) ? null : string.getUtf8String(offset); } @Nullable public static String toUtf8StringOrNull(MemorySegment string) { - return MemorySegment.NULL.equals(string)? null: string.getUtf8String(0); + return MemorySegment.NULL.equals(string) ? null : string.getUtf8String(0); } } 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 56a3266f..47b0cf0c 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 @@ -155,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)); } } 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 b6bb72a4..05a01df8 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 @@ -155,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)); } } 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 91471cd4..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 @@ -155,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)); } } 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 5eba956a..153fafb5 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 @@ -164,7 +164,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)); } } From c6751be1874b162b188688ecdab473351c46a234 Mon Sep 17 00:00:00 2001 From: Armin Schrenk Date: Thu, 19 Oct 2023 13:25:02 +0200 Subject: [PATCH 08/13] prevent sigsev when allocating FileInfo on linux-amd64 --- .../cryptomator/jfuse/linux/amd64/FileInfoImpl.java | 13 +++++++++++++ .../org/cryptomator/jfuse/linux/amd64/FuseImpl.java | 12 ++++++------ 2 files changed, 19 insertions(+), 6 deletions(-) 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 05a01df8..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 @@ -117,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)); } } @@ -161,7 +161,7 @@ int fsyncdir(MemorySegment path, int datasync, MemorySegment fi) { 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)); } } @@ -254,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 +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)); } } } From d725a32b700b762a378afea9a2ceaa17fa76dba9 Mon Sep 17 00:00:00 2001 From: Armin Schrenk Date: Thu, 19 Oct 2023 13:27:57 +0200 Subject: [PATCH 09/13] prevent sigsev when mapping FileInfo on linux-aarch64 --- .../jfuse/linux/aarch64/FileInfoImpl.java | 13 +++++++++++++ .../cryptomator/jfuse/linux/aarch64/FuseImpl.java | 12 ++++++------ 2 files changed, 19 insertions(+), 6 deletions(-) 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 47b0cf0c..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 @@ -117,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)); } } @@ -161,7 +161,7 @@ int fsyncdir(MemorySegment path, int datasync, MemorySegment fi) { 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)); } } @@ -254,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)); } } @@ -272,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)); } } } From 63281afb6b8442bb790860c97a7df35836481f43 Mon Sep 17 00:00:00 2001 From: Armin Schrenk Date: Thu, 19 Oct 2023 13:30:28 +0200 Subject: [PATCH 10/13] prevent sigsev when mapping FileInfo on windows --- .../org/cryptomator/jfuse/win/FileInfoImpl.java | 13 +++++++++++++ .../java/org/cryptomator/jfuse/win/FuseImpl.java | 10 +++++----- 2 files changed, 18 insertions(+), 5 deletions(-) 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 153fafb5..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 @@ -126,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)); } } @@ -171,7 +171,7 @@ int fsyncdir(MemorySegment path, int datasync, MemorySegment fi) { @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)); } } @@ -265,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)); } } @@ -282,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)); } } From a0b9c0b7cc6f45ef99494e2096ffbb2d0533923f Mon Sep 17 00:00:00 2001 From: Armin Schrenk Date: Thu, 19 Oct 2023 13:54:59 +0200 Subject: [PATCH 11/13] Update jfuse-api/src/main/java/org/cryptomator/jfuse/api/util/MemoryUtils.java Co-authored-by: Sebastian Stenzel --- .../main/java/org/cryptomator/jfuse/api/util/MemoryUtils.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 index 0f72b33e..100c3b73 100644 --- 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 @@ -13,6 +13,6 @@ public static String toUtf8StringOrNull(MemorySegment string, long offset) { @Nullable public static String toUtf8StringOrNull(MemorySegment string) { - return MemorySegment.NULL.equals(string) ? null : string.getUtf8String(0); + return toUtf8StringOrNull(string, 0); } } From c3bb1540f6a5f9e869af1c928e8d66f93afc4327 Mon Sep 17 00:00:00 2001 From: Armin Schrenk Date: Thu, 19 Oct 2023 16:58:48 +0200 Subject: [PATCH 12/13] add test --- .../jfuse/api/util/MemoryUtilsTest.java | 41 +++++++++++++++++++ 1 file changed, 41 insertions(+) create mode 100644 jfuse-api/src/test/java/org/cryptomator/jfuse/api/util/MemoryUtilsTest.java 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); + } +} From 77c871a2094002c2dc206c826221c95f581a81c3 Mon Sep 17 00:00:00 2001 From: Armin Schrenk Date: Fri, 20 Oct 2023 12:33:39 +0200 Subject: [PATCH 13/13] prepare 0.6.3 --- jfuse-api/pom.xml | 2 +- jfuse-examples/pom.xml | 2 +- jfuse-linux-aarch64/pom.xml | 2 +- jfuse-linux-amd64/pom.xml | 2 +- jfuse-mac/pom.xml | 2 +- jfuse-tests/pom.xml | 2 +- jfuse-win/pom.xml | 2 +- jfuse/pom.xml | 2 +- pom.xml | 2 +- 9 files changed, 9 insertions(+), 9 deletions(-) diff --git a/jfuse-api/pom.xml b/jfuse-api/pom.xml index f75c2eb8..e3472271 100644 --- a/jfuse-api/pom.xml +++ b/jfuse-api/pom.xml @@ -5,7 +5,7 @@ org.cryptomator jfuse-parent - 0.7.0-SNAPSHOT + 0.6.3 4.0.0 jfuse-api diff --git a/jfuse-examples/pom.xml b/jfuse-examples/pom.xml index 5eae611f..ef8549a9 100644 --- a/jfuse-examples/pom.xml +++ b/jfuse-examples/pom.xml @@ -5,7 +5,7 @@ org.cryptomator jfuse-parent - 0.7.0-SNAPSHOT + 0.6.3 4.0.0 jfuse-examples diff --git a/jfuse-linux-aarch64/pom.xml b/jfuse-linux-aarch64/pom.xml index ce47979a..a5d3b388 100644 --- a/jfuse-linux-aarch64/pom.xml +++ b/jfuse-linux-aarch64/pom.xml @@ -5,7 +5,7 @@ jfuse-parent org.cryptomator - 0.7.0-SNAPSHOT + 0.6.3 4.0.0 jfuse-linux-aarch64 diff --git a/jfuse-linux-amd64/pom.xml b/jfuse-linux-amd64/pom.xml index 50cf5937..93623607 100644 --- a/jfuse-linux-amd64/pom.xml +++ b/jfuse-linux-amd64/pom.xml @@ -5,7 +5,7 @@ org.cryptomator jfuse-parent - 0.7.0-SNAPSHOT + 0.6.3 4.0.0 jfuse-linux-amd64 diff --git a/jfuse-mac/pom.xml b/jfuse-mac/pom.xml index 3156bb24..17807d3c 100644 --- a/jfuse-mac/pom.xml +++ b/jfuse-mac/pom.xml @@ -5,7 +5,7 @@ org.cryptomator jfuse-parent - 0.7.0-SNAPSHOT + 0.6.3 4.0.0 jfuse-mac diff --git a/jfuse-tests/pom.xml b/jfuse-tests/pom.xml index 47e38dac..3fcace78 100644 --- a/jfuse-tests/pom.xml +++ b/jfuse-tests/pom.xml @@ -5,7 +5,7 @@ org.cryptomator jfuse-parent - 0.7.0-SNAPSHOT + 0.6.3 4.0.0 jfuse-tests diff --git a/jfuse-win/pom.xml b/jfuse-win/pom.xml index 540b4f9e..8dca5bc9 100644 --- a/jfuse-win/pom.xml +++ b/jfuse-win/pom.xml @@ -5,7 +5,7 @@ org.cryptomator jfuse-parent - 0.7.0-SNAPSHOT + 0.6.3 4.0.0 jfuse-win diff --git a/jfuse/pom.xml b/jfuse/pom.xml index 67920ee3..d0456ba0 100644 --- a/jfuse/pom.xml +++ b/jfuse/pom.xml @@ -5,7 +5,7 @@ org.cryptomator jfuse-parent - 0.7.0-SNAPSHOT + 0.6.3 4.0.0 jfuse diff --git a/pom.xml b/pom.xml index 91790c97..27206973 100644 --- a/pom.xml +++ b/pom.xml @@ -6,7 +6,7 @@ org.cryptomator jfuse-parent pom - 0.7.0-SNAPSHOT + 0.6.3 jFUSE Java bindings for FUSE using foreign functions & memory API https://github.com/cryptomator/jfuse