Skip to content

Commit ae15463

Browse files
committed
Merge branch 'release/2.6.7'
2 parents 358362b + 322603b commit ae15463

File tree

5 files changed

+908
-853
lines changed

5 files changed

+908
-853
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>2.6.6</version>
5+
<version>2.6.7</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/CryptoFileSystemImpl.java

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
import org.cryptomator.cryptofs.common.DeletingFileVisitor;
1919
import org.cryptomator.cryptofs.common.FinallyUtil;
2020
import org.cryptomator.cryptofs.dir.CiphertextDirectoryDeleter;
21+
import org.cryptomator.cryptofs.dir.DirectoryStreamFilters;
2122
import org.cryptomator.cryptofs.dir.DirectoryStreamFactory;
2223
import org.cryptomator.cryptofs.fh.OpenCryptoFiles;
2324
import org.cryptomator.cryptolib.api.Cryptor;
@@ -621,20 +622,21 @@ private void moveDirectory(CryptoPath cleartextSource, CryptoPath cleartextTarge
621622
throw new AtomicMoveNotSupportedException(cleartextSource.toString(), cleartextTarget.toString(), "Replacing directories during move requires non-atomic status checks.");
622623
}
623624
// check if dir is empty:
624-
Path oldCiphertextDir = cryptoPathMapper.getCiphertextDir(cleartextTarget).path;
625-
boolean oldCiphertextDirExists = true;
626-
try (DirectoryStream<Path> ds = Files.newDirectoryStream(oldCiphertextDir)) {
625+
Path targetCiphertextDirContentDir = cryptoPathMapper.getCiphertextDir(cleartextTarget).path;
626+
boolean targetCiphertextDirExists = true;
627+
try (DirectoryStream<Path> ds = Files.newDirectoryStream(targetCiphertextDirContentDir, DirectoryStreamFilters.EXCLUDE_DIR_ID_BACKUP)) {
627628
if (ds.iterator().hasNext()) {
628629
throw new DirectoryNotEmptyException(cleartextTarget.toString());
629630
}
630631
} catch (NoSuchFileException e) {
631-
oldCiphertextDirExists = false;
632-
}
633-
// cleanup dir to be replaced:
634-
if (oldCiphertextDirExists) {
635-
Files.walkFileTree(oldCiphertextDir, DeletingFileVisitor.INSTANCE);
632+
targetCiphertextDirExists = false;
636633
}
634+
//delete dir link
637635
Files.walkFileTree(ciphertextTarget.getRawPath(), DeletingFileVisitor.INSTANCE);
636+
// cleanup content dir
637+
if (targetCiphertextDirExists) {
638+
Files.walkFileTree(targetCiphertextDirContentDir, DeletingFileVisitor.INSTANCE);
639+
}
638640
}
639641

640642
// no exceptions until this point, so MOVE:
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
package org.cryptomator.cryptofs.dir;
2+
3+
import org.cryptomator.cryptofs.common.Constants;
4+
5+
import java.nio.file.DirectoryStream;
6+
import java.nio.file.Path;
7+
8+
public interface DirectoryStreamFilters {
9+
10+
static DirectoryStream.Filter<Path> EXCLUDE_DIR_ID_BACKUP = p -> !p.equals(p.resolveSibling(Constants.DIR_BACKUP_FILE_NAME));
11+
12+
}
Lines changed: 103 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,103 @@
1+
package org.cryptomator.cryptofs;
2+
3+
import com.google.common.jimfs.Configuration;
4+
import com.google.common.jimfs.Jimfs;
5+
import org.cryptomator.cryptolib.api.Masterkey;
6+
import org.cryptomator.cryptolib.api.MasterkeyLoader;
7+
import org.junit.jupiter.api.AfterAll;
8+
import org.junit.jupiter.api.AfterEach;
9+
import org.junit.jupiter.api.BeforeAll;
10+
import org.junit.jupiter.api.BeforeEach;
11+
import org.junit.jupiter.api.DisplayName;
12+
import org.junit.jupiter.api.Test;
13+
import org.mockito.Mockito;
14+
15+
import java.io.IOException;
16+
import java.net.URI;
17+
import java.nio.file.FileSystem;
18+
import java.nio.file.FileSystems;
19+
import java.nio.file.Files;
20+
import java.nio.file.Path;
21+
import java.util.Arrays;
22+
import java.util.Comparator;
23+
import java.util.Set;
24+
25+
import static java.nio.file.StandardCopyOption.REPLACE_EXISTING;
26+
import static org.cryptomator.cryptofs.CryptoFileSystemProperties.cryptoFileSystemProperties;
27+
import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
28+
import static org.junit.jupiter.api.Assertions.assertTrue;
29+
30+
public class CryptoFileSystemProviderInMemoryIntegrationTest {
31+
32+
private static FileSystem tmpFs;
33+
private static Path pathToVault;
34+
35+
@BeforeAll
36+
public static void beforeAll() {
37+
tmpFs = Jimfs.newFileSystem(Configuration.unix());
38+
pathToVault = tmpFs.getPath("/vault");
39+
}
40+
41+
@BeforeEach
42+
public void beforeEach() throws IOException {
43+
Files.createDirectory(pathToVault);
44+
}
45+
46+
@AfterEach
47+
public void afterEach() throws IOException {
48+
try (var paths = Files.walk(pathToVault)) {
49+
var nodes = paths.sorted(Comparator.reverseOrder()).toList();
50+
for (var node : nodes) {
51+
Files.delete(node);
52+
}
53+
}
54+
}
55+
56+
@AfterAll
57+
public static void afterAll() throws IOException {
58+
tmpFs.close();
59+
}
60+
61+
@Test
62+
@DisplayName("Replace an existing, shortened, empty directory")
63+
public void testReplaceExistingShortenedDirEmpty() throws IOException {
64+
try (var fs = setupCryptoFs(50, 100, false)) {
65+
var dirName50Chars = "/target_89_123456789_123456789_123456789_123456789_"; //since filename encryption increases filename length, 50 cleartext chars are sufficient
66+
var source = fs.getPath("/sourceDir");
67+
var target = fs.getPath(dirName50Chars);
68+
Files.createDirectory(source);
69+
Files.createDirectory(target);
70+
assertDoesNotThrow(() -> Files.move(source, target, REPLACE_EXISTING));
71+
assertTrue(Files.notExists(source));
72+
assertTrue(Files.exists(target));
73+
}
74+
}
75+
76+
@Test
77+
@DisplayName("Replace an existing, shortened file")
78+
public void testReplaceExistingShortenedFile() throws IOException {
79+
try (var fs = setupCryptoFs(50, 100, false)) {
80+
var fiftyCharName2 = "/50char2_50char2_50char2_50char2_50char2_50char.txt"; //since filename encryption increases filename length, 50 cleartext chars are sufficient
81+
var source = fs.getPath("/source.txt");
82+
var target = fs.getPath(fiftyCharName2);
83+
Files.createFile(source);
84+
Files.createFile(target);
85+
86+
assertDoesNotThrow(() -> Files.move(source, target, REPLACE_EXISTING));
87+
assertTrue(Files.notExists(source));
88+
assertTrue(Files.exists(target));
89+
}
90+
}
91+
92+
private FileSystem setupCryptoFs(int ciphertextShorteningThreshold, int maxCleartextFilename, boolean readonly) throws IOException {
93+
byte[] key = new byte[64];
94+
Arrays.fill(key, (byte) 0x55);
95+
var keyLoader = Mockito.mock(MasterkeyLoader.class);
96+
Mockito.when(keyLoader.loadKey(Mockito.any())).thenAnswer(ignored -> new Masterkey(key));
97+
var properties = CryptoFileSystemProperties.cryptoFileSystemProperties().withKeyLoader(keyLoader).withShorteningThreshold(ciphertextShorteningThreshold).withMaxCleartextNameLength(maxCleartextFilename).withFlags(readonly ? Set.of(CryptoFileSystemProperties.FileSystemFlags.READONLY) : Set.of()).build();
98+
CryptoFileSystemProvider.initialize(pathToVault, properties, URI.create("test:key"));
99+
URI fsUri = CryptoFileSystemUri.create(pathToVault);
100+
return FileSystems.newFileSystem(fsUri, cryptoFileSystemProperties().withKeyLoader(keyLoader).build());
101+
}
102+
103+
}

0 commit comments

Comments
 (0)