diff --git a/BuildTools/LicenseUpdater/Program.cs b/BuildTools/LicenseUpdater/Program.cs index c69cfbaaa..007341537 100755 --- a/BuildTools/LicenseUpdater/Program.cs +++ b/BuildTools/LicenseUpdater/Program.cs @@ -37,7 +37,7 @@ var target_extensions = new[] { // ".css" }.ToHashSet(StringComparer.OrdinalIgnoreCase); -File.WriteAllText(Path.Combine(startpath, "LICENSE.txt"), Fragments.GetLicenseTextWithPrefixedLines(string.Empty)); +File.WriteAllText(Path.Combine(startpath, "LICENSE"), Fragments.GetLicenseTextWithPrefixedLines(string.Empty)); var candidates = Directory.EnumerateFiles(startpath, "*", SearchOption.AllDirectories) .Where(x => target_extensions.Contains(Path.GetExtension(x) ?? string.Empty)); diff --git a/Duplicati/Library/Main/Backend/BackendManager.cs b/Duplicati/Library/Main/Backend/BackendManager.cs index 20ded2a5f..3786ff52c 100644 --- a/Duplicati/Library/Main/Backend/BackendManager.cs +++ b/Duplicati/Library/Main/Backend/BackendManager.cs @@ -36,15 +36,6 @@ internal partial class BackendManager : IBackendManager /// private readonly Task queueRunner; - /// - /// The last file read size - /// - public long LastReadSize { get; private set; } - /// - /// The last file write size - /// - public long LastWriteSize { get; private set; } - /// /// The execution context /// @@ -171,8 +162,7 @@ internal partial class BackendManager : IBackendManager Decrypt = true }; await QueueTask(op).ConfigureAwait(false); - (var file, var _, var downloadSize) = await op.GetResult().ConfigureAwait(false); - LastReadSize = downloadSize; + (var file, var _, var _) = await op.GetResult().ConfigureAwait(false); return file; } @@ -192,8 +182,7 @@ internal partial class BackendManager : IBackendManager Decrypt = false }; await QueueTask(op).ConfigureAwait(false); - (var file, var _, var downloadSize) = await op.GetResult().ConfigureAwait(false); - LastReadSize = downloadSize; + (var file, var _, var _) = await op.GetResult().ConfigureAwait(false); return file; } @@ -226,7 +215,6 @@ internal partial class BackendManager : IBackendManager }; await QueueTask(op).ConfigureAwait(false); (var file, var downloadHash, var downloadSize) = await op.GetResult().ConfigureAwait(false); - LastReadSize = downloadSize; return (file, downloadHash, downloadSize); } diff --git a/Duplicati/Library/Main/Database/LocalBackupDatabase.cs b/Duplicati/Library/Main/Database/LocalBackupDatabase.cs index 5c0dae4a9..8e1918bcc 100644 --- a/Duplicati/Library/Main/Database/LocalBackupDatabase.cs +++ b/Duplicati/Library/Main/Database/LocalBackupDatabase.cs @@ -660,6 +660,15 @@ SELECT ""BlocklistHash"".""BlocksetID"" FROM ""BlocklistHash"" WHERE ""Blocklist base.Dispose(); } + public long GetLastWrittenDBlockVolumeSize(IDbTransaction? transaction) + { + using (var cmd = m_connection.CreateCommand(transaction)) + return cmd.SetCommandAndParameters(@"SELECT ""Size"" FROM ""RemoteVolume"" WHERE ""State"" = @State AND ""Type"" = @Type ORDER BY ""ID"" DESC LIMIT 1") + .SetParameterValue("@State", RemoteVolumeState.Uploaded.ToString()) + .SetParameterValue("@Type", RemoteVolumeType.Blocks.ToString()) + .ExecuteScalarInt64(-1); + } + private long GetPreviousFilesetID(IDbCommand cmd) { return GetPreviousFilesetID(cmd, OperationTimestamp, m_filesetId, cmd.Transaction); diff --git a/Duplicati/Library/Main/Database/LocalDatabase.cs b/Duplicati/Library/Main/Database/LocalDatabase.cs index 446fe87d5..8c56a5744 100644 --- a/Duplicati/Library/Main/Database/LocalDatabase.cs +++ b/Duplicati/Library/Main/Database/LocalDatabase.cs @@ -206,17 +206,17 @@ namespace Duplicati.Library.Main.Database return Library.Utility.Utility.EPOCH.AddSeconds(seconds); } - public void UpdateRemoteVolume(string name, RemoteVolumeState state, long size, string hash, IDbTransaction? transaction = null) + public void UpdateRemoteVolume(string name, RemoteVolumeState state, long size, string? hash, IDbTransaction? transaction = null) { UpdateRemoteVolume(name, state, size, hash, false, transaction); } - public void UpdateRemoteVolume(string name, RemoteVolumeState state, long size, string hash, bool suppressCleanup, IDbTransaction? transaction = null) + public void UpdateRemoteVolume(string name, RemoteVolumeState state, long size, string? hash, bool suppressCleanup, IDbTransaction? transaction = null) { UpdateRemoteVolume(name, state, size, hash, suppressCleanup, new TimeSpan(0), transaction); } - public void UpdateRemoteVolume(string name, RemoteVolumeState state, long size, string hash, bool suppressCleanup, TimeSpan deleteGraceTime, IDbTransaction? transaction = null) + public void UpdateRemoteVolume(string name, RemoteVolumeState state, long size, string? hash, bool suppressCleanup, TimeSpan deleteGraceTime, IDbTransaction? transaction = null) { m_updateremotevolumeCommand.Transaction = transaction; var c = m_updateremotevolumeCommand.SetParameterValue("@OperationID", m_operationid) @@ -391,7 +391,7 @@ namespace Duplicati.Library.Main.Database /// The operation performed /// The path involved /// Any data relating to the operation - public void LogRemoteOperation(string operation, string path, string data, IDbTransaction transaction) + public void LogRemoteOperation(string operation, string path, string? data, IDbTransaction? transaction) { m_insertremotelogCommand .SetParameterValue("@OperationID", m_operationid) @@ -1434,7 +1434,7 @@ AND oldVersion.FilesetID = (SELECT ID FROM Fileset WHERE ID != @FilesetId ORDER } } - public void RenameRemoteFile(string oldname, string newname, IDbTransaction transaction) + public void RenameRemoteFile(string oldname, string newname, IDbTransaction? transaction) { using (var tr = new TemporaryTransactionWrapper(m_connection, transaction)) using (var cmd = m_connection.CreateCommand(tr.Parent)) diff --git a/Duplicati/Library/Main/IBackendManager.cs b/Duplicati/Library/Main/IBackendManager.cs index 99c4104ba..380c2c5be 100644 --- a/Duplicati/Library/Main/IBackendManager.cs +++ b/Duplicati/Library/Main/IBackendManager.cs @@ -126,16 +126,6 @@ internal interface IBackendManager : IDisposable /// The downloaded files, hash, size, and name IAsyncEnumerable<(TempFile File, string Hash, long Size, string Name)> GetFilesOverlappedAsync(IEnumerable volumes, CancellationToken cancelToken); - /// - /// Gets the size of the last read operation - /// - long LastReadSize { get; } - - /// - /// Gets the size of the last write operation - /// - long LastWriteSize { get; } - /// /// Flushes the database messages to the database /// diff --git a/Duplicati/Library/Main/Operation/BackupHandler.cs b/Duplicati/Library/Main/Operation/BackupHandler.cs index 322e0f1a2..153217795 100644 --- a/Duplicati/Library/Main/Operation/BackupHandler.cs +++ b/Duplicati/Library/Main/Operation/BackupHandler.cs @@ -595,7 +595,7 @@ namespace Duplicati.Library.Main.Operation return new AggregateException(ex.First().Message, ex); } - private static async Task FlushBackend(Backup.BackupDatabase database, BackupResults result, IBackendManager backendManager) + private static async Task FlushBackend(Backup.BackupDatabase database, BackupResults result, IBackendManager backendManager) { // Wait for upload completion result.OperationProgressUpdater.UpdatePhase(OperationPhase.Backup_WaitForUpload); @@ -605,14 +605,10 @@ namespace Duplicati.Library.Main.Operation await database.FlushBackendMessagesAndCommitAsync(backendManager).ConfigureAwait(false); await backendManager.WaitForEmptyAsync(result.TaskControl.ProgressToken).ConfigureAwait(false); await database.FlushBackendMessagesAndCommitAsync(backendManager).ConfigureAwait(false); - // Grab the size of the last uploaded volume - return backendManager.LastWriteSize; } catch (RetiredException) { } - - return -1; } public async Task RunAsync(string[] sources, IBackendManager backendManager, IFilter filter) @@ -719,7 +715,7 @@ namespace Duplicati.Library.Main.Operation // Wait for upload completion m_result.OperationProgressUpdater.UpdatePhase(OperationPhase.Backup_WaitForUpload); - var lastVolumeSize = await FlushBackend(db, m_result, backendManager).ConfigureAwait(false); + await FlushBackend(db, m_result, backendManager).ConfigureAwait(false); if (!m_options.Dryrun) database.TerminatedWithActiveUploads = false; @@ -730,7 +726,10 @@ namespace Duplicati.Library.Main.Operation { // If this throws, we should roll back the transaction if (await m_result.TaskControl.ProgressRendevouz().ConfigureAwait(false)) + { + var lastVolumeSize = m_database.GetLastWrittenDBlockVolumeSize(rtr.Transaction); await CompactIfRequired(backendManager, rtr, lastVolumeSize); + } if (m_options.UploadVerificationFile && await m_result.TaskControl.ProgressRendevouz().ConfigureAwait(false)) { diff --git a/Duplicati/License/Duplicati.License.csproj b/Duplicati/License/Duplicati.License.csproj index d32900c23..ca829d99a 100644 --- a/Duplicati/License/Duplicati.License.csproj +++ b/Duplicati/License/Duplicati.License.csproj @@ -18,7 +18,7 @@ changelog.txt PreserveNewest - + licenses\license.txt PreserveNewest diff --git a/Duplicati/Server/webroot/ngax/templates/about.html b/Duplicati/Server/webroot/ngax/templates/about.html index fceb6cf9f..6a148db1c 100644 --- a/Duplicati/Server/webroot/ngax/templates/about.html +++ b/Duplicati/Server/webroot/ngax/templates/about.html @@ -17,9 +17,9 @@ translate-params-mail1="'mailto:kenneth@duplicati.com'" translate-params-mail2="'mailto:rene@duplicati.com'" translate-params-websitename="'duplicati.com'" - translate-params-websitelink="'http://www.duplicati.com'" + translate-params-websitelink="'https://duplicati.com'" translate-params-licensename="'MIT license'" - translate-params-licenselink="'https://raw.githubusercontent.com/duplicati/duplicati/master/LICENSE.txt'" + translate-params-licenselink="'https://raw.githubusercontent.com/duplicati/duplicati/master/LICENSE'" > {{appname}} was primarily developed by {{dev1}} and {{dev2}}. {{appname}} can be downloaded from {{websitename}}. {{appname}} is licensed under the {{licensename}}. diff --git a/Duplicati/UnitTest/DisruptionTests.cs b/Duplicati/UnitTest/DisruptionTests.cs index 3aa9ddcc8..c4a8f53e2 100644 --- a/Duplicati/UnitTest/DisruptionTests.cs +++ b/Duplicati/UnitTest/DisruptionTests.cs @@ -741,6 +741,9 @@ namespace Duplicati.UnitTest using (var c = new Controller("file://" + TARGETFOLDER, testopts, null)) TestUtils.AssertResults(c.Backup(new string[] { DATAFOLDER })); + // Ensure that the target folder only has a single dlist file + Assert.AreEqual(1, Directory.EnumerateFiles(TARGETFOLDER, "*.dlist.*").Count(), "There should be only one dlist file in the target folder"); + // Make a new backup that fails uploading a dblock file ModifySourceFiles(); @@ -753,6 +756,7 @@ namespace Duplicati.UnitTest var secondUploadCompleted = false; // Fail the compact after the first dblock put is completed + var uploads = new List(); DeterministicErrorBackend.ErrorGenerator = (DeterministicErrorBackend.BackendAction action, string remotename) => { if (action.IsGetOperation) @@ -783,6 +787,11 @@ namespace Duplicati.UnitTest Assert.That(secondUploadStarted, Is.True, "Second upload was not started"); Assert.That(secondUploadCompleted, Is.True, "Second upload was not started"); + Assert.That(hasFailed, Is.True, "Failed to fail the upload"); + Assert.That(!uploads.Any(x => x.Contains("dlist")), Is.True, "Upload of dlist file was not skipped"); + + // Ensure that the target folder only has a single dlist file + Assert.AreEqual(1, Directory.EnumerateFiles(TARGETFOLDER, "*.dlist.*").Count(), $"There should be only one dlist file in the target folder: {string.Join(", ", uploads)}"); // Create a regular backup using (var c = new Controller("file://" + TARGETFOLDER, testopts, null)) diff --git a/ReleaseBuilder/Build/Command.CreatePackage.cs b/ReleaseBuilder/Build/Command.CreatePackage.cs index 21232ab44..4d8de5310 100644 --- a/ReleaseBuilder/Build/Command.CreatePackage.cs +++ b/ReleaseBuilder/Build/Command.CreatePackage.cs @@ -819,7 +819,7 @@ public static partial class Command // Write the license file File.Copy( - Path.Combine(baseDir, "LICENSE.txt"), + Path.Combine(baseDir, "LICENSE"), EnsureFolderForFile( Path.Combine(pkgroot, "usr", "share", "doc", "duplicati", "copyright") )