Skip to content

Commit

Permalink
Merge branch 'release/2.6.7'
Browse files Browse the repository at this point in the history
  • Loading branch information
infeo committed Aug 9, 2023
2 parents 358362b + 322603b commit ae15463
Show file tree
Hide file tree
Showing 5 changed files with 908 additions and 853 deletions.
2 changes: 1 addition & 1 deletion pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
<modelVersion>4.0.0</modelVersion>
<groupId>org.cryptomator</groupId>
<artifactId>cryptofs</artifactId>
<version>2.6.6</version>
<version>2.6.7</version>
<name>Cryptomator Crypto Filesystem</name>
<description>This library provides the Java filesystem provider used by Cryptomator.</description>
<url>https://github.com/cryptomator/cryptofs</url>
Expand Down
18 changes: 10 additions & 8 deletions src/main/java/org/cryptomator/cryptofs/CryptoFileSystemImpl.java
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
import org.cryptomator.cryptofs.common.DeletingFileVisitor;
import org.cryptomator.cryptofs.common.FinallyUtil;
import org.cryptomator.cryptofs.dir.CiphertextDirectoryDeleter;
import org.cryptomator.cryptofs.dir.DirectoryStreamFilters;
import org.cryptomator.cryptofs.dir.DirectoryStreamFactory;
import org.cryptomator.cryptofs.fh.OpenCryptoFiles;
import org.cryptomator.cryptolib.api.Cryptor;
Expand Down Expand Up @@ -621,20 +622,21 @@ private void moveDirectory(CryptoPath cleartextSource, CryptoPath cleartextTarge
throw new AtomicMoveNotSupportedException(cleartextSource.toString(), cleartextTarget.toString(), "Replacing directories during move requires non-atomic status checks.");
}
// check if dir is empty:
Path oldCiphertextDir = cryptoPathMapper.getCiphertextDir(cleartextTarget).path;
boolean oldCiphertextDirExists = true;
try (DirectoryStream<Path> ds = Files.newDirectoryStream(oldCiphertextDir)) {
Path targetCiphertextDirContentDir = cryptoPathMapper.getCiphertextDir(cleartextTarget).path;
boolean targetCiphertextDirExists = true;
try (DirectoryStream<Path> ds = Files.newDirectoryStream(targetCiphertextDirContentDir, DirectoryStreamFilters.EXCLUDE_DIR_ID_BACKUP)) {
if (ds.iterator().hasNext()) {
throw new DirectoryNotEmptyException(cleartextTarget.toString());
}
} catch (NoSuchFileException e) {
oldCiphertextDirExists = false;
}
// cleanup dir to be replaced:
if (oldCiphertextDirExists) {
Files.walkFileTree(oldCiphertextDir, DeletingFileVisitor.INSTANCE);
targetCiphertextDirExists = false;
}
//delete dir link
Files.walkFileTree(ciphertextTarget.getRawPath(), DeletingFileVisitor.INSTANCE);
// cleanup content dir
if (targetCiphertextDirExists) {
Files.walkFileTree(targetCiphertextDirContentDir, DeletingFileVisitor.INSTANCE);
}
}

// no exceptions until this point, so MOVE:
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package org.cryptomator.cryptofs.dir;

import org.cryptomator.cryptofs.common.Constants;

import java.nio.file.DirectoryStream;
import java.nio.file.Path;

public interface DirectoryStreamFilters {

static DirectoryStream.Filter<Path> EXCLUDE_DIR_ID_BACKUP = p -> !p.equals(p.resolveSibling(Constants.DIR_BACKUP_FILE_NAME));

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
package org.cryptomator.cryptofs;

import com.google.common.jimfs.Configuration;
import com.google.common.jimfs.Jimfs;
import org.cryptomator.cryptolib.api.Masterkey;
import org.cryptomator.cryptolib.api.MasterkeyLoader;
import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import org.mockito.Mockito;

import java.io.IOException;
import java.net.URI;
import java.nio.file.FileSystem;
import java.nio.file.FileSystems;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.Arrays;
import java.util.Comparator;
import java.util.Set;

import static java.nio.file.StandardCopyOption.REPLACE_EXISTING;
import static org.cryptomator.cryptofs.CryptoFileSystemProperties.cryptoFileSystemProperties;
import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
import static org.junit.jupiter.api.Assertions.assertTrue;

public class CryptoFileSystemProviderInMemoryIntegrationTest {

private static FileSystem tmpFs;
private static Path pathToVault;

@BeforeAll
public static void beforeAll() {
tmpFs = Jimfs.newFileSystem(Configuration.unix());
pathToVault = tmpFs.getPath("/vault");
}

@BeforeEach
public void beforeEach() throws IOException {
Files.createDirectory(pathToVault);
}

@AfterEach
public void afterEach() throws IOException {
try (var paths = Files.walk(pathToVault)) {
var nodes = paths.sorted(Comparator.reverseOrder()).toList();
for (var node : nodes) {
Files.delete(node);
}
}
}

@AfterAll
public static void afterAll() throws IOException {
tmpFs.close();
}

@Test
@DisplayName("Replace an existing, shortened, empty directory")
public void testReplaceExistingShortenedDirEmpty() throws IOException {
try (var fs = setupCryptoFs(50, 100, false)) {
var dirName50Chars = "/target_89_123456789_123456789_123456789_123456789_"; //since filename encryption increases filename length, 50 cleartext chars are sufficient
var source = fs.getPath("/sourceDir");
var target = fs.getPath(dirName50Chars);
Files.createDirectory(source);
Files.createDirectory(target);
assertDoesNotThrow(() -> Files.move(source, target, REPLACE_EXISTING));
assertTrue(Files.notExists(source));
assertTrue(Files.exists(target));
}
}

@Test
@DisplayName("Replace an existing, shortened file")
public void testReplaceExistingShortenedFile() throws IOException {
try (var fs = setupCryptoFs(50, 100, false)) {
var fiftyCharName2 = "/50char2_50char2_50char2_50char2_50char2_50char.txt"; //since filename encryption increases filename length, 50 cleartext chars are sufficient
var source = fs.getPath("/source.txt");
var target = fs.getPath(fiftyCharName2);
Files.createFile(source);
Files.createFile(target);

assertDoesNotThrow(() -> Files.move(source, target, REPLACE_EXISTING));
assertTrue(Files.notExists(source));
assertTrue(Files.exists(target));
}
}

private FileSystem setupCryptoFs(int ciphertextShorteningThreshold, int maxCleartextFilename, boolean readonly) throws IOException {
byte[] key = new byte[64];
Arrays.fill(key, (byte) 0x55);
var keyLoader = Mockito.mock(MasterkeyLoader.class);
Mockito.when(keyLoader.loadKey(Mockito.any())).thenAnswer(ignored -> new Masterkey(key));
var properties = CryptoFileSystemProperties.cryptoFileSystemProperties().withKeyLoader(keyLoader).withShorteningThreshold(ciphertextShorteningThreshold).withMaxCleartextNameLength(maxCleartextFilename).withFlags(readonly ? Set.of(CryptoFileSystemProperties.FileSystemFlags.READONLY) : Set.of()).build();
CryptoFileSystemProvider.initialize(pathToVault, properties, URI.create("test:key"));
URI fsUri = CryptoFileSystemUri.create(pathToVault);
return FileSystems.newFileSystem(fsUri, cryptoFileSystemProperties().withKeyLoader(keyLoader).build());
}

}
Loading

0 comments on commit ae15463

Please sign in to comment.