Changes to filesystem API and nio implementation

* Partial implementation of nio filesystem
* Removed timeouts from openReadable and openWritable
* Added convenience methods for copying
* Added utility to support deadlock safe opening of multiple files
This commit is contained in:
Markus Kreusch
2015-12-17 23:46:58 +01:00
parent 58524e5099
commit 25eed3dc4a
29 changed files with 725 additions and 165 deletions
@@ -10,8 +10,6 @@ package org.cryptomator.crypto.fs;
import java.io.UncheckedIOException;
import java.time.Instant;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import org.cryptomator.crypto.engine.Cryptor;
import org.cryptomator.filesystem.File;
@@ -37,13 +35,13 @@ public class CryptoFile extends CryptoNode implements File {
}
@Override
public ReadableFile openReadable(long timeout, TimeUnit unit) throws TimeoutException {
public ReadableFile openReadable() {
// TODO Auto-generated method stub
return null;
}
@Override
public WritableFile openWritable(long timeout, TimeUnit unit) throws TimeoutException {
public WritableFile openWritable() {
// TODO Auto-generated method stub
return null;
}
@@ -53,4 +51,9 @@ public class CryptoFile extends CryptoNode implements File {
return parent.toString() + name;
}
@Override
public int compareTo(File o) {
return toString().compareTo(o.toString());
}
}
@@ -8,12 +8,8 @@
*******************************************************************************/
package org.cryptomator.crypto.fs;
import java.io.IOException;
import java.io.UncheckedIOException;
import java.nio.ByteBuffer;
import java.util.Optional;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import org.cryptomator.crypto.engine.Cryptor;
import org.cryptomator.filesystem.File;
@@ -50,12 +46,13 @@ public class CryptoFileSystem extends CryptoFolder implements FileSystem {
}
assert masterkeyFile.exists() : "A CryptoFileSystem can not exist without a masterkey file.";
final File backupFile = physicalRoot.file(MASTERKEY_BACKUP_FILENAME);
backupMasterKeyFileSilently(masterkeyFile, backupFile);
masterkeyFile.copyTo(backupFile);
}
private static boolean decryptMasterKeyFile(Cryptor cryptor, File masterkeyFile, CharSequence passphrase) {
try (ReadableFile file = masterkeyFile.openReadable(1, TimeUnit.SECONDS)) {
// TODO we need to read the whole file but can not be sure about the buffer size:
try (ReadableFile file = masterkeyFile.openReadable()) {
// TODO we need to read the whole file but can not be sure about the
// buffer size:
final ByteBuffer bigEnoughBuffer = ByteBuffer.allocate(500);
file.read(bigEnoughBuffer);
bigEnoughBuffer.flip();
@@ -63,25 +60,13 @@ public class CryptoFileSystem extends CryptoFolder implements FileSystem {
final byte[] fileContents = new byte[bigEnoughBuffer.remaining()];
bigEnoughBuffer.get(fileContents);
return cryptor.readKeysFromMasterkeyFile(fileContents, passphrase);
} catch (TimeoutException e) {
throw new UncheckedIOException(new IOException("Failed to lock masterkey file in time. " + masterkeyFile, e));
}
}
private static void encryptMasterKeyFile(Cryptor cryptor, File masterkeyFile, CharSequence passphrase) {
try (WritableFile file = masterkeyFile.openWritable(1, TimeUnit.SECONDS)) {
try (WritableFile file = masterkeyFile.openWritable()) {
final byte[] fileContents = cryptor.writeKeysToMasterkeyFile(passphrase);
file.write(ByteBuffer.wrap(fileContents));
} catch (TimeoutException e) {
throw new UncheckedIOException(new IOException("Failed to lock masterkey file in time. " + masterkeyFile, e));
}
}
private static void backupMasterKeyFileSilently(File masterkeyFile, File backupFile) {
try (ReadableFile src = masterkeyFile.openReadable(1, TimeUnit.SECONDS); WritableFile dst = backupFile.openWritable(1, TimeUnit.SECONDS)) {
src.copyTo(dst);
} catch (TimeoutException e) {
LOG.warn("Failed to lock masterkey file (" + masterkeyFile + ") or backup file (" + backupFile + ") in time. Skipping backup.");
}
}
@@ -115,11 +100,9 @@ public class CryptoFileSystem extends CryptoFolder implements FileSystem {
physicalDataRoot().create(mode);
final File dirFile = physicalFile();
final String directoryId = getDirectoryId();
try (WritableFile writable = dirFile.openWritable(1, TimeUnit.SECONDS)) {
try (WritableFile writable = dirFile.openWritable()) {
final ByteBuffer buf = ByteBuffer.wrap(directoryId.getBytes());
writable.write(buf);
} catch (TimeoutException e) {
throw new UncheckedIOException(new IOException("Failed to lock directory file in time. " + dirFile, e));
}
physicalFolder().create(FolderCreateMode.INCLUDING_PARENTS);
}
@@ -9,13 +9,10 @@
package org.cryptomator.crypto.fs;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.UncheckedIOException;
import java.nio.ByteBuffer;
import java.time.Instant;
import java.util.UUID;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import java.util.concurrent.atomic.AtomicReference;
import java.util.stream.Stream;
@@ -46,15 +43,13 @@ class CryptoFolder extends CryptoNode implements Folder {
if (directoryId.get() == null) {
File dirFile = physicalFile();
if (dirFile.exists()) {
try (ReadableFile readable = dirFile.openReadable(1, TimeUnit.SECONDS)) {
try (ReadableFile readable = dirFile.openReadable()) {
final ByteBuffer buf = ByteBuffer.allocate(64);
readable.read(buf);
buf.flip();
byte[] bytes = new byte[buf.remaining()];
buf.get(bytes);
directoryId.set(new String(bytes));
} catch (TimeoutException e) {
throw new UncheckedIOException(new IOException("Failed to lock directory file in time." + dirFile, e));
}
} else {
directoryId.compareAndSet(null, UUID.randomUUID().toString());
@@ -125,11 +120,9 @@ class CryptoFolder extends CryptoNode implements Folder {
}
assert parent.exists();
final String directoryId = getDirectoryId();
try (WritableFile writable = dirFile.openWritable(1, TimeUnit.SECONDS)) {
try (WritableFile writable = dirFile.openWritable()) {
final ByteBuffer buf = ByteBuffer.wrap(directoryId.getBytes());
writable.write(buf);
} catch (TimeoutException e) {
throw new UncheckedIOException(new IOException("Failed to lock directory file in time." + dirFile, e));
}
physicalFolder().create(FolderCreateMode.INCLUDING_PARENTS);
}
@@ -150,12 +143,11 @@ class CryptoFolder extends CryptoNode implements Folder {
target.physicalFile().parent().get().create(FolderCreateMode.INCLUDING_PARENTS);
assert target.physicalFile().parent().get().exists();
try (WritableFile src = this.physicalFile().openWritable(1, TimeUnit.SECONDS); WritableFile dst = target.physicalFile().openWritable(1, TimeUnit.SECONDS)) {
try (WritableFile src = this.physicalFile().openWritable(); WritableFile dst = target.physicalFile().openWritable()) {
src.moveTo(dst);
} catch (TimeoutException e) {
throw new UncheckedIOException(new IOException("Failed to lock file for moving (src: " + this + ", dst: " + target + ")", e));
}
// directoryId is now used by target, we must no longer use the same id (we'll generate a new one when needed)
// directoryId is now used by target, we must no longer use the same id
// (we'll generate a new one when needed)
directoryId.set(null);
}