#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; i<strlen (szWinDriveLetters); i++) {
- if (islower(szWinDriveLetters[i]))
- Jmsg(jcr, M_WARNING, 0, _("Generate VSS snapshot of drive %c: failed\n"), szWinDriveLetters[i]);
+ if (g_pVSSClient) {
+ if (g_pVSSClient->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. 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; i<strlen (szWinDriveLetters); i++) {
+ if (islower(szWinDriveLetters[i]))
+ Jmsg(jcr, M_WARNING, 0, _("Generate VSS snapshot of drive %c: failed\n"), szWinDriveLetters[i]);
+ }
+ }
+ }
+ } else {
+ Jmsg(jcr, M_WARNING, 0, _("VSS was not initialized properly. VSS support is disabled."));
}
+
}
#endif
cleanup:
#ifdef WIN32_VSS
/* tell vss to close the backup session */
- g_VSSClient.CloseBackup();
+ if (g_pVSSClient)
+ g_pVSSClient->CloseBackup();
#endif
bnet_fsend(dir, EndJob, jcr->JobStatus, jcr->JobFiles,
#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 */
t_GetCurrentDirectoryA p_GetCurrentDirectoryA = NULL;
t_GetCurrentDirectoryW p_GetCurrentDirectoryW = NULL;
+#ifdef WIN32_VSS
+void
+VSSCleanup()
+{
+ if (g_pVSSClient)
+ delete (g_pVSSClient);
+}
+#endif
void
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;
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
extern t_GetCurrentDirectoryW p_GetCurrentDirectoryW;
#ifdef WIN32_VSS
-class VSSClient;
-extern VSSClient g_VSSClient;
+class VSSClient;
+extern VSSClient* g_pVSSClient;
#endif
void InitWinAPIWrapper();
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
}
// Used for safe string manipulation
#include <strsafe.h>
-
-#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;
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<IVssAsync> 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<IVssAsync> 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<IVssEnumObject> 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;
#define __VSS_H_
// some forward declarations
-class IVssBackupComponents;
struct IVssAsync;
class VSSClient
// 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_ */
--- /dev/null
+/*
+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"
+
+
+
--- /dev/null
+#define B_VSS_XP
+#include "vss_generic.cpp"
+
--- /dev/null
+// -*- 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 <stdio.h>
+#include <basetsd.h>
+#include <stdarg.h>
+#include <sys/types.h>
+#include <process.h>
+#include <direct.h>
+#include <winsock2.h>
+#include <windows.h>
+#include <wincon.h>
+#include <winbase.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <conio.h>
+#include <process.h>
+#include <errno.h>
+#include <string.h>
+#include <time.h>
+#include <signal.h>
+#include <malloc.h>
+#include <setjmp.h>
+#include <direct.h>
+#include <ctype.h>
+#include <fcntl.h>
+#include <io.h>
+
+
+// STL includes
+#include <vector>
+#include <algorithm>
+#include <string>
+#include <fstream>
+using namespace std;
+
+#include <atlcomcli.h>
+#include <objbase.h>
+
+// Used for safe string manipulation
+#include <strsafe.h>
+
+#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 <Unknown>
+ 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<IVssAsync> pAsync1;
+ CComPtr<IVssAsync> 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<IVssAsync> 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<IVssEnumObject> 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);
+ }
+}
+