1
1
package org .cryptomator .cryptofs ;
2
2
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 ;
6
8
9
+ import javax .inject .Inject ;
7
10
import java .io .IOException ;
8
11
import java .nio .ByteBuffer ;
9
12
import java .nio .channels .ReadableByteChannel ;
15
18
import java .util .regex .Matcher ;
16
19
import java .util .regex .Pattern ;
17
20
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 ;
24
23
25
24
@ CryptoFileSystemScoped
26
25
class ConflictResolver {
27
26
28
27
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}" );
30
29
private static final int MAX_DIR_FILE_SIZE = 87 ; // "normal" file header has 88 bytes
31
30
32
31
private final LongFileNameProvider longFileNameProvider ;
@@ -51,10 +50,10 @@ public ConflictResolver(LongFileNameProvider longFileNameProvider, Cryptor crypt
51
50
public Path resolveConflictsIfNecessary (Path ciphertextPath , String dirId ) throws IOException {
52
51
String ciphertextFileName = ciphertextPath .getFileName ().toString ();
53
52
String basename = StringUtils .removeEnd (ciphertextFileName , LONG_NAME_FILE_EXT );
54
- Matcher m = BASE32_PATTERN .matcher (basename );
53
+ Matcher m = CIPHERTEXT_FILENAME_PATTERN .matcher (basename );
55
54
if (!m .matches () && m .find (0 )) {
56
55
// 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 );
58
57
} else {
59
58
// full match or no match at all -> nothing to resolve
60
59
return ciphertextPath ;
@@ -65,35 +64,35 @@ public Path resolveConflictsIfNecessary(Path ciphertextPath, String dirId) throw
65
64
* Resolves a conflict.
66
65
*
67
66
* @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.
69
68
* @param dirId The directory id of the file's parent directory.
70
69
* @return The new path of the conflicting file after the conflict has been resolved.
71
70
* @throws IOException
72
71
*/
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 );
86
83
} 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 );
91
86
}
92
87
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 )) {
94
93
return canonicalPath ;
95
94
} else {
96
- return renameConflictingFile (canonicalPath , conflictingPath , ciphertext , dirId , dirPrefix );
95
+ return renameConflictingFile (canonicalPath , conflictingPath , ciphertext , dirId , type . getPrefix () );
97
96
}
98
97
}
99
98
0 commit comments