Skip to content

Commit

Permalink
Updated FileSystemCapabilityChecker API
Browse files Browse the repository at this point in the history
(related to #102)
  • Loading branch information
overheadhunter committed Apr 16, 2021
1 parent 16695e9 commit bbc3c86
Show file tree
Hide file tree
Showing 4 changed files with 35 additions and 13 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
/**
* Indicates that an operation failed, as it would result in a ciphertext path that is too long for the underlying file system.
*
* @see org.cryptomator.cryptofs.common.FileSystemCapabilityChecker#determineSupportedFileNameLength(Path)
* @see org.cryptomator.cryptofs.common.FileSystemCapabilityChecker#determineSupportedCleartextFileNameLength(Path)
* @since 2.0.0
*/
public class FileNameTooLongException extends FileSystemException {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -93,16 +93,24 @@ public void assertWriteAccess(Path pathToVault) throws MissingCapabilityExceptio
}
}

public int determineSupportedCleartextFileNameLength(Path pathToVault) throws IOException {
int maxCiphertextLen = determineSupportedCiphertextFileNameLength(pathToVault);
assert maxCiphertextLen >= MIN_CIPHERTEXT_NAME_LENGTH;
// math explained in https://github.com/cryptomator/cryptofs/issues/60#issuecomment-523238303;
// subtract 4 for file extension, base64-decode, subtract 16 for IV
return (maxCiphertextLen - 4) / 4 * 3 - 16;
}

/**
* Determinse the number of chars a ciphertext filename (including its extension) is allowed to have inside a vault's <code>d/XX/YYYYYYYYYYYYYYYYYYYYYYYYYYYYYY/</code> directory.
*
* @param pathToVault Path to the vault
* @return Number of chars a .c9r file is allowed to have
* @throws IOException If unable to perform this check
*/
public int determineSupportedFileNameLength(Path pathToVault) throws IOException {
public int determineSupportedCiphertextFileNameLength(Path pathToVault) throws IOException {
int subPathLength = MAX_ADDITIONAL_PATH_LENGTH - 2; // subtract "c/"
return determineSupportedFileNameLength(pathToVault.resolve("c"), subPathLength, MIN_CIPHERTEXT_NAME_LENGTH, MAX_CIPHERTEXT_NAME_LENGTH);
return determineSupportedCiphertextFileNameLength(pathToVault.resolve("c"), subPathLength, MIN_CIPHERTEXT_NAME_LENGTH, MAX_CIPHERTEXT_NAME_LENGTH);
}

/**
Expand All @@ -115,7 +123,7 @@ public int determineSupportedFileNameLength(Path pathToVault) throws IOException
* @return The supported filename length inside a subdirectory of <code>dir</code> with <code>subPathLength</code> chars
* @throws IOException If unable to perform this check
*/
public int determineSupportedFileNameLength(Path dir, int subPathLength, int minFileNameLength, int maxFileNameLength) throws IOException {
public int determineSupportedCiphertextFileNameLength(Path dir, int subPathLength, int minFileNameLength, int maxFileNameLength) throws IOException {
Preconditions.checkArgument(subPathLength >= 6, "subPathLength must be larger than charcount(a/nnn/)");
Preconditions.checkArgument(minFileNameLength > 0);
Preconditions.checkArgument(maxFileNameLength <= 999);
Expand All @@ -130,13 +138,13 @@ public int determineSupportedFileNameLength(Path dir, int subPathLength, int min
throw new IOException("Unable to read dir");
}
// perform actual check:
return determineSupportedFileNameLength(fillerDir, minFileNameLength, maxFileNameLength + 1);
return determineSupportedCiphertextFileNameLength(fillerDir, minFileNameLength, maxFileNameLength + 1);
} finally {
deleteRecursivelySilently(fillerDir);
}
}

private int determineSupportedFileNameLength(Path p, int lowerBoundIncl, int upperBoundExcl) {
private int determineSupportedCiphertextFileNameLength(Path p, int lowerBoundIncl, int upperBoundExcl) {
assert lowerBoundIncl < upperBoundExcl;
int mid = (lowerBoundIncl + upperBoundExcl) / 2;
assert mid < upperBoundExcl;
Expand All @@ -145,9 +153,9 @@ private int determineSupportedFileNameLength(Path p, int lowerBoundIncl, int upp
}
assert lowerBoundIncl < mid;
if (canHandleFileNameLength(p, mid)) {
return determineSupportedFileNameLength(p, mid, upperBoundExcl);
return determineSupportedCiphertextFileNameLength(p, mid, upperBoundExcl);
} else {
return determineSupportedFileNameLength(p, lowerBoundIncl, mid);
return determineSupportedCiphertextFileNameLength(p, lowerBoundIncl, mid);
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ public void migrate(Path vaultRoot, String vaultConfigFilename, String masterkey
LOG.info("Backed up masterkey from {} to {}.", masterkeyFile.getFileName(), masterkeyBackupFile.getFileName());

// check file system capabilities:
int filenameLengthLimit = new FileSystemCapabilityChecker().determineSupportedFileNameLength(vaultRoot.resolve("c"), 46, 28, 220);
int filenameLengthLimit = new FileSystemCapabilityChecker().determineSupportedCiphertextFileNameLength(vaultRoot.resolve("c"), 46, 28, 220);
int pathLengthLimit = filenameLengthLimit + 48; // TODO
PreMigrationVisitor preMigrationVisitor;
if (filenameLengthLimit >= 220) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,13 @@
import org.cryptomator.cryptofs.mocks.DirectoryStreamMock;
import org.cryptomator.cryptofs.mocks.SeekableByteChannelMock;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Nested;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.TestInstance;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.CsvSource;
import org.mockito.Mockito;

import java.io.IOException;
Expand Down Expand Up @@ -62,7 +63,7 @@ public void testUnlimitedLength() throws IOException {
return checkDirMock;
});

int determinedLimit = new FileSystemCapabilityChecker().determineSupportedFileNameLength(pathToVault);
int determinedLimit = new FileSystemCapabilityChecker().determineSupportedCiphertextFileNameLength(pathToVault);

Assertions.assertEquals(220, determinedLimit);
}
Expand Down Expand Up @@ -95,7 +96,7 @@ public void testLimitedLengthDuringDirListing() throws IOException {
return checkDirMock;
});

int determinedLimit = new FileSystemCapabilityChecker().determineSupportedFileNameLength(pathToVault);
int determinedLimit = new FileSystemCapabilityChecker().determineSupportedCiphertextFileNameLength(pathToVault);

Assertions.assertEquals(limit, determinedLimit);
}
Expand Down Expand Up @@ -125,10 +126,23 @@ public void testLimitedLengthDuringFileCreation() throws IOException {
return checkDirMock;
});

int determinedLimit = new FileSystemCapabilityChecker().determineSupportedFileNameLength(pathToVault);
int determinedLimit = new FileSystemCapabilityChecker().determineSupportedCiphertextFileNameLength(pathToVault);

Assertions.assertEquals(limit, determinedLimit);
}

@DisplayName("determineSupportedCleartextFileNameLength(...)")
@ParameterizedTest(name = "ciphertext length {0} -> cleartext length {1}")
@CsvSource({"220, 146", "219, 143", "218, 143", "217, 143", "216, 143", "215, 140"})
public void testDetermineSupportedCleartextFileNameLength(int ciphertextLimit, int expectedCleartextLimit) throws IOException {
Path path = Mockito.mock(Path.class);
FileSystemCapabilityChecker checker = Mockito.spy(new FileSystemCapabilityChecker());
Mockito.doReturn(ciphertextLimit).when(checker).determineSupportedCiphertextFileNameLength(path);

int result = checker.determineSupportedCleartextFileNameLength(path);

Assertions.assertEquals(expectedCleartextLimit, result);
}

}

Expand Down

0 comments on commit bbc3c86

Please sign in to comment.