diff --git a/src/main/java/org/cryptomator/cryptofs/CryptoFileSystemImpl.java b/src/main/java/org/cryptomator/cryptofs/CryptoFileSystemImpl.java index 8bd83d2d..d3d7af7c 100644 --- a/src/main/java/org/cryptomator/cryptofs/CryptoFileSystemImpl.java +++ b/src/main/java/org/cryptomator/cryptofs/CryptoFileSystemImpl.java @@ -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; @@ -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 ds = Files.newDirectoryStream(oldCiphertextDir)) { + Path targetCiphertextDirContentDir = cryptoPathMapper.getCiphertextDir(cleartextTarget).path; + boolean targetCiphertextDirExists = true; + try (DirectoryStream 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: diff --git a/src/main/java/org/cryptomator/cryptofs/dir/DirectoryStreamFilters.java b/src/main/java/org/cryptomator/cryptofs/dir/DirectoryStreamFilters.java new file mode 100644 index 00000000..13f87c11 --- /dev/null +++ b/src/main/java/org/cryptomator/cryptofs/dir/DirectoryStreamFilters.java @@ -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 EXCLUDE_DIR_ID_BACKUP = p -> !p.equals(p.resolveSibling(Constants.DIR_BACKUP_FILE_NAME)); + +} diff --git a/src/test/java/org/cryptomator/cryptofs/CryptoFileSystemProviderInMemoryIntegrationTest.java b/src/test/java/org/cryptomator/cryptofs/CryptoFileSystemProviderInMemoryIntegrationTest.java index c2822284..6b494ebb 100644 --- a/src/test/java/org/cryptomator/cryptofs/CryptoFileSystemProviderInMemoryIntegrationTest.java +++ b/src/test/java/org/cryptomator/cryptofs/CryptoFileSystemProviderInMemoryIntegrationTest.java @@ -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 {