Using DI to stack up filesystem layers

This commit is contained in:
Sebastian Stenzel
2016-01-05 16:55:52 +01:00
parent b31f6a0aec
commit ddf6353729
23 changed files with 339 additions and 298 deletions

View File

@@ -1,15 +0,0 @@
package org.cryptomator.crypto;
import javax.inject.Singleton;
import org.cryptomator.crypto.engine.impl.CryptoModule;
import dagger.Component;
@Singleton
@Component(modules = CryptoModule.class)
interface CryptoComponent {
CryptoFileSystemFactory cryptoFileSystemFactory();
}

View File

@@ -1,27 +0,0 @@
package org.cryptomator.crypto;
import javax.inject.Inject;
import javax.inject.Provider;
import javax.inject.Singleton;
import org.cryptomator.crypto.engine.Cryptor;
import org.cryptomator.crypto.engine.impl.FileContentCryptorImpl;
import org.cryptomator.filesystem.FileSystem;
import org.cryptomator.filesystem.Folder;
import org.cryptomator.filesystem.blockaligned.BlockAlignedFileSystem;
import org.cryptomator.filesystem.crypto.CryptoFileSystem;
@Singleton
public class CryptoFileSystemFactory {
private final Provider<Cryptor> cryptorProvider;
@Inject
public CryptoFileSystemFactory(Provider<Cryptor> cryptorProvider) {
this.cryptorProvider = cryptorProvider;
}
public FileSystem get(Folder root, CharSequence passphrase) {
return new BlockAlignedFileSystem(new CryptoFileSystem(root, cryptorProvider.get(), passphrase), FileContentCryptorImpl.CHUNK_SIZE);
}
}

View File

@@ -9,15 +9,15 @@ import dagger.Module;
import dagger.Provides;
@Module
public class CryptoModule {
public class CryptoEngineModule {
@Provides
Cryptor provideCryptor(SecureRandom secureRandom) {
public Cryptor provideCryptor(SecureRandom secureRandom) {
return new CryptorImpl(secureRandom);
}
@Provides
SecureRandom provideSecureRandom() {
public SecureRandom provideSecureRandom() {
try {
return SecureRandom.getInstanceStrong();
} catch (NoSuchAlgorithmException e) {

View File

@@ -21,7 +21,7 @@ import org.cryptomator.crypto.engine.FileContentEncryptor;
public class FileContentCryptorImpl implements FileContentCryptor {
public static final int CHUNK_SIZE = 32 * 1024;
static final int MAC_SIZE = 32;
public static final int MAC_SIZE = 32;
private final SecretKey encryptionKey;
private final SecretKey macKey;

View File

@@ -11,7 +11,7 @@ package org.cryptomator.filesystem.blockaligned;
import org.cryptomator.filesystem.FileSystem;
import org.cryptomator.filesystem.Folder;
public class BlockAlignedFileSystem extends BlockAlignedFolder implements FileSystem {
class BlockAlignedFileSystem extends BlockAlignedFolder implements FileSystem {
public BlockAlignedFileSystem(Folder delegate, int blockSize) {
super(null, delegate, blockSize);

View File

@@ -0,0 +1,20 @@
package org.cryptomator.filesystem.blockaligned;
import javax.inject.Inject;
import javax.inject.Singleton;
import org.cryptomator.crypto.engine.impl.FileContentCryptorImpl;
import org.cryptomator.filesystem.FileSystem;
import org.cryptomator.filesystem.Folder;
@Singleton
public class BlockAlignedFileSystemFactory {
@Inject
public BlockAlignedFileSystemFactory() {
}
public FileSystem get(Folder root) {
return new BlockAlignedFileSystem(root, FileContentCryptorImpl.CHUNK_SIZE);
}
}

View File

@@ -19,7 +19,7 @@ import org.cryptomator.filesystem.Folder;
import org.cryptomator.filesystem.ReadableFile;
import org.cryptomator.filesystem.WritableFile;
public class CryptoFileSystem extends CryptoFolder implements FileSystem {
class CryptoFileSystem extends CryptoFolder implements FileSystem {
private static final String DATA_ROOT_DIR = "d";
private static final String ROOT_DIR_FILE = "root";

View File

@@ -0,0 +1,15 @@
package org.cryptomator.filesystem.crypto;
import javax.inject.Singleton;
import org.cryptomator.crypto.engine.impl.CryptoEngineModule;
import dagger.Component;
@Singleton
@Component(modules = CryptoEngineModule.class)
interface CryptoFileSystemComponent {
CryptoFileSystemFactory cryptoFileSystemFactory();
}

View File

@@ -0,0 +1,32 @@
package org.cryptomator.filesystem.crypto;
import javax.inject.Inject;
import javax.inject.Provider;
import javax.inject.Singleton;
import org.cryptomator.crypto.engine.Cryptor;
import org.cryptomator.filesystem.FileSystem;
import org.cryptomator.filesystem.Folder;
import org.cryptomator.filesystem.blockaligned.BlockAlignedFileSystemFactory;
import org.cryptomator.filesystem.shortening.ShorteningFileSystemFactory;
@Singleton
public class CryptoFileSystemFactory {
private final Provider<Cryptor> cryptorProvider;
private final ShorteningFileSystemFactory shorteningFileSystemFactory;
private final BlockAlignedFileSystemFactory blockAlignedFileSystemFactory;
@Inject
public CryptoFileSystemFactory(Provider<Cryptor> cryptorProvider, ShorteningFileSystemFactory shorteningFileSystemFactory, BlockAlignedFileSystemFactory blockAlignedFileSystemFactory) {
this.cryptorProvider = cryptorProvider;
this.shorteningFileSystemFactory = shorteningFileSystemFactory;
this.blockAlignedFileSystemFactory = blockAlignedFileSystemFactory;
}
public FileSystem get(Folder root, CharSequence passphrase) {
final FileSystem nameShorteningFs = shorteningFileSystemFactory.get(root);
final FileSystem cryptoFs = new CryptoFileSystem(nameShorteningFs, cryptorProvider.get(), passphrase);
return blockAlignedFileSystemFactory.get(cryptoFs);
}
}

View File

@@ -1,60 +0,0 @@
package org.cryptomator.crypto;
import java.nio.ByteBuffer;
import java.util.Arrays;
import org.cryptomator.filesystem.File;
import org.cryptomator.filesystem.FileSystem;
import org.cryptomator.filesystem.Folder;
import org.cryptomator.filesystem.ReadableFile;
import org.cryptomator.filesystem.WritableFile;
import org.cryptomator.filesystem.inmem.InMemoryFileSystem;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
public class CryptoFileSystemIntegrationTest {
private FileSystem ciphertextFs;
private FileSystem cleartextFs;
@Before
public void setupFileSystems() {
ciphertextFs = new InMemoryFileSystem();
// final Predicate<Node> isMetadataFolder = (Node node) -> node.equals(physicalFs.folder("m"));
// final FileSystem metadataHidingFs = new BlacklistingFileSystem(physicalFs, isMetadataFolder);
// final FileSystem shorteningFs = new ShorteningFileSystem(metadataHidingFs, physicalFs.folder("m"), 70);
cleartextFs = DaggerCryptoTestComponent.create().cryptoFileSystemFactory().get(ciphertextFs, "TopSecret");
cleartextFs.create();
}
@Test
public void testRandomAccess() {
File cleartextFile = cleartextFs.file("test");
try (WritableFile writable = cleartextFile.openWritable()) {
ByteBuffer buf = ByteBuffer.allocate(25000);
for (int i = 0; i < 40; i++) { // 40 * 25k = 1M
buf.clear();
Arrays.fill(buf.array(), (byte) i);
writable.write(buf);
}
}
Folder ciphertextRootFolder = ciphertextFs.folder("d").folders().findAny().get().folders().findAny().get();
Assert.assertTrue(ciphertextRootFolder.exists());
File ciphertextFile = ciphertextRootFolder.files().findAny().get();
Assert.assertTrue(ciphertextFile.exists());
try (ReadableFile readable = cleartextFile.openReadable()) {
ByteBuffer buf = ByteBuffer.allocate(1);
for (int i = 0; i < 40; i++) {
buf.clear();
readable.position(i * 25000 + (long) Math.random() * 24999);
readable.read(buf);
buf.flip();
Assert.assertEquals(i, buf.get());
}
}
}
}

View File

@@ -1,15 +0,0 @@
package org.cryptomator.crypto;
import javax.inject.Singleton;
import org.cryptomator.crypto.engine.impl.CryptoTestModule;
import dagger.Component;
@Singleton
@Component(modules = CryptoTestModule.class)
interface CryptoTestComponent {
CryptoFileSystemFactory cryptoFileSystemFactory();
}

View File

@@ -0,0 +1,23 @@
package org.cryptomator.crypto.engine.impl;
import java.security.SecureRandom;
import java.util.Arrays;
/**
* Used as drop-in-replacement for {@link CryptoEngineModule} during unit tests.
*/
public class CryptoEngineTestModule extends CryptoEngineModule {
@Override
public SecureRandom provideSecureRandom() {
return new SecureRandom() {
@Override
public void nextBytes(byte[] bytes) {
Arrays.fill(bytes, (byte) 0x00);
}
};
}
}

View File

@@ -1,31 +0,0 @@
package org.cryptomator.crypto.engine.impl;
import java.security.SecureRandom;
import java.util.Arrays;
import org.cryptomator.crypto.engine.Cryptor;
import dagger.Module;
import dagger.Provides;
@Module
public class CryptoTestModule {
@Provides
Cryptor provideCryptor(SecureRandom secureRandom) {
return new CryptorImpl(secureRandom);
}
@Provides
SecureRandom provideSecureRandom() {
return new SecureRandom() {
@Override
public void nextBytes(byte[] bytes) {
Arrays.fill(bytes, (byte) 0x00);
}
};
}
}

View File

@@ -0,0 +1,104 @@
package org.cryptomator.filesystem.crypto;
import java.nio.ByteBuffer;
import java.util.Arrays;
import org.cryptomator.crypto.engine.impl.CryptoEngineTestModule;
import org.cryptomator.filesystem.File;
import org.cryptomator.filesystem.FileSystem;
import org.cryptomator.filesystem.Folder;
import org.cryptomator.filesystem.Node;
import org.cryptomator.filesystem.ReadableFile;
import org.cryptomator.filesystem.WritableFile;
import org.cryptomator.filesystem.inmem.InMemoryFileSystem;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
public class CryptoFileSystemComponentIntegrationTest {
private static final CryptoFileSystemComponent cryptoFsComp = DaggerCryptoFileSystemComponent.builder().cryptoEngineModule(new CryptoEngineTestModule()).build();
private FileSystem ciphertextFs;
private FileSystem cleartextFs;
@Before
public void setupFileSystems() {
ciphertextFs = new InMemoryFileSystem();
cleartextFs = cryptoFsComp.cryptoFileSystemFactory().get(ciphertextFs, "TopSecret");
cleartextFs.create();
}
@Test
public void testEncryptionOfLongFolderNames() {
final String shortName = "normal folder name";
final String longName = "this will be a long filename after encryption, because its encrypted name is longer than onehundredandeighty characters";
final Folder shortFolder = cleartextFs.folder(shortName);
final Folder longFolder = cleartextFs.folder(longName);
shortFolder.create();
longFolder.create();
// because of the long file, a metadata folder should exist on the physical layer:
Assert.assertEquals(1, ciphertextFs.folder("m").folders().count());
Assert.assertTrue(ciphertextFs.folder("m").exists());
// but the shortened filenames must not be visible on the cleartext layer:
Assert.assertArrayEquals(new String[] {shortName, longName}, cleartextFs.folders().map(Node::name).sorted().toArray());
}
@Test
public void testEncryptionAndDecryptionOfFiles() {
// write test content to encrypted file
try (WritableFile writable = cleartextFs.file("test1.txt").openWritable()) {
writable.write(ByteBuffer.wrap("Hello ".getBytes()));
writable.write(ByteBuffer.wrap("World".getBytes()));
}
File physicalFile = ciphertextFs.folder("d").folders().findAny().get().folders().findAny().get().files().findAny().get();
Assert.assertTrue(physicalFile.exists());
// read test content from decrypted file
try (ReadableFile readable = cleartextFs.file("test1.txt").openReadable()) {
ByteBuffer buf1 = ByteBuffer.allocate(5);
readable.read(buf1);
buf1.flip();
Assert.assertEquals("Hello", new String(buf1.array(), 0, buf1.remaining()));
ByteBuffer buf2 = ByteBuffer.allocate(10);
readable.read(buf2);
buf2.flip();
Assert.assertArrayEquals(" World".getBytes(), Arrays.copyOfRange(buf2.array(), 0, buf2.remaining()));
}
}
@Test
public void testRandomAccess() {
File cleartextFile = cleartextFs.file("test");
try (WritableFile writable = cleartextFile.openWritable()) {
ByteBuffer buf = ByteBuffer.allocate(25000);
for (int i = 0; i < 40; i++) { // 40 * 25k = 1M
buf.clear();
Arrays.fill(buf.array(), (byte) i);
writable.write(buf);
}
}
Folder ciphertextRootFolder = ciphertextFs.folder("d").folders().findAny().get().folders().findAny().get();
Assert.assertTrue(ciphertextRootFolder.exists());
File ciphertextFile = ciphertextRootFolder.files().findAny().get();
Assert.assertTrue(ciphertextFile.exists());
try (ReadableFile readable = cleartextFile.openReadable()) {
ByteBuffer buf = ByteBuffer.allocate(1);
for (int i = 0; i < 40; i++) {
buf.clear();
readable.position(i * 25000 + (long) Math.random() * 24999); // "random access", told you so.
readable.read(buf);
buf.flip();
Assert.assertEquals(i, buf.get());
}
}
}
}

View File

@@ -1,37 +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.crypto;
import static org.cryptomator.filesystem.FileSystemVisitor.fileSystemVisitor;
import org.cryptomator.filesystem.Folder;
public final class DirectoryPrinter {
private DirectoryPrinter() {
}
public static String print(Folder rootFolder) {
StringBuilder result = new StringBuilder();
StringBuilder indentation = new StringBuilder();
fileSystemVisitor() //
.beforeFolder(folder -> {
result.append(indentation).append(folder.name()).append("/\n");
indentation.append(" ");
}) //
.afterFolder(folder -> {
indentation.delete(indentation.length() - 2, indentation.length());
}).forEachFile(file -> {
result.append(indentation).append(file.name()).append('\n');
}) //
.visit(rootFolder);
return result.toString();
}
}

View File

@@ -1,105 +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.crypto;
import static org.cryptomator.filesystem.FileSystemVisitor.fileSystemVisitor;
import java.nio.ByteBuffer;
import java.util.Arrays;
import java.util.function.Predicate;
import org.cryptomator.crypto.engine.Cryptor;
import org.cryptomator.crypto.engine.impl.TestCryptorImplFactory;
import org.cryptomator.filesystem.File;
import org.cryptomator.filesystem.FileSystem;
import org.cryptomator.filesystem.Folder;
import org.cryptomator.filesystem.Node;
import org.cryptomator.filesystem.ReadableFile;
import org.cryptomator.filesystem.WritableFile;
import org.cryptomator.filesystem.blacklisting.BlacklistingFileSystem;
import org.cryptomator.filesystem.inmem.InMemoryFileSystem;
import org.cryptomator.filesystem.shortening.ShorteningFileSystem;
import org.junit.Assert;
import org.junit.Test;
public class EncryptAndShortenIntegrationTest {
// private static final Logger LOG = LoggerFactory.getLogger(EncryptAndShortenIntegrationTest.class);
@Test
public void testEncryptionOfLongFolderNames() {
final FileSystem physicalFs = new InMemoryFileSystem();
final Predicate<Node> isMetadataFolder = (Node node) -> node.equals(physicalFs.folder("m"));
final FileSystem metadataHidingFs = new BlacklistingFileSystem(physicalFs, isMetadataFolder);
final FileSystem shorteningFs = new ShorteningFileSystem(metadataHidingFs, physicalFs.folder("m"), 70);
final Cryptor cryptor = TestCryptorImplFactory.insecureCryptorImpl();
cryptor.randomizeMasterkey();
final FileSystem fs = new CryptoFileSystem(shorteningFs, cryptor, "foo");
fs.create();
final Folder shortFolder = fs.folder("normal folder name");
shortFolder.create();
final Folder longFolder = fs.folder("this will be a long filename after encryption");
longFolder.create();
// on the first (physical) layer all files including metadata files are visible:
// the long name will produce a metadata file on the physical layer:
// LOG.debug("Physical file system:\n" + DirectoryPrinter.print(physicalFs));
Assert.assertEquals(1, physicalFs.folder("m").folders().count());
Assert.assertTrue(physicalFs.folder("m").exists());
// on the second (blacklisting) layer we hide the metadata folder:
// LOG.debug("Filtered files:\n" + DirectoryPrinter.print(metadataHidingFs));
Assert.assertEquals(1, metadataHidingFs.folders().count()); // only "d", no "m".
// on the third layer all .lng files are resolved to their actual names:
// LOG.debug("Unlimited filename length:\n" + DirectoryPrinter.print(shorteningFs));
fileSystemVisitor() //
.forEachNode(node -> {
Assert.assertFalse(node.name().endsWith(".lng"));
}) //
.visit(shorteningFs);
// on the fourth (cleartext) layer we have cleartext names on the root level:
// LOG.debug("Cleartext files:\n" + DirectoryPrinter.print(fs));
Assert.assertArrayEquals(new String[] {"normal folder name", "this will be a long filename after encryption"}, fs.folders().map(Node::name).sorted().toArray());
}
@Test
public void testEncryptionAndDecryptionOfFiles() {
final FileSystem physicalFs = new InMemoryFileSystem();
final FileSystem shorteningFs = new ShorteningFileSystem(physicalFs, physicalFs.folder("m"), 70);
final Cryptor cryptor = TestCryptorImplFactory.insecureCryptorImpl();
cryptor.randomizeMasterkey();
final FileSystem fs = new CryptoFileSystem(shorteningFs, cryptor, "foo");
fs.create();
// write test content to encrypted file
try (WritableFile writable = fs.file("test1.txt").openWritable()) {
writable.write(ByteBuffer.wrap("Hello ".getBytes()));
writable.write(ByteBuffer.wrap("World".getBytes()));
}
File physicalFile = physicalFs.folder("d").folders().findAny().get().folders().findAny().get().files().findAny().get();
Assert.assertTrue(physicalFile.exists());
// read test content from decrypted file
try (ReadableFile readable = fs.file("test1.txt").openReadable()) {
ByteBuffer buf1 = ByteBuffer.allocate(5);
readable.read(buf1);
buf1.flip();
Assert.assertEquals("Hello", new String(buf1.array(), 0, buf1.remaining()));
ByteBuffer buf2 = ByteBuffer.allocate(10);
readable.read(buf2);
buf2.flip();
Assert.assertArrayEquals(" World".getBytes(), Arrays.copyOfRange(buf2.array(), 0, buf2.remaining()));
}
}
}

View File

@@ -42,6 +42,17 @@
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
</dependency>
<!-- DI -->
<dependency>
<groupId>com.google.dagger</groupId>
<artifactId>dagger</artifactId>
</dependency>
<dependency>
<groupId>com.google.dagger</groupId>
<artifactId>dagger-compiler</artifactId>
<scope>provided</scope>
</dependency>
<!-- Tests -->
<dependency>

View File

@@ -6,7 +6,7 @@ import org.cryptomator.filesystem.FileSystem;
import org.cryptomator.filesystem.Folder;
import org.cryptomator.filesystem.Node;
public class BlacklistingFileSystem extends BlacklistingFolder implements FileSystem {
class BlacklistingFileSystem extends BlacklistingFolder implements FileSystem {
public BlacklistingFileSystem(Folder root, Predicate<Node> hiddenNodes) {
super(null, root, hiddenNodes);

View File

@@ -0,0 +1,22 @@
package org.cryptomator.filesystem.blacklisting;
import java.util.function.Predicate;
import javax.inject.Inject;
import javax.inject.Singleton;
import org.cryptomator.filesystem.FileSystem;
import org.cryptomator.filesystem.Folder;
import org.cryptomator.filesystem.Node;
@Singleton
public class BlacklistingFileSystemFactory {
@Inject
public BlacklistingFileSystemFactory() {
}
public FileSystem get(Folder root, Predicate<Node> hiddenFiles) {
return new BlacklistingFileSystem(root, hiddenFiles);
}
}

View File

@@ -3,7 +3,7 @@ package org.cryptomator.filesystem.shortening;
import org.cryptomator.filesystem.FileSystem;
import org.cryptomator.filesystem.Folder;
public class ShorteningFileSystem extends ShorteningFolder implements FileSystem {
class ShorteningFileSystem extends ShorteningFolder implements FileSystem {
public ShorteningFileSystem(Folder root, Folder metadataRoot, int threshold) {
super(null, root, "", new FilenameShortener(metadataRoot, threshold));

View File

@@ -0,0 +1,32 @@
package org.cryptomator.filesystem.shortening;
import java.util.function.Predicate;
import javax.inject.Inject;
import javax.inject.Singleton;
import org.cryptomator.filesystem.FileSystem;
import org.cryptomator.filesystem.Folder;
import org.cryptomator.filesystem.Node;
import org.cryptomator.filesystem.blacklisting.BlacklistingFileSystemFactory;
@Singleton
public class ShorteningFileSystemFactory {
private static final int SHORTENING_THRESHOLD = 140;
private static final String METADATA_FOLDER_NAME = "m";
private final BlacklistingFileSystemFactory blacklistingFileSystemFactory;
@Inject
public ShorteningFileSystemFactory(BlacklistingFileSystemFactory blacklistingFileSystemFactory) {
this.blacklistingFileSystemFactory = blacklistingFileSystemFactory;
}
public FileSystem get(Folder root) {
final Folder metadataFolder = root.folder(METADATA_FOLDER_NAME);
final Predicate<Node> isMetadataFolder = (Node node) -> metadataFolder.equals(node);
final FileSystem metadataHidingFs = blacklistingFileSystemFactory.get(root, isMetadataFolder);
return new ShorteningFileSystem(metadataHidingFs, metadataFolder, SHORTENING_THRESHOLD);
}
}

View File

@@ -0,0 +1,59 @@
package org.cryptomator.filesystem.shortening;
import java.nio.ByteBuffer;
import org.cryptomator.filesystem.File;
import org.cryptomator.filesystem.FileSystem;
import org.cryptomator.filesystem.Folder;
import org.cryptomator.filesystem.WritableFile;
import org.cryptomator.filesystem.inmem.InMemoryFileSystem;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
public class ShorteningFileSystemFactoryTest {
private static final ShorteningFileSystemFactory shorteningFsFactory = DaggerShorteningFileSystemTestComponent.create().shorteningFileSystemFactory();
private static final String LONG_NAME = "aaaaabbbbbcccccdddddeeeeefffffggggghhhhhiiiiijjjjjkkkkklllll" //
+ "mmmmmnnnnnooooopppppqqqqqrrrrrssssstttttuuuuuvvvvvwwwwwxxxxxyyyyyzzzzz" //
+ "00000111112222233333444445555566666777778888899999";
private static final String SHORTENED_FILE = "UYPJJ35VGP2JJ4YISC5S2XQLENLR5MVC.lng"; // base32(sha1(LONG_NAME)) + '.lng'
private static final String CORRESPONDING_METADATA_FILE = "m/UY/PJ/UYPJJ35VGP2JJ4YISC5S2XQLENLR5MVC.lng";
private FileSystem physicalFs;
private FileSystem shortenedFs;
@Before
public void setupFileSystems() {
physicalFs = new InMemoryFileSystem();
shortenedFs = shorteningFsFactory.get(physicalFs);
shortenedFs.create();
}
@Test
public void testFileCreation() {
File file = shortenedFs.file(LONG_NAME);
Assert.assertFalse(file.exists());
Assert.assertFalse(physicalFs.resolveFile(SHORTENED_FILE).exists());
Assert.assertFalse(physicalFs.resolveFile(CORRESPONDING_METADATA_FILE).exists());
try (WritableFile w = file.openWritable()) {
w.write(ByteBuffer.allocate(0));
}
Assert.assertTrue(file.exists());
Assert.assertTrue(physicalFs.resolveFile(SHORTENED_FILE).exists());
Assert.assertTrue(physicalFs.resolveFile(CORRESPONDING_METADATA_FILE).exists());
}
@Test
public void testFolderCreation() {
Folder folder = shortenedFs.folder(LONG_NAME);
Assert.assertFalse(folder.exists());
Assert.assertFalse(physicalFs.resolveFolder(SHORTENED_FILE).exists());
Assert.assertFalse(physicalFs.resolveFile(CORRESPONDING_METADATA_FILE).exists());
folder.create();
Assert.assertTrue(folder.exists());
Assert.assertTrue(physicalFs.resolveFolder(SHORTENED_FILE).exists());
Assert.assertTrue(physicalFs.resolveFile(CORRESPONDING_METADATA_FILE).exists());
}
}

View File

@@ -0,0 +1,13 @@
package org.cryptomator.filesystem.shortening;
import javax.inject.Singleton;
import dagger.Component;
@Singleton
@Component
public interface ShorteningFileSystemTestComponent {
ShorteningFileSystemFactory shorteningFileSystemFactory();
}