From a0d93ca95b823608ec523e0ce95de9c8f3904396 Mon Sep 17 00:00:00 2001 From: Sebastian Stenzel Date: Mon, 11 Nov 2019 11:18:46 +0100 Subject: [PATCH] Opening FileChannels on readonly file systems no longer attempts to write long filename metadata fixes #68 --- .../cryptofs/CryptoFileSystemImpl.java | 4 +- .../cryptofs/CryptoFileSystemImplTest.java | 56 +++++++++++++++++++ 2 files changed, 59 insertions(+), 1 deletion(-) diff --git a/src/main/java/org/cryptomator/cryptofs/CryptoFileSystemImpl.java b/src/main/java/org/cryptomator/cryptofs/CryptoFileSystemImpl.java index db4fac79..ece13e75 100644 --- a/src/main/java/org/cryptomator/cryptofs/CryptoFileSystemImpl.java +++ b/src/main/java/org/cryptomator/cryptofs/CryptoFileSystemImpl.java @@ -356,7 +356,9 @@ private FileChannel newFileChannel(CryptoPath cleartextFilePath, EffectiveOpenOp } else { // might also throw FileAlreadyExists: FileChannel ch = openCryptoFiles.getOrCreate(ciphertextPath).newFileChannel(options); - longFileNameProvider.getCached(ciphertextPath).ifPresent(LongFileNameProvider.DeflatedFileName::persist); + if (options.writable()) { + longFileNameProvider.getCached(ciphertextPath).ifPresent(LongFileNameProvider.DeflatedFileName::persist); + } return ch; } } diff --git a/src/test/java/org/cryptomator/cryptofs/CryptoFileSystemImplTest.java b/src/test/java/org/cryptomator/cryptofs/CryptoFileSystemImplTest.java index 60460c81..1dd145cd 100644 --- a/src/test/java/org/cryptomator/cryptofs/CryptoFileSystemImplTest.java +++ b/src/test/java/org/cryptomator/cryptofs/CryptoFileSystemImplTest.java @@ -5,6 +5,7 @@ import org.cryptomator.cryptofs.attr.AttributeProvider; import org.cryptomator.cryptofs.attr.AttributeViewProvider; import org.cryptomator.cryptofs.attr.AttributeViewType; +import org.cryptomator.cryptofs.fh.OpenCryptoFile; import org.cryptomator.cryptofs.fh.OpenCryptoFiles; import org.cryptomator.cryptofs.fh.OpenCryptoFiles.TwoPhaseMove; import org.cryptomator.cryptofs.mocks.FileChannelMock; @@ -17,6 +18,7 @@ import org.junit.jupiter.api.Test; import org.mockito.Mockito; +import javax.inject.Named; import java.io.IOException; import java.lang.reflect.Field; import java.nio.ByteBuffer; @@ -52,6 +54,7 @@ import java.util.Collections; import java.util.EnumSet; import java.util.Iterator; +import java.util.Optional; import java.util.Set; import java.util.concurrent.TimeUnit; @@ -333,6 +336,59 @@ public void testNewWatchServiceThrowsUnsupportedOperationException() throws IOEx inTest.newWatchService(); }); } + + @Nested + public class NewFileChannel { + + private final CryptoPath cleartextPath = mock(CryptoPath.class, "cleartext"); + private final Path ciphertextPath = mock(Path.class, "ciphertext"); + private final OpenCryptoFile openCryptoFile = mock(OpenCryptoFile.class); + private final FileChannel fileChannel = mock(FileChannel.class); + + @BeforeEach + public void setup() throws IOException { + when(cryptoPathMapper.getCiphertextFileType(cleartextPath)).thenReturn(CiphertextFileType.FILE); + when(cryptoPathMapper.getCiphertextFilePath(cleartextPath, CiphertextFileType.FILE)).thenReturn(ciphertextPath); + when(openCryptoFiles.getOrCreate(ciphertextPath)).thenReturn(openCryptoFile); + when(openCryptoFile.newFileChannel(any())).thenReturn(fileChannel); + } + + @Test + @Named("newFileChannel read-only") + public void testNewFileChannelReadOnly() throws IOException { + FileChannel ch = inTest.newFileChannel(cleartextPath, EnumSet.of(StandardOpenOption.READ)); + + Assertions.assertSame(fileChannel, ch); + verify(readonlyFlag, Mockito.never()).assertWritable(); + } + + @Test + @Named("newFileChannel read-only with long filename") + public void testNewFileChannelReadOnlyShortened() throws IOException { + LongFileNameProvider.DeflatedFileName deflatedFileName = Mockito.mock(LongFileNameProvider.DeflatedFileName.class); + when(longFileNameProvider.getCached(ciphertextPath)).thenReturn(Optional.of(deflatedFileName)); + + FileChannel ch = inTest.newFileChannel(cleartextPath, EnumSet.of(StandardOpenOption.READ)); + + Assertions.assertSame(fileChannel, ch); + verify(readonlyFlag, Mockito.never()).assertWritable(); + verify(deflatedFileName, Mockito.never()).persist(); + } + + @Test + @Named("newFileChannel read-write with long filename") + public void testNewFileChannelReadWriteShortened() throws IOException { + LongFileNameProvider.DeflatedFileName deflatedFileName = Mockito.mock(LongFileNameProvider.DeflatedFileName.class); + when(longFileNameProvider.getCached(ciphertextPath)).thenReturn(Optional.of(deflatedFileName)); + + FileChannel ch = inTest.newFileChannel(cleartextPath, EnumSet.of(StandardOpenOption.WRITE)); + + Assertions.assertSame(fileChannel, ch); + verify(readonlyFlag, Mockito.atLeastOnce()).assertWritable(); + verify(deflatedFileName).persist(); + } + + } @Nested public class Delete {