diff --git a/Duplicati/Library/Main/Database/LocalDatabase.cs b/Duplicati/Library/Main/Database/LocalDatabase.cs index 8f9397b49..3692c2082 100644 --- a/Duplicati/Library/Main/Database/LocalDatabase.cs +++ b/Duplicati/Library/Main/Database/LocalDatabase.cs @@ -755,7 +755,7 @@ namespace Duplicati.Library.Main.Database while(rd.Read()) { var p = rd.GetValue(0).ToString(); - if(Library.Utility.FilterExpression.Matches(filter, p, true)) + if(Library.Utility.FilterExpression.Matches(filter, p)) { cmd.SetParameterValue(0, p); cmd.ExecuteNonQuery(); diff --git a/Duplicati/Library/Main/Database/LocalListChangesDatabase.cs b/Duplicati/Library/Main/Database/LocalListChangesDatabase.cs index 8da011c96..24d0d8bbd 100644 --- a/Duplicati/Library/Main/Database/LocalListChangesDatabase.cs +++ b/Duplicati/Library/Main/Database/LocalListChangesDatabase.cs @@ -175,7 +175,7 @@ namespace Duplicati.Library.Main.Database while (rd.Read()) { rd.GetValues(values); - if (values[0] != null && values[0] != DBNull.Value && Library.Utility.FilterExpression.Matches(filter, values[0].ToString(), true)) + if (values[0] != null && values[0] != DBNull.Value && Library.Utility.FilterExpression.Matches(filter, values[0].ToString())) { cmd2.SetParameterValue(0, values[0]); cmd2.SetParameterValue(1, values[1]); diff --git a/Duplicati/Library/Main/Database/LocalRestoreDatabase.cs b/Duplicati/Library/Main/Database/LocalRestoreDatabase.cs index 3b8f8d85a..29f241823 100644 --- a/Duplicati/Library/Main/Database/LocalRestoreDatabase.cs +++ b/Duplicati/Library/Main/Database/LocalRestoreDatabase.cs @@ -117,7 +117,7 @@ namespace Duplicati.Library.Main.Database while (rd.Read()) { rd.GetValues(values); - if (values[0] != null && values[0] != DBNull.Value && Library.Utility.FilterExpression.Matches(filter, values[0].ToString(), true)) + if (values[0] != null && values[0] != DBNull.Value && Library.Utility.FilterExpression.Matches(filter, values[0].ToString())) { cmd2.SetParameterValue(0, values[0]); cmd2.SetParameterValue(1, values[1]); diff --git a/Duplicati/Library/Main/Operation/BackupHandler.cs b/Duplicati/Library/Main/Operation/BackupHandler.cs index 2e01f8a63..2b92e7015 100644 --- a/Duplicati/Library/Main/Operation/BackupHandler.cs +++ b/Duplicati/Library/Main/Operation/BackupHandler.cs @@ -156,7 +156,7 @@ namespace Duplicati.Library.Main.Operation return false; } - if (!Library.Utility.FilterExpression.Matches(m_filter, path, true)) + if (!Library.Utility.FilterExpression.Matches(m_filter, path)) { m_result.AddVerboseMessage("Excluding path due to filter {0}", path); return false; diff --git a/Duplicati/Library/Main/Operation/ListChangesHandler.cs b/Duplicati/Library/Main/Operation/ListChangesHandler.cs index 8ab42fb29..a5f2823c1 100644 --- a/Duplicati/Library/Main/Operation/ListChangesHandler.cs +++ b/Duplicati/Library/Main/Operation/ListChangesHandler.cs @@ -130,13 +130,13 @@ namespace Duplicati.Library.Main.Operation using(var tmpfile = backend.Get(baseFile.File.Name, baseFile.File.Size, null)) using(var rd = new Volumes.FilesetVolumeReader(RestoreHandler.GetCompressionModule(baseFile.File.Name), tmpfile, m_options)) foreach(var f in rd.Files) - if (Library.Utility.FilterExpression.Matches(filter, f.Path, true)) + if (Library.Utility.FilterExpression.Matches(filter, f.Path)) storageKeeper.AddElement(f.Path, f.Hash, f.Metahash, f.Size, conv(f.Type), false); using(var tmpfile = backend.Get(compareFile.File.Name, compareFile.File.Size, null)) using(var rd = new Volumes.FilesetVolumeReader(RestoreHandler.GetCompressionModule(compareFile.File.Name), tmpfile, m_options)) foreach(var f in rd.Files) - if (Library.Utility.FilterExpression.Matches(filter, f.Path, true)) + if (Library.Utility.FilterExpression.Matches(filter, f.Path)) storageKeeper.AddElement(f.Path, f.Hash, f.Metahash, f.Size, conv(f.Type), true); } diff --git a/Duplicati/Library/Main/Operation/ListControlFilesHandler.cs b/Duplicati/Library/Main/Operation/ListControlFilesHandler.cs index 92af18267..238bdb793 100644 --- a/Duplicati/Library/Main/Operation/ListControlFilesHandler.cs +++ b/Duplicati/Library/Main/Operation/ListControlFilesHandler.cs @@ -67,7 +67,7 @@ namespace Duplicati.Library.Main.Operation using (var tmpfile = backend.Get(file.Name, size, hash)) using (var tmp = new Volumes.FilesetVolumeReader(RestoreHandler.GetCompressionModule(file.Name), tmpfile, m_options)) foreach (var cf in tmp.ControlFiles) - if (Library.Utility.FilterExpression.Matches(filter, cf.Key, true)) + if (Library.Utility.FilterExpression.Matches(filter, cf.Key)) files.Add(new ListResultFile(cf.Key, null)); m_result.SetResult(new Library.Interface.IListResultFileset[] { new ListResultFileset(fileversion.Key, fileversion.Value.Time, -1, -1) }, files); diff --git a/Duplicati/Library/Main/Operation/ListFilesHandler.cs b/Duplicati/Library/Main/Operation/ListFilesHandler.cs index 711737505..4d210889b 100644 --- a/Duplicati/Library/Main/Operation/ListFilesHandler.cs +++ b/Duplicati/Library/Main/Operation/ListFilesHandler.cs @@ -77,7 +77,7 @@ namespace Duplicati.Library.Main.Operation m_result.SetResult( numberSeq.Take(1), (from n in rd.Files - where Library.Utility.FilterExpression.Matches(filter, n.Path, true) + where Library.Utility.FilterExpression.Matches(filter, n.Path) orderby n.Path select new ListResultFile(n.Path, new long[] { n.Size })) .ToArray() @@ -88,7 +88,7 @@ namespace Duplicati.Library.Main.Operation else { res = rd.Files - .Where(x => Library.Utility.FilterExpression.Matches(filter, x.Path, true)) + .Where(x => Library.Utility.FilterExpression.Matches(filter, x.Path)) .ToDictionary( x => x.Path, y => @@ -106,7 +106,7 @@ namespace Duplicati.Library.Main.Operation using(var tmpfile = backend.Get(flentry.Value.File.Name, -1, null)) using (var rd = new Volumes.FilesetVolumeReader(flentry.Value.CompressionModule, tmpfile, m_options)) { - foreach(var p in from n in rd.Files where Library.Utility.FilterExpression.Matches(filter, n.Path, true) select n) + foreach(var p in from n in rd.Files where Library.Utility.FilterExpression.Matches(filter, n.Path) select n) { List lst; if (!res.TryGetValue(p.Path, out lst)) diff --git a/Duplicati/Library/Main/Operation/RecreateDatabaseHandler.cs b/Duplicati/Library/Main/Operation/RecreateDatabaseHandler.cs index f07e8e609..e7ff25f34 100644 --- a/Duplicati/Library/Main/Operation/RecreateDatabaseHandler.cs +++ b/Duplicati/Library/Main/Operation/RecreateDatabaseHandler.cs @@ -170,7 +170,7 @@ namespace Duplicati.Library.Main.Operation // Create timestamped operations based on the file timestamp backupdb.CreateFileset(volumeIds[entry.Name], parsed.Time, tr); using (var filelistreader = new FilesetVolumeReader(parsed.CompressionModule, tmpfile, m_options)) - foreach (var fe in filelistreader.Files.Where(x => Library.Utility.FilterExpression.Matches(filter, x.Path, true))) + foreach (var fe in filelistreader.Files.Where(x => Library.Utility.FilterExpression.Matches(filter, x.Path))) { if (fe.Type == FilelistEntryType.Folder) { diff --git a/Duplicati/Library/Main/Operation/RestoreControlFilesHandler.cs b/Duplicati/Library/Main/Operation/RestoreControlFilesHandler.cs index 412642a23..aabf0737e 100644 --- a/Duplicati/Library/Main/Operation/RestoreControlFilesHandler.cs +++ b/Duplicati/Library/Main/Operation/RestoreControlFilesHandler.cs @@ -56,7 +56,7 @@ namespace Duplicati.Library.Main.Operation using (var tmpfile = backend.Get(file.Name, size, hash)) using (var tmp = new Volumes.FilesetVolumeReader(RestoreHandler.GetCompressionModule(file.Name), tmpfile, m_options)) foreach (var cf in tmp.ControlFiles) - if (Library.Utility.FilterExpression.Matches(filter, cf.Key, true)) + if (Library.Utility.FilterExpression.Matches(filter, cf.Key)) { var targetpath = System.IO.Path.Combine(m_options.Restorepath, cf.Key); using (var ts = System.IO.File.Create(targetpath)) diff --git a/Duplicati/Library/Utility/FilterExpression.cs b/Duplicati/Library/Utility/FilterExpression.cs index cecac8b1b..087c53653 100644 --- a/Duplicati/Library/Utility/FilterExpression.cs +++ b/Duplicati/Library/Utility/FilterExpression.cs @@ -200,17 +200,35 @@ namespace Duplicati.Library.Utility /// /// The filter to evaluate /// The path to evaluate - /// The default return value if no filter matches - public static bool Matches(IFilter filter, string path, bool @default) + public static bool Matches(IFilter filter, string path) { if (filter == null || filter.Empty) - return @default; + return true; bool result; - if (!filter.Matches(path, out result)) - result = @default; + if (filter.Matches(path, out result)) + return result; + + // If we only exclude files, choose to include by default + var q = new Queue(); + q.Enqueue(filter); - return result; + while (q.Count > 0) + { + var p = q.Dequeue(); + if (p == null || p.Empty) + continue; + else if (p is FilterExpression && ((FilterExpression)filter).Result) + return false; // We have an include filter, so we exclude by default + else if (p is JoinedFilterExpression) + { + q.Enqueue(((JoinedFilterExpression)p).First); + q.Enqueue(((JoinedFilterExpression)p).Second); + } + } + + // Only excludes, we return true + return true; } /// diff --git a/Duplicati/Library/Utility/JoinedFilterExpression.cs b/Duplicati/Library/Utility/JoinedFilterExpression.cs index 186ebe0a8..08c3ef823 100644 --- a/Duplicati/Library/Utility/JoinedFilterExpression.cs +++ b/Duplicati/Library/Utility/JoinedFilterExpression.cs @@ -21,21 +21,21 @@ namespace Duplicati.Library.Utility { public class JoinedFilterExpression : IFilter { - private IFilter m_first; - private IFilter m_second; + public readonly IFilter First; + public readonly IFilter Second; public JoinedFilterExpression(IFilter first, IFilter second) { - m_first = first ?? new FilterExpression(); - m_second = second ?? new FilterExpression(); + this.First = first ?? new FilterExpression(); + this.Second = second ?? new FilterExpression(); } public bool Matches(string entry, out bool result) { - return m_first.Matches(entry, out result) || m_second.Matches(entry, out result); + return First.Matches(entry, out result) || Second.Matches(entry, out result); } - public bool Empty { get { return m_first.Empty && m_second.Empty; } } + public bool Empty { get { return First.Empty && Second.Empty; } } public static IFilter Join(IFilter first, IFilter second) {