Skip to content

Commit 3accfd2

Browse files
Merge branch 'release/1.9.3'
2 parents 000dc40 + ef3c085 commit 3accfd2

13 files changed

+141
-88
lines changed

pom.xml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
<modelVersion>4.0.0</modelVersion>
33
<groupId>org.cryptomator</groupId>
44
<artifactId>cryptofs</artifactId>
5-
<version>1.9.2</version>
5+
<version>1.9.3</version>
66
<name>Cryptomator Crypto Filesystem</name>
77
<description>This library provides the Java filesystem provider used by Cryptomator.</description>
88
<url>https://github.com/cryptomator/cryptofs</url>

src/main/java/org/cryptomator/cryptofs/CryptoFileSystemComponent.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,12 @@
33
import dagger.BindsInstance;
44
import dagger.Subcomponent;
55
import org.cryptomator.cryptofs.attr.AttributeViewComponent;
6+
import org.cryptomator.cryptofs.common.FileSystemCapabilityChecker;
67
import org.cryptomator.cryptofs.dir.DirectoryStreamComponent;
78
import org.cryptomator.cryptofs.fh.OpenCryptoFileComponent;
89

910
import java.nio.file.Path;
11+
import java.util.Set;
1012

1113
@CryptoFileSystemScoped
1214
@Subcomponent(modules = {CryptoFileSystemModule.class})

src/main/java/org/cryptomator/cryptofs/CryptoFileSystemProvider.java

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -164,7 +164,7 @@ public static void initialize(Path pathToVault, String masterkeyFilename, byte[]
164164
if (!Files.isDirectory(pathToVault)) {
165165
throw new NotDirectoryException(pathToVault.toString());
166166
}
167-
new FileSystemCapabilityChecker().checkCapabilities(pathToVault);
167+
new FileSystemCapabilityChecker().assertAllCapabilities(pathToVault);
168168
try (Cryptor cryptor = CRYPTOR_PROVIDER.createNew()) {
169169
// save masterkey file:
170170
Path masterKeyPath = pathToVault.resolve(masterkeyFilename);
@@ -293,8 +293,6 @@ public String getScheme() {
293293
public CryptoFileSystem newFileSystem(URI uri, Map<String, ?> rawProperties) throws IOException {
294294
CryptoFileSystemUri parsedUri = CryptoFileSystemUri.parse(uri);
295295
CryptoFileSystemProperties properties = CryptoFileSystemProperties.wrap(rawProperties);
296-
297-
new FileSystemCapabilityChecker().checkCapabilities(parsedUri.pathToVault());
298296

299297
// TODO remove implicit initialization in 2.0.0
300298
initializeFileSystemIfRequired(parsedUri, properties);

src/main/java/org/cryptomator/cryptofs/CryptoFileSystemProviderComponent.java

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
import javax.inject.Singleton;
88

99
@Singleton
10-
@Component
10+
@Component(modules = {CryptoFileSystemProviderModule.class})
1111
interface CryptoFileSystemProviderComponent {
1212

1313
CryptoFileSystems fileSystems();
@@ -16,8 +16,6 @@ interface CryptoFileSystemProviderComponent {
1616

1717
CopyOperation copyOperation();
1818

19-
CryptoFileSystemComponent.Builder newCryptoFileSystemComponent();
20-
2119
@Component.Builder
2220
interface Builder {
2321
@BindsInstance
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
package org.cryptomator.cryptofs;
2+
3+
import dagger.Module;
4+
import dagger.Provides;
5+
import org.cryptomator.cryptofs.common.FileSystemCapabilityChecker;
6+
7+
import javax.inject.Singleton;
8+
9+
@Module(subcomponents = {CryptoFileSystemComponent.class})
10+
public class CryptoFileSystemProviderModule {
11+
12+
@Provides
13+
@Singleton
14+
public FileSystemCapabilityChecker provideFileSystemCapabilityChecker() {
15+
return new FileSystemCapabilityChecker();
16+
}
17+
18+
}

src/main/java/org/cryptomator/cryptofs/CryptoFileSystems.java

Lines changed: 33 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,38 +1,47 @@
11
package org.cryptomator.cryptofs;
22

3+
import org.cryptomator.cryptofs.common.FileSystemCapabilityChecker;
4+
import org.slf4j.Logger;
5+
import org.slf4j.LoggerFactory;
6+
37
import javax.inject.Inject;
48
import javax.inject.Singleton;
59
import java.io.IOException;
610
import java.io.UncheckedIOException;
711
import java.nio.file.FileSystemAlreadyExistsException;
812
import java.nio.file.FileSystemNotFoundException;
913
import java.nio.file.Path;
14+
import java.util.EnumSet;
15+
import java.util.Set;
1016
import java.util.concurrent.ConcurrentHashMap;
1117
import java.util.concurrent.ConcurrentMap;
1218

1319
import static java.lang.String.format;
1420

1521
@Singleton
1622
class CryptoFileSystems {
17-
18-
private final CryptoFileSystemProviderComponent cryptoFileSystemProviderComponent;
23+
24+
private static final Logger LOG = LoggerFactory.getLogger(CryptoFileSystems.class);
1925

2026
private final ConcurrentMap<Path, CryptoFileSystemImpl> fileSystems = new ConcurrentHashMap<>();
27+
private final CryptoFileSystemComponent.Builder cryptoFileSystemComponentBuilder;
28+
private final FileSystemCapabilityChecker capabilityChecker;
2129

2230
@Inject
23-
public CryptoFileSystems(CryptoFileSystemProviderComponent cryptoFileSystemProviderComponent) {
24-
this.cryptoFileSystemProviderComponent = cryptoFileSystemProviderComponent;
31+
public CryptoFileSystems(CryptoFileSystemComponent.Builder cryptoFileSystemComponentBuilder, FileSystemCapabilityChecker capabilityChecker) {
32+
this.cryptoFileSystemComponentBuilder = cryptoFileSystemComponentBuilder;
33+
this.capabilityChecker = capabilityChecker;
2534
}
2635

2736
public CryptoFileSystemImpl create(CryptoFileSystemProvider provider, Path pathToVault, CryptoFileSystemProperties properties) throws IOException {
2837
try {
2938
Path normalizedPathToVault = pathToVault.normalize();
39+
CryptoFileSystemProperties adjustedProperites = adjustForCapabilities(normalizedPathToVault, properties);
3040
return fileSystems.compute(normalizedPathToVault, (key, value) -> {
3141
if (value == null) {
32-
return cryptoFileSystemProviderComponent //
33-
.newCryptoFileSystemComponent() //
42+
return cryptoFileSystemComponentBuilder //
3443
.pathToVault(key) //
35-
.properties(properties) //
44+
.properties(adjustedProperites) //
3645
.provider(provider) //
3746
.build() //
3847
.cryptoFileSystem();
@@ -44,6 +53,23 @@ public CryptoFileSystemImpl create(CryptoFileSystemProvider provider, Path pathT
4453
throw new IOException("Error during file system creation.", e);
4554
}
4655
}
56+
57+
private CryptoFileSystemProperties adjustForCapabilities(Path pathToVault, CryptoFileSystemProperties originalProperties) throws FileSystemCapabilityChecker.MissingCapabilityException {
58+
if (!originalProperties.readonly()) {
59+
try {
60+
capabilityChecker.assertWriteAccess(pathToVault);
61+
return originalProperties;
62+
} catch (FileSystemCapabilityChecker.MissingCapabilityException e) {
63+
capabilityChecker.assertReadAccess(pathToVault);
64+
LOG.warn("No write access to vault. Fallback to read-only access.");
65+
Set<CryptoFileSystemProperties.FileSystemFlags> flags = EnumSet.copyOf(originalProperties.flags());
66+
flags.add(CryptoFileSystemProperties.FileSystemFlags.READONLY);
67+
return CryptoFileSystemProperties.cryptoFileSystemPropertiesFrom(originalProperties).withFlags(flags).build();
68+
}
69+
} else {
70+
return originalProperties;
71+
}
72+
}
4773

4874
public void remove(CryptoFileSystemImpl cryptoFileSystem) {
4975
fileSystems.values().remove(cryptoFileSystem);

src/main/java/org/cryptomator/cryptofs/ReadonlyFlag.java

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -18,13 +18,10 @@ public class ReadonlyFlag {
1818
private final boolean readonly;
1919

2020
@Inject
21-
public ReadonlyFlag(CryptoFileSystemProperties properties, @PathToVault Path pathToVault) {
21+
public ReadonlyFlag(CryptoFileSystemProperties properties) {
2222
if (properties.readonly()) {
2323
LOG.info("Vault opened readonly.");
2424
readonly = true;
25-
} else if (!Files.isWritable(pathToVault)) {
26-
LOG.warn("Vault directory is write-protected.");
27-
readonly = true;
2825
} else {
2926
LOG.debug("Vault opened for read and write.");
3027
readonly = false;

src/main/java/org/cryptomator/cryptofs/attr/AttributeViewProvider.java

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,8 @@
88
*******************************************************************************/
99
package org.cryptomator.cryptofs.attr;
1010

11-
import org.cryptomator.cryptofs.CryptoFileSystemComponent;
12-
import org.cryptomator.cryptofs.CryptoPath;
1311
import org.cryptomator.cryptofs.CryptoFileSystemScoped;
12+
import org.cryptomator.cryptofs.CryptoPath;
1413
import org.slf4j.Logger;
1514
import org.slf4j.LoggerFactory;
1615

src/main/java/org/cryptomator/cryptofs/common/FileSystemCapabilityChecker.java

Lines changed: 65 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
import org.slf4j.LoggerFactory;
99

1010
import java.io.IOException;
11+
import java.nio.file.DirectoryStream;
1112
import java.nio.file.FileSystemException;
1213
import java.nio.file.Files;
1314
import java.nio.file.Path;
@@ -17,13 +18,27 @@ public class FileSystemCapabilityChecker {
1718
private static final Logger LOG = LoggerFactory.getLogger(FileSystemCapabilityChecker.class);
1819

1920
public enum Capability {
21+
/**
22+
* File system allows read access
23+
* @since 1.9.3
24+
*/
25+
READ_ACCESS,
26+
27+
/**
28+
* File system allows write access
29+
* @since 1.9.3
30+
*/
31+
WRITE_ACCESS,
32+
2033
/**
2134
* File system supports filenames with ≥ 230 chars.
35+
* @since @since 1.9.2
2236
*/
2337
LONG_FILENAMES,
2438

2539
/**
2640
* File system supports paths with ≥ 400 chars.
41+
* @since @since 1.9.2
2742
*/
2843
LONG_PATHS,
2944
}
@@ -36,38 +51,78 @@ public enum Capability {
3651
* @implNote Only short-running tests with constant time are performed
3752
* @since 1.9.2
3853
*/
39-
public void checkCapabilities(Path pathToVault) throws MissingCapabilityException {
54+
public void assertAllCapabilities(Path pathToVault) throws MissingCapabilityException {
55+
assertReadAccess(pathToVault);
56+
assertWriteAccess(pathToVault);
57+
assertLongFilenameSupport(pathToVault);
58+
assertLongFilePathSupport(pathToVault);
59+
}
60+
61+
/**
62+
* Checks whether the underlying filesystem allows reading the given dir.
63+
* @param pathToVault Path to a vault's storage location
64+
* @throws MissingCapabilityException if the check fails
65+
* @since 1.9.3
66+
*/
67+
public void assertReadAccess(Path pathToVault) throws MissingCapabilityException {
68+
try (DirectoryStream ds = Files.newDirectoryStream(pathToVault)) {
69+
assert ds != null;
70+
} catch (IOException e) {
71+
throw new MissingCapabilityException(pathToVault, Capability.READ_ACCESS);
72+
}
73+
}
74+
75+
/**
76+
* Checks whether the underlying filesystem allows writing to the given dir.
77+
* @param pathToVault Path to a vault's storage location
78+
* @throws MissingCapabilityException if the check fails
79+
* @since 1.9.3
80+
*/
81+
public void assertWriteAccess(Path pathToVault) throws MissingCapabilityException {
4082
Path checkDir = pathToVault.resolve("c");
4183
try {
42-
checkLongFilenames(checkDir);
43-
checkLongFilePaths(checkDir);
84+
Files.createDirectory(checkDir);
85+
} catch (IOException e) {
86+
throw new MissingCapabilityException(checkDir, Capability.WRITE_ACCESS);
4487
} finally {
45-
try {
46-
MoreFiles.deleteRecursively(checkDir, RecursiveDeleteOption.ALLOW_INSECURE);
47-
} catch (IOException e) {
48-
LOG.warn("Failed to clean up " + checkDir, e);
49-
}
88+
deleteSilently(checkDir);
5089
}
5190
}
5291

53-
private void checkLongFilenames(Path checkDir) throws MissingCapabilityException {
92+
public void assertLongFilenameSupport(Path pathToVault) throws MissingCapabilityException {
5493
String longFileName = Strings.repeat("a", 226) + ".c9r";
94+
Path checkDir = pathToVault.resolve("c");
5595
Path p = checkDir.resolve(longFileName);
5696
try {
5797
Files.createDirectories(p);
5898
} catch (IOException e) {
5999
throw new MissingCapabilityException(p, Capability.LONG_FILENAMES);
100+
} finally {
101+
deleteSilently(checkDir);
60102
}
61103
}
62104

63-
private void checkLongFilePaths(Path checkDir) throws MissingCapabilityException {
105+
public void assertLongFilePathSupport(Path pathToVault) throws MissingCapabilityException {
64106
String longFileName = Strings.repeat("a", 96) + ".c9r";
65107
String longPath = Joiner.on('/').join(longFileName, longFileName, longFileName, longFileName);
108+
Path checkDir = pathToVault.resolve("c");
66109
Path p = checkDir.resolve(longPath);
67110
try {
68111
Files.createDirectories(p);
69112
} catch (IOException e) {
70113
throw new MissingCapabilityException(p, Capability.LONG_PATHS);
114+
} finally {
115+
deleteSilently(checkDir);
116+
}
117+
}
118+
119+
private void deleteSilently(Path dir) {
120+
try {
121+
if (Files.exists(dir)) {
122+
MoreFiles.deleteRecursively(dir, RecursiveDeleteOption.ALLOW_INSECURE);
123+
}
124+
} catch (IOException e) {
125+
LOG.warn("Failed to clean up " + dir, e);
71126
}
72127
}
73128

src/main/java/org/cryptomator/cryptofs/migration/Migrators.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -94,7 +94,7 @@ public boolean needsMigration(Path pathToVault, String masterkeyFilename) throws
9494
* @throws IOException if an I/O error occurs migrating the vault
9595
*/
9696
public void migrate(Path pathToVault, String masterkeyFilename, CharSequence passphrase, MigrationProgressListener progressListener) throws NoApplicableMigratorException, InvalidPassphraseException, IOException {
97-
fsCapabilityChecker.checkCapabilities(pathToVault);
97+
fsCapabilityChecker.assertAllCapabilities(pathToVault);
9898

9999
Path masterKeyPath = pathToVault.resolve(masterkeyFilename);
100100
byte[] keyFileContents = Files.readAllBytes(masterKeyPath);

0 commit comments

Comments
 (0)