From: Thorsten Engel Date: Tue, 24 May 2005 14:25:57 +0000 (+0000) Subject: improved vss support (goal: only 1 binary, still problems on w2k3, xp seems to work) X-Git-Tag: Release-1.38.0~419 X-Git-Url: https://git.sur5r.net/?a=commitdiff_plain;h=681eb5d183d4742cbbbb75e0b9ca2123c25506e8;p=bacula%2Fbacula improved vss support (goal: only 1 binary, still problems on w2k3, xp seems to work) git-svn-id: https://bacula.svn.sourceforge.net/svnroot/bacula/trunk@2081 91ce42f0-d328-0410-95d8-f526ca767f89 --- diff --git a/bacula/src/filed/job.c b/bacula/src/filed/job.c index b6f02c51b9..7d3edd1b8b 100644 --- a/bacula/src/filed/job.c +++ b/bacula/src/filed/job.c @@ -1204,17 +1204,27 @@ static int backup_cmd(JCR *jcr) #ifdef WIN32_VSS /* START VSS ON WIN 32 */ - g_VSSClient.InitializeForBackup(); - /* tell vss which drives to snapshot */ - char szWinDriveLetters[27]; - if (get_win32_driveletters((FF_PKT *)jcr->ff, szWinDriveLetters)) { - Jmsg(jcr, M_INFO, 0, _("Generate VSS snapshots. Drives=%s\n"), szWinDriveLetters); - g_VSSClient.CreateSnapshots(szWinDriveLetters); - - for (int i=0; iInitializeForBackup()) { + /* tell vss which drives to snapshot */ + char szWinDriveLetters[27]; + if (get_win32_driveletters((FF_PKT *)jcr->ff, szWinDriveLetters)) { + Jmsg(jcr, M_INFO, 0, _("Generate VSS snapshots. Driver=%s, Drive(s)=%s\n"), g_pVSSClient->GetDriverName(), szWinDriveLetters); + + if (!g_pVSSClient->CreateSnapshots(szWinDriveLetters)) { + Jmsg(jcr, M_WARNING, 0, _("Generate VSS snapshots failed\n")); + } + else { + for (int i=0; iCloseBackup(); #endif bnet_fsend(dir, EndJob, jcr->JobStatus, jcr->JobFiles, diff --git a/bacula/src/lib/winapi.c b/bacula/src/lib/winapi.c index b7bf9d613e..0f640a49ad 100644 --- a/bacula/src/lib/winapi.c +++ b/bacula/src/lib/winapi.c @@ -31,8 +31,14 @@ #include "winapi.h" +#ifdef WIN32_VSS +#include "vss.h" +#endif + // init with win9x, but maybe set to NT in InitWinAPI DWORD g_platform_id = VER_PLATFORM_WIN32_WINDOWS; +/* preset VSSClient to NULL */ +VSSClient* g_pVSSClient = NULL; /* API Pointers */ @@ -75,6 +81,14 @@ t_SetCurrentDirectoryW p_SetCurrentDirectoryW = NULL; t_GetCurrentDirectoryA p_GetCurrentDirectoryA = NULL; t_GetCurrentDirectoryW p_GetCurrentDirectoryW = NULL; +#ifdef WIN32_VSS +void +VSSCleanup() +{ + if (g_pVSSClient) + delete (g_pVSSClient); +} +#endif void InitWinAPIWrapper() @@ -162,16 +176,21 @@ InitWinAPIWrapper() } // do we run on win 9x ??? - OSVERSIONINFO osversioninfo; + OSVERSIONINFO osversioninfo; osversioninfo.dwOSVersionInfoSize = sizeof(osversioninfo); + DWORD dwMinorVersion; + // Get the current OS version if (!GetVersionEx(&osversioninfo)) { g_platform_id = 0; + dwMinorVersion = 0; } else { g_platform_id = osversioninfo.dwPlatformId; + dwMinorVersion = osversioninfo.dwMinorVersion; } + /* deinitialize some routines on win95 - they're not implemented well */ if (g_platform_id == VER_PLATFORM_WIN32_WINDOWS) { p_BackupRead = NULL; p_BackupWrite = NULL; @@ -191,5 +210,20 @@ InitWinAPIWrapper() p_wmkdir = NULL; p_wopen = NULL; } + + /* decide which vss class to initialize */ +#ifdef WIN32_VSS + switch (dwMinorVersion) { + case 1: + g_pVSSClient = new VSSClientXP(); + atexit(VSSCleanup); + break; + case 2: + g_pVSSClient = new VSSClient2003(); + atexit(VSSCleanup); + break; + } +#endif } + #endif diff --git a/bacula/src/lib/winapi.h b/bacula/src/lib/winapi.h index ed3580a416..1b815d51d9 100644 --- a/bacula/src/lib/winapi.h +++ b/bacula/src/lib/winapi.h @@ -140,8 +140,8 @@ extern t_GetCurrentDirectoryA p_GetCurrentDirectoryA; extern t_GetCurrentDirectoryW p_GetCurrentDirectoryW; #ifdef WIN32_VSS -class VSSClient; -extern VSSClient g_VSSClient; +class VSSClient; +extern VSSClient* g_pVSSClient; #endif void InitWinAPIWrapper(); diff --git a/bacula/src/win32/compat/compat.cpp b/bacula/src/win32/compat/compat.cpp index 840c0404dd..18d1ec6ec4 100644 --- a/bacula/src/win32/compat/compat.cpp +++ b/bacula/src/win32/compat/compat.cpp @@ -84,12 +84,14 @@ cygwin_conv_to_win32_path(const char *name, char *win32_name, DWORD dwSize) can get longer because VSS will make something like \\\\?\\GLOBALROOT\\Device\\HarddiskVolumeShadowCopy1\\bacula\\uninstall.exe from c:\bacula\uninstall.exe - */ - POOLMEM* pszBuf = get_pool_memory (PM_FNAME); - pszBuf = check_pool_memory_size(pszBuf, dwSize); - bstrncpy (pszBuf, tname, strlen(tname)+1); - g_VSSClient.GetShadowPath(pszBuf,tname,dwSize); - free_pool_memory(pszBuf); + */ + if (g_pVSSClient) { + POOLMEM* pszBuf = get_pool_memory (PM_FNAME); + pszBuf = check_pool_memory_size(pszBuf, dwSize); + bstrncpy (pszBuf, tname, strlen(tname)+1); + g_pVSSClient->GetShadowPath(pszBuf,tname,dwSize); + free_pool_memory(pszBuf); + } #endif } diff --git a/bacula/src/win32/compat/vss.cpp b/bacula/src/win32/compat/vss.cpp index 6177b06c61..523cc68f21 100644 --- a/bacula/src/win32/compat/vss.cpp +++ b/bacula/src/win32/compat/vss.cpp @@ -65,74 +65,18 @@ using namespace std; // Used for safe string manipulation #include - -#include "vss/inc/WinXP/vss.h" -#include "vss/inc/WinXP/vswriter.h" -#include "vss/inc/WinXP/vsbackup.h" - #include "vss.h" -#pragma comment(lib,"C:/Development/bacula/bacula/src/win32/compat/vss/lib/WinXP/obj/i386/vssapi.lib") -#pragma comment(lib,"C:/Development/bacula/bacula/src/win32/compat/vss/lib/WinXP/obj/i386/vss_uuid.lib") -#pragma comment(lib,"atlsd.lib") - - - -// define global VssClient -VSSClient g_VSSClient; - -/* - * - * some helper functions - * - * - */ - -// Append a backslash to the current string -inline wstring AppendBackslash(wstring str) -{ - if (str.length() == 0) - return wstring(L"\\"); - if (str[str.length() - 1] == L'\\') - return str; - return str.append(L"\\"); -} - -// Get the unique volume name for the given path -inline wstring GetUniqueVolumeNameForPath(wstring path) -{ - _ASSERTE(path.length() > 0); - - // Add the backslash termination, if needed - path = AppendBackslash(path); - - // Get the root path of the volume - WCHAR volumeRootPath[MAX_PATH]; - WCHAR volumeName[MAX_PATH]; - WCHAR volumeUniqueName[MAX_PATH]; - if (!GetVolumePathNameW((LPCWSTR)path.c_str(), volumeRootPath, MAX_PATH)) - return L'\0'; - - // Get the volume name alias (might be different from the unique volume name in rare cases) - if (!GetVolumeNameForVolumeMountPointW(volumeRootPath, volumeName, MAX_PATH)) - return L'\0'; - - // Get the unique volume name - if (!GetVolumeNameForVolumeMountPointW(volumeName, volumeUniqueName, MAX_PATH)) - return L'\0'; - - return volumeUniqueName; -} +#pragma comment(lib,"atlsd.lib") -// we need something like a map // Constructor VSSClient::VSSClient() { m_bCoInitializeCalled = false; - m_dwContext = VSS_CTX_BACKUP; + m_dwContext = 0; // VSS_CTX_BACKUP; m_bDuringRestore = false; m_bBackupIsInitialized = false; m_pVssObject = NULL; @@ -157,232 +101,18 @@ VSSClient::~VSSClient() BOOL VSSClient::InitializeForBackup() { - return Initialize (VSS_CTX_BACKUP); -} - -// Initialize the COM infrastructure and the internal pointers -BOOL VSSClient::Initialize(DWORD dwContext, bool bDuringRestore) -{ - HRESULT hr; - // Initialize COM - if (!m_bCoInitializeCalled) { - if (FAILED(CoInitialize(NULL))) - return FALSE; - - m_bCoInitializeCalled = true; - - // Initialize COM security - hr = - CoInitializeSecurity( - NULL, // Allow *all* VSS writers to communicate back! - -1, // Default COM authentication service - NULL, // Default COM authorization service - NULL, // reserved parameter - RPC_C_AUTHN_LEVEL_PKT_PRIVACY, // Strongest COM authentication level - RPC_C_IMP_LEVEL_IDENTIFY, // Minimal impersonation abilities - NULL, // Default COM authentication settings - EOAC_NONE, // No special options - NULL // Reserved parameter - ); - - if (FAILED(hr)) - return FALSE; - } - - // Release the IVssBackupComponents interface - if (m_pVssObject) { - m_pVssObject->Release(); - m_pVssObject = NULL; - } - - // Create the internal backup components object - hr = CreateVssBackupComponents(&m_pVssObject); - if (FAILED(hr)) - return FALSE; - - // We are during restore now? - m_bDuringRestore = bDuringRestore; -/* - // Call either Initialize for backup or for restore - if (m_bDuringRestore) { - hr = m_pVssObject->InitializeForRestore(CComBSTR(L"")); - if (FAILED(hr)) - return FALSE; - } - else - { - // Initialize for backup - hr = m_pVssObject->InitializeForBackup(); - if (FAILED(hr)) - return FALSE; - } - - - - // Set various properties per backup components instance - hr = m_pVssObject->SetBackupState(true, true, VSS_BT_FULL, false); - if (FAILED(hr)) - return FALSE; -*/ -// Keep the context - m_dwContext = dwContext; - - return TRUE; + //return Initialize (VSS_CTX_BACKUP); + return Initialize (0); } -void VSSClient::WaitAndCheckForAsyncOperation(IVssAsync* pAsync) -{ - // Wait until the async operation finishes - HRESULT hr = pAsync->Wait(); - - // Check the result of the asynchronous operation - HRESULT hrReturned = S_OK; - hr = pAsync->QueryStatus(&hrReturned, NULL); - // Check if the async operation succeeded... - if(FAILED(hrReturned)) - { - throw(hrReturned); - } -} -BOOL VSSClient::CreateSnapshots(char* szDriveLetters) -{ - /* szDriveLetters contains all drive letters in uppercase */ - /* if a drive can not being added, it's converted to lowercase in szDriveLetters */ - /* http://msdn.microsoft.com/library/default.asp?url=/library/en-us/vss/base/ivssbackupcomponents_startsnapshotset.asp */ - - if (!m_pVssObject || m_bBackupIsInitialized) - return FALSE; - - m_bBackupIsInitialized = true; - - // 1. InitializeForBackup - HRESULT hr = m_pVssObject->InitializeForBackup(); - if (FAILED(hr)) - return FALSE; - - // 2. SetBackupState - hr = m_pVssObject->SetBackupState(true, true, VSS_BT_FULL, false); - if (FAILED(hr)) - return FALSE; - - CComPtr pAsync; - VSS_ID latestSnapshotSetID; - VSS_ID pid; - - // 3. startSnapshotSet - - m_pVssObject->StartSnapshotSet(&latestSnapshotSetID); - - // 4. AddToSnapshotSet - - WCHAR szDrive[3]; - szDrive[1] = ':'; - szDrive[2] = 0; - - wstring volume; - - for (size_t i=0; i < strlen (szDriveLetters); i++) { - szDrive[0] = szDriveLetters[i]; - volume = GetUniqueVolumeNameForPath(szDrive); - // store uniquevolumname - if (SUCCEEDED(m_pVssObject->AddToSnapshotSet((LPWSTR)volume.c_str(), GUID_NULL, &pid))) - wcsncpy (m_wszUniqueVolumeName[szDriveLetters[i]-'A'], (LPWSTR) volume.c_str(), MAX_PATH); - else - szDriveLetters[i] = tolower (szDriveLetters[i]); - } - - // 5. PrepareForBackup - - m_pVssObject->PrepareForBackup(&pAsync); - - // Waits for the async operation to finish and checks the result - WaitAndCheckForAsyncOperation(pAsync); - - - // 6. DoSnapShotSet - - pAsync = NULL; - m_pVssObject->DoSnapshotSet(&pAsync); - - // Waits for the async operation to finish and checks the result - WaitAndCheckForAsyncOperation(pAsync); - - /* query snapshot info */ - QuerySnapshotSet(latestSnapshotSetID); - - return TRUE; -} - -BOOL VSSClient::CloseBackup() +BOOL VSSClient::GetShadowPath (const char* szFilePath, char* szShadowPath, int nBuflen) { - if (!m_pVssObject || !m_bBackupIsInitialized) + if (!m_bBackupIsInitialized) return FALSE; - m_bBackupIsInitialized = false; - - CComPtr pAsync; - - if (SUCCEEDED(m_pVssObject->BackupComplete(&pAsync))) { - // Waits for the async operation to finish and checks the result - WaitAndCheckForAsyncOperation(pAsync); - } - else return FALSE; - - return TRUE; -} - -// Query all the shadow copies in the given set -void VSSClient::QuerySnapshotSet(GUID snapshotSetID) -{ - memset (m_szShadowCopyName,0,sizeof (m_szShadowCopyName)); - - if (snapshotSetID == GUID_NULL || m_pVssObject == NULL) - return; - - // Get list all shadow copies. - CComPtr pIEnumSnapshots; - HRESULT hr = m_pVssObject->Query( GUID_NULL, - VSS_OBJECT_NONE, - VSS_OBJECT_SNAPSHOT, - &pIEnumSnapshots ); - - // If there are no shadow copies, just return - if (hr == S_FALSE) { - return; - } - - // Enumerate all shadow copies. - VSS_OBJECT_PROP Prop; - VSS_SNAPSHOT_PROP& Snap = Prop.Obj.Snap; - - while(true) - { - // Get the next element - ULONG ulFetched; - hr = pIEnumSnapshots->Next( 1, &Prop, &ulFetched ); - - // We reached the end of list - if (ulFetched == 0) - break; - - // Print the shadow copy (if not filtered out) - if (Snap.m_SnapshotSetId == snapshotSetID) { - for (char ch='A'-'A';ch<='Z'-'A';ch++) { - if (wcscmp(Snap.m_pwszOriginalVolumeName, m_wszUniqueVolumeName[ch]) == 0) { - WideCharToMultiByte(CP_UTF8,0,Snap.m_pwszSnapshotDeviceObject,-1,m_szShadowCopyName[ch],MAX_PATH*2,NULL,NULL); - break; - } - } - } - ::VssFreeSnapshotProperties(&Snap); - } -} - -BOOL VSSClient::GetShadowPath (const char* szFilePath, char* szShadowPath, int nBuflen) -{ /* check for valid pathname */ BOOL bIsValidName; diff --git a/bacula/src/win32/compat/vss.h b/bacula/src/win32/compat/vss.h index 9b26f0470b..d8abd82479 100644 --- a/bacula/src/win32/compat/vss.h +++ b/bacula/src/win32/compat/vss.h @@ -34,7 +34,6 @@ #define __VSS_H_ // some forward declarations -class IVssBackupComponents; struct IVssAsync; class VSSClient @@ -45,33 +44,60 @@ public: // Backup Process BOOL InitializeForBackup(); - BOOL CreateSnapshots(char* szDriveLetters); + virtual BOOL CreateSnapshots(char* szDriveLetters) = 0; + virtual BOOL CloseBackup() = 0; + virtual const char* GetDriverName() = 0; BOOL GetShadowPath (const char* szFilePath, char* szShadowPath, int nBuflen); - BOOL CloseBackup(); - -private: - - BOOL Initialize(DWORD dwContext, bool bDuringRestore = false); - void WaitAndCheckForAsyncOperation(IVssAsync* pAsync); - void QuerySnapshotSet(GUID snapshotSetID); + private: + virtual BOOL Initialize(DWORD dwContext, BOOL bDuringRestore = FALSE) = 0; + virtual void WaitAndCheckForAsyncOperation(IVssAsync* pAsync) = 0; + virtual void QuerySnapshotSet(GUID snapshotSetID) = 0; + +protected: + HMODULE m_hLib; - bool m_bCoInitializeCalled; + BOOL m_bCoInitializeCalled; DWORD m_dwContext; - IVssBackupComponents* m_pVssObject; + IUnknown* m_pVssObject; // TRUE if we are during restore - bool m_bDuringRestore; - bool m_bBackupIsInitialized; + BOOL m_bDuringRestore; + BOOL m_bBackupIsInitialized; // drive A will be stored on position 0,Z on pos. 25 WCHAR m_wszUniqueVolumeName[26][MAX_PATH]; // approx. 7 KB char /* in utf-8 */ m_szShadowCopyName[26][MAX_PATH*2]; // approx. 7 KB }; -// define global VssClient -extern VSSClient g_VSSClient; +class VSSClientXP:public VSSClient +{ +public: + VSSClientXP(); + virtual ~VSSClientXP(); + virtual BOOL CreateSnapshots(char* szDriveLetters); + virtual BOOL CloseBackup(); + virtual const char* GetDriverName() { return "VSS WinXP"; }; +private: + virtual BOOL Initialize(DWORD dwContext, BOOL bDuringRestore); + virtual void WaitAndCheckForAsyncOperation(IVssAsync* pAsync); + virtual void QuerySnapshotSet(GUID snapshotSetID); +}; + +class VSSClient2003:public VSSClient +{ +public: + VSSClient2003(); + virtual ~VSSClient2003(); + virtual BOOL CreateSnapshots(char* szDriveLetters); + virtual BOOL CloseBackup(); + virtual const char* GetDriverName() { return "VSS Win 2003"; }; +private: + virtual BOOL Initialize(DWORD dwContext, BOOL bDuringRestore); + virtual void WaitAndCheckForAsyncOperation(IVssAsync* pAsync); + virtual void QuerySnapshotSet(GUID snapshotSetID); +}; #endif /* __VSS_H_ */ diff --git a/bacula/src/win32/compat/vss_W2K3.cpp b/bacula/src/win32/compat/vss_W2K3.cpp new file mode 100644 index 0000000000..d052f79e07 --- /dev/null +++ b/bacula/src/win32/compat/vss_W2K3.cpp @@ -0,0 +1,14 @@ +/* +we need one class per OS as Microsofts API +differs only by calling convention and some +function we don't use. + +vss_generic will handle all versions and +switch between different headers to include. +*/ + +#define B_VSS_W2K3 +#include "vss_generic.cpp" + + + diff --git a/bacula/src/win32/compat/vss_XP.cpp b/bacula/src/win32/compat/vss_XP.cpp new file mode 100644 index 0000000000..45c084bca1 --- /dev/null +++ b/bacula/src/win32/compat/vss_XP.cpp @@ -0,0 +1,3 @@ +#define B_VSS_XP +#include "vss_generic.cpp" + diff --git a/bacula/src/win32/compat/vss_generic.cpp b/bacula/src/win32/compat/vss_generic.cpp new file mode 100644 index 0000000000..81323e41b4 --- /dev/null +++ b/bacula/src/win32/compat/vss_generic.cpp @@ -0,0 +1,410 @@ +// -*- Mode: C++ -*- +// vss.cpp -- Interface to Volume Shadow Copies (VSS) +// +// Copyright transferred from MATRIX-Computer GmbH to +// Kern Sibbald by express permission. +// +// Copyright (C) 2004-2005 Kern Sibbald +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 2 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free +// Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, +// MA 02111-1307, USA. +// +// Author : Thorsten Engel +// Created On : Fri May 06 21:44:00 2006 + + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +// STL includes +#include +#include +#include +#include +using namespace std; + +#include +#include + +// Used for safe string manipulation +#include + +#ifdef B_VSS_XP + #pragma message("compile VSS for Windows XP") + #define VSSClientGeneric VSSClientXP + + #include "vss/inc/WinXP/vss.h" + #include "vss/inc/WinXP/vswriter.h" + #include "vss/inc/WinXP/vsbackup.h" + + /* In VSSAPI.DLL */ + typedef HRESULT (STDAPICALLTYPE* t_CreateVssBackupComponents)(OUT IVssBackupComponents **); + typedef void (APIENTRY* t_VssFreeSnapshotProperties)(IN VSS_SNAPSHOT_PROP*); + + static t_CreateVssBackupComponents p_CreateVssBackupComponents = NULL; + static t_VssFreeSnapshotProperties p_VssFreeSnapshotProperties = NULL; + + #define VSSVBACK_ENTRY "?CreateVssBackupComponents@@YGJPAPAVIVssBackupComponents@@@Z" +#endif + +#ifdef B_VSS_W2K3 + #pragma message("compile VSS for Windows 2003") + #define VSSClientGeneric VSSClient2003 + + #include "vss/inc/Win2003/vss.h" + #include "vss/inc/Win2003/vswriter.h" + #include "vss/inc/Win2003/vsbackup.h" + + /* In VSSAPI.DLL */ + typedef HRESULT (STDAPICALLTYPE* t_CreateVssBackupComponents)(OUT IVssBackupComponents **); + typedef void (APIENTRY* t_VssFreeSnapshotProperties)(IN VSS_SNAPSHOT_PROP*); + + static t_CreateVssBackupComponents p_CreateVssBackupComponents = NULL; + static t_VssFreeSnapshotProperties p_VssFreeSnapshotProperties = NULL; + + #define VSSVBACK_ENTRY "?CreateVssBackupComponents@@YGJPAPAVIVssBackupComponents@@@Z" +#endif + +#include "vss.h" + +/* + * + * some helper functions + * + * + */ + +// Append a backslash to the current string +inline wstring AppendBackslash(wstring str) +{ + if (str.length() == 0) + return wstring(L"\\"); + if (str[str.length() - 1] == L'\\') + return str; + return str.append(L"\\"); +} + +// Get the unique volume name for the given path +inline wstring GetUniqueVolumeNameForPath(wstring path) +{ + _ASSERTE(path.length() > 0); + + // Add the backslash termination, if needed + path = AppendBackslash(path); + + // Get the root path of the volume + WCHAR volumeRootPath[MAX_PATH]; + WCHAR volumeName[MAX_PATH]; + WCHAR volumeUniqueName[MAX_PATH]; + + if (!GetVolumePathNameW((LPCWSTR)path.c_str(), volumeRootPath, MAX_PATH)) + return L'\0'; + + // Get the volume name alias (might be different from the unique volume name in rare cases) + if (!GetVolumeNameForVolumeMountPointW(volumeRootPath, volumeName, MAX_PATH)) + return L'\0'; + + // Get the unique volume name + if (!GetVolumeNameForVolumeMountPointW(volumeName, volumeUniqueName, MAX_PATH)) + return L'\0'; + + return volumeUniqueName; +} + + + +// Constructor + +VSSClientGeneric::VSSClientGeneric() +{ + m_hLib = LoadLibraryA("VSSAPI.DLL"); + if (m_hLib) { + p_CreateVssBackupComponents = (t_CreateVssBackupComponents) + GetProcAddress(m_hLib, VSSVBACK_ENTRY); + + p_VssFreeSnapshotProperties = (t_VssFreeSnapshotProperties) + GetProcAddress(m_hLib, "VssFreeSnapshotProperties"); + } +} + + + +// Destructor +VSSClientGeneric::~VSSClientGeneric() +{ + if (m_hLib) + FreeLibrary(m_hLib); +} + +// Initialize the COM infrastructure and the internal pointers +BOOL VSSClientGeneric::Initialize(DWORD dwContext, BOOL bDuringRestore) +{ + if (!(p_CreateVssBackupComponents && p_VssFreeSnapshotProperties)) + return FALSE; + + HRESULT hr; + // Initialize COM + if (!m_bCoInitializeCalled) { + if (FAILED(CoInitialize(NULL))) + return FALSE; + + m_bCoInitializeCalled = true; + + // Initialize COM security + hr = + CoInitializeSecurity( + NULL, // Allow *all* VSS writers to communicate back! + -1, // Default COM authentication service + NULL, // Default COM authorization service + NULL, // reserved parameter + RPC_C_AUTHN_LEVEL_PKT_PRIVACY, // Strongest COM authentication level + RPC_C_IMP_LEVEL_IDENTIFY, // Minimal impersonation abilities + NULL, // Default COM authentication settings + EOAC_NONE, // No special options + NULL // Reserved parameter + ); + + if (FAILED(hr)) + return FALSE; + } + + IVssBackupComponents* pVss = (IVssBackupComponents*) m_pVssObject; + // Release the IVssBackupComponents interface + if (pVss) { + pVss->Release(); + pVss = NULL; + } + + // Create the internal backup components object + hr = p_CreateVssBackupComponents((IVssBackupComponents**) &m_pVssObject); + if (FAILED(hr)) + return FALSE; + + // We are during restore now? + m_bDuringRestore = bDuringRestore; + + // Keep the context + m_dwContext = dwContext; + + return TRUE; +} + + +void VSSClientGeneric::WaitAndCheckForAsyncOperation(IVssAsync* pAsync) +{ + // Wait until the async operation finishes + HRESULT hr = pAsync->Wait(); + + // Check the result of the asynchronous operation + HRESULT hrReturned = S_OK; + hr = pAsync->QueryStatus(&hrReturned, NULL); + + // Check if the async operation succeeded... + if(FAILED(hrReturned)) + { + PWCHAR pwszBuffer = NULL; + DWORD dwRet = ::FormatMessageW( + FORMAT_MESSAGE_ALLOCATE_BUFFER + | FORMAT_MESSAGE_FROM_SYSTEM + | FORMAT_MESSAGE_IGNORE_INSERTS, + NULL, hrReturned, + MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), + (LPWSTR)&pwszBuffer, 0, NULL); + + // No message found for this error. Just return + if (dwRet != 0) + { + // Convert the message into wstring + + LocalFree(pwszBuffer); + } + throw(hrReturned); + } +} + +BOOL VSSClientGeneric::CreateSnapshots(char* szDriveLetters) +{ + /* szDriveLetters contains all drive letters in uppercase */ + /* if a drive can not being added, it's converted to lowercase in szDriveLetters */ + /* http://msdn.microsoft.com/library/default.asp?url=/library/en-us/vss/base/ivssbackupcomponents_startsnapshotset.asp */ + + if (!m_pVssObject || m_bBackupIsInitialized) + return FALSE; + + IVssBackupComponents* pVss = (IVssBackupComponents*) m_pVssObject; + + // 1. InitializeForBackup + HRESULT hr = pVss->InitializeForBackup(); + if (FAILED(hr)) + return FALSE; + + // 2. SetBackupState + hr = pVss->SetBackupState(true, true, VSS_BT_FULL, false); + if (FAILED(hr)) + return FALSE; + + CComPtr pAsync1; + CComPtr pAsync2; + VSS_ID latestSnapshotSetID; + VSS_ID pid; + + // 3. startSnapshotSet + + pVss->StartSnapshotSet(&latestSnapshotSetID); + + // 4. AddToSnapshotSet + + WCHAR szDrive[3]; + szDrive[1] = ':'; + szDrive[2] = 0; + + wstring volume; + + for (size_t i=0; i < strlen (szDriveLetters); i++) { + szDrive[0] = szDriveLetters[i]; + volume = GetUniqueVolumeNameForPath(szDrive); + // store uniquevolumname + if (SUCCEEDED(pVss->AddToSnapshotSet((LPWSTR)volume.c_str(), GUID_NULL, &pid))) + wcsncpy (m_wszUniqueVolumeName[szDriveLetters[i]-'A'], (LPWSTR) volume.c_str(), MAX_PATH); + else + szDriveLetters[i] = tolower (szDriveLetters[i]); + } + + // 5. PrepareForBackup + + pVss->PrepareForBackup(&pAsync1); + + // Waits for the async operation to finish and checks the result + WaitAndCheckForAsyncOperation(pAsync1); + + + // 6. DoSnapShotSet + + pVss->DoSnapshotSet(&pAsync2); + + // Waits for the async operation to finish and checks the result + WaitAndCheckForAsyncOperation(pAsync2); + + /* query snapshot info */ + QuerySnapshotSet(latestSnapshotSetID); + + m_bBackupIsInitialized = true; + + return TRUE; +} + +BOOL VSSClientGeneric::CloseBackup() +{ + if (!m_pVssObject) + return FALSE; + + BOOL bRet = FALSE; + IVssBackupComponents* pVss = (IVssBackupComponents*) m_pVssObject; + CComPtr pAsync; + + m_bBackupIsInitialized = false; + + if (SUCCEEDED(pVss->BackupComplete(&pAsync))) { + // Waits for the async operation to finish and checks the result + WaitAndCheckForAsyncOperation(pAsync); + bRet = TRUE; + } + else { + pVss->AbortBackup(); + } + + pVss->Release(); + m_pVssObject = NULL; + + return bRet; +} + +// Query all the shadow copies in the given set +void VSSClientGeneric::QuerySnapshotSet(GUID snapshotSetID) +{ + if (!(p_CreateVssBackupComponents && p_VssFreeSnapshotProperties)) + return; + + memset (m_szShadowCopyName,0,sizeof (m_szShadowCopyName)); + + if (snapshotSetID == GUID_NULL || m_pVssObject == NULL) + return; + + IVssBackupComponents* pVss = (IVssBackupComponents*) m_pVssObject; + + + // Get list all shadow copies. + CComPtr pIEnumSnapshots; + HRESULT hr = pVss->Query( GUID_NULL, + VSS_OBJECT_NONE, + VSS_OBJECT_SNAPSHOT, + &pIEnumSnapshots ); + + // If there are no shadow copies, just return + if (hr == S_FALSE) { + return; + } + + // Enumerate all shadow copies. + VSS_OBJECT_PROP Prop; + VSS_SNAPSHOT_PROP& Snap = Prop.Obj.Snap; + + while(true) + { + // Get the next element + ULONG ulFetched; + hr = pIEnumSnapshots->Next( 1, &Prop, &ulFetched ); + + // We reached the end of list + if (ulFetched == 0) + break; + + // Print the shadow copy (if not filtered out) + if (Snap.m_SnapshotSetId == snapshotSetID) { + for (char ch='A'-'A';ch<='Z'-'A';ch++) { + if (wcscmp(Snap.m_pwszOriginalVolumeName, m_wszUniqueVolumeName[ch]) == 0) { + WideCharToMultiByte(CP_UTF8,0,Snap.m_pwszSnapshotDeviceObject,-1,m_szShadowCopyName[ch],MAX_PATH*2,NULL,NULL); + break; + } + } + } + p_VssFreeSnapshotProperties(&Snap); + } +} +