// 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>
// 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"
#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"
// 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);
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;
}
// 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);
CHECK_CASE_FOR_CONSTANT(VSS_WS_FAILED_AT_POST_RESTORE);
default:
- return wstring(L"Undefined");
+ return wstring(L"Error or Undefined");
}
}
// 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!
NULL // Reserved parameter
);
- if (FAILED(hr))
+ if (FAILED(hr)) {
+ errno = b_errno_win32;
return FALSE;
+ }
+ m_bCoInitializeSecurityCalled = true;
}
// Release the IVssBackupComponents interface
// 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
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
(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);
}
}
/* 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;
// 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);
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;
}
// 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;
&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 );
}
p_VssFreeSnapshotProperties(&Snap);
}
+ errno = 0;
}
// Check the status for all selected writers
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);
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;
&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);
}
pVWriterInfo->push_back(osf.str());
}
+ errno = 0;
return TRUE;
-}
\ No newline at end of file
+}