diff --git a/main/filesystem-crypto/pom.xml b/main/filesystem-crypto/pom.xml
index 1897ef0c9..403777a29 100644
--- a/main/filesystem-crypto/pom.xml
+++ b/main/filesystem-crypto/pom.xml
@@ -19,7 +19,7 @@
1.51
- 1.0.2
+ 1.0.4
diff --git a/main/pom.xml b/main/pom.xml
index 321c0122e..cfb5ace1a 100644
--- a/main/pom.xml
+++ b/main/pom.xml
@@ -43,13 +43,6 @@
2.4
-
-
- jitpack.io
- https://jitpack.io
-
-
-
diff --git a/main/ui/src/main/java/org/cryptomator/ui/model/UpgradeVersion3to4.java b/main/ui/src/main/java/org/cryptomator/ui/model/UpgradeVersion3to4.java
index f660ae7d3..45c3a9ff6 100644
--- a/main/ui/src/main/java/org/cryptomator/ui/model/UpgradeVersion3to4.java
+++ b/main/ui/src/main/java/org/cryptomator/ui/model/UpgradeVersion3to4.java
@@ -2,8 +2,13 @@ package org.cryptomator.ui.model;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
+import java.nio.file.FileVisitResult;
+import java.nio.file.FileVisitor;
import java.nio.file.Files;
import java.nio.file.Path;
+import java.nio.file.attribute.BasicFileAttributes;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
import javax.inject.Inject;
import javax.inject.Provider;
@@ -19,6 +24,8 @@ import org.slf4j.LoggerFactory;
class UpgradeVersion3to4 extends UpgradeStrategy {
private static final Logger LOG = LoggerFactory.getLogger(UpgradeVersion3to4.class);
+ private static final Pattern BASE32_FOLLOWED_BY_UNDERSCORE_PATTERN = Pattern.compile("^(([A-Z2-7]{8})*[A-Z2-7=]{8})_");
+ private static final int FILE_MIN_SIZE = 88; // vault version 3 files have a header of 88 bytes (assuming no chunks at all)
@Inject
public UpgradeVersion3to4(Provider cryptorProvider, Localization localization) {
@@ -32,7 +39,61 @@ class UpgradeVersion3to4 extends UpgradeStrategy {
@Override
protected void upgrade(Vault vault, Cryptor cryptor) throws UpgradeFailedException {
- throw new UpgradeFailedException("not yet implemented");
+ Path dataDir = vault.path().get().resolve("d");
+ if (!Files.isDirectory(dataDir)) {
+ return; // empty vault. no migration needed.
+ }
+ try {
+ Files.walkFileTree(dataDir, new FileVisitor() {
+
+ @Override
+ public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs) throws IOException {
+ return FileVisitResult.CONTINUE;
+ }
+
+ @Override
+ public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
+ migrate(file, attrs);
+ return FileVisitResult.CONTINUE;
+ }
+
+ @Override
+ public FileVisitResult visitFileFailed(Path file, IOException exc) throws IOException {
+ throw exc;
+ }
+
+ @Override
+ public FileVisitResult postVisitDirectory(Path dir, IOException exc) throws IOException {
+ return FileVisitResult.CONTINUE;
+ }
+
+ });
+ } catch (IOException e) {
+ LOG.error("Migration failed.", e);
+ throw new UpgradeFailedException(localization.getString("upgrade.version3to4.err.io"));
+ }
+ LOG.info("Migration finished.");
+ }
+
+ private void migrate(Path file, BasicFileAttributes attrs) throws IOException {
+ String name = file.getFileName().toString();
+ long size = attrs.size();
+ Matcher m = BASE32_FOLLOWED_BY_UNDERSCORE_PATTERN.matcher(name);
+ if (m.find(0) && size < FILE_MIN_SIZE) {
+ String base32 = m.group(1);
+ String suffix = name.substring(m.end());
+ String renamed = "0" + base32 + (suffix.isEmpty() ? "" : " " + suffix);
+ renameWithoutOverwriting(file, renamed);
+ }
+ }
+
+ private void renameWithoutOverwriting(Path path, String newName) throws IOException {
+ Path newPath = path.resolveSibling(newName);
+ for (int i = 2; Files.exists(newPath); i++) {
+ newPath = path.resolveSibling(newName + " " + i);
+ }
+ Files.move(path, newPath);
+ LOG.info("Renaming {} to {}", path, newPath.getFileName());
}
@Override
diff --git a/main/ui/src/main/resources/localization/en.txt b/main/ui/src/main/resources/localization/en.txt
index 489b0861e..a108831f7 100644
--- a/main/ui/src/main/resources/localization/en.txt
+++ b/main/ui/src/main/resources/localization/en.txt
@@ -26,7 +26,7 @@ initialize.label.password=Password
initialize.label.retypePassword=Retype password
initialize.button.ok=Create vault
initialize.messageLabel.alreadyInitialized=Vault already initialized
-initialize.messageLabel.initializationFailed=Could not initialize vault. See logfile for details.
+initialize.messageLabel.initializationFailed=Could not initialize vault. See log file for details.
initialize.messageLabel.passwordStrength.0=Very weak
initialize.messageLabel.passwordStrength.1=Weak
initialize.messageLabel.passwordStrength.2=Fair
@@ -44,7 +44,7 @@ upgrade.version3dropBundleExtension.msg=This vault needs to be migrated to a new
upgrade.version3dropBundleExtension.err.alreadyExists=Automatic migration failed.\n"%s" already exists.
upgrade.version3to4.msg=This vault needs to be migrated to a newer format.\nEncrypted folder names will be updated.\nPlease make sure synchronization has finished before proceeding.
-
+upgrade.version3to4.err.io=Migration failed due to an I/O Exception. See log file for details.
# unlock.fxml
unlock.label.password=Password
@@ -57,7 +57,7 @@ unlock.button.advancedOptions.show=More options
unlock.button.advancedOptions.hide=Less options
unlock.choicebox.winDriveLetter.auto=Assign automatically
unlock.errorMessage.wrongPassword=Wrong password
-unlock.errorMessage.mountingFailed=Mounting failed. See logfile for details.
+unlock.errorMessage.mountingFailed=Mounting failed. See log file for details.
unlock.errorMessage.unsupportedVersion.vaultOlderThanSoftware=Unsupported vault. This vault has been created with an older version of Cryptomator.
unlock.errorMessage.unsupportedVersion.softwareOlderThanVault=Unsupported vault. This vault has been created with a newer version of Cryptomator.
unlock.messageLabel.startServerFailed=Starting WebDAV server failed.