Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 3 additions & 5 deletions src/main/java/org/cryptomator/cryptofs/fh/OpenCryptoFile.java
Original file line number Diff line number Diff line change
Expand Up @@ -70,15 +70,13 @@ public synchronized FileChannel newFileChannel(EffectiveOpenOptions options, Fil
try {
ciphertextFileChannel = path.getFileSystem().provider().newFileChannel(path, options.createOpenOptionsForEncryptedFile(), attrs);
initFileHeader(options, ciphertextFileChannel);
if (options.truncateExisting()) {
chunkCache.invalidateStale();
ciphertextFileChannel.truncate(cryptor.fileHeaderCryptor().headerSize());
fileSize.set(0);
}
initFileSize(ciphertextFileChannel);
cleartextFileChannel = component.newChannelComponent() //
.create(ciphertextFileChannel, options, this::cleartextChannelClosed) //
.channel();
if (options.truncateExisting()) {
cleartextFileChannel.truncate(0);
}
} finally {
if (cleartextFileChannel == null) { // i.e. something didn't work
cleartextChannelClosed(ciphertextFileChannel);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -616,8 +616,8 @@ public void testWriteThenDeleteThenRead() throws IOException {
Assertions.assertEquals(-1, bytesRead);
}

@RepeatedTest(50)
public void testConcurrentWriteAndTruncate() throws IOException {
@RepeatedTest(15)
public void testConcurrentWriteAndTruncate() throws IOException, InterruptedException {
AtomicBoolean keepWriting = new AtomicBoolean(true);
ByteBuffer buf = ByteBuffer.wrap("the quick brown fox jumps over the lazy dog".getBytes(StandardCharsets.UTF_8));
var executor = Executors.newCachedThreadPool();
Expand All @@ -632,6 +632,7 @@ public void testConcurrentWriteAndTruncate() throws IOException {
buf.flip();
}
});
Thread.sleep(1000);
try (FileChannel truncatingChannel = FileChannel.open(file, WRITE, TRUNCATE_EXISTING)) {
keepWriting.set(false);
}
Expand Down
20 changes: 4 additions & 16 deletions src/test/java/org/cryptomator/cryptofs/fh/OpenCryptoFileTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -93,19 +93,20 @@ public void testCloseImmediatelyIfOpeningFirstChannelFails() {
}

@Test
@DisplayName("Opening a file channel with TRUNCATE_EXISTING sets the file size to 0")
@DisplayName("Opening a file channel with TRUNCATE_EXISTING calls truncate(0) on the cleartextChannel")
public void testFileSizeZerodOnTruncateExisting() throws IOException {
EffectiveOpenOptions options = EffectiveOpenOptions.from(EnumSet.of(StandardOpenOption.CREATE_NEW, StandardOpenOption.WRITE, StandardOpenOption.TRUNCATE_EXISTING), readonlyFlag);
var cleartextChannel = mock(CleartextFileChannel.class);
Mockito.when(headerHolder.get()).thenReturn(Mockito.mock(FileHeader.class));
Mockito.when(cryptor.fileHeaderCryptor()).thenReturn(fileHeaderCryptor);
Mockito.when(fileHeaderCryptor.headerSize()).thenReturn(42);
Mockito.when(openCryptoFileComponent.newChannelComponent()).thenReturn(channelComponentFactory);
Mockito.when(channelComponentFactory.create(any(), any(), any())).thenReturn(channelComponent);
Mockito.when(channelComponent.channel()).thenReturn(mock(CleartextFileChannel.class));
Mockito.when(channelComponent.channel()).thenReturn(cleartextChannel);
OpenCryptoFile openCryptoFile = new OpenCryptoFile(closeListener, chunkCache, cryptor, headerHolder, chunkIO, CURRENT_FILE_PATH, fileSize, lastModified, openCryptoFileComponent);

openCryptoFile.newFileChannel(options);
verify(fileSize).set(0L);
verify(cleartextChannel).truncate(0L);
}

@Nested
Expand Down Expand Up @@ -260,19 +261,6 @@ public void testGetSizeAfterCreatingSecondFileChannel() {
Assertions.assertEquals(0l, openCryptoFile.size().get());
}


@Test
@Order(20)
@DisplayName("TRUNCATE_EXISTING leads to chunk cache invalidation")
public void testTruncateExistingInvalidatesChunkCache() throws IOException {
Mockito.when(cryptor.fileHeaderCryptor()).thenReturn(fileHeaderCryptor);
Mockito.when(fileHeaderCryptor.headerSize()).thenReturn(43);
Files.write(CURRENT_FILE_PATH.get(), new byte[0]);
EffectiveOpenOptions options = EffectiveOpenOptions.from(EnumSet.of(StandardOpenOption.TRUNCATE_EXISTING, StandardOpenOption.WRITE), readonlyFlag);
openCryptoFile.newFileChannel(options);
verify(chunkCache).invalidateStale();
}

@Test
@Order(100)
@DisplayName("closeListener triggers chunkIO.unregisterChannel()")
Expand Down
Loading