mirror of
https://github.com/cryptomator/cryptomator.git
synced 2026-05-18 02:31:27 +00:00
moved CryptoFolder.contains(Node) to Folder.isAncestorOf(Node), clarified a few javadocs
This commit is contained in:
@@ -15,7 +15,6 @@ import java.nio.ByteBuffer;
|
||||
import java.security.MessageDigest;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.time.Instant;
|
||||
import java.util.Optional;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.TimeoutException;
|
||||
@@ -146,15 +145,6 @@ class CryptoFolder extends CryptoNode implements Folder {
|
||||
physicalFolder().create(FolderCreateMode.INCLUDING_PARENTS);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void copyTo(Folder target) {
|
||||
if (this.contains(target)) {
|
||||
throw new IllegalArgumentException("Can not copy parent to child directory (src: " + this + ", dst: " + target + ")");
|
||||
}
|
||||
|
||||
Folder.super.copyTo(target);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void moveTo(Folder target) {
|
||||
if (target instanceof CryptoFolder) {
|
||||
@@ -165,7 +155,7 @@ class CryptoFolder extends CryptoNode implements Folder {
|
||||
}
|
||||
|
||||
private void moveToInternal(CryptoFolder target) {
|
||||
if (this.contains(target) || target.contains(this)) {
|
||||
if (this.isAncestorOf(target) || target.isAncestorOf(this)) {
|
||||
throw new IllegalArgumentException("Can not move directories containing one another (src: " + this + ", dst: " + target + ")");
|
||||
}
|
||||
|
||||
@@ -180,17 +170,6 @@ class CryptoFolder extends CryptoNode implements Folder {
|
||||
directoryId.set(null);
|
||||
}
|
||||
|
||||
private boolean contains(Node node) {
|
||||
Optional<? extends Folder> nodeParent = node.parent();
|
||||
while (nodeParent.isPresent()) {
|
||||
if (this.equals(nodeParent.get())) {
|
||||
return true;
|
||||
}
|
||||
nodeParent = nodeParent.get().parent();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void delete() {
|
||||
// TODO Auto-generated method stub
|
||||
|
||||
@@ -58,7 +58,7 @@ public interface Folder extends Node {
|
||||
Folder folder(String name) throws UncheckedIOException;
|
||||
|
||||
/**
|
||||
* Creates the directory, if it doesn't exist yet. After successful invocation {@link #exists()} will return <code>true</code>
|
||||
* Creates the directory, if it doesn't exist yet. No effect, if folder already exists. After successful invocation {@link #exists()} will return <code>true</code>.
|
||||
*
|
||||
* @param mode Depending on this option either the attempt is made to recursively create all parent directories or an exception is thrown if the parent doesn't exist yet.
|
||||
* @throws UncheckedIOException wrapping an {@link FileNotFoundException}, if mode is {@link FolderCreateMode#FAIL_IF_PARENT_IS_MISSING FAIL_IF_PARENT_IS_MISSING} and parent doesn't exist.
|
||||
@@ -66,20 +66,41 @@ public interface Folder extends Node {
|
||||
void create(FolderCreateMode mode) throws UncheckedIOException;
|
||||
|
||||
/**
|
||||
* Copies this directory and its contents to the given destination.
|
||||
* Recusively copies this directory and all its contents to (not into) the given destination, creating nonexisting parent directories.
|
||||
* If the target exists it is deleted before performing the copy.
|
||||
*
|
||||
* @param target Destination folder. Must not be a descendant of this folder.
|
||||
*/
|
||||
default void copyTo(Folder target) throws UncheckedIOException {
|
||||
final Folder copy = target.folder(this.name());
|
||||
copy.create(FolderCreateMode.INCLUDING_PARENTS);
|
||||
folders().forEach(folder -> folder.copyTo(copy));
|
||||
if (this.isAncestorOf(target)) {
|
||||
throw new IllegalArgumentException("Can not copy parent to child directory (src: " + this + ", dst: " + target + ")");
|
||||
}
|
||||
|
||||
// remove previous contents:
|
||||
if (target.exists()) {
|
||||
target.delete();
|
||||
}
|
||||
|
||||
// make sure target directory exists:
|
||||
target.create(FolderCreateMode.INCLUDING_PARENTS);
|
||||
assert target.exists();
|
||||
|
||||
// copy files:
|
||||
files().forEach(srcFile -> {
|
||||
final File dstFile = copy.file(srcFile.name());
|
||||
try (ReadableFile src = srcFile.openReadable(1, TimeUnit.SECONDS); WritableFile dst = dstFile.openWritable(1, TimeUnit.SECONDS)) {
|
||||
src.copyTo(dst);
|
||||
try (ReadableFile src = srcFile.openReadable(1, TimeUnit.SECONDS)) {
|
||||
final File dstFile = target.file(srcFile.name());
|
||||
try (WritableFile dst = dstFile.openWritable(1, TimeUnit.MILLISECONDS)) {
|
||||
src.copyTo(dst);
|
||||
} catch (TimeoutException e) {
|
||||
throw new IllegalStateException("Destination file (" + dstFile + ") must not exist yet, thus can't be locked.");
|
||||
}
|
||||
} catch (TimeoutException e) {
|
||||
throw new UncheckedIOException(new IOException("Failed to lock file in time.", e));
|
||||
throw new UncheckedIOException(new IOException("Failed to lock source file (" + srcFile + ") in time.", e));
|
||||
}
|
||||
});
|
||||
|
||||
// copy subdirectories:
|
||||
folders().forEach(folder -> folder.copyTo(target.folder(folder.name())));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -113,4 +134,20 @@ public interface Folder extends Node {
|
||||
.map(Folder.class::cast);
|
||||
}
|
||||
|
||||
/**
|
||||
* Recursively checks whether this folder or any subfolder contains the given node.
|
||||
*
|
||||
* @param node Potential child, grandchild, ...
|
||||
* @return <code>true</code> if this folder is an ancestor of the node.
|
||||
*/
|
||||
default boolean isAncestorOf(Node node) {
|
||||
if (!node.parent().isPresent()) {
|
||||
return false;
|
||||
} else if (node.parent().get().equals(this)) {
|
||||
return true;
|
||||
} else {
|
||||
return this.isAncestorOf(node.parent().get());
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -12,6 +12,9 @@ import java.util.Optional;
|
||||
/**
|
||||
* Represents a node, namely a {@link File} or {@link Folder}, in a
|
||||
* {@link FileSystem}.
|
||||
* <p>
|
||||
* A node's identity (i.e. {@link #hashCode()} and {@link #equals(Object)}) depends on its parent node and its name (forming the node's path).
|
||||
* These properties are meant to be immutable. This means that e.g. moving a node doesn't modify the node's identity but rather transfers properties to the destination node.
|
||||
*
|
||||
* @author Markus Kreusch
|
||||
* @see Folder
|
||||
@@ -21,6 +24,9 @@ public interface Node {
|
||||
|
||||
String name() throws UncheckedIOException;
|
||||
|
||||
/**
|
||||
* @return Optional parent folder. No parent is present for the root node (see {@link FileSystem#parent()}).
|
||||
*/
|
||||
Optional<? extends Folder> parent() throws UncheckedIOException;
|
||||
|
||||
boolean exists() throws UncheckedIOException;
|
||||
|
||||
@@ -102,7 +102,6 @@ public class InMemoryFileSystemTest {
|
||||
final FileSystem fs = new InMemoryFileSystem();
|
||||
final Folder fooBarFolder = fs.folder("foo").folder("bar");
|
||||
final Folder qweAsdFolder = fs.folder("qwe").folder("asd");
|
||||
final Folder qweAsdBarFolder = qweAsdFolder.folder("bar");
|
||||
final File test1File = fooBarFolder.file("test1.txt");
|
||||
final File test2File = fooBarFolder.file("test2.txt");
|
||||
fooBarFolder.create(FolderCreateMode.INCLUDING_PARENTS);
|
||||
@@ -116,11 +115,10 @@ public class InMemoryFileSystemTest {
|
||||
Assert.assertTrue(test1File.exists());
|
||||
Assert.assertTrue(test2File.exists());
|
||||
|
||||
// copy foo/bar/ to qwe/asd/ (result is qwe/asd/bar/file1.txt & qwe/asd/bar/file2.txt)
|
||||
// copy foo/bar/ to qwe/asd/ (result is qwe/asd/file1.txt & qwe/asd/file2.txt)
|
||||
fooBarFolder.copyTo(qweAsdFolder);
|
||||
Assert.assertTrue(qweAsdBarFolder.exists());
|
||||
Assert.assertEquals(1, qweAsdFolder.folders().count());
|
||||
Assert.assertEquals(2, qweAsdBarFolder.files().count());
|
||||
Assert.assertTrue(qweAsdFolder.exists());
|
||||
Assert.assertEquals(2, qweAsdFolder.files().count());
|
||||
|
||||
// make sure original files still exist:
|
||||
Assert.assertTrue(test1File.exists());
|
||||
|
||||
Reference in New Issue
Block a user