diff --git a/pom.xml b/pom.xml
index f4965755..b04b5f5e 100644
--- a/pom.xml
+++ b/pom.xml
@@ -2,7 +2,7 @@
4.0.0
org.cryptomator
cryptofs
- 1.8.5
+ 1.8.6
Cryptomator Crypto Filesystem
This library provides the Java filesystem provider used by Cryptomator.
https://github.com/cryptomator/cryptofs
diff --git a/src/main/java/org/cryptomator/cryptofs/ConflictResolver.java b/src/main/java/org/cryptomator/cryptofs/ConflictResolver.java
index 38ccec01..46a38d27 100644
--- a/src/main/java/org/cryptomator/cryptofs/ConflictResolver.java
+++ b/src/main/java/org/cryptomator/cryptofs/ConflictResolver.java
@@ -122,7 +122,7 @@ private Path renameConflictingFile(Path canonicalPath, Path conflictingPath, Str
}
LOG.info("Moving conflicting file {} to {}", conflictingPath, alternativePath);
Path resolved = Files.move(conflictingPath, alternativePath, StandardCopyOption.ATOMIC_MOVE);
- longFileNameProvider.persistCachedIfDeflated(resolved);
+ longFileNameProvider.getCached(resolved).ifPresent(LongFileNameProvider.DeflatedFileName::persist);
return resolved;
} catch (AuthenticationFailedException e) {
// not decryptable, no need to resolve any kind of conflict
diff --git a/src/main/java/org/cryptomator/cryptofs/CryptoFileSystemImpl.java b/src/main/java/org/cryptomator/cryptofs/CryptoFileSystemImpl.java
index 4322b0ba..db4fac79 100644
--- a/src/main/java/org/cryptomator/cryptofs/CryptoFileSystemImpl.java
+++ b/src/main/java/org/cryptomator/cryptofs/CryptoFileSystemImpl.java
@@ -56,6 +56,7 @@
import java.util.Collections;
import java.util.EnumSet;
import java.util.Map;
+import java.util.Optional;
import java.util.Set;
import java.util.stream.Collectors;
@@ -304,7 +305,7 @@ void createDirectory(CryptoPath cleartextDir, FileAttribute>... attrs) throws
// create dir if and only if the dirFile has been created right now (not if it has been created before):
try {
Files.createDirectories(ciphertextDir.path);
- longFileNameProvider.persistCachedIfDeflated(ciphertextDirFile);
+ longFileNameProvider.getCached(ciphertextDirFile).ifPresent(LongFileNameProvider.DeflatedFileName::persist);
} catch (IOException e) {
// make sure there is no orphan dir file:
Files.delete(ciphertextDirFile);
@@ -355,7 +356,7 @@ private FileChannel newFileChannel(CryptoPath cleartextFilePath, EffectiveOpenOp
} else {
// might also throw FileAlreadyExists:
FileChannel ch = openCryptoFiles.getOrCreate(ciphertextPath).newFileChannel(options);
- longFileNameProvider.persistCachedIfDeflated(ciphertextPath);
+ longFileNameProvider.getCached(ciphertextPath).ifPresent(LongFileNameProvider.DeflatedFileName::persist);
return ch;
}
}
@@ -423,8 +424,10 @@ private void copySymlink(CryptoPath cleartextSource, CryptoPath cleartextTarget,
Path ciphertextSourceFile = cryptoPathMapper.getCiphertextFilePath(cleartextSource, CiphertextFileType.SYMLINK);
Path ciphertextTargetFile = cryptoPathMapper.getCiphertextFilePath(cleartextTarget, CiphertextFileType.SYMLINK);
CopyOption[] resolvedOptions = ArrayUtils.without(options, LinkOption.NOFOLLOW_LINKS).toArray(CopyOption[]::new);
+ Optional deflatedFileName = longFileNameProvider.getCached(ciphertextTargetFile);
Files.copy(ciphertextSourceFile, ciphertextTargetFile, resolvedOptions);
- longFileNameProvider.persistCachedIfDeflated(ciphertextTargetFile);
+ deflatedFileName.ifPresent(LongFileNameProvider.DeflatedFileName::persist);
+
} else {
CryptoPath resolvedSource = symlinks.resolveRecursively(cleartextSource);
CryptoPath resolvedTarget = symlinks.resolveRecursively(cleartextTarget);
@@ -436,8 +439,9 @@ private void copySymlink(CryptoPath cleartextSource, CryptoPath cleartextTarget,
private void copyFile(CryptoPath cleartextSource, CryptoPath cleartextTarget, CopyOption[] options) throws IOException {
Path ciphertextSourceFile = cryptoPathMapper.getCiphertextFilePath(cleartextSource, CiphertextFileType.FILE);
Path ciphertextTargetFile = cryptoPathMapper.getCiphertextFilePath(cleartextTarget, CiphertextFileType.FILE);
+ Optional deflatedFileName = longFileNameProvider.getCached(ciphertextTargetFile);
Files.copy(ciphertextSourceFile, ciphertextTargetFile, options);
- longFileNameProvider.persistCachedIfDeflated(ciphertextTargetFile);
+ deflatedFileName.ifPresent(LongFileNameProvider.DeflatedFileName::persist);
}
private void copyDirectory(CryptoPath cleartextSource, CryptoPath cleartextTarget, CopyOption[] options) throws IOException {
@@ -445,8 +449,9 @@ private void copyDirectory(CryptoPath cleartextSource, CryptoPath cleartextTarge
Path ciphertextTargetDirFile = cryptoPathMapper.getCiphertextFilePath(cleartextTarget, CiphertextFileType.DIRECTORY);
if (Files.notExists(ciphertextTargetDirFile)) {
// create new:
+ Optional deflatedFileName = longFileNameProvider.getCached(ciphertextTargetDirFile);
createDirectory(cleartextTarget);
- longFileNameProvider.persistCachedIfDeflated(ciphertextTargetDirFile);
+ deflatedFileName.ifPresent(LongFileNameProvider.DeflatedFileName::persist);
} else if (ArrayUtils.contains(options, StandardCopyOption.REPLACE_EXISTING)) {
// keep existing (if empty):
Path ciphertextTargetDir = cryptoPathMapper.getCiphertextDir(cleartextTarget).path;
@@ -525,7 +530,7 @@ private void moveSymlink(CryptoPath cleartextSource, CryptoPath cleartextTarget,
Path ciphertextTargetFile = cryptoPathMapper.getCiphertextFilePath(cleartextTarget, CiphertextFileType.SYMLINK);
try (OpenCryptoFiles.TwoPhaseMove twoPhaseMove = openCryptoFiles.prepareMove(ciphertextSourceFile, ciphertextTargetFile)) {
Files.move(ciphertextSourceFile, ciphertextTargetFile, options);
- longFileNameProvider.persistCachedIfDeflated(ciphertextTargetFile);
+ longFileNameProvider.getCached(ciphertextTargetFile).ifPresent(LongFileNameProvider.DeflatedFileName::persist);
twoPhaseMove.commit();
}
}
@@ -537,7 +542,7 @@ private void moveFile(CryptoPath cleartextSource, CryptoPath cleartextTarget, Co
Path ciphertextTargetFile = cryptoPathMapper.getCiphertextFilePath(cleartextTarget, CiphertextFileType.FILE);
try (OpenCryptoFiles.TwoPhaseMove twoPhaseMove = openCryptoFiles.prepareMove(ciphertextSourceFile, ciphertextTargetFile)) {
Files.move(ciphertextSourceFile, ciphertextTargetFile, options);
- longFileNameProvider.persistCachedIfDeflated(ciphertextTargetFile);
+ longFileNameProvider.getCached(ciphertextTargetFile).ifPresent(LongFileNameProvider.DeflatedFileName::persist);
twoPhaseMove.commit();
}
}
@@ -550,7 +555,7 @@ private void moveDirectory(CryptoPath cleartextSource, CryptoPath cleartextTarge
if (!ArrayUtils.contains(options, StandardCopyOption.REPLACE_EXISTING)) {
// try to move, don't replace:
Files.move(ciphertextSourceDirFile, ciphertextTargetDirFile, options);
- longFileNameProvider.persistCachedIfDeflated(ciphertextTargetDirFile);
+ longFileNameProvider.getCached(ciphertextTargetDirFile).ifPresent(LongFileNameProvider.DeflatedFileName::persist);
} else if (ArrayUtils.contains(options, StandardCopyOption.ATOMIC_MOVE)) {
// replace atomically (impossible):
assert ArrayUtils.contains(options, StandardCopyOption.REPLACE_EXISTING);
@@ -569,7 +574,7 @@ private void moveDirectory(CryptoPath cleartextSource, CryptoPath cleartextTarge
Files.delete(ciphertextTargetDir);
}
Files.move(ciphertextSourceDirFile, ciphertextTargetDirFile, options);
- longFileNameProvider.persistCachedIfDeflated(ciphertextTargetDirFile);
+ longFileNameProvider.getCached(ciphertextTargetDirFile).ifPresent(LongFileNameProvider.DeflatedFileName::persist);
}
dirIdProvider.move(ciphertextSourceDirFile, ciphertextTargetDirFile);
cryptoPathMapper.invalidatePathMapping(cleartextSource);
diff --git a/src/main/java/org/cryptomator/cryptofs/LongFileNameProvider.java b/src/main/java/org/cryptomator/cryptofs/LongFileNameProvider.java
index 5dc965ec..a206b629 100644
--- a/src/main/java/org/cryptomator/cryptofs/LongFileNameProvider.java
+++ b/src/main/java/org/cryptomator/cryptofs/LongFileNameProvider.java
@@ -13,13 +13,11 @@
import com.google.common.cache.CacheLoader;
import com.google.common.cache.LoadingCache;
import com.google.common.io.BaseEncoding;
-import com.google.common.util.concurrent.UncheckedExecutionException;
import org.cryptomator.cryptolib.common.MessageDigestSupplier;
import javax.inject.Inject;
import java.io.IOException;
import java.io.UncheckedIOException;
-import java.nio.ByteBuffer;
import java.nio.channels.WritableByteChannel;
import java.nio.file.FileAlreadyExistsException;
import java.nio.file.Files;
@@ -27,6 +25,7 @@
import java.nio.file.StandardOpenOption;
import java.time.Duration;
import java.util.Arrays;
+import java.util.Optional;
import java.util.concurrent.ExecutionException;
import static java.nio.charset.StandardCharsets.UTF_8;
@@ -86,34 +85,51 @@ public String deflate(String longFileName) {
return shortName;
}
- public void persistCachedIfDeflated(Path ciphertextFile) throws IOException {
- String filename = ciphertextFile.getFileName().toString();
- if (isDeflated(filename)) {
- persistCached(filename);
- }
+ private Path resolveMetadataFile(String shortName) {
+ return metadataRoot.resolve(shortName.substring(0, 2)).resolve(shortName.substring(2, 4)).resolve(shortName);
}
- // visible for testing
- void persistCached(String shortName) throws IOException {
- readonlyFlag.assertWritable();
+ public Optional getCached(Path ciphertextFile) {
+ String shortName = ciphertextFile.getFileName().toString();
String longName = longNames.getIfPresent(shortName);
- if (longName == null) {
- throw new IllegalStateException("Long name for " + shortName + " has not been shortened within the last " + MAX_CACHE_AGE);
- }
- Path file = resolveMetadataFile(shortName);
- Path fileDir = file.getParent();
- assert fileDir != null : "resolveMetadataFile returned path to a file";
- Files.createDirectories(fileDir);
- try (WritableByteChannel ch = Files.newByteChannel(file, StandardOpenOption.WRITE, StandardOpenOption.CREATE_NEW)) {
- ch.write(UTF_8.encode(longName));
- } catch (FileAlreadyExistsException e) {
- // no-op: if the file already exists, we assume its content to be what we want (or we found a SHA1 collision ;-))
- assert Arrays.equals(Files.readAllBytes(file), longName.getBytes(UTF_8));
+ if (longName != null) {
+ return Optional.of(new DeflatedFileName(shortName, longName));
+ } else {
+ return Optional.empty();
}
}
- private Path resolveMetadataFile(String shortName) {
- return metadataRoot.resolve(shortName.substring(0, 2)).resolve(shortName.substring(2, 4)).resolve(shortName);
+ public class DeflatedFileName {
+
+ public final String shortName;
+ public final String longName;
+
+ private DeflatedFileName(String shortName, String longName) {
+ this.shortName = shortName;
+ this.longName = longName;
+ }
+
+ public void persist() {
+ readonlyFlag.assertWritable();
+ try {
+ persistInternal();
+ } catch (IOException e) {
+ throw new UncheckedIOException(e);
+ }
+ }
+
+ private void persistInternal() throws IOException {
+ Path file = resolveMetadataFile(shortName);
+ Path fileDir = file.getParent();
+ assert fileDir != null : "resolveMetadataFile returned path to a file";
+ Files.createDirectories(fileDir);
+ try (WritableByteChannel ch = Files.newByteChannel(file, StandardOpenOption.WRITE, StandardOpenOption.CREATE_NEW)) {
+ ch.write(UTF_8.encode(longName));
+ } catch (FileAlreadyExistsException e) {
+ // no-op: if the file already exists, we assume its content to be what we want (or we found a SHA1 collision ;-))
+ assert Arrays.equals(Files.readAllBytes(file), longName.getBytes(UTF_8));
+ }
+ }
}
}
diff --git a/src/main/java/org/cryptomator/cryptofs/Symlinks.java b/src/main/java/org/cryptomator/cryptofs/Symlinks.java
index 8af6bfcb..93b837e6 100644
--- a/src/main/java/org/cryptomator/cryptofs/Symlinks.java
+++ b/src/main/java/org/cryptomator/cryptofs/Symlinks.java
@@ -43,7 +43,7 @@ public void createSymbolicLink(CryptoPath cleartextPath, Path target, FileAttrib
EffectiveOpenOptions openOptions = EffectiveOpenOptions.from(EnumSet.of(StandardOpenOption.WRITE, StandardOpenOption.CREATE_NEW), readonlyFlag);
ByteBuffer content = UTF_8.encode(target.toString());
openCryptoFiles.writeCiphertextFile(ciphertextSymlinkFile, openOptions, content);
- longFileNameProvider.persistCachedIfDeflated(ciphertextSymlinkFile);
+ longFileNameProvider.getCached(ciphertextSymlinkFile).ifPresent(LongFileNameProvider.DeflatedFileName::persist);
}
public CryptoPath readSymbolicLink(CryptoPath cleartextPath) throws IOException {
diff --git a/src/main/java/org/cryptomator/cryptofs/attr/CryptoBasicFileAttributes.java b/src/main/java/org/cryptomator/cryptofs/attr/CryptoBasicFileAttributes.java
index 64352d65..de7828d2 100644
--- a/src/main/java/org/cryptomator/cryptofs/attr/CryptoBasicFileAttributes.java
+++ b/src/main/java/org/cryptomator/cryptofs/attr/CryptoBasicFileAttributes.java
@@ -54,7 +54,7 @@ public CryptoBasicFileAttributes(BasicFileAttributes delegate, CiphertextFileTyp
}
private static long getPlaintextFileSize(Path ciphertextPath, long size, Optional openCryptoFile, Cryptor cryptor) {
- return openCryptoFile.map(OpenCryptoFile::size).orElseGet(() -> calculatePlaintextFileSize(ciphertextPath, size, cryptor));
+ return openCryptoFile.flatMap(OpenCryptoFile::size).orElseGet(() -> calculatePlaintextFileSize(ciphertextPath, size, cryptor));
}
private static long calculatePlaintextFileSize(Path ciphertextPath, long size, Cryptor cryptor) {
diff --git a/src/main/java/org/cryptomator/cryptofs/ch/CleartextFileChannel.java b/src/main/java/org/cryptomator/cryptofs/ch/CleartextFileChannel.java
index 6da94530..af5d12f2 100644
--- a/src/main/java/org/cryptomator/cryptofs/ch/CleartextFileChannel.java
+++ b/src/main/java/org/cryptomator/cryptofs/ch/CleartextFileChannel.java
@@ -227,38 +227,58 @@ public MappedByteBuffer map(MapMode mode, long position, long size) {
}
@Override
- public FileLock lock(long position, long size, boolean shared) throws IOException {
+ public FileLock lock(long pos, long size, boolean shared) throws IOException {
assertOpen();
if (shared && !options.readable()) {
throw new NonReadableChannelException(); // shared lock only available on readable channel
} else if (!shared && !options.writable()) {
throw new NonWritableChannelException(); // exclusive lock only available on writable channel
}
- long firstChunk = position / cryptor.fileContentCryptor().cleartextChunkSize();
- long lastChunk = firstChunk + size / cryptor.fileContentCryptor().cleartextChunkSize();
- long ciphertextPosition = cryptor.fileHeaderCryptor().headerSize() + firstChunk * cryptor.fileContentCryptor().ciphertextChunkSize();
- long ciphertextSize = (lastChunk - firstChunk + 1) * cryptor.fileContentCryptor().ciphertextChunkSize();
- FileLock ciphertextLock = ciphertextFileChannel.lock(ciphertextPosition, ciphertextSize, shared);
- return new CleartextFileLock(this, ciphertextLock, position, size);
+ long beginOfFirstChunk = beginOfChunk(pos);
+ long beginOfLastChunk = beginOfChunk(pos + size);
+ final FileLock ciphertextLock;
+ if (beginOfFirstChunk == Long.MAX_VALUE || beginOfLastChunk == Long.MAX_VALUE) {
+ ciphertextLock = ciphertextFileChannel.lock(0l, Long.MAX_VALUE, shared);
+ } else {
+ long endOfLastChunk = beginOfLastChunk + cryptor.fileContentCryptor().ciphertextChunkSize();
+ ciphertextLock = ciphertextFileChannel.lock(beginOfFirstChunk, endOfLastChunk - beginOfFirstChunk, shared);
+ }
+ return new CleartextFileLock(this, ciphertextLock, pos, size);
}
@Override
- public FileLock tryLock(long position, long size, boolean shared) throws IOException {
+ public FileLock tryLock(long pos, long size, boolean shared) throws IOException {
assertOpen();
if (shared && !options.readable()) {
throw new NonReadableChannelException(); // shared lock only available on readable channel
} else if (!shared && !options.writable()) {
throw new NonWritableChannelException(); // exclusive lock only available on writable channel
}
- long firstChunk = position / cryptor.fileContentCryptor().cleartextChunkSize();
- long lastChunk = firstChunk + size / cryptor.fileContentCryptor().cleartextChunkSize();
- long ciphertextPosition = cryptor.fileHeaderCryptor().headerSize() + firstChunk * cryptor.fileContentCryptor().ciphertextChunkSize();
- long ciphertextSize = (lastChunk - firstChunk + 1) * cryptor.fileContentCryptor().ciphertextChunkSize();
- FileLock ciphertextLock = ciphertextFileChannel.tryLock(ciphertextPosition, ciphertextSize, shared);
+ long beginOfFirstChunk = beginOfChunk(pos);
+ long beginOfLastChunk = beginOfChunk(pos + size);
+ final FileLock ciphertextLock;
+ if (beginOfFirstChunk == Long.MAX_VALUE || beginOfLastChunk == Long.MAX_VALUE) {
+ ciphertextLock = ciphertextFileChannel.tryLock(0l, Long.MAX_VALUE, shared);
+ } else {
+ long endOfLastChunk = beginOfLastChunk + cryptor.fileContentCryptor().ciphertextChunkSize();
+ ciphertextLock = ciphertextFileChannel.tryLock(beginOfFirstChunk, endOfLastChunk - beginOfFirstChunk, shared);
+ }
if (ciphertextLock == null) {
return null;
} else {
- return new CleartextFileLock(this, ciphertextLock, position, size);
+ return new CleartextFileLock(this, ciphertextLock, pos, size);
+ }
+ }
+
+ // visible for testing
+ long beginOfChunk(long cleartextPos) {
+ long maxCiphertextPayloadSize = Long.MAX_VALUE - cryptor.fileHeaderCryptor().headerSize();
+ long maxChunks = maxCiphertextPayloadSize / cryptor.fileContentCryptor().ciphertextChunkSize();
+ long chunk = cleartextPos / cryptor.fileContentCryptor().cleartextChunkSize();
+ if (chunk > maxChunks) {
+ return Long.MAX_VALUE;
+ } else {
+ return chunk * cryptor.fileContentCryptor().ciphertextChunkSize() + cryptor.fileHeaderCryptor().headerSize();
}
}
diff --git a/src/main/java/org/cryptomator/cryptofs/fh/OpenCryptoFile.java b/src/main/java/org/cryptomator/cryptofs/fh/OpenCryptoFile.java
index fb54964e..1217d628 100644
--- a/src/main/java/org/cryptomator/cryptofs/fh/OpenCryptoFile.java
+++ b/src/main/java/org/cryptomator/cryptofs/fh/OpenCryptoFile.java
@@ -25,6 +25,7 @@
import java.nio.file.Path;
import java.nio.file.attribute.FileTime;
import java.time.Instant;
+import java.util.Optional;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.atomic.AtomicLong;
@@ -146,12 +147,15 @@ private void initFileSize(FileChannel ciphertextFileChannel) throws IOException
}
/**
- * @return The size of the opened file
- * @throws IllegalStateException If the OpenCryptoFile {@link OpenCryptoFiles#getOrCreate(Path) has been created} without {@link #newFileChannel(EffectiveOpenOptions) creating a file channel} next.
+ * @return The size of the opened file. Note that the filesize is unknown until a {@link #newFileChannel(EffectiveOpenOptions) file channel is opened}. In this case this method returns an empty optional.
*/
- public long size() {
- Preconditions.checkState(fileSize.get() != -1l, "size must only be called after a FileChannel is created for this OpenCryptoFile");
- return fileSize.get();
+ public Optional size() {
+ long val = fileSize.get();
+ if (val == -1l) {
+ return Optional.empty();
+ } else {
+ return Optional.of(val);
+ }
}
public FileTime getLastModifiedTime() {
diff --git a/src/test/java/org/cryptomator/cryptofs/CryptoFileChannelWriteReadIntegrationTest.java b/src/test/java/org/cryptomator/cryptofs/CryptoFileChannelWriteReadIntegrationTest.java
index 6defb010..5f4aae6c 100644
--- a/src/test/java/org/cryptomator/cryptofs/CryptoFileChannelWriteReadIntegrationTest.java
+++ b/src/test/java/org/cryptomator/cryptofs/CryptoFileChannelWriteReadIntegrationTest.java
@@ -26,6 +26,7 @@
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;
+import java.nio.channels.FileLock;
import java.nio.charset.StandardCharsets;
import java.nio.file.FileSystem;
import java.nio.file.Files;
@@ -110,6 +111,24 @@ public void afterEach() throws IOException {
Files.deleteIfExists(file);
}
+ @Test
+ public void testLockEmptyChannel() throws IOException {
+ try (FileChannel ch = FileChannel.open(file, CREATE, WRITE)) {
+ try (FileLock lock = ch.lock()) {
+ Assertions.assertNotNull(lock);
+ }
+ }
+ }
+
+ @Test
+ public void testTryLockEmptyChannel() throws IOException {
+ try (FileChannel ch = FileChannel.open(file, CREATE, WRITE)) {
+ try (FileLock lock = ch.tryLock()) {
+ Assertions.assertNotNull(lock);
+ }
+ }
+ }
+
// tests https://github.com/cryptomator/cryptofs/issues/55
@Test
public void testCreateNewFileSetsLastModifiedToNow() throws IOException, InterruptedException {
diff --git a/src/test/java/org/cryptomator/cryptofs/LongFileNameProviderTest.java b/src/test/java/org/cryptomator/cryptofs/LongFileNameProviderTest.java
index 1518f4dd..344d0f04 100644
--- a/src/test/java/org/cryptomator/cryptofs/LongFileNameProviderTest.java
+++ b/src/test/java/org/cryptomator/cryptofs/LongFileNameProviderTest.java
@@ -18,10 +18,12 @@
import java.nio.file.Files;
import java.nio.file.NoSuchFileException;
import java.nio.file.Path;
+import java.nio.file.Paths;
import java.nio.file.ReadOnlyFileSystemException;
import java.nio.file.SimpleFileVisitor;
import java.nio.file.attribute.BasicFileAttributes;
import java.util.Collections;
+import java.util.Optional;
import java.util.concurrent.atomic.AtomicInteger;
public class LongFileNameProviderTest {
@@ -58,7 +60,7 @@ public void testDeflateAndInflate(@TempDir Path tmpPath) throws IOException {
Assertions.assertEquals(orig, inflated1);
Assertions.assertEquals(0, countFiles(tmpPath));
- prov1.persistCached(deflated);
+ prov1.getCached(Paths.get(deflated)).ifPresent(LongFileNameProvider.DeflatedFileName::persist);
Assertions.assertEquals(1, countFiles(tmpPath));
LongFileNameProvider prov2 = new LongFileNameProvider(tmpPath, readonlyFlag);
@@ -89,9 +91,14 @@ public void testDeflateMultipleTimes(@TempDir Path tmpPath) {
public void testPerstistCachedFailsOnReadOnlyFileSystems(@TempDir Path tmpPath) {
LongFileNameProvider prov = new LongFileNameProvider(tmpPath, readonlyFlag);
+ String orig = "longName";
+ String shortened = prov.deflate(orig);
+ Optional cachedFileName = prov.getCached(Paths.get(shortened));
+
+ Assertions.assertTrue(cachedFileName.isPresent());
Mockito.doThrow(new ReadOnlyFileSystemException()).when(readonlyFlag).assertWritable();
Assertions.assertThrows(ReadOnlyFileSystemException.class, () -> {
- prov.persistCached("whatever");
+ cachedFileName.get().persist();
});
}
diff --git a/src/test/java/org/cryptomator/cryptofs/ch/CleartextFileChannelTest.java b/src/test/java/org/cryptomator/cryptofs/ch/CleartextFileChannelTest.java
index 7e7fc89a..ac41721e 100644
--- a/src/test/java/org/cryptomator/cryptofs/ch/CleartextFileChannelTest.java
+++ b/src/test/java/org/cryptomator/cryptofs/ch/CleartextFileChannelTest.java
@@ -16,6 +16,8 @@
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Nested;
import org.junit.jupiter.api.Test;
+import org.junit.jupiter.params.ParameterizedTest;
+import org.junit.jupiter.params.provider.CsvSource;
import org.mockito.InOrder;
import org.mockito.Mockito;
@@ -243,12 +245,21 @@ public void setup() {
Assumptions.assumeTrue(fileContentCryptor.ciphertextChunkSize() == 110);
}
+ @ParameterizedTest(name = "beginOfChunk({0}) == {1}")
+ @CsvSource({"0,50", "1,50", "99,50", "100,160", "199,160", "200,270", "300,380", "372,380", "399,380", "400,490", "4200,4670", "9223372036854775807,9223372036854775807"})
+ @DisplayName("correctness of beginOfChunk()")
+ public void testBeginOfChunk(long cleaertextPos, long expectedCiphertextPos) {
+ long ciphertextPos = inTest.beginOfChunk(cleaertextPos);
+
+ Assertions.assertEquals(expectedCiphertextPos, ciphertextPos);
+ }
+
@Test
@DisplayName("unsuccessful tryLock()")
public void testTryLockReturnsNullIfDelegateReturnsNull() throws IOException {
when(ciphertextFileChannel.tryLock(Mockito.anyLong(), Mockito.anyLong(), Mockito.anyBoolean())).thenReturn(null);
- FileLock result = inTest.tryLock(380l, 4290l, true);
+ FileLock result = inTest.tryLock(372l, 3828l, true);
Assertions.assertNull(result);
}
@@ -256,7 +267,7 @@ public void testTryLockReturnsNullIfDelegateReturnsNull() throws IOException {
@Test
@DisplayName("successful tryLock()")
public void testTryLockReturnsCryptoFileLockWrappingDelegate() throws IOException {
- when(ciphertextFileChannel.tryLock(380l, 4290l, true)).thenReturn(delegate);
+ when(ciphertextFileChannel.tryLock(380l, 4670l+110l-380l, true)).thenReturn(delegate);
FileLock result = inTest.tryLock(372l, 3828l, true);
@@ -272,7 +283,7 @@ public void testTryLockReturnsCryptoFileLockWrappingDelegate() throws IOExceptio
@Test
@DisplayName("successful lock()")
public void testLockReturnsCryptoFileLockWrappingDelegate() throws IOException {
- when(ciphertextFileChannel.lock(380l, 4290l, true)).thenReturn(delegate);
+ when(ciphertextFileChannel.lock(380l, 4670l+110l-380l, true)).thenReturn(delegate);
FileLock result = inTest.lock(372l, 3828l, true);
diff --git a/src/test/java/org/cryptomator/cryptofs/fh/OpenCryptoFileTest.java b/src/test/java/org/cryptomator/cryptofs/fh/OpenCryptoFileTest.java
index 2332b748..f424d770 100644
--- a/src/test/java/org/cryptomator/cryptofs/fh/OpenCryptoFileTest.java
+++ b/src/test/java/org/cryptomator/cryptofs/fh/OpenCryptoFileTest.java
@@ -124,9 +124,7 @@ public void setup() throws IOException {
@Order(0)
@DisplayName("getting size fails before creating first file channel")
public void testGetSizeBeforeCreatingFileChannel() {
- Assertions.assertThrows(IllegalStateException.class, () -> {
- openCryptoFile.size();
- });
+ Assertions.assertFalse(openCryptoFile.size().isPresent());
}
@Test
@@ -143,7 +141,7 @@ public void createFileChannel() throws IOException {
@Order(11)
@DisplayName("getting size succeeds after creating first file channel")
public void testGetSizeAfterCreatingFirstFileChannel() {
- Assertions.assertEquals(0l, openCryptoFile.size());
+ Assertions.assertEquals(0l, openCryptoFile.size().get());
}
// related to https://github.com/cryptomator/cryptofs/issues/51
@@ -166,7 +164,7 @@ public void errorDuringCreationOfSecondChannel() {
@Order(13)
@DisplayName("getting size succeeds after creating second file channel")
public void testGetSizeAfterCreatingSecondFileChannel() {
- Assertions.assertEquals(0l, openCryptoFile.size());
+ Assertions.assertEquals(0l, openCryptoFile.size().get());
}