From 34f1f8051d00ab9047ff9c33210c8f24272ec402 Mon Sep 17 00:00:00 2001 From: Armin Schrenk Date: Fri, 9 Feb 2024 00:05:47 +0100 Subject: [PATCH 01/22] fixes #205 * make persistLastModified() last action of close() * close cipherChannel from ClearChannel --- .../cryptofs/ch/ChannelCloseListener.java | 4 +--- .../cryptofs/ch/CleartextFileChannel.java | 7 ++++--- .../cryptofs/fh/OpenCryptoFile.java | 18 +++++++----------- 3 files changed, 12 insertions(+), 17 deletions(-) diff --git a/src/main/java/org/cryptomator/cryptofs/ch/ChannelCloseListener.java b/src/main/java/org/cryptomator/cryptofs/ch/ChannelCloseListener.java index 4933e1bc..3ee1c008 100644 --- a/src/main/java/org/cryptomator/cryptofs/ch/ChannelCloseListener.java +++ b/src/main/java/org/cryptomator/cryptofs/ch/ChannelCloseListener.java @@ -1,11 +1,9 @@ package org.cryptomator.cryptofs.ch; -import java.io.IOException; - @FunctionalInterface public interface ChannelCloseListener { - void closed(CleartextFileChannel channel) throws IOException; + void closed(CleartextFileChannel channel); } \ No newline at end of file diff --git a/src/main/java/org/cryptomator/cryptofs/ch/CleartextFileChannel.java b/src/main/java/org/cryptomator/cryptofs/ch/CleartextFileChannel.java index 97791365..95bd7ed3 100644 --- a/src/main/java/org/cryptomator/cryptofs/ch/CleartextFileChannel.java +++ b/src/main/java/org/cryptomator/cryptofs/ch/CleartextFileChannel.java @@ -322,6 +322,10 @@ long beginOfChunk(long cleartextPos) { protected void implCloseChannel() throws IOException { try { flush(); + } finally { + super.implCloseChannel(); + closeListener.closed(this); + ciphertextFileChannel.close(); try { persistLastModified(); } catch (NoSuchFileException nsfe) { @@ -330,9 +334,6 @@ protected void implCloseChannel() throws IOException { //only best effort attempt LOG.warn("Failed to persist last modified timestamp for encrypted file: {}", e.getMessage()); } - } finally { - super.implCloseChannel(); - closeListener.closed(this); } } } diff --git a/src/main/java/org/cryptomator/cryptofs/fh/OpenCryptoFile.java b/src/main/java/org/cryptomator/cryptofs/fh/OpenCryptoFile.java index a07b5db2..14e5d072 100644 --- a/src/main/java/org/cryptomator/cryptofs/fh/OpenCryptoFile.java +++ b/src/main/java/org/cryptomator/cryptofs/fh/OpenCryptoFile.java @@ -183,17 +183,13 @@ public void updateCurrentFilePath(Path newFilePath) { currentFilePath.updateAndGet(p -> p == null ? null : newFilePath); } - private synchronized void channelClosed(CleartextFileChannel cleartextFileChannel) throws IOException { - try { - FileChannel ciphertextFileChannel = openChannels.remove(cleartextFileChannel); - if (ciphertextFileChannel != null) { - chunkIO.unregisterChannel(ciphertextFileChannel); - ciphertextFileChannel.close(); - } - } finally { - if (openChannels.isEmpty()) { - close(); - } + private synchronized void channelClosed(CleartextFileChannel cleartextFileChannel) { + FileChannel ciphertextFileChannel = openChannels.remove(cleartextFileChannel); + if (ciphertextFileChannel != null) { + chunkIO.unregisterChannel(ciphertextFileChannel); + } + if (openChannels.isEmpty()) { + close(); } } From 6a3c352a2db3952298011decbd15807681e7efc5 Mon Sep 17 00:00:00 2001 From: Armin Schrenk Date: Fri, 9 Feb 2024 00:06:21 +0100 Subject: [PATCH 02/22] first store updated lastModified in filesystem before writing it to underlying storage --- .../cryptomator/cryptofs/attr/CryptoBasicFileAttributeView.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/org/cryptomator/cryptofs/attr/CryptoBasicFileAttributeView.java b/src/main/java/org/cryptomator/cryptofs/attr/CryptoBasicFileAttributeView.java index 1e44bfa1..f621b770 100644 --- a/src/main/java/org/cryptomator/cryptofs/attr/CryptoBasicFileAttributeView.java +++ b/src/main/java/org/cryptomator/cryptofs/attr/CryptoBasicFileAttributeView.java @@ -48,10 +48,10 @@ public BasicFileAttributes readAttributes() throws IOException { @Override public void setTimes(FileTime lastModifiedTime, FileTime lastAccessTime, FileTime createTime) throws IOException { readonlyFlag.assertWritable(); - getCiphertextAttributeView(BasicFileAttributeView.class).setTimes(lastModifiedTime, lastAccessTime, createTime); if (lastModifiedTime != null) { getOpenCryptoFile().ifPresent(file -> file.setLastModifiedTime(lastModifiedTime)); } + getCiphertextAttributeView(BasicFileAttributeView.class).setTimes(lastModifiedTime, lastAccessTime, createTime); } } From 9fc978057efbb861dcaebc7c8c0c57cb149beb27 Mon Sep 17 00:00:00 2001 From: Armin Schrenk Date: Fri, 9 Feb 2024 00:17:50 +0100 Subject: [PATCH 03/22] improve unit tests --- .../cryptofs/ch/CleartextFileChannel.java | 7 +++-- .../cryptofs/ch/CleartextFileChannelTest.java | 31 +++++++++++++++---- 2 files changed, 30 insertions(+), 8 deletions(-) diff --git a/src/main/java/org/cryptomator/cryptofs/ch/CleartextFileChannel.java b/src/main/java/org/cryptomator/cryptofs/ch/CleartextFileChannel.java index 95bd7ed3..34b5d416 100644 --- a/src/main/java/org/cryptomator/cryptofs/ch/CleartextFileChannel.java +++ b/src/main/java/org/cryptomator/cryptofs/ch/CleartextFileChannel.java @@ -1,5 +1,6 @@ package org.cryptomator.cryptofs.ch; +import com.google.common.annotations.VisibleForTesting; import com.google.common.base.Preconditions; import org.cryptomator.cryptofs.CryptoFileSystemStats; import org.cryptomator.cryptofs.EffectiveOpenOptions; @@ -232,7 +233,8 @@ private void forceInternal(boolean metaData) throws IOException { * * @throws IOException */ - private void flush() throws IOException { + @VisibleForTesting + void flush() throws IOException { if (isWritable()) { writeHeaderIfNeeded(); chunkCache.flush(); @@ -245,7 +247,8 @@ private void flush() throws IOException { * * @throws IOException */ - private void persistLastModified() throws IOException { + @VisibleForTesting + void persistLastModified() throws IOException { FileTime lastModifiedTime = isWritable() ? FileTime.from(lastModified.get()) : null; FileTime lastAccessTime = FileTime.from(Instant.now()); var p = currentFilePath.get(); diff --git a/src/test/java/org/cryptomator/cryptofs/ch/CleartextFileChannelTest.java b/src/test/java/org/cryptomator/cryptofs/ch/CleartextFileChannelTest.java index 8b07565a..1880110d 100644 --- a/src/test/java/org/cryptomator/cryptofs/ch/CleartextFileChannelTest.java +++ b/src/test/java/org/cryptomator/cryptofs/ch/CleartextFileChannelTest.java @@ -43,7 +43,6 @@ import java.util.concurrent.atomic.AtomicReference; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReadWriteLock; -import java.util.function.Supplier; import static org.hamcrest.CoreMatchers.is; import static org.mockito.ArgumentMatchers.any; @@ -69,7 +68,7 @@ public class CleartextFileChannelTest { private FileHeaderHolder headerHolder = mock(FileHeaderHolder.class); private AtomicBoolean headerIsPersisted = mock(AtomicBoolean.class); private EffectiveOpenOptions options = mock(EffectiveOpenOptions.class); - private Path filePath = Mockito.mock(Path.class,"/foo/bar"); + private Path filePath = Mockito.mock(Path.class, "/foo/bar"); private AtomicReference currentFilePath = new AtomicReference<>(filePath); private AtomicLong fileSize = new AtomicLong(100); private AtomicReference lastModified = new AtomicReference<>(Instant.ofEpochMilli(0)); @@ -96,7 +95,7 @@ public void setUp() throws IOException { var fsProvider = Mockito.mock(FileSystemProvider.class); when(filePath.getFileSystem()).thenReturn(fs); when(fs.provider()).thenReturn(fsProvider); - when(fsProvider.getFileAttributeView(filePath,BasicFileAttributeView.class)).thenReturn(attributeView); + when(fsProvider.getFileAttributeView(filePath, BasicFileAttributeView.class)).thenReturn(attributeView); when(readWriteLock.readLock()).thenReturn(readLock); when(readWriteLock.writeLock()).thenReturn(writeLock); @@ -234,10 +233,16 @@ public void testForceWithoutMetadataDoesntUpdatesLastModifiedTime() throws IOExc public class Close { @Test - public void testCloseTriggersCloseListener() throws IOException { - inTest.implCloseChannel(); + @DisplayName("IOException during flush cleans up, persists lastModified and rethrows") + public void testCloseIoExceptionFlush() throws IOException { + var inSpy = Mockito.spy(inTest); + Mockito.doThrow(IOException.class).when(inSpy).flush(); + + Assertions.assertThrows(IOException.class, () -> inSpy.implCloseChannel()); - verify(closeListener).closed(inTest); + verify(closeListener).closed(inSpy); + verify(ciphertextFileChannel).close(); + verify(inSpy).persistLastModified(); } @Test @@ -251,6 +256,20 @@ public void testCloseUpdatesLastModifiedTimeIfWriteable() throws IOException { verify(attributeView).setTimes(Mockito.eq(fileTime), Mockito.any(), Mockito.isNull()); } + @Test + @DisplayName("IOException on persisting lastModified during close is ignored") + public void testCloseExceptionOnLastModifiedPersistenceIgnored() throws IOException { + when(options.writable()).thenReturn(true); + lastModified.set(Instant.ofEpochMilli(123456789000l)); + + var inSpy = Mockito.spy(inTest); + Mockito.doThrow(IOException.class).when(inSpy).persistLastModified(); + + Assertions.assertDoesNotThrow(() -> inSpy.implCloseChannel()); + verify(closeListener).closed(inSpy); + verify(ciphertextFileChannel).close(); + } + @Test public void testCloseDoesNotUpdateLastModifiedTimeIfReadOnly() throws IOException { when(options.writable()).thenReturn(false); From ae742d11fb9168591966d4b441d5b40d848bbed1 Mon Sep 17 00:00:00 2001 From: Armin Schrenk Date: Fri, 9 Feb 2024 13:22:01 +0100 Subject: [PATCH 04/22] always persist lastModified --- .../cryptofs/ch/CleartextFileChannel.java | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/src/main/java/org/cryptomator/cryptofs/ch/CleartextFileChannel.java b/src/main/java/org/cryptomator/cryptofs/ch/CleartextFileChannel.java index 34b5d416..61bafcdb 100644 --- a/src/main/java/org/cryptomator/cryptofs/ch/CleartextFileChannel.java +++ b/src/main/java/org/cryptomator/cryptofs/ch/CleartextFileChannel.java @@ -328,14 +328,17 @@ protected void implCloseChannel() throws IOException { } finally { super.implCloseChannel(); closeListener.closed(this); - ciphertextFileChannel.close(); try { - persistLastModified(); - } catch (NoSuchFileException nsfe) { - //no-op, see https://github.com/cryptomator/cryptofs/issues/169 - } catch (IOException e) { - //only best effort attempt - LOG.warn("Failed to persist last modified timestamp for encrypted file: {}", e.getMessage()); + ciphertextFileChannel.close(); + } finally { + try { + persistLastModified(); + } catch (NoSuchFileException nsfe) { + //no-op, see https://github.com/cryptomator/cryptofs/issues/169 + } catch (IOException e) { + //only best effort attempt + LOG.warn("Failed to persist last modified timestamp for encrypted file: {}", e.getMessage()); + } } } } From 819991f8b667be756adbd7d96e8fda647c0de2a3 Mon Sep 17 00:00:00 2001 From: Armin Schrenk Date: Wed, 28 Feb 2024 16:09:49 +0100 Subject: [PATCH 05/22] use stream instead of iterator --- .../java/org/cryptomator/cryptofs/fh/ChunkIO.java | 14 ++------------ 1 file changed, 2 insertions(+), 12 deletions(-) diff --git a/src/main/java/org/cryptomator/cryptofs/fh/ChunkIO.java b/src/main/java/org/cryptomator/cryptofs/fh/ChunkIO.java index 8ec707f8..e1e73c63 100644 --- a/src/main/java/org/cryptomator/cryptofs/fh/ChunkIO.java +++ b/src/main/java/org/cryptomator/cryptofs/fh/ChunkIO.java @@ -52,21 +52,11 @@ int write(ByteBuffer src, long position) throws IOException { } private FileChannel getReadableChannel() { - Iterator iter = readableChannels.iterator(); - if (iter.hasNext()) { - return iter.next(); - } else { - throw new NonReadableChannelException(); - } + return readableChannels.stream().findFirst().orElseThrow(NonReadableChannelException::new); } private FileChannel getWritableChannel() { - Iterator iter = writableChannels.iterator(); - if (iter.hasNext()) { - return iter.next(); - } else { - throw new NonWritableChannelException(); - } + return writableChannels.stream().findFirst().orElseThrow(NonWritableChannelException::new); } } From df785eb7746196e66d424368a70c57962b3616f9 Mon Sep 17 00:00:00 2001 From: Armin Schrenk Date: Wed, 28 Feb 2024 23:15:22 +0100 Subject: [PATCH 06/22] fix unit test --- .../cryptomator/cryptofs/ch/CleartextFileChannelTest.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/test/java/org/cryptomator/cryptofs/ch/CleartextFileChannelTest.java b/src/test/java/org/cryptomator/cryptofs/ch/CleartextFileChannelTest.java index d439d58a..a19e508d 100644 --- a/src/test/java/org/cryptomator/cryptofs/ch/CleartextFileChannelTest.java +++ b/src/test/java/org/cryptomator/cryptofs/ch/CleartextFileChannelTest.java @@ -248,13 +248,13 @@ public void testCloseIoExceptionFlush() throws IOException { } @Test - @DisplayName("On close, first flush channel, then persist lastModified") - public void testCloseFlushBeforePersist() throws IOException { + @DisplayName("On close, first close channel, then persist lastModified") + public void testCloseCipherChannelCloseBeforePersist() throws IOException { var inSpy = spy(inTest); inSpy.implCloseChannel(); var ordering = inOrder(inSpy, ciphertextFileChannel); - ordering.verify(ciphertextFileChannel).force(true); + ordering.verify(ciphertextFileChannel).close(); ordering.verify(inSpy).persistLastModified(); } From e95825714123f8e3529709fddd1d1f9895391ccc Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 9 Apr 2024 08:27:50 +0000 Subject: [PATCH 07/22] Bump the github-actions group with 1 update (#217) --- .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 88f8da8a..6b19755e 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -42,7 +42,7 @@ jobs: path: target/*.jar - name: Create release if: startsWith(github.ref, 'refs/tags/') - uses: softprops/action-gh-release@v1 + uses: softprops/action-gh-release@v2 with: token: ${{ secrets.CRYPTOBOT_RELEASE_TOKEN }} generate_release_notes: true From 12497b1dd821cda57c6a90da395fe0cb189f3f07 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 15 Apr 2024 09:32:48 +0000 Subject: [PATCH 08/22] Bump the maven-build-plugins group with 6 updates (#220) --- pom.xml | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/pom.xml b/pom.xml index 10c0395e..de365969 100644 --- a/pom.xml +++ b/pom.xml @@ -32,9 +32,9 @@ 1.3.0 - 9.0.9 + 9.1.0 1.2.1 - 0.8.11 + 0.8.12 1.6.13 @@ -143,7 +143,7 @@ org.apache.maven.plugins maven-compiler-plugin - 3.12.1 + 3.13.0 true @@ -181,11 +181,11 @@ org.apache.maven.plugins maven-jar-plugin - 3.3.0 + 3.4.0 maven-source-plugin - 3.3.0 + 3.3.1 attach-sources @@ -300,7 +300,7 @@ maven-gpg-plugin - 3.1.0 + 3.2.3 sign-artifacts From dd12be1e40d1c74f97ee13c143fd7164c013acc9 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 22 Apr 2024 08:25:17 +0000 Subject: [PATCH 09/22] Bump the maven-build-plugins group with 2 updates (#221) --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index de365969..5fea6d9c 100644 --- a/pom.xml +++ b/pom.xml @@ -181,7 +181,7 @@ org.apache.maven.plugins maven-jar-plugin - 3.4.0 + 3.4.1 maven-source-plugin @@ -300,7 +300,7 @@ maven-gpg-plugin - 3.2.3 + 3.2.4 sign-artifacts From b3b9158c6b749bbc52fea8bfa430182ecb241425 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 4 Jun 2024 08:05:42 +0000 Subject: [PATCH 10/22] Bump the maven-build-plugins group across 1 directory with 2 updates (#225) --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index 5fea6d9c..5b1702a3 100644 --- a/pom.xml +++ b/pom.xml @@ -32,7 +32,7 @@ 1.3.0 - 9.1.0 + 9.2.0 1.2.1 0.8.12 1.6.13 @@ -197,7 +197,7 @@ maven-javadoc-plugin - 3.6.3 + 3.7.0 attach-javadocs From d9d7cf858075d2402518eeb5e2a55d5634fafc8d Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 4 Jun 2024 12:55:26 +0000 Subject: [PATCH 11/22] Bump the java-production-dependencies group across 1 directory with 7 updates (#226) --- pom.xml | 10 +++++----- src/main/java/module-info.java | 1 + 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/pom.xml b/pom.xml index 5b1702a3..b4bc6d3a 100644 --- a/pom.xml +++ b/pom.xml @@ -18,12 +18,12 @@ 17 - 2.1.2 + 2.2.0 4.4.0 - 2.49 - 32.1.3-jre + 2.51.1 + 33.2.1-jre 3.1.8 - 2.0.12 + 2.0.13 5.10.2 @@ -35,7 +35,7 @@ 9.2.0 1.2.1 0.8.12 - 1.6.13 + 1.7.0 diff --git a/src/main/java/module-info.java b/src/main/java/module-info.java index 5cbfb094..abe11b30 100644 --- a/src/main/java/module-info.java +++ b/src/main/java/module-info.java @@ -19,6 +19,7 @@ // https://github.com/javax-inject/javax-inject/issues/33 // May be provided by another lib during runtime requires static javax.inject; + requires java.compiler; exports org.cryptomator.cryptofs; exports org.cryptomator.cryptofs.common; From 0682c2a197cbdbb22153cdeba14cc561d50eec58 Mon Sep 17 00:00:00 2001 From: Julian Raufelder Date: Fri, 7 Jun 2024 14:07:52 +0000 Subject: [PATCH 12/22] Hardening the CI in relation to PRs --- .github/workflows/build.yml | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 6b19755e..d26ab7d2 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -1,6 +1,8 @@ name: Build on: - [push] + push: + pull_request_target: + types: [labeled] jobs: build: name: Build and Test @@ -46,4 +48,4 @@ jobs: with: token: ${{ secrets.CRYPTOBOT_RELEASE_TOKEN }} generate_release_notes: true - prerelease: true \ No newline at end of file + prerelease: true From e247a2e264eb0a6f9e2cff53e77238678d43b842 Mon Sep 17 00:00:00 2001 From: Armin Schrenk Date: Tue, 2 Jul 2024 15:25:36 +0200 Subject: [PATCH 13/22] strech the finally methods over 3 methods --- .../cryptofs/ch/CleartextFileChannel.java | 30 ++++++++++++------- 1 file changed, 20 insertions(+), 10 deletions(-) diff --git a/src/main/java/org/cryptomator/cryptofs/ch/CleartextFileChannel.java b/src/main/java/org/cryptomator/cryptofs/ch/CleartextFileChannel.java index 61bafcdb..75f634f1 100644 --- a/src/main/java/org/cryptomator/cryptofs/ch/CleartextFileChannel.java +++ b/src/main/java/org/cryptomator/cryptofs/ch/CleartextFileChannel.java @@ -326,19 +326,29 @@ protected void implCloseChannel() throws IOException { try { flush(); } finally { + implCloseChannelFinally1(); + } + } + + private void implCloseChannelFinally1() throws IOException { + try { super.implCloseChannel(); + } finally { closeListener.closed(this); + implCloseChannelFinally2(); + } + } + + private void implCloseChannelFinally2() throws IOException { + try { + ciphertextFileChannel.close(); + } finally { try { - ciphertextFileChannel.close(); - } finally { - try { - persistLastModified(); - } catch (NoSuchFileException nsfe) { - //no-op, see https://github.com/cryptomator/cryptofs/issues/169 - } catch (IOException e) { - //only best effort attempt - LOG.warn("Failed to persist last modified timestamp for encrypted file: {}", e.getMessage()); - } + persistLastModified(); + } catch (NoSuchFileException nsfe) { + //no-op, see https://github.com/cryptomator/cryptofs/issues/169 + } catch (IOException e) { + LOG.warn("Failed to persist last modified timestamp for encrypted file: {}", e.getMessage()); } } } From 4d8a96837af10d94408a913021606d43313e5193 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 8 Jul 2024 07:52:19 +0000 Subject: [PATCH 14/22] Bump the maven-build-plugins group across 1 directory with 3 updates (#231) --- pom.xml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/pom.xml b/pom.xml index b4bc6d3a..26288b72 100644 --- a/pom.xml +++ b/pom.xml @@ -32,7 +32,7 @@ 1.3.0 - 9.2.0 + 10.0.2 1.2.1 0.8.12 1.7.0 @@ -158,7 +158,7 @@ org.apache.maven.plugins maven-surefire-plugin - 3.2.5 + 3.3.0 me.fabriciorby @@ -181,7 +181,7 @@ org.apache.maven.plugins maven-jar-plugin - 3.4.1 + 3.4.2 maven-source-plugin From 675780129dfacd5cb6f8f0ebcd6ad9b13942eee0 Mon Sep 17 00:00:00 2001 From: Armin Schrenk Date: Wed, 17 Jul 2024 15:29:19 +0200 Subject: [PATCH 15/22] use helper function to execute all close actions --- .../cryptofs/ch/CleartextFileChannel.java | 45 +++++++++++-------- 1 file changed, 26 insertions(+), 19 deletions(-) diff --git a/src/main/java/org/cryptomator/cryptofs/ch/CleartextFileChannel.java b/src/main/java/org/cryptomator/cryptofs/ch/CleartextFileChannel.java index 75f634f1..44d165a8 100644 --- a/src/main/java/org/cryptomator/cryptofs/ch/CleartextFileChannel.java +++ b/src/main/java/org/cryptomator/cryptofs/ch/CleartextFileChannel.java @@ -29,6 +29,8 @@ import java.nio.file.attribute.BasicFileAttributeView; import java.nio.file.attribute.FileTime; import java.time.Instant; +import java.util.Iterator; +import java.util.List; import java.util.concurrent.atomic.AtomicLong; import java.util.concurrent.atomic.AtomicReference; import java.util.concurrent.locks.ReadWriteLock; @@ -323,33 +325,38 @@ long beginOfChunk(long cleartextPos) { @Override protected void implCloseChannel() throws IOException { - try { - flush(); - } finally { - implCloseChannelFinally1(); - } + var closeActions = List.of(this::flush, // + super::implCloseChannel, // + () -> closeListener.closed(this), // + ciphertextFileChannel::close, // + this::tryPersistLastModified); + tryAll(closeActions.iterator()); } - private void implCloseChannelFinally1() throws IOException { + private void tryPersistLastModified() { try { - super.implCloseChannel(); - } finally { - closeListener.closed(this); - implCloseChannelFinally2(); + persistLastModified(); + } catch (NoSuchFileException nsfe) { + //no-op, see https://github.com/cryptomator/cryptofs/issues/169 + } catch (IOException e) { + LOG.warn("Failed to persist last modified timestamp for encrypted file: {}", e.getMessage()); } } - private void implCloseChannelFinally2() throws IOException { - try { - ciphertextFileChannel.close(); - } finally { + private void tryAll(Iterator actions) throws IOException { + if (actions.hasNext()) { try { - persistLastModified(); - } catch (NoSuchFileException nsfe) { - //no-op, see https://github.com/cryptomator/cryptofs/issues/169 - } catch (IOException e) { - LOG.warn("Failed to persist last modified timestamp for encrypted file: {}", e.getMessage()); + actions.next().run(); + } finally { + tryAll(actions); } } } + + @FunctionalInterface + private interface CloseAction { + + void run() throws IOException; + } + } From 93bfa1c1cb0448232367e6c143d67f54c8dafd19 Mon Sep 17 00:00:00 2001 From: Armin Schrenk Date: Wed, 24 Jul 2024 14:27:44 +0200 Subject: [PATCH 16/22] update dependabot config --- .github/dependabot.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/dependabot.yml b/.github/dependabot.yml index 9f706d7d..8396a94f 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -19,6 +19,7 @@ updates: - "org.apache.maven.plugins:*" - "org.jacoco:jacoco-maven-plugin" - "org.owasp:dependency-check-maven" + - "me.fabriciorby:maven-surefire-junit5-tree-reporter" java-production-dependencies: patterns: - "*" @@ -30,6 +31,7 @@ updates: - "org.mockito:*" - "org.hamcrest:*" - "com.google.jimfs:jimfs" + - "me.fabriciorby:maven-surefire-junit5-tree-reporter" - package-ecosystem: "github-actions" From d8dee784992ce0336b540d48a13e86ad259c1f6a Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 8 Aug 2024 15:26:05 +0000 Subject: [PATCH 17/22] Bump the maven-build-plugins group across 1 directory with 4 updates (#235) --- pom.xml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/pom.xml b/pom.xml index 26288b72..a2ea7406 100644 --- a/pom.xml +++ b/pom.xml @@ -32,8 +32,8 @@ 1.3.0 - 10.0.2 - 1.2.1 + 10.0.3 + 1.3.0 0.8.12 1.7.0 @@ -158,7 +158,7 @@ org.apache.maven.plugins maven-surefire-plugin - 3.3.0 + 3.3.1 me.fabriciorby @@ -197,7 +197,7 @@ maven-javadoc-plugin - 3.7.0 + 3.8.0 attach-javadocs From 780ad4f746c873601e44effe38fc185b80491d10 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 8 Aug 2024 15:26:33 +0000 Subject: [PATCH 18/22] Bump the java-test-dependencies group across 1 directory with 2 updates (#236) --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index a2ea7406..b3687a91 100644 --- a/pom.xml +++ b/pom.xml @@ -26,9 +26,9 @@ 2.0.13 - 5.10.2 + 5.10.3 5.2.0 - 2.2 + 3.0 1.3.0 From 8d784b05a221247fbc898a4b4a665ed0f841b987 Mon Sep 17 00:00:00 2001 From: Armin Schrenk Date: Fri, 9 Aug 2024 10:46:40 +0200 Subject: [PATCH 19/22] use bc signer in maven-gpg-plugin --- .github/workflows/publish-central.yml | 5 ++--- .github/workflows/publish-github.yml | 3 +-- pom.xml | 5 +---- 3 files changed, 4 insertions(+), 9 deletions(-) diff --git a/.github/workflows/publish-central.yml b/.github/workflows/publish-central.yml index 9eb1b363..4129b18c 100644 --- a/.github/workflows/publish-central.yml +++ b/.github/workflows/publish-central.yml @@ -22,8 +22,6 @@ jobs: server-id: ossrh # Value of the distributionManagement/repository/id field of the pom.xml server-username: MAVEN_USERNAME # env variable for username in deploy server-password: MAVEN_PASSWORD # env variable for token in deploy - gpg-private-key: ${{ secrets.RELEASES_GPG_PRIVATE_KEY }} # Value of the GPG private key to import - gpg-passphrase: MAVEN_GPG_PASSPHRASE # env variable for GPG private key passphrase - name: Enforce project version ${{ github.event.inputs.tag }} run: mvn versions:set -B -DnewVersion=${{ github.event.inputs.tag }} - name: Deploy @@ -36,4 +34,5 @@ jobs: --add-opens=java.desktop/java.awt.font=ALL-UNNAMED MAVEN_USERNAME: ${{ secrets.OSSRH_USERNAME }} MAVEN_PASSWORD: ${{ secrets.OSSRH_PASSWORD }} - MAVEN_GPG_PASSPHRASE: ${{ secrets.RELEASES_GPG_PASSPHRASE }} \ No newline at end of file + MAVEN_GPG_PASSPHRASE: ${{ secrets.RELEASES_GPG_PASSPHRASE }} + MAVEN_GPG_KEY: ${{ secrets.RELEASES_GPG_PRIVATE_KEY }} # Value of the GPG private key to import diff --git a/.github/workflows/publish-github.yml b/.github/workflows/publish-github.yml index e0f8b793..dff71ad5 100644 --- a/.github/workflows/publish-github.yml +++ b/.github/workflows/publish-github.yml @@ -15,8 +15,6 @@ jobs: java-version: 17 distribution: 'temurin' cache: 'maven' - gpg-private-key: ${{ secrets.RELEASES_GPG_PRIVATE_KEY }} # Value of the GPG private key to import - gpg-passphrase: MAVEN_GPG_PASSPHRASE # env variable for GPG private key passphrase - name: Enforce project version ${{ github.event.release.tag_name }} run: mvn versions:set -B -DnewVersion=${{ github.event.release.tag_name }} - name: Deploy @@ -24,6 +22,7 @@ jobs: env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} MAVEN_GPG_PASSPHRASE: ${{ secrets.RELEASES_GPG_PASSPHRASE }} + MAVEN_GPG_KEY: ${{ secrets.RELEASES_GPG_PRIVATE_KEY }} # Value of the GPG private key to import - name: Slack Notification uses: rtCamp/action-slack-notify@v2 env: diff --git a/pom.xml b/pom.xml index b3687a91..a1358ea1 100644 --- a/pom.xml +++ b/pom.xml @@ -309,10 +309,7 @@ sign - - --pinentry-mode - loopback - + bc From b8316e0fd0d32ba8e19b29506fe080ec747463c8 Mon Sep 17 00:00:00 2001 From: Armin Schrenk Date: Fri, 9 Aug 2024 10:47:25 +0200 Subject: [PATCH 20/22] prevent leaking of NVD API key into logs --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index a1358ea1..3847f6b0 100644 --- a/pom.xml +++ b/pom.xml @@ -252,7 +252,7 @@ true true suppression.xml - ${env.NVD_API_KEY} + NVD_API_KEY From 674bdab28589d3361eeba46ce2dac27433014910 Mon Sep 17 00:00:00 2001 From: Armin Schrenk Date: Fri, 9 Aug 2024 12:56:17 +0200 Subject: [PATCH 21/22] Feature: JDK 21 (#237) Migrate project to JDK 21 --- .github/workflows/build.yml | 2 +- .github/workflows/codeql-analysis.yml | 2 +- .github/workflows/dependency-check.yml | 2 +- .github/workflows/publish-central.yml | 2 +- .github/workflows/publish-github.yml | 2 +- .idea/misc.xml | 2 +- README.md | 3 +- pom.xml | 6 ++-- .../cryptofs/CryptoFileSystemImplTest.java | 30 ++++++++++++------- .../cryptofs/CryptoPathMapperTest.java | 3 ++ 10 files changed, 34 insertions(+), 20 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index d26ab7d2..da527ddf 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -14,7 +14,7 @@ jobs: show-progress: false - uses: actions/setup-java@v4 with: - java-version: 17 + java-version: 21 distribution: 'temurin' cache: 'maven' - name: Cache SonarCloud packages diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml index 237bcac3..9bfa8088 100644 --- a/.github/workflows/codeql-analysis.yml +++ b/.github/workflows/codeql-analysis.yml @@ -22,7 +22,7 @@ jobs: show-progress: false - uses: actions/setup-java@v4 with: - java-version: 17 + java-version: 21 distribution: 'temurin' cache: 'maven' - name: Initialize CodeQL diff --git a/.github/workflows/dependency-check.yml b/.github/workflows/dependency-check.yml index 4e7e7d0f..601975f4 100644 --- a/.github/workflows/dependency-check.yml +++ b/.github/workflows/dependency-check.yml @@ -14,7 +14,7 @@ jobs: with: runner-os: 'ubuntu-latest' java-distribution: 'temurin' - java-version: 17 + java-version: 21 secrets: nvd-api-key: ${{ secrets.NVD_API_KEY }} slack-webhook-url: ${{ secrets.SLACK_WEBHOOK_URL }} diff --git a/.github/workflows/publish-central.yml b/.github/workflows/publish-central.yml index 4129b18c..07727e4c 100644 --- a/.github/workflows/publish-central.yml +++ b/.github/workflows/publish-central.yml @@ -16,7 +16,7 @@ jobs: show-progress: false - uses: actions/setup-java@v4 with: - java-version: 17 + java-version: 21 distribution: 'temurin' cache: 'maven' server-id: ossrh # Value of the distributionManagement/repository/id field of the pom.xml diff --git a/.github/workflows/publish-github.yml b/.github/workflows/publish-github.yml index dff71ad5..59b312e4 100644 --- a/.github/workflows/publish-github.yml +++ b/.github/workflows/publish-github.yml @@ -12,7 +12,7 @@ jobs: show-progress: false - uses: actions/setup-java@v4 with: - java-version: 17 + java-version: 21 distribution: 'temurin' cache: 'maven' - name: Enforce project version ${{ github.event.release.tag_name }} diff --git a/.idea/misc.xml b/.idea/misc.xml index 67e1e611..9dc782bb 100644 --- a/.idea/misc.xml +++ b/.idea/misc.xml @@ -8,5 +8,5 @@ - + \ No newline at end of file diff --git a/README.md b/README.md index 6ed04e88..3050a0db 100644 --- a/README.md +++ b/README.md @@ -6,6 +6,7 @@ [![Known Vulnerabilities](https://snyk.io/test/github/cryptomator/cryptofs/badge.svg)](https://snyk.io/test/github/cryptomator/cryptofs) **CryptoFS:** Implementation of the [Cryptomator](https://github.com/cryptomator/cryptomator) encryption scheme. +For more info about the encryption scheme, read the [docs](https://docs.cryptomator.org/en/latest/security/vault/). ## Features @@ -98,7 +99,7 @@ For more details on how to use the constructed `FileSystem`, you may consult the ### Dependencies -* Java 17 +* Java 21 * Maven 3 ### Run Maven diff --git a/pom.xml b/pom.xml index 3847f6b0..569edd68 100644 --- a/pom.xml +++ b/pom.xml @@ -15,7 +15,7 @@ UTF-8 - 17 + 21 2.2.0 @@ -27,7 +27,7 @@ 5.10.3 - 5.2.0 + 5.12.0 3.0 1.3.0 @@ -114,7 +114,7 @@ org.mockito - mockito-inline + mockito-core ${mockito.version} test diff --git a/src/test/java/org/cryptomator/cryptofs/CryptoFileSystemImplTest.java b/src/test/java/org/cryptomator/cryptofs/CryptoFileSystemImplTest.java index e694130f..5095b5cd 100644 --- a/src/test/java/org/cryptomator/cryptofs/CryptoFileSystemImplTest.java +++ b/src/test/java/org/cryptomator/cryptofs/CryptoFileSystemImplTest.java @@ -72,7 +72,6 @@ import static org.hamcrest.Matchers.contains; import static org.hamcrest.Matchers.containsInAnyOrder; import static org.mockito.ArgumentMatchers.any; -import static org.mockito.ArgumentMatchers.isA; import static org.mockito.Mockito.doAnswer; import static org.mockito.Mockito.doNothing; import static org.mockito.Mockito.doThrow; @@ -959,6 +958,7 @@ public void copyDirectory() throws IOException { when(physicalFsProv.newFileChannel(Mockito.eq(ciphertextDestinationDirFile), Mockito.any(), any(FileAttribute[].class))).thenReturn(ciphertextTargetDirDirFileFileChannel); when(cryptoPathMapper.getCiphertextFileType(cleartextSource)).thenReturn(CiphertextFileType.DIRECTORY); when(cryptoPathMapper.getCiphertextFileType(cleartextDestination)).thenThrow(NoSuchFileException.class); + when(physicalFsProv.exists(ciphertextTargetParent)).thenReturn(true); Mockito.doThrow(new NoSuchFileException("ciphertextDestinationDirFile")).when(physicalFsProv).checkAccess(ciphertextDestinationFile); inTest.copy(cleartextSource, cleartextDestination); @@ -1007,6 +1007,7 @@ public void moveDirectoryCopyBasicAttributes() throws IOException { when(physicalFsProv.readAttributes(Mockito.same(ciphertextSourceDir), Mockito.same(BasicFileAttributes.class), any(LinkOption[].class))).thenReturn(srcAttrs); when(physicalFsProv.getFileAttributeView(Mockito.same(ciphertextDestinationDir), Mockito.same(BasicFileAttributeView.class), any(LinkOption[].class))).thenReturn(dstAttrView); when(physicalFsProv.newFileChannel(Mockito.same(ciphertextDestinationDirFile), Mockito.anySet(), any(FileAttribute[].class))).thenReturn(ciphertextTargetDirDirFileFileChannel); + when(physicalFsProv.exists(ciphertextTargetParent)).thenReturn(true); inTest.copy(cleartextSource, cleartextDestination, StandardCopyOption.COPY_ATTRIBUTES); @@ -1027,6 +1028,7 @@ public void moveDirectoryCopyFileOwnerAttributes() throws IOException { when(physicalFsProv.getFileAttributeView(Mockito.same(ciphertextSourceDir), Mockito.same(FileOwnerAttributeView.class), any(LinkOption[].class))).thenReturn(srcAttrsView); when(physicalFsProv.getFileAttributeView(Mockito.same(ciphertextDestinationDir), Mockito.same(FileOwnerAttributeView.class), any(LinkOption[].class))).thenReturn(dstAttrView); when(physicalFsProv.newFileChannel(Mockito.same(ciphertextDestinationDirFile), Mockito.anySet(), any(FileAttribute[].class))).thenReturn(ciphertextTargetDirDirFileFileChannel); + when(physicalFsProv.exists(ciphertextTargetParent)).thenReturn(true); inTest.copy(cleartextSource, cleartextDestination, StandardCopyOption.COPY_ATTRIBUTES); @@ -1050,6 +1052,7 @@ public void moveDirectoryCopyPosixAttributes() throws IOException { when(physicalFsProv.readAttributes(Mockito.same(ciphertextSourceDir), Mockito.same(PosixFileAttributes.class), any(LinkOption[].class))).thenReturn(srcAttrs); when(physicalFsProv.getFileAttributeView(Mockito.same(ciphertextDestinationDir), Mockito.same(PosixFileAttributeView.class), any(LinkOption[].class))).thenReturn(dstAttrView); when(physicalFsProv.newFileChannel(Mockito.same(ciphertextDestinationDirFile), Mockito.anySet(), any(FileAttribute[].class))).thenReturn(ciphertextTargetDirDirFileFileChannel); + when(physicalFsProv.exists(ciphertextTargetParent)).thenReturn(true); inTest.copy(cleartextSource, cleartextDestination, StandardCopyOption.COPY_ATTRIBUTES); @@ -1073,6 +1076,7 @@ public void moveDirectoryCopyDosAttributes() throws IOException { when(physicalFsProv.readAttributes(Mockito.same(ciphertextSourceDir), Mockito.same(DosFileAttributes.class), any(LinkOption[].class))).thenReturn(srcAttrs); when(physicalFsProv.getFileAttributeView(Mockito.same(ciphertextDestinationDir), Mockito.same(DosFileAttributeView.class), any(LinkOption[].class))).thenReturn(dstAttrView); when(physicalFsProv.newFileChannel(Mockito.same(ciphertextDestinationDirFile), Mockito.anySet(), any(FileAttribute[].class))).thenReturn(ciphertextTargetDirDirFileFileChannel); + when(physicalFsProv.exists(ciphertextTargetParent)).thenReturn(true); inTest.copy(cleartextSource, cleartextDestination, StandardCopyOption.COPY_ATTRIBUTES); @@ -1168,6 +1172,7 @@ public void createDirectoryIfPathCiphertextFileDoesExistThrowsFileAlreadyExcepti when(cryptoPathMapper.getCiphertextDir(parent)).thenReturn(new CiphertextDirectory("foo", ciphertextParent)); when(ciphertextParent.getFileSystem()).thenReturn(fileSystem); doThrow(new FileAlreadyExistsException(path.toString())).when(cryptoPathMapper).assertNonExisting(path); + when(provider.exists(ciphertextParent)).thenReturn(true); FileAlreadyExistsException e = Assertions.assertThrows(FileAlreadyExistsException.class, () -> { inTest.createDirectory(path); @@ -1177,7 +1182,7 @@ public void createDirectoryIfPathCiphertextFileDoesExistThrowsFileAlreadyExcepti @Test public void createDirectoryCreatesDirectoryIfConditonsAreMet() throws IOException { - Path ciphertextParent = mock(Path.class, "ciphertextParent"); + Path ciphertextParent = mock(Path.class, "d/00/00"); Path ciphertextRawPath = mock(Path.class, "d/00/00/path.c9r"); Path ciphertextDirFile = mock(Path.class, "d/00/00/path.c9r/dir.c9r"); Path ciphertextDirPath = mock(Path.class, "d/FF/FF/"); @@ -1187,7 +1192,7 @@ public void createDirectoryCreatesDirectoryIfConditonsAreMet() throws IOExceptio when(ciphertextRawPath.resolve("dir.c9r")).thenReturn(ciphertextDirFile); when(cryptoPathMapper.getCiphertextFilePath(path)).thenReturn(ciphertextPath); when(cryptoPathMapper.getCiphertextDir(path)).thenReturn(new CiphertextDirectory(dirId, ciphertextDirPath)); - when(cryptoPathMapper.getCiphertextDir(parent)).thenReturn(new CiphertextDirectory("parentDirId", ciphertextDirPath)); + when(cryptoPathMapper.getCiphertextDir(parent)).thenReturn(new CiphertextDirectory("parentDirId", ciphertextParent)); when(cryptoPathMapper.getCiphertextFileType(path)).thenThrow(NoSuchFileException.class); when(ciphertextPath.getRawPath()).thenReturn(ciphertextRawPath); when(ciphertextPath.getDirFilePath()).thenReturn(ciphertextDirFile); @@ -1197,6 +1202,7 @@ public void createDirectoryCreatesDirectoryIfConditonsAreMet() throws IOExceptio when(ciphertextDirPath.getFileSystem()).thenReturn(fileSystem); when(ciphertextDirFile.getName(3)).thenReturn(mock(Path.class, "path.c9r")); when(provider.newFileChannel(ciphertextDirFile, EnumSet.of(StandardOpenOption.CREATE_NEW, StandardOpenOption.WRITE))).thenReturn(channel); + when(provider.exists(ciphertextParent)).thenReturn(true); inTest.createDirectory(path); @@ -1206,7 +1212,7 @@ public void createDirectoryCreatesDirectoryIfConditonsAreMet() throws IOExceptio @Test public void createDirectoryClearsDirIdAndDeletesDirFileIfCreatingDirFails() throws IOException { - Path ciphertextParent = mock(Path.class, "ciphertextParent"); + Path ciphertextParent = mock(Path.class, "d/00/00"); Path ciphertextRawPath = mock(Path.class, "d/00/00/path.c9r"); Path ciphertextDirFile = mock(Path.class, "d/00/00/path.c9r/dir.c9r"); Path ciphertextDirPath = mock(Path.class, "d/FF/FF/"); @@ -1216,7 +1222,7 @@ public void createDirectoryClearsDirIdAndDeletesDirFileIfCreatingDirFails() thro when(ciphertextRawPath.resolve("dir.c9r")).thenReturn(ciphertextDirFile); when(cryptoPathMapper.getCiphertextFilePath(path)).thenReturn(ciphertextPath); when(cryptoPathMapper.getCiphertextDir(path)).thenReturn(new CiphertextDirectory(dirId, ciphertextDirPath)); - when(cryptoPathMapper.getCiphertextDir(parent)).thenReturn(new CiphertextDirectory("parentDirId", ciphertextDirPath)); + when(cryptoPathMapper.getCiphertextDir(parent)).thenReturn(new CiphertextDirectory("parentDirId", ciphertextParent)); when(cryptoPathMapper.getCiphertextFileType(path)).thenThrow(NoSuchFileException.class); when(ciphertextPath.getRawPath()).thenReturn(ciphertextRawPath); when(ciphertextPath.getDirFilePath()).thenReturn(ciphertextDirFile); @@ -1226,15 +1232,18 @@ public void createDirectoryClearsDirIdAndDeletesDirFileIfCreatingDirFails() thro when(ciphertextDirPath.getFileSystem()).thenReturn(fileSystem); when(ciphertextDirFile.getName(3)).thenReturn(mock(Path.class, "path.c9r")); when(provider.newFileChannel(ciphertextDirFile, EnumSet.of(StandardOpenOption.CREATE_NEW, StandardOpenOption.WRITE))).thenReturn(channel); + when(provider.exists(ciphertextParent)).thenReturn(true); - // make createDirectory with an FileSystemException during Files.createDirectories(ciphertextDirPath) - doThrow(new IOException()).when(provider).createDirectory(ciphertextDirPath); + // make createDirectory with an FileSystemException during Files.createDirectories(ciphertextContentDir) + doThrow(new IOException()).when(provider).readAttributesIfExists(ciphertextDirPath, BasicFileAttributes.class); + doThrow(new FileAlreadyExistsException("very specific")).when(provider).createDirectory(ciphertextDirPath); when(ciphertextDirPath.toAbsolutePath()).thenReturn(ciphertextDirPath); when(ciphertextDirPath.getParent()).thenReturn(null); - Assertions.assertThrows(IOException.class, () -> { + var exception = Assertions.assertThrows(FileAlreadyExistsException.class, () -> { inTest.createDirectory(path); }); + Assertions.assertEquals("very specific", exception.getMessage()); verify(readonlyFlag).assertWritable(); verify(provider).delete(ciphertextDirFile); verify(dirIdProvider).delete(ciphertextDirFile); @@ -1243,7 +1252,7 @@ public void createDirectoryClearsDirIdAndDeletesDirFileIfCreatingDirFails() thro @Test public void createDirectoryBackupsDirIdInCiphertextDirPath() throws IOException { - Path ciphertextParent = mock(Path.class, "ciphertextParent"); + Path ciphertextParent = mock(Path.class, "d/00/00"); Path ciphertextRawPath = mock(Path.class, "d/00/00/path.c9r"); Path ciphertextDirFile = mock(Path.class, "d/00/00/path.c9r/dir.c9r"); Path ciphertextDirPath = mock(Path.class, "d/FF/FF/"); @@ -1254,7 +1263,7 @@ public void createDirectoryBackupsDirIdInCiphertextDirPath() throws IOException when(ciphertextRawPath.resolve("dir.c9r")).thenReturn(ciphertextDirFile); when(cryptoPathMapper.getCiphertextFilePath(path)).thenReturn(ciphertextPath); when(cryptoPathMapper.getCiphertextDir(path)).thenReturn(cipherDirObject); - when(cryptoPathMapper.getCiphertextDir(parent)).thenReturn(new CiphertextDirectory("parentDirId", ciphertextDirPath)); + when(cryptoPathMapper.getCiphertextDir(parent)).thenReturn(new CiphertextDirectory("parentDirId", ciphertextParent)); when(cryptoPathMapper.getCiphertextFileType(path)).thenThrow(NoSuchFileException.class); when(ciphertextPath.getRawPath()).thenReturn(ciphertextRawPath); when(ciphertextPath.getDirFilePath()).thenReturn(ciphertextDirFile); @@ -1264,6 +1273,7 @@ public void createDirectoryBackupsDirIdInCiphertextDirPath() throws IOException when(ciphertextDirPath.getFileSystem()).thenReturn(fileSystem); when(ciphertextDirFile.getName(3)).thenReturn(mock(Path.class, "path.c9r")); when(provider.newFileChannel(ciphertextDirFile, EnumSet.of(StandardOpenOption.CREATE_NEW, StandardOpenOption.WRITE))).thenReturn(channel); + when(provider.exists(ciphertextParent)).thenReturn(true); inTest.createDirectory(path); diff --git a/src/test/java/org/cryptomator/cryptofs/CryptoPathMapperTest.java b/src/test/java/org/cryptomator/cryptofs/CryptoPathMapperTest.java index e2da36a8..32241fb8 100644 --- a/src/test/java/org/cryptomator/cryptofs/CryptoPathMapperTest.java +++ b/src/test/java/org/cryptomator/cryptofs/CryptoPathMapperTest.java @@ -290,6 +290,7 @@ public void testGetCiphertextFileTypeForDirectory() throws IOException { Mockito.when(underlyingFileSystemProvider.readAttributes(dirFilePath, BasicFileAttributes.class, LinkOption.NOFOLLOW_LINKS)).thenReturn(Mockito.mock(BasicFileAttributes.class)); Mockito.when(underlyingFileSystemProvider.readAttributes(symlinkFilePath, BasicFileAttributes.class, LinkOption.NOFOLLOW_LINKS)).thenThrow(NoSuchFileException.class); Mockito.when(underlyingFileSystemProvider.readAttributes(contentsFilePath, BasicFileAttributes.class, LinkOption.NOFOLLOW_LINKS)).thenThrow(NoSuchFileException.class); + Mockito.when(underlyingFileSystemProvider.exists(dirFilePath, LinkOption.NOFOLLOW_LINKS)).thenReturn(true); CryptoPathMapper mapper = new CryptoPathMapper(pathToVault, cryptor, dirIdProvider, longFileNameProvider, vaultConfig); @@ -305,6 +306,7 @@ public void testGetCiphertextFileTypeForSymlink() throws IOException { Mockito.when(underlyingFileSystemProvider.readAttributes(dirFilePath, BasicFileAttributes.class, LinkOption.NOFOLLOW_LINKS)).thenThrow(NoSuchFileException.class); Mockito.when(underlyingFileSystemProvider.readAttributes(symlinkFilePath, BasicFileAttributes.class, LinkOption.NOFOLLOW_LINKS)).thenReturn(Mockito.mock(BasicFileAttributes.class)); Mockito.when(underlyingFileSystemProvider.readAttributes(contentsFilePath, BasicFileAttributes.class, LinkOption.NOFOLLOW_LINKS)).thenThrow(NoSuchFileException.class); + Mockito.when(underlyingFileSystemProvider.exists(symlinkFilePath, LinkOption.NOFOLLOW_LINKS)).thenReturn(true); CryptoPathMapper mapper = new CryptoPathMapper(pathToVault, cryptor, dirIdProvider, longFileNameProvider, vaultConfig); @@ -322,6 +324,7 @@ public void testGetCiphertextFileTypeForShortenedFile() throws IOException { Mockito.when(underlyingFileSystemProvider.readAttributes(contentsFilePath, BasicFileAttributes.class, LinkOption.NOFOLLOW_LINKS)).thenReturn(Mockito.mock(BasicFileAttributes.class)); Mockito.when(fileNameCryptor.encryptFilename(Mockito.any(), Mockito.eq("LONGCLEAR"), Mockito.any())).thenReturn(Strings.repeat("A", 1000)); Mockito.when(longFileNameProvider.deflate(Mockito.any())).thenReturn(new LongFileNameProvider.DeflatedFileName(c9rPath, null, null)); + Mockito.when(underlyingFileSystemProvider.exists(contentsFilePath, LinkOption.NOFOLLOW_LINKS)).thenReturn(true); CryptoPathMapper mapper = new CryptoPathMapper(pathToVault, cryptor, dirIdProvider, longFileNameProvider, vaultConfig); From 183dfab7787854446499dc0273d0b8f68426cd37 Mon Sep 17 00:00:00 2001 From: Armin Schrenk Date: Fri, 9 Aug 2024 17:58:56 +0200 Subject: [PATCH 22/22] prepare 2.7.0 --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 569edd68..a0fc375d 100644 --- a/pom.xml +++ b/pom.xml @@ -2,7 +2,7 @@ 4.0.0 org.cryptomator cryptofs - 2.7.0-SNAPSHOT + 2.7.0 Cryptomator Crypto Filesystem This library provides the Java filesystem provider used by Cryptomator. https://github.com/cryptomator/cryptofs