summaryrefslogtreecommitdiffstats
path: root/qemu/qga/vss-win32/provider.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'qemu/qga/vss-win32/provider.cpp')
-rw-r--r--qemu/qga/vss-win32/provider.cpp534
1 files changed, 534 insertions, 0 deletions
diff --git a/qemu/qga/vss-win32/provider.cpp b/qemu/qga/vss-win32/provider.cpp
new file mode 100644
index 000000000..d5129f8f6
--- /dev/null
+++ b/qemu/qga/vss-win32/provider.cpp
@@ -0,0 +1,534 @@
+/*
+ * QEMU Guest Agent win32 VSS Provider implementations
+ *
+ * Copyright Hitachi Data Systems Corp. 2013
+ *
+ * Authors:
+ * Tomoki Sekiyama <tomoki.sekiyama@hds.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ */
+
+#include <stdio.h>
+#include "vss-common.h"
+#include "inc/win2003/vscoordint.h"
+#include "inc/win2003/vsprov.h"
+
+#define VSS_TIMEOUT_MSEC (60*1000)
+
+static long g_nComObjsInUse;
+HINSTANCE g_hinstDll;
+
+/* VSS common GUID's */
+
+const CLSID CLSID_VSSCoordinator = { 0xE579AB5F, 0x1CC4, 0x44b4,
+ {0xBE, 0xD9, 0xDE, 0x09, 0x91, 0xFF, 0x06, 0x23} };
+const IID IID_IVssAdmin = { 0x77ED5996, 0x2F63, 0x11d3,
+ {0x8A, 0x39, 0x00, 0xC0, 0x4F, 0x72, 0xD8, 0xE3} };
+
+const IID IID_IVssHardwareSnapshotProvider = { 0x9593A157, 0x44E9, 0x4344,
+ {0xBB, 0xEB, 0x44, 0xFB, 0xF9, 0xB0, 0x6B, 0x10} };
+const IID IID_IVssSoftwareSnapshotProvider = { 0x609e123e, 0x2c5a, 0x44d3,
+ {0x8f, 0x01, 0x0b, 0x1d, 0x9a, 0x47, 0xd1, 0xff} };
+const IID IID_IVssProviderCreateSnapshotSet = { 0x5F894E5B, 0x1E39, 0x4778,
+ {0x8E, 0x23, 0x9A, 0xBA, 0xD9, 0xF0, 0xE0, 0x8C} };
+const IID IID_IVssProviderNotifications = { 0xE561901F, 0x03A5, 0x4afe,
+ {0x86, 0xD0, 0x72, 0xBA, 0xEE, 0xCE, 0x70, 0x04} };
+
+const IID IID_IVssEnumObject = { 0xAE1C7110, 0x2F60, 0x11d3,
+ {0x8A, 0x39, 0x00, 0xC0, 0x4F, 0x72, 0xD8, 0xE3} };
+
+
+void LockModule(BOOL lock)
+{
+ if (lock) {
+ InterlockedIncrement(&g_nComObjsInUse);
+ } else {
+ InterlockedDecrement(&g_nComObjsInUse);
+ }
+}
+
+/* Empty enumerator for VssObject */
+
+class CQGAVSSEnumObject : public IVssEnumObject
+{
+public:
+ STDMETHODIMP QueryInterface(REFIID riid, void **ppObj);
+ STDMETHODIMP_(ULONG) AddRef();
+ STDMETHODIMP_(ULONG) Release();
+
+ /* IVssEnumObject Methods */
+ STDMETHODIMP Next(
+ ULONG celt, VSS_OBJECT_PROP *rgelt, ULONG *pceltFetched);
+ STDMETHODIMP Skip(ULONG celt);
+ STDMETHODIMP Reset(void);
+ STDMETHODIMP Clone(IVssEnumObject **ppenum);
+
+ /* CQGAVSSEnumObject Methods */
+ CQGAVSSEnumObject();
+ ~CQGAVSSEnumObject();
+
+private:
+ long m_nRefCount;
+};
+
+CQGAVSSEnumObject::CQGAVSSEnumObject()
+{
+ m_nRefCount = 0;
+ LockModule(TRUE);
+}
+
+CQGAVSSEnumObject::~CQGAVSSEnumObject()
+{
+ LockModule(FALSE);
+}
+
+STDMETHODIMP CQGAVSSEnumObject::QueryInterface(REFIID riid, void **ppObj)
+{
+ if (riid == IID_IUnknown || riid == IID_IVssEnumObject) {
+ *ppObj = static_cast<void*>(static_cast<IVssEnumObject*>(this));
+ AddRef();
+ return S_OK;
+ }
+ *ppObj = NULL;
+ return E_NOINTERFACE;
+}
+
+STDMETHODIMP_(ULONG) CQGAVSSEnumObject::AddRef()
+{
+ return InterlockedIncrement(&m_nRefCount);
+}
+
+STDMETHODIMP_(ULONG) CQGAVSSEnumObject::Release()
+{
+ long nRefCount = InterlockedDecrement(&m_nRefCount);
+ if (m_nRefCount == 0) {
+ delete this;
+ }
+ return nRefCount;
+}
+
+STDMETHODIMP CQGAVSSEnumObject::Next(
+ ULONG celt, VSS_OBJECT_PROP *rgelt, ULONG *pceltFetched)
+{
+ *pceltFetched = 0;
+ return S_FALSE;
+}
+
+STDMETHODIMP CQGAVSSEnumObject::Skip(ULONG celt)
+{
+ return S_FALSE;
+}
+
+STDMETHODIMP CQGAVSSEnumObject::Reset(void)
+{
+ return S_OK;
+}
+
+STDMETHODIMP CQGAVSSEnumObject::Clone(IVssEnumObject **ppenum)
+{
+ return E_NOTIMPL;
+}
+
+
+/* QGAVssProvider */
+
+class CQGAVssProvider :
+ public IVssSoftwareSnapshotProvider,
+ public IVssProviderCreateSnapshotSet,
+ public IVssProviderNotifications
+{
+public:
+ STDMETHODIMP QueryInterface(REFIID riid, void **ppObj);
+ STDMETHODIMP_(ULONG) AddRef();
+ STDMETHODIMP_(ULONG) Release();
+
+ /* IVssSoftwareSnapshotProvider Methods */
+ STDMETHODIMP SetContext(LONG lContext);
+ STDMETHODIMP GetSnapshotProperties(
+ VSS_ID SnapshotId, VSS_SNAPSHOT_PROP *pProp);
+ STDMETHODIMP Query(
+ VSS_ID QueriedObjectId, VSS_OBJECT_TYPE eQueriedObjectType,
+ VSS_OBJECT_TYPE eReturnedObjectsType, IVssEnumObject **ppEnum);
+ STDMETHODIMP DeleteSnapshots(
+ VSS_ID SourceObjectId, VSS_OBJECT_TYPE eSourceObjectType,
+ BOOL bForceDelete, LONG *plDeletedSnapshots,
+ VSS_ID *pNondeletedSnapshotID);
+ STDMETHODIMP BeginPrepareSnapshot(
+ VSS_ID SnapshotSetId, VSS_ID SnapshotId,
+ VSS_PWSZ pwszVolumeName, LONG lNewContext);
+ STDMETHODIMP IsVolumeSupported(
+ VSS_PWSZ pwszVolumeName, BOOL *pbSupportedByThisProvider);
+ STDMETHODIMP IsVolumeSnapshotted(
+ VSS_PWSZ pwszVolumeName, BOOL *pbSnapshotsPresent,
+ LONG *plSnapshotCompatibility);
+ STDMETHODIMP SetSnapshotProperty(
+ VSS_ID SnapshotId, VSS_SNAPSHOT_PROPERTY_ID eSnapshotPropertyId,
+ VARIANT vProperty);
+ STDMETHODIMP RevertToSnapshot(VSS_ID SnapshotId);
+ STDMETHODIMP QueryRevertStatus(VSS_PWSZ pwszVolume, IVssAsync **ppAsync);
+
+ /* IVssProviderCreateSnapshotSet Methods */
+ STDMETHODIMP EndPrepareSnapshots(VSS_ID SnapshotSetId);
+ STDMETHODIMP PreCommitSnapshots(VSS_ID SnapshotSetId);
+ STDMETHODIMP CommitSnapshots(VSS_ID SnapshotSetId);
+ STDMETHODIMP PostCommitSnapshots(
+ VSS_ID SnapshotSetId, LONG lSnapshotsCount);
+ STDMETHODIMP PreFinalCommitSnapshots(VSS_ID SnapshotSetId);
+ STDMETHODIMP PostFinalCommitSnapshots(VSS_ID SnapshotSetId);
+ STDMETHODIMP AbortSnapshots(VSS_ID SnapshotSetId);
+
+ /* IVssProviderNotifications Methods */
+ STDMETHODIMP OnLoad(IUnknown *pCallback);
+ STDMETHODIMP OnUnload(BOOL bForceUnload);
+
+ /* CQGAVssProvider Methods */
+ CQGAVssProvider();
+ ~CQGAVssProvider();
+
+private:
+ long m_nRefCount;
+};
+
+CQGAVssProvider::CQGAVssProvider()
+{
+ m_nRefCount = 0;
+ LockModule(TRUE);
+}
+
+CQGAVssProvider::~CQGAVssProvider()
+{
+ LockModule(FALSE);
+}
+
+STDMETHODIMP CQGAVssProvider::QueryInterface(REFIID riid, void **ppObj)
+{
+ if (riid == IID_IUnknown) {
+ *ppObj = static_cast<void*>(this);
+ AddRef();
+ return S_OK;
+ }
+ if (riid == IID_IVssSoftwareSnapshotProvider) {
+ *ppObj = static_cast<void*>(
+ static_cast<IVssSoftwareSnapshotProvider*>(this));
+ AddRef();
+ return S_OK;
+ }
+ if (riid == IID_IVssProviderCreateSnapshotSet) {
+ *ppObj = static_cast<void*>(
+ static_cast<IVssProviderCreateSnapshotSet*>(this));
+ AddRef();
+ return S_OK;
+ }
+ if (riid == IID_IVssProviderNotifications) {
+ *ppObj = static_cast<void*>(
+ static_cast<IVssProviderNotifications*>(this));
+ AddRef();
+ return S_OK;
+ }
+ *ppObj = NULL;
+ return E_NOINTERFACE;
+}
+
+STDMETHODIMP_(ULONG) CQGAVssProvider::AddRef()
+{
+ return InterlockedIncrement(&m_nRefCount);
+}
+
+STDMETHODIMP_(ULONG) CQGAVssProvider::Release()
+{
+ long nRefCount = InterlockedDecrement(&m_nRefCount);
+ if (m_nRefCount == 0) {
+ delete this;
+ }
+ return nRefCount;
+}
+
+
+/*
+ * IVssSoftwareSnapshotProvider methods
+ */
+
+STDMETHODIMP CQGAVssProvider::SetContext(LONG lContext)
+{
+ return S_OK;
+}
+
+STDMETHODIMP CQGAVssProvider::GetSnapshotProperties(
+ VSS_ID SnapshotId, VSS_SNAPSHOT_PROP *pProp)
+{
+ return VSS_E_OBJECT_NOT_FOUND;
+}
+
+STDMETHODIMP CQGAVssProvider::Query(
+ VSS_ID QueriedObjectId, VSS_OBJECT_TYPE eQueriedObjectType,
+ VSS_OBJECT_TYPE eReturnedObjectsType, IVssEnumObject **ppEnum)
+{
+ try {
+ *ppEnum = new CQGAVSSEnumObject;
+ } catch (...) {
+ return E_OUTOFMEMORY;
+ }
+ (*ppEnum)->AddRef();
+ return S_OK;
+}
+
+STDMETHODIMP CQGAVssProvider::DeleteSnapshots(
+ VSS_ID SourceObjectId, VSS_OBJECT_TYPE eSourceObjectType,
+ BOOL bForceDelete, LONG *plDeletedSnapshots, VSS_ID *pNondeletedSnapshotID)
+{
+ *plDeletedSnapshots = 0;
+ *pNondeletedSnapshotID = SourceObjectId;
+ return S_OK;
+}
+
+STDMETHODIMP CQGAVssProvider::BeginPrepareSnapshot(
+ VSS_ID SnapshotSetId, VSS_ID SnapshotId,
+ VSS_PWSZ pwszVolumeName, LONG lNewContext)
+{
+ return S_OK;
+}
+
+STDMETHODIMP CQGAVssProvider::IsVolumeSupported(
+ VSS_PWSZ pwszVolumeName, BOOL *pbSupportedByThisProvider)
+{
+ HANDLE hEventFrozen;
+
+ /* Check if a requester is qemu-ga by whether an event is created */
+ hEventFrozen = OpenEvent(EVENT_ALL_ACCESS, FALSE, EVENT_NAME_FROZEN);
+ if (!hEventFrozen) {
+ *pbSupportedByThisProvider = FALSE;
+ return S_OK;
+ }
+ CloseHandle(hEventFrozen);
+
+ *pbSupportedByThisProvider = TRUE;
+ return S_OK;
+}
+
+STDMETHODIMP CQGAVssProvider::IsVolumeSnapshotted(VSS_PWSZ pwszVolumeName,
+ BOOL *pbSnapshotsPresent, LONG *plSnapshotCompatibility)
+{
+ *pbSnapshotsPresent = FALSE;
+ *plSnapshotCompatibility = 0;
+ return S_OK;
+}
+
+STDMETHODIMP CQGAVssProvider::SetSnapshotProperty(VSS_ID SnapshotId,
+ VSS_SNAPSHOT_PROPERTY_ID eSnapshotPropertyId, VARIANT vProperty)
+{
+ return E_NOTIMPL;
+}
+
+STDMETHODIMP CQGAVssProvider::RevertToSnapshot(VSS_ID SnapshotId)
+{
+ return E_NOTIMPL;
+}
+
+STDMETHODIMP CQGAVssProvider::QueryRevertStatus(
+ VSS_PWSZ pwszVolume, IVssAsync **ppAsync)
+{
+ return E_NOTIMPL;
+}
+
+
+/*
+ * IVssProviderCreateSnapshotSet methods
+ */
+
+STDMETHODIMP CQGAVssProvider::EndPrepareSnapshots(VSS_ID SnapshotSetId)
+{
+ return S_OK;
+}
+
+STDMETHODIMP CQGAVssProvider::PreCommitSnapshots(VSS_ID SnapshotSetId)
+{
+ return S_OK;
+}
+
+STDMETHODIMP CQGAVssProvider::CommitSnapshots(VSS_ID SnapshotSetId)
+{
+ HRESULT hr = S_OK;
+ HANDLE hEventFrozen, hEventThaw, hEventTimeout;
+
+ hEventFrozen = OpenEvent(EVENT_ALL_ACCESS, FALSE, EVENT_NAME_FROZEN);
+ if (!hEventFrozen) {
+ return E_FAIL;
+ }
+
+ hEventThaw = OpenEvent(EVENT_ALL_ACCESS, FALSE, EVENT_NAME_THAW);
+ if (!hEventThaw) {
+ CloseHandle(hEventFrozen);
+ return E_FAIL;
+ }
+
+ hEventTimeout = OpenEvent(EVENT_ALL_ACCESS, FALSE, EVENT_NAME_TIMEOUT);
+ if (!hEventTimeout) {
+ CloseHandle(hEventFrozen);
+ CloseHandle(hEventThaw);
+ return E_FAIL;
+ }
+
+ /* Send event to qemu-ga to notify filesystem is frozen */
+ SetEvent(hEventFrozen);
+
+ /* Wait until the snapshot is taken by the host. */
+ if (WaitForSingleObject(hEventThaw, VSS_TIMEOUT_MSEC) != WAIT_OBJECT_0) {
+ /* Send event to qemu-ga to notify the provider is timed out */
+ SetEvent(hEventTimeout);
+ hr = E_ABORT;
+ }
+
+ CloseHandle(hEventThaw);
+ CloseHandle(hEventFrozen);
+ CloseHandle(hEventTimeout);
+ return hr;
+}
+
+STDMETHODIMP CQGAVssProvider::PostCommitSnapshots(
+ VSS_ID SnapshotSetId, LONG lSnapshotsCount)
+{
+ return S_OK;
+}
+
+STDMETHODIMP CQGAVssProvider::PreFinalCommitSnapshots(VSS_ID SnapshotSetId)
+{
+ return S_OK;
+}
+
+STDMETHODIMP CQGAVssProvider::PostFinalCommitSnapshots(VSS_ID SnapshotSetId)
+{
+ return S_OK;
+}
+
+STDMETHODIMP CQGAVssProvider::AbortSnapshots(VSS_ID SnapshotSetId)
+{
+ return S_OK;
+}
+
+/*
+ * IVssProviderNotifications methods
+ */
+
+STDMETHODIMP CQGAVssProvider::OnLoad(IUnknown *pCallback)
+{
+ return S_OK;
+}
+
+STDMETHODIMP CQGAVssProvider::OnUnload(BOOL bForceUnload)
+{
+ return S_OK;
+}
+
+
+/*
+ * CQGAVssProviderFactory class
+ */
+
+class CQGAVssProviderFactory : public IClassFactory
+{
+public:
+ STDMETHODIMP QueryInterface(REFIID riid, void **ppv);
+ STDMETHODIMP_(ULONG) AddRef();
+ STDMETHODIMP_(ULONG) Release();
+ STDMETHODIMP CreateInstance(
+ IUnknown *pUnknownOuter, REFIID iid, void **ppv);
+ STDMETHODIMP LockServer(BOOL lock) { return E_NOTIMPL; }
+
+ CQGAVssProviderFactory();
+ ~CQGAVssProviderFactory();
+
+private:
+ long m_nRefCount;
+};
+
+CQGAVssProviderFactory::CQGAVssProviderFactory()
+{
+ m_nRefCount = 0;
+ LockModule(TRUE);
+}
+
+CQGAVssProviderFactory::~CQGAVssProviderFactory()
+{
+ LockModule(FALSE);
+}
+
+STDMETHODIMP CQGAVssProviderFactory::QueryInterface(REFIID riid, void **ppv)
+{
+ if (riid == IID_IUnknown || riid == IID_IClassFactory) {
+ *ppv = static_cast<void*>(this);
+ AddRef();
+ return S_OK;
+ }
+ *ppv = NULL;
+ return E_NOINTERFACE;
+}
+
+STDMETHODIMP_(ULONG) CQGAVssProviderFactory::AddRef()
+{
+ return InterlockedIncrement(&m_nRefCount);
+}
+
+STDMETHODIMP_(ULONG) CQGAVssProviderFactory::Release()
+{
+ long nRefCount = InterlockedDecrement(&m_nRefCount);
+ if (m_nRefCount == 0) {
+ delete this;
+ }
+ return nRefCount;
+}
+
+STDMETHODIMP CQGAVssProviderFactory::CreateInstance(
+ IUnknown *pUnknownOuter, REFIID iid, void **ppv)
+{
+ CQGAVssProvider *pObj;
+
+ if (pUnknownOuter) {
+ return CLASS_E_NOAGGREGATION;
+ }
+ try {
+ pObj = new CQGAVssProvider;
+ } catch (...) {
+ return E_OUTOFMEMORY;
+ }
+ HRESULT hr = pObj->QueryInterface(iid, ppv);
+ if (FAILED(hr)) {
+ delete pObj;
+ }
+ return hr;
+}
+
+
+/*
+ * DLL functions
+ */
+
+STDAPI DllGetClassObject(REFCLSID rclsid, REFIID riid, LPVOID *ppv)
+{
+ CQGAVssProviderFactory *factory;
+ try {
+ factory = new CQGAVssProviderFactory;
+ } catch (...) {
+ return E_OUTOFMEMORY;
+ }
+ factory->AddRef();
+ HRESULT hr = factory->QueryInterface(riid, ppv);
+ factory->Release();
+ return hr;
+}
+
+STDAPI DllCanUnloadNow()
+{
+ return g_nComObjsInUse == 0 ? S_OK : S_FALSE;
+}
+
+EXTERN_C
+BOOL WINAPI DllMain(HINSTANCE hinstDll, DWORD dwReason, LPVOID lpReserved)
+{
+ if (dwReason == DLL_PROCESS_ATTACH) {
+ g_hinstDll = hinstDll;
+ DisableThreadLibraryCalls(hinstDll);
+ }
+ return TRUE;
+}