From: Thorsten Engel Date: Tue, 17 May 2005 12:00:47 +0000 (+0000) Subject: experimental vss support (needs some microsoft libs and include files + WIN32_VSS... X-Git-Tag: Release-1.38.0~447 X-Git-Url: https://git.sur5r.net/?a=commitdiff_plain;h=6439f489bfab55f3dad23781120c1b081dc9ab5b;p=bacula%2Fbacula experimental vss support (needs some microsoft libs and include files + WIN32_VSS compiler switch) git-svn-id: https://bacula.svn.sourceforge.net/svnroot/bacula/trunk@2053 91ce42f0-d328-0410-95d8-f526ca767f89 --- diff --git a/bacula/src/win32/compat/vss.cpp b/bacula/src/win32/compat/vss.cpp new file mode 100644 index 0000000000..6177b06c61 --- /dev/null +++ b/bacula/src/win32/compat/vss.cpp @@ -0,0 +1,408 @@ +// -*- 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 + +#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; +} + + +// we need something like a map + +// Constructor +VSSClient::VSSClient() +{ + m_bCoInitializeCalled = false; + m_dwContext = VSS_CTX_BACKUP; + m_bDuringRestore = false; + m_bBackupIsInitialized = false; + m_pVssObject = NULL; + memset (m_wszUniqueVolumeName,0,sizeof (m_wszUniqueVolumeName)); + memset (m_szShadowCopyName,0,sizeof (m_szShadowCopyName)); +} + +// Destructor +VSSClient::~VSSClient() +{ + // Release the IVssBackupComponents interface + // WARNING: this must be done BEFORE calling CoUninitialize() + if (m_pVssObject) { + m_pVssObject->Release(); + m_pVssObject = NULL; + } + + // Call CoUninitialize if the CoInitialize was performed sucesfully + if (m_bCoInitializeCalled) + CoUninitialize(); +} + +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; +} + + +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() +{ + if (!m_pVssObject || !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; + + bIsValidName = strlen (szFilePath) > 3; + if (bIsValidName) + bIsValidName &= isalpha (szFilePath[0]) && + szFilePath[1]==':' && + szFilePath[2]=='\\'; + + if (bIsValidName) { + int nDriveIndex = toupper(szFilePath[0])-'A'; + if (m_szShadowCopyName[nDriveIndex][0] != 0) { + strncpy (szShadowPath, m_szShadowCopyName[nDriveIndex], nBuflen); + nBuflen -= (int) strlen (m_szShadowCopyName[nDriveIndex]); + strncat (szShadowPath, szFilePath+2,nBuflen); + + return TRUE; + } + } + + strncpy (szShadowPath, szFilePath, nBuflen); + return FALSE; +} \ No newline at end of file diff --git a/bacula/src/win32/compat/vss.h b/bacula/src/win32/compat/vss.h new file mode 100644 index 0000000000..9b26f0470b --- /dev/null +++ b/bacula/src/win32/compat/vss.h @@ -0,0 +1,77 @@ +/* -*- Mode: C -*- + * vss.h -- + */ + +// +// 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 + */ + +#ifndef __VSS_H_ +#define __VSS_H_ + +// some forward declarations +class IVssBackupComponents; +struct IVssAsync; + +class VSSClient +{ +public: + VSSClient(); + ~VSSClient(); + + // Backup Process + BOOL InitializeForBackup(); + BOOL CreateSnapshots(char* szDriveLetters); + 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: + + bool m_bCoInitializeCalled; + DWORD m_dwContext; + + IVssBackupComponents* m_pVssObject; + // TRUE if we are during restore + 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; + + +#endif /* __VSS_H_ */