Merge tag 'qemu-macppc-20230206' of https://github.com/mcayland/qemu into staging
[qemu.git] / qga / vss-win32 / provider.cpp
blob1b885e24ee17952a6bef341732c434c348e8d59c
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 #ifdef HAVE_VSS_SDK
16 #include <vscoordint.h>
17 #else
18 #include <vsadmin.h>
19 #endif
20 #include <vsprov.h>
22 #define VSS_TIMEOUT_MSEC (60*1000)
24 static long g_nComObjsInUse;
25 HINSTANCE g_hinstDll;
27 /* VSS common GUID's */
29 const CLSID CLSID_VSSCoordinator = { 0xE579AB5F, 0x1CC4, 0x44b4,
30 {0xBE, 0xD9, 0xDE, 0x09, 0x91, 0xFF, 0x06, 0x23} };
31 const IID IID_IVssAdmin = { 0x77ED5996, 0x2F63, 0x11d3,
32 {0x8A, 0x39, 0x00, 0xC0, 0x4F, 0x72, 0xD8, 0xE3} };
34 const IID IID_IVssHardwareSnapshotProvider = { 0x9593A157, 0x44E9, 0x4344,
35 {0xBB, 0xEB, 0x44, 0xFB, 0xF9, 0xB0, 0x6B, 0x10} };
36 const IID IID_IVssSoftwareSnapshotProvider = { 0x609e123e, 0x2c5a, 0x44d3,
37 {0x8f, 0x01, 0x0b, 0x1d, 0x9a, 0x47, 0xd1, 0xff} };
38 const IID IID_IVssProviderCreateSnapshotSet = { 0x5F894E5B, 0x1E39, 0x4778,
39 {0x8E, 0x23, 0x9A, 0xBA, 0xD9, 0xF0, 0xE0, 0x8C} };
40 const IID IID_IVssProviderNotifications = { 0xE561901F, 0x03A5, 0x4afe,
41 {0x86, 0xD0, 0x72, 0xBA, 0xEE, 0xCE, 0x70, 0x04} };
43 const IID IID_IVssEnumObject = { 0xAE1C7110, 0x2F60, 0x11d3,
44 {0x8A, 0x39, 0x00, 0xC0, 0x4F, 0x72, 0xD8, 0xE3} };
47 void LockModule(BOOL lock)
49 if (lock) {
50 InterlockedIncrement(&g_nComObjsInUse);
51 } else {
52 InterlockedDecrement(&g_nComObjsInUse);
56 /* Empty enumerator for VssObject */
58 class CQGAVSSEnumObject : public IVssEnumObject
60 public:
61 STDMETHODIMP QueryInterface(REFIID riid, void **ppObj);
62 STDMETHODIMP_(ULONG) AddRef();
63 STDMETHODIMP_(ULONG) Release();
65 /* IVssEnumObject Methods */
66 STDMETHODIMP Next(
67 ULONG celt, VSS_OBJECT_PROP *rgelt, ULONG *pceltFetched);
68 STDMETHODIMP Skip(ULONG celt);
69 STDMETHODIMP Reset(void);
70 STDMETHODIMP Clone(IVssEnumObject **ppenum);
72 /* CQGAVSSEnumObject Methods */
73 CQGAVSSEnumObject();
74 ~CQGAVSSEnumObject();
76 private:
77 long m_nRefCount;
80 CQGAVSSEnumObject::CQGAVSSEnumObject()
82 m_nRefCount = 0;
83 LockModule(TRUE);
86 CQGAVSSEnumObject::~CQGAVSSEnumObject()
88 LockModule(FALSE);
91 STDMETHODIMP CQGAVSSEnumObject::QueryInterface(REFIID riid, void **ppObj)
93 if (riid == IID_IUnknown || riid == IID_IVssEnumObject) {
94 *ppObj = static_cast<void*>(static_cast<IVssEnumObject*>(this));
95 AddRef();
96 return S_OK;
98 *ppObj = NULL;
99 return E_NOINTERFACE;
102 STDMETHODIMP_(ULONG) CQGAVSSEnumObject::AddRef()
104 return InterlockedIncrement(&m_nRefCount);
107 STDMETHODIMP_(ULONG) CQGAVSSEnumObject::Release()
109 long nRefCount = InterlockedDecrement(&m_nRefCount);
110 if (m_nRefCount == 0) {
111 delete this;
113 return nRefCount;
116 STDMETHODIMP CQGAVSSEnumObject::Next(
117 ULONG celt, VSS_OBJECT_PROP *rgelt, ULONG *pceltFetched)
119 *pceltFetched = 0;
120 return S_FALSE;
123 STDMETHODIMP CQGAVSSEnumObject::Skip(ULONG celt)
125 return S_FALSE;
128 STDMETHODIMP CQGAVSSEnumObject::Reset(void)
130 return S_OK;
133 STDMETHODIMP CQGAVSSEnumObject::Clone(IVssEnumObject **ppenum)
135 return E_NOTIMPL;
139 /* QGAVssProvider */
141 class CQGAVssProvider :
142 public IVssSoftwareSnapshotProvider,
143 public IVssProviderCreateSnapshotSet,
144 public IVssProviderNotifications
146 public:
147 STDMETHODIMP QueryInterface(REFIID riid, void **ppObj);
148 STDMETHODIMP_(ULONG) AddRef();
149 STDMETHODIMP_(ULONG) Release();
151 /* IVssSoftwareSnapshotProvider Methods */
152 STDMETHODIMP SetContext(LONG lContext);
153 STDMETHODIMP GetSnapshotProperties(
154 VSS_ID SnapshotId, VSS_SNAPSHOT_PROP *pProp);
155 STDMETHODIMP Query(
156 VSS_ID QueriedObjectId, VSS_OBJECT_TYPE eQueriedObjectType,
157 VSS_OBJECT_TYPE eReturnedObjectsType, IVssEnumObject **ppEnum);
158 STDMETHODIMP DeleteSnapshots(
159 VSS_ID SourceObjectId, VSS_OBJECT_TYPE eSourceObjectType,
160 BOOL bForceDelete, LONG *plDeletedSnapshots,
161 VSS_ID *pNondeletedSnapshotID);
162 STDMETHODIMP BeginPrepareSnapshot(
163 VSS_ID SnapshotSetId, VSS_ID SnapshotId,
164 VSS_PWSZ pwszVolumeName, LONG lNewContext);
165 STDMETHODIMP IsVolumeSupported(
166 VSS_PWSZ pwszVolumeName, BOOL *pbSupportedByThisProvider);
167 STDMETHODIMP IsVolumeSnapshotted(
168 VSS_PWSZ pwszVolumeName, BOOL *pbSnapshotsPresent,
169 LONG *plSnapshotCompatibility);
170 STDMETHODIMP SetSnapshotProperty(
171 VSS_ID SnapshotId, VSS_SNAPSHOT_PROPERTY_ID eSnapshotPropertyId,
172 VARIANT vProperty);
173 STDMETHODIMP RevertToSnapshot(VSS_ID SnapshotId);
174 STDMETHODIMP QueryRevertStatus(VSS_PWSZ pwszVolume, IVssAsync **ppAsync);
176 /* IVssProviderCreateSnapshotSet Methods */
177 STDMETHODIMP EndPrepareSnapshots(VSS_ID SnapshotSetId);
178 STDMETHODIMP PreCommitSnapshots(VSS_ID SnapshotSetId);
179 STDMETHODIMP CommitSnapshots(VSS_ID SnapshotSetId);
180 STDMETHODIMP PostCommitSnapshots(
181 VSS_ID SnapshotSetId, LONG lSnapshotsCount);
182 STDMETHODIMP PreFinalCommitSnapshots(VSS_ID SnapshotSetId);
183 STDMETHODIMP PostFinalCommitSnapshots(VSS_ID SnapshotSetId);
184 STDMETHODIMP AbortSnapshots(VSS_ID SnapshotSetId);
186 /* IVssProviderNotifications Methods */
187 STDMETHODIMP OnLoad(IUnknown *pCallback);
188 STDMETHODIMP OnUnload(BOOL bForceUnload);
190 /* CQGAVssProvider Methods */
191 CQGAVssProvider();
192 ~CQGAVssProvider();
194 private:
195 long m_nRefCount;
198 CQGAVssProvider::CQGAVssProvider()
200 m_nRefCount = 0;
201 LockModule(TRUE);
204 CQGAVssProvider::~CQGAVssProvider()
206 LockModule(FALSE);
209 STDMETHODIMP CQGAVssProvider::QueryInterface(REFIID riid, void **ppObj)
211 if (riid == IID_IUnknown) {
212 *ppObj = static_cast<void*>(this);
213 AddRef();
214 return S_OK;
216 if (riid == IID_IVssSoftwareSnapshotProvider) {
217 *ppObj = static_cast<void*>(
218 static_cast<IVssSoftwareSnapshotProvider*>(this));
219 AddRef();
220 return S_OK;
222 if (riid == IID_IVssProviderCreateSnapshotSet) {
223 *ppObj = static_cast<void*>(
224 static_cast<IVssProviderCreateSnapshotSet*>(this));
225 AddRef();
226 return S_OK;
228 if (riid == IID_IVssProviderNotifications) {
229 *ppObj = static_cast<void*>(
230 static_cast<IVssProviderNotifications*>(this));
231 AddRef();
232 return S_OK;
234 *ppObj = NULL;
235 return E_NOINTERFACE;
238 STDMETHODIMP_(ULONG) CQGAVssProvider::AddRef()
240 return InterlockedIncrement(&m_nRefCount);
243 STDMETHODIMP_(ULONG) CQGAVssProvider::Release()
245 long nRefCount = InterlockedDecrement(&m_nRefCount);
246 if (m_nRefCount == 0) {
247 delete this;
249 return nRefCount;
254 * IVssSoftwareSnapshotProvider methods
257 STDMETHODIMP CQGAVssProvider::SetContext(LONG lContext)
259 return S_OK;
262 STDMETHODIMP CQGAVssProvider::GetSnapshotProperties(
263 VSS_ID SnapshotId, VSS_SNAPSHOT_PROP *pProp)
265 return VSS_E_OBJECT_NOT_FOUND;
268 STDMETHODIMP CQGAVssProvider::Query(
269 VSS_ID QueriedObjectId, VSS_OBJECT_TYPE eQueriedObjectType,
270 VSS_OBJECT_TYPE eReturnedObjectsType, IVssEnumObject **ppEnum)
272 try {
273 *ppEnum = new CQGAVSSEnumObject;
274 } catch (...) {
275 return E_OUTOFMEMORY;
277 (*ppEnum)->AddRef();
278 return S_OK;
281 STDMETHODIMP CQGAVssProvider::DeleteSnapshots(
282 VSS_ID SourceObjectId, VSS_OBJECT_TYPE eSourceObjectType,
283 BOOL bForceDelete, LONG *plDeletedSnapshots, VSS_ID *pNondeletedSnapshotID)
285 *plDeletedSnapshots = 0;
286 *pNondeletedSnapshotID = SourceObjectId;
287 return S_OK;
290 STDMETHODIMP CQGAVssProvider::BeginPrepareSnapshot(
291 VSS_ID SnapshotSetId, VSS_ID SnapshotId,
292 VSS_PWSZ pwszVolumeName, LONG lNewContext)
294 return S_OK;
297 STDMETHODIMP CQGAVssProvider::IsVolumeSupported(
298 VSS_PWSZ pwszVolumeName, BOOL *pbSupportedByThisProvider)
300 HANDLE hEventFrozen;
302 /* Check if a requester is qemu-ga by whether an event is created */
303 hEventFrozen = OpenEvent(EVENT_ALL_ACCESS, FALSE, EVENT_NAME_FROZEN);
304 if (!hEventFrozen) {
305 *pbSupportedByThisProvider = FALSE;
306 return S_OK;
308 CloseHandle(hEventFrozen);
310 *pbSupportedByThisProvider = TRUE;
311 return S_OK;
314 STDMETHODIMP CQGAVssProvider::IsVolumeSnapshotted(VSS_PWSZ pwszVolumeName,
315 BOOL *pbSnapshotsPresent, LONG *plSnapshotCompatibility)
317 *pbSnapshotsPresent = FALSE;
318 *plSnapshotCompatibility = 0;
319 return S_OK;
322 STDMETHODIMP CQGAVssProvider::SetSnapshotProperty(VSS_ID SnapshotId,
323 VSS_SNAPSHOT_PROPERTY_ID eSnapshotPropertyId, VARIANT vProperty)
325 return E_NOTIMPL;
328 STDMETHODIMP CQGAVssProvider::RevertToSnapshot(VSS_ID SnapshotId)
330 return E_NOTIMPL;
333 STDMETHODIMP CQGAVssProvider::QueryRevertStatus(
334 VSS_PWSZ pwszVolume, IVssAsync **ppAsync)
336 return E_NOTIMPL;
341 * IVssProviderCreateSnapshotSet methods
344 STDMETHODIMP CQGAVssProvider::EndPrepareSnapshots(VSS_ID SnapshotSetId)
346 return S_OK;
349 STDMETHODIMP CQGAVssProvider::PreCommitSnapshots(VSS_ID SnapshotSetId)
351 return S_OK;
354 STDMETHODIMP CQGAVssProvider::CommitSnapshots(VSS_ID SnapshotSetId)
356 HRESULT hr = S_OK;
357 HANDLE hEventFrozen, hEventThaw, hEventTimeout;
359 hEventFrozen = OpenEvent(EVENT_ALL_ACCESS, FALSE, EVENT_NAME_FROZEN);
360 if (!hEventFrozen) {
361 return E_FAIL;
364 hEventThaw = OpenEvent(EVENT_ALL_ACCESS, FALSE, EVENT_NAME_THAW);
365 if (!hEventThaw) {
366 CloseHandle(hEventFrozen);
367 return E_FAIL;
370 hEventTimeout = OpenEvent(EVENT_ALL_ACCESS, FALSE, EVENT_NAME_TIMEOUT);
371 if (!hEventTimeout) {
372 CloseHandle(hEventFrozen);
373 CloseHandle(hEventThaw);
374 return E_FAIL;
377 /* Send event to qemu-ga to notify filesystem is frozen */
378 SetEvent(hEventFrozen);
380 /* Wait until the snapshot is taken by the host. */
381 if (WaitForSingleObject(hEventThaw, VSS_TIMEOUT_MSEC) != WAIT_OBJECT_0) {
382 /* Send event to qemu-ga to notify the provider is timed out */
383 SetEvent(hEventTimeout);
386 CloseHandle(hEventThaw);
387 CloseHandle(hEventFrozen);
388 CloseHandle(hEventTimeout);
389 return hr;
392 STDMETHODIMP CQGAVssProvider::PostCommitSnapshots(
393 VSS_ID SnapshotSetId, LONG lSnapshotsCount)
395 return S_OK;
398 STDMETHODIMP CQGAVssProvider::PreFinalCommitSnapshots(VSS_ID SnapshotSetId)
400 return S_OK;
403 STDMETHODIMP CQGAVssProvider::PostFinalCommitSnapshots(VSS_ID SnapshotSetId)
405 return S_OK;
408 STDMETHODIMP CQGAVssProvider::AbortSnapshots(VSS_ID SnapshotSetId)
410 return S_OK;
414 * IVssProviderNotifications methods
417 STDMETHODIMP CQGAVssProvider::OnLoad(IUnknown *pCallback)
419 return S_OK;
422 STDMETHODIMP CQGAVssProvider::OnUnload(BOOL bForceUnload)
424 return S_OK;
429 * CQGAVssProviderFactory class
432 class CQGAVssProviderFactory : public IClassFactory
434 public:
435 STDMETHODIMP QueryInterface(REFIID riid, void **ppv);
436 STDMETHODIMP_(ULONG) AddRef();
437 STDMETHODIMP_(ULONG) Release();
438 STDMETHODIMP CreateInstance(
439 IUnknown *pUnknownOuter, REFIID iid, void **ppv);
440 STDMETHODIMP LockServer(BOOL lock) { return E_NOTIMPL; }
442 CQGAVssProviderFactory();
443 ~CQGAVssProviderFactory();
445 private:
446 long m_nRefCount;
449 CQGAVssProviderFactory::CQGAVssProviderFactory()
451 m_nRefCount = 0;
452 LockModule(TRUE);
455 CQGAVssProviderFactory::~CQGAVssProviderFactory()
457 LockModule(FALSE);
460 STDMETHODIMP CQGAVssProviderFactory::QueryInterface(REFIID riid, void **ppv)
462 if (riid == IID_IUnknown || riid == IID_IClassFactory) {
463 *ppv = static_cast<void*>(this);
464 AddRef();
465 return S_OK;
467 *ppv = NULL;
468 return E_NOINTERFACE;
471 STDMETHODIMP_(ULONG) CQGAVssProviderFactory::AddRef()
473 return InterlockedIncrement(&m_nRefCount);
476 STDMETHODIMP_(ULONG) CQGAVssProviderFactory::Release()
478 long nRefCount = InterlockedDecrement(&m_nRefCount);
479 if (m_nRefCount == 0) {
480 delete this;
482 return nRefCount;
485 STDMETHODIMP CQGAVssProviderFactory::CreateInstance(
486 IUnknown *pUnknownOuter, REFIID iid, void **ppv)
488 CQGAVssProvider *pObj;
490 if (pUnknownOuter) {
491 return CLASS_E_NOAGGREGATION;
493 try {
494 pObj = new CQGAVssProvider;
495 } catch (...) {
496 return E_OUTOFMEMORY;
498 HRESULT hr = pObj->QueryInterface(iid, ppv);
499 if (FAILED(hr)) {
500 delete pObj;
502 return hr;
507 * DLL functions
510 STDAPI DllGetClassObject(REFCLSID rclsid, REFIID riid, LPVOID *ppv)
512 CQGAVssProviderFactory *factory;
513 try {
514 factory = new CQGAVssProviderFactory;
515 } catch (...) {
516 return E_OUTOFMEMORY;
518 factory->AddRef();
519 HRESULT hr = factory->QueryInterface(riid, ppv);
520 factory->Release();
521 return hr;
524 STDAPI DllCanUnloadNow()
526 return g_nComObjsInUse == 0 ? S_OK : S_FALSE;
529 EXTERN_C
530 BOOL WINAPI DllMain(HINSTANCE hinstDll, DWORD dwReason, LPVOID lpReserved)
532 if (dwReason == DLL_PROCESS_ATTACH) {
533 g_hinstDll = hinstDll;
534 DisableThreadLibraryCalls(hinstDll);
536 return TRUE;