Explorar el Código

Refactored filesystem api

* Removed Readable- and WritableBytes
** Replaced with Readable-/WritableByteChannel
** Methods now integrated in Readable- and WritableFile
** Replaced positioned read/write by method to set the position
Markus Kreusch hace 9 años
padre
commit
356ea5c319

+ 1 - 1
main/commons-test/src/main/java/org/cryptomator/commons/test/matcher/ContainsMatcher.java

@@ -1,4 +1,4 @@
-package org.cryptomator.commons.test.matcher;
+package org.cryptomator.common.test.matcher;
 
 import org.hamcrest.Matcher;
 import org.hamcrest.Matchers;

+ 1 - 1
main/commons-test/src/main/java/org/cryptomator/commons/test/matcher/PropertyMatcher.java

@@ -3,7 +3,7 @@
  * This file is licensed under the terms of the MIT license.
  * See the LICENSE.txt file for more info.
  ******************************************************************************/
-package org.cryptomator.commons.test.matcher;
+package org.cryptomator.common.test.matcher;
 
 import java.util.function.Function;
 

+ 1 - 1
main/filesystem-api/src/main/java/org/cryptomator/filesystem/OpenFiles.java

@@ -39,7 +39,7 @@ public class OpenFiles implements AutoCloseable {
 	}
 
 	static void cleanup(Collection<ReadableFile> readableFiles, Collection<WritableFile> writableFiles) {
-		Iterator<AutoCloseable> iterator = Stream.concat(readableFiles.stream(), writableFiles.stream()).iterator();
+		Iterator<? extends AutoCloseable> iterator = Stream.concat(readableFiles.stream(), writableFiles.stream()).iterator();
 		UncheckedIOException firstException = null;
 		while (iterator.hasNext()) {
 			AutoCloseable openFile = iterator.next();

+ 0 - 46
main/filesystem-api/src/main/java/org/cryptomator/filesystem/ReadableBytes.java

@@ -1,46 +0,0 @@
-/*******************************************************************************
- * Copyright (c) 2015 Markus Kreusch
- * This file is licensed under the terms of the MIT license.
- * See the LICENSE.txt file for more info.
- ******************************************************************************/
-package org.cryptomator.filesystem;
-
-import java.io.IOException;
-import java.io.UncheckedIOException;
-import java.nio.ByteBuffer;
-
-public interface ReadableBytes {
-
-	/**
-	 * <p>
-	 * Tries to fill the remaining space in the given byte buffer with data from
-	 * this readable bytes from the current position.
-	 * <p>
-	 * May read less bytes if the end of this readable bytes has been reached.
-	 * 
-	 * @param target
-	 *            the byte buffer to fill
-	 * @throws UncheckedIOException
-	 *             if an {@link IOException} occurs while reading from this
-	 *             {@code ReadableBytes}
-	 */
-	void read(ByteBuffer target) throws UncheckedIOException;
-
-	/**
-	 * <p>
-	 * Tries to fill the remaining space in the given byte buffer with data from
-	 * this readable bytes from the given position.
-	 * <p>
-	 * May read less bytes if the end of this readable bytes has been reached.
-	 * 
-	 * @param target
-	 *            the byte buffer to fill
-	 * @param position
-	 *            the position to read bytes from
-	 * @throws UncheckedIOException
-	 *             if an {@link IOException} occurs while reading from this
-	 *             {@code ReadableBytes}
-	 */
-	void read(ByteBuffer target, long position) throws UncheckedIOException;
-
-}

+ 35 - 1
main/filesystem-api/src/main/java/org/cryptomator/filesystem/ReadableFile.java

@@ -5,12 +5,46 @@
  ******************************************************************************/
 package org.cryptomator.filesystem;
 
+import java.io.IOException;
 import java.io.UncheckedIOException;
+import java.nio.ByteBuffer;
+import java.nio.channels.ReadableByteChannel;
 
-public interface ReadableFile extends ReadableBytes, AutoCloseable {
+public interface ReadableFile extends ReadableByteChannel {
 
 	void copyTo(WritableFile other) throws UncheckedIOException;
 
+	/**
+	 * <p>
+	 * Tries to fill the remaining space in the given byte buffer with data from
+	 * this readable bytes from the current position.
+	 * <p>
+	 * May read less bytes if the end of this readable bytes has been reached.
+	 * 
+	 * @param target
+	 *            the byte buffer to fill
+	 * @return the number of bytes actually read, or {@code -1} if the end of
+	 *         file has been reached
+	 * @throws UncheckedIOException
+	 *             if an {@link IOException} occurs while reading from this
+	 *             {@code ReadableBytes}
+	 */
+	int read(ByteBuffer target) throws UncheckedIOException;
+
+	/**
+	 * <p>
+	 * Fast-forwards or rewinds the file to the specified position.
+	 * <p>
+	 * Consecutive reads on the file will begin at the new position.
+	 * 
+	 * @param position
+	 *            the position to set the file to
+	 * @throws UncheckedIOException
+	 *             if an {@link IOException} occurs
+	 * 
+	 */
+	void position(long position) throws UncheckedIOException;
+
 	@Override
 	void close() throws UncheckedIOException;
 

+ 0 - 38
main/filesystem-api/src/main/java/org/cryptomator/filesystem/WritableBytes.java

@@ -1,38 +0,0 @@
-/*******************************************************************************
- * Copyright (c) 2015 Markus Kreusch
- * This file is licensed under the terms of the MIT license.
- * See the LICENSE.txt file for more info.
- ******************************************************************************/
-package org.cryptomator.filesystem;
-
-import java.io.IOException;
-import java.io.UncheckedIOException;
-import java.nio.ByteBuffer;
-
-public interface WritableBytes {
-
-	/**
-	 * Writes the data in the given byte buffer to this readable bytes at the
-	 * current position.
-	 * 
-	 * @param target
-	 *            the byte buffer to use
-	 * @throws UncheckedIOException
-	 *             if an {@link IOException} occurs while writing
-	 */
-	void write(ByteBuffer source) throws UncheckedIOException;
-
-	/**
-	 * Writes the data in the given byte buffer to this readable bytes at the
-	 * given position, overwriting existing content (not inserting).
-	 * 
-	 * @param target
-	 *            the byte buffer to use
-	 * @param position
-	 *            the position to write the data to
-	 * @throws UncheckedIOException
-	 *             if an {@link IOException} occurs while writing
-	 */
-	void write(ByteBuffer source, int position) throws UncheckedIOException;
-
-}

+ 35 - 1
main/filesystem-api/src/main/java/org/cryptomator/filesystem/WritableFile.java

@@ -5,10 +5,13 @@
  ******************************************************************************/
 package org.cryptomator.filesystem;
 
+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 WritableBytes, AutoCloseable {
+public interface WritableFile extends WritableByteChannel {
 
 	void moveTo(WritableFile other) throws UncheckedIOException;
 
@@ -24,6 +27,37 @@ public interface WritableFile extends WritableBytes, AutoCloseable {
 
 	void truncate() throws UncheckedIOException;
 
+	/**
+	 * Writes the data in the given byte buffer to this readable bytes at the
+	 * current position.
+	 * 
+	 * @param source
+	 *            the byte buffer to use
+	 * @return the number of bytes written, always equal to
+	 *         {@code source.remaining()}
+	 * @throws UncheckedIOException
+	 *             if an {@link IOException} occurs while writing
+	 */
+	int write(ByteBuffer source) throws UncheckedIOException;
+
+	/**
+	 * <p>
+	 * Fast-forwards or rewinds the file to the specified position.
+	 * <p>
+	 * Consecutive writes on the file will begin at the new position.
+	 * <p>
+	 * If the position is set to a value greater than the current end of file
+	 * consecutive writes will write data to the given position. The value of
+	 * all bytes between this position and the previous end of file will be
+	 * unspecified.
+	 * 
+	 * @param position
+	 *            the position to set the file to
+	 * @throws UncheckedIOException
+	 *             if an {@link IOException} occurs
+	 */
+	void position(long position) throws UncheckedIOException;
+
 	/**
 	 * <p>
 	 * Closes this {@code WritableFile} which finally commits all operations

+ 28 - 12
main/filesystem-crypto/src/main/java/org/cryptomator/crypto/fs/CryptoReadableFile.java

@@ -1,5 +1,6 @@
 package org.cryptomator.crypto.fs;
 
+import java.io.UncheckedIOException;
 import java.nio.ByteBuffer;
 import java.util.concurrent.Callable;
 import java.util.concurrent.ExecutorService;
@@ -14,7 +15,10 @@ import org.cryptomator.io.ByteBuffers;
 
 class CryptoReadableFile implements ReadableFile {
 
-	private static final int READ_BUFFER_SIZE = 32 * 1024 + 32; // aligned with encrypted chunk size + MAC size
+	private static final int READ_BUFFER_SIZE = 32 * 1024 + 32; // aligned with
+																// encrypted
+																// chunk size +
+																// MAC size
 	private static final ByteBuffer EMPTY_BUFFER = ByteBuffer.allocate(0);
 
 	private final ExecutorService executorService = Executors.newSingleThreadScheduledExecutor();
@@ -26,7 +30,8 @@ class CryptoReadableFile implements ReadableFile {
 	public CryptoReadableFile(FileContentCryptor cryptor, ReadableFile file) {
 		final int headerSize = cryptor.getHeaderSize();
 		final ByteBuffer header = ByteBuffer.allocate(headerSize);
-		file.read(header, 0);
+		file.position(0);
+		file.read(header);
 		header.flip();
 		this.decryptor = cryptor.createFileContentDecryptor(header);
 		this.file = file;
@@ -42,31 +47,37 @@ class CryptoReadableFile implements ReadableFile {
 	}
 
 	@Override
-	public void read(ByteBuffer target) {
+	public int read(ByteBuffer target) {
 		try {
+			if (bufferedCleartext == FileContentCryptor.EOF) {
+				return -1;
+			}
+			int bytesRead = 0;
 			while (target.remaining() > 0 && bufferedCleartext != FileContentCryptor.EOF) {
 				bufferCleartext();
-				readFromBufferedCleartext(target);
+				bytesRead += readFromBufferedCleartext(target);
 			}
+			return bytesRead;
 		} catch (InterruptedException e) {
 			Thread.currentThread().interrupt();
+			throw new RuntimeException(e);
 		}
 	}
 
+	@Override
+	public void position(long position) throws UncheckedIOException {
+		throw new UnsupportedOperationException("Partial read unsupported");
+	}
+
 	private void bufferCleartext() throws InterruptedException {
 		if (!bufferedCleartext.hasRemaining()) {
 			bufferedCleartext = decryptor.cleartext();
 		}
 	}
 
-	private void readFromBufferedCleartext(ByteBuffer target) {
+	private int readFromBufferedCleartext(ByteBuffer target) {
 		assert bufferedCleartext != null;
-		ByteBuffers.copy(bufferedCleartext, target);
-	}
-
-	@Override
-	public void read(ByteBuffer target, long position) {
-		throw new UnsupportedOperationException("Partial read not implemented yet.");
+		return ByteBuffers.copy(bufferedCleartext, target);
 	}
 
 	@Override
@@ -79,6 +90,11 @@ class CryptoReadableFile implements ReadableFile {
 		}
 	}
 
+	@Override
+	public boolean isOpen() {
+		return file.isOpen();
+	}
+
 	@Override
 	public void close() {
 		executorService.shutdownNow();
@@ -95,7 +111,7 @@ class CryptoReadableFile implements ReadableFile {
 
 		@Override
 		public Void call() {
-			file.read(EMPTY_BUFFER, startpos);
+			file.position(startpos);
 			int bytesRead = -1;
 			try {
 				do {

+ 18 - 6
main/filesystem-crypto/src/main/java/org/cryptomator/crypto/fs/CryptoWritableFile.java

@@ -32,24 +32,27 @@ class CryptoWritableFile implements WritableFile {
 	private void writeHeader() {
 		ByteBuffer header = encryptor.getHeader();
 		header.rewind();
-		file.write(header, 0);
+		file.position(0);
+		file.write(header);
 	}
 
 	@Override
-	public void write(ByteBuffer source) {
-		final ByteBuffer cleartextCopy = ByteBuffer.allocate(source.remaining());
+	public int write(ByteBuffer source) {
+		final int size = source.remaining();
+		final ByteBuffer cleartextCopy = ByteBuffer.allocate(size);
 		ByteBuffers.copy(source, cleartextCopy);
 		cleartextCopy.flip();
 		try {
 			encryptor.append(cleartextCopy);
-			file.write(source);
+			return size;
 		} catch (InterruptedException e) {
 			Thread.currentThread().interrupt();
+			throw new RuntimeException(e);
 		}
 	}
 
 	@Override
-	public void write(ByteBuffer source, int position) {
+	public void position(long position) {
 		throw new UnsupportedOperationException("Partial write not implemented yet.");
 	}
 
@@ -75,7 +78,16 @@ class CryptoWritableFile implements WritableFile {
 
 	@Override
 	public void truncate() {
-		this.write(ByteBuffer.allocate(0), 0);
+		/*
+		 * TODO kill writer thread (EOF) and reinitialize CryptoWritableFile
+		 * after truncating the file
+		 */
+		throw new UnsupportedOperationException("Truncate not supported yet");
+	}
+
+	@Override
+	public boolean isOpen() {
+		return file.isOpen();
 	}
 
 	@Override

+ 14 - 16
main/filesystem-inmemory/src/main/java/org/cryptomator/filesystem/inmem/InMemoryFile.java

@@ -52,31 +52,24 @@ class InMemoryFile extends InMemoryNode implements File, ReadableFile, WritableF
 	}
 
 	@Override
-	public void read(ByteBuffer target) {
-		ByteBuffers.copy(content, target);
-	}
-
-	@Override
-	public void read(ByteBuffer target, long position) {
-		if (position > Integer.MAX_VALUE) {
-			throw new IllegalArgumentException("Can not keep files of virtually unlimited size in memory.");
-		}
+	public void position(long position) throws UncheckedIOException {
 		content.position((int) position);
-		ByteBuffers.copy(content, target);
 	}
 
 	@Override
-	public void write(ByteBuffer source) {
-		this.write(source, content.position());
+	public int read(ByteBuffer target) {
+		return ByteBuffers.copy(content, target);
 	}
 
 	@Override
-	public void write(ByteBuffer source, int position) {
+	public int write(ByteBuffer source) {
 		assert content != null;
-		expandContentCapacityIfRequired(position + source.remaining());
-		content.position(position);
+		final int initialContentPosition = content.position();
+		expandContentCapacityIfRequired(initialContentPosition + source.remaining());
+		content.position(initialContentPosition);
 		assert content.remaining() >= source.remaining();
 		content.put(source);
+		return content.position() - initialContentPosition;
 	}
 
 	private void expandContentCapacityIfRequired(int requiredCapacity) {
@@ -121,7 +114,12 @@ class InMemoryFile extends InMemoryNode implements File, ReadableFile, WritableF
 			// returning null removes the entry.
 			return null;
 		});
-		assert!this.exists();
+		assert !this.exists();
+	}
+
+	@Override
+	public boolean isOpen() {
+		return lock.isWriteLockedByCurrentThread() || lock.getReadHoldCount() > 0;
 	}
 
 	@Override

+ 4 - 2
main/filesystem-inmemory/src/test/java/org/cryptomator/filesystem/inmem/InMemoryFileSystemTest.java

@@ -136,7 +136,8 @@ public class InMemoryFileSystemTest {
 		}
 		final ByteBuffer readBuf = ByteBuffer.allocate(5);
 		try (ReadableFile readable = bazFile.openReadable()) {
-			readable.read(readBuf, 6);
+			readable.position(6);
+			readable.read(readBuf);
 		}
 		Assert.assertEquals("world", new String(readBuf.array()));
 	}
@@ -159,7 +160,8 @@ public class InMemoryFileSystemTest {
 		Assert.assertTrue(test1File.exists());
 		Assert.assertTrue(test2File.exists());
 
-		// copy foo/bar/ to qwe/asd/ (result is qwe/asd/file1.txt & qwe/asd/file2.txt)
+		// copy foo/bar/ to qwe/asd/ (result is qwe/asd/file1.txt &
+		// qwe/asd/file2.txt)
 		fooBarFolder.copyTo(qweAsdFolder);
 		Assert.assertTrue(qweAsdFolder.exists());
 		Assert.assertEquals(2, qweAsdFolder.files().count());

+ 16 - 4
main/filesystem-nio/src/main/java/org/cryptomator/filesystem/nio/NioFile.java

@@ -42,11 +42,17 @@ class NioFile extends NioNode implements File {
 	private class ReadableView implements ReadableFile {
 
 		@Override
-		public void read(ByteBuffer target) throws UncheckedIOException {
+		public int read(ByteBuffer target) throws UncheckedIOException {
+			return -1;
 		}
 
 		@Override
-		public void read(ByteBuffer target, long position) throws UncheckedIOException {
+		public boolean isOpen() {
+			return false;
+		}
+
+		@Override
+		public void position(long position) throws UncheckedIOException {
 		}
 
 		@Override
@@ -62,11 +68,17 @@ class NioFile extends NioNode implements File {
 	private class WritableView implements WritableFile {
 
 		@Override
-		public void write(ByteBuffer source) throws UncheckedIOException {
+		public int write(ByteBuffer source) throws UncheckedIOException {
+			return -1;
+		}
+
+		@Override
+		public boolean isOpen() {
+			return false;
 		}
 
 		@Override
-		public void write(ByteBuffer source, int position) throws UncheckedIOException {
+		public void position(long position) throws UncheckedIOException {
 		}
 
 		@Override

+ 1 - 1
main/filesystem-nio/src/test/java/org/cryptomator/filesystem/nio/NioFolderTest.java

@@ -1,7 +1,7 @@
 package org.cryptomator.filesystem.nio;
 
 import static java.util.stream.Collectors.toList;
-import static org.cryptomator.commons.test.matcher.ContainsMatcher.containsInAnyOrder;
+import static org.cryptomator.common.test.matcher.ContainsMatcher.containsInAnyOrder;
 import static org.cryptomator.filesystem.FolderCreateMode.FAIL_IF_PARENT_IS_MISSING;
 import static org.cryptomator.filesystem.FolderCreateMode.INCLUDING_PARENTS;
 import static org.cryptomator.filesystem.nio.FilesystemSetupUtils.emptyFilesystem;

+ 1 - 1
main/filesystem-nio/src/test/java/org/cryptomator/filesystem/nio/NioNodeMatcher.java

@@ -2,7 +2,7 @@ package org.cryptomator.filesystem.nio;
 
 import static org.hamcrest.CoreMatchers.equalTo;
 
-import org.cryptomator.commons.test.matcher.PropertyMatcher;
+import org.cryptomator.common.test.matcher.PropertyMatcher;
 import org.cryptomator.filesystem.File;
 import org.cryptomator.filesystem.Folder;
 import org.hamcrest.Matcher;