Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
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
Expand Up @@ -58,6 +58,21 @@ 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 {
Expand Down