]> git.sur5r.net Git - bacula/bacula/blobdiff - bacula/src/win32/compat/vss_generic.cpp
This commit was manufactured by cvs2svn to create tag
[bacula/bacula] / bacula / src / win32 / compat / vss_generic.cpp
index bafc9ee380dc6241d3e3fd38af091eba3a531707..94beae42f0ce0eb3d4ca5e6aa5b446865fadf0c8 100644 (file)
@@ -4,25 +4,21 @@
 // Copyright transferred from MATRIX-Computer GmbH to
 //   Kern Sibbald by express permission.
 //
-// Copyright (C) 2004-2005 Kern Sibbald
+//  Copyright (C) 2005-2006 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 free software; you can redistribute it and/or
+//  modify it under the terms of the GNU General Public License
+//  version 2 as amended with additional clauses defined in the
+//  file LICENSE in the main source directory.
 //
-//   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.
+//  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 
+//  the file LICENSE for additional 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
+// Created On      : Fri May 06 21:44:00 2005
 
 
 #include <stdio.h>
@@ -66,9 +62,13 @@ using namespace std;
 // Used for safe string manipulation
 #include <strsafe.h>
 
+#include "../../lib/winapi.h"
+
 #ifdef B_VSS_XP
    #pragma message("compile VSS for Windows XP")   
    #define VSSClientGeneric VSSClientXP
+   // wait is not available under XP...
+   #define VSS_TIMEOUT
 
    #include "vss/inc/WinXP/vss.h"
    #include "vss/inc/WinXP/vswriter.h"
@@ -87,6 +87,9 @@ using namespace std;
 #ifdef B_VSS_W2K3
    #pragma message("compile VSS for Windows 2003")
    #define VSSClientGeneric VSSClient2003
+   // wait x ms for a VSS asynchronous operation (-1 = infinite)
+   // unfortunately, it doesn't work, so do not set timeout
+   #define VSS_TIMEOUT
 
    #include "vss/inc/Win2003/vss.h"
    #include "vss/inc/Win2003/vswriter.h"
@@ -124,7 +127,7 @@ inline wstring AppendBackslash(wstring str)
 // Get the unique volume name for the given path
 inline wstring GetUniqueVolumeNameForPath(wstring path)
 {
-    _ASSERTE(path.length() > 0);
+    _ASSERTE(path.length() > 0);    
 
     // Add the backslash termination, if needed
     path = AppendBackslash(path);
@@ -134,16 +137,16 @@ inline wstring GetUniqueVolumeNameForPath(wstring path)
     WCHAR volumeName[MAX_PATH];
     WCHAR volumeUniqueName[MAX_PATH];
 
-    if (!GetVolumePathNameW((LPCWSTR)path.c_str(), volumeRootPath, MAX_PATH))
-      return L'\0';
+    if (!p_GetVolumePathNameW || !p_GetVolumePathNameW((LPCWSTR)path.c_str(), volumeRootPath, MAX_PATH))
+      return L"";
     
     // 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';
+    if (!p_GetVolumeNameForVolumeMountPointW || !p_GetVolumeNameForVolumeMountPointW(volumeRootPath, volumeName, MAX_PATH))
+       return L"";
     
     // Get the unique volume name    
-    if (!GetVolumeNameForVolumeMountPointW(volumeName, volumeUniqueName, MAX_PATH))
-       return L'\0';
+    if (!p_GetVolumeNameForVolumeMountPointW(volumeName, volumeUniqueName, MAX_PATH))
+       return L"";
     
     return volumeUniqueName;
 }
@@ -160,8 +163,7 @@ inline wstring GetUniqueVolumeNameForPath(wstring path)
 // Convert a writer status into a string
 inline wstring GetStringFromWriterStatus(VSS_WRITER_STATE eWriterStatus)
 {
-    switch (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);
@@ -178,7 +180,7 @@ inline wstring GetStringFromWriterStatus(VSS_WRITER_STATE eWriterStatus)
     CHECK_CASE_FOR_CONSTANT(VSS_WS_FAILED_AT_POST_RESTORE);
 
     default:
-        return wstring(L"Undefined");
+        return wstring(L"Error or Undefined");
     }
 }
 
@@ -208,18 +210,23 @@ VSSClientGeneric::~VSSClientGeneric()
 // Initialize the COM infrastructure and the internal pointers
 BOOL VSSClientGeneric::Initialize(DWORD dwContext, BOOL bDuringRestore)
 {
-   if (!(p_CreateVssBackupComponents && p_VssFreeSnapshotProperties))
+   if (!(p_CreateVssBackupComponents && p_VssFreeSnapshotProperties)) {
+      errno = ENOSYS;
       return FALSE;
+   }
 
    HRESULT hr;
    // Initialize COM 
    if (!m_bCoInitializeCalled)  {
-      if (FAILED(CoInitialize(NULL)))
+      if (FAILED(CoInitialize(NULL))) {
+         errno = b_errno_win32;
          return FALSE;
-
+      }
       m_bCoInitializeCalled = true;
+   }
 
-      // Initialize COM security
+   // Initialize COM security
+   if (!m_bCoInitializeSecurityCalled) {
       hr =
          CoInitializeSecurity(
          NULL,                           //  Allow *all* VSS writers to communicate back!
@@ -233,8 +240,11 @@ BOOL VSSClientGeneric::Initialize(DWORD dwContext, BOOL bDuringRestore)
          NULL                            //  Reserved parameter
          );
 
-      if (FAILED(hr))
+      if (FAILED(hr)) {
+         errno = b_errno_win32;
          return FALSE;
+      }
+      m_bCoInitializeSecurityCalled = true;      
    }
    
    // Release the IVssBackupComponents interface 
@@ -245,14 +255,18 @@ BOOL VSSClientGeneric::Initialize(DWORD dwContext, BOOL bDuringRestore)
 
    // Create the internal backup components object
    hr = p_CreateVssBackupComponents((IVssBackupComponents**) &m_pVssObject);
-   if (FAILED(hr))
+   if (FAILED(hr)) {
+      errno = b_errno_win32;
       return FALSE;
+   }
 
 #ifdef B_VSS_W2K3
    if (dwContext != VSS_CTX_BACKUP) {
       hr = ((IVssBackupComponents*) m_pVssObject)->SetContext(dwContext);
-      if (FAILED(hr))
+      if (FAILED(hr)) {
+         errno = b_errno_win32;
          return FALSE;
+      }
    }
 #endif
 
@@ -268,16 +282,17 @@ BOOL VSSClientGeneric::Initialize(DWORD dwContext, BOOL bDuringRestore)
 
 void VSSClientGeneric::WaitAndCheckForAsyncOperation(IVssAsync* pAsync)
 {
-     // Wait until the async operation finishes
-    HRESULT hr = pAsync->Wait();
+    // Wait until the async operation finishes
+    // unfortunately we can't use a timeout here yet.
+    // the interface would allow it on W2k3, but it is not implemented yet....
+    HRESULT hr = pAsync->Wait(VSS_TIMEOUT);
 
     // 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))
-    {
+    if(FAILED(hrReturned)) {
       PWCHAR pwszBuffer = NULL;
       DWORD dwRet = ::FormatMessageW(
          FORMAT_MESSAGE_ALLOCATE_BUFFER 
@@ -288,10 +303,7 @@ void VSSClientGeneric::WaitAndCheckForAsyncOperation(IVssAsync* pAsync)
          (LPWSTR)&pwszBuffer, 0, NULL);
 
       // No message found for this error. Just return <Unknown>
-      if (dwRet != 0)
-      {
-         // Convert the message into wstring         
-    
+      if (dwRet != 0) {
          LocalFree(pwszBuffer);         
       }
     }
@@ -303,22 +315,28 @@ BOOL VSSClientGeneric::CreateSnapshots(char* szDriveLetters)
    /* 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)
+   if (!m_pVssObject || m_bBackupIsInitialized) {
+      errno = ENOSYS;
       return FALSE;  
+   }
 
    m_uidCurrentSnapshotSet = GUID_NULL;
 
-   IVssBackupComponents* pVss = (IVssBackupComponents*) m_pVssObject;
+   IVssBackupComponents *pVss = (IVssBackupComponents*)m_pVssObject;
 
    // 1. InitializeForBackup
    HRESULT hr = pVss->InitializeForBackup();
-   if (FAILED(hr))
+   if (FAILED(hr)) {
+      errno = b_errno_win32;
       return FALSE;
+   }
    
    // 2. SetBackupState
    hr = pVss->SetBackupState(true, true, VSS_BT_FULL, false);
-   if (FAILED(hr))
+   if (FAILED(hr)) {
+      errno = b_errno_win32;
       return FALSE;
+   }
 
    CComPtr<IVssAsync>  pAsync1;
    CComPtr<IVssAsync>  pAsync2;   
@@ -327,8 +345,10 @@ BOOL VSSClientGeneric::CreateSnapshots(char* szDriveLetters)
 
    // 3. GatherWriterMetaData
    hr = pVss->GatherWriterMetadata(&pAsync3);
-   if (FAILED(hr))
+   if (FAILED(hr)) {
+      errno = b_errno_win32;
       return FALSE;
+   }
 
    // Waits for the async operation to finish and checks the result
    WaitAndCheckForAsyncOperation(pAsync3);
@@ -379,41 +399,47 @@ BOOL VSSClientGeneric::CreateSnapshots(char* szDriveLetters)
 
 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;     
-   }
+   if (!m_pVssObject)
+      errno = ENOSYS;
    else {
-      pVss->AbortBackup();
-   }
+      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 {
+         errno = b_errno_win32;
+         pVss->AbortBackup();
+      }
 
-   if (m_uidCurrentSnapshotSet != GUID_NULL) {
-      VSS_ID idNonDeletedSnapshotID = GUID_NULL;
-      LONG lSnapshots;
+      if (m_uidCurrentSnapshotSet != GUID_NULL) {
+         VSS_ID idNonDeletedSnapshotID = GUID_NULL;
+         LONG lSnapshots;
 
-      pVss->DeleteSnapshots(
-         m_uidCurrentSnapshotSet, 
-         VSS_OBJECT_SNAPSHOT_SET,
-         FALSE,
-         &lSnapshots,
-         &idNonDeletedSnapshotID);
+         pVss->DeleteSnapshots(
+            m_uidCurrentSnapshotSet, 
+            VSS_OBJECT_SNAPSHOT_SET,
+            FALSE,
+            &lSnapshots,
+            &idNonDeletedSnapshotID);
 
-      m_uidCurrentSnapshotSet = GUID_NULL;
-   }
+         m_uidCurrentSnapshotSet = GUID_NULL;
+      }
 
+      pVss->Release();
+      m_pVssObject = NULL;
+   }
 
-   pVss->Release();
-   m_pVssObject = NULL;
+   // Call CoUninitialize if the CoInitialize was performed sucesfully
+   if (m_bCoInitializeCalled) {
+      CoUninitialize();
+      m_bCoInitializeCalled = false;
+   }
 
    return bRet;
 }
@@ -421,13 +447,17 @@ BOOL VSSClientGeneric::CloseBackup()
 // Query all the shadow copies in the given set
 void VSSClientGeneric::QuerySnapshotSet(GUID snapshotSetID)
 {   
-   if (!(p_CreateVssBackupComponents && p_VssFreeSnapshotProperties))
+   if (!(p_CreateVssBackupComponents && p_VssFreeSnapshotProperties)) {
+      errno = ENOSYS;
       return;
+   }
 
    memset (m_szShadowCopyName,0,sizeof (m_szShadowCopyName));
    
-   if (snapshotSetID == GUID_NULL || m_pVssObject == NULL)
+   if (snapshotSetID == GUID_NULL || m_pVssObject == NULL) {
+      errno = ENOSYS;
       return;
+   }
 
    IVssBackupComponents* pVss = (IVssBackupComponents*) m_pVssObject;
                
@@ -439,16 +469,16 @@ void VSSClientGeneric::QuerySnapshotSet(GUID snapshotSetID)
          &pIEnumSnapshots );    
 
    // If there are no shadow copies, just return
-   if (hr == S_FALSE) {
-      return;
-   } 
+   if (FAILED(hr)) {
+      errno = b_errno_win32;
+      return;   
+   }
 
    // Enumerate all shadow copies. 
    VSS_OBJECT_PROP Prop;
    VSS_SNAPSHOT_PROP& Snap = Prop.Obj.Snap;
    
-   while(true)
-   {
+   while (true) {
       // Get the next element
       ULONG ulFetched;
       hr = pIEnumSnapshots->Next( 1, &Prop, &ulFetched );
@@ -468,6 +498,7 @@ void VSSClientGeneric::QuerySnapshotSet(GUID snapshotSetID)
       }
       p_VssFreeSnapshotProperties(&Snap);
    }
+   errno = 0;
 }
 
 // Check the status for all selected writers
@@ -484,8 +515,10 @@ BOOL VSSClientGeneric::CheckWriterStatus()
     CComPtr<IVssAsync>  pAsync;
     
     HRESULT hr = pVss->GatherWriterStatus(&pAsync);
-    if (FAILED(hr))
-      return FALSE;
+    if (FAILED(hr)) {
+       errno = b_errno_win32;
+       return FALSE;
+    } 
 
     // Waits for the async operation to finish and checks the result
     WaitAndCheckForAsyncOperation(pAsync);
@@ -493,12 +526,13 @@ BOOL VSSClientGeneric::CheckWriterStatus()
     unsigned cWriters = 0;
 
     hr = pVss->GetWriterStatusCount(&cWriters);
-    if (FAILED(hr))
-      return FALSE;
+    if (FAILED(hr)) {
+       errno = b_errno_win32;
+       return FALSE;
+    }
     
     // Enumerate each writer
-    for(unsigned iWriter = 0; iWriter < cWriters; iWriter++)
-    {
+    for (unsigned iWriter = 0; iWriter < cWriters; iWriter++) {
         VSS_ID idInstance = GUID_NULL;
         VSS_ID idWriter= GUID_NULL;
         VSS_WRITER_STATE eWriterStatus = VSS_WS_UNKNOWN;
@@ -512,31 +546,31 @@ BOOL VSSClientGeneric::CheckWriterStatus()
                              &bstrWriterName,
                              &eWriterStatus,
                              &hrWriterFailure);
-        if (FAILED(hr))
+        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:
+        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:
+        case VSS_WS_FAILED_AT_BACKUPSHUTDOWN:
 #endif
-               /* failed */
-               pVWriterStates->push_back(-1);
-               break;
+           /* failed */
+           pVWriterStates->push_back(-1);
+           break;
 
-            default:
-                /* okay */
-                pVWriterStates->push_back(1);                
+        default:
+           /* okay */
+           pVWriterStates->push_back(1);                
         }
 
                
@@ -545,5 +579,6 @@ BOOL VSSClientGeneric::CheckWriterStatus()
     
         pVWriterInfo->push_back(osf.str());
     }
+    errno = 0;
     return TRUE;
-}
\ No newline at end of file
+}