// // Copyright (c) Microsoft. All rights reserved. // Licensed under the MIT license. See LICENSE file in the project root for full license information. // #nullable disable using System; using System.Data; using System.Data.Common; using Microsoft.Data.SqlClient; using System.Globalization; using System.IO; using Microsoft.SqlServer.Management.Sdk.Sfc; using Microsoft.SqlServer.Management.Smo; using Microsoft.SqlTools.ServiceLayer.Connection; using Microsoft.SqlTools.ServiceLayer.Connection.ReliableConnection; using Microsoft.SqlTools.ServiceLayer.FileBrowser; namespace Microsoft.SqlTools.ServiceLayer.DisasterRecovery { /// /// Validate selected file paths for backup/restore operations /// public static class DisasterRecoveryFileValidator { internal const string LocalSqlServer = "(local)"; internal const string LocalMachineName = "."; public static bool ValidatePaths(FileBrowserValidateEventArgs args, out string errorMessage) { errorMessage = string.Empty; bool result = true; SqlConnection connection = null; if (args != null) { ConnectionInfo connInfo; ConnectionService.Instance.TryFindConnection(args.OwnerUri, out connInfo); if (connInfo != null) { DbConnection dbConnection = null; connInfo.TryGetConnection(Connection.ConnectionType.Default, out dbConnection); if (dbConnection != null) { connection = ReliableConnectionHelper.GetAsSqlConnection(dbConnection); } } } if (connection != null) { foreach (string filePath in args.FilePaths) { bool isFolder; bool existing = IsPathExisting(connection, filePath, out isFolder); if (existing) { if (isFolder) { errorMessage = SR.BackupPathIsFolderError; } } else { if (args.ServiceType == FileValidationServiceConstants.Backup) { errorMessage = IsFolderPathExisting(connection, filePath); } else if (args.ServiceType == FileValidationServiceConstants.Restore) { errorMessage = SR.InvalidBackupPathError; } } if (!string.IsNullOrEmpty(errorMessage)) { result = false; break; } } } return result; } #region private methods /// /// Check if the folder path exists /// /// sql connection /// full file path /// internal static string IsFolderPathExisting(SqlConnection connection, string filePath) { string folderPath = PathWrapper.GetDirectoryName(filePath); string errorMessage = string.Empty; if (string.IsNullOrEmpty(folderPath)) { errorMessage = SR.InvalidBackupPathError; } else if (string.Compare(GetMachineName(connection.DataSource), Environment.MachineName, StringComparison.OrdinalIgnoreCase) == 0 && !Directory.Exists(folderPath)) { errorMessage = SR.InvalidBackupPathError; } else { bool isFolderOnRemote; bool existsOnRemote = IsPathExisting(connection, folderPath, out isFolderOnRemote); if (!existsOnRemote) { errorMessage = SR.InvalidBackupPathError; } } return errorMessage; } internal static bool IsPathExisting(SqlConnection connection, string path, out bool isFolder) { Request req = new Request { Urn = "Server/File[@FullName='" + Urn.EscapeString(path) + "']", Fields = new[] { "IsFile" } }; Enumerator en = new Enumerator(); bool isExisting = false; isFolder = false; using (DataSet ds = en.Process(connection, req)) { if (FileBrowserBase.IsValidDataSet(ds)) { isFolder = !(Convert.ToBoolean(ds.Tables[0].Rows[0]["IsFile"], CultureInfo.InvariantCulture)); isExisting = true; } } return isExisting; } internal static string GetMachineName(string sqlServerName) { string machineName = string.Empty; if (sqlServerName != null) { string serverName = sqlServerName.ToLowerInvariant().Trim(); if ((serverName == LocalSqlServer) || (serverName == LocalMachineName)) { machineName = System.Environment.MachineName; } else { machineName = sqlServerName; if (sqlServerName.Trim().Length != 0) { // [0] = machine, [1] = instance return sqlServerName.Split('\\')[0]; } } } return machineName; } #endregion } }