mirror of
https://github.com/cryptomator/cryptomator.git
synced 2026-05-18 10:41:26 +00:00
- moved method from WritableFile to File: moveTo, setLastModified, setCreationTime, delete
- moved method from File and Folder to Node: setLastModified, setCreationTime, delete
This commit is contained in:
@@ -73,23 +73,9 @@ public interface File extends Node, Comparable<File> {
|
||||
Copier.copy(this, destination);
|
||||
}
|
||||
|
||||
default void moveTo(File destination) {
|
||||
Mover.move(this, destination);
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* Deletes the file if it exists.
|
||||
* <p>
|
||||
* Does nothign if the file does not exist.
|
||||
* Moves this file including content to a new location specified by <code>destination</code>.
|
||||
*/
|
||||
default void delete() {
|
||||
if (!exists()) {
|
||||
return;
|
||||
}
|
||||
try (WritableFile writableFile = openWritable()) {
|
||||
writableFile.delete();
|
||||
}
|
||||
}
|
||||
void moveTo(File destination) throws UncheckedIOException;
|
||||
|
||||
}
|
||||
|
||||
@@ -98,14 +98,6 @@ public interface Folder extends Node {
|
||||
Copier.copy(this, target);
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* Deletes the directory including all child elements.
|
||||
* <p>
|
||||
* If the directory does not exist this method does nothing.
|
||||
*/
|
||||
void delete();
|
||||
|
||||
/**
|
||||
* Moves this directory and its contents to the given destination. If the
|
||||
* target exists it is deleted before performing the move.
|
||||
|
||||
@@ -1,22 +0,0 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2015 Sebastian Stenzel and others.
|
||||
* This file is licensed under the terms of the MIT license.
|
||||
* See the LICENSE.txt file for more info.
|
||||
*
|
||||
* Contributors:
|
||||
* Sebastian Stenzel - initial API and implementation
|
||||
*******************************************************************************/
|
||||
package org.cryptomator.filesystem;
|
||||
|
||||
class Mover {
|
||||
|
||||
public static void move(File source, File destination) {
|
||||
if (source == destination) {
|
||||
return;
|
||||
}
|
||||
try (OpenFiles openFiles = DeadlockSafeFileOpener.withWritable(source).andWritable(destination).open()) {
|
||||
openFiles.writable(source).moveTo(openFiles.writable(destination));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -30,10 +30,35 @@ public interface Node {
|
||||
*/
|
||||
Optional<? extends Folder> parent() throws UncheckedIOException;
|
||||
|
||||
/**
|
||||
* @return <code>true</code> if the node exists.
|
||||
*/
|
||||
boolean exists() throws UncheckedIOException;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* Deletes the node if it exists.
|
||||
* <p>
|
||||
* Does nothing if the node does not exist.
|
||||
*/
|
||||
void delete() throws UncheckedIOException;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* Determines the last modified date of this node.
|
||||
*
|
||||
* @returns the last modified date of the file
|
||||
*/
|
||||
Instant lastModified() throws UncheckedIOException;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* Sets the last modified date of the file.
|
||||
*
|
||||
* @param lastModified the time to set as creation time
|
||||
*/
|
||||
void setLastModified(Instant lastModified) throws UncheckedIOException;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* Determines the creation time of this node.
|
||||
@@ -53,9 +78,9 @@ public interface Node {
|
||||
* Setting the creation time may not be supported by all {@link FileSystem FileSystems}. If the {@code FileSystem} this {@code Node} belongs to does not support the
|
||||
* setting the creation time the behavior of this method is unspecified.
|
||||
*
|
||||
* @param instant the time to set as creation time
|
||||
* @param creationTime the time to set as creation time
|
||||
*/
|
||||
default void setCreationTime(Instant instant) throws UncheckedIOException {
|
||||
default void setCreationTime(Instant creationTime) throws UncheckedIOException {
|
||||
throw new UncheckedIOException(new IOException("CreationTime not supported"));
|
||||
}
|
||||
|
||||
|
||||
@@ -9,42 +9,9 @@ import java.io.IOException;
|
||||
import java.io.UncheckedIOException;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.channels.WritableByteChannel;
|
||||
import java.time.Instant;
|
||||
|
||||
public interface WritableFile extends WritableByteChannel {
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* Moves this file including content to another.
|
||||
* <p>
|
||||
* Moving a file causes itself and the target to be
|
||||
* {@link WritableFile#close() closed}.
|
||||
*/
|
||||
void moveTo(WritableFile other) throws UncheckedIOException;
|
||||
|
||||
void setLastModified(Instant instant) throws UncheckedIOException;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* Sets the creation time of the file.
|
||||
* <p>
|
||||
* Setting the creation time may not be supported by all {@link FileSystem FileSystems}. If the {@code FileSystem} this {@code WritableFile} belongs to does not support the
|
||||
* setting the creation time the behavior of this method is unspecified.
|
||||
*
|
||||
* @param instant the time to set as creation time
|
||||
*/
|
||||
default void setCreationTime(Instant instant) throws UncheckedIOException {
|
||||
throw new UncheckedIOException(new IOException("CreationTime not supported"));
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* Deletes this file from the file system.
|
||||
* <p>
|
||||
* Deleting a file causes it to be {@link WritableFile#close() closed}.
|
||||
*/
|
||||
void delete() throws UncheckedIOException;
|
||||
|
||||
void truncate() throws UncheckedIOException;
|
||||
|
||||
/**
|
||||
@@ -58,6 +25,7 @@ public interface WritableFile extends WritableByteChannel {
|
||||
* @throws UncheckedIOException
|
||||
* if an {@link IOException} occurs while writing
|
||||
*/
|
||||
@Override
|
||||
int write(ByteBuffer source) throws UncheckedIOException;
|
||||
|
||||
/**
|
||||
|
||||
@@ -9,7 +9,6 @@
|
||||
package org.cryptomator.filesystem.delegating;
|
||||
|
||||
import java.io.UncheckedIOException;
|
||||
import java.time.Instant;
|
||||
import java.util.Optional;
|
||||
|
||||
import org.cryptomator.filesystem.File;
|
||||
@@ -60,6 +59,11 @@ public abstract class DelegatingFile<D extends DelegatingFolder<D, ?>> extends D
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void delete() throws UncheckedIOException {
|
||||
delegate.delete();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int compareTo(File o) {
|
||||
if (getClass().equals(o.getClass())) {
|
||||
@@ -70,14 +74,4 @@ public abstract class DelegatingFile<D extends DelegatingFolder<D, ?>> extends D
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<Instant> creationTime() throws UncheckedIOException {
|
||||
return delegate.creationTime();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setCreationTime(Instant instant) throws UncheckedIOException {
|
||||
delegate.setCreationTime(instant);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -9,7 +9,6 @@
|
||||
package org.cryptomator.filesystem.delegating;
|
||||
|
||||
import java.io.UncheckedIOException;
|
||||
import java.time.Instant;
|
||||
import java.util.Optional;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
@@ -97,14 +96,4 @@ public abstract class DelegatingFolder<D extends DelegatingFolder<D, F>, F exten
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<Instant> creationTime() throws UncheckedIOException {
|
||||
return delegate.creationTime();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setCreationTime(Instant instant) throws UncheckedIOException {
|
||||
delegate.setCreationTime(instant);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -40,11 +40,21 @@ public abstract class DelegatingNode<T extends Node> implements Node {
|
||||
return delegate.lastModified();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setLastModified(Instant instant) throws UncheckedIOException {
|
||||
delegate.setLastModified(instant);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<Instant> creationTime() throws UncheckedIOException {
|
||||
return delegate.creationTime();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setCreationTime(Instant instant) throws UncheckedIOException {
|
||||
delegate.setCreationTime(instant);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return delegate.hashCode();
|
||||
|
||||
@@ -10,7 +10,6 @@ package org.cryptomator.filesystem.delegating;
|
||||
|
||||
import java.io.UncheckedIOException;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.time.Instant;
|
||||
|
||||
import org.cryptomator.filesystem.WritableFile;
|
||||
|
||||
@@ -27,26 +26,6 @@ public class DelegatingWritableFile implements WritableFile {
|
||||
return delegate.isOpen();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void moveTo(WritableFile destination) throws UncheckedIOException {
|
||||
if (getClass().equals(destination.getClass())) {
|
||||
final WritableFile delegateDest = ((DelegatingWritableFile) destination).delegate;
|
||||
delegate.moveTo(delegateDest);
|
||||
} else {
|
||||
throw new IllegalArgumentException("Can only move DelegatingWritableFile to a DelegatingWritableFile.");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setLastModified(Instant instant) throws UncheckedIOException {
|
||||
delegate.setLastModified(instant);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void delete() throws UncheckedIOException {
|
||||
delegate.delete();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void truncate() throws UncheckedIOException {
|
||||
delegate.truncate();
|
||||
@@ -67,9 +46,4 @@ public class DelegatingWritableFile implements WritableFile {
|
||||
delegate.close();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setCreationTime(Instant instant) throws UncheckedIOException {
|
||||
delegate.setCreationTime(instant);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
package org.cryptomator.filesystem.delegating;
|
||||
|
||||
import java.time.Instant;
|
||||
import java.util.Optional;
|
||||
|
||||
import org.cryptomator.filesystem.File;
|
||||
import org.cryptomator.filesystem.Folder;
|
||||
@@ -54,13 +55,43 @@ public class DelegatingFileTest {
|
||||
@Test
|
||||
public void testLastModified() {
|
||||
File mockFile = Mockito.mock(File.class);
|
||||
Instant now = Instant.now();
|
||||
|
||||
Mockito.when(mockFile.lastModified()).thenReturn(now);
|
||||
DelegatingFile<?> delegatingFile = new TestDelegatingFile(null, mockFile);
|
||||
|
||||
Instant now = Instant.now();
|
||||
Mockito.when(mockFile.lastModified()).thenReturn(now);
|
||||
Assert.assertEquals(now, delegatingFile.lastModified());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSetLastModified() {
|
||||
File mockFile = Mockito.mock(File.class);
|
||||
DelegatingFile<?> delegatingFile = new TestDelegatingFile(null, mockFile);
|
||||
|
||||
Instant now = Instant.now();
|
||||
delegatingFile.setLastModified(now);
|
||||
Mockito.verify(mockFile).setLastModified(now);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCreationTime() {
|
||||
File mockFile = Mockito.mock(File.class);
|
||||
DelegatingFile<?> delegatingFile = new TestDelegatingFile(null, mockFile);
|
||||
|
||||
Instant now = Instant.now();
|
||||
Mockito.when(mockFile.creationTime()).thenReturn(Optional.of(now));
|
||||
Assert.assertEquals(now, delegatingFile.creationTime().get());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSetCreationTime() {
|
||||
File mockFile = Mockito.mock(File.class);
|
||||
DelegatingFile<?> delegatingFile = new TestDelegatingFile(null, mockFile);
|
||||
|
||||
Instant now = Instant.now();
|
||||
delegatingFile.setCreationTime(now);
|
||||
Mockito.verify(mockFile).setCreationTime(now);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testOpenReadable() {
|
||||
File mockFile = Mockito.mock(File.class);
|
||||
@@ -122,6 +153,15 @@ public class DelegatingFileTest {
|
||||
Mockito.verify(mockFile1).copyTo(mockFile2);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDelete() {
|
||||
File mockFile = Mockito.mock(File.class);
|
||||
DelegatingFile<?> delegatingFile = new TestDelegatingFile(null, mockFile);
|
||||
|
||||
delegatingFile.delete();
|
||||
Mockito.verify(mockFile).delete();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCompareTo() {
|
||||
File mockFile1 = Mockito.mock(File.class);
|
||||
|
||||
@@ -11,6 +11,7 @@ package org.cryptomator.filesystem.delegating;
|
||||
import java.time.Instant;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
@@ -58,13 +59,43 @@ public class DelegatingFolderTest {
|
||||
@Test
|
||||
public void testLastModified() {
|
||||
Folder mockFolder = Mockito.mock(Folder.class);
|
||||
Instant now = Instant.now();
|
||||
|
||||
Mockito.when(mockFolder.lastModified()).thenReturn(now);
|
||||
DelegatingFolder<?, ?> delegatingFolder = new TestDelegatingFolder(null, mockFolder);
|
||||
|
||||
Instant now = Instant.now();
|
||||
Mockito.when(mockFolder.lastModified()).thenReturn(now);
|
||||
Assert.assertEquals(now, delegatingFolder.lastModified());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSetLastModified() {
|
||||
Folder mockFolder = Mockito.mock(Folder.class);
|
||||
DelegatingFolder<?, ?> delegatingFolder = new TestDelegatingFolder(null, mockFolder);
|
||||
|
||||
Instant now = Instant.now();
|
||||
delegatingFolder.setLastModified(now);
|
||||
Mockito.verify(mockFolder).setLastModified(now);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCreationTime() {
|
||||
Folder mockFolder = Mockito.mock(Folder.class);
|
||||
DelegatingFolder<?, ?> delegatingFolder = new TestDelegatingFolder(null, mockFolder);
|
||||
|
||||
Instant now = Instant.now();
|
||||
Mockito.when(mockFolder.creationTime()).thenReturn(Optional.of(now));
|
||||
Assert.assertEquals(now, delegatingFolder.creationTime().get());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSetCreationTime() {
|
||||
Folder mockFolder = Mockito.mock(Folder.class);
|
||||
DelegatingFolder<?, ?> delegatingFolder = new TestDelegatingFolder(null, mockFolder);
|
||||
|
||||
Instant now = Instant.now();
|
||||
delegatingFolder.setCreationTime(now);
|
||||
Mockito.verify(mockFolder).setCreationTime(now);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testChildren() {
|
||||
Folder mockFolder = Mockito.mock(Folder.class);
|
||||
@@ -172,16 +203,4 @@ public class DelegatingFolderTest {
|
||||
Assert.assertSame(delegatingFolder.folder("mockSubFolder"), delegatingFolder.folder("mockSubFolder"));
|
||||
Assert.assertSame(delegatingFolder.file("mockSubFile"), delegatingFolder.file("mockSubFile"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSetCreationTime() {
|
||||
Folder mockFolder = Mockito.mock(Folder.class);
|
||||
DelegatingFolder<?, ?> delegatingFolder = new TestDelegatingFolder(null, mockFolder);
|
||||
|
||||
Instant now = Instant.now();
|
||||
|
||||
delegatingFolder.setCreationTime(now);
|
||||
Mockito.verify(mockFolder).setCreationTime(now);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -9,7 +9,6 @@
|
||||
package org.cryptomator.filesystem.delegating;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
import java.time.Instant;
|
||||
|
||||
import org.cryptomator.filesystem.WritableFile;
|
||||
import org.junit.Assert;
|
||||
@@ -31,49 +30,6 @@ public class DelegatingWritableFileTest {
|
||||
Assert.assertFalse(delegatingWritableFile.isOpen());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMoveTo() {
|
||||
WritableFile mockWritableFile1 = Mockito.mock(WritableFile.class);
|
||||
WritableFile mockWritableFile2 = Mockito.mock(WritableFile.class);
|
||||
@SuppressWarnings("resource")
|
||||
DelegatingWritableFile delegatingWritableFile1 = new DelegatingWritableFile(mockWritableFile1);
|
||||
DelegatingWritableFile delegatingWritableFile2 = new DelegatingWritableFile(mockWritableFile2);
|
||||
|
||||
delegatingWritableFile1.moveTo(delegatingWritableFile2);
|
||||
Mockito.verify(mockWritableFile1).moveTo(mockWritableFile2);
|
||||
}
|
||||
|
||||
@Test(expected = IllegalArgumentException.class)
|
||||
public void testMoveToDestinationFromDifferentLayer() {
|
||||
WritableFile mockWritableFile1 = Mockito.mock(WritableFile.class);
|
||||
WritableFile mockWritableFile2 = Mockito.mock(WritableFile.class);
|
||||
@SuppressWarnings("resource")
|
||||
DelegatingWritableFile delegatingWritableFile1 = new DelegatingWritableFile(mockWritableFile1);
|
||||
|
||||
delegatingWritableFile1.moveTo(mockWritableFile2);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSetLastModified() {
|
||||
WritableFile mockWritableFile = Mockito.mock(WritableFile.class);
|
||||
@SuppressWarnings("resource")
|
||||
DelegatingWritableFile delegatingWritableFile = new DelegatingWritableFile(mockWritableFile);
|
||||
|
||||
Instant now = Instant.now();
|
||||
delegatingWritableFile.setLastModified(now);
|
||||
Mockito.verify(mockWritableFile).setLastModified(now);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDelete() {
|
||||
WritableFile mockWritableFile = Mockito.mock(WritableFile.class);
|
||||
@SuppressWarnings("resource")
|
||||
DelegatingWritableFile delegatingWritableFile = new DelegatingWritableFile(mockWritableFile);
|
||||
|
||||
delegatingWritableFile.delete();
|
||||
Mockito.verify(mockWritableFile).delete();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testTruncate() {
|
||||
WritableFile mockWritableFile = Mockito.mock(WritableFile.class);
|
||||
@@ -115,16 +71,4 @@ public class DelegatingWritableFileTest {
|
||||
Mockito.verify(mockWritableFile).close();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSetCreationTime() {
|
||||
WritableFile mockWritableFile = Mockito.mock(WritableFile.class);
|
||||
@SuppressWarnings("resource")
|
||||
DelegatingWritableFile delegatingWritableFile = new DelegatingWritableFile(mockWritableFile);
|
||||
|
||||
Instant now = Instant.now();
|
||||
|
||||
delegatingWritableFile.setCreationTime(now);
|
||||
Mockito.verify(mockWritableFile).setCreationTime(now);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -10,7 +10,6 @@ package org.cryptomator.filesystem.blockaligned;
|
||||
|
||||
import java.io.UncheckedIOException;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.time.Instant;
|
||||
import java.util.Optional;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
@@ -128,31 +127,6 @@ class BlockAlignedWritableFile implements WritableFile {
|
||||
return delegate.get().isOpen();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void moveTo(WritableFile destination) throws UncheckedIOException {
|
||||
if (destination instanceof BlockAlignedWritableFile) {
|
||||
final WritableFile delegateDest = ((BlockAlignedWritableFile) destination).delegate.get();
|
||||
delegate.get().moveTo(delegateDest);
|
||||
} else {
|
||||
throw new IllegalArgumentException("Can only move DelegatingWritableFile to a DelegatingWritableFile.");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setLastModified(Instant instant) throws UncheckedIOException {
|
||||
delegate.get().setLastModified(instant);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setCreationTime(Instant instant) throws UncheckedIOException {
|
||||
delegate.get().setCreationTime(instant);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void delete() throws UncheckedIOException {
|
||||
delegate.get().delete();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void truncate() throws UncheckedIOException {
|
||||
delegate.get().truncate();
|
||||
|
||||
@@ -60,4 +60,19 @@ public class CryptoFile extends CryptoNode implements File {
|
||||
return toString().compareTo(o.toString());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void delete() throws UncheckedIOException {
|
||||
forceGetPhysicalFile().delete();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void moveTo(File destination) throws UncheckedIOException {
|
||||
if (destination instanceof CryptoFile) {
|
||||
CryptoFile dst = (CryptoFile) destination;
|
||||
forceGetPhysicalFile().moveTo(dst.forceGetPhysicalFile());
|
||||
} else {
|
||||
throw new IllegalArgumentException("Can not move CryptoFile to conventional File.");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -75,14 +75,19 @@ abstract class CryptoNode implements Node {
|
||||
return forceGetPhysicalFile().lastModified();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setLastModified(Instant lastModified) throws UncheckedIOException {
|
||||
forceGetPhysicalFile().setLastModified(lastModified);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<Instant> creationTime() throws UncheckedIOException {
|
||||
return forceGetPhysicalFile().creationTime();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setCreationTime(Instant instant) throws UncheckedIOException {
|
||||
forceGetPhysicalFile().setCreationTime(instant);
|
||||
public void setCreationTime(Instant creationTime) throws UncheckedIOException {
|
||||
forceGetPhysicalFile().setCreationTime(creationTime);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -12,7 +12,6 @@ import java.io.IOException;
|
||||
import java.io.InterruptedIOException;
|
||||
import java.io.UncheckedIOException;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.time.Instant;
|
||||
import java.util.Optional;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
@@ -73,32 +72,6 @@ class CryptoWritableFile implements WritableFile {
|
||||
throw new UnsupportedOperationException("Partial write not implemented yet.");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void moveTo(WritableFile other) {
|
||||
if (other instanceof CryptoWritableFile) {
|
||||
CryptoWritableFile dst = (CryptoWritableFile) other;
|
||||
file.moveTo(dst.file);
|
||||
} else {
|
||||
throw new IllegalArgumentException("Can not move CryptoFile to conventional File.");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setLastModified(Instant instant) {
|
||||
file.setLastModified(instant);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setCreationTime(Instant instant) throws UncheckedIOException {
|
||||
file.setCreationTime(instant);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void delete() {
|
||||
writeTask.cancel(true);
|
||||
file.delete();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void truncate() {
|
||||
contentChanged = true;
|
||||
|
||||
@@ -37,6 +37,22 @@ class InMemoryFile extends InMemoryNode implements File {
|
||||
content.flip();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void moveTo(File destination) throws UncheckedIOException {
|
||||
if (destination instanceof InMemoryFile) {
|
||||
internalMoveTo((InMemoryFile) destination);
|
||||
} else {
|
||||
throw new IllegalArgumentException("Can only move an InMemoryFile to another InMemoryFile");
|
||||
}
|
||||
}
|
||||
|
||||
private void internalMoveTo(InMemoryFile destination) {
|
||||
this.content.rewind();
|
||||
destination.create();
|
||||
destination.content = this.content;
|
||||
this.delete();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ReadableFile openReadable() {
|
||||
if (!exists()) {
|
||||
@@ -62,21 +78,8 @@ class InMemoryFile extends InMemoryNode implements File {
|
||||
final WriteLock writeLock = lock.writeLock();
|
||||
writeLock.lock();
|
||||
try {
|
||||
final InMemoryFolder parent = parent().get();
|
||||
parent.existingChildren.compute(this.name(), (k, v) -> {
|
||||
if (v != null && v != this) {
|
||||
// other file or folder with same name already exists.
|
||||
throw new UncheckedIOException(new FileAlreadyExistsException(k));
|
||||
} else {
|
||||
if (v == null) {
|
||||
assert!content.hasRemaining();
|
||||
this.creationTime = Instant.now();
|
||||
}
|
||||
this.lastModified = Instant.now();
|
||||
return this;
|
||||
}
|
||||
});
|
||||
final WritableFile result = new InMemoryWritableFile(this::setLastModified, this::setCreationTime, this::getContent, this::setContent, this::delete, writeLock);
|
||||
create();
|
||||
final WritableFile result = new InMemoryWritableFile(this::getContent, this::setContent, writeLock);
|
||||
success = true;
|
||||
return result;
|
||||
} finally {
|
||||
@@ -86,8 +89,21 @@ class InMemoryFile extends InMemoryNode implements File {
|
||||
}
|
||||
}
|
||||
|
||||
private void setLastModified(Instant lastModified) {
|
||||
this.lastModified = lastModified;
|
||||
private void create() {
|
||||
final InMemoryFolder parent = parent().get();
|
||||
parent.existingChildren.compute(this.name(), (k, v) -> {
|
||||
if (v != null && v != this) {
|
||||
// other file or folder with same name already exists.
|
||||
throw new UncheckedIOException(new FileAlreadyExistsException(k));
|
||||
} else {
|
||||
if (v == null) {
|
||||
assert!content.hasRemaining();
|
||||
this.creationTime = Instant.now();
|
||||
}
|
||||
this.lastModified = Instant.now();
|
||||
return this;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private ByteBuffer getContent() {
|
||||
|
||||
@@ -16,7 +16,7 @@ import java.util.Optional;
|
||||
|
||||
import org.cryptomator.filesystem.Node;
|
||||
|
||||
class InMemoryNode implements Node {
|
||||
abstract class InMemoryNode implements Node {
|
||||
|
||||
protected final InMemoryFolder parent;
|
||||
protected final String name;
|
||||
@@ -53,6 +53,25 @@ class InMemoryNode implements Node {
|
||||
return lastModified;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setLastModified(Instant lastModified) throws UncheckedIOException {
|
||||
this.lastModified = lastModified;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<Instant> creationTime() throws UncheckedIOException {
|
||||
if (exists()) {
|
||||
return Optional.of(creationTime);
|
||||
} else {
|
||||
throw new UncheckedIOException(new IOException("Node does not exist"));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setCreationTime(Instant creationTime) throws UncheckedIOException {
|
||||
this.creationTime = creationTime;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
final int prime = 31;
|
||||
@@ -74,18 +93,4 @@ class InMemoryNode implements Node {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<Instant> creationTime() throws UncheckedIOException {
|
||||
if (exists()) {
|
||||
return Optional.of(creationTime);
|
||||
} else {
|
||||
throw new UncheckedIOException(new IOException("Node does not exist"));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setCreationTime(Instant creationTime) throws UncheckedIOException {
|
||||
this.creationTime = creationTime;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -10,7 +10,6 @@ package org.cryptomator.filesystem.inmem;
|
||||
|
||||
import java.io.UncheckedIOException;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.time.Instant;
|
||||
import java.util.concurrent.locks.ReentrantReadWriteLock.WriteLock;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.function.Supplier;
|
||||
@@ -20,23 +19,17 @@ import org.cryptomator.io.ByteBuffers;
|
||||
|
||||
public class InMemoryWritableFile implements WritableFile {
|
||||
|
||||
private final Consumer<Instant> lastModifiedSetter;
|
||||
private final Consumer<Instant> creationTimeSetter;
|
||||
private final Supplier<ByteBuffer> contentGetter;
|
||||
private final Consumer<ByteBuffer> contentSetter;
|
||||
private final Runnable deleter;
|
||||
private final WriteLock writeLock;
|
||||
|
||||
private boolean open = true;
|
||||
private volatile int position = 0;
|
||||
|
||||
public InMemoryWritableFile(Consumer<Instant> lastModifiedSetter, Consumer<Instant> creationTimeSetter, Supplier<ByteBuffer> contentGetter, Consumer<ByteBuffer> contentSetter, Runnable deleter, WriteLock writeLock) {
|
||||
this.lastModifiedSetter = lastModifiedSetter;
|
||||
public InMemoryWritableFile(Supplier<ByteBuffer> contentGetter, Consumer<ByteBuffer> contentSetter, WriteLock writeLock) {
|
||||
this.contentGetter = contentGetter;
|
||||
this.contentSetter = contentSetter;
|
||||
this.deleter = deleter;
|
||||
this.writeLock = writeLock;
|
||||
this.creationTimeSetter = creationTimeSetter;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -44,37 +37,6 @@ public class InMemoryWritableFile implements WritableFile {
|
||||
return open;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void moveTo(WritableFile other) throws UncheckedIOException {
|
||||
if (other instanceof InMemoryWritableFile) {
|
||||
internalMoveTo((InMemoryWritableFile) other);
|
||||
} else {
|
||||
throw new IllegalArgumentException("Can only move an InMemoryWritableFile to another InMemoryWritableFile");
|
||||
}
|
||||
}
|
||||
|
||||
private void internalMoveTo(InMemoryWritableFile destination) {
|
||||
try {
|
||||
destination.contentSetter.accept(this.contentGetter.get());
|
||||
destination.contentGetter.get().rewind();
|
||||
deleter.run();
|
||||
} finally {
|
||||
open = false;
|
||||
destination.open = false;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setLastModified(Instant instant) throws UncheckedIOException {
|
||||
lastModifiedSetter.accept(instant);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void delete() throws UncheckedIOException {
|
||||
deleter.run();
|
||||
open = false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void truncate() throws UncheckedIOException {
|
||||
contentSetter.accept(ByteBuffer.allocate(0));
|
||||
@@ -111,12 +73,6 @@ public class InMemoryWritableFile implements WritableFile {
|
||||
public void close() throws UncheckedIOException {
|
||||
open = false;
|
||||
writeLock.unlock();
|
||||
lastModifiedSetter.accept(Instant.now());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setCreationTime(Instant instant) throws UncheckedIOException {
|
||||
creationTimeSetter.accept(instant);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -116,11 +116,7 @@ public class InMemoryFileSystemTest {
|
||||
|
||||
// move bar to baz
|
||||
File bazFile = fs.file("baz.txt");
|
||||
try (WritableFile src = barFile.openWritable()) {
|
||||
try (WritableFile dst = bazFile.openWritable()) {
|
||||
src.moveTo(dst);
|
||||
}
|
||||
}
|
||||
barFile.moveTo(bazFile);
|
||||
Assert.assertFalse(barFile.exists());
|
||||
Assert.assertTrue(bazFile.exists());
|
||||
|
||||
|
||||
@@ -12,6 +12,7 @@ import static org.hamcrest.CoreMatchers.is;
|
||||
import static org.junit.Assert.assertThat;
|
||||
|
||||
import java.io.UncheckedIOException;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.time.Instant;
|
||||
|
||||
import org.cryptomator.filesystem.WritableFile;
|
||||
@@ -27,38 +28,39 @@ public class InMemoryFileTest {
|
||||
@Test
|
||||
public void testCreationTimeOfNonExistingFileThrowsUncheckedIOException() {
|
||||
InMemoryFileSystem fileSystem = new InMemoryFileSystem();
|
||||
InMemoryFile inTest = fileSystem.file("foo");
|
||||
InMemoryFile file = fileSystem.file("foo");
|
||||
|
||||
thrown.expect(UncheckedIOException.class);
|
||||
|
||||
inTest.creationTime();
|
||||
file.creationTime();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCreationTimeOfCreatedFileIsSetToInstantDuringCreation() {
|
||||
InMemoryFileSystem fileSystem = new InMemoryFileSystem();
|
||||
InMemoryFile inTest = fileSystem.file("foo");
|
||||
InMemoryFile file = fileSystem.file("foo");
|
||||
|
||||
Instant minCreationTime = Instant.now();
|
||||
Instant maxCreationTime;
|
||||
try (WritableFile writable = inTest.openWritable()) {
|
||||
try (WritableFile writable = file.openWritable()) {
|
||||
maxCreationTime = Instant.now();
|
||||
}
|
||||
|
||||
assertThat(inTest.creationTime().get().isBefore(minCreationTime), is(false));
|
||||
assertThat(inTest.creationTime().get().isAfter(maxCreationTime), is(false));
|
||||
assertThat(file.creationTime().get().isBefore(minCreationTime), is(false));
|
||||
assertThat(file.creationTime().get().isAfter(maxCreationTime), is(false));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCreationTimeSetInWritableFileIsSaved() {
|
||||
public void testCreationTimeSetIsSaved() {
|
||||
Instant creationTime = Instant.parse("2015-03-23T21:11:32Z");
|
||||
InMemoryFileSystem fileSystem = new InMemoryFileSystem();
|
||||
InMemoryFile inTest = fileSystem.file("foo");
|
||||
try (WritableFile writable = inTest.openWritable()) {
|
||||
writable.setCreationTime(creationTime);
|
||||
InMemoryFile file = fileSystem.file("foo");
|
||||
try (WritableFile writable = file.openWritable()) {
|
||||
writable.write(ByteBuffer.allocate(0));
|
||||
}
|
||||
|
||||
assertThat(inTest.creationTime().get(), is(creationTime));
|
||||
file.setCreationTime(creationTime);
|
||||
assertThat(file.creationTime().get(), is(creationTime));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -75,10 +75,7 @@ public class ShorteningFileSystemTest {
|
||||
Assert.assertFalse(metadataRoot.children().findAny().isPresent());
|
||||
|
||||
final File longNamedFolder = fs.file("morethantenchars");
|
||||
try (WritableFile src = shortNamedFolder.openWritable(); //
|
||||
WritableFile dst = longNamedFolder.openWritable()) {
|
||||
src.moveTo(dst);
|
||||
}
|
||||
shortNamedFolder.moveTo(longNamedFolder);
|
||||
Assert.assertTrue(metadataRoot.children().findAny().isPresent());
|
||||
}
|
||||
|
||||
|
||||
@@ -23,8 +23,8 @@ class DefaultInstanceFactory implements InstanceFactory {
|
||||
}
|
||||
|
||||
@Override
|
||||
public WritableNioFile writableNioFile(FileSystem fileSystem, Path path, SharedFileChannel channel, Runnable afterCloseCallback, NioAccess nioAccess) {
|
||||
return new WritableNioFile(fileSystem, path, channel, afterCloseCallback, nioAccess);
|
||||
public WritableNioFile writableNioFile(FileSystem fileSystem, Path path, SharedFileChannel channel, Runnable afterCloseCallback) {
|
||||
return new WritableNioFile(fileSystem, path, channel, afterCloseCallback);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -16,7 +16,7 @@ interface InstanceFactory {
|
||||
|
||||
SharedFileChannel sharedFileChannel(Path path, NioAccess nioAccess);
|
||||
|
||||
WritableNioFile writableNioFile(FileSystem fileSystem, Path path, SharedFileChannel channel, Runnable afterCloseCallback, NioAccess nioAccess);
|
||||
WritableNioFile writableNioFile(FileSystem fileSystem, Path path, SharedFileChannel channel, Runnable afterCloseCallback);
|
||||
|
||||
ReadableNioFile readableNioFile(Path path, SharedFileChannel channel, Runnable afterCloseCallback);
|
||||
|
||||
|
||||
@@ -1,11 +1,15 @@
|
||||
package org.cryptomator.filesystem.nio;
|
||||
|
||||
import static java.lang.String.format;
|
||||
import static java.nio.file.StandardCopyOption.REPLACE_EXISTING;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.UncheckedIOException;
|
||||
import java.nio.file.Path;
|
||||
import java.time.Instant;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.concurrent.locks.ReentrantReadWriteLock;
|
||||
|
||||
@@ -16,7 +20,7 @@ import org.cryptomator.filesystem.WritableFile;
|
||||
class NioFile extends NioNode implements File {
|
||||
|
||||
private final ReentrantReadWriteLock lock = new ReentrantReadWriteLock(true);
|
||||
private SharedFileChannel sharedChannel;
|
||||
private final SharedFileChannel sharedChannel;
|
||||
|
||||
public NioFile(Optional<NioFolder> parent, Path eventuallyNonAbsolutePath, NioAccess nioAccess, InstanceFactory instanceFactory) {
|
||||
super(parent, eventuallyNonAbsolutePath, nioAccess, instanceFactory);
|
||||
@@ -47,11 +51,17 @@ class NioFile extends NioNode implements File {
|
||||
if (lock.getReadHoldCount() > 0) {
|
||||
throw new IllegalStateException("Current thread is currently reading this file");
|
||||
}
|
||||
lock.writeLock().lock();
|
||||
return instanceFactory.writableNioFile(fileSystem(), path, sharedChannel, this::unlockWriteLock, nioAccess);
|
||||
lockWriteLock();
|
||||
return instanceFactory.writableNioFile(fileSystem(), path, sharedChannel, this::unlockWriteLock);
|
||||
}
|
||||
|
||||
private void unlockWriteLock() {
|
||||
// visible for testing
|
||||
void lockWriteLock() {
|
||||
lock.writeLock().lock();
|
||||
}
|
||||
|
||||
// visible for testing
|
||||
void unlockWriteLock() {
|
||||
lock.writeLock().unlock();
|
||||
}
|
||||
|
||||
@@ -68,6 +78,63 @@ class NioFile extends NioNode implements File {
|
||||
return super.lastModified();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<Instant> creationTime() throws UncheckedIOException {
|
||||
if (nioAccess.exists(path) && !exists()) {
|
||||
throw new UncheckedIOException(new IOException(format("%s is a folder", path)));
|
||||
}
|
||||
return super.creationTime();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void moveTo(File destination) throws UncheckedIOException {
|
||||
if (destination == this) {
|
||||
return;
|
||||
} else if (belongsToSameFilesystem(destination)) {
|
||||
internalMoveTo((NioFile) destination);
|
||||
} else {
|
||||
throw new IllegalArgumentException("Can only move to a File from the same FileSystem");
|
||||
}
|
||||
}
|
||||
|
||||
private void assertMovePreconditionsAreMet(NioFile destination) {
|
||||
if (nioAccess.isDirectory(path())) {
|
||||
throw new UncheckedIOException(new IOException(format("Can not move %s to %s. Source is a directory", path(), destination.path())));
|
||||
}
|
||||
if (nioAccess.isDirectory(destination.path())) {
|
||||
throw new UncheckedIOException(new IOException(format("Can not move %s to %s. Target is a directory", path(), destination.path())));
|
||||
}
|
||||
}
|
||||
|
||||
private void internalMoveTo(NioFile destination) {
|
||||
assertMovePreconditionsAreMet(destination);
|
||||
// TODO review deadlock-safety of locking two files. see DeadLockSafeFileOpener
|
||||
List<NioFile> filesToBeLocked = new ArrayList<>();
|
||||
filesToBeLocked.add(this);
|
||||
filesToBeLocked.add(destination);
|
||||
Collections.sort(filesToBeLocked);
|
||||
filesToBeLocked.forEach(file -> file.lockWriteLock());
|
||||
try {
|
||||
nioAccess.move(path(), destination.path(), REPLACE_EXISTING);
|
||||
} catch (IOException e) {
|
||||
throw new UncheckedIOException(e);
|
||||
} finally {
|
||||
filesToBeLocked.forEach(file -> file.unlockWriteLock());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void delete() throws UncheckedIOException {
|
||||
if (!exists()) {
|
||||
return;
|
||||
}
|
||||
try {
|
||||
nioAccess.delete(path());
|
||||
} catch (IOException e) {
|
||||
throw new UncheckedIOException(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int compareTo(File o) {
|
||||
if (belongsToSameFilesystem(o)) {
|
||||
@@ -82,12 +149,4 @@ class NioFile extends NioNode implements File {
|
||||
return format("NioFile(%s)", path);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<Instant> creationTime() throws UncheckedIOException {
|
||||
if (nioAccess.exists(path) && !exists()) {
|
||||
throw new UncheckedIOException(new IOException(format("%s is a folder", path)));
|
||||
}
|
||||
return super.creationTime();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -25,6 +25,11 @@ abstract class NioNode implements Node {
|
||||
this.instanceFactory = instanceFactoy;
|
||||
}
|
||||
|
||||
// visible for testing
|
||||
Path path() {
|
||||
return path;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String name() throws UncheckedIOException {
|
||||
return path.getFileName().toString();
|
||||
@@ -35,6 +40,8 @@ abstract class NioNode implements Node {
|
||||
return parent;
|
||||
}
|
||||
|
||||
private static final Instant JANNUARY_THE_SECOND_NINTEENHUNDRED_SEVENTY = Instant.parse("1970-01-02T00:00:00Z");
|
||||
|
||||
@Override
|
||||
public Instant lastModified() throws UncheckedIOException {
|
||||
try {
|
||||
@@ -44,7 +51,14 @@ abstract class NioNode implements Node {
|
||||
}
|
||||
}
|
||||
|
||||
private static final Instant JANNUARY_THE_SECOND_NINTEENHUNDRED_SEVENTY = Instant.parse("1970-01-02T00:00:00Z");
|
||||
@Override
|
||||
public void setLastModified(Instant lastModified) throws UncheckedIOException {
|
||||
try {
|
||||
nioAccess.setLastModifiedTime(path, FileTime.from(lastModified));
|
||||
} catch (IOException e) {
|
||||
throw new UncheckedIOException(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<Instant> creationTime() throws UncheckedIOException {
|
||||
|
||||
@@ -1,16 +1,12 @@
|
||||
package org.cryptomator.filesystem.nio;
|
||||
|
||||
import static java.lang.String.format;
|
||||
import static java.nio.file.StandardCopyOption.REPLACE_EXISTING;
|
||||
import static org.cryptomator.filesystem.nio.OpenMode.WRITE;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.UncheckedIOException;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.channels.ClosedChannelException;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.attribute.FileTime;
|
||||
import java.time.Instant;
|
||||
|
||||
import org.cryptomator.filesystem.FileSystem;
|
||||
import org.cryptomator.filesystem.WritableFile;
|
||||
@@ -20,19 +16,17 @@ class WritableNioFile implements WritableFile {
|
||||
private final FileSystem fileSystem;
|
||||
private final Path path;
|
||||
private final SharedFileChannel channel;
|
||||
private final NioAccess nioAccess;
|
||||
private Runnable afterCloseCallback;
|
||||
private final Runnable afterCloseCallback;
|
||||
|
||||
private boolean open = true;
|
||||
private boolean channelOpened = false;
|
||||
private long position = 0;
|
||||
|
||||
public WritableNioFile(FileSystem fileSystem, Path path, SharedFileChannel channel, Runnable afterCloseCallback, NioAccess nioAccess) {
|
||||
public WritableNioFile(FileSystem fileSystem, Path path, SharedFileChannel channel, Runnable afterCloseCallback) {
|
||||
this.fileSystem = fileSystem;
|
||||
this.path = path;
|
||||
this.channel = channel;
|
||||
this.afterCloseCallback = afterCloseCallback;
|
||||
this.nioAccess = nioAccess;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -55,73 +49,6 @@ class WritableNioFile implements WritableFile {
|
||||
this.position = position;
|
||||
}
|
||||
|
||||
private boolean belongsToSameFilesystem(WritableFile other) {
|
||||
return other instanceof WritableNioFile && ((WritableNioFile) other).fileSystem() == fileSystem;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void moveTo(WritableFile other) throws UncheckedIOException {
|
||||
assertOpen();
|
||||
if (other == this) {
|
||||
return;
|
||||
} else if (belongsToSameFilesystem(other)) {
|
||||
internalMoveTo((WritableNioFile) other);
|
||||
} else {
|
||||
throw new IllegalArgumentException("Can only move to a WritableFile from the same FileSystem");
|
||||
}
|
||||
}
|
||||
|
||||
private void internalMoveTo(WritableNioFile other) {
|
||||
other.assertOpen();
|
||||
assertMovePreconditionsAreMet(other);
|
||||
try {
|
||||
closeChannelIfOpened();
|
||||
other.closeChannelIfOpened();
|
||||
nioAccess.move(path, other.path(), REPLACE_EXISTING);
|
||||
} catch (IOException e) {
|
||||
throw new UncheckedIOException(e);
|
||||
} finally {
|
||||
open = false;
|
||||
other.open = false;
|
||||
other.invokeAfterCloseCallback();
|
||||
invokeAfterCloseCallback();
|
||||
}
|
||||
}
|
||||
|
||||
private void assertMovePreconditionsAreMet(WritableNioFile other) {
|
||||
if (nioAccess.isDirectory(path)) {
|
||||
throw new UncheckedIOException(new IOException(format("Can not move %s to %s. Source is a directory", path, other.path())));
|
||||
}
|
||||
if (nioAccess.isDirectory(other.path())) {
|
||||
throw new UncheckedIOException(new IOException(format("Can not move %s to %s. Target is a directory", path, other.path())));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setLastModified(Instant instant) throws UncheckedIOException {
|
||||
assertOpen();
|
||||
ensureChannelIsOpened();
|
||||
try {
|
||||
nioAccess.setLastModifiedTime(path, FileTime.from(instant));
|
||||
} catch (IOException e) {
|
||||
throw new UncheckedIOException(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void delete() throws UncheckedIOException {
|
||||
assertOpen();
|
||||
try {
|
||||
closeChannelIfOpened();
|
||||
nioAccess.delete(path);
|
||||
} catch (IOException e) {
|
||||
throw new UncheckedIOException(e);
|
||||
} finally {
|
||||
open = false;
|
||||
invokeAfterCloseCallback();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void truncate() throws UncheckedIOException {
|
||||
assertOpen();
|
||||
@@ -129,17 +56,6 @@ class WritableNioFile implements WritableFile {
|
||||
channel.truncate(0);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setCreationTime(Instant instant) throws UncheckedIOException {
|
||||
assertOpen();
|
||||
ensureChannelIsOpened();
|
||||
try {
|
||||
nioAccess.setCreationTime(path, FileTime.from(instant));
|
||||
} catch (IOException e) {
|
||||
throw new UncheckedIOException(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() throws UncheckedIOException {
|
||||
if (!open) {
|
||||
|
||||
@@ -23,7 +23,7 @@ public class DefaultInstanceFactoryTest {
|
||||
private NioAccess nioAccess;
|
||||
private SharedFileChannel channel;
|
||||
|
||||
private DefaultInstanceFactory inTest = new DefaultInstanceFactory();
|
||||
private final DefaultInstanceFactory inTest = new DefaultInstanceFactory();
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
@@ -67,14 +67,13 @@ public class DefaultInstanceFactoryTest {
|
||||
@Test
|
||||
public void testWritableNioFileCreatesWritableNioFile() throws IOException {
|
||||
Runnable afterCloseCallback = mock(Runnable.class);
|
||||
WritableNioFile result = inTest.writableNioFile(fileSystem, path, channel, afterCloseCallback, nioAccess);
|
||||
WritableNioFile result = inTest.writableNioFile(fileSystem, path, channel, afterCloseCallback);
|
||||
|
||||
assertThat(result.path(), is(path));
|
||||
assertThat(result.channel(), is(channel));
|
||||
assertThat(result.fileSystem(), is(fileSystem));
|
||||
|
||||
result.delete();
|
||||
verify(nioAccess).delete(path);
|
||||
result.close();
|
||||
verify(afterCloseCallback).run();
|
||||
}
|
||||
|
||||
|
||||
@@ -1,13 +1,17 @@
|
||||
package org.cryptomator.filesystem.nio;
|
||||
|
||||
import static java.lang.String.format;
|
||||
import static java.nio.file.StandardCopyOption.REPLACE_EXISTING;
|
||||
import static org.cryptomator.common.test.matcher.OptionalMatcher.emptyOptional;
|
||||
import static org.hamcrest.CoreMatchers.is;
|
||||
import static org.junit.Assert.assertThat;
|
||||
import static org.mockito.Matchers.any;
|
||||
import static org.mockito.Matchers.same;
|
||||
import static org.mockito.Mockito.doThrow;
|
||||
import static org.mockito.Mockito.inOrder;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.verifyZeroInteractions;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import java.io.IOException;
|
||||
@@ -27,6 +31,7 @@ import org.junit.Test;
|
||||
import org.junit.rules.ExpectedException;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.ArgumentCaptor;
|
||||
import org.mockito.InOrder;
|
||||
|
||||
import de.bechte.junit.runners.context.HierarchicalContextRunner;
|
||||
|
||||
@@ -128,7 +133,7 @@ public class NioFileTest {
|
||||
@Test
|
||||
public void testOpenReadableInvokedAfterInvokingAfterCloseOperationWorks() {
|
||||
ArgumentCaptor<Runnable> captor = ArgumentCaptor.forClass(Runnable.class);
|
||||
when(instanceFactory.writableNioFile(same(fileSystem), same(path), same(channel), captor.capture(), same(nioAccess))).thenReturn(null);
|
||||
when(instanceFactory.writableNioFile(same(fileSystem), same(path), same(channel), captor.capture())).thenReturn(null);
|
||||
inTest.openWritable();
|
||||
captor.getValue().run();
|
||||
|
||||
@@ -138,7 +143,7 @@ public class NioFileTest {
|
||||
@Test
|
||||
public void testOpenWritableCreatesWritableNioFileFromNioFileAndNioAccessUsingInstanceFactory() {
|
||||
WritableNioFile writableNioFile = mock(WritableNioFile.class);
|
||||
when(instanceFactory.writableNioFile(same(fileSystem), same(path), same(channel), any(), same(nioAccess))).thenReturn(writableNioFile);
|
||||
when(instanceFactory.writableNioFile(same(fileSystem), same(path), same(channel), any())).thenReturn(writableNioFile);
|
||||
|
||||
WritableFile writableFile = inTest.openWritable();
|
||||
|
||||
@@ -149,7 +154,7 @@ public class NioFileTest {
|
||||
public void testOpenWritableInvokedAfterAfterCloseOperationCreatesNewWritableFile() {
|
||||
WritableNioFile writableNioFile = mock(WritableNioFile.class);
|
||||
ArgumentCaptor<Runnable> captor = ArgumentCaptor.forClass(Runnable.class);
|
||||
when(instanceFactory.writableNioFile(same(fileSystem), same(path), same(channel), captor.capture(), same(nioAccess))).thenReturn(null, writableNioFile);
|
||||
when(instanceFactory.writableNioFile(same(fileSystem), same(path), same(channel), captor.capture())).thenReturn(null, writableNioFile);
|
||||
inTest.openWritable();
|
||||
captor.getValue().run();
|
||||
|
||||
@@ -190,6 +195,74 @@ public class NioFileTest {
|
||||
|
||||
}
|
||||
|
||||
public class MoveTo {
|
||||
|
||||
private NioFile target;
|
||||
|
||||
private Path pathOfTarget;
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
target = mock(NioFile.class);
|
||||
pathOfTarget = mock(Path.class);
|
||||
when(target.fileSystem()).thenReturn(fileSystem);
|
||||
when(target.path()).thenReturn(pathOfTarget);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMoveToFailsIfTargetIsNoWritableNioFile() {
|
||||
thrown.expect(IllegalArgumentException.class);
|
||||
thrown.expectMessage("Can only move to a File from the same FileSystem");
|
||||
|
||||
inTest.moveTo(mock(File.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMoveToFailsIfTargetIsNotFromSameFileSystem() {
|
||||
NioFile targetFromOtherFileSystem = mock(NioFile.class);
|
||||
when(targetFromOtherFileSystem.fileSystem()).thenReturn(mock(FileSystem.class));
|
||||
|
||||
thrown.expect(IllegalArgumentException.class);
|
||||
thrown.expectMessage("Can only move to a File from the same FileSystem");
|
||||
|
||||
inTest.moveTo(targetFromOtherFileSystem);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMoveToFailsIfTargetIsDirectory() {
|
||||
when(nioAccess.isDirectory(path)).thenReturn(false);
|
||||
when(nioAccess.isDirectory(pathOfTarget)).thenReturn(true);
|
||||
|
||||
thrown.expect(UncheckedIOException.class);
|
||||
thrown.expectMessage("Target is a directory");
|
||||
thrown.expectMessage(path.toString());
|
||||
thrown.expectMessage(pathOfTarget.toString());
|
||||
|
||||
inTest.moveTo(target);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMoveToDoesNothingIfTargetIsSameInstance() {
|
||||
inTest.moveTo(inTest);
|
||||
|
||||
verifyZeroInteractions(nioAccess);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMoveToWrapsIOExceptionFromMoveInUncheckedIOException() throws IOException {
|
||||
when(nioAccess.isDirectory(path)).thenReturn(false);
|
||||
when(nioAccess.isDirectory(pathOfTarget)).thenReturn(false);
|
||||
IOException exceptionFromMove = new IOException();
|
||||
doThrow(exceptionFromMove).when(nioAccess).move(path, pathOfTarget, REPLACE_EXISTING);
|
||||
|
||||
thrown.expect(UncheckedIOException.class);
|
||||
thrown.expectCause(is(exceptionFromMove));
|
||||
|
||||
inTest.moveTo(target);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public class Exists {
|
||||
|
||||
@Test
|
||||
@@ -259,39 +332,30 @@ public class NioFileTest {
|
||||
|
||||
}
|
||||
|
||||
public class CompareTo {
|
||||
public class SetLastModified {
|
||||
|
||||
private Path otherPath;
|
||||
private NioFile otherInTest;
|
||||
@Test
|
||||
public void testSetLastModifiedOpensChannelIfClosedAndSetsLastModifiedTime() throws IOException {
|
||||
Instant instant = Instant.parse("2016-01-05T13:51:00Z");
|
||||
FileTime time = FileTime.from(instant);
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
otherPath = mock(Path.class);
|
||||
inTest.setLastModified(instant);
|
||||
|
||||
Path maybeNonAbsolutePath = mock(Path.class);
|
||||
when(maybeNonAbsolutePath.toAbsolutePath()).thenReturn(otherPath);
|
||||
|
||||
otherInTest = new NioFile(parent, maybeNonAbsolutePath, nioAccess, instanceFactory);
|
||||
InOrder inOrder = inOrder(channel, nioAccess);
|
||||
inOrder.verify(nioAccess).setLastModifiedTime(path, time);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCompareToFileFromOtherFileSystemThrowsIllegalArgumentException() {
|
||||
File other = mock(File.class);
|
||||
when(other.fileSystem()).thenReturn(mock(FileSystem.class));
|
||||
public void testSetLastModifiedWrapsIOExceptionFromSetLastModifiedInUncheckedIOException() throws IOException {
|
||||
IOException exceptionFromSetLastModified = new IOException();
|
||||
Instant instant = Instant.parse("2016-01-05T13:51:00Z");
|
||||
FileTime time = FileTime.from(instant);
|
||||
doThrow(exceptionFromSetLastModified).when(nioAccess).setLastModifiedTime(path, time);
|
||||
|
||||
thrown.expect(IllegalArgumentException.class);
|
||||
thrown.expect(UncheckedIOException.class);
|
||||
thrown.expectCause(is(exceptionFromSetLastModified));
|
||||
|
||||
inTest.compareTo(other);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCompareToReturnsResultOfPathsCompareTo() {
|
||||
int expectedResult = 2873;
|
||||
when(path.compareTo(otherPath)).thenReturn(expectedResult);
|
||||
|
||||
int result = inTest.compareTo(otherInTest);
|
||||
|
||||
assertThat(result, is(expectedResult));
|
||||
inTest.setLastModified(instant);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -345,6 +409,69 @@ public class NioFileTest {
|
||||
|
||||
}
|
||||
|
||||
public class SetCreationTime {
|
||||
|
||||
@Test
|
||||
public void testSetCreationTimeOpensChannelIfClosedAndInvokesNioAccessSetCreationTimeAfterwards() throws IOException {
|
||||
Instant instant = Instant.parse("2016-01-08T22:32:00Z");
|
||||
|
||||
inTest.setCreationTime(instant);
|
||||
|
||||
InOrder inOrder = inOrder(nioAccess, channel);
|
||||
inOrder.verify(nioAccess).setCreationTime(path, FileTime.from(instant));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSetCreationTimeWrapsIOExceptionFromSetCreationTimeInUncheckedIOException() throws IOException {
|
||||
IOException exceptionFromSetCreationTime = new IOException();
|
||||
Instant irrelevant = Instant.now();
|
||||
doThrow(exceptionFromSetCreationTime).when(nioAccess).setCreationTime(same(path), any());
|
||||
|
||||
thrown.expect(UncheckedIOException.class);
|
||||
thrown.expectCause(is(exceptionFromSetCreationTime));
|
||||
|
||||
inTest.setCreationTime(irrelevant);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public class CompareTo {
|
||||
|
||||
private Path otherPath;
|
||||
private NioFile otherInTest;
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
otherPath = mock(Path.class);
|
||||
|
||||
Path maybeNonAbsolutePath = mock(Path.class);
|
||||
when(maybeNonAbsolutePath.toAbsolutePath()).thenReturn(otherPath);
|
||||
|
||||
otherInTest = new NioFile(parent, maybeNonAbsolutePath, nioAccess, instanceFactory);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCompareToFileFromOtherFileSystemThrowsIllegalArgumentException() {
|
||||
File other = mock(File.class);
|
||||
when(other.fileSystem()).thenReturn(mock(FileSystem.class));
|
||||
|
||||
thrown.expect(IllegalArgumentException.class);
|
||||
|
||||
inTest.compareTo(other);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCompareToReturnsResultOfPathsCompareTo() {
|
||||
int expectedResult = 2873;
|
||||
when(path.compareTo(otherPath)).thenReturn(expectedResult);
|
||||
|
||||
int result = inTest.compareTo(otherInTest);
|
||||
|
||||
assertThat(result, is(expectedResult));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNameReturnsFileNameOfPath() {
|
||||
Path fileName = mock(Path.class);
|
||||
|
||||
@@ -1,13 +1,10 @@
|
||||
package org.cryptomator.filesystem.nio;
|
||||
|
||||
import static java.lang.String.format;
|
||||
import static java.nio.file.StandardCopyOption.REPLACE_EXISTING;
|
||||
import static org.cryptomator.filesystem.nio.OpenMode.WRITE;
|
||||
import static org.hamcrest.CoreMatchers.is;
|
||||
import static org.junit.Assert.assertThat;
|
||||
import static org.mockito.Matchers.any;
|
||||
import static org.mockito.Matchers.anyInt;
|
||||
import static org.mockito.Matchers.same;
|
||||
import static org.mockito.Mockito.doThrow;
|
||||
import static org.mockito.Mockito.inOrder;
|
||||
import static org.mockito.Mockito.mock;
|
||||
@@ -15,15 +12,11 @@ import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.verifyZeroInteractions;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.UncheckedIOException;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.attribute.FileTime;
|
||||
import java.time.Instant;
|
||||
|
||||
import org.cryptomator.filesystem.FileSystem;
|
||||
import org.cryptomator.filesystem.WritableFile;
|
||||
import org.junit.Before;
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
@@ -47,8 +40,6 @@ public class WritableNioFileTest {
|
||||
|
||||
private Runnable afterCloseCallback;
|
||||
|
||||
private NioAccess nioAccess;
|
||||
|
||||
private WritableNioFile inTest;
|
||||
|
||||
@Before
|
||||
@@ -57,8 +48,7 @@ public class WritableNioFileTest {
|
||||
channel = mock(SharedFileChannel.class);
|
||||
path = mock(Path.class);
|
||||
afterCloseCallback = mock(Runnable.class);
|
||||
nioAccess = mock(NioAccess.class);
|
||||
inTest = new WritableNioFile(fileSystem, path, channel, afterCloseCallback, nioAccess);
|
||||
inTest = new WritableNioFile(fileSystem, path, channel, afterCloseCallback);
|
||||
}
|
||||
|
||||
public class ConstructorTests {
|
||||
@@ -147,238 +137,6 @@ public class WritableNioFileTest {
|
||||
|
||||
}
|
||||
|
||||
public class MoveToTests {
|
||||
|
||||
private WritableNioFile target;
|
||||
|
||||
private Path pathOfTarget;
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
target = mock(WritableNioFile.class);
|
||||
pathOfTarget = mock(Path.class);
|
||||
when(target.fileSystem()).thenReturn(fileSystem);
|
||||
when(target.path()).thenReturn(pathOfTarget);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMoveToFailsIfTargetIsNoWritableNioFile() {
|
||||
thrown.expect(IllegalArgumentException.class);
|
||||
thrown.expectMessage("Can only move to a WritableFile from the same FileSystem");
|
||||
|
||||
inTest.moveTo(mock(WritableFile.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMoveToFailsIfTargetIsNotFromSameFileSystem() {
|
||||
WritableNioFile targetFromOtherFileSystem = mock(WritableNioFile.class);
|
||||
when(targetFromOtherFileSystem.fileSystem()).thenReturn(mock(FileSystem.class));
|
||||
|
||||
thrown.expect(IllegalArgumentException.class);
|
||||
thrown.expectMessage("Can only move to a WritableFile from the same FileSystem");
|
||||
|
||||
inTest.moveTo(mock(WritableFile.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMoveToFailsIfSourceIsDirectory() {
|
||||
when(nioAccess.isDirectory(path)).thenReturn(true);
|
||||
|
||||
thrown.expect(UncheckedIOException.class);
|
||||
thrown.expectMessage("Source is a directory");
|
||||
thrown.expectMessage(path.toString());
|
||||
thrown.expectMessage(pathOfTarget.toString());
|
||||
|
||||
inTest.moveTo(target);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMoveToFailsIfTargetIsDirectory() {
|
||||
when(nioAccess.isDirectory(path)).thenReturn(false);
|
||||
when(nioAccess.isDirectory(pathOfTarget)).thenReturn(true);
|
||||
|
||||
thrown.expect(UncheckedIOException.class);
|
||||
thrown.expectMessage("Target is a directory");
|
||||
thrown.expectMessage(path.toString());
|
||||
thrown.expectMessage(pathOfTarget.toString());
|
||||
|
||||
inTest.moveTo(target);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMoveToDoesNothingIfTargetIsSameInstance() {
|
||||
inTest.moveTo(inTest);
|
||||
|
||||
verifyZeroInteractions(nioAccess);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMoveToAssertsTargetIsOpenClosesChannelsIfOpenMovesFileAndInvokesAfterCloseCallbacks() throws IOException {
|
||||
when(nioAccess.isDirectory(path)).thenReturn(false);
|
||||
when(nioAccess.isDirectory(pathOfTarget)).thenReturn(false);
|
||||
|
||||
inTest.ensureChannelIsOpened();
|
||||
inTest.moveTo(target);
|
||||
|
||||
InOrder inOrder = inOrder(target, nioAccess, channel, afterCloseCallback);
|
||||
inOrder.verify(target).assertOpen();
|
||||
inOrder.verify(channel).close();
|
||||
inOrder.verify(target).closeChannelIfOpened();
|
||||
inOrder.verify(nioAccess).move(path, pathOfTarget, REPLACE_EXISTING);
|
||||
inOrder.verify(target).invokeAfterCloseCallback();
|
||||
inOrder.verify(afterCloseCallback).run();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMoveToWrapsIOExceptionFromMoveInUncheckedIOException() throws IOException {
|
||||
when(nioAccess.isDirectory(path)).thenReturn(false);
|
||||
when(nioAccess.isDirectory(pathOfTarget)).thenReturn(false);
|
||||
IOException exceptionFromMove = new IOException();
|
||||
doThrow(exceptionFromMove).when(nioAccess).move(path, pathOfTarget, REPLACE_EXISTING);
|
||||
|
||||
thrown.expect(UncheckedIOException.class);
|
||||
thrown.expectCause(is(exceptionFromMove));
|
||||
|
||||
inTest.moveTo(target);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMoveToInvokesAfterCloseCallbacksEvenIfMoveToThrowsException() throws IOException {
|
||||
when(nioAccess.isDirectory(path)).thenReturn(false);
|
||||
when(nioAccess.isDirectory(pathOfTarget)).thenReturn(false);
|
||||
IOException exceptionFromMove = new IOException();
|
||||
doThrow(exceptionFromMove).when(nioAccess).move(path, pathOfTarget, REPLACE_EXISTING);
|
||||
|
||||
thrown.expect(UncheckedIOException.class);
|
||||
thrown.expectCause(is(exceptionFromMove));
|
||||
|
||||
inTest.moveTo(target);
|
||||
|
||||
verify(target).invokeAfterCloseCallback();
|
||||
verify(afterCloseCallback).run();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public class SetLastModifiedTests {
|
||||
|
||||
@Test
|
||||
public void testSetLastModifiedOpensChannelIfClosedAndSetsLastModifiedTime() throws IOException {
|
||||
Instant instant = Instant.parse("2016-01-05T13:51:00Z");
|
||||
FileTime time = FileTime.from(instant);
|
||||
|
||||
inTest.setLastModified(instant);
|
||||
|
||||
InOrder inOrder = inOrder(channel, nioAccess);
|
||||
inOrder.verify(channel).open(OpenMode.WRITE);
|
||||
inOrder.verify(nioAccess).setLastModifiedTime(path, time);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSetLastModifiedWrapsIOExceptionFromSetLastModifiedInUncheckedIOException() throws IOException {
|
||||
IOException exceptionFromSetLastModified = new IOException();
|
||||
Instant instant = Instant.parse("2016-01-05T13:51:00Z");
|
||||
FileTime time = FileTime.from(instant);
|
||||
doThrow(exceptionFromSetLastModified).when(nioAccess).setLastModifiedTime(path, time);
|
||||
|
||||
thrown.expect(UncheckedIOException.class);
|
||||
thrown.expectCause(is(exceptionFromSetLastModified));
|
||||
|
||||
inTest.setLastModified(instant);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public class SetCreationTimeTests {
|
||||
|
||||
@Test
|
||||
public void testSetCreationTimeFailsIfNotOpen() {
|
||||
Instant irrelevant = null;
|
||||
inTest.close();
|
||||
|
||||
thrown.expect(UncheckedIOException.class);
|
||||
thrown.expectMessage("already closed");
|
||||
|
||||
inTest.setCreationTime(irrelevant);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSetCreationTimeOpensChannelIfClosedAndInvokesNioAccessSetCreationTimeAfterwards() throws IOException {
|
||||
Instant instant = Instant.parse("2016-01-08T22:32:00Z");
|
||||
|
||||
inTest.setCreationTime(instant);
|
||||
|
||||
InOrder inOrder = inOrder(nioAccess, channel);
|
||||
inOrder.verify(channel).open(OpenMode.WRITE);
|
||||
inOrder.verify(nioAccess).setCreationTime(path, FileTime.from(instant));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSetCreationTimeWrapsIOExceptionFromSetCreationTimeInUncheckedIOException() throws IOException {
|
||||
IOException exceptionFromSetCreationTime = new IOException();
|
||||
Instant irrelevant = Instant.now();
|
||||
doThrow(exceptionFromSetCreationTime).when(nioAccess).setCreationTime(same(path), any());
|
||||
|
||||
thrown.expect(UncheckedIOException.class);
|
||||
thrown.expectCause(is(exceptionFromSetCreationTime));
|
||||
|
||||
inTest.setCreationTime(irrelevant);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public class DeleteTests {
|
||||
|
||||
@Test
|
||||
public void testDeleteClosesChannelIfOpenAndDeletesFileAndInvokesAfterCloseCallback() throws IOException {
|
||||
inTest.ensureChannelIsOpened();
|
||||
inTest.delete();
|
||||
|
||||
InOrder inOrder = inOrder(channel, nioAccess, afterCloseCallback);
|
||||
inOrder.verify(channel).close();
|
||||
inOrder.verify(nioAccess).delete(path);
|
||||
inOrder.verify(afterCloseCallback).run();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDeleteClosesWritableNioFile() {
|
||||
inTest.delete();
|
||||
|
||||
assertThat(inTest.isOpen(), is(false));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDeleteClosesWritableNioFileEvenIfDeleteFails() throws IOException {
|
||||
IOException exceptionFromDelete = new IOException();
|
||||
doThrow(exceptionFromDelete).when(nioAccess).delete(path);
|
||||
|
||||
thrown.expect(UncheckedIOException.class);
|
||||
thrown.expectCause(is(exceptionFromDelete));
|
||||
|
||||
try {
|
||||
inTest.delete();
|
||||
} finally {
|
||||
assertThat(inTest.isOpen(), is(false));
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDeleteInvokesAfterCloseCallbackEvenIfDeleteFails() throws IOException {
|
||||
IOException exceptionFromDelete = new IOException();
|
||||
doThrow(exceptionFromDelete).when(nioAccess).delete(path);
|
||||
|
||||
thrown.expect(UncheckedIOException.class);
|
||||
thrown.expectCause(is(exceptionFromDelete));
|
||||
|
||||
try {
|
||||
inTest.delete();
|
||||
} finally {
|
||||
verify(afterCloseCallback).run();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public class TruncateTests {
|
||||
|
||||
@Test
|
||||
@@ -491,36 +249,6 @@ public class WritableNioFileTest {
|
||||
inTest.truncate();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMoveToFailsIfClosed() {
|
||||
inTest.close();
|
||||
|
||||
thrown.expect(UncheckedIOException.class);
|
||||
thrown.expectMessage("already closed");
|
||||
|
||||
inTest.moveTo(null);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSetLastModifiedFailsIfClosed() {
|
||||
inTest.close();
|
||||
|
||||
thrown.expect(UncheckedIOException.class);
|
||||
thrown.expectMessage("already closed");
|
||||
|
||||
inTest.setLastModified(null);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDeleteFailsIfClosed() {
|
||||
inTest.close();
|
||||
|
||||
thrown.expect(UncheckedIOException.class);
|
||||
thrown.expectMessage("already closed");
|
||||
|
||||
inTest.delete();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
|
||||
@@ -31,7 +31,6 @@ import org.apache.jackrabbit.webdav.property.DefaultDavProperty;
|
||||
import org.cryptomator.filesystem.File;
|
||||
import org.cryptomator.filesystem.Folder;
|
||||
import org.cryptomator.filesystem.ReadableFile;
|
||||
import org.cryptomator.filesystem.WritableFile;
|
||||
import org.cryptomator.filesystem.jackrabbit.FileLocator;
|
||||
|
||||
import com.google.common.io.ByteStreams;
|
||||
@@ -155,17 +154,13 @@ class DavFile extends DavNode<FileLocator> {
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void setModificationTime(Instant instant) {
|
||||
try (WritableFile writable = node.openWritable()) {
|
||||
writable.setLastModified(instant);
|
||||
}
|
||||
protected void setModificationTime(Instant lastModified) {
|
||||
node.setLastModified(lastModified);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void setCreationTime(Instant instant) {
|
||||
try (WritableFile writable = node.openWritable()) {
|
||||
writable.setCreationTime(instant);
|
||||
}
|
||||
protected void setCreationTime(Instant creationTime) {
|
||||
node.setCreationTime(creationTime);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -29,7 +29,6 @@ import org.apache.jackrabbit.webdav.lock.LockManager;
|
||||
import org.apache.jackrabbit.webdav.property.DavPropertyName;
|
||||
import org.apache.jackrabbit.webdav.property.DefaultDavProperty;
|
||||
import org.apache.jackrabbit.webdav.property.ResourceType;
|
||||
import org.cryptomator.filesystem.File;
|
||||
import org.cryptomator.filesystem.Folder;
|
||||
import org.cryptomator.filesystem.Node;
|
||||
import org.cryptomator.filesystem.WritableFile;
|
||||
@@ -98,17 +97,7 @@ class DavFolder extends DavNode<FolderLocator> {
|
||||
@Override
|
||||
public void removeMember(DavResource member) throws DavException {
|
||||
final Node child = getMemberNode(member.getDisplayName());
|
||||
if (child instanceof Folder) {
|
||||
Folder folder = (Folder) child;
|
||||
folder.delete();
|
||||
} else if (child instanceof File) {
|
||||
File file = (File) child;
|
||||
try (WritableFile writable = file.openWritable()) {
|
||||
writable.delete();
|
||||
}
|
||||
} else {
|
||||
throw new IllegalStateException("Unexpected node type: " + child.getClass().getName());
|
||||
}
|
||||
child.delete();
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
Reference in New Issue
Block a user