From 95b8240a21a31ac671d84c38125e9eb684003b37 Mon Sep 17 00:00:00 2001 From: Sebastian Stenzel Date: Wed, 18 Oct 2017 12:35:20 +0200 Subject: [PATCH] fixed vault migration version 3 to 4: conflicting .lng files are now properly migrated --- .../ui/model/UpgradeVersion3to4.java | 54 ++++++++++++------- 1 file changed, 34 insertions(+), 20 deletions(-) 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 3dd4b6010..421eda002 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 @@ -42,9 +42,10 @@ class UpgradeVersion3to4 extends UpgradeStrategy { private static final Logger LOG = LoggerFactory.getLogger(UpgradeVersion3to4.class); private static final Pattern LVL1_DIR_PATTERN = Pattern.compile("[A-Z2-7]{2}"); private static final Pattern LVL2_DIR_PATTERN = Pattern.compile("[A-Z2-7]{30}"); - private static final Pattern BASE32_FOLLOWED_BY_UNDERSCORE_PATTERN = Pattern.compile("^(([A-Z2-7]{8})*[A-Z2-7=]{8})_"); + private static final Pattern BASE32_PATTERN = Pattern.compile("^(([A-Z2-7]{8})*[A-Z2-7=]{8})"); + private static final Pattern BASE32_FOLLOWED_BY_UNDERSCORE_PATTERN = Pattern.compile(BASE32_PATTERN.pattern() + "_"); private static final int FILE_MIN_SIZE = 88; // vault version 3 files have a header of 88 bytes (assuming no chunks at all) - private static final String LONG_FILENAME_SUFFIX = ".lng"; + private static final String LONG_FILENAME_EXT = ".lng"; private static final String OLD_FOLDER_SUFFIX = "_"; private static final String NEW_FOLDER_PREFIX = "0"; @@ -96,10 +97,12 @@ class UpgradeVersion3to4 extends UpgradeStrategy { @Override public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException { String name = file.getFileName().toString(); - if (name.endsWith(LONG_FILENAME_SUFFIX)) { + if (!attrs.isRegularFile() || attrs.size() > FILE_MIN_SIZE) { + LOG.trace("Skipping non-directory file {}.", file); + } else if (name.endsWith(LONG_FILENAME_EXT)) { migrateLong(metadataDir, file); } else { - migrate(file, attrs); + migrate(file); } return FileVisitResult.CONTINUE; } @@ -112,14 +115,13 @@ class UpgradeVersion3to4 extends UpgradeStrategy { LOG.info("Migration finished."); } - private void migrate(Path file, BasicFileAttributes attrs) throws IOException { + private void migrate(Path file) throws IOException { String name = file.getFileName().toString(); - long size = attrs.size(); Matcher m = BASE32_FOLLOWED_BY_UNDERSCORE_PATTERN.matcher(name); - if (attrs.isRegularFile() && m.find(0) && size < FILE_MIN_SIZE) { + if (m.find(0)) { String base32 = m.group(1); String suffix = name.substring(m.end()); - String renamed = NEW_FOLDER_PREFIX + base32 + (suffix.isEmpty() ? "" : " " + suffix); + String renamed = NEW_FOLDER_PREFIX + base32 + StringUtils.prependIfMissing(suffix, " "); renameWithoutOverwriting(file, renamed); } } @@ -135,22 +137,34 @@ class UpgradeVersion3to4 extends UpgradeStrategy { private void migrateLong(Path metadataDir, Path path) throws IOException { String oldName = path.getFileName().toString(); - Path oldMetadataFile = metadataDir.resolve(oldName.substring(0, 2)).resolve(oldName.substring(2, 4)).resolve(oldName); - if (Files.isRegularFile(oldMetadataFile)) { - String oldContent = new String(Files.readAllBytes(oldMetadataFile), UTF_8); - if (oldContent.endsWith(OLD_FOLDER_SUFFIX)) { - String newContent = NEW_FOLDER_PREFIX + StringUtils.removeEnd(oldContent, OLD_FOLDER_SUFFIX); - String newName = base32.encodeAsString(sha1.digest(newContent.getBytes(UTF_8))) + LONG_FILENAME_SUFFIX; + assert oldName.endsWith(LONG_FILENAME_EXT); + String oldNameBase = StringUtils.removeEnd(oldName, LONG_FILENAME_EXT); + + Matcher m = BASE32_PATTERN.matcher(oldNameBase); + if (m.find(0)) { + String oldNameBase32 = m.group(1); + String oldNameSuffix = oldNameBase.substring(m.end()); + String oldCanonicalName = oldNameBase32 + LONG_FILENAME_EXT; + + Path oldMetadataFile = metadataDir.resolve(oldCanonicalName.substring(0, 2)).resolve(oldCanonicalName.substring(2, 4)).resolve(oldCanonicalName); + if (!Files.isRegularFile(oldMetadataFile)) { + LOG.warn("Found uninflatable long file name. Expected: {}", oldMetadataFile); + return; + } + + String oldLongName = new String(Files.readAllBytes(oldMetadataFile), UTF_8); + if (oldLongName.endsWith(OLD_FOLDER_SUFFIX)) { + String newLongName = NEW_FOLDER_PREFIX + StringUtils.removeEnd(oldLongName, OLD_FOLDER_SUFFIX); + String newCanonicalBase32 = base32.encodeAsString(sha1.digest(newLongName.getBytes(UTF_8))); + String newCanonicalName = newCanonicalBase32 + LONG_FILENAME_EXT; + Path newMetadataFile = metadataDir.resolve(newCanonicalName.substring(0, 2)).resolve(newCanonicalName.substring(2, 4)).resolve(newCanonicalName); + String newName = newCanonicalBase32 + oldNameSuffix + LONG_FILENAME_EXT; Path newPath = path.resolveSibling(newName); - Path newMetadataFile = metadataDir.resolve(newName.substring(0, 2)).resolve(newName.substring(2, 4)).resolve(newName); Files.move(path, newPath); Files.createDirectories(newMetadataFile.getParent()); - Files.write(newMetadataFile, newContent.getBytes(UTF_8)); - Files.delete(oldMetadataFile); - LOG.info("Renaming {} to {}\nDeleting {}\nCreating {}", path, newName, oldMetadataFile, newMetadataFile); + Files.write(newMetadataFile, newLongName.getBytes(UTF_8)); + LOG.info("Renaming {} to {}\nCreating {}", path, newName, newMetadataFile); } - } else { - LOG.warn("Found uninflatable long file name. Expected: {}", oldMetadataFile); } }