Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
90 commits
Select commit Hold shift + click to select a range
f45b61e
first draft when to open lock files
infeo Jul 30, 2025
2248ea8
extend logic to read inUseFile on failure
infeo Jul 30, 2025
751dcc7
refactor inUse check:
infeo Jul 31, 2025
3dd536b
refactor to own class
infeo Jul 31, 2025
a07bc23
add content to in use file (via properties) and fileInUseEvent
infeo Jul 31, 2025
c421f2a
add a validate method and more tests
infeo Aug 1, 2025
9ac3c6a
add integration test
infeo Aug 1, 2025
da573e7
add close unit tests
infeo Aug 1, 2025
c336283
on move, move also inUse file
infeo Aug 3, 2025
531300e
refactoring:
infeo Aug 6, 2025
128b857
reduce inUseFile impl for moveFile to a TODO comment
infeo Aug 7, 2025
8de1fba
change in-use-file extension to ".c9u"
infeo Aug 7, 2025
640f7aa
rename method
infeo Aug 7, 2025
768ce65
add todo
infeo Aug 7, 2025
eb49e42
add map for selfUsed files
infeo Aug 7, 2025
880f0b8
refactor and rename classes
infeo Aug 8, 2025
40cb207
remove unused inUseFile map
infeo Aug 12, 2025
2a29ded
move generation of in-use-event to CryptoFileSystemImpl
infeo Aug 12, 2025
85f7ea9
renaming method
infeo Aug 12, 2025
6c071de
implement in-use-check for moveFile
infeo Aug 12, 2025
83388ad
implement in-use-feature for deleteFile()
infeo Aug 12, 2025
0f13de9
cleanup
infeo Aug 13, 2025
8f443d8
add in-use-check to deleteFile
infeo Aug 13, 2025
f92b4e0
async approach
infeo Aug 14, 2025
842b3c6
Refactor useToken and add unit tests
infeo Aug 27, 2025
3d2a009
Enhancing UseToken:
infeo Aug 27, 2025
ce1ecd9
decouple inUseManager from OpenCryptoFile
infeo Aug 27, 2025
fb3cf20
Refactor inUseManager
infeo Aug 31, 2025
22a83b1
refine inUseManager api
infeo Aug 31, 2025
1a722ea
fix file deletion problem
infeo Aug 31, 2025
aeb6f6c
fix wrong path used in move and close methods
infeo Sep 1, 2025
2997f04
add unit tests for RealInUseManager
infeo Sep 1, 2025
ac44892
cleanup
infeo Sep 1, 2025
80a8edb
if the filesystem is read-only, ignore in-use feature
infeo Sep 1, 2025
a6d236e
add CLOSED_TOKEN and assign new token based on if old token is closed
infeo Sep 1, 2025
dd79342
remove unused parameter
infeo Sep 1, 2025
3bce755
extend unit tests for OpenCryptoFile
infeo Sep 1, 2025
05a326f
enable clean compilation
infeo Sep 2, 2025
732bf7f
add owner to CryptoFileSystemProperties
infeo Sep 2, 2025
901f058
adjust CryptoFileSystemImpl tests to new API
infeo Sep 2, 2025
17319a3
fix unit tests
infeo Sep 2, 2025
775e0a0
Add cryptor to RealInUseManager
infeo Sep 5, 2025
b0b6947
Add encryption to inUse file
infeo Sep 5, 2025
1567acc
add unit tests for readInUseFIle
infeo Sep 22, 2025
5517765
clean up
infeo Sep 22, 2025
fcf468a
restrict the length of owner parameter
infeo Sep 24, 2025
4699146
resolve todo
infeo Sep 24, 2025
ca875c0
add time condition to isInUse
infeo Sep 26, 2025
cb07aa9
move validate to isInUse method
infeo Sep 26, 2025
c2edfbc
move inUse exception to correct package
infeo Sep 30, 2025
56305b2
add method to ignoreOwnership to InUseManager API
infeo Sep 30, 2025
71cc4d7
add method to ignoreInUse file and cache useInfo for short time
infeo Oct 10, 2025
dcd6dab
add documentation to InUseManager interface
infeo Oct 10, 2025
c79f1e4
refactor inner record UseInfo to own class file
infeo Oct 10, 2025
f30e5e0
refactor FileIsInUseEvent
infeo Oct 10, 2025
3296a91
add method to event which allows to ignore the use-file of the event …
infeo Oct 10, 2025
7c85167
remove not needed assertion in test
infeo Oct 10, 2025
10ecd47
Merge branch 'develop' into feature/files-in-use
infeo Oct 14, 2025
4d5204a
add refresh logic
infeo Oct 14, 2025
57d3649
resolve todo
infeo Oct 14, 2025
3888eba
remove usage of jspecify
infeo Oct 14, 2025
83b596e
doc doc
infeo Oct 14, 2025
64d3e38
fix validation method
infeo Oct 14, 2025
3a64f09
don't mask actual exception with close() failure
infeo Oct 14, 2025
ee96d60
fix doc
infeo Oct 14, 2025
7dd7540
fix unclosed inUse file channels
infeo Oct 14, 2025
b6f0e4f
doc doc doc
infeo Oct 15, 2025
463d8dc
prevent unwanted integer cast
infeo Oct 15, 2025
fc70e09
clean up
infeo Oct 15, 2025
0960792
always open a new file channel on refresh
infeo Oct 16, 2025
943503d
adjust log levels
infeo Oct 16, 2025
e5fb49e
Remove unused code and simplify code
infeo Oct 16, 2025
5a89b48
reduce log level
infeo Oct 16, 2025
8fb283b
reset filechannel after writing to file
infeo Oct 16, 2025
d7c65ee
use a single virtual thread executor for creating in useFiles
infeo Oct 17, 2025
19e189c
follow a more idiomatic programming style accquiring locks
infeo Oct 17, 2025
270cf11
doc doc doc
infeo Oct 17, 2025
a9bd0a0
only create actual token when a filechannel is opened for writing
infeo Oct 17, 2025
b40d183
remove unnecessary comment string in decrypted in-use-file
infeo Oct 17, 2025
fe9bbc7
avoid typecasting
infeo Oct 17, 2025
b65c0ea
add more tests to RealUseToken
infeo Oct 17, 2025
5eb9191
Merge branch 'develop' into feature/files-in-use
infeo Oct 17, 2025
7a2b548
Remove CryptoPath from FileIsInUseEvent
infeo Oct 17, 2025
819a414
fix ignoring mechanism
infeo Oct 21, 2025
cd7bf09
close executor services on filesystem.close()
infeo Oct 21, 2025
c2089ab
adjust pom to coding style
infeo Oct 22, 2025
7d3998a
fix test description
infeo Oct 22, 2025
bd9032f
Force writings to inUseFile
infeo Oct 22, 2025
3448469
Remove TODO
infeo Oct 22, 2025
ebe8c6e
always truncate inUse file before writing
infeo Oct 22, 2025
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
1 change: 1 addition & 0 deletions .idea/codeStyles/Project.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

7 changes: 7 additions & 0 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
<slf4j.version>2.0.17</slf4j.version>

<!-- test dependencies -->
<awaitility.version>4.3.0</awaitility.version>
<junit.jupiter.version>6.0.0</junit.jupiter.version>
<jmh.version>1.37</jmh.version>
<mockito.version>5.20.0</mockito.version>
Expand Down Expand Up @@ -159,6 +160,12 @@
<version>${jimfs.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.awaitility</groupId>
<artifactId>awaitility</artifactId>
<version>${awaitility.version}</version>
<scope>test</scope>
</dependency>
</dependencies>

<build>
Expand Down
63 changes: 53 additions & 10 deletions src/main/java/org/cryptomator/cryptofs/CryptoFileSystemImpl.java
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
*******************************************************************************/
package org.cryptomator.cryptofs;

import jakarta.inject.Inject;
import org.cryptomator.cryptofs.attr.AttributeByNameProvider;
import org.cryptomator.cryptofs.attr.AttributeProvider;
import org.cryptomator.cryptofs.attr.AttributeViewProvider;
Expand All @@ -19,10 +20,14 @@
import org.cryptomator.cryptofs.dir.CiphertextDirectoryDeleter;
import org.cryptomator.cryptofs.dir.DirectoryStreamFactory;
import org.cryptomator.cryptofs.dir.DirectoryStreamFilters;
import org.cryptomator.cryptofs.event.FileIsInUseEvent;
import org.cryptomator.cryptofs.event.FilesystemEvent;
import org.cryptomator.cryptofs.fh.OpenCryptoFiles;
import org.cryptomator.cryptofs.inuse.FileAlreadyInUseException;
import org.cryptomator.cryptofs.inuse.InUseManager;
import org.cryptomator.cryptofs.inuse.UseInfo;
import org.cryptomator.cryptolib.api.Cryptor;

import jakarta.inject.Inject;
import java.io.IOException;
import java.nio.channels.FileChannel;
import java.nio.file.AccessDeniedException;
Expand Down Expand Up @@ -56,12 +61,14 @@
import java.nio.file.attribute.PosixFileAttributes;
import java.nio.file.attribute.PosixFilePermission;
import java.nio.file.attribute.UserPrincipalLookupService;
import java.time.Instant;
import java.util.Arrays;
import java.util.Collections;
import java.util.EnumSet;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
import java.util.function.Consumer;
import java.util.stream.Collectors;

import static java.lang.String.format;
Expand Down Expand Up @@ -92,10 +99,11 @@ class CryptoFileSystemImpl extends CryptoFileSystem {
private final CiphertextDirectoryDeleter ciphertextDirDeleter;
private final ReadonlyFlag readonlyFlag;
private final CryptoFileSystemProperties fileSystemProperties;

private final InUseManager inUseManager;
private final CryptoPath rootPath;
private final CryptoPath emptyPath;
private final FileNameDecryptor fileNameDecryptor;
private final Consumer<FilesystemEvent> eventConsumer;

private volatile boolean open = true;

Expand All @@ -105,7 +113,7 @@ public CryptoFileSystemImpl(CryptoFileSystemProvider provider, CryptoFileSystems
PathMatcherFactory pathMatcherFactory, DirectoryStreamFactory directoryStreamFactory, DirectoryIdProvider dirIdProvider, DirectoryIdBackup dirIdBackup, //
AttributeProvider fileAttributeProvider, AttributeByNameProvider fileAttributeByNameProvider, AttributeViewProvider fileAttributeViewProvider, //
OpenCryptoFiles openCryptoFiles, Symlinks symlinks, FinallyUtil finallyUtil, CiphertextDirectoryDeleter ciphertextDirDeleter, ReadonlyFlag readonlyFlag, //
CryptoFileSystemProperties fileSystemProperties, FileNameDecryptor fileNameDecryptor) {
CryptoFileSystemProperties fileSystemProperties, InUseManager inUseManager, FileNameDecryptor fileNameDecryptor, Consumer<FilesystemEvent> eventConsumer) {
this.provider = provider;
this.cryptoFileSystems = cryptoFileSystems;
this.pathToVault = pathToVault;
Expand All @@ -130,7 +138,9 @@ public CryptoFileSystemImpl(CryptoFileSystemProvider provider, CryptoFileSystems

this.rootPath = cryptoPathFactory.rootFor(this);
this.emptyPath = cryptoPathFactory.emptyFor(this);
this.inUseManager = inUseManager;
this.fileNameDecryptor = fileNameDecryptor;
this.eventConsumer = eventConsumer;
}

@Override
Expand Down Expand Up @@ -203,9 +213,11 @@ public void close() throws IOException {
open = false;
finallyUtil.guaranteeInvocationOf( //
() -> cryptoFileSystems.remove(this), //
() -> openCryptoFiles.close(), //
() -> directoryStreamFactory.close(), //
() -> cryptor.destroy());
openCryptoFiles::close, //
directoryStreamFactory::close, //
inUseManager::close, //
cryptor::destroy //
);
}
}

Expand Down Expand Up @@ -402,8 +414,9 @@ private FileChannel newFileChannelFromFile(CryptoPath cleartextFilePath, Effecti
Files.createDirectories(ciphertextPath.getRawPath()); // suppresses FileAlreadyExists
}

FileChannel ch = openCryptoFiles.getOrCreate(ciphertextFilePath).newFileChannel(options, attrs); // might throw FileAlreadyExists
FileChannel ch = null;
try {
ch = openCryptoFiles.getOrCreate(ciphertextFilePath).newFileChannel(options, attrs); // might throw FileAlreadyExists
if (options.writable()) {
ciphertextPath.persistLongFileName();
stats.incrementAccessesWritten();
Expand All @@ -414,7 +427,17 @@ private FileChannel newFileChannelFromFile(CryptoPath cleartextFilePath, Effecti
stats.incrementAccesses();
return ch;
} catch (Exception e) {
ch.close();
if (e instanceof FileAlreadyInUseException) {
var useInfo = inUseManager.getUseInfo(ciphertextFilePath).orElse(new UseInfo("UNKNOWN", Instant.now()));
eventConsumer.accept(new FileIsInUseEvent(cleartextFilePath, ciphertextFilePath, useInfo.owner(), useInfo.lastUpdated(), () -> inUseManager.ignoreInUse(ciphertextFilePath)));
}
if (ch != null) {
try {
ch.close();
} catch (IOException closeEx) {
e.addSuppressed(closeEx);
}
}
throw e;
}
}
Expand All @@ -428,11 +451,18 @@ void delete(CryptoPath cleartextPath) throws IOException {
CiphertextFilePath ciphertextPath = cryptoPathMapper.getCiphertextFilePath(cleartextPath);
switch (ciphertextFileType) {
case DIRECTORY -> deleteDirectory(cleartextPath, ciphertextPath);
case FILE, SYMLINK -> deleteFileOrSymlink(ciphertextPath);
case FILE -> deleteFile(cleartextPath, ciphertextPath);
case SYMLINK -> deleteSymlink(ciphertextPath);
}
}

private void deleteFileOrSymlink(CiphertextFilePath ciphertextPath) throws IOException {
private void deleteFile(CryptoPath cleartextPath, CiphertextFilePath ciphertextPath) throws IOException {
checkUsage(cleartextPath, ciphertextPath);
openCryptoFiles.delete(ciphertextPath.getFilePath());
Files.walkFileTree(ciphertextPath.getRawPath(), DeletingFileVisitor.INSTANCE);
}

private void deleteSymlink(CiphertextFilePath ciphertextPath) throws IOException {
openCryptoFiles.delete(ciphertextPath.getFilePath());
Files.walkFileTree(ciphertextPath.getRawPath(), DeletingFileVisitor.INSTANCE);
}
Expand Down Expand Up @@ -605,6 +635,9 @@ private void moveFile(CryptoPath cleartextSource, CryptoPath cleartextTarget, Co
CiphertextFilePath ciphertextSource = cryptoPathMapper.getCiphertextFilePath(cleartextSource);
CiphertextFilePath ciphertextTarget = cryptoPathMapper.getCiphertextFilePath(cleartextTarget);
try (OpenCryptoFiles.TwoPhaseMove twoPhaseMove = openCryptoFiles.prepareMove(ciphertextSource.getRawPath(), ciphertextTarget.getRawPath())) {
//TODO: skip this if owner is not set in Properties
checkUsage(cleartextSource, ciphertextSource);
checkUsage(cleartextTarget, ciphertextTarget);
if (ciphertextTarget.isShortened()) {
Files.createDirectories(ciphertextTarget.getRawPath());
ciphertextTarget.persistLongFileName();
Expand Down Expand Up @@ -700,4 +733,14 @@ public String toString() {
return format("%sCryptoFileSystem(%s)", open ? "" : "closed ", pathToVault);
}

//visible for testing
void checkUsage(CryptoPath cleartextPath, CiphertextFilePath ciphertextPath) throws FileAlreadyInUseException {
var path = ciphertextPath.getFilePath();
if (inUseManager.isInUseByOthers(path)) {
var useInfo = inUseManager.getUseInfo(path).orElse(new UseInfo("UNKNOWN", Instant.now()));
eventConsumer.accept(new FileIsInUseEvent(cleartextPath, ciphertextPath.getRawPath(), useInfo.owner(), useInfo.lastUpdated(), () -> inUseManager.ignoreInUse(path)));
throw new FileAlreadyInUseException(ciphertextPath.getRawPath());
}
Comment on lines +736 to +743
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Use consistent ciphertext path (filePath) for event and exception

isInUseByOthers() checks the file path; emitting the event and throwing the exception with rawPath is inconsistent and may confuse consumers.

-			eventConsumer.accept(new FileIsInUseEvent(cleartextPath, ciphertextPath.getRawPath(), useInfo.owner(), useInfo.lastUpdated(), () -> inUseManager.ignoreInUse(path)));
-			throw new FileAlreadyInUseException(ciphertextPath.getRawPath());
+			eventConsumer.accept(new FileIsInUseEvent(cleartextPath, path, useInfo.owner(), useInfo.lastUpdated(), () -> inUseManager.ignoreInUse(path)));
+			throw new FileAlreadyInUseException(path);
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
//visible for testing
void checkUsage(CryptoPath cleartextPath, CiphertextFilePath ciphertextPath) throws FileAlreadyInUseException {
var path = ciphertextPath.getFilePath();
if (inUseManager.isInUseByOthers(path)) {
var useInfo = inUseManager.getUseInfo(path).orElse(new UseInfo("UNKNOWN", Instant.now()));
eventConsumer.accept(new FileIsInUseEvent(cleartextPath, ciphertextPath.getRawPath(), useInfo.owner(), useInfo.lastUpdated(), () -> inUseManager.ignoreInUse(path)));
throw new FileAlreadyInUseException(ciphertextPath.getRawPath());
}
// visible for testing
void checkUsage(CryptoPath cleartextPath, CiphertextFilePath ciphertextPath) throws FileAlreadyInUseException {
var path = ciphertextPath.getFilePath();
if (inUseManager.isInUseByOthers(path)) {
var useInfo = inUseManager.getUseInfo(path)
.orElse(new UseInfo("UNKNOWN", Instant.now()));
eventConsumer.accept(new FileIsInUseEvent(
cleartextPath,
path,
useInfo.owner(),
useInfo.lastUpdated(),
() -> inUseManager.ignoreInUse(path)
));
throw new FileAlreadyInUseException(path);
}
🤖 Prompt for AI Agents
In src/main/java/org/cryptomator/cryptofs/CryptoFileSystemImpl.java around lines
730 to 737, the code checks inUseManager.isInUseByOthers(path) using
ciphertextPath.getFilePath() but then emits the FileIsInUseEvent and throws
FileAlreadyInUseException with ciphertextPath.getRawPath(), causing
inconsistency; update the event and exception to use the same ciphertext file
path variable (path or ciphertextPath.getFilePath()) so both the
FileIsInUseEvent and the FileAlreadyInUseException carry the canonical
ciphertext path, and keep the existing ignoreInUse callback unchanged.

}

}
17 changes: 17 additions & 0 deletions src/main/java/org/cryptomator/cryptofs/CryptoFileSystemModule.java
Original file line number Diff line number Diff line change
Expand Up @@ -11,14 +11,19 @@
import org.cryptomator.cryptofs.attr.AttributeViewComponent;
import org.cryptomator.cryptofs.dir.DirectoryStreamComponent;
import org.cryptomator.cryptofs.event.FilesystemEvent;
import org.cryptomator.cryptofs.inuse.StubInUseManager;
import org.cryptomator.cryptofs.inuse.InUseManager;
import org.cryptomator.cryptofs.fh.OpenCryptoFileComponent;
import org.cryptomator.cryptofs.inuse.RealInUseManager;
import org.cryptomator.cryptolib.api.Cryptor;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.IOException;
import java.nio.file.FileStore;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.Objects;
import java.util.Optional;
import java.util.function.Consumer;

Expand Down Expand Up @@ -50,4 +55,16 @@ public Consumer<FilesystemEvent> provideFilesystemEventConsumer(CryptoFileSystem
}
};
}

@Provides
@CryptoFileSystemScoped
public InUseManager provideInUseManager(CryptoFileSystemProperties fsProps, Cryptor cryptor) {
var owner = Objects.requireNonNullElse(fsProps.owner(),"");
if(!owner.isBlank() && !fsProps.readonly()) {
return new RealInUseManager(owner, cryptor);
} else {
return new StubInUseManager();
}

}
}
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,14 @@ public enum FileSystemFlags {

static final CryptorProvider.Scheme DEFAULT_CIPHER_COMBO = CryptorProvider.Scheme.SIV_GCM;

/**
* Key identifying the filesystem owner.
*
* @since 2.10.0
*/
public static final String PROPERTY_OWNER = "owner";
static final String DEFAULT_OWNER = "";

private final Set<Entry<String, Object>> entries;

private CryptoFileSystemProperties(Builder builder) {
Expand All @@ -126,7 +134,8 @@ private CryptoFileSystemProperties(Builder builder) {
Map.entry(PROPERTY_EVENT_CONSUMER, builder.eventConsumer), //
Map.entry(PROPERTY_MAX_CLEARTEXT_NAME_LENGTH, builder.maxCleartextNameLength), //
Map.entry(PROPERTY_SHORTENING_THRESHOLD, builder.shorteningThreshold), //
Map.entry(PROPERTY_CIPHER_COMBO, builder.cipherCombo) //
Map.entry(PROPERTY_CIPHER_COMBO, builder.cipherCombo), //
Map.entry(PROPERTY_OWNER, builder.owner) //
);
}

Expand Down Expand Up @@ -169,6 +178,10 @@ Consumer<FilesystemEvent> filesystemEventConsumer() {
return (Consumer<FilesystemEvent>) get(PROPERTY_EVENT_CONSUMER);
}

String owner() {
return (String) get(PROPERTY_OWNER);
}

@Override
public Set<Entry<String, Object>> entrySet() {
return entries;
Expand Down Expand Up @@ -225,6 +238,7 @@ public static class Builder {
private int maxCleartextNameLength = DEFAULT_MAX_CLEARTEXT_NAME_LENGTH;
private int shorteningThreshold = DEFAULT_SHORTENING_THRESHOLD;
private Consumer<FilesystemEvent> eventConsumer = DEFAULT_EVENT_CONSUMER;
private String owner = DEFAULT_OWNER;

private Builder() {
}
Expand All @@ -238,6 +252,7 @@ private Builder(Map<String, ?> properties) {
checkedSet(Integer.class, PROPERTY_SHORTENING_THRESHOLD, properties, this::withShorteningThreshold);
checkedSet(CryptorProvider.Scheme.class, PROPERTY_CIPHER_COMBO, properties, this::withCipherCombo);
checkedSet(Consumer.class, PROPERTY_EVENT_CONSUMER, properties, this::withFilesystemEventConsumer);
checkedSet(String.class, PROPERTY_OWNER, properties, this::withOwner);
}

private <T> void checkedSet(Class<T> type, String key, Map<String, ?> properties, Consumer<T> setter) {
Expand Down Expand Up @@ -367,6 +382,23 @@ public Builder withFilesystemEventConsumer(Consumer<FilesystemEvent> eventConsum
return this;
}

/**
* Sets the owner of the filesystem.
* <p>
* The owners length must be less than or equal to 100.
*
* @param owner the owner string used when marking files in-use
* @return this
* @since 2.10.0
*/
public Builder withOwner(String owner) {
if (owner.length() > 100) {
throw new IllegalArgumentException("owner must have length less than or equal to 100");
}
this.owner = owner;
return this;
}

/**
* Validates the values and creates new {@link CryptoFileSystemProperties}.
*
Expand Down
15 changes: 3 additions & 12 deletions src/main/java/org/cryptomator/cryptofs/DirectoryIdBackup.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,12 @@

import jakarta.inject.Inject;
import org.cryptomator.cryptofs.common.Constants;
import org.cryptomator.cryptofs.common.EncryptedChannels;
import org.cryptomator.cryptolib.api.CryptoException;
import org.cryptomator.cryptolib.api.Cryptor;
import org.cryptomator.cryptolib.common.DecryptingReadableByteChannel;
import org.cryptomator.cryptolib.common.EncryptingWritableByteChannel;

import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.channels.ByteChannel;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
Expand Down Expand Up @@ -38,7 +36,7 @@ public DirectoryIdBackup(Cryptor cryptor) {
*/
public void write(CiphertextDirectory ciphertextDirectory) throws IOException {
try (var channel = Files.newByteChannel(getBackupFilePath(ciphertextDirectory.path()), StandardOpenOption.CREATE_NEW, StandardOpenOption.WRITE); //
var encryptingChannel = wrapEncryptionAround(channel, cryptor)) {
var encryptingChannel = EncryptedChannels.wrapEncryptionAround(channel, cryptor)) {
encryptingChannel.write(ByteBuffer.wrap(ciphertextDirectory.dirId().getBytes(StandardCharsets.US_ASCII)));
}
}
Expand Down Expand Up @@ -72,7 +70,7 @@ public byte[] read(Path ciphertextContentDir) throws IOException, CryptoExceptio
var dirIdBuffer = ByteBuffer.allocate(Constants.MAX_DIR_ID_LENGTH + 1); //a dir id contains at most 36 ascii chars, we add for security checks one more

try (var channel = Files.newByteChannel(dirIdBackupFile, StandardOpenOption.READ); //
var decryptingChannel = wrapDecryptionAround(channel, cryptor)) {
var decryptingChannel = EncryptedChannels.wrapDecryptionAround(channel, cryptor)) {
int read = decryptingChannel.read(dirIdBuffer);
if (read < 0 || read > Constants.MAX_DIR_ID_LENGTH) {
throw new IllegalStateException("Read directory id exceeds the maximum length of %d characters".formatted(Constants.MAX_DIR_ID_LENGTH));
Expand Down Expand Up @@ -103,11 +101,4 @@ private static Path getBackupFilePath(Path ciphertextContentDir) {
return ciphertextContentDir.resolve(Constants.DIR_ID_BACKUP_FILE_NAME);
}

DecryptingReadableByteChannel wrapDecryptionAround(ByteChannel channel, Cryptor cryptor) {
return new DecryptingReadableByteChannel(channel, cryptor, true);
}

EncryptingWritableByteChannel wrapEncryptionAround(ByteChannel channel, Cryptor cryptor) {
return new EncryptingWritableByteChannel(channel, cryptor);
}
}
Loading