private Dictionary <string, string> RealParseSourcePaths(ref string[] paths, ref string filter, Dictionary <string, string> commandlineOptions) { var changedOptions = new Dictionary <string, string>(); var filtersInclude = new List <string>(); var filtersExclude = new List <string>(); if (!string.IsNullOrEmpty(filter)) { var filters = filter.Split(new string[] { System.IO.Path.PathSeparator.ToString() }, StringSplitOptions.RemoveEmptyEntries); filtersInclude = filters.Where(x => x.StartsWith("+") && Regex.IsMatch(x, m_HyperVPathGuidRegExp, RegexOptions.IgnoreCase | RegexOptions.CultureInvariant)) .Select(x => Regex.Match(x.Substring(1), m_HyperVPathGuidRegExp, RegexOptions.IgnoreCase | RegexOptions.CultureInvariant).Groups[1].Value).ToList(); filtersExclude = filters.Where(x => x.StartsWith("-") && Regex.IsMatch(x, m_HyperVPathGuidRegExp, RegexOptions.IgnoreCase | RegexOptions.CultureInvariant)) .Select(x => Regex.Match(x.Substring(1), m_HyperVPathGuidRegExp, RegexOptions.IgnoreCase | RegexOptions.CultureInvariant).Groups[1].Value).ToList(); var remainingfilters = filters.Where(x => !Regex.IsMatch(x, m_HyperVPathGuidRegExp, RegexOptions.IgnoreCase | RegexOptions.CultureInvariant)).ToArray(); filter = string.Join(System.IO.Path.PathSeparator.ToString(), remainingfilters); } var hypervUtility = new HyperVUtility(); if (paths == null || !ContainFilesForBackup(paths) || !hypervUtility.IsHyperVInstalled) { 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"].Equals("required", StringComparison.OrdinalIgnoreCase)) { 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"; } if (!hypervUtility.IsVSSWriterSupported) { Logging.Log.WriteMessage("This is client version of Windows. Hyper-V VSS writer is present only on Server version. Backup will continue, but will be crash consistent only in opposite to application consistent in Server version", Logging.LogMessageType.Warning); } Logging.Log.WriteMessage("Starting to gather Hyper-V information", Logging.LogMessageType.Information); hypervUtility.QueryHyperVGuestsInfo(true); Logging.Log.WriteMessage(string.Format("Found {0} virtual machines on Hyper-V", hypervUtility.Guests.Count), Logging.LogMessageType.Information); foreach (var guest in hypervUtility.Guests) { Logging.Log.WriteMessage(string.Format("Found VM name {0}, ID {1}, files {2}", guest.Name, guest.ID, string.Join(";", guest.DataPaths)), Logging.LogMessageType.Profiling); } List <HyperVGuest> guestsForBackup = new List <HyperVGuest>(); if (paths.Contains(m_HyperVPathAllRegExp, StringComparer.OrdinalIgnoreCase)) { guestsForBackup = hypervUtility.Guests; } else { foreach (var guestID in paths.Where(x => Regex.IsMatch(x, m_HyperVPathGuidRegExp, RegexOptions.IgnoreCase | RegexOptions.CultureInvariant)) .Select(x => Regex.Match(x, m_HyperVPathGuidRegExp, RegexOptions.IgnoreCase | RegexOptions.CultureInvariant).Groups[1].Value).ToArray()) { var foundGuest = hypervUtility.Guests.Where(x => x.ID == new Guid(guestID)); if (foundGuest.Count() != 1) { throw new Duplicati.Library.Interface.UserInformationException(string.Format("Hyper-V guest specified in source with ID {0} cannot be found", guestID)); } guestsForBackup.Add(foundGuest.First()); } } if (filtersInclude.Count > 0) { foreach (var guestID in filtersInclude) { var foundGuest = hypervUtility.Guests.Where(x => x.ID == new Guid(guestID)); if (foundGuest.Count() != 1) { throw new Duplicati.Library.Interface.UserInformationException(string.Format("Hyper-V guest specified in include filter with ID {0} cannot be found", guestID)); } guestsForBackup.Add(foundGuest.First()); Logging.Log.WriteMessage(string.Format("Including {0} based on including filters", guestID), Logging.LogMessageType.Information); } } guestsForBackup = guestsForBackup.Distinct().ToList(); if (filtersExclude.Count > 0) { foreach (var guestID in filtersExclude) { var foundGuest = guestsForBackup.Where(x => x.ID == new Guid(guestID)); if (foundGuest.Count() != 1) { throw new Duplicati.Library.Interface.UserInformationException(string.Format("Hyper-V guest specified in exclude filter with ID {0} cannot be found", guestID)); } guestsForBackup.Remove(foundGuest.First()); Logging.Log.WriteMessage(string.Format("Excluding {0} based on excluding filters", guestID), Logging.LogMessageType.Information); } } var pathsForBackup = new List <string>(paths); var filterhandler = new Utility.FilterExpression( filter.Split(new string[] { System.IO.Path.PathSeparator.ToString() }, StringSplitOptions.RemoveEmptyEntries).Where(x => x.StartsWith("-")).Select(x => x.Substring(1)).ToList()); foreach (var guestForBackup in guestsForBackup) { foreach (var pathForBackup in guestForBackup.DataPaths) { bool bResult; Utility.IFilter matchFilter; if (!filterhandler.Matches(pathForBackup, out bResult, out matchFilter)) { Logging.Log.WriteMessage(string.Format("For VM {0} - adding {1}", guestForBackup.Name, pathForBackup), Logging.LogMessageType.Information); pathsForBackup.Add(pathForBackup); } else { Logging.Log.WriteMessage(string.Format("Excluding {0} based on excluding filters", pathForBackup), Logging.LogMessageType.Information); } } } paths = pathsForBackup.Where(x => !x.Equals(m_HyperVPathAllRegExp, StringComparison.OrdinalIgnoreCase) && !Regex.IsMatch(x, m_HyperVPathGuidRegExp, RegexOptions.IgnoreCase | RegexOptions.CultureInvariant)) .Distinct(Utility.Utility.ClientFilenameStringComparer).OrderBy(a => a).ToArray(); return(changedOptions); }
private Dictionary <string, string> RealParseSourcePaths(ref string[] paths, ref string filter, Dictionary <string, string> commandlineOptions) { var changedOptions = new Dictionary <string, string>(); var filtersInclude = new List <string>(); var filtersExclude = new List <string>(); if (!string.IsNullOrEmpty(filter)) { var filters = filter.Split(new string[] { System.IO.Path.PathSeparator.ToString() }, StringSplitOptions.RemoveEmptyEntries); filtersInclude = filters.Where(x => x.StartsWith("+", StringComparison.Ordinal) && Regex.IsMatch(x, m_MSSQLPathDBRegExp, RegexOptions.IgnoreCase | RegexOptions.CultureInvariant)) .Select(x => Regex.Match(x.Substring(1), m_MSSQLPathDBRegExp, RegexOptions.IgnoreCase | RegexOptions.CultureInvariant).Groups[1].Value).ToList(); filtersExclude = filters.Where(x => x.StartsWith("-", StringComparison.Ordinal) && Regex.IsMatch(x, m_MSSQLPathDBRegExp, RegexOptions.IgnoreCase | RegexOptions.CultureInvariant)) .Select(x => Regex.Match(x.Substring(1), m_MSSQLPathDBRegExp, RegexOptions.IgnoreCase | RegexOptions.CultureInvariant).Groups[1].Value).ToList(); var remainingfilters = filters.Where(x => !Regex.IsMatch(x, m_MSSQLPathDBRegExp, RegexOptions.IgnoreCase | RegexOptions.CultureInvariant)).ToArray(); filter = string.Join(System.IO.Path.PathSeparator.ToString(), remainingfilters); } var mssqlUtility = new MSSQLUtility(); if (paths == null || !ContainFilesForBackup(paths) || !mssqlUtility.IsMSSQLInstalled) { 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(MSSQLUtility.MSSQLWriterGuid)) { Logging.Log.WriteWarningMessage(LOGTAG, "CannotExcludeMsSqlVSSWriter", null, "Excluded writers for VSS cannot contain MS SQL writer when backuping Microsoft SQL Server databases. Removing \"{0}\" to continue", MSSQLUtility.MSSQLWriterGuid.ToString()); changedOptions["vss-exclude-writers"] = string.Join(";", excludedWriters.Where(x => x != MSSQLUtility.MSSQLWriterGuid)); } } if (!commandlineOptions.Keys.Contains("snapshot-policy") || !commandlineOptions["snapshot-policy"].Equals("required", StringComparison.OrdinalIgnoreCase)) { Logging.Log.WriteWarningMessage(LOGTAG, "MustSetSnapshotPolicy", null, "Snapshot policy have to be set to \"required\" when backuping Microsoft SQL Server databases. Changing to \"required\" to continue"); changedOptions["snapshot-policy"] = "required"; } Logging.Log.WriteInformationMessage(LOGTAG, "StartingMsSqlQuery", "Starting to gather Microsoft SQL Server information", Logging.LogMessageType.Information); mssqlUtility.QueryDBsInfo(); Logging.Log.WriteInformationMessage(LOGTAG, "MsSqlDatabaseCount", "Found {0} databases on Microsoft SQL Server", mssqlUtility.DBs.Count); foreach (var db in mssqlUtility.DBs) { Logging.Log.WriteProfilingMessage(LOGTAG, "MsSqlDatabaseName", "Found DB name {0}, ID {1}, files {2}", db.Name, db.ID, string.Join(";", db.DataPaths)); } List <MSSQLDB> dbsForBackup = new List <MSSQLDB>(); if (paths.Contains(m_MSSQLPathAllRegExp, StringComparer.OrdinalIgnoreCase)) { dbsForBackup = mssqlUtility.DBs; } else { foreach (var dbID in paths.Where(x => Regex.IsMatch(x, m_MSSQLPathDBRegExp, RegexOptions.IgnoreCase | RegexOptions.CultureInvariant)) .Select(x => Regex.Match(x, m_MSSQLPathDBRegExp, RegexOptions.IgnoreCase | RegexOptions.CultureInvariant).Groups[1].Value).ToArray()) { var foundDB = mssqlUtility.DBs.Where(x => x.ID.Equals(dbID, StringComparison.OrdinalIgnoreCase)); if (foundDB.Count() != 1) { throw new Duplicati.Library.Interface.UserInformationException(string.Format("DB name specified in source with ID {0} cannot be found", dbID), "MsSqlDatabaseNotFound"); } dbsForBackup.Add(foundDB.First()); } } if (filtersInclude.Count > 0) { foreach (var dbID in filtersInclude) { var foundDB = mssqlUtility.DBs.Where(x => x.ID.Equals(dbID, StringComparison.OrdinalIgnoreCase)); if (foundDB.Count() != 1) { throw new Duplicati.Library.Interface.UserInformationException(string.Format("DB name specified in include filter with ID {0} cannot be found", dbID), "MsSqlDatabaseNotFound"); } dbsForBackup.Add(foundDB.First()); Logging.Log.WriteInformationMessage(LOGTAG, "IncludeByFilter", "Including {0} based on including filters", dbID); } } dbsForBackup = dbsForBackup.Distinct().ToList(); if (filtersExclude.Count > 0) { foreach (var dbID in filtersExclude) { var foundDB = dbsForBackup.Where(x => x.ID.Equals(dbID, StringComparison.OrdinalIgnoreCase)); if (foundDB.Count() != 1) { throw new Duplicati.Library.Interface.UserInformationException(string.Format("DB name specified in exclude filter with ID {0} cannot be found", dbID), "MsSqlDatabaseNotFound"); } dbsForBackup.Remove(foundDB.First()); Logging.Log.WriteInformationMessage(LOGTAG, "ExcludeByFilter", "Excluding {0} based on excluding filters", dbID); } } var pathsForBackup = new List <string>(paths); var filterhandler = new Utility.FilterExpression( filter.Split(new string[] { System.IO.Path.PathSeparator.ToString() }, StringSplitOptions.RemoveEmptyEntries).Where(x => x.StartsWith("-", StringComparison.Ordinal)).Select(x => x.Substring(1)).ToList()); foreach (var dbForBackup in dbsForBackup) { foreach (var pathForBackup in dbForBackup.DataPaths) { bool bResult; Utility.IFilter matchFilter; if (!filterhandler.Matches(pathForBackup, out bResult, out matchFilter)) { Logging.Log.WriteInformationMessage(LOGTAG, "IncludeDatabase", "For DB {0} - adding {1}", dbForBackup.Name, pathForBackup); pathsForBackup.Add(pathForBackup); } else { Logging.Log.WriteInformationMessage(LOGTAG, "ExcludeByFilter", "Excluding {0} based on excluding filters", pathForBackup); } } } paths = pathsForBackup.Where(x => !x.Equals(m_MSSQLPathAllRegExp, StringComparison.OrdinalIgnoreCase) && !Regex.IsMatch(x, m_MSSQLPathDBRegExp, RegexOptions.IgnoreCase | RegexOptions.CultureInvariant)) .Distinct(Utility.Utility.ClientFilenameStringComparer).OrderBy(a => a).ToArray(); return(changedOptions); }