Skip to content

Commit 483693e

Browse files
author
infeo
committed
Merge branch 'release/1.6.2'
2 parents a7f380f + 2452c4b commit 483693e

13 files changed

+153
-109
lines changed

pom.xml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
<modelVersion>4.0.0</modelVersion>
33
<groupId>org.cryptomator</groupId>
44
<artifactId>cryptofs</artifactId>
5-
<version>1.6.1</version>
5+
<version>1.6.2</version>
66
<name>Cryptomator Crypto Filesystem</name>
77
<description>This library provides the Java filesystem provider used by Cryptomator.</description>
88
<url>https://github.com/cryptomator/cryptofs</url>

src/main/java/org/cryptomator/cryptofs/AbstractCryptoFileAttributeView.java

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,9 @@ public final S readAttributes() throws IOException {
4646
public void setTimes(FileTime lastModifiedTime, FileTime lastAccessTime, FileTime createTime) throws IOException {
4747
readonlyFlag.assertWritable();
4848
delegate.setTimes(lastModifiedTime, lastAccessTime, createTime);
49-
openCryptoFile.ifPresent(file -> file.setLastModifiedTime(lastModifiedTime));
49+
if(lastModifiedTime != null){
50+
openCryptoFile.ifPresent(file -> file.setLastModifiedTime(lastModifiedTime));
51+
}
5052
}
5153

5254
}
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
package org.cryptomator.cryptofs;
2+
3+
import javax.inject.Qualifier;
4+
import java.lang.annotation.Documented;
5+
import java.lang.annotation.Retention;
6+
7+
import static java.lang.annotation.RetentionPolicy.RUNTIME;
8+
9+
/**
10+
* The current Path of an OpenCryptoFile.
11+
* @see OriginalOpenFilePath
12+
*/
13+
@Qualifier
14+
@Documented
15+
@Retention(RUNTIME)
16+
@interface CurrentOpenFilePath {
17+
}

src/main/java/org/cryptomator/cryptofs/OpenCryptoFile.java

Lines changed: 10 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,6 @@
1616
import java.nio.ByteBuffer;
1717
import java.nio.channels.FileChannel;
1818
import java.nio.channels.FileLock;
19-
import java.nio.file.NoSuchFileException;
2019
import java.nio.file.Path;
2120
import java.nio.file.attribute.BasicFileAttributeView;
2221
import java.nio.file.attribute.FileTime;
@@ -25,6 +24,7 @@
2524
import java.util.concurrent.atomic.AtomicInteger;
2625
import java.util.concurrent.atomic.AtomicLong;
2726
import java.util.concurrent.atomic.AtomicReference;
27+
import java.util.function.Supplier;
2828

2929
import static java.lang.Math.max;
3030
import static java.lang.Math.min;
@@ -43,16 +43,15 @@ class OpenCryptoFile {
4343
private final CryptoFileSystemStats stats;
4444
private final ExceptionsDuringWrite exceptionsDuringWrite;
4545
private final FinallyUtil finallyUtil;
46-
private final BasicFileAttributeView attributeView;
46+
private final Supplier<BasicFileAttributeView> attributeViewProvider;
4747
private final AtomicBoolean headerWritten;
4848
private final AtomicReference<Instant> lastModified;
4949
private final AtomicInteger openChannelCounter;
50-
51-
private Path currentFilePath;
50+
private final AtomicReference<Path> currentFilePath;
5251

5352
@Inject
5453
public OpenCryptoFile(Cryptor cryptor, FileChannel channel, FileHeader header, @OpenFileSize AtomicLong size, CryptoFileChannelFactory cryptoFileChannelFactory,
55-
ChunkCache chunkCache, OpenCryptoFiles openCryptoFileFactory, CryptoFileSystemStats stats, ExceptionsDuringWrite exceptionsDuringWrite, FinallyUtil finallyUtil, BasicFileAttributeView attrView) {
54+
ChunkCache chunkCache, OpenCryptoFiles openCryptoFileFactory, CryptoFileSystemStats stats, ExceptionsDuringWrite exceptionsDuringWrite, FinallyUtil finallyUtil, Supplier<BasicFileAttributeView> attrViewProvider, @CurrentOpenFilePath AtomicReference<Path> currentFilePath) {
5655
this.cryptor = cryptor;
5756
this.channel = channel;
5857
this.header = header;
@@ -63,11 +62,12 @@ public OpenCryptoFile(Cryptor cryptor, FileChannel channel, FileHeader header, @
6362
this.stats = stats;
6463
this.exceptionsDuringWrite = exceptionsDuringWrite;
6564
this.finallyUtil = finallyUtil;
66-
this.attributeView = attrView;
65+
this.attributeViewProvider = attrViewProvider;
66+
this.currentFilePath = currentFilePath;
6767
this.headerWritten = new AtomicBoolean(false);
6868
this.lastModified = new AtomicReference<>();
6969
try {
70-
lastModified.set(attrView.readAttributes().lastModifiedTime().toInstant());
70+
lastModified.set(attrViewProvider.get().readAttributes().lastModifiedTime().toInstant());
7171
} catch (IOException e) {
7272
lastModified.set(Instant.ofEpochSecond(0));
7373
}
@@ -194,11 +194,7 @@ public synchronized void force(boolean metaData, EffectiveOpenOptions options) t
194194
exceptionsDuringWrite.throwIfPresent();
195195
}
196196
channel.force(metaData);
197-
try {
198-
attributeView.setTimes(FileTime.from(lastModified.get()), null, null);
199-
} catch (NoSuchFileException e) {
200-
//NO-OP because file is already deleted
201-
}
197+
attributeViewProvider.get().setTimes(FileTime.from(lastModified.get()), null, null);
202198
}
203199

204200
public FileLock lock(long position, long size, boolean shared) throws IOException {
@@ -220,11 +216,11 @@ void decreaseOpenChannelCounter() throws IOException {
220216
}
221217

222218
public Path getCurrentFilePath() {
223-
return currentFilePath;
219+
return currentFilePath.get();
224220
}
225221

226222
public void setCurrentFilePath(Path currentFilePath) {
227-
this.currentFilePath = currentFilePath;
223+
this.currentFilePath.set(currentFilePath);
228224
}
229225

230226
public void close() throws IOException {

src/main/java/org/cryptomator/cryptofs/OpenCryptoFileComponent.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
import dagger.Subcomponent;
44

5-
@Subcomponent(modules = {OpenCryptoFileModule.class, OpenCryptoFileFactoryModule.class})
5+
@Subcomponent(modules = {OpenCryptoFileModule.class})
66
@PerOpenFile
77
interface OpenCryptoFileComponent {
88

src/main/java/org/cryptomator/cryptofs/OpenCryptoFileFactoryModule.java

Lines changed: 0 additions & 81 deletions
This file was deleted.

src/main/java/org/cryptomator/cryptofs/OpenCryptoFileModule.java

Lines changed: 83 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,26 +1,47 @@
11
package org.cryptomator.cryptofs;
22

3+
import java.io.IOException;
4+
import java.nio.ByteBuffer;
5+
import java.nio.channels.FileChannel;
36
import java.nio.file.Path;
7+
import java.nio.file.attribute.BasicFileAttributeView;
8+
import java.util.concurrent.atomic.AtomicLong;
9+
import java.util.concurrent.atomic.AtomicReference;
10+
import java.util.function.Supplier;
411

512
import dagger.Module;
613
import dagger.Provides;
14+
import org.cryptomator.cryptolib.api.Cryptor;
15+
import org.cryptomator.cryptolib.api.FileHeader;
16+
17+
import static org.cryptomator.cryptofs.UncheckedThrows.rethrowUnchecked;
18+
import static org.cryptomator.cryptolib.Cryptors.cleartextSize;
719

820
@Module
921
class OpenCryptoFileModule {
1022

11-
private final Path path;
23+
private final Path originalPath;
24+
private final AtomicReference<Path> currentPath;
1225
private final EffectiveOpenOptions options;
1326

1427
private OpenCryptoFileModule(Builder builder) {
15-
this.path = builder.path;
28+
this.originalPath = builder.path;
29+
this.currentPath = new AtomicReference<>(builder.path);
1630
this.options = builder.options;
1731
}
1832

1933
@Provides
2034
@PerOpenFile
2135
@OriginalOpenFilePath
22-
public Path providePath() {
23-
return path;
36+
public Path provideOriginalPath() {
37+
return originalPath;
38+
}
39+
40+
@Provides
41+
@PerOpenFile
42+
@CurrentOpenFilePath
43+
public AtomicReference<Path> provideCurrentPath() {
44+
return currentPath;
2445
}
2546

2647
@Provides
@@ -29,6 +50,64 @@ public EffectiveOpenOptions provideOptions() {
2950
return options;
3051
}
3152

53+
@Provides
54+
@PerOpenFile
55+
public FileChannel provideFileChannel(EffectiveOpenOptions options) {
56+
return rethrowUnchecked(IOException.class).from(() -> originalPath.getFileSystem().provider().newFileChannel(originalPath, options.createOpenOptionsForEncryptedFile()));
57+
}
58+
59+
@Provides
60+
@PerOpenFile
61+
public Supplier<BasicFileAttributeView> provideBasicFileAttributeViewSupplier() {
62+
return () -> {
63+
Path path = currentPath.get();
64+
return path.getFileSystem().provider().getFileAttributeView(path, BasicFileAttributeView.class);
65+
};
66+
}
67+
68+
@Provides
69+
@PerOpenFile
70+
@OpenFileSize
71+
public AtomicLong provideFileSize(FileChannel channel, Cryptor cryptor) {
72+
return rethrowUnchecked(IOException.class).from(() -> {
73+
long size = channel.size();
74+
if (size == 0) {
75+
return new AtomicLong();
76+
} else {
77+
int headerSize = cryptor.fileHeaderCryptor().headerSize();
78+
return new AtomicLong(cleartextSize(size - headerSize, cryptor));
79+
}
80+
});
81+
}
82+
83+
@Provides
84+
@PerOpenFile
85+
public FileHeader provideFileHeader(FileChannel channel, Cryptor cryptor, EffectiveOpenOptions options) {
86+
return rethrowUnchecked(IOException.class).from(() -> {
87+
if (options.truncateExisting() || isNewFile(channel, options)) {
88+
FileHeader newHeader = cryptor.fileHeaderCryptor().create();
89+
channel.position(0);
90+
channel.write(cryptor.fileHeaderCryptor().encryptHeader(newHeader));
91+
channel.force(false);
92+
return newHeader;
93+
} else {
94+
ByteBuffer existingHeaderBuf = ByteBuffer.allocate(cryptor.fileHeaderCryptor().headerSize());
95+
channel.position(0);
96+
channel.read(existingHeaderBuf);
97+
existingHeaderBuf.flip();
98+
try {
99+
return cryptor.fileHeaderCryptor().decryptHeader(existingHeaderBuf);
100+
} catch (IllegalArgumentException e) {
101+
throw new IOException(e);
102+
}
103+
}
104+
});
105+
}
106+
107+
private boolean isNewFile(FileChannel channel, EffectiveOpenOptions options) throws IOException {
108+
return options.createNew() || options.create() && channel.size() == 0;
109+
}
110+
32111
public static Builder openCryptoFileModule() {
33112
return new Builder();
34113
}

src/main/java/org/cryptomator/cryptofs/OpenCryptoFiles.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,7 @@ private OpenCryptoFile create(Path normalizedPath, EffectiveOpenOptions options)
7373
.withOptions(options) //
7474
.build();
7575
OpenCryptoFile file = component.newOpenCryptoFileComponent(module).openCryptoFile();
76+
//TODO: is this call necessary?
7677
file.setCurrentFilePath(normalizedPath);
7778
return file;
7879
}

src/main/java/org/cryptomator/cryptofs/OriginalOpenFilePath.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99

1010
/**
1111
* The Path used to create an OpenCryptoFile
12+
* @see CurrentOpenFilePath
1213
*/
1314
@Qualifier
1415
@Documented

src/test/java/org/cryptomator/cryptofs/CryptoFileSystemFileAttributeIntegrationTest.java

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,13 +19,14 @@
1919
import org.junit.Test;
2020
import org.junit.rules.ExpectedException;
2121

22-
import java.io.File;
2322
import java.io.IOException;
2423
import java.nio.ByteBuffer;
2524
import java.nio.channels.FileChannel;
2625
import java.nio.file.*;
26+
import java.nio.file.attribute.BasicFileAttributeView;
2727
import java.nio.file.attribute.FileTime;
2828
import java.nio.file.attribute.UserPrincipal;
29+
import java.time.Instant;
2930
import java.util.Map;
3031

3132
import static java.lang.Boolean.FALSE;
@@ -137,6 +138,25 @@ public void testLastModifiedDateUpdatesOnlyDuringWrite() throws IOException, Int
137138
Assert.assertEquals(t3.toMillis(), t4.toMillis()); // round to millis, since in-memory times of opened files may have sub-milli resolution
138139
}
139140

141+
@Test
142+
public void testFileAttributeViewUpdatesAfterMove() throws IOException {
143+
Path oldpath = fileSystem.getPath("/x");
144+
Path newpath = fileSystem.getPath("/y");
145+
try (FileChannel channel = FileChannel.open(oldpath, StandardOpenOption.CREATE_NEW, StandardOpenOption.WRITE)) {
146+
BasicFileAttributeView attrView = Files.getFileAttributeView(oldpath, BasicFileAttributeView.class);
147+
FileTime now = FileTime.from(Instant.ofEpochSecond(123456789L));
148+
attrView.setTimes(now, null, null);
149+
Files.move(oldpath, newpath);
150+
channel.force(true);
151+
BasicFileAttributeView attrView2 = Files.getFileAttributeView(newpath, BasicFileAttributeView.class);
152+
Assert.assertEquals(now, attrView2.readAttributes().lastModifiedTime());
153+
154+
thrown.expect(NoSuchFileException.class);
155+
Files.getFileAttributeView(oldpath, BasicFileAttributeView.class).readAttributes();
156+
}
157+
158+
}
159+
140160
private static Matcher<FileTime> isAfter(FileTime previousFileTime) {
141161
return new BaseMatcher<FileTime>() {
142162
@Override

0 commit comments

Comments
 (0)