diff --git a/Duplicati/Library/Interface/IGenericSourceModule.cs b/Duplicati/Library/Interface/IGenericSourceModule.cs
index 1f1d8c0b4..aced0c6c5 100644
--- a/Duplicati/Library/Interface/IGenericSourceModule.cs
+++ b/Duplicati/Library/Interface/IGenericSourceModule.cs
@@ -42,13 +42,20 @@ namespace Duplicati.Library.Interface
/// Filters that are applied to backup paths (include, exclude)
/// A set of commandline options passed to Duplicati
/// A list of changed or added options values
- Dictionary ParseSource(ref string[] paths, ref string filter, Dictionary commandlineOptions);
+ Dictionary ParseSourcePaths(ref string[] paths, ref string filter, Dictionary commandlineOptions);
///
- /// This method is the interception where the module can interact with the execution environment and modify the settings.
+ /// This method decides if input variables contains something to backup.
///
/// A set of commandline options passed to Duplicati
/// If module is going to backup anything, it returns true, otherwise false
- bool ContainFiles(Dictionary commandlineOptions);
+ bool ContainFilesForBackup(Dictionary commandlineOptions);
+
+ ///
+ /// This method decides if input variables contains something to backup.
+ ///
+ /// A set of source paths
+ /// If module is going to backup anything, it returns true, otherwise false
+ bool ContainFilesForBackup(string[] paths);
}
}
diff --git a/Duplicati/Library/Main/Controller.cs b/Duplicati/Library/Main/Controller.cs
index 3d53b0f33..3f3892dcb 100644
--- a/Duplicati/Library/Main/Controller.cs
+++ b/Duplicati/Library/Main/Controller.cs
@@ -181,7 +181,7 @@ namespace Duplicati.Library.Main
foreach (var mx in m_options.LoadedModules)
if (mx.Key && mx.Value is Library.Interface.IGenericSourceModule)
if(!bModulesFiles)
- bModulesFiles = ((Library.Interface.IGenericSourceModule)mx.Value).ContainFiles(m_options.RawOptions);
+ bModulesFiles = ((Library.Interface.IGenericSourceModule)mx.Value).ContainFilesForBackup(m_options.RawOptions);
if (!bModulesFiles && (inputsources == null || inputsources.Length == 0))
throw new Exception(Strings.Controller.NoSourceFoldersError);
@@ -613,7 +613,7 @@ namespace Duplicati.Library.Main
if (mx.Value is Library.Interface.IGenericSourceModule)
{
- var sourceoptions = ((Library.Interface.IGenericSourceModule)mx.Value).ParseSource(ref paths, ref pristinefilter, m_options.RawOptions);
+ var sourceoptions = ((Library.Interface.IGenericSourceModule)mx.Value).ParseSourcePaths(ref paths, ref pristinefilter, m_options.RawOptions);
foreach (var sourceoption in sourceoptions)
m_options.RawOptions[sourceoption.Key] = sourceoption.Value;
diff --git a/Duplicati/Library/Modules/Builtin/HyperVOptions.cs b/Duplicati/Library/Modules/Builtin/HyperVOptions.cs
index e605faf63..f8641a9bf 100644
--- a/Duplicati/Library/Modules/Builtin/HyperVOptions.cs
+++ b/Duplicati/Library/Modules/Builtin/HyperVOptions.cs
@@ -75,60 +75,77 @@ namespace Duplicati.Library.Modules.Builtin
#endregion
#region Implementation of IGenericSourceModule
- public Dictionary ParseSource(ref string[] paths, ref string filter, Dictionary commandlineOptions)
+ public Dictionary ParseSourcePaths(ref string[] paths, ref string filter, Dictionary commandlineOptions)
{
- var pathshyperv = new List();
- var ret = new Dictionary();
+ var changedOptions = new Dictionary();
+ var filtersInclude = new List();
+ var filtersExclude = new List();
- if (paths != null)
- {
- if (paths.Contains(m_HyperVPathAllRegExp, StringComparer.OrdinalIgnoreCase))
- {
- if (Utility.Utility.IsClientWindows)
- {
- var hypervUtility = new HyperVUtility();
- hypervUtility.QueryHyperVGuestsInfo();
- pathshyperv = hypervUtility.Guests.Select(x => string.Format(@"%HYPERV%\{0}", x.ID)).ToList();
- }
- }
- else
- pathshyperv = paths.Where(x => Regex.IsMatch(x, m_HyperVPathGuidRegExp, RegexOptions.IgnoreCase | RegexOptions.CultureInvariant)).ToList();
- }
- paths = paths.Where(x => !x.Equals(m_HyperVPathAllRegExp, StringComparison.OrdinalIgnoreCase) && !Regex.IsMatch(x, m_HyperVPathGuidRegExp, RegexOptions.IgnoreCase | RegexOptions.CultureInvariant)).ToArray();
-
if (!string.IsNullOrEmpty(filter))
{
var filters = filter.Split(new string[] { System.IO.Path.PathSeparator.ToString() }, StringSplitOptions.RemoveEmptyEntries);
- var filtersInclude = filters.Where(x => x.StartsWith("+") && Regex.IsMatch(x, m_HyperVPathGuidRegExp, RegexOptions.IgnoreCase | RegexOptions.CultureInvariant)).Select(x => x.Substring(1)).ToList();
- var filtersExclude = filters.Where(x => x.StartsWith("-") && Regex.IsMatch(x, m_HyperVPathGuidRegExp, RegexOptions.IgnoreCase | RegexOptions.CultureInvariant)).Select(x => x.Substring(1)).ToList();
+ filtersInclude = filters.Where(x => x.StartsWith("+") && Regex.IsMatch(x, m_HyperVPathGuidRegExp, RegexOptions.IgnoreCase | RegexOptions.CultureInvariant)).Select(x => x.Substring(1)).ToList();
+ filtersExclude = filters.Where(x => x.StartsWith("-") && Regex.IsMatch(x, m_HyperVPathGuidRegExp, RegexOptions.IgnoreCase | RegexOptions.CultureInvariant)).Select(x => x.Substring(1)).ToList();
var remainingfilters = filters.Where(x => !Regex.IsMatch(x, m_HyperVPathGuidRegExp, RegexOptions.IgnoreCase)).ToArray();
filter = string.Join(System.IO.Path.PathSeparator.ToString(), remainingfilters);
-
- pathshyperv = pathshyperv.Union(filtersInclude).Except(filtersExclude).ToList();
}
+ if (!Utility.Utility.IsClientWindows)
+ {
+ Logging.Log.WriteMessage("Hyper-V backup works only on Windows OS.", Logging.LogMessageType.Warning);
+
+ if(paths != null)
+ paths = paths.Where(x => !x.Equals(m_HyperVPathAllRegExp, StringComparison.OrdinalIgnoreCase) && !Regex.IsMatch(x, m_HyperVPathGuidRegExp, RegexOptions.IgnoreCase | RegexOptions.CultureInvariant)).ToArray();
+ }
+
+ if (paths == null || !ContainFilesForBackup(paths) || !Utility.Utility.IsClientWindows)
+ return changedOptions;
+
+ if (commandlineOptions.Keys.Contains("vss-exclude-writers"))
+ {
+ var excludedWriters = commandlineOptions["vss-exclude-writers"].Split(';').Where(x => !string.IsNullOrWhiteSpace(x) && x.Trim().Length > 0).Select(x => new Guid(x)).ToArray();
+
+ if (excludedWriters.Contains(HyperVUtility.HyperVWriterGuid))
+ {
+ Logging.Log.WriteMessage(string.Format("Excluded writers for VSS cannot contain Hyper-V writer when backuping Hyper-V virtual machines. Removing \"{0}\" to continue.", HyperVUtility.HyperVWriterGuid.ToString()), Logging.LogMessageType.Warning);
+
+ changedOptions["vss-exclude-writers"] = string.Join(";", excludedWriters.Where(x => x != HyperVUtility.HyperVWriterGuid));
+ }
+ }
+
+ if (!commandlineOptions.Keys.Contains("snapshot-policy") || commandlineOptions["snapshot-policy"] != "required")
+ {
+ Logging.Log.WriteMessage("Snapshot strategy have to be set to \"required\" when backuping Hyper-V virtual machines. Changing to \"required\" to continue.", Logging.LogMessageType.Warning);
+ changedOptions["snapshot-policy"] = "required";
+ }
+
+ var pathshyperv = new List();
+
+ if (paths.Contains(m_HyperVPathAllRegExp, StringComparer.OrdinalIgnoreCase))
+ {
+ var hypervUtility = new HyperVUtility();
+ hypervUtility.QueryHyperVGuestsInfo();
+ pathshyperv = hypervUtility.Guests.Select(x => string.Format(@"%HYPERV%\{0}", x.ID)).ToList();
+ }
+ else
+ pathshyperv = paths.Where(x => Regex.IsMatch(x, m_HyperVPathGuidRegExp, RegexOptions.IgnoreCase | RegexOptions.CultureInvariant)).ToList();
+
+ paths = paths.Where(x => !x.Equals(m_HyperVPathAllRegExp, StringComparison.OrdinalIgnoreCase) && !Regex.IsMatch(x, m_HyperVPathGuidRegExp, RegexOptions.IgnoreCase | RegexOptions.CultureInvariant)).ToArray();
+
+ if (filtersInclude.Count > 0 || filtersExclude.Count > 0)
+ pathshyperv = pathshyperv.Union(filtersInclude).Except(filtersExclude).ToList();
+
pathshyperv = pathshyperv.Select(x => Regex.Match(x, m_HyperVGuidRegExp).Value).ToList();
-
- if (pathshyperv.Count != 0 && Utility.Utility.IsClientWindows && (!commandlineOptions.Keys.Contains("snapshot-policy") || commandlineOptions["snapshot-policy"] != "required"))
- {
- Logging.Log.WriteMessage("Snapshot strategy have to be set to \"required\" when backuping Hyper-V virtual machines. Changing to \"required\" to continue.", Logging.LogMessageType.Information);
- ret["snapshot-policy"] = "required";
- }
-
+
if (pathshyperv.Count != 0)
- {
- if (Utility.Utility.IsClientWindows)
- ret[OPTION_SOURCE] = string.Join(System.IO.Path.PathSeparator.ToString(), pathshyperv);
- else
- Logging.Log.WriteMessage("Hyper-V backup works only on Windows OS.", Logging.LogMessageType.Warning);
- }
+ changedOptions[OPTION_SOURCE] = string.Join(System.IO.Path.PathSeparator.ToString(), pathshyperv);
- return ret;
+ return changedOptions;
}
- public bool ContainFiles(Dictionary commandlineOptions)
+ public bool ContainFilesForBackup(Dictionary commandlineOptions)
{
if (commandlineOptions != null && !commandlineOptions.Keys.Contains(OPTION_SOURCE))
return false;
@@ -139,6 +156,17 @@ namespace Duplicati.Library.Modules.Builtin
return false;
}
+ public bool ContainFilesForBackup(string[] paths)
+ {
+ if (paths == null)
+ return false;
+
+ if (paths.Contains(m_HyperVPathAllRegExp, StringComparer.OrdinalIgnoreCase))
+ return true;
+
+ return paths.Where(x => Regex.IsMatch(x, m_HyperVPathGuidRegExp, RegexOptions.IgnoreCase | RegexOptions.CultureInvariant)).Count() > 0;
+ }
+
#endregion
}
}