Drops the unnecessary local DB update post-recompress, and associated tests.

This commit is contained in:
aureliandevel
2026-04-23 10:14:51 +10:00
parent 4d5bb90e4a
commit 575cd643ee
2 changed files with 0 additions and 191 deletions
@@ -115,7 +115,6 @@ namespace Duplicati.CommandLine.RecoveryTool
bool reencrypt = Library.Utility.Utility.ParseBoolOption(options, "reencrypt");
bool reupload = Library.Utility.Utility.ParseBoolOption(options, "reupload");
var fullyRewroteRemoteSet = reupload;
// Needs order (Files or Blocks) and Indexes as last because indexes content will be adjusted based on recompressed blocks
var files = remotefiles.Where(a => a.FileType == RemoteVolumeType.Files).ToArray();
@@ -124,10 +123,6 @@ namespace Duplicati.CommandLine.RecoveryTool
remotefiles = files.Concat(blocks).ToArray().Concat(indexes).ToArray();
Options updatedLocalDatabaseOptions = null;
if (reupload)
updatedLocalDatabaseOptions = new Options(BuildUpdatedRawOptions(m_Options, remotefiles, target_compr_module, reencrypt));
var retainedReuploadedBlockFiles = new List<string>();
Console.WriteLine("Found {0} files which belongs to backup with prefix {1}", remotefiles.Count(), m_Options.Prefix);
@@ -162,14 +157,12 @@ namespace Duplicati.CommandLine.RecoveryTool
else
{
Console.WriteLine(" - cannot detect compression type");
fullyRewroteRemoteSet = false;
continue;
}
if ((!reencrypt && File.Exists(localFileTarget)) || (reencrypt && File.Exists(localFileTarget + "." + localFileSourceEncryption)))
{
Console.WriteLine(" - target file already exist");
fullyRewroteRemoteSet = false;
continue;
}
@@ -305,7 +298,6 @@ namespace Duplicati.CommandLine.RecoveryTool
{
Console.WriteLine(" error: {0}", ex);
errors++;
fullyRewroteRemoteSet = false;
}
}
@@ -332,10 +324,7 @@ namespace Duplicati.CommandLine.RecoveryTool
Console.WriteLine("Download complete, of {0} remote files, {1} were downloaded with {2} errors", remotefiles.Count(), downloaded, errors);
if (needspass > 0)
{
Console.WriteLine("Additonally {0} remote files were skipped because of encryption, supply --passphrase to download those", needspass);
fullyRewroteRemoteSet = false;
}
if (errors > 0)
{
@@ -343,31 +332,10 @@ namespace Duplicati.CommandLine.RecoveryTool
return 200;
}
if (reupload && reuploaded > 0)
{
if (fullyRewroteRemoteSet && reuploaded == remotefiles.Length)
UpdateLocalDatabase(args[2], m_Options, updatedLocalDatabaseOptions);
else
Console.WriteLine("The local database was not updated because the reupload did not rewrite the full remote set.");
}
return 0;
}
}
private static void UpdateLocalDatabase(string backendUrl, Options originalOptions, Options updatedOptions)
{
var dbpath = CLIDatabaseLocator.GetDatabasePathForCLI(backendUrl, originalOptions, false, true);
if (string.IsNullOrWhiteSpace(dbpath) || !File.Exists(dbpath))
{
Console.WriteLine("The local database was not updated because no matching database file was found. Supply --dbpath to update it explicitly.");
return;
}
Duplicati.Library.Main.Utility.PersistOptionsToDatabaseWithoutValidation(dbpath, updatedOptions, "RecoveryTool Recompress", CancellationToken.None).Await();
Console.WriteLine("Updated stored backup options in local database: {0}", dbpath);
}
private static void RestoreOptionsFromLocalDatabaseIfAvailable(string backendUrl, Options options)
{
var dbpath = CLIDatabaseLocator.GetDatabasePathForCLI(backendUrl, options, false, false);
@@ -376,38 +344,5 @@ namespace Duplicati.CommandLine.RecoveryTool
Duplicati.Library.Main.Utility.UpdateOptionsFromDatabase(dbpath, options, "RecoveryTool Recompress", CancellationToken.None).Await();
}
private static Dictionary<string, string> BuildUpdatedRawOptions(Options originalOptions, IEnumerable<IParsedVolume> remoteFiles, string targetCompressionModule, bool reencrypt)
{
var updatedOptions = new Dictionary<string, string>(originalOptions.RawOptions);
updatedOptions["compression-module"] = targetCompressionModule;
var encryptionModules = remoteFiles
.Select(volume => volume.EncryptionModule)
.Where(module => !string.IsNullOrWhiteSpace(module))
.Distinct(StringComparer.OrdinalIgnoreCase)
.ToArray();
if (reencrypt && encryptionModules.Length > 0)
{
if (encryptionModules.Length != 1)
throw new UserInformationException("Unable to update the local database because the rewritten remote set contains multiple encryption modules.", "RecoveryToolMultipleEncryptionModules");
updatedOptions.Remove("no-encryption");
updatedOptions["encryption-module"] = encryptionModules[0];
updatedOptions["passphrase"] = string.IsNullOrWhiteSpace(originalOptions.NewPassphrase)
? originalOptions.Passphrase
: originalOptions.NewPassphrase;
}
else
{
updatedOptions["no-encryption"] = bool.TrueString;
updatedOptions.Remove("encryption-module");
updatedOptions.Remove("passphrase");
}
updatedOptions.Remove("new-passphrase");
return updatedOptions;
}
}
}
-126
View File
@@ -298,131 +298,5 @@ namespace Duplicati.UnitTest
Assert.AreEqual(0, status);
}
[Test]
[Category("RecoveryTool")]
public async Task RecompressReuploadUpdatesLocalDbForNewPassphrase()
{
File.WriteAllText(Path.Combine(this.DATAFOLDER, "sample.txt"), "payload");
Dictionary<string, string> options = new Dictionary<string, string>(this.TestOptions);
options["prefix"] = "recompressprefix";
string backendURL = "file://" + this.TARGETFOLDER;
using (Controller c = new Controller(backendURL, options, null))
{
IBackupResults backupResults = c.Backup(new[] { this.DATAFOLDER });
Assert.AreEqual(0, backupResults.Errors.Count());
Assert.AreEqual(0, backupResults.Warnings.Count());
}
IDictionary<string, string> beforeOptions;
await using (var beforeUpdate = await LocalDatabase.CreateLocalDatabaseAsync(this.DBFILE, "before-recompress", true, null, System.Threading.CancellationToken.None))
beforeOptions = await beforeUpdate.GetDbOptions(System.Threading.CancellationToken.None);
int status = CommandLine.RecoveryTool.Program.Main(new[]
{
"recompress",
"zip",
backendURL,
this.RESTOREFOLDER,
"--reupload=true",
$"--dbpath={this.DBFILE}",
$"--passphrase={options["passphrase"]}",
"--reencrypt=true",
"--new-passphrase=654321"
});
Assert.AreEqual(0, status);
await using var afterUpdate = await LocalDatabase.CreateLocalDatabaseAsync(this.DBFILE, "after-recompress", true, null, System.Threading.CancellationToken.None);
var afterOptions = await afterUpdate.GetDbOptions(System.Threading.CancellationToken.None);
Assert.That(afterOptions["prefix"], Is.EqualTo("recompressprefix"));
Assert.That(afterOptions["compression-module"], Is.EqualTo("zip"));
Assert.That(afterOptions["encryption-module"], Is.EqualTo("aes"));
Assert.That(afterOptions["passphrase"], Is.Not.EqualTo(beforeOptions["passphrase"]));
}
[Test]
[Category("RecoveryTool")]
public async Task RecompressReuploadUpdatesLocalDbForRemovedEncryption()
{
File.WriteAllText(Path.Combine(this.DATAFOLDER, "sample.txt"), "payload");
Dictionary<string, string> options = new Dictionary<string, string>(this.TestOptions);
string backendURL = "file://" + this.TARGETFOLDER;
using (Controller c = new Controller(backendURL, options, null))
{
IBackupResults backupResults = c.Backup(new[] { this.DATAFOLDER });
Assert.AreEqual(0, backupResults.Errors.Count());
Assert.AreEqual(0, backupResults.Warnings.Count());
}
int status = CommandLine.RecoveryTool.Program.Main(new[]
{
"recompress",
"zip",
backendURL,
this.RESTOREFOLDER,
"--reupload=true",
$"--dbpath={this.DBFILE}",
$"--passphrase={options["passphrase"]}"
});
Assert.AreEqual(0, status);
await using var db = await LocalDatabase.CreateLocalDatabaseAsync(this.DBFILE, "after-remove-encryption", true, null, System.Threading.CancellationToken.None);
var storedOptions = await db.GetDbOptions(System.Threading.CancellationToken.None);
Assert.That(storedOptions["compression-module"], Is.EqualTo("zip"));
Assert.That(storedOptions["passphrase"], Is.EqualTo("no-encryption"));
Assert.That(storedOptions.ContainsKey("encryption-module"), Is.False);
Assert.That(storedOptions.ContainsKey("passphrase-salt"), Is.False);
}
[Test]
[Category("RecoveryTool")]
public void RecompressReencryptFailsBeforeTouchingBackendWhenRemoteSetHasMixedEncryptionModules()
{
File.WriteAllText(Path.Combine(this.DATAFOLDER, "sample.txt"), "payload");
Dictionary<string, string> options = new Dictionary<string, string>(this.TestOptions);
string backendURL = "file://" + this.TARGETFOLDER;
using (Controller c = new Controller(backendURL, options, null))
{
IBackupResults backupResults = c.Backup(new[] { this.DATAFOLDER });
Assert.AreEqual(0, backupResults.Errors.Count());
Assert.AreEqual(0, backupResults.Warnings.Count());
}
var remoteFile = Directory.GetFiles(this.TARGETFOLDER, "*.aes").First();
var renamedRemoteFile = remoteFile.Substring(0, remoteFile.Length - ".aes".Length) + ".gpg";
File.Move(remoteFile, renamedRemoteFile);
var backendFilesBeforeRun = Directory.GetFiles(this.TARGETFOLDER)
.Select(Path.GetFileName)
.OrderBy(name => name, StringComparer.Ordinal)
.ToArray();
int status = CommandLine.RecoveryTool.Program.Main(new[]
{
"recompress",
"zip",
backendURL,
this.RESTOREFOLDER,
"--reupload=true",
"--reencrypt=true",
$"--passphrase={options["passphrase"]}"
});
Assert.AreEqual(200, status);
var backendFilesAfterRun = Directory.GetFiles(this.TARGETFOLDER)
.Select(Path.GetFileName)
.OrderBy(name => name, StringComparer.Ordinal)
.ToArray();
Assert.That(backendFilesAfterRun, Is.EqualTo(backendFilesBeforeRun));
}
}
}