diff --git a/main/filesystem-api/src/main/java/org/cryptomator/filesystem/FileSystemVisitor.java b/main/filesystem-api/src/main/java/org/cryptomator/filesystem/FolderVisitor.java similarity index 72% rename from main/filesystem-api/src/main/java/org/cryptomator/filesystem/FileSystemVisitor.java rename to main/filesystem-api/src/main/java/org/cryptomator/filesystem/FolderVisitor.java index becf74feb..c46de4a17 100644 --- a/main/filesystem-api/src/main/java/org/cryptomator/filesystem/FileSystemVisitor.java +++ b/main/filesystem-api/src/main/java/org/cryptomator/filesystem/FolderVisitor.java @@ -12,7 +12,7 @@ import static java.lang.String.format; import java.util.function.Consumer; -public class FileSystemVisitor { +public class FolderVisitor { private final Consumer beforeFolderVisitor; private final Consumer afterFolderVisitor; @@ -20,7 +20,7 @@ public class FileSystemVisitor { private final Consumer nodeVisitor; private final int maxDepth; - public FileSystemVisitor(FileSystemVisitorBuilder builder) { + public FolderVisitor(FolderVisitorBuilder builder) { this.beforeFolderVisitor = builder.beforeFolderVisitor; this.afterFolderVisitor = builder.afterFolderVisitor; this.fileVisitor = builder.fileVisitor; @@ -28,19 +28,19 @@ public class FileSystemVisitor { this.maxDepth = builder.maxDepth; } - public static FileSystemVisitorBuilder fileSystemVisitor() { - return new FileSystemVisitorBuilder(); + public static FolderVisitorBuilder folderVisitor() { + return new FolderVisitorBuilder(); } - public FileSystemVisitor visit(Folder folder) { + public FolderVisitor visit(Folder folder) { return visit(folder, 0); } - public FileSystemVisitor visit(File file) { + public FolderVisitor visit(File file) { return visit(file, 0); } - private FileSystemVisitor visit(Folder folder, int depth) { + private FolderVisitor visit(Folder folder, int depth) { beforeFolderVisitor.accept(folder); nodeVisitor.accept(folder); final int childDepth = depth + 1; @@ -52,13 +52,13 @@ public class FileSystemVisitor { return this; } - private FileSystemVisitor visit(File file, int depth) { + private FolderVisitor visit(File file, int depth) { nodeVisitor.accept(file); fileVisitor.accept(file); return this; } - public static class FileSystemVisitorBuilder { + public static class FolderVisitorBuilder { private Consumer beforeFolderVisitor = noOp(); private Consumer afterFolderVisitor = noOp(); @@ -66,10 +66,10 @@ public class FileSystemVisitor { private Consumer nodeVisitor = noOp(); private int maxDepth = Integer.MAX_VALUE; - private FileSystemVisitorBuilder() { + private FolderVisitorBuilder() { } - public FileSystemVisitorBuilder beforeFolder(Consumer beforeFolderVisitor) { + public FolderVisitorBuilder beforeFolder(Consumer beforeFolderVisitor) { if (beforeFolderVisitor == null) { throw new IllegalArgumentException("Vistior may not be null"); } @@ -77,7 +77,7 @@ public class FileSystemVisitor { return this; } - public FileSystemVisitorBuilder afterFolder(Consumer afterFolderVisitor) { + public FolderVisitorBuilder afterFolder(Consumer afterFolderVisitor) { if (afterFolderVisitor == null) { throw new IllegalArgumentException("Vistior may not be null"); } @@ -85,7 +85,7 @@ public class FileSystemVisitor { return this; } - public FileSystemVisitorBuilder forEachFile(Consumer fileVisitor) { + public FolderVisitorBuilder forEachFile(Consumer fileVisitor) { if (fileVisitor == null) { throw new IllegalArgumentException("Vistior may not be null"); } @@ -93,7 +93,7 @@ public class FileSystemVisitor { return this; } - public FileSystemVisitorBuilder forEachNode(Consumer nodeVisitor) { + public FolderVisitorBuilder forEachNode(Consumer nodeVisitor) { if (nodeVisitor == null) { throw new IllegalArgumentException("Vistior may not be null"); } @@ -101,7 +101,7 @@ public class FileSystemVisitor { return this; } - public FileSystemVisitorBuilder withMaxDepth(int maxDepth) { + public FolderVisitorBuilder withMaxDepth(int maxDepth) { if (maxDepth < 0) { throw new IllegalArgumentException(format("maxDepth must not be smaller 0 but was %d", maxDepth)); } @@ -109,16 +109,16 @@ public class FileSystemVisitor { return this; } - public FileSystemVisitor visit(Folder folder) { + public FolderVisitor visit(Folder folder) { return build().visit(folder); } - public FileSystemVisitor visit(File file) { + public FolderVisitor visit(File file) { return build().visit(file); } - public FileSystemVisitor build() { - return new FileSystemVisitor(this); + public FolderVisitor build() { + return new FolderVisitor(this); } private static Consumer noOp() { diff --git a/main/filesystem-crypto/src/main/java/org/cryptomator/filesystem/crypto/CryptoFolder.java b/main/filesystem-crypto/src/main/java/org/cryptomator/filesystem/crypto/CryptoFolder.java index 8463ee14d..304b30467 100644 --- a/main/filesystem-crypto/src/main/java/org/cryptomator/filesystem/crypto/CryptoFolder.java +++ b/main/filesystem-crypto/src/main/java/org/cryptomator/filesystem/crypto/CryptoFolder.java @@ -160,8 +160,8 @@ class CryptoFolder extends CryptoNode implements Folder { assert target.parent().isPresent() : "Target can not be root, thus has a parent"; // prepare target: - target.parent().get().create(); target.delete(); + target.parent().get().create(); // perform the actual move: final File dirFile = forceGetPhysicalFile(); @@ -186,7 +186,12 @@ class CryptoFolder extends CryptoNode implements Folder { return; } Deleter.deleteContent(this); - forceGetPhysicalFolder().delete(); + Folder physicalFolder = forceGetPhysicalFolder(); + physicalFolder.delete(); + Folder physicalFolderParent = physicalFolder.parent().get(); + if (physicalFolderParent.folders().count() == 0) { + physicalFolderParent.delete(); + } forceGetPhysicalFile().delete(); invalidateDirectoryIdsRecursively(); } diff --git a/main/filesystem-crypto/src/test/java/org/cryptomator/filesystem/crypto/CryptoFileSystemTest.java b/main/filesystem-crypto/src/test/java/org/cryptomator/filesystem/crypto/CryptoFileSystemTest.java index 4f42301a2..a8dd8fec3 100644 --- a/main/filesystem-crypto/src/test/java/org/cryptomator/filesystem/crypto/CryptoFileSystemTest.java +++ b/main/filesystem-crypto/src/test/java/org/cryptomator/filesystem/crypto/CryptoFileSystemTest.java @@ -8,14 +8,15 @@ *******************************************************************************/ package org.cryptomator.filesystem.crypto; -import static org.cryptomator.filesystem.FileSystemVisitor.fileSystemVisitor; +import static org.hamcrest.Matchers.both; +import static org.hamcrest.Matchers.greaterThanOrEqualTo; +import static org.hamcrest.Matchers.lessThanOrEqualTo; import java.io.IOException; import java.io.UncheckedIOException; import java.nio.ByteBuffer; import java.time.Instant; import java.util.Arrays; -import java.util.concurrent.atomic.AtomicInteger; import org.cryptomator.crypto.engine.Cryptor; import org.cryptomator.crypto.engine.NoCryptor; @@ -37,7 +38,6 @@ public class CryptoFileSystemTest { final FileSystem physicalFs = new InMemoryFileSystem(); final Folder physicalDataRoot = physicalFs.folder("d"); final FileSystem fs = new CryptoFileSystem(physicalFs, cryptor, Mockito.mock(CryptoFileSystemDelegate.class), "foo"); - fs.create(); // add another encrypted folder: final Folder fooFolder = fs.folder("foo"); @@ -47,8 +47,24 @@ public class CryptoFileSystemTest { fooBarFolder.create(); Assert.assertTrue(fooFolder.exists()); Assert.assertTrue(fooBarFolder.exists()); - Assert.assertEquals(3, countDataFolders(physicalDataRoot)); // parent + - // foo + bar + Assert.assertEquals(3, countDataFolders(physicalDataRoot)); // parent + foo + bar + } + + @Test(timeout = 1000) + public void testDirectoryDeletion() throws UncheckedIOException, IOException { + // mock stuff and prepare crypto FS: + final Cryptor cryptor = new NoCryptor(); + final FileSystem physicalFs = new InMemoryFileSystem(); + final Folder physicalDataRoot = physicalFs.folder("d"); + final FileSystem fs = new CryptoFileSystem(physicalFs, cryptor, Mockito.mock(CryptoFileSystemDelegate.class), "foo"); + + // create and delete folders: + fs.folder("foo").folder("bar").folder("baz").create(); + Assert.assertEquals(4, countDataFolders(physicalDataRoot)); // root + foo + bar + baz + Assert.assertThat(physicalDataRoot.folders().count(), both(greaterThanOrEqualTo(1l)).and(lessThanOrEqualTo(4l))); // parent folders of the 4 folders + fs.folder("foo").delete(); + Assert.assertEquals(1, countDataFolders(physicalDataRoot)); // just root + Assert.assertEquals(1, physicalDataRoot.folders().count()); // just the parent of root } @Test(timeout = 2000) @@ -204,22 +220,10 @@ public class CryptoFileSystemTest { } /** - * @return number of folders on second level inside the given dataRoot - * folder. + * @return number of folders on second level inside the given dataRoot folder. */ private static int countDataFolders(Folder dataRoot) { - final AtomicInteger num = new AtomicInteger(); - fileSystemVisitor() // - .afterFolder(folder -> { - final Folder parent = folder.parent().get(); - final Folder parentOfParent = parent.parent().orElse(null); - if (parentOfParent != null && parentOfParent.equals(dataRoot)) { - num.incrementAndGet(); - } - }) // - .withMaxDepth(2) // - .visit(dataRoot); - return num.get(); + return (int) dataRoot.folders().flatMap(Folder::folders).count(); } }