Merge tag 'accel-sh4-ui-20240503' of https://github.com/philmd/qemu into staging
[qemu/armbru.git] / qga / vss-win32 / provider.cpp
blobcc72e5ef1b939a1d79a26ab95a96636b2641361f
1 /*
2 * QEMU Guest Agent win32 VSS Provider implementations
4 * Copyright Hitachi Data Systems Corp. 2013
6 * Authors:
7 * Tomoki Sekiyama <tomoki.sekiyama@hds.com>
9 * This work is licensed under the terms of the GNU GPL, version 2 or later.
10 * See the COPYING file in the top-level directory.
13 #include "qemu/osdep.h"
14 #include "vss-common.h"
15 #include "vss-debug.h"
16 #ifdef HAVE_VSS_SDK
17 #include <vscoordint.h>
18 #else
19 #include <vsadmin.h>
20 #endif
21 #include <vsprov.h>
23 #define VSS_TIMEOUT_MSEC (60*1000)
25 static long g_nComObjsInUse;
26 HINSTANCE g_hinstDll;
28 /* VSS common GUID's */
30 const CLSID CLSID_VSSCoordinator = { 0xE579AB5F, 0x1CC4, 0x44b4,
31 {0xBE, 0xD9, 0xDE, 0x09, 0x91, 0xFF, 0x06, 0x23} };
32 const IID IID_IVssAdmin = { 0x77ED5996, 0x2F63, 0x11d3,
33 {0x8A, 0x39, 0x00, 0xC0, 0x4F, 0x72, 0xD8, 0xE3} };
35 const IID IID_IVssHardwareSnapshotProvider = { 0x9593A157, 0x44E9, 0x4344,
36 {0xBB, 0xEB, 0x44, 0xFB, 0xF9, 0xB0, 0x6B, 0x10} };
37 const IID IID_IVssSoftwareSnapshotProvider = { 0x609e123e, 0x2c5a, 0x44d3,
38 {0x8f, 0x01, 0x0b, 0x1d, 0x9a, 0x47, 0xd1, 0xff} };
39 const IID IID_IVssProviderCreateSnapshotSet = { 0x5F894E5B, 0x1E39, 0x4778,
40 {0x8E, 0x23, 0x9A, 0xBA, 0xD9, 0xF0, 0xE0, 0x8C} };
41 const IID IID_IVssProviderNotifications = { 0xE561901F, 0x03A5, 0x4afe,
42 {0x86, 0xD0, 0x72, 0xBA, 0xEE, 0xCE, 0x70, 0x04} };
44 const IID IID_IVssEnumObject = { 0xAE1C7110, 0x2F60, 0x11d3,
45 {0x8A, 0x39, 0x00, 0xC0, 0x4F, 0x72, 0xD8, 0xE3} };
48 void LockModule(BOOL lock)
50 if (lock) {
51 InterlockedIncrement(&g_nComObjsInUse);
52 } else {
53 InterlockedDecrement(&g_nComObjsInUse);
57 /* Empty enumerator for VssObject */
59 class CQGAVSSEnumObject : public IVssEnumObject
61 public:
62 STDMETHODIMP QueryInterface(REFIID riid, void **ppObj);
63 STDMETHODIMP_(ULONG) AddRef();
64 STDMETHODIMP_(ULONG) Release();
66 /* IVssEnumObject Methods */
67 STDMETHODIMP Next(
68 ULONG celt, VSS_OBJECT_PROP *rgelt, ULONG *pceltFetched);
69 STDMETHODIMP Skip(ULONG celt);
70 STDMETHODIMP Reset(void);
71 STDMETHODIMP Clone(IVssEnumObject **ppenum);
73 /* CQGAVSSEnumObject Methods */
74 CQGAVSSEnumObject();
75 ~CQGAVSSEnumObject();
77 private:
78 long m_nRefCount;
81 CQGAVSSEnumObject::CQGAVSSEnumObject()
83 m_nRefCount = 0;
84 LockModule(TRUE);
87 CQGAVSSEnumObject::~CQGAVSSEnumObject()
89 LockModule(FALSE);
92 STDMETHODIMP CQGAVSSEnumObject::QueryInterface(REFIID riid, void **ppObj)
94 if (riid == IID_IUnknown || riid == IID_IVssEnumObject) {
95 *ppObj = static_cast<void*>(static_cast<IVssEnumObject*>(this));
96 AddRef();
97 return S_OK;
99 *ppObj = NULL;
100 return E_NOINTERFACE;
103 STDMETHODIMP_(ULONG) CQGAVSSEnumObject::AddRef()
105 return InterlockedIncrement(&m_nRefCount);
108 STDMETHODIMP_(ULONG) CQGAVSSEnumObject::Release()
110 long nRefCount = InterlockedDecrement(&m_nRefCount);
111 if (m_nRefCount == 0) {
112 delete this;
114 return nRefCount;
117 STDMETHODIMP CQGAVSSEnumObject::Next(
118 ULONG celt, VSS_OBJECT_PROP *rgelt, ULONG *pceltFetched)
120 *pceltFetched = 0;
121 return S_FALSE;
124 STDMETHODIMP CQGAVSSEnumObject::Skip(ULONG celt)
126 return S_FALSE;
129 STDMETHODIMP CQGAVSSEnumObject::Reset(void)
131 return S_OK;
134 STDMETHODIMP CQGAVSSEnumObject::Clone(IVssEnumObject **ppenum)
136 return E_NOTIMPL;
140 /* QGAVssProvider */
142 class CQGAVssProvider :
143 public IVssSoftwareSnapshotProvider,
144 public IVssProviderCreateSnapshotSet,
145 public IVssProviderNotifications
147 public:
148 STDMETHODIMP QueryInterface(REFIID riid, void **ppObj);
149 STDMETHODIMP_(ULONG) AddRef();
150 STDMETHODIMP_(ULONG) Release();
152 /* IVssSoftwareSnapshotProvider Methods */
153 STDMETHODIMP SetContext(LONG lContext);
154 STDMETHODIMP GetSnapshotProperties(
155 VSS_ID SnapshotId, VSS_SNAPSHOT_PROP *pProp);
156 STDMETHODIMP Query(
157 VSS_ID QueriedObjectId, VSS_OBJECT_TYPE eQueriedObjectType,
158 VSS_OBJECT_TYPE eReturnedObjectsType, IVssEnumObject **ppEnum);
159 STDMETHODIMP DeleteSnapshots(
160 VSS_ID SourceObjectId, VSS_OBJECT_TYPE eSourceObjectType,
161 BOOL bForceDelete, LONG *plDeletedSnapshots,
162 VSS_ID *pNondeletedSnapshotID);
163 STDMETHODIMP BeginPrepareSnapshot(
164 VSS_ID SnapshotSetId, VSS_ID SnapshotId,
165 VSS_PWSZ pwszVolumeName, LONG lNewContext);
166 STDMETHODIMP IsVolumeSupported(
167 VSS_PWSZ pwszVolumeName, BOOL *pbSupportedByThisProvider);
168 STDMETHODIMP IsVolumeSnapshotted(
169 VSS_PWSZ pwszVolumeName, BOOL *pbSnapshotsPresent,
170 LONG *plSnapshotCompatibility);
171 STDMETHODIMP SetSnapshotProperty(
172 VSS_ID SnapshotId, VSS_SNAPSHOT_PROPERTY_ID eSnapshotPropertyId,
173 VARIANT vProperty);
174 STDMETHODIMP RevertToSnapshot(VSS_ID SnapshotId);
175 STDMETHODIMP QueryRevertStatus(VSS_PWSZ pwszVolume, IVssAsync **ppAsync);
177 /* IVssProviderCreateSnapshotSet Methods */
178 STDMETHODIMP EndPrepareSnapshots(VSS_ID SnapshotSetId);
179 STDMETHODIMP PreCommitSnapshots(VSS_ID SnapshotSetId);
180 STDMETHODIMP CommitSnapshots(VSS_ID SnapshotSetId);
181 STDMETHODIMP PostCommitSnapshots(
182 VSS_ID SnapshotSetId, LONG lSnapshotsCount);
183 STDMETHODIMP PreFinalCommitSnapshots(VSS_ID SnapshotSetId);
184 STDMETHODIMP PostFinalCommitSnapshots(VSS_ID SnapshotSetId);
185 STDMETHODIMP AbortSnapshots(VSS_ID SnapshotSetId);
187 /* IVssProviderNotifications Methods */
188 STDMETHODIMP OnLoad(IUnknown *pCallback);
189 STDMETHODIMP OnUnload(BOOL bForceUnload);
191 /* CQGAVssProvider Methods */
192 CQGAVssProvider();
193 ~CQGAVssProvider();
195 private:
196 long m_nRefCount;
199 CQGAVssProvider::CQGAVssProvider()
201 m_nRefCount = 0;
202 LockModule(TRUE);
205 CQGAVssProvider::~CQGAVssProvider()
207 LockModule(FALSE);
210 STDMETHODIMP CQGAVssProvider::QueryInterface(REFIID riid, void **ppObj)
212 if (riid == IID_IUnknown) {
213 *ppObj = static_cast<void*>(this);
214 AddRef();
215 return S_OK;
217 if (riid == IID_IVssSoftwareSnapshotProvider) {
218 *ppObj = static_cast<void*>(
219 static_cast<IVssSoftwareSnapshotProvider*>(this));
220 AddRef();
221 return S_OK;
223 if (riid == IID_IVssProviderCreateSnapshotSet) {
224 *ppObj = static_cast<void*>(
225 static_cast<IVssProviderCreateSnapshotSet*>(this));
226 AddRef();
227 return S_OK;
229 if (riid == IID_IVssProviderNotifications) {
230 *ppObj = static_cast<void*>(
231 static_cast<IVssProviderNotifications*>(this));
232 AddRef();
233 return S_OK;
235 *ppObj = NULL;
236 return E_NOINTERFACE;
239 STDMETHODIMP_(ULONG) CQGAVssProvider::AddRef()
241 return InterlockedIncrement(&m_nRefCount);
244 STDMETHODIMP_(ULONG) CQGAVssProvider::Release()
246 long nRefCount = InterlockedDecrement(&m_nRefCount);
247 if (m_nRefCount == 0) {
248 delete this;
250 return nRefCount;
255 * IVssSoftwareSnapshotProvider methods
258 STDMETHODIMP CQGAVssProvider::SetContext(LONG lContext)
260 return S_OK;
263 STDMETHODIMP CQGAVssProvider::GetSnapshotProperties(
264 VSS_ID SnapshotId, VSS_SNAPSHOT_PROP *pProp)
266 return VSS_E_OBJECT_NOT_FOUND;
269 STDMETHODIMP CQGAVssProvider::Query(
270 VSS_ID QueriedObjectId, VSS_OBJECT_TYPE eQueriedObjectType,
271 VSS_OBJECT_TYPE eReturnedObjectsType, IVssEnumObject **ppEnum)
273 try {
274 *ppEnum = new CQGAVSSEnumObject;
275 } catch (...) {
276 return E_OUTOFMEMORY;
278 (*ppEnum)->AddRef();
279 return S_OK;
282 STDMETHODIMP CQGAVssProvider::DeleteSnapshots(
283 VSS_ID SourceObjectId, VSS_OBJECT_TYPE eSourceObjectType,
284 BOOL bForceDelete, LONG *plDeletedSnapshots, VSS_ID *pNondeletedSnapshotID)
286 *plDeletedSnapshots = 0;
287 *pNondeletedSnapshotID = SourceObjectId;
288 return S_OK;
291 STDMETHODIMP CQGAVssProvider::BeginPrepareSnapshot(
292 VSS_ID SnapshotSetId, VSS_ID SnapshotId,
293 VSS_PWSZ pwszVolumeName, LONG lNewContext)
295 return S_OK;
298 STDMETHODIMP CQGAVssProvider::IsVolumeSupported(
299 VSS_PWSZ pwszVolumeName, BOOL *pbSupportedByThisProvider)
301 HANDLE hEventFrozen;
303 /* Check if a requester is qemu-ga by whether an event is created */
304 hEventFrozen = OpenEvent(EVENT_ALL_ACCESS, FALSE, EVENT_NAME_FROZEN);
305 if (!hEventFrozen) {
306 *pbSupportedByThisProvider = FALSE;
307 return S_OK;
309 CloseHandle(hEventFrozen);
311 *pbSupportedByThisProvider = TRUE;
312 return S_OK;
315 STDMETHODIMP CQGAVssProvider::IsVolumeSnapshotted(VSS_PWSZ pwszVolumeName,
316 BOOL *pbSnapshotsPresent, LONG *plSnapshotCompatibility)
318 *pbSnapshotsPresent = FALSE;
319 *plSnapshotCompatibility = 0;
320 return S_OK;
323 STDMETHODIMP CQGAVssProvider::SetSnapshotProperty(VSS_ID SnapshotId,
324 VSS_SNAPSHOT_PROPERTY_ID eSnapshotPropertyId, VARIANT vProperty)
326 return E_NOTIMPL;
329 STDMETHODIMP CQGAVssProvider::RevertToSnapshot(VSS_ID SnapshotId)
331 return E_NOTIMPL;
334 STDMETHODIMP CQGAVssProvider::QueryRevertStatus(
335 VSS_PWSZ pwszVolume, IVssAsync **ppAsync)
337 return E_NOTIMPL;
342 * IVssProviderCreateSnapshotSet methods
345 STDMETHODIMP CQGAVssProvider::EndPrepareSnapshots(VSS_ID SnapshotSetId)
347 return S_OK;
350 STDMETHODIMP CQGAVssProvider::PreCommitSnapshots(VSS_ID SnapshotSetId)
352 return S_OK;
355 STDMETHODIMP CQGAVssProvider::CommitSnapshots(VSS_ID SnapshotSetId)
357 HRESULT hr = S_OK;
358 HANDLE hEventFrozen, hEventThaw, hEventTimeout;
360 hEventFrozen = OpenEvent(EVENT_ALL_ACCESS, FALSE, EVENT_NAME_FROZEN);
361 if (!hEventFrozen) {
362 return E_FAIL;
365 hEventThaw = OpenEvent(EVENT_ALL_ACCESS, FALSE, EVENT_NAME_THAW);
366 if (!hEventThaw) {
367 CloseHandle(hEventFrozen);
368 return E_FAIL;
371 hEventTimeout = OpenEvent(EVENT_ALL_ACCESS, FALSE, EVENT_NAME_TIMEOUT);
372 if (!hEventTimeout) {
373 CloseHandle(hEventFrozen);
374 CloseHandle(hEventThaw);
375 return E_FAIL;
378 /* Send event to qemu-ga to notify filesystem is frozen */
379 SetEvent(hEventFrozen);
381 /* Wait until the snapshot is taken by the host. */
382 if (WaitForSingleObject(hEventThaw, VSS_TIMEOUT_MSEC) != WAIT_OBJECT_0) {
383 /* Send event to qemu-ga to notify the provider is timed out */
384 SetEvent(hEventTimeout);
387 CloseHandle(hEventThaw);
388 CloseHandle(hEventFrozen);
389 CloseHandle(hEventTimeout);
390 return hr;
393 STDMETHODIMP CQGAVssProvider::PostCommitSnapshots(
394 VSS_ID SnapshotSetId, LONG lSnapshotsCount)
396 return S_OK;
399 STDMETHODIMP CQGAVssProvider::PreFinalCommitSnapshots(VSS_ID SnapshotSetId)
401 return S_OK;
404 STDMETHODIMP CQGAVssProvider::PostFinalCommitSnapshots(VSS_ID SnapshotSetId)
406 return S_OK;
409 STDMETHODIMP CQGAVssProvider::AbortSnapshots(VSS_ID SnapshotSetId)
411 return S_OK;
415 * IVssProviderNotifications methods
418 STDMETHODIMP CQGAVssProvider::OnLoad(IUnknown *pCallback)
420 return S_OK;
423 STDMETHODIMP CQGAVssProvider::OnUnload(BOOL bForceUnload)
425 return S_OK;
430 * CQGAVssProviderFactory class
433 class CQGAVssProviderFactory : public IClassFactory
435 public:
436 STDMETHODIMP QueryInterface(REFIID riid, void **ppv);
437 STDMETHODIMP_(ULONG) AddRef();
438 STDMETHODIMP_(ULONG) Release();
439 STDMETHODIMP CreateInstance(
440 IUnknown *pUnknownOuter, REFIID iid, void **ppv);
441 STDMETHODIMP LockServer(BOOL lock) { return E_NOTIMPL; }
443 CQGAVssProviderFactory();
444 ~CQGAVssProviderFactory();
446 private:
447 long m_nRefCount;
450 CQGAVssProviderFactory::CQGAVssProviderFactory()
452 m_nRefCount = 0;
453 LockModule(TRUE);
456 CQGAVssProviderFactory::~CQGAVssProviderFactory()
458 LockModule(FALSE);
461 STDMETHODIMP CQGAVssProviderFactory::QueryInterface(REFIID riid, void **ppv)
463 if (riid == IID_IUnknown || riid == IID_IClassFactory) {
464 *ppv = static_cast<void*>(this);
465 AddRef();
466 return S_OK;
468 *ppv = NULL;
469 return E_NOINTERFACE;
472 STDMETHODIMP_(ULONG) CQGAVssProviderFactory::AddRef()
474 return InterlockedIncrement(&m_nRefCount);
477 STDMETHODIMP_(ULONG) CQGAVssProviderFactory::Release()
479 long nRefCount = InterlockedDecrement(&m_nRefCount);
480 if (m_nRefCount == 0) {
481 delete this;
483 return nRefCount;
486 STDMETHODIMP CQGAVssProviderFactory::CreateInstance(
487 IUnknown *pUnknownOuter, REFIID iid, void **ppv)
489 CQGAVssProvider *pObj;
491 if (pUnknownOuter) {
492 return CLASS_E_NOAGGREGATION;
494 try {
495 pObj = new CQGAVssProvider;
496 } catch (...) {
497 return E_OUTOFMEMORY;
499 HRESULT hr = pObj->QueryInterface(iid, ppv);
500 if (FAILED(hr)) {
501 delete pObj;
503 return hr;
508 * DLL functions
511 STDAPI DllGetClassObject(REFCLSID rclsid, REFIID riid, LPVOID *ppv)
513 CQGAVssProviderFactory *factory;
514 try {
515 factory = new CQGAVssProviderFactory;
516 } catch (...) {
517 return E_OUTOFMEMORY;
519 factory->AddRef();
520 HRESULT hr = factory->QueryInterface(riid, ppv);
521 factory->Release();
522 return hr;
525 STDAPI DllCanUnloadNow()
527 return g_nComObjsInUse == 0 ? S_OK : S_FALSE;
530 EXTERN_C
531 BOOL WINAPI DllMain(HINSTANCE hinstDll, DWORD dwReason, LPVOID lpReserved)
533 qga_debug("begin, reason = %lu", dwReason);
534 if (dwReason == DLL_PROCESS_ATTACH) {
535 g_hinstDll = hinstDll;
536 DisableThreadLibraryCalls(hinstDll);
538 qga_debug_end;
539 return TRUE;