fixed vault migration version 3 to 4: conflicting .lng files are now properly migrated

This commit is contained in:
Sebastian Stenzel
2017-10-18 12:35:20 +02:00
parent 69d379d03b
commit 95b8240a21
@@ -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);
}
}