diff options
Diffstat (limited to 'qemu/qga/vss-win32/provider.cpp')
-rw-r--r-- | qemu/qga/vss-win32/provider.cpp | 534 |
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; +} |