From 25d35f68b4ffca2afaeac0255a501995afcb4b7e Mon Sep 17 00:00:00 2001 From: Kenneth Skovhede Date: Sat, 14 Mar 2026 18:26:37 +0100 Subject: [PATCH] Fixed usage of filelist filter --- Duplicati/Library/Main/Controller.cs | 2 +- .../Main/Operation/ListFilesHandler.cs | 3 +- .../Library/Main/Operation/RepairHandler.cs | 2 +- .../Library/Main/Operation/RestoreHandler.cs | 60 +++++++++---------- 4 files changed, 33 insertions(+), 34 deletions(-) diff --git a/Duplicati/Library/Main/Controller.cs b/Duplicati/Library/Main/Controller.cs index f469fa43b..f6c251caa 100644 --- a/Duplicati/Library/Main/Controller.cs +++ b/Duplicati/Library/Main/Controller.cs @@ -369,7 +369,7 @@ namespace Duplicati.Library.Main public IRecreateDatabaseResults UpdateDatabaseWithVersions(IFilter filter = null) { - var filelistfilter = Operation.RestoreHandler.FilterNumberedFilelist(m_options.Time, m_options.Version, singleTimeMatch: true); + var filelistfilter = Operation.RestoreHandler.GetNumberedFilelistFilterDelegate(m_options.Time, m_options.Version, singleTimeMatch: true); return RunAction(new RecreateDatabaseResults(), ref filter, async (result, backendManager) => { diff --git a/Duplicati/Library/Main/Operation/ListFilesHandler.cs b/Duplicati/Library/Main/Operation/ListFilesHandler.cs index 8ad83b976..6a8cd7d45 100644 --- a/Duplicati/Library/Main/Operation/ListFilesHandler.cs +++ b/Duplicati/Library/Main/Operation/ListFilesHandler.cs @@ -238,8 +238,7 @@ namespace Duplicati.Library.Main.Operation where p != null && p.FileType == RemoteVolumeType.Files orderby p.Time descending select p).ToArray(); - var filelistFilter = RestoreHandler.FilterNumberedFilelist(options.Time, options.Version); - return filelistFilter(parsedlist).ToList(); + return RestoreHandler.FilterNumberedFilelist(parsedlist, options.Time, options.Version).ToList(); } private class RemoteVolumeMapper(IParsedVolume Volume) : IRemoteVolume diff --git a/Duplicati/Library/Main/Operation/RepairHandler.cs b/Duplicati/Library/Main/Operation/RepairHandler.cs index aff8f3df8..157aaea95 100644 --- a/Duplicati/Library/Main/Operation/RepairHandler.cs +++ b/Duplicati/Library/Main/Operation/RepairHandler.cs @@ -127,7 +127,7 @@ namespace Duplicati.Library.Main.Operation if (f != null && File.Exists(f)) File.Delete(f); - var filelistfilter = RestoreHandler.FilterNumberedFilelist(m_options.Time, m_options.Version); + var filelistfilter = RestoreHandler.GetNumberedFilelistFilterDelegate(m_options.Time, m_options.Version); await new RecreateDatabaseHandler(m_options, (RecreateDatabaseResults)m_result.RecreateDatabaseResults) .RunAsync(m_options.Dryrun ? (string)f : m_options.Dbpath, backendManager, filter, filelistfilter, null) diff --git a/Duplicati/Library/Main/Operation/RestoreHandler.cs b/Duplicati/Library/Main/Operation/RestoreHandler.cs index 569345361..c6c44b7fb 100644 --- a/Duplicati/Library/Main/Operation/RestoreHandler.cs +++ b/Duplicati/Library/Main/Operation/RestoreHandler.cs @@ -101,7 +101,15 @@ namespace Duplicati.Library.Main.Operation return tmp.CompressionModule; } - public static RecreateDatabaseHandler.NumberedFilterFilelistDelegate FilterNumberedFilelist(DateTime time, long[] versions, bool singleTimeMatch = false) + public static RecreateDatabaseHandler.NumberedFilterFilelistDelegate GetNumberedFilelistFilterDelegate(DateTime time, long[] versions, bool singleTimeMatch = false) + { + if (versions.Length == 0 && time.Ticks == 0) + return null; + + return (filelist) => FilterNumberedFilelist(filelist, time, versions, singleTimeMatch); + } + + public static IEnumerable> FilterNumberedFilelist(IEnumerable filelist, DateTime time, long[] versions, bool singleTimeMatch = false) { if (time.Kind == DateTimeKind.Unspecified) throw new Exception("Unspecified datetime instance, must be either local or UTC"); @@ -111,36 +119,28 @@ namespace Duplicati.Library.Main.Operation time = Library.Utility.Utility.DeserializeDateTime(Library.Utility.Utility.SerializeDateTime(time)).ToUniversalTime(); versions ??= []; + // Unwrap, so we do not query the remote storage twice + var lst = (from n in filelist + where n.FileType == RemoteVolumeType.Files + orderby n.Time descending + select n).ToArray(); - if (versions.Length == 0 && time.Ticks == 0) - return null; + var numbers = lst.Zip(Enumerable.Range(0, lst.Length), (a, b) => new KeyValuePair(b, a)).ToList(); - return - _lst => - { - // Unwrap, so we do not query the remote storage twice - var lst = (from n in _lst - where n.FileType == RemoteVolumeType.Files - orderby n.Time descending - select n).ToArray(); - - var numbers = lst.Zip(Enumerable.Range(0, lst.Length), (a, b) => new KeyValuePair(b, a)).ToList(); - - if (time.Ticks > 0 && versions.Length > 0) - return from n in numbers - where (singleTimeMatch ? n.Value.Time == time : n.Value.Time <= time) && versions.Contains(n.Key) - select n; - else if (time.Ticks > 0) - return from n in numbers - where (singleTimeMatch ? n.Value.Time == time : n.Value.Time <= time) - select n; - else if (versions.Length > 0) - return from n in numbers - where versions.Contains(n.Key) - select n; - else - return numbers; - }; + if (time.Ticks > 0 && versions.Length > 0) + return from n in numbers + where (singleTimeMatch ? n.Value.Time == time : n.Value.Time <= time) && versions.Contains(n.Key) + select n; + else if (time.Ticks > 0) + return from n in numbers + where (singleTimeMatch ? n.Value.Time == time : n.Value.Time <= time) + select n; + else if (versions.Length > 0) + return from n in numbers + where versions.Contains(n.Key) + select n; + else + return numbers; } public async Task RunAsync(string[] paths, IBackendManager backendManager, Library.Utility.IFilter filter, IRestoreDestinationProvider restoreDestination) @@ -172,7 +172,7 @@ namespace Duplicati.Library.Main.Operation { Logging.Log.WriteInformationMessage(LOGTAG, "NoLocalDatabase", "No local database, building a temporary database"); tmpdb = new TempFile(); - RecreateDatabaseHandler.NumberedFilterFilelistDelegate filelistfilter = FilterNumberedFilelist(m_options.Time, m_options.Version); + RecreateDatabaseHandler.NumberedFilterFilelistDelegate filelistfilter = GetNumberedFilelistFilterDelegate(m_options.Time, m_options.Version); db = await LocalRestoreDatabase.CreateAsync(tmpdb, null, m_result.TaskControl.ProgressToken) .ConfigureAwait(false); m_result.RecreateDatabaseResults = new RecreateDatabaseResults(m_result);