From bbb20cd378f2d8da77b6c5e50061f3113e3c7ef2 Mon Sep 17 00:00:00 2001 From: Thorsten Engel Date: Thu, 9 Jun 2005 17:39:42 +0000 Subject: [PATCH] major changes of VSS support (added VSS Writer support + proofed functionality on W2K3) git-svn-id: https://bacula.svn.sourceforge.net/svnroot/bacula/trunk@2117 91ce42f0-d328-0410-95d8-f526ca767f89 --- bacula/src/win32/compat/vss.cpp | 29 ++++ bacula/src/win32/compat/vss.h | 9 ++ bacula/src/win32/compat/vss_generic.cpp | 175 +++++++++++++++++++++--- 3 files changed, 195 insertions(+), 18 deletions(-) diff --git a/bacula/src/win32/compat/vss.cpp b/bacula/src/win32/compat/vss.cpp index 523cc68f21..5104b33432 100644 --- a/bacula/src/win32/compat/vss.cpp +++ b/bacula/src/win32/compat/vss.cpp @@ -80,6 +80,9 @@ VSSClient::VSSClient() m_bDuringRestore = false; m_bBackupIsInitialized = false; m_pVssObject = NULL; + m_pVectorWriterStates = new vector; + m_pVectorWriterInfo = new vector; + m_uidCurrentSnapshotSet = GUID_NULL; memset (m_wszUniqueVolumeName,0,sizeof (m_wszUniqueVolumeName)); memset (m_szShadowCopyName,0,sizeof (m_szShadowCopyName)); } @@ -94,6 +97,12 @@ VSSClient::~VSSClient() m_pVssObject = NULL; } + if (m_pVectorWriterStates) + delete (m_pVectorWriterStates); + + if (m_pVectorWriterInfo) + delete (m_pVectorWriterInfo); + // Call CoUninitialize if the CoInitialize was performed sucesfully if (m_bCoInitializeCalled) CoUninitialize(); @@ -135,4 +144,24 @@ BOOL VSSClient::GetShadowPath (const char* szFilePath, char* szShadowPath, int n strncpy (szShadowPath, szFilePath, nBuflen); return FALSE; +} + + +const size_t VSSClient::GetWriterCount() +{ + vector* pV = (vector*) m_pVectorWriterStates; + return pV->size(); +} + +const char* VSSClient::GetWriterInfo(size_t nIndex) +{ + vector* pV = (vector*) m_pVectorWriterInfo; + return pV->at(nIndex).c_str(); +} + + +const int VSSClient::GetWriterState(size_t nIndex) +{ + vector* pV = (vector*) m_pVectorWriterStates; + return pV->at(nIndex); } \ No newline at end of file diff --git a/bacula/src/win32/compat/vss.h b/bacula/src/win32/compat/vss.h index d8abd82479..f773eeac3f 100644 --- a/bacula/src/win32/compat/vss.h +++ b/bacula/src/win32/compat/vss.h @@ -49,6 +49,9 @@ public: virtual const char* GetDriverName() = 0; BOOL GetShadowPath (const char* szFilePath, char* szShadowPath, int nBuflen); + const size_t GetWriterCount(); + const char* GetWriterInfo(size_t nIndex); + const int GetWriterState(size_t nIndex); private: virtual BOOL Initialize(DWORD dwContext, BOOL bDuringRestore = FALSE) = 0; @@ -62,6 +65,7 @@ protected: DWORD m_dwContext; IUnknown* m_pVssObject; + GUID m_uidCurrentSnapshotSet; // TRUE if we are during restore BOOL m_bDuringRestore; BOOL m_bBackupIsInitialized; @@ -69,6 +73,9 @@ protected: // 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 + + void* m_pVectorWriterStates; + void* m_pVectorWriterInfo; }; class VSSClientXP:public VSSClient @@ -83,6 +90,7 @@ private: virtual BOOL Initialize(DWORD dwContext, BOOL bDuringRestore); virtual void WaitAndCheckForAsyncOperation(IVssAsync* pAsync); virtual void QuerySnapshotSet(GUID snapshotSetID); + BOOL CheckWriterStatus(); }; class VSSClient2003:public VSSClient @@ -97,6 +105,7 @@ private: virtual BOOL Initialize(DWORD dwContext, BOOL bDuringRestore); virtual void WaitAndCheckForAsyncOperation(IVssAsync* pAsync); virtual void QuerySnapshotSet(GUID snapshotSetID); + BOOL CheckWriterStatus(); }; diff --git a/bacula/src/win32/compat/vss_generic.cpp b/bacula/src/win32/compat/vss_generic.cpp index 81323e41b4..bafc9ee380 100644 --- a/bacula/src/win32/compat/vss_generic.cpp +++ b/bacula/src/win32/compat/vss_generic.cpp @@ -56,6 +56,7 @@ #include #include #include +#include #include using namespace std; @@ -148,6 +149,38 @@ inline wstring GetUniqueVolumeNameForPath(wstring path) } +// Helper macro for quick treatment of case statements for error codes +#define GEN_MERGE(A, B) A##B +#define GEN_MAKE_W(A) GEN_MERGE(L, A) + +#define CHECK_CASE_FOR_CONSTANT(value) \ + case value: return wstring(GEN_MAKE_W(#value)); + + +// Convert a writer status into a string +inline wstring GetStringFromWriterStatus(VSS_WRITER_STATE eWriterStatus) +{ + switch (eWriterStatus) + { + CHECK_CASE_FOR_CONSTANT(VSS_WS_STABLE); + CHECK_CASE_FOR_CONSTANT(VSS_WS_WAITING_FOR_FREEZE); + CHECK_CASE_FOR_CONSTANT(VSS_WS_WAITING_FOR_THAW); + CHECK_CASE_FOR_CONSTANT(VSS_WS_WAITING_FOR_POST_SNAPSHOT); + CHECK_CASE_FOR_CONSTANT(VSS_WS_WAITING_FOR_BACKUP_COMPLETE); + CHECK_CASE_FOR_CONSTANT(VSS_WS_FAILED_AT_IDENTIFY); + CHECK_CASE_FOR_CONSTANT(VSS_WS_FAILED_AT_PREPARE_BACKUP); + CHECK_CASE_FOR_CONSTANT(VSS_WS_FAILED_AT_PREPARE_SNAPSHOT); + CHECK_CASE_FOR_CONSTANT(VSS_WS_FAILED_AT_FREEZE); + CHECK_CASE_FOR_CONSTANT(VSS_WS_FAILED_AT_THAW); + CHECK_CASE_FOR_CONSTANT(VSS_WS_FAILED_AT_POST_SNAPSHOT); + CHECK_CASE_FOR_CONSTANT(VSS_WS_FAILED_AT_BACKUP_COMPLETE); + CHECK_CASE_FOR_CONSTANT(VSS_WS_FAILED_AT_PRE_RESTORE); + CHECK_CASE_FOR_CONSTANT(VSS_WS_FAILED_AT_POST_RESTORE); + + default: + return wstring(L"Undefined"); + } +} // Constructor @@ -203,12 +236,11 @@ BOOL VSSClientGeneric::Initialize(DWORD dwContext, BOOL bDuringRestore) if (FAILED(hr)) return FALSE; } - - IVssBackupComponents* pVss = (IVssBackupComponents*) m_pVssObject; + // Release the IVssBackupComponents interface - if (pVss) { - pVss->Release(); - pVss = NULL; + if (m_pVssObject) { + m_pVssObject->Release(); + m_pVssObject = NULL; } // Create the internal backup components object @@ -216,6 +248,14 @@ BOOL VSSClientGeneric::Initialize(DWORD dwContext, BOOL bDuringRestore) if (FAILED(hr)) return FALSE; +#ifdef B_VSS_W2K3 + if (dwContext != VSS_CTX_BACKUP) { + hr = ((IVssBackupComponents*) m_pVssObject)->SetContext(dwContext); + if (FAILED(hr)) + return FALSE; + } +#endif + // We are during restore now? m_bDuringRestore = bDuringRestore; @@ -254,7 +294,6 @@ void VSSClientGeneric::WaitAndCheckForAsyncOperation(IVssAsync* pAsync) LocalFree(pwszBuffer); } - throw(hrReturned); } } @@ -265,7 +304,9 @@ BOOL VSSClientGeneric::CreateSnapshots(char* szDriveLetters) /* http://msdn.microsoft.com/library/default.asp?url=/library/en-us/vss/base/ivssbackupcomponents_startsnapshotset.asp */ if (!m_pVssObject || m_bBackupIsInitialized) - return FALSE; + return FALSE; + + m_uidCurrentSnapshotSet = GUID_NULL; IVssBackupComponents* pVss = (IVssBackupComponents*) m_pVssObject; @@ -280,13 +321,23 @@ BOOL VSSClientGeneric::CreateSnapshots(char* szDriveLetters) return FALSE; CComPtr pAsync1; - CComPtr pAsync2; - VSS_ID latestSnapshotSetID; + CComPtr pAsync2; + CComPtr pAsync3; VSS_ID pid; - // 3. startSnapshotSet + // 3. GatherWriterMetaData + hr = pVss->GatherWriterMetadata(&pAsync3); + if (FAILED(hr)) + return FALSE; - pVss->StartSnapshotSet(&latestSnapshotSetID); + // Waits for the async operation to finish and checks the result + WaitAndCheckForAsyncOperation(pAsync3); + + CheckWriterStatus(); + + // 4. startSnapshotSet + + pVss->StartSnapshotSet(&m_uidCurrentSnapshotSet); // 4. AddToSnapshotSet @@ -307,22 +358,19 @@ BOOL VSSClientGeneric::CreateSnapshots(char* szDriveLetters) } // 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); + QuerySnapshotSet(m_uidCurrentSnapshotSet); m_bBackupIsInitialized = true; @@ -349,6 +397,21 @@ BOOL VSSClientGeneric::CloseBackup() pVss->AbortBackup(); } + if (m_uidCurrentSnapshotSet != GUID_NULL) { + VSS_ID idNonDeletedSnapshotID = GUID_NULL; + LONG lSnapshots; + + pVss->DeleteSnapshots( + m_uidCurrentSnapshotSet, + VSS_OBJECT_SNAPSHOT_SET, + FALSE, + &lSnapshots, + &idNonDeletedSnapshotID); + + m_uidCurrentSnapshotSet = GUID_NULL; + } + + pVss->Release(); m_pVssObject = NULL; @@ -367,8 +430,7 @@ void VSSClientGeneric::QuerySnapshotSet(GUID snapshotSetID) return; IVssBackupComponents* pVss = (IVssBackupComponents*) m_pVssObject; - - + // Get list all shadow copies. CComPtr pIEnumSnapshots; HRESULT hr = pVss->Query( GUID_NULL, @@ -408,3 +470,80 @@ void VSSClientGeneric::QuerySnapshotSet(GUID snapshotSetID) } } +// Check the status for all selected writers +BOOL VSSClientGeneric::CheckWriterStatus() +{ + IVssBackupComponents* pVss = (IVssBackupComponents*) m_pVssObject; + vector* pVWriterStates = (vector*) m_pVectorWriterStates; + vector* pVWriterInfo = (vector*) m_pVectorWriterInfo; + + pVWriterStates->clear(); + pVWriterInfo->clear(); + + // Gather writer status to detect potential errors + CComPtr pAsync; + + HRESULT hr = pVss->GatherWriterStatus(&pAsync); + if (FAILED(hr)) + return FALSE; + + // Waits for the async operation to finish and checks the result + WaitAndCheckForAsyncOperation(pAsync); + + unsigned cWriters = 0; + + hr = pVss->GetWriterStatusCount(&cWriters); + if (FAILED(hr)) + return FALSE; + + // Enumerate each writer + for(unsigned iWriter = 0; iWriter < cWriters; iWriter++) + { + VSS_ID idInstance = GUID_NULL; + VSS_ID idWriter= GUID_NULL; + VSS_WRITER_STATE eWriterStatus = VSS_WS_UNKNOWN; + CComBSTR bstrWriterName; + HRESULT hrWriterFailure = S_OK; + + // Get writer status + hr = pVss->GetWriterStatus(iWriter, + &idInstance, + &idWriter, + &bstrWriterName, + &eWriterStatus, + &hrWriterFailure); + if (FAILED(hr)) + continue; + + // If the writer is in non-stable state, break + switch(eWriterStatus) + { + case VSS_WS_FAILED_AT_IDENTIFY: + case VSS_WS_FAILED_AT_PREPARE_BACKUP: + case VSS_WS_FAILED_AT_PREPARE_SNAPSHOT: + case VSS_WS_FAILED_AT_FREEZE: + case VSS_WS_FAILED_AT_THAW: + case VSS_WS_FAILED_AT_POST_SNAPSHOT: + case VSS_WS_FAILED_AT_BACKUP_COMPLETE: + case VSS_WS_FAILED_AT_PRE_RESTORE: + case VSS_WS_FAILED_AT_POST_RESTORE: +#ifdef B_VSS_W2K3 + case VSS_WS_FAILED_AT_BACKUPSHUTDOWN: +#endif + /* failed */ + pVWriterStates->push_back(-1); + break; + + default: + /* okay */ + pVWriterStates->push_back(1); + } + + + stringstream osf; + osf << "\"" << CW2A(bstrWriterName) << "\", State: " << eWriterStatus << " (" << CW2A(GetStringFromWriterStatus(eWriterStatus).c_str()) << ")"; + + pVWriterInfo->push_back(osf.str()); + } + return TRUE; +} \ No newline at end of file -- 2.39.5