2016-11-09 12:57:35 +01:00
using Alphaleonis.Win32.Vss ;
using System ;
using System.Collections.Generic ;
using System.IO ;
using System.Linq ;
namespace Duplicati.Library.Snapshots
{
public class MSSQLDB : IEquatable < MSSQLDB >
{
public string Name { get ; }
public string ID { get ; }
public List < string > DataPaths { get ; }
public MSSQLDB ( string Name , string ID , List < string > DataPaths )
{
this . Name = Name ;
this . ID = ID ;
this . DataPaths = DataPaths ;
}
bool IEquatable < MSSQLDB >. Equals ( MSSQLDB other )
{
return ID . Equals ( other . ID );
}
public override int GetHashCode ()
{
return ID . GetHashCode ();
}
public override bool Equals ( object obj )
{
MSSQLDB db = obj as MSSQLDB ;
if ( db != null )
{
return Equals ( db );
}
else
{
return false ;
}
}
public static bool operator ==( MSSQLDB db1 , MSSQLDB db2 )
{
if ( object . ReferenceEquals ( db1 , db2 )) return true ;
if ( object . ReferenceEquals ( db1 , null )) return false ;
if ( object . ReferenceEquals ( db2 , null )) return false ;
return db1 . Equals ( db2 );
}
public static bool operator !=( MSSQLDB db1 , MSSQLDB db2 )
{
if ( object . ReferenceEquals ( db1 , db2 )) return false ;
if ( object . ReferenceEquals ( db1 , null )) return true ;
if ( object . ReferenceEquals ( db2 , null )) return true ;
return ! db1 . Equals ( db2 );
}
}
public class MSSQLUtility
{
2018-03-12 14:07:11 +01:00
/// <summary>
/// The tag used for logging
/// </summary>
private static readonly string LOGTAG = Logging . Log . LogTagFromType < MSSQLUtility >();
2016-11-09 12:57:35 +01:00
/// <summary>
/// The MS SQL VSS Writer Guid
/// </summary>
public static readonly Guid MSSQLWriterGuid = new Guid ( "a65faa63-5ea8-4ebc-9dbd-a0c4db26912a" );
/// <summary>
/// MS SQL is supported only on Windows platform
/// </summary>
public bool IsMSSQLInstalled { get ; }
/// <summary>
/// Enumerated MS SQL DBs
/// </summary>
public List < MSSQLDB > DBs { get { return m_DBs ; } }
private List < MSSQLDB > m_DBs ;
public MSSQLUtility ()
{
m_DBs = new List < MSSQLDB >();
if (! Utility . Utility . IsClientWindows )
{
IsMSSQLInstalled = false ;
return ;
}
string [] arrInstalledInstances = null ;
var installed = Microsoft . Win32 . Registry . GetValue ( @"HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Microsoft SQL Server" , "InstalledInstances" , "" );
if ( installed is string )
{
if (! string . IsNullOrWhiteSpace ( installed as string ))
arrInstalledInstances = new string [] { installed as string };
2018-01-09 11:29:40 +01:00
}
2016-11-09 12:57:35 +01:00
else if ( installed is string [])
arrInstalledInstances = ( string []) installed ;
else if ( installed != null )
try { arrInstalledInstances = ( string []) installed ; }
catch { }
2018-01-09 11:29:40 +01:00
if ( Environment . Is64BitOperatingSystem && arrInstalledInstances == null )
2018-01-09 11:17:33 +01:00
{
var installed32on64 = Microsoft . Win32 . Registry . GetValue ( @"HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\Microsoft\Microsoft SQL Server" , "InstalledInstances" , "" );
if ( installed32on64 is string )
{
if (! string . IsNullOrWhiteSpace ( installed32on64 as string ))
arrInstalledInstances = new string [] { installed32on64 as string };
}
else if ( installed32on64 is string [])
arrInstalledInstances = ( string []) installed32on64 ;
else if ( installed32on64 != null )
try { arrInstalledInstances = ( string []) installed32on64 ; }
catch { }
}
2016-11-09 12:57:35 +01:00
IsMSSQLInstalled = arrInstalledInstances == null ? false : arrInstalledInstances . Length > 0 ;
if (! IsMSSQLInstalled )
2018-03-12 14:07:11 +01:00
Logging . Log . WriteInformationMessage ( LOGTAG , "NoMSSQLInstance" , "Cannot find any MS SQL Server instance. MS SQL Server is probably not installed." );
2016-11-09 12:57:35 +01:00
}
/// <summary>
/// For all MS SQL databases it enumerate all associated paths using VSS data
/// </summary>
/// <returns>A collection of DBs and paths</returns>
public void QueryDBsInfo ()
{
if (! IsMSSQLInstalled )
return ;
m_DBs . Clear ();
//Substitute for calling VssUtils.LoadImplementation(), as we have the dlls outside the GAC
string alphadir = Path . Combine ( Path . GetDirectoryName ( System . Reflection . Assembly . GetExecutingAssembly (). Location ), "alphavss" );
string alphadll = Path . Combine ( alphadir , VssUtils . GetPlatformSpecificAssemblyShortName () + ".dll" );
IVssImplementation vss = ( IVssImplementation ) System . Reflection . Assembly . LoadFile ( alphadll ). CreateInstance ( "Alphaleonis.Win32.Vss.VssImplementation" );
using ( var m_backup = vss . CreateVssBackupComponents ())
{
m_backup . InitializeForBackup ( null );
m_backup . SetContext ( VssSnapshotContext . Backup );
m_backup . SetBackupState ( false , true , VssBackupType . Full , false );
m_backup . EnableWriterClasses ( new Guid [] { MSSQLWriterGuid });
try
{
m_backup . GatherWriterMetadata ();
var writerMetaData = m_backup . WriterMetadata . FirstOrDefault ( o => o . WriterId . Equals ( MSSQLWriterGuid ));
if ( writerMetaData == null )
2018-03-12 14:07:11 +01:00
throw new Duplicati . Library . Interface . UserInformationException ( "Microsoft SQL Server VSS Writer not found - cannot backup SQL databases." , "NoMsSqlVssWriter" );
2016-11-09 12:57:35 +01:00
foreach ( var component in writerMetaData . Components )
{
var paths = new List < string >();
foreach ( var file in component . Files )
if ( file . FileSpecification . Contains ( "*" ))
{
if ( Directory . Exists ( Utility . Utility . AppendDirSeparator ( file . Path )))
paths . Add ( Utility . Utility . AppendDirSeparator ( file . Path ));
}
else
{
if ( File . Exists ( Path . Combine ( file . Path , file . FileSpecification )))
paths . Add ( Path . Combine ( file . Path , file . FileSpecification ));
}
m_DBs . Add ( new MSSQLDB ( component . ComponentName , component . LogicalPath + "\\" + component . ComponentName , paths . Distinct ( Utility . Utility . ClientFilenameStringComparer ). OrderBy ( a => a ). ToList ()));
}
}
finally
{
m_backup . FreeWriterMetadata ();
}
}
}
}
2018-01-09 11:17:33 +01:00
}