]> git.sur5r.net Git - bacula/bacula/commitdiff
major changes of VSS support (added VSS Writer support + proofed functionality on...
authorThorsten Engel <thorsten.engel@matrix-computer.com>
Thu, 9 Jun 2005 17:39:42 +0000 (17:39 +0000)
committerThorsten Engel <thorsten.engel@matrix-computer.com>
Thu, 9 Jun 2005 17:39:42 +0000 (17:39 +0000)
git-svn-id: https://bacula.svn.sourceforge.net/svnroot/bacula/trunk@2117 91ce42f0-d328-0410-95d8-f526ca767f89

bacula/src/win32/compat/vss.cpp
bacula/src/win32/compat/vss.h
bacula/src/win32/compat/vss_generic.cpp

index 523cc68f21bd8b1f4e08f2ccfeef78dd7d9aef89..5104b33432211b064fe95f978594d4be41928cd2 100644 (file)
@@ -80,6 +80,9 @@ VSSClient::VSSClient()
     m_bDuringRestore = false;
     m_bBackupIsInitialized = false;
     m_pVssObject = NULL;
+    m_pVectorWriterStates = new vector<int>;
+    m_pVectorWriterInfo = new vector<string>;
+    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<int>* pV = (vector<int>*) m_pVectorWriterStates;
+   return pV->size();
+}
+
+const char* VSSClient::GetWriterInfo(size_t nIndex)
+{
+   vector<string>* pV = (vector<string>*) m_pVectorWriterInfo;   
+   return pV->at(nIndex).c_str();
+}
+
+
+const int VSSClient::GetWriterState(size_t nIndex)
+{
+   vector<int>* pV = (vector<int>*) m_pVectorWriterStates;   
+   return pV->at(nIndex);
 }
\ No newline at end of file
index d8abd82479280acd2d3c5f9cda969e5d7570265f..f773eeac3fad2416e3af762a2104b494b2390a6a 100644 (file)
@@ -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();
 };
 
 
index 81323e41b430ffeb3e1c91a9aecb433058691c95..bafc9ee380dc6241d3e3fd38af091eba3a531707 100644 (file)
@@ -56,6 +56,7 @@
 #include <vector>
 #include <algorithm>
 #include <string>
+#include <sstream>
 #include <fstream>
 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<IVssAsync>  pAsync1;
-   CComPtr<IVssAsync>  pAsync2;
-   VSS_ID latestSnapshotSetID;
+   CComPtr<IVssAsync>  pAsync2;   
+   CComPtr<IVssAsync>  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<IVssEnumObject> 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<int>* pVWriterStates = (vector<int>*) m_pVectorWriterStates;
+    vector<string>* pVWriterInfo = (vector<string>*) m_pVectorWriterInfo;   
+
+    pVWriterStates->clear();
+    pVWriterInfo->clear();
+
+    // Gather writer status to detect potential errors
+    CComPtr<IVssAsync>  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