123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543 |
- /*
- * 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 "qemu/osdep.h"
- #include "vss-common.h"
- #include "vss-debug.h"
- #ifdef HAVE_VSS_SDK
- #include <vscoordint.h>
- #else
- #include <vsadmin.h>
- #endif
- #include <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} };
- static 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);
- }
- 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);
- EXTERN_C
- BOOL WINAPI DllMain(HINSTANCE hinstDll, DWORD dwReason, LPVOID lpReserved)
- {
- qga_debug("begin, reason = %lu", dwReason);
- if (dwReason == DLL_PROCESS_ATTACH) {
- g_hinstDll = hinstDll;
- DisableThreadLibraryCalls(hinstDll);
- }
- qga_debug_end;
- return TRUE;
- }
|