Skip to content

Commit 20e00a0

Browse files
Merge branch 'release/1.8.3'
2 parents 06cf5fb + 4e27d7a commit 20e00a0

27 files changed

+256
-156
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.8.2</version>
5+
<version>1.8.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>
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
package org.cryptomator.cryptofs;
2+
3+
import java.util.Arrays;
4+
import java.util.function.Predicate;
5+
import java.util.stream.Stream;
6+
7+
/**
8+
* Filename prefix as defined <a href="https://github.com/cryptomator/cryptofs/issues/38">issue 38</a>.
9+
*/
10+
public enum CiphertextFileType {
11+
FILE(""), DIRECTORY("0"), SYMLINK("1S");
12+
13+
private final String prefix;
14+
15+
CiphertextFileType(String prefix) {
16+
this.prefix = prefix;
17+
}
18+
19+
public String getPrefix() {
20+
return prefix;
21+
}
22+
23+
public boolean isTypeOfFile(String filename) {
24+
return filename.startsWith(prefix);
25+
}
26+
27+
public static CiphertextFileType forFileName(String filename) {
28+
return nonTrivialValues().filter(type -> type.isTypeOfFile(filename)).findAny().orElse(CiphertextFileType.FILE);
29+
}
30+
31+
public static Stream<CiphertextFileType> nonTrivialValues() {
32+
Predicate<CiphertextFileType> isTrivial = FILE::equals;
33+
return Arrays.stream(values()).filter(isTrivial.negate());
34+
}
35+
}

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

Lines changed: 31 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,12 @@
11
package org.cryptomator.cryptofs;
22

3-
import static org.cryptomator.cryptofs.Constants.DIR_PREFIX;
4-
import static org.cryptomator.cryptofs.Constants.SHORT_NAMES_MAX_LENGTH;
5-
import static org.cryptomator.cryptofs.LongFileNameProvider.LONG_NAME_FILE_EXT;
3+
import com.google.common.base.Preconditions;
4+
import org.cryptomator.cryptolib.api.AuthenticationFailedException;
5+
import org.cryptomator.cryptolib.api.Cryptor;
6+
import org.slf4j.Logger;
7+
import org.slf4j.LoggerFactory;
68

9+
import javax.inject.Inject;
710
import java.io.IOException;
811
import java.nio.ByteBuffer;
912
import java.nio.channels.ReadableByteChannel;
@@ -15,18 +18,14 @@
1518
import java.util.regex.Matcher;
1619
import java.util.regex.Pattern;
1720

18-
import javax.inject.Inject;
19-
20-
import org.cryptomator.cryptolib.api.AuthenticationFailedException;
21-
import org.cryptomator.cryptolib.api.Cryptor;
22-
import org.slf4j.Logger;
23-
import org.slf4j.LoggerFactory;
21+
import static org.cryptomator.cryptofs.Constants.SHORT_NAMES_MAX_LENGTH;
22+
import static org.cryptomator.cryptofs.LongFileNameProvider.LONG_NAME_FILE_EXT;
2423

2524
@CryptoFileSystemScoped
2625
class ConflictResolver {
2726

2827
private static final Logger LOG = LoggerFactory.getLogger(ConflictResolver.class);
29-
private static final Pattern BASE32_PATTERN = Pattern.compile("(0|1[A-Z0-9])?(([A-Z2-7]{8})*[A-Z2-7=]{8})");
28+
private static final Pattern CIPHERTEXT_FILENAME_PATTERN = Pattern.compile("(0|1[A-Z0-9])?([A-Z2-7]{8})*[A-Z2-7=]{8}");
3029
private static final int MAX_DIR_FILE_SIZE = 87; // "normal" file header has 88 bytes
3130

3231
private final LongFileNameProvider longFileNameProvider;
@@ -51,10 +50,10 @@ public ConflictResolver(LongFileNameProvider longFileNameProvider, Cryptor crypt
5150
public Path resolveConflictsIfNecessary(Path ciphertextPath, String dirId) throws IOException {
5251
String ciphertextFileName = ciphertextPath.getFileName().toString();
5352
String basename = StringUtils.removeEnd(ciphertextFileName, LONG_NAME_FILE_EXT);
54-
Matcher m = BASE32_PATTERN.matcher(basename);
53+
Matcher m = CIPHERTEXT_FILENAME_PATTERN.matcher(basename);
5554
if (!m.matches() && m.find(0)) {
5655
// no full match, but still contains base32 -> partial match
57-
return resolveConflict(ciphertextPath, m.group(2), dirId);
56+
return resolveConflict(ciphertextPath, m.group(0), dirId);
5857
} else {
5958
// full match or no match at all -> nothing to resolve
6059
return ciphertextPath;
@@ -65,35 +64,35 @@ public Path resolveConflictsIfNecessary(Path ciphertextPath, String dirId) throw
6564
* Resolves a conflict.
6665
*
6766
* @param conflictingPath The path of a file containing a valid base 32 part.
68-
* @param base32match The base32 part inside the filename of the conflicting file.
67+
* @param ciphertextFileName The base32 part inside the filename of the conflicting file.
6968
* @param dirId The directory id of the file's parent directory.
7069
* @return The new path of the conflicting file after the conflict has been resolved.
7170
* @throws IOException
7271
*/
73-
private Path resolveConflict(Path conflictingPath, String base32match, String dirId) throws IOException {
74-
final Path directory = conflictingPath.getParent();
75-
final String originalFileName = conflictingPath.getFileName().toString();
76-
final String ciphertext;
77-
final boolean isDirectory;
78-
final String dirPrefix;
79-
final Path canonicalPath;
80-
if (longFileNameProvider.isDeflated(originalFileName)) {
81-
String inflated = longFileNameProvider.inflate(base32match + LONG_NAME_FILE_EXT);
82-
ciphertext = StringUtils.removeStart(inflated, DIR_PREFIX);
83-
isDirectory = inflated.startsWith(DIR_PREFIX);
84-
dirPrefix = isDirectory ? DIR_PREFIX : "";
85-
canonicalPath = directory.resolve(base32match + LONG_NAME_FILE_EXT);
72+
private Path resolveConflict(Path conflictingPath, String ciphertextFileName, String dirId) throws IOException {
73+
String conflictingFileName = conflictingPath.getFileName().toString();
74+
Preconditions.checkArgument(conflictingFileName.contains(ciphertextFileName), "%s does not contain %s", conflictingPath, ciphertextFileName);
75+
76+
Path parent = conflictingPath.getParent();
77+
String inflatedFileName;
78+
Path canonicalPath;
79+
if (longFileNameProvider.isDeflated(conflictingFileName)) {
80+
String deflatedName = ciphertextFileName + LONG_NAME_FILE_EXT;
81+
inflatedFileName = longFileNameProvider.inflate(deflatedName);
82+
canonicalPath = parent.resolve(deflatedName);
8683
} else {
87-
ciphertext = base32match;
88-
isDirectory = originalFileName.startsWith(DIR_PREFIX);
89-
dirPrefix = isDirectory ? DIR_PREFIX : "";
90-
canonicalPath = directory.resolve(dirPrefix + ciphertext);
84+
inflatedFileName = ciphertextFileName;
85+
canonicalPath = parent.resolve(ciphertextFileName);
9186
}
9287

93-
if (isDirectory && resolveDirectoryConflictTrivially(canonicalPath, conflictingPath)) {
88+
CiphertextFileType type = CiphertextFileType.forFileName(inflatedFileName);
89+
assert inflatedFileName.startsWith(type.getPrefix());
90+
String ciphertext = inflatedFileName.substring(type.getPrefix().length());
91+
92+
if (CiphertextFileType.DIRECTORY.equals(type) && resolveDirectoryConflictTrivially(canonicalPath, conflictingPath)) {
9493
return canonicalPath;
9594
} else {
96-
return renameConflictingFile(canonicalPath, conflictingPath, ciphertext, dirId, dirPrefix);
95+
return renameConflictingFile(canonicalPath, conflictingPath, ciphertext, dirId, type.getPrefix());
9796
}
9897
}
9998

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

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
*
66
* Contributors:
77
* Sebastian Stenzel - initial API and implementation
8-
*******************************************************************************/
8+
*******************************************************************************/
99
package org.cryptomator.cryptofs;
1010

1111
public final class Constants {
@@ -15,7 +15,6 @@ public final class Constants {
1515

1616
static final String DATA_DIR_NAME = "d";
1717
static final String METADATA_DIR_NAME = "m";
18-
static final String DIR_PREFIX = "0";
1918
static final int SHORT_NAMES_MAX_LENGTH = 129;
2019
static final String ROOT_DIR_ID = "";
2120

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

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,12 @@
88
*******************************************************************************/
99
package org.cryptomator.cryptofs;
1010

11+
import org.cryptomator.cryptofs.CryptoPathMapper.CiphertextDirectory;
12+
import org.cryptomator.cryptolib.api.AuthenticationFailedException;
13+
import org.cryptomator.cryptolib.api.FileNameCryptor;
14+
import org.slf4j.Logger;
15+
import org.slf4j.LoggerFactory;
16+
1117
import java.io.IOException;
1218
import java.nio.charset.StandardCharsets;
1319
import java.nio.file.DirectoryIteratorException;
@@ -21,12 +27,6 @@
2127
import java.util.stream.Stream;
2228
import java.util.stream.StreamSupport;
2329

24-
import org.cryptomator.cryptofs.CryptoPathMapper.CiphertextDirectory;
25-
import org.cryptomator.cryptolib.api.AuthenticationFailedException;
26-
import org.cryptomator.cryptolib.api.FileNameCryptor;
27-
import org.slf4j.Logger;
28-
import org.slf4j.LoggerFactory;
29-
3030
import static org.cryptomator.cryptofs.Constants.SHORT_NAMES_MAX_LENGTH;
3131

3232
class CryptoDirectoryStream implements DirectoryStream<Path> {
@@ -149,7 +149,7 @@ private ProcessedPaths inflatePermanently(ProcessedPaths paths, String longFileN
149149

150150
private boolean isBrokenDirectoryFile(ProcessedPaths paths) {
151151
Path potentialDirectoryFile = paths.getCiphertextPath();
152-
if (paths.getInflatedPath().getFileName().toString().startsWith(Constants.DIR_PREFIX)) {
152+
if (paths.getInflatedPath().getFileName().toString().startsWith(CiphertextFileType.DIRECTORY.getPrefix())) {
153153
final Path dirPath;
154154
try {
155155
dirPath = cryptoPathMapper.resolveDirectory(potentialDirectoryFile).path;

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

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,6 @@
99
package org.cryptomator.cryptofs;
1010

1111
import org.cryptomator.cryptofs.CryptoPathMapper.CiphertextDirectory;
12-
import org.cryptomator.cryptofs.CryptoPathMapper.CiphertextFileType;
1312
import org.cryptomator.cryptofs.attr.AttributeByNameProvider;
1413
import org.cryptomator.cryptofs.attr.AttributeProvider;
1514
import org.cryptomator.cryptofs.attr.AttributeViewProvider;

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

Lines changed: 0 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,6 @@
2828
import java.util.concurrent.ExecutionException;
2929

3030
import static org.cryptomator.cryptofs.Constants.DATA_DIR_NAME;
31-
import static org.cryptomator.cryptofs.Constants.DIR_PREFIX;
3231

3332
@CryptoFileSystemScoped
3433
public class CryptoPathMapper {
@@ -57,20 +56,6 @@ public class CryptoPathMapper {
5756
this.rootDirectory = resolveDirectory(Constants.ROOT_DIR_ID);
5857
}
5958

60-
public enum CiphertextFileType {
61-
FILE(""), DIRECTORY(DIR_PREFIX), SYMLINK("1S");
62-
63-
private final String prefix;
64-
65-
CiphertextFileType(String prefix) {
66-
this.prefix = prefix;
67-
}
68-
69-
public String getPrefix() {
70-
return prefix;
71-
}
72-
}
73-
7459
/**
7560
* Verifies that no node exists for the given path. Otherwise a {@link FileAlreadyExistsException} will be thrown.
7661
*

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

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
package org.cryptomator.cryptofs;
22

3-
import org.cryptomator.cryptofs.CryptoPathMapper.CiphertextFileType;
43
import org.cryptomator.cryptofs.fh.OpenCryptoFiles;
54

65
import javax.inject.Inject;

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

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
package org.cryptomator.cryptofs.attr;
1010

1111
import org.cryptomator.cryptofs.ArrayUtils;
12+
import org.cryptomator.cryptofs.CiphertextFileType;
1213
import org.cryptomator.cryptofs.CryptoPath;
1314
import org.cryptomator.cryptofs.CryptoPathMapper;
1415
import org.cryptomator.cryptofs.fh.OpenCryptoFiles;
@@ -48,7 +49,7 @@ protected Optional<OpenCryptoFile> getOpenCryptoFile() throws IOException {
4849
}
4950

5051
private Path getCiphertextPath(CryptoPath path) throws IOException {
51-
CryptoPathMapper.CiphertextFileType type = pathMapper.getCiphertextFileType(path);
52+
CiphertextFileType type = pathMapper.getCiphertextFileType(path);
5253
switch (type) {
5354
case SYMLINK:
5455
if (ArrayUtils.contains(linkOptions, LinkOption.NOFOLLOW_LINKS)) {

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

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
package org.cryptomator.cryptofs.attr;
1010

1111
import org.cryptomator.cryptofs.ArrayUtils;
12+
import org.cryptomator.cryptofs.CiphertextFileType;
1213
import org.cryptomator.cryptofs.CryptoFileSystemProperties;
1314
import org.cryptomator.cryptofs.CryptoPath;
1415
import org.cryptomator.cryptofs.CryptoPathMapper;
@@ -61,7 +62,7 @@ public <A extends BasicFileAttributes> A readAttributes(CryptoPath cleartextPath
6162
if (!ATTR_CONSTRUCTORS.containsKey(type)) {
6263
throw new UnsupportedOperationException("Unsupported file attribute type: " + type);
6364
}
64-
CryptoPathMapper.CiphertextFileType ciphertextFileType = pathMapper.getCiphertextFileType(cleartextPath);
65+
CiphertextFileType ciphertextFileType = pathMapper.getCiphertextFileType(cleartextPath);
6566
switch (ciphertextFileType) {
6667
case SYMLINK: {
6768
if (ArrayUtils.contains(options, LinkOption.NOFOLLOW_LINKS)) {
@@ -85,7 +86,7 @@ public <A extends BasicFileAttributes> A readAttributes(CryptoPath cleartextPath
8586
}
8687
}
8788

88-
private <A extends BasicFileAttributes> A readAttributes(CryptoPathMapper.CiphertextFileType ciphertextFileType, Path ciphertextPath, Class<A> type) throws IOException {
89+
private <A extends BasicFileAttributes> A readAttributes(CiphertextFileType ciphertextFileType, Path ciphertextPath, Class<A> type) throws IOException {
8990
assert ATTR_CONSTRUCTORS.containsKey(type);
9091
A ciphertextAttrs = Files.readAttributes(ciphertextPath, type);
9192
AttributesConstructor<A> constructor = (AttributesConstructor<A>) ATTR_CONSTRUCTORS.get(type);
@@ -94,7 +95,7 @@ private <A extends BasicFileAttributes> A readAttributes(CryptoPathMapper.Cipher
9495

9596
@FunctionalInterface
9697
private interface AttributesConstructor<A extends BasicFileAttributes> {
97-
A construct(A delegate, CryptoPathMapper.CiphertextFileType ciphertextFileType, Path ciphertextPath, Cryptor cryptor, Optional<OpenCryptoFile> openCryptoFile, boolean readonlyFileSystem);
98+
A construct(A delegate, CiphertextFileType ciphertextFileType, Path ciphertextPath, Cryptor cryptor, Optional<OpenCryptoFile> openCryptoFile, boolean readonlyFileSystem);
9899
}
99100

100101
}

0 commit comments

Comments
 (0)