summaryrefslogtreecommitdiff
path: root/lib/ShadowCopy/shadow.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'lib/ShadowCopy/shadow.cpp')
-rw-r--r--lib/ShadowCopy/shadow.cpp196
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;
}
bgstack15