From 7507320239286484f7a828f478c2b162754917a6 Mon Sep 17 00:00:00 2001 From: infeo Date: Wed, 7 Nov 2018 15:18:58 +0100 Subject: [PATCH 1/8] fixing NullPointerException in setTimes in abstractFileAttributeView --- .../cryptomator/cryptofs/AbstractCryptoFileAttributeView.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/main/java/org/cryptomator/cryptofs/AbstractCryptoFileAttributeView.java b/src/main/java/org/cryptomator/cryptofs/AbstractCryptoFileAttributeView.java index c414a2ea..d40da773 100644 --- a/src/main/java/org/cryptomator/cryptofs/AbstractCryptoFileAttributeView.java +++ b/src/main/java/org/cryptomator/cryptofs/AbstractCryptoFileAttributeView.java @@ -46,7 +46,9 @@ public final S readAttributes() throws IOException { public void setTimes(FileTime lastModifiedTime, FileTime lastAccessTime, FileTime createTime) throws IOException { readonlyFlag.assertWritable(); delegate.setTimes(lastModifiedTime, lastAccessTime, createTime); - openCryptoFile.ifPresent(file -> file.setLastModifiedTime(lastModifiedTime)); + if(lastModifiedTime != null){ + openCryptoFile.ifPresent(file -> file.setLastModifiedTime(lastModifiedTime)); + } } } From 491bf6f0c1f383246435ee81d7339f1634043fb5 Mon Sep 17 00:00:00 2001 From: Sebastian Stenzel Date: Wed, 14 Nov 2018 14:16:11 +0100 Subject: [PATCH 2/8] merged redundant dagger modules --- .../cryptofs/OpenCryptoFileComponent.java | 2 +- .../cryptofs/OpenCryptoFileFactoryModule.java | 81 ------------------- .../cryptofs/OpenCryptoFileModule.java | 65 +++++++++++++++ 3 files changed, 66 insertions(+), 82 deletions(-) delete mode 100644 src/main/java/org/cryptomator/cryptofs/OpenCryptoFileFactoryModule.java diff --git a/src/main/java/org/cryptomator/cryptofs/OpenCryptoFileComponent.java b/src/main/java/org/cryptomator/cryptofs/OpenCryptoFileComponent.java index 64c91c70..12516059 100644 --- a/src/main/java/org/cryptomator/cryptofs/OpenCryptoFileComponent.java +++ b/src/main/java/org/cryptomator/cryptofs/OpenCryptoFileComponent.java @@ -2,7 +2,7 @@ import dagger.Subcomponent; -@Subcomponent(modules = {OpenCryptoFileModule.class, OpenCryptoFileFactoryModule.class}) +@Subcomponent(modules = {OpenCryptoFileModule.class}) @PerOpenFile interface OpenCryptoFileComponent { diff --git a/src/main/java/org/cryptomator/cryptofs/OpenCryptoFileFactoryModule.java b/src/main/java/org/cryptomator/cryptofs/OpenCryptoFileFactoryModule.java deleted file mode 100644 index e20d3ec0..00000000 --- a/src/main/java/org/cryptomator/cryptofs/OpenCryptoFileFactoryModule.java +++ /dev/null @@ -1,81 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2017 Skymatic UG (haftungsbeschränkt). - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the accompanying LICENSE file. - *******************************************************************************/ -package org.cryptomator.cryptofs; - -import dagger.Module; -import dagger.Provides; -import org.cryptomator.cryptolib.api.Cryptor; -import org.cryptomator.cryptolib.api.FileHeader; - -import java.io.IOException; -import java.nio.ByteBuffer; -import java.nio.channels.FileChannel; -import java.nio.file.Path; -import java.nio.file.attribute.BasicFileAttributeView; -import java.util.concurrent.atomic.AtomicLong; - -import static org.cryptomator.cryptofs.UncheckedThrows.rethrowUnchecked; -import static org.cryptomator.cryptolib.Cryptors.cleartextSize; - -@Module -class OpenCryptoFileFactoryModule { - - @Provides - @PerOpenFile - public FileChannel provideFileChannel(@OriginalOpenFilePath Path path, EffectiveOpenOptions options) { - return rethrowUnchecked(IOException.class).from(() -> path.getFileSystem().provider().newFileChannel(path, options.createOpenOptionsForEncryptedFile())); - } - - @Provides - @PerOpenFile - public BasicFileAttributeView provideBasicFileAttributeView(@OriginalOpenFilePath Path path) { - return path.getFileSystem().provider().getFileAttributeView(path, BasicFileAttributeView.class); - } - - @Provides - @PerOpenFile - @OpenFileSize - public AtomicLong provideFileSize(FileChannel channel, Cryptor cryptor) { - return rethrowUnchecked(IOException.class).from(() -> { - long size = channel.size(); - if (size == 0) { - return new AtomicLong(); - } else { - int headerSize = cryptor.fileHeaderCryptor().headerSize(); - return new AtomicLong(cleartextSize(size - headerSize, cryptor)); - } - }); - } - - @Provides - @PerOpenFile - public FileHeader provideFileHeader(FileChannel channel, Cryptor cryptor, EffectiveOpenOptions options) { - return rethrowUnchecked(IOException.class).from(() -> { - if (options.truncateExisting() || isNewFile(channel, options)) { - FileHeader newHeader = cryptor.fileHeaderCryptor().create(); - channel.position(0); - channel.write(cryptor.fileHeaderCryptor().encryptHeader(newHeader)); - channel.force(false); - return newHeader; - } else { - ByteBuffer existingHeaderBuf = ByteBuffer.allocate(cryptor.fileHeaderCryptor().headerSize()); - channel.position(0); - channel.read(existingHeaderBuf); - existingHeaderBuf.flip(); - try { - return cryptor.fileHeaderCryptor().decryptHeader(existingHeaderBuf); - } catch (IllegalArgumentException e) { - throw new IOException(e); - } - } - }); - } - - private boolean isNewFile(FileChannel channel, EffectiveOpenOptions options) throws IOException { - return options.createNew() || options.create() && channel.size() == 0; - } - -} diff --git a/src/main/java/org/cryptomator/cryptofs/OpenCryptoFileModule.java b/src/main/java/org/cryptomator/cryptofs/OpenCryptoFileModule.java index 2a239432..0704baba 100644 --- a/src/main/java/org/cryptomator/cryptofs/OpenCryptoFileModule.java +++ b/src/main/java/org/cryptomator/cryptofs/OpenCryptoFileModule.java @@ -1,9 +1,19 @@ package org.cryptomator.cryptofs; +import java.io.IOException; +import java.nio.ByteBuffer; +import java.nio.channels.FileChannel; import java.nio.file.Path; +import java.nio.file.attribute.BasicFileAttributeView; +import java.util.concurrent.atomic.AtomicLong; import dagger.Module; import dagger.Provides; +import org.cryptomator.cryptolib.api.Cryptor; +import org.cryptomator.cryptolib.api.FileHeader; + +import static org.cryptomator.cryptofs.UncheckedThrows.rethrowUnchecked; +import static org.cryptomator.cryptolib.Cryptors.cleartextSize; @Module class OpenCryptoFileModule { @@ -29,6 +39,61 @@ public EffectiveOpenOptions provideOptions() { return options; } + @Provides + @PerOpenFile + public FileChannel provideFileChannel(@OriginalOpenFilePath Path path, EffectiveOpenOptions options) { + return rethrowUnchecked(IOException.class).from(() -> path.getFileSystem().provider().newFileChannel(path, options.createOpenOptionsForEncryptedFile())); + } + + @Provides + @PerOpenFile + public BasicFileAttributeView provideBasicFileAttributeView(@OriginalOpenFilePath Path path) { + return path.getFileSystem().provider().getFileAttributeView(path, BasicFileAttributeView.class); + } + + @Provides + @PerOpenFile + @OpenFileSize + public AtomicLong provideFileSize(FileChannel channel, Cryptor cryptor) { + return rethrowUnchecked(IOException.class).from(() -> { + long size = channel.size(); + if (size == 0) { + return new AtomicLong(); + } else { + int headerSize = cryptor.fileHeaderCryptor().headerSize(); + return new AtomicLong(cleartextSize(size - headerSize, cryptor)); + } + }); + } + + @Provides + @PerOpenFile + public FileHeader provideFileHeader(FileChannel channel, Cryptor cryptor, EffectiveOpenOptions options) { + return rethrowUnchecked(IOException.class).from(() -> { + if (options.truncateExisting() || isNewFile(channel, options)) { + FileHeader newHeader = cryptor.fileHeaderCryptor().create(); + channel.position(0); + channel.write(cryptor.fileHeaderCryptor().encryptHeader(newHeader)); + channel.force(false); + return newHeader; + } else { + ByteBuffer existingHeaderBuf = ByteBuffer.allocate(cryptor.fileHeaderCryptor().headerSize()); + channel.position(0); + channel.read(existingHeaderBuf); + existingHeaderBuf.flip(); + try { + return cryptor.fileHeaderCryptor().decryptHeader(existingHeaderBuf); + } catch (IllegalArgumentException e) { + throw new IOException(e); + } + } + }); + } + + private boolean isNewFile(FileChannel channel, EffectiveOpenOptions options) throws IOException { + return options.createNew() || options.create() && channel.size() == 0; + } + public static Builder openCryptoFileModule() { return new Builder(); } From 061e4c9c3382bd912e94d8142d6e62b089d3d9a6 Mon Sep 17 00:00:00 2001 From: Sebastian Stenzel Date: Wed, 14 Nov 2018 14:41:59 +0100 Subject: [PATCH 3/8] No longer eagerly creating and keeping an AttributeView. Getting it on-demand instead. References #37 --- .../cryptofs/CurrentOpenFilePath.java | 17 +++++++++++++ .../cryptomator/cryptofs/OpenCryptoFile.java | 19 +++++++------- .../cryptofs/OpenCryptoFileModule.java | 25 +++++++++++++------ .../cryptofs/OriginalOpenFilePath.java | 1 + .../cryptofs/OpenCryptoFileModuleTest.java | 3 ++- .../cryptofs/OpenCryptoFileTest.java | 9 ++++++- 6 files changed, 56 insertions(+), 18 deletions(-) create mode 100644 src/main/java/org/cryptomator/cryptofs/CurrentOpenFilePath.java diff --git a/src/main/java/org/cryptomator/cryptofs/CurrentOpenFilePath.java b/src/main/java/org/cryptomator/cryptofs/CurrentOpenFilePath.java new file mode 100644 index 00000000..218de800 --- /dev/null +++ b/src/main/java/org/cryptomator/cryptofs/CurrentOpenFilePath.java @@ -0,0 +1,17 @@ +package org.cryptomator.cryptofs; + +import javax.inject.Qualifier; +import java.lang.annotation.Documented; +import java.lang.annotation.Retention; + +import static java.lang.annotation.RetentionPolicy.RUNTIME; + +/** + * The current Path of an OpenCryptoFile. + * @see OriginalOpenFilePath + */ +@Qualifier +@Documented +@Retention(RUNTIME) +@interface CurrentOpenFilePath { +} diff --git a/src/main/java/org/cryptomator/cryptofs/OpenCryptoFile.java b/src/main/java/org/cryptomator/cryptofs/OpenCryptoFile.java index ace05ba4..a9336612 100644 --- a/src/main/java/org/cryptomator/cryptofs/OpenCryptoFile.java +++ b/src/main/java/org/cryptomator/cryptofs/OpenCryptoFile.java @@ -12,6 +12,7 @@ import org.cryptomator.cryptolib.api.FileHeader; import javax.inject.Inject; +import javax.inject.Provider; import java.io.IOException; import java.nio.ByteBuffer; import java.nio.channels.FileChannel; @@ -43,16 +44,15 @@ class OpenCryptoFile { private final CryptoFileSystemStats stats; private final ExceptionsDuringWrite exceptionsDuringWrite; private final FinallyUtil finallyUtil; - private final BasicFileAttributeView attributeView; + private final Provider attributeViewProvider; private final AtomicBoolean headerWritten; private final AtomicReference lastModified; private final AtomicInteger openChannelCounter; - - private Path currentFilePath; + private final AtomicReference currentFilePath; @Inject public OpenCryptoFile(Cryptor cryptor, FileChannel channel, FileHeader header, @OpenFileSize AtomicLong size, CryptoFileChannelFactory cryptoFileChannelFactory, - ChunkCache chunkCache, OpenCryptoFiles openCryptoFileFactory, CryptoFileSystemStats stats, ExceptionsDuringWrite exceptionsDuringWrite, FinallyUtil finallyUtil, BasicFileAttributeView attrView) { + ChunkCache chunkCache, OpenCryptoFiles openCryptoFileFactory, CryptoFileSystemStats stats, ExceptionsDuringWrite exceptionsDuringWrite, FinallyUtil finallyUtil, Provider attrViewProvider, @CurrentOpenFilePath AtomicReference currentFilePath) { this.cryptor = cryptor; this.channel = channel; this.header = header; @@ -63,11 +63,12 @@ public OpenCryptoFile(Cryptor cryptor, FileChannel channel, FileHeader header, @ this.stats = stats; this.exceptionsDuringWrite = exceptionsDuringWrite; this.finallyUtil = finallyUtil; - this.attributeView = attrView; + this.attributeViewProvider = attrViewProvider; + this.currentFilePath = currentFilePath; this.headerWritten = new AtomicBoolean(false); this.lastModified = new AtomicReference<>(); try { - lastModified.set(attrView.readAttributes().lastModifiedTime().toInstant()); + lastModified.set(attrViewProvider.get().readAttributes().lastModifiedTime().toInstant()); } catch (IOException e) { lastModified.set(Instant.ofEpochSecond(0)); } @@ -195,7 +196,7 @@ public synchronized void force(boolean metaData, EffectiveOpenOptions options) t } channel.force(metaData); try { - attributeView.setTimes(FileTime.from(lastModified.get()), null, null); + attributeViewProvider.get().setTimes(FileTime.from(lastModified.get()), null, null); } catch (NoSuchFileException e) { //NO-OP because file is already deleted } @@ -220,11 +221,11 @@ void decreaseOpenChannelCounter() throws IOException { } public Path getCurrentFilePath() { - return currentFilePath; + return currentFilePath.get(); } public void setCurrentFilePath(Path currentFilePath) { - this.currentFilePath = currentFilePath; + this.currentFilePath.set(currentFilePath); } public void close() throws IOException { diff --git a/src/main/java/org/cryptomator/cryptofs/OpenCryptoFileModule.java b/src/main/java/org/cryptomator/cryptofs/OpenCryptoFileModule.java index 0704baba..dc0f41ac 100644 --- a/src/main/java/org/cryptomator/cryptofs/OpenCryptoFileModule.java +++ b/src/main/java/org/cryptomator/cryptofs/OpenCryptoFileModule.java @@ -6,6 +6,7 @@ import java.nio.file.Path; import java.nio.file.attribute.BasicFileAttributeView; import java.util.concurrent.atomic.AtomicLong; +import java.util.concurrent.atomic.AtomicReference; import dagger.Module; import dagger.Provides; @@ -18,19 +19,28 @@ @Module class OpenCryptoFileModule { - private final Path path; + private final Path originalPath; + private final AtomicReference currentPath; private final EffectiveOpenOptions options; private OpenCryptoFileModule(Builder builder) { - this.path = builder.path; + this.originalPath = builder.path; + this.currentPath = new AtomicReference<>(builder.path); this.options = builder.options; } @Provides @PerOpenFile @OriginalOpenFilePath - public Path providePath() { - return path; + public Path provideOriginalPath() { + return originalPath; + } + + @Provides + @PerOpenFile + @CurrentOpenFilePath + public AtomicReference provideCurrentPath() { + return currentPath; } @Provides @@ -41,13 +51,14 @@ public EffectiveOpenOptions provideOptions() { @Provides @PerOpenFile - public FileChannel provideFileChannel(@OriginalOpenFilePath Path path, EffectiveOpenOptions options) { - return rethrowUnchecked(IOException.class).from(() -> path.getFileSystem().provider().newFileChannel(path, options.createOpenOptionsForEncryptedFile())); + public FileChannel provideFileChannel(EffectiveOpenOptions options) { + return rethrowUnchecked(IOException.class).from(() -> originalPath.getFileSystem().provider().newFileChannel(originalPath, options.createOpenOptionsForEncryptedFile())); } @Provides @PerOpenFile - public BasicFileAttributeView provideBasicFileAttributeView(@OriginalOpenFilePath Path path) { + public BasicFileAttributeView provideBasicFileAttributeView() { + Path path = currentPath.get(); return path.getFileSystem().provider().getFileAttributeView(path, BasicFileAttributeView.class); } diff --git a/src/main/java/org/cryptomator/cryptofs/OriginalOpenFilePath.java b/src/main/java/org/cryptomator/cryptofs/OriginalOpenFilePath.java index b3f00fd5..da52cca6 100644 --- a/src/main/java/org/cryptomator/cryptofs/OriginalOpenFilePath.java +++ b/src/main/java/org/cryptomator/cryptofs/OriginalOpenFilePath.java @@ -9,6 +9,7 @@ /** * The Path used to create an OpenCryptoFile + * @see CurrentOpenFilePath */ @Qualifier @Documented diff --git a/src/test/java/org/cryptomator/cryptofs/OpenCryptoFileModuleTest.java b/src/test/java/org/cryptomator/cryptofs/OpenCryptoFileModuleTest.java index 800a308e..965635c0 100644 --- a/src/test/java/org/cryptomator/cryptofs/OpenCryptoFileModuleTest.java +++ b/src/test/java/org/cryptomator/cryptofs/OpenCryptoFileModuleTest.java @@ -33,7 +33,8 @@ public void testBuilder() { .build(); assertThat(inTest.provideOptions(), is(options)); - assertThat(inTest.providePath(), is(path)); + assertThat(inTest.provideOriginalPath(), is(path)); + assertThat(inTest.provideCurrentPath().get(), is(path)); } @Test diff --git a/src/test/java/org/cryptomator/cryptofs/OpenCryptoFileTest.java b/src/test/java/org/cryptomator/cryptofs/OpenCryptoFileTest.java index 7d992ba5..85fe1a44 100644 --- a/src/test/java/org/cryptomator/cryptofs/OpenCryptoFileTest.java +++ b/src/test/java/org/cryptomator/cryptofs/OpenCryptoFileTest.java @@ -16,18 +16,22 @@ import org.mockito.junit.MockitoJUnit; import org.mockito.junit.MockitoRule; +import javax.inject.Provider; import java.io.IOException; import java.nio.ByteBuffer; import java.nio.channels.FileChannel; import java.nio.channels.FileLock; import java.nio.file.NoSuchFileException; +import java.nio.file.Path; import java.nio.file.StandardOpenOption; +import java.nio.file.attribute.AttributeView; import java.nio.file.attribute.BasicFileAttributeView; import java.nio.file.attribute.BasicFileAttributes; import java.nio.file.attribute.FileTime; import java.time.Instant; import java.util.EnumSet; import java.util.concurrent.atomic.AtomicLong; +import java.util.concurrent.atomic.AtomicReference; import java.util.function.Consumer; import static org.hamcrest.Matchers.is; @@ -56,16 +60,19 @@ public class OpenCryptoFileTest { private FinallyUtil finallyUtil = new FinallyUtil(); private ReadonlyFlag readonlyFlag = mock(ReadonlyFlag.class); private BasicFileAttributeView attributeView = mock(BasicFileAttributeView.class); + private Provider attributeViewProvider = mock(Provider.class); private BasicFileAttributes attributes = mock(BasicFileAttributes.class); + private AtomicReference currentFilePath = mock(AtomicReference.class); private OpenCryptoFile inTest; @Before public void setup() throws IOException { + Mockito.when(attributeViewProvider.get()).thenReturn(attributeView); Mockito.when(attributeView.readAttributes()).thenReturn(attributes); Mockito.when(attributes.lastModifiedTime()).thenReturn(FileTime.from(Instant.now())); - inTest = new OpenCryptoFile(cryptor, channel, header, size, cryptoFileChannelFactory, chunkCache, openCryptoFileFactory, stats, exceptionsDuringWrite, finallyUtil, attributeView); + inTest = new OpenCryptoFile(cryptor, channel, header, size, cryptoFileChannelFactory, chunkCache, openCryptoFileFactory, stats, exceptionsDuringWrite, finallyUtil, attributeViewProvider, currentFilePath); } @Theory From 204e7122d8b1ee459d84a6d05fe710c05bf6de10 Mon Sep 17 00:00:00 2001 From: infeo Date: Wed, 14 Nov 2018 15:41:16 +0100 Subject: [PATCH 4/8] fixing tests to run also on windows --- .../org/cryptomator/cryptofs/OpenCryptoFilesTest.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/test/java/org/cryptomator/cryptofs/OpenCryptoFilesTest.java b/src/test/java/org/cryptomator/cryptofs/OpenCryptoFilesTest.java index 5765b901..fb4ec750 100644 --- a/src/test/java/org/cryptomator/cryptofs/OpenCryptoFilesTest.java +++ b/src/test/java/org/cryptomator/cryptofs/OpenCryptoFilesTest.java @@ -49,8 +49,8 @@ public void testGetOrCreate() throws IOException { @Test public void testTwoPhaseMoveFailsWhenTargetIsOpened() throws IOException { EffectiveOpenOptions openOptions = mock(EffectiveOpenOptions.class); - Path src = Paths.get("/src"); - Path dst = Paths.get("/dst"); + Path src = Paths.get("/src").toAbsolutePath(); + Path dst = Paths.get("/dst").toAbsolutePath(); inTest.getOrCreate(dst, openOptions); thrown.expect(FileAlreadyExistsException.class); @@ -76,8 +76,8 @@ public void testTwoPhaseMoveDoesntChangeAnythingWhenRolledBack() throws IOExcept @Test public void testTwoPhaseMoveChangesReferencesWhenCommitted() throws IOException { EffectiveOpenOptions openOptions = mock(EffectiveOpenOptions.class); - Path src = Paths.get("/src"); - Path dst = Paths.get("/dst"); + Path src = Paths.get("/src").toAbsolutePath(); + Path dst = Paths.get("/dst").toAbsolutePath(); inTest.getOrCreate(src, openOptions); Assert.assertTrue(inTest.get(src).isPresent()); From 5c61b78621cf01660e0b594b89983343e708e114 Mon Sep 17 00:00:00 2001 From: infeo Date: Wed, 21 Nov 2018 14:48:51 +0100 Subject: [PATCH 5/8] fixes #37 (again) --- pom.xml | 1 - .../cryptomator/cryptofs/OpenCryptoFile.java | 13 ++++------- .../cryptofs/OpenCryptoFileModule.java | 9 +++++--- .../cryptomator/cryptofs/OpenCryptoFiles.java | 1 + ...ileSystemFileAttributeIntegrationTest.java | 22 ++++++++++++++++++- .../cryptofs/OpenCryptoFileTest.java | 7 +++--- 6 files changed, 36 insertions(+), 17 deletions(-) diff --git a/pom.xml b/pom.xml index a2e30fb8..c0eb6463 100644 --- a/pom.xml +++ b/pom.xml @@ -141,7 +141,6 @@ 1.8 1.8 - 8 true diff --git a/src/main/java/org/cryptomator/cryptofs/OpenCryptoFile.java b/src/main/java/org/cryptomator/cryptofs/OpenCryptoFile.java index a9336612..586f4553 100644 --- a/src/main/java/org/cryptomator/cryptofs/OpenCryptoFile.java +++ b/src/main/java/org/cryptomator/cryptofs/OpenCryptoFile.java @@ -12,12 +12,10 @@ import org.cryptomator.cryptolib.api.FileHeader; import javax.inject.Inject; -import javax.inject.Provider; import java.io.IOException; import java.nio.ByteBuffer; import java.nio.channels.FileChannel; import java.nio.channels.FileLock; -import java.nio.file.NoSuchFileException; import java.nio.file.Path; import java.nio.file.attribute.BasicFileAttributeView; import java.nio.file.attribute.FileTime; @@ -26,6 +24,7 @@ import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicLong; import java.util.concurrent.atomic.AtomicReference; +import java.util.function.Supplier; import static java.lang.Math.max; import static java.lang.Math.min; @@ -44,7 +43,7 @@ class OpenCryptoFile { private final CryptoFileSystemStats stats; private final ExceptionsDuringWrite exceptionsDuringWrite; private final FinallyUtil finallyUtil; - private final Provider attributeViewProvider; + private final Supplier attributeViewProvider; private final AtomicBoolean headerWritten; private final AtomicReference lastModified; private final AtomicInteger openChannelCounter; @@ -52,7 +51,7 @@ class OpenCryptoFile { @Inject public OpenCryptoFile(Cryptor cryptor, FileChannel channel, FileHeader header, @OpenFileSize AtomicLong size, CryptoFileChannelFactory cryptoFileChannelFactory, - ChunkCache chunkCache, OpenCryptoFiles openCryptoFileFactory, CryptoFileSystemStats stats, ExceptionsDuringWrite exceptionsDuringWrite, FinallyUtil finallyUtil, Provider attrViewProvider, @CurrentOpenFilePath AtomicReference currentFilePath) { + ChunkCache chunkCache, OpenCryptoFiles openCryptoFileFactory, CryptoFileSystemStats stats, ExceptionsDuringWrite exceptionsDuringWrite, FinallyUtil finallyUtil, Supplier attrViewProvider, @CurrentOpenFilePath AtomicReference currentFilePath) { this.cryptor = cryptor; this.channel = channel; this.header = header; @@ -195,11 +194,7 @@ public synchronized void force(boolean metaData, EffectiveOpenOptions options) t exceptionsDuringWrite.throwIfPresent(); } channel.force(metaData); - try { - attributeViewProvider.get().setTimes(FileTime.from(lastModified.get()), null, null); - } catch (NoSuchFileException e) { - //NO-OP because file is already deleted - } + attributeViewProvider.get().setTimes(FileTime.from(lastModified.get()), null, null); } public FileLock lock(long position, long size, boolean shared) throws IOException { diff --git a/src/main/java/org/cryptomator/cryptofs/OpenCryptoFileModule.java b/src/main/java/org/cryptomator/cryptofs/OpenCryptoFileModule.java index dc0f41ac..a65606b8 100644 --- a/src/main/java/org/cryptomator/cryptofs/OpenCryptoFileModule.java +++ b/src/main/java/org/cryptomator/cryptofs/OpenCryptoFileModule.java @@ -7,6 +7,7 @@ import java.nio.file.attribute.BasicFileAttributeView; import java.util.concurrent.atomic.AtomicLong; import java.util.concurrent.atomic.AtomicReference; +import java.util.function.Supplier; import dagger.Module; import dagger.Provides; @@ -57,9 +58,11 @@ public FileChannel provideFileChannel(EffectiveOpenOptions options) { @Provides @PerOpenFile - public BasicFileAttributeView provideBasicFileAttributeView() { - Path path = currentPath.get(); - return path.getFileSystem().provider().getFileAttributeView(path, BasicFileAttributeView.class); + public Supplier provideBasicFileAttributeViewSupplier() { + return () -> { + Path path = currentPath.get(); + return path.getFileSystem().provider().getFileAttributeView(path, BasicFileAttributeView.class); + }; } @Provides diff --git a/src/main/java/org/cryptomator/cryptofs/OpenCryptoFiles.java b/src/main/java/org/cryptomator/cryptofs/OpenCryptoFiles.java index fe324126..37f28301 100644 --- a/src/main/java/org/cryptomator/cryptofs/OpenCryptoFiles.java +++ b/src/main/java/org/cryptomator/cryptofs/OpenCryptoFiles.java @@ -73,6 +73,7 @@ private OpenCryptoFile create(Path normalizedPath, EffectiveOpenOptions options) .withOptions(options) // .build(); OpenCryptoFile file = component.newOpenCryptoFileComponent(module).openCryptoFile(); + //TODO: is this call necessary? file.setCurrentFilePath(normalizedPath); return file; } diff --git a/src/test/java/org/cryptomator/cryptofs/CryptoFileSystemFileAttributeIntegrationTest.java b/src/test/java/org/cryptomator/cryptofs/CryptoFileSystemFileAttributeIntegrationTest.java index e85616e2..8d8c92a7 100644 --- a/src/test/java/org/cryptomator/cryptofs/CryptoFileSystemFileAttributeIntegrationTest.java +++ b/src/test/java/org/cryptomator/cryptofs/CryptoFileSystemFileAttributeIntegrationTest.java @@ -19,13 +19,14 @@ import org.junit.Test; import org.junit.rules.ExpectedException; -import java.io.File; import java.io.IOException; import java.nio.ByteBuffer; import java.nio.channels.FileChannel; import java.nio.file.*; +import java.nio.file.attribute.BasicFileAttributeView; import java.nio.file.attribute.FileTime; import java.nio.file.attribute.UserPrincipal; +import java.time.Instant; import java.util.Map; import static java.lang.Boolean.FALSE; @@ -137,6 +138,25 @@ public void testLastModifiedDateUpdatesOnlyDuringWrite() throws IOException, Int Assert.assertEquals(t3.toMillis(), t4.toMillis()); // round to millis, since in-memory times of opened files may have sub-milli resolution } + @Test + public void testFileAttributeViewUpdatesAfterMove() throws IOException { + Path oldpath = fileSystem.getPath("/a"); + Path newpath = fileSystem.getPath("/b"); + try (FileChannel channel = FileChannel.open(oldpath, StandardOpenOption.CREATE_NEW, StandardOpenOption.WRITE)) { + BasicFileAttributeView attrView = Files.getFileAttributeView(oldpath, BasicFileAttributeView.class); + FileTime now = FileTime.from(Instant.ofEpochSecond(123456789L)); + attrView.setTimes(now, null, null); + Files.move(oldpath, newpath); + channel.force(true); + BasicFileAttributeView attrView2 = Files.getFileAttributeView(newpath, BasicFileAttributeView.class); + Assert.assertEquals(now, attrView2.readAttributes().lastModifiedTime()); + + thrown.expect(NoSuchFileException.class); + Files.getFileAttributeView(oldpath, BasicFileAttributeView.class).readAttributes(); + } + + } + private static Matcher isAfter(FileTime previousFileTime) { return new BaseMatcher() { @Override diff --git a/src/test/java/org/cryptomator/cryptofs/OpenCryptoFileTest.java b/src/test/java/org/cryptomator/cryptofs/OpenCryptoFileTest.java index 85fe1a44..21aa940a 100644 --- a/src/test/java/org/cryptomator/cryptofs/OpenCryptoFileTest.java +++ b/src/test/java/org/cryptomator/cryptofs/OpenCryptoFileTest.java @@ -33,6 +33,7 @@ import java.util.concurrent.atomic.AtomicLong; import java.util.concurrent.atomic.AtomicReference; import java.util.function.Consumer; +import java.util.function.Supplier; import static org.hamcrest.Matchers.is; import static org.junit.Assert.assertThat; @@ -60,7 +61,7 @@ public class OpenCryptoFileTest { private FinallyUtil finallyUtil = new FinallyUtil(); private ReadonlyFlag readonlyFlag = mock(ReadonlyFlag.class); private BasicFileAttributeView attributeView = mock(BasicFileAttributeView.class); - private Provider attributeViewProvider = mock(Provider.class); + private Supplier attributeViewSupplier= mock(Supplier.class); private BasicFileAttributes attributes = mock(BasicFileAttributes.class); private AtomicReference currentFilePath = mock(AtomicReference.class); @@ -68,11 +69,11 @@ public class OpenCryptoFileTest { @Before public void setup() throws IOException { - Mockito.when(attributeViewProvider.get()).thenReturn(attributeView); + Mockito.when(attributeViewSupplier.get()).thenReturn(attributeView); Mockito.when(attributeView.readAttributes()).thenReturn(attributes); Mockito.when(attributes.lastModifiedTime()).thenReturn(FileTime.from(Instant.now())); - inTest = new OpenCryptoFile(cryptor, channel, header, size, cryptoFileChannelFactory, chunkCache, openCryptoFileFactory, stats, exceptionsDuringWrite, finallyUtil, attributeViewProvider, currentFilePath); + inTest = new OpenCryptoFile(cryptor, channel, header, size, cryptoFileChannelFactory, chunkCache, openCryptoFileFactory, stats, exceptionsDuringWrite, finallyUtil, attributeViewSupplier, currentFilePath); } @Theory From 584f00a072390e791667d537dc579fae0f2aba39 Mon Sep 17 00:00:00 2001 From: infeo Date: Wed, 21 Nov 2018 15:02:30 +0100 Subject: [PATCH 6/8] reverting removal of release property in pom.xml --- pom.xml | 1 + 1 file changed, 1 insertion(+) diff --git a/pom.xml b/pom.xml index c0eb6463..a2e30fb8 100644 --- a/pom.xml +++ b/pom.xml @@ -141,6 +141,7 @@ 1.8 1.8 + 8 true From d23e0076defcbcec9aa17e1e917ae87033415673 Mon Sep 17 00:00:00 2001 From: infeo Date: Wed, 21 Nov 2018 15:19:06 +0100 Subject: [PATCH 7/8] fixing test --- .../CryptoFileSystemFileAttributeIntegrationTest.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/test/java/org/cryptomator/cryptofs/CryptoFileSystemFileAttributeIntegrationTest.java b/src/test/java/org/cryptomator/cryptofs/CryptoFileSystemFileAttributeIntegrationTest.java index 8d8c92a7..86631219 100644 --- a/src/test/java/org/cryptomator/cryptofs/CryptoFileSystemFileAttributeIntegrationTest.java +++ b/src/test/java/org/cryptomator/cryptofs/CryptoFileSystemFileAttributeIntegrationTest.java @@ -140,8 +140,8 @@ public void testLastModifiedDateUpdatesOnlyDuringWrite() throws IOException, Int @Test public void testFileAttributeViewUpdatesAfterMove() throws IOException { - Path oldpath = fileSystem.getPath("/a"); - Path newpath = fileSystem.getPath("/b"); + Path oldpath = fileSystem.getPath("/x"); + Path newpath = fileSystem.getPath("/y"); try (FileChannel channel = FileChannel.open(oldpath, StandardOpenOption.CREATE_NEW, StandardOpenOption.WRITE)) { BasicFileAttributeView attrView = Files.getFileAttributeView(oldpath, BasicFileAttributeView.class); FileTime now = FileTime.from(Instant.ofEpochSecond(123456789L)); From 2452c4b37017f06b8919eed3b505a8214b6daa7d Mon Sep 17 00:00:00 2001 From: infeo Date: Wed, 21 Nov 2018 15:30:18 +0100 Subject: [PATCH 8/8] preparing 1.6.2 --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index a2e30fb8..ffd5b0bf 100644 --- a/pom.xml +++ b/pom.xml @@ -2,7 +2,7 @@ 4.0.0 org.cryptomator cryptofs - 1.7.0-SNAPSHOT + 1.6.2 Cryptomator Crypto Filesystem This library provides the Java filesystem provider used by Cryptomator. https://github.com/cryptomator/cryptofs