Skip to content

Commit 24403e0

Browse files
committed
make cleartext path visible to OpenFileComponent and fix DecryptionFailedEvent
1 parent 5e552d1 commit 24403e0

22 files changed

+183
-152
lines changed

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

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -402,7 +402,7 @@ private FileChannel newFileChannelFromFile(CryptoPath cleartextFilePath, Effecti
402402
Files.createDirectories(ciphertextPath.getRawPath()); // suppresses FileAlreadyExists
403403
}
404404

405-
FileChannel ch = openCryptoFiles.getOrCreate(ciphertextFilePath).newFileChannel(options, attrs); // might throw FileAlreadyExists
405+
FileChannel ch = openCryptoFiles.getOrCreate(cleartextFilePath, ciphertextFilePath).newFileChannel(options, attrs); // might throw FileAlreadyExists
406406
try {
407407
if (options.writable()) {
408408
ciphertextPath.persistLongFileName();
@@ -588,7 +588,7 @@ private void moveSymlink(CryptoPath cleartextSource, CryptoPath cleartextTarget,
588588
// "the symbolic link itself, not the target of the link, is moved"
589589
CiphertextFilePath ciphertextSource = cryptoPathMapper.getCiphertextFilePath(cleartextSource);
590590
CiphertextFilePath ciphertextTarget = cryptoPathMapper.getCiphertextFilePath(cleartextTarget);
591-
try (OpenCryptoFiles.TwoPhaseMove twoPhaseMove = openCryptoFiles.prepareMove(ciphertextSource.getRawPath(), ciphertextTarget.getRawPath())) {
591+
try (OpenCryptoFiles.TwoPhaseMove twoPhaseMove = openCryptoFiles.prepareMove(ciphertextSource.getRawPath(), cleartextTarget, ciphertextTarget.getRawPath())) {
592592
Files.move(ciphertextSource.getRawPath(), ciphertextTarget.getRawPath(), options);
593593
if (ciphertextTarget.isShortened()) {
594594
ciphertextTarget.persistLongFileName();
@@ -604,7 +604,7 @@ private void moveFile(CryptoPath cleartextSource, CryptoPath cleartextTarget, Co
604604
// we need to re-map the OpenCryptoFile entry.
605605
CiphertextFilePath ciphertextSource = cryptoPathMapper.getCiphertextFilePath(cleartextSource);
606606
CiphertextFilePath ciphertextTarget = cryptoPathMapper.getCiphertextFilePath(cleartextTarget);
607-
try (OpenCryptoFiles.TwoPhaseMove twoPhaseMove = openCryptoFiles.prepareMove(ciphertextSource.getRawPath(), ciphertextTarget.getRawPath())) {
607+
try (OpenCryptoFiles.TwoPhaseMove twoPhaseMove = openCryptoFiles.prepareMove(ciphertextSource.getRawPath(), cleartextTarget, ciphertextTarget.getRawPath())) {
608608
if (ciphertextTarget.isShortened()) {
609609
Files.createDirectories(ciphertextTarget.getRawPath());
610610
ciphertextTarget.persistLongFileName();

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

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,6 @@
1515
import org.slf4j.Logger;
1616
import org.slf4j.LoggerFactory;
1717

18-
import javax.inject.Named;
1918
import java.io.IOException;
2019
import java.nio.file.FileStore;
2120
import java.nio.file.Files;

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

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,6 @@
2121
import java.util.EnumSet;
2222
import java.util.Map;
2323
import java.util.Set;
24-
import java.util.concurrent.Flow;
2524
import java.util.function.Consumer;
2625

2726
import static java.util.Arrays.asList;
@@ -89,7 +88,7 @@ public class CryptoFileSystemProperties extends AbstractMap<String, Object> {
8988
*/
9089
public static final String PROPERTY_NOTIFY_METHOD = "notificationConsumer";
9190

92-
static final Consumer<FilesystemEvent> DEFAULT_NOTIFY_METHOD = (FilesystemEvent e) -> {} ;
91+
static final Consumer<FilesystemEvent> DEFAULT_NOTIFY_METHOD = (FilesystemEvent e) -> {};
9392

9493
/**
9594
* Key identifying the filesystem flags.

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

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -27,14 +27,12 @@
2727
public class Symlinks {
2828

2929
private final CryptoPathMapper cryptoPathMapper;
30-
private final LongFileNameProvider longFileNameProvider;
3130
private final OpenCryptoFiles openCryptoFiles;
3231
private final ReadonlyFlag readonlyFlag;
3332

3433
@Inject
35-
Symlinks(CryptoPathMapper cryptoPathMapper, LongFileNameProvider longFileNameProvider, OpenCryptoFiles openCryptoFiles, ReadonlyFlag readonlyFlag) {
34+
Symlinks(CryptoPathMapper cryptoPathMapper, OpenCryptoFiles openCryptoFiles, ReadonlyFlag readonlyFlag) {
3635
this.cryptoPathMapper = cryptoPathMapper;
37-
this.longFileNameProvider = longFileNameProvider;
3836
this.openCryptoFiles = openCryptoFiles;
3937
this.readonlyFlag = readonlyFlag;
4038
}
@@ -48,7 +46,7 @@ public void createSymbolicLink(CryptoPath cleartextPath, Path target, FileAttrib
4846
EffectiveOpenOptions openOptions = EffectiveOpenOptions.from(EnumSet.of(StandardOpenOption.WRITE, StandardOpenOption.CREATE_NEW), readonlyFlag);
4947
ByteBuffer content = UTF_8.encode(target.toString());
5048
Files.createDirectory(ciphertextFilePath.getRawPath());
51-
openCryptoFiles.writeCiphertextFile(ciphertextFilePath.getSymlinkFilePath(), openOptions, content);
49+
openCryptoFiles.writeCiphertextFile(cleartextPath, ciphertextFilePath.getSymlinkFilePath(), openOptions, content);
5250
ciphertextFilePath.persistLongFileName();
5351
}
5452

@@ -57,7 +55,7 @@ public CryptoPath readSymbolicLink(CryptoPath cleartextPath) throws IOException
5755
EffectiveOpenOptions openOptions = EffectiveOpenOptions.from(EnumSet.of(StandardOpenOption.READ), readonlyFlag);
5856
assertIsSymlink(cleartextPath, ciphertextSymlinkFile);
5957
try {
60-
ByteBuffer content = openCryptoFiles.readCiphertextFile(ciphertextSymlinkFile, openOptions, Constants.MAX_SYMLINK_LENGTH);
58+
ByteBuffer content = openCryptoFiles.readCiphertextFile(cleartextPath, ciphertextSymlinkFile, openOptions, Constants.MAX_SYMLINK_LENGTH);
6159
return cleartextPath.getFileSystem().getPath(UTF_8.decode(content).toString());
6260
} catch (BufferUnderflowException e) {
6361
throw new NotLinkException(cleartextPath.toString(), null, "Unreasonably large symlink file");

src/main/java/org/cryptomator/cryptofs/ch/CleartextFileChannel.java

Lines changed: 10 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,8 @@
77
import org.cryptomator.cryptofs.fh.BufferPool;
88
import org.cryptomator.cryptofs.fh.Chunk;
99
import org.cryptomator.cryptofs.fh.ChunkCache;
10-
import org.cryptomator.cryptofs.fh.CurrentOpenFilePath;
10+
import org.cryptomator.cryptofs.fh.ClearAndCipherPath;
11+
import org.cryptomator.cryptofs.fh.CurrentOpenFilePaths;
1112
import org.cryptomator.cryptofs.fh.ExceptionsDuringWrite;
1213
import org.cryptomator.cryptofs.fh.FileHeaderHolder;
1314
import org.cryptomator.cryptofs.fh.OpenFileModifiedDate;
@@ -25,7 +26,6 @@
2526
import java.nio.channels.NonReadableChannelException;
2627
import java.nio.channels.NonWritableChannelException;
2728
import java.nio.file.NoSuchFileException;
28-
import java.nio.file.Path;
2929
import java.nio.file.attribute.BasicFileAttributeView;
3030
import java.nio.file.attribute.FileTime;
3131
import java.time.Instant;
@@ -50,23 +50,23 @@ public class CleartextFileChannel extends AbstractFileChannel {
5050
private final ChunkCache chunkCache;
5151
private final BufferPool bufferPool;
5252
private final EffectiveOpenOptions options;
53-
private final AtomicReference<Path> currentFilePath;
53+
private final AtomicReference<ClearAndCipherPath> currentFilePaths;
5454
private final AtomicLong fileSize;
5555
private final AtomicReference<Instant> lastModified;
5656
private final ExceptionsDuringWrite exceptionsDuringWrite;
5757
private final Consumer<FileChannel> closeListener;
5858
private final CryptoFileSystemStats stats;
5959

6060
@Inject
61-
public CleartextFileChannel(FileChannel ciphertextFileChannel, FileHeaderHolder fileHeaderHolder, ReadWriteLock readWriteLock, Cryptor cryptor, ChunkCache chunkCache, BufferPool bufferPool, EffectiveOpenOptions options, @OpenFileSize AtomicLong fileSize, @OpenFileModifiedDate AtomicReference<Instant> lastModified, @CurrentOpenFilePath AtomicReference<Path> currentPath, ExceptionsDuringWrite exceptionsDuringWrite, Consumer<FileChannel> closeListener, CryptoFileSystemStats stats) {
61+
public CleartextFileChannel(FileChannel ciphertextFileChannel, FileHeaderHolder fileHeaderHolder, ReadWriteLock readWriteLock, Cryptor cryptor, ChunkCache chunkCache, BufferPool bufferPool, EffectiveOpenOptions options, @OpenFileSize AtomicLong fileSize, @OpenFileModifiedDate AtomicReference<Instant> lastModified, @CurrentOpenFilePaths AtomicReference<ClearAndCipherPath> currentPaths, ExceptionsDuringWrite exceptionsDuringWrite, Consumer<FileChannel> closeListener, CryptoFileSystemStats stats) {
6262
super(readWriteLock);
6363
this.ciphertextFileChannel = ciphertextFileChannel;
6464
this.fileHeaderHolder = fileHeaderHolder;
6565
this.cryptor = cryptor;
6666
this.chunkCache = chunkCache;
6767
this.bufferPool = bufferPool;
6868
this.options = options;
69-
this.currentFilePath = currentPath;
69+
this.currentFilePaths = currentPaths;
7070
this.fileSize = fileSize;
7171
this.lastModified = lastModified;
7272
this.exceptionsDuringWrite = exceptionsDuringWrite;
@@ -254,10 +254,11 @@ void flush() throws IOException {
254254
void persistLastModified() throws IOException {
255255
FileTime lastModifiedTime = isWritable() ? FileTime.from(lastModified.get()) : null;
256256
FileTime lastAccessTime = FileTime.from(Instant.now());
257-
var p = currentFilePath.get();
258-
if (p != null) {
259-
p.getFileSystem().provider()//
260-
.getFileAttributeView(p, BasicFileAttributeView.class)
257+
var ps = currentFilePaths.get();
258+
if (ps != null) {
259+
var ciphertextPath = ps.ciphertextPath();
260+
ciphertextPath.getFileSystem().provider()//
261+
.getFileAttributeView(ciphertextPath, BasicFileAttributeView.class)
261262
.setTimes(lastModifiedTime, lastAccessTime, null);
262263
}
263264

src/main/java/org/cryptomator/cryptofs/dir/C9rConflictResolver.java

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,6 @@
1717
import javax.inject.Named;
1818
import java.io.IOException;
1919
import java.nio.charset.StandardCharsets;
20-
import java.nio.file.FileSystem;
2120
import java.nio.file.Files;
2221
import java.nio.file.NoSuchFileException;
2322
import java.nio.file.Path;
@@ -122,7 +121,7 @@ private Node renameConflictingFile(Path canonicalPath, Path conflictingPath, Str
122121
Node node = new Node(alternativePath);
123122
node.cleartextName = alternativeCleartext;
124123
node.extractedCiphertext = alternativeCiphertext;
125-
eventConsumer.accept(new ConflictResolvedEvent(cleartextPath.resolve(cleartext), canonicalPath, cleartextPath.resolve(alternativeCleartext),alternativePath));
124+
eventConsumer.accept(new ConflictResolvedEvent(cleartextPath.resolve(cleartext), canonicalPath, cleartextPath.resolve(alternativeCleartext), alternativePath));
126125
return node;
127126
}
128127

src/main/java/org/cryptomator/cryptofs/fh/ChunkLoader.java

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -7,28 +7,26 @@
77
import org.cryptomator.cryptolib.api.Cryptor;
88

99
import javax.inject.Inject;
10-
import javax.inject.Named;
1110
import java.io.IOException;
1211
import java.nio.ByteBuffer;
13-
import java.nio.file.Path;
1412
import java.util.concurrent.atomic.AtomicReference;
1513
import java.util.function.Consumer;
1614

1715
@OpenFileScoped
1816
class ChunkLoader {
1917

2018
private final Consumer<FilesystemEvent> eventConsumer;
21-
private final AtomicReference<Path> path;
19+
private final AtomicReference<ClearAndCipherPath> paths;
2220
private final Cryptor cryptor;
2321
private final ChunkIO ciphertext;
2422
private final FileHeaderHolder headerHolder;
2523
private final CryptoFileSystemStats stats;
2624
private final BufferPool bufferPool;
2725

2826
@Inject
29-
public ChunkLoader(Consumer<FilesystemEvent> eventConsumer, @CurrentOpenFilePath AtomicReference<Path> path, Cryptor cryptor, ChunkIO ciphertext, FileHeaderHolder headerHolder, CryptoFileSystemStats stats, BufferPool bufferPool) {
27+
public ChunkLoader(Consumer<FilesystemEvent> eventConsumer, @CurrentOpenFilePaths AtomicReference<ClearAndCipherPath> paths, Cryptor cryptor, ChunkIO ciphertext, FileHeaderHolder headerHolder, CryptoFileSystemStats stats, BufferPool bufferPool) {
3028
this.eventConsumer = eventConsumer;
31-
this.path = path;
29+
this.paths = paths;
3230
this.cryptor = cryptor;
3331
this.ciphertext = ciphertext;
3432
this.headerHolder = headerHolder;
@@ -53,7 +51,8 @@ public ByteBuffer load(Long chunkIndex) throws IOException, AuthenticationFailed
5351
}
5452
return cleartextBuf;
5553
} catch (AuthenticationFailedException e) {
56-
eventConsumer.accept(new DecryptionFailedEvent(null, path.get(), e));
54+
var tmp = paths.get();
55+
eventConsumer.accept(new DecryptionFailedEvent(tmp.cleartextPath(), tmp.ciphertextPath(), e));
5756
throw e;
5857
} finally {
5958
bufferPool.recycle(ciphertextBuf);
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
package org.cryptomator.cryptofs.fh;
2+
3+
import org.cryptomator.cryptofs.CryptoPath;
4+
5+
import java.nio.file.Path;
6+
7+
public record ClearAndCipherPath(CryptoPath cleartextPath, Path ciphertextPath) {
8+
9+
}

src/main/java/org/cryptomator/cryptofs/fh/CurrentOpenFilePath.java renamed to src/main/java/org/cryptomator/cryptofs/fh/CurrentOpenFilePaths.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,10 +8,10 @@
88

99
/**
1010
* The current Path of an OpenCryptoFile.
11-
* @see OriginalOpenFilePath
11+
* @see OriginalOpenFilePaths
1212
*/
1313
@Qualifier
1414
@Documented
1515
@Retention(RUNTIME)
16-
public @interface CurrentOpenFilePath {
16+
public @interface CurrentOpenFilePaths {
1717
}

src/main/java/org/cryptomator/cryptofs/fh/FileHeaderHolder.java

Lines changed: 8 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -10,11 +10,9 @@
1010
import org.slf4j.LoggerFactory;
1111

1212
import javax.inject.Inject;
13-
import javax.inject.Named;
1413
import java.io.IOException;
1514
import java.nio.ByteBuffer;
1615
import java.nio.channels.FileChannel;
17-
import java.nio.file.Path;
1816
import java.util.concurrent.atomic.AtomicBoolean;
1917
import java.util.concurrent.atomic.AtomicReference;
2018
import java.util.function.Consumer;
@@ -26,16 +24,16 @@ public class FileHeaderHolder {
2624

2725
private final Consumer<FilesystemEvent> eventConsumer;
2826
private final Cryptor cryptor;
29-
private final AtomicReference<Path> path;
27+
private final AtomicReference<ClearAndCipherPath> paths;
3028
private final AtomicReference<FileHeader> header = new AtomicReference<>();
3129
private final AtomicReference<ByteBuffer> encryptedHeader = new AtomicReference<>();
3230
private final AtomicBoolean isPersisted = new AtomicBoolean();
3331

3432
@Inject
35-
public FileHeaderHolder(Consumer<FilesystemEvent> eventConsumer, Cryptor cryptor, @CurrentOpenFilePath AtomicReference<Path> path) {
33+
public FileHeaderHolder(Consumer<FilesystemEvent> eventConsumer, Cryptor cryptor, @CurrentOpenFilePaths AtomicReference<ClearAndCipherPath> paths) {
3634
this.eventConsumer = eventConsumer;
3735
this.cryptor = cryptor;
38-
this.path = path;
36+
this.paths = paths;
3937
}
4038

4139
public FileHeader get() {
@@ -55,7 +53,7 @@ public ByteBuffer getEncrypted() {
5553
}
5654

5755
FileHeader createNew() {
58-
LOG.trace("Generating file header for {}", path.get());
56+
LOG.trace("Generating file header for {}", paths.get().ciphertextPath());
5957
FileHeader newHeader = cryptor.fileHeaderCryptor().create();
6058
encryptedHeader.set(cryptor.fileHeaderCryptor().encryptHeader(newHeader).asReadOnlyBuffer()); //to prevent NONCE reuse, we already encrypt the header and cache it
6159
header.set(newHeader);
@@ -71,7 +69,7 @@ FileHeader createNew() {
7169
* @throws IOException if the file header cannot be read or decrypted
7270
*/
7371
FileHeader loadExisting(FileChannel ch) throws IOException {
74-
LOG.trace("Reading file header from {}", path.get());
72+
LOG.trace("Reading file header from {}", paths.get().cleartextPath());
7573
ByteBuffer existingHeaderBuf = ByteBuffer.allocate(cryptor.fileHeaderCryptor().headerSize());
7674
ch.read(existingHeaderBuf, 0);
7775
existingHeaderBuf.flip();
@@ -82,10 +80,11 @@ FileHeader loadExisting(FileChannel ch) throws IOException {
8280
isPersisted.set(true);
8381
return existingHeader;
8482
} catch (IllegalArgumentException | CryptoException e) {
83+
var ps = paths.get();
8584
if (e instanceof AuthenticationFailedException afe) {
86-
eventConsumer.accept(new DecryptionFailedEvent(null, path.get(), afe));
85+
eventConsumer.accept(new DecryptionFailedEvent(ps.cleartextPath(), ps.ciphertextPath(), afe));
8786
}
88-
throw new IOException("Unable to decrypt header of file " + path.get(), e);
87+
throw new IOException("Unable to decrypt header of file " + ps.ciphertextPath(), e);
8988
}
9089
}
9190

0 commit comments

Comments
 (0)