diff options
Diffstat (limited to 'lib/ShadowCopy/shadow.cpp')
-rw-r--r-- | lib/ShadowCopy/shadow.cpp | 196 |
1 files changed, 83 insertions, 113 deletions
diff --git a/lib/ShadowCopy/shadow.cpp b/lib/ShadowCopy/shadow.cpp index 12e9fa60..5047a698 100644 --- a/lib/ShadowCopy/shadow.cpp +++ b/lib/ShadowCopy/shadow.cpp @@ -7,12 +7,9 @@ #include "shadow.h" #include <algorithm> #include <string> -#include <comdef.h> #include <zen/com_ptr.h> #include <zen/com_error.h> - -#define WIN32_LEAN_AND_MEAN -#include "windows.h" +#include <zen/scope_guard.h> #ifdef USE_SHADOW_XP #include "xp/inc/vss.h" @@ -23,13 +20,30 @@ #include "Server 2003/inc/vss.h" #include "Server 2003/inc/vswriter.h" #include "Server 2003/inc/vsbackup.h" + +#elif defined USE_SHADOW_WINDOWS7 +#include <vss.h> // +#include <vswriter.h> //part of Windows SDK for Windows 7 +#include <vsbackup.h> // +#pragma comment(lib, "VssApi.lib") + #else -adapt! +#error adapt! #endif using namespace zen; +struct shadow::ShadowData +{ + ShadowData(const ComPtr<IVssBackupComponents>& backupComp, + const std::wstring& shadowVolume) : backupComp_(backupComp), shadowVolume_(shadowVolume) {} + + ComPtr<IVssBackupComponents> backupComp_; + std::wstring shadowVolume_; +}; + + namespace { inline @@ -45,143 +59,99 @@ void copyString(const std::wstring& input, wchar_t* buffer, size_t bufferSize) } } -inline -void writeErrorMsg(const wchar_t* input, HRESULT hr, wchar_t* output, unsigned int outputLen) -{ - copyString(generateErrorMsg(input, hr), output, outputLen); -} -} - -bool shadow::createShadowCopy(const wchar_t* volumeName, - wchar_t* shadowVolName, - unsigned int shadowBufferLen, - ShadowHandle* handle, - wchar_t* errorMessage, - unsigned int errorBufferLen) +shadow::ShadowData createShadowCopy(const wchar_t* volumeName) //throw ComError { - //MessageBox(0, L"backup err", L"", 0); */ - *handle = 0; - HRESULT hr = NULL; - ComPtr<IVssBackupComponents> backupComp; - if (FAILED(hr = CreateVssBackupComponents(backupComp.init()))) { - if (hr == E_ACCESSDENIED) - writeErrorMsg(L"The caller does not have sufficient backup privileges or is not an administrator.", hr, errorMessage, errorBufferLen); - else - writeErrorMsg(L"Error calling \"CreateVssBackupComponents\".", hr, errorMessage, errorBufferLen); - return false; + HRESULT hr = ::CreateVssBackupComponents(backupComp.init()); + if (FAILED(hr)) + { + if (hr == E_ACCESSDENIED) + throw ComError(L"The caller does not have sufficient backup privileges or is not an administrator.", hr); + throw ComError(L"Error calling \"CreateVssBackupComponents\".", hr); + } } - if (FAILED(hr = backupComp->InitializeForBackup())) - { - writeErrorMsg(L"Error calling \"InitializeForBackup\".", hr, errorMessage, errorBufferLen); - return false; - } + ZEN_CHECK_COM(backupComp->InitializeForBackup()); //throw ComError + ZEN_CHECK_COM(backupComp->SetBackupState(false, false, VSS_BT_FULL)); //throw ComError - if (FAILED(hr = backupComp->SetBackupState(false, false, VSS_BT_FULL))) + auto waitForComFuture = [](IVssAsync& fut) { - writeErrorMsg(L"Error calling \"SetBackupState\".", hr, errorMessage, errorBufferLen); - return false; - } + ZEN_CHECK_COM(fut.Wait()); - ComPtr<IVssAsync> vssWriters; - if (FAILED(hr = backupComp->GatherWriterMetadata(vssWriters.init()))) - { - //this can happen if XP-version of VSS is used on Windows Vista (which needs at least VSS-Server2003 build) - writeErrorMsg(L"Error calling \"GatherWriterMetadata\".", hr, errorMessage, errorBufferLen); - return false; - } + HRESULT hr = S_OK; + ZEN_CHECK_COM(fut.QueryStatus(&hr, NULL)); //check if the async operation succeeded... + if (FAILED(hr)) + throw ComError(L"Error calling \"fut->QueryStatus\".", hr); + }; - //wait for shadow copy writers to complete - if (FAILED(hr = vssWriters->Wait())) - { - writeErrorMsg(L"Error calling \"vssWriters->Wait\".", hr, errorMessage, errorBufferLen); - return false; - } + ComPtr<IVssAsync> gatherAsync; + ZEN_CHECK_COM(backupComp->GatherWriterMetadata(gatherAsync.init())); + waitForComFuture(*gatherAsync); //failure can happen if XP-version of VSS is used on Windows Vista (which needs at least VSS-Server2003 build) - vssWriters->QueryStatus(&hr, NULL); //check if the async operation succeeded... - if (FAILED(hr)) - { - writeErrorMsg(L"Error calling \"vssWriters->QueryStatus\".", hr, errorMessage, errorBufferLen); - return false; - } + VSS_ID snapshotSetId = {}; + ZEN_CHECK_COM(backupComp->StartSnapshotSet(&snapshotSetId)); + ScopeGuard guardSnapShot = makeGuard([&]() { backupComp->AbortBackup(); }); + //Quote: "This method must be called if a backup operation terminates after the creation of a + //shadow copy set with "StartSnapshotSet" and before "DoSnapshotSet" returns." - VSS_ID snapshotSetId = {0}; - if (FAILED(hr = backupComp->StartSnapshotSet(&snapshotSetId))) + VSS_ID SnapShotId = {}; { - writeErrorMsg(L"Error calling \"StartSnapshotSet\".", hr, errorMessage, errorBufferLen); - return false; + HRESULT hr = backupComp->AddToSnapshotSet(const_cast<wchar_t*>(volumeName), GUID_NULL, &SnapShotId); + if (FAILED(hr)) + { + if (hr == VSS_E_VOLUME_NOT_SUPPORTED) + throw ComError(L"Volume Shadow Copy Service is not supported on this volume!"); + throw ComError(L"Error calling \"backupComp->AddToSnapshotSet\".", hr); + } } - VSS_ID SnapShotId = {0}; - if (FAILED(hr = backupComp->AddToSnapshotSet(const_cast<wchar_t*>(volumeName), GUID_NULL, &SnapShotId))) - { - writeErrorMsg(L"Error calling \"AddToSnapshotSet\".", hr, errorMessage, errorBufferLen); - return false; - } + ComPtr<IVssAsync> prepareAsync; + ZEN_CHECK_COM(backupComp->PrepareForBackup(prepareAsync.init())); + waitForComFuture(*prepareAsync); - ComPtr<IVssAsync> vssPrepare; - if (FAILED(hr = backupComp->PrepareForBackup(vssPrepare.init()))) - { - writeErrorMsg(L"Error calling \"PrepareForBackup\".", hr, errorMessage, errorBufferLen); - return false; - } + ComPtr<IVssAsync> snapshotAsync; + ZEN_CHECK_COM(backupComp->DoSnapshotSet(snapshotAsync.init())); + guardSnapShot.dismiss(); + waitForComFuture(*snapshotAsync); - if (FAILED(hr = vssPrepare->Wait())) - { - writeErrorMsg(L"Error calling \"vssPrepare->Wait\".", hr, errorMessage, errorBufferLen); - return false; - } + VSS_SNAPSHOT_PROP props = {}; + ZEN_CHECK_COM(backupComp->GetSnapshotProperties(SnapShotId, &props)); + ZEN_ON_BLOCK_EXIT(::VssFreeSnapshotProperties(&props)); - vssPrepare->QueryStatus(&hr, NULL); //check if the async operation succeeded... - if (FAILED(hr)) - { - writeErrorMsg(L"Error calling \"vssPrepare->QueryStatus\".", hr, errorMessage, errorBufferLen); - return false; - } - - ComPtr<IVssAsync> vssDoShadowCopy; - if (FAILED(hr = backupComp->DoSnapshotSet(vssDoShadowCopy.init()))) - { - writeErrorMsg(L"Error calling \"DoSnapshotSet\".", hr, errorMessage, errorBufferLen); - return false; - } + //finally: write volume name of newly created shadow copy + return shadow::ShadowData(backupComp, props.m_pwszSnapshotDeviceObject); +} +} - if (FAILED(hr = vssDoShadowCopy->Wait())) - { - writeErrorMsg(L"Error calling \"vssDoShadowCopy->Wait\".", hr, errorMessage, errorBufferLen); - return false; - } - vssDoShadowCopy->QueryStatus(&hr, NULL); //check if the async operation succeeded... - if (FAILED(hr)) +shadow::ShadowHandle shadow::createShadowCopy(const wchar_t* volumeName, + wchar_t* errorMessage, + unsigned int errorBufferLen) +{ + try { - writeErrorMsg(L"Error calling \"vssDoShadowCopy->QueryStatus\".", hr, errorMessage, errorBufferLen); - return false; + ShadowData result = ::createShadowCopy(volumeName); //shadow handle owned by caller! throw ComError + return new ShadowData(result); } - - VSS_SNAPSHOT_PROP props; - if (FAILED(hr = backupComp->GetSnapshotProperties(SnapShotId, &props))) + catch (const zen::ComError& e) { - writeErrorMsg(L"Error calling \"GetSnapshotProperties\".", hr, errorMessage, errorBufferLen); - return false; + copyString(e.toString(), errorMessage, errorBufferLen); + return nullptr; } +} - //finally: write volume name of newly created shadow copy - copyString(props.m_pwszSnapshotDeviceObject, shadowVolName, shadowBufferLen); - - VssFreeSnapshotProperties(&props); - - *handle = backupComp.release(); - return true; +void shadow::getShadowVolume(shadow::ShadowHandle handle, + wchar_t* buffer, + unsigned int bufferLen) +{ + copyString(handle->shadowVolume_, buffer, bufferLen); } void shadow::releaseShadowCopy(ShadowHandle handle) { - if (handle) - handle->Release(); + delete handle; } |