]> git.proxmox.com Git - mirror_qemu.git/blame - qga/vss-win32/provider.cpp
qga-vss: Use the proper operator to free memory
[mirror_qemu.git] / qga / vss-win32 / provider.cpp
CommitLineData
b39297ae
TS
1/*
2 * QEMU Guest Agent win32 VSS Provider implementations
3 *
4 * Copyright Hitachi Data Systems Corp. 2013
5 *
6 * Authors:
7 * Tomoki Sekiyama <tomoki.sekiyama@hds.com>
8 *
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.
11 */
12
e55eb806 13#include "qemu/osdep.h"
b39297ae 14#include "vss-common.h"
872b69e6 15#ifdef HAVE_VSS_SDK
61fb0bd1 16#include <vscoordint.h>
872b69e6
MAL
17#else
18#include <vsadmin.h>
19#endif
61fb0bd1 20#include <vsprov.h>
b39297ae
TS
21
22#define VSS_TIMEOUT_MSEC (60*1000)
23
24static long g_nComObjsInUse;
25HINSTANCE g_hinstDll;
26
27/* VSS common GUID's */
28
29const CLSID CLSID_VSSCoordinator = { 0xE579AB5F, 0x1CC4, 0x44b4,
30 {0xBE, 0xD9, 0xDE, 0x09, 0x91, 0xFF, 0x06, 0x23} };
31const IID IID_IVssAdmin = { 0x77ED5996, 0x2F63, 0x11d3,
32 {0x8A, 0x39, 0x00, 0xC0, 0x4F, 0x72, 0xD8, 0xE3} };
33
34const IID IID_IVssHardwareSnapshotProvider = { 0x9593A157, 0x44E9, 0x4344,
35 {0xBB, 0xEB, 0x44, 0xFB, 0xF9, 0xB0, 0x6B, 0x10} };
36const IID IID_IVssSoftwareSnapshotProvider = { 0x609e123e, 0x2c5a, 0x44d3,
37 {0x8f, 0x01, 0x0b, 0x1d, 0x9a, 0x47, 0xd1, 0xff} };
38const IID IID_IVssProviderCreateSnapshotSet = { 0x5F894E5B, 0x1E39, 0x4778,
39 {0x8E, 0x23, 0x9A, 0xBA, 0xD9, 0xF0, 0xE0, 0x8C} };
40const IID IID_IVssProviderNotifications = { 0xE561901F, 0x03A5, 0x4afe,
41 {0x86, 0xD0, 0x72, 0xBA, 0xEE, 0xCE, 0x70, 0x04} };
42
43const IID IID_IVssEnumObject = { 0xAE1C7110, 0x2F60, 0x11d3,
44 {0x8A, 0x39, 0x00, 0xC0, 0x4F, 0x72, 0xD8, 0xE3} };
45
46
47void LockModule(BOOL lock)
48{
49 if (lock) {
50 InterlockedIncrement(&g_nComObjsInUse);
51 } else {
52 InterlockedDecrement(&g_nComObjsInUse);
53 }
54}
55
56/* Empty enumerator for VssObject */
57
58class CQGAVSSEnumObject : public IVssEnumObject
59{
60public:
61 STDMETHODIMP QueryInterface(REFIID riid, void **ppObj);
62 STDMETHODIMP_(ULONG) AddRef();
63 STDMETHODIMP_(ULONG) Release();
64
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);
71
72 /* CQGAVSSEnumObject Methods */
73 CQGAVSSEnumObject();
74 ~CQGAVSSEnumObject();
75
76private:
77 long m_nRefCount;
78};
79
80CQGAVSSEnumObject::CQGAVSSEnumObject()
81{
82 m_nRefCount = 0;
83 LockModule(TRUE);
84}
85
86CQGAVSSEnumObject::~CQGAVSSEnumObject()
87{
88 LockModule(FALSE);
89}
90
91STDMETHODIMP CQGAVSSEnumObject::QueryInterface(REFIID riid, void **ppObj)
92{
93 if (riid == IID_IUnknown || riid == IID_IVssEnumObject) {
94 *ppObj = static_cast<void*>(static_cast<IVssEnumObject*>(this));
95 AddRef();
96 return S_OK;
97 }
98 *ppObj = NULL;
99 return E_NOINTERFACE;
100}
101
102STDMETHODIMP_(ULONG) CQGAVSSEnumObject::AddRef()
103{
104 return InterlockedIncrement(&m_nRefCount);
105}
106
107STDMETHODIMP_(ULONG) CQGAVSSEnumObject::Release()
108{
109 long nRefCount = InterlockedDecrement(&m_nRefCount);
110 if (m_nRefCount == 0) {
111 delete this;
112 }
113 return nRefCount;
114}
115
116STDMETHODIMP CQGAVSSEnumObject::Next(
117 ULONG celt, VSS_OBJECT_PROP *rgelt, ULONG *pceltFetched)
118{
119 *pceltFetched = 0;
120 return S_FALSE;
121}
122
123STDMETHODIMP CQGAVSSEnumObject::Skip(ULONG celt)
124{
125 return S_FALSE;
126}
127
128STDMETHODIMP CQGAVSSEnumObject::Reset(void)
129{
130 return S_OK;
131}
132
133STDMETHODIMP CQGAVSSEnumObject::Clone(IVssEnumObject **ppenum)
134{
135 return E_NOTIMPL;
136}
137
138
139/* QGAVssProvider */
140
141class CQGAVssProvider :
142 public IVssSoftwareSnapshotProvider,
143 public IVssProviderCreateSnapshotSet,
144 public IVssProviderNotifications
145{
146public:
147 STDMETHODIMP QueryInterface(REFIID riid, void **ppObj);
148 STDMETHODIMP_(ULONG) AddRef();
149 STDMETHODIMP_(ULONG) Release();
150
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);
175
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);
185
186 /* IVssProviderNotifications Methods */
187 STDMETHODIMP OnLoad(IUnknown *pCallback);
188 STDMETHODIMP OnUnload(BOOL bForceUnload);
189
190 /* CQGAVssProvider Methods */
191 CQGAVssProvider();
192 ~CQGAVssProvider();
193
194private:
195 long m_nRefCount;
196};
197
198CQGAVssProvider::CQGAVssProvider()
199{
200 m_nRefCount = 0;
201 LockModule(TRUE);
202}
203
204CQGAVssProvider::~CQGAVssProvider()
205{
206 LockModule(FALSE);
207}
208
209STDMETHODIMP CQGAVssProvider::QueryInterface(REFIID riid, void **ppObj)
210{
211 if (riid == IID_IUnknown) {
212 *ppObj = static_cast<void*>(this);
213 AddRef();
214 return S_OK;
215 }
216 if (riid == IID_IVssSoftwareSnapshotProvider) {
217 *ppObj = static_cast<void*>(
218 static_cast<IVssSoftwareSnapshotProvider*>(this));
219 AddRef();
220 return S_OK;
221 }
222 if (riid == IID_IVssProviderCreateSnapshotSet) {
223 *ppObj = static_cast<void*>(
224 static_cast<IVssProviderCreateSnapshotSet*>(this));
225 AddRef();
226 return S_OK;
227 }
228 if (riid == IID_IVssProviderNotifications) {
229 *ppObj = static_cast<void*>(
230 static_cast<IVssProviderNotifications*>(this));
231 AddRef();
232 return S_OK;
233 }
234 *ppObj = NULL;
235 return E_NOINTERFACE;
236}
237
238STDMETHODIMP_(ULONG) CQGAVssProvider::AddRef()
239{
240 return InterlockedIncrement(&m_nRefCount);
241}
242
243STDMETHODIMP_(ULONG) CQGAVssProvider::Release()
244{
245 long nRefCount = InterlockedDecrement(&m_nRefCount);
246 if (m_nRefCount == 0) {
247 delete this;
248 }
249 return nRefCount;
250}
251
252
253/*
254 * IVssSoftwareSnapshotProvider methods
255 */
256
257STDMETHODIMP CQGAVssProvider::SetContext(LONG lContext)
258{
259 return S_OK;
260}
261
262STDMETHODIMP CQGAVssProvider::GetSnapshotProperties(
263 VSS_ID SnapshotId, VSS_SNAPSHOT_PROP *pProp)
264{
265 return VSS_E_OBJECT_NOT_FOUND;
266}
267
268STDMETHODIMP CQGAVssProvider::Query(
269 VSS_ID QueriedObjectId, VSS_OBJECT_TYPE eQueriedObjectType,
270 VSS_OBJECT_TYPE eReturnedObjectsType, IVssEnumObject **ppEnum)
271{
272 try {
273 *ppEnum = new CQGAVSSEnumObject;
274 } catch (...) {
275 return E_OUTOFMEMORY;
276 }
277 (*ppEnum)->AddRef();
278 return S_OK;
279}
280
281STDMETHODIMP CQGAVssProvider::DeleteSnapshots(
282 VSS_ID SourceObjectId, VSS_OBJECT_TYPE eSourceObjectType,
283 BOOL bForceDelete, LONG *plDeletedSnapshots, VSS_ID *pNondeletedSnapshotID)
284{
d9e1f574
TS
285 *plDeletedSnapshots = 0;
286 *pNondeletedSnapshotID = SourceObjectId;
287 return S_OK;
b39297ae
TS
288}
289
290STDMETHODIMP CQGAVssProvider::BeginPrepareSnapshot(
291 VSS_ID SnapshotSetId, VSS_ID SnapshotId,
292 VSS_PWSZ pwszVolumeName, LONG lNewContext)
293{
294 return S_OK;
295}
296
297STDMETHODIMP CQGAVssProvider::IsVolumeSupported(
298 VSS_PWSZ pwszVolumeName, BOOL *pbSupportedByThisProvider)
299{
ff8adbcf 300 HANDLE hEventFrozen;
b39297ae 301
ff8adbcf
TS
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;
307 }
308 CloseHandle(hEventFrozen);
309
310 *pbSupportedByThisProvider = TRUE;
b39297ae
TS
311 return S_OK;
312}
313
314STDMETHODIMP CQGAVssProvider::IsVolumeSnapshotted(VSS_PWSZ pwszVolumeName,
315 BOOL *pbSnapshotsPresent, LONG *plSnapshotCompatibility)
316{
317 *pbSnapshotsPresent = FALSE;
318 *plSnapshotCompatibility = 0;
319 return S_OK;
320}
321
322STDMETHODIMP CQGAVssProvider::SetSnapshotProperty(VSS_ID SnapshotId,
323 VSS_SNAPSHOT_PROPERTY_ID eSnapshotPropertyId, VARIANT vProperty)
324{
325 return E_NOTIMPL;
326}
327
328STDMETHODIMP CQGAVssProvider::RevertToSnapshot(VSS_ID SnapshotId)
329{
330 return E_NOTIMPL;
331}
332
333STDMETHODIMP CQGAVssProvider::QueryRevertStatus(
334 VSS_PWSZ pwszVolume, IVssAsync **ppAsync)
335{
336 return E_NOTIMPL;
337}
338
339
340/*
341 * IVssProviderCreateSnapshotSet methods
342 */
343
344STDMETHODIMP CQGAVssProvider::EndPrepareSnapshots(VSS_ID SnapshotSetId)
345{
346 return S_OK;
347}
348
349STDMETHODIMP CQGAVssProvider::PreCommitSnapshots(VSS_ID SnapshotSetId)
350{
351 return S_OK;
352}
353
354STDMETHODIMP CQGAVssProvider::CommitSnapshots(VSS_ID SnapshotSetId)
355{
356 HRESULT hr = S_OK;
357 HANDLE hEventFrozen, hEventThaw, hEventTimeout;
358
359 hEventFrozen = OpenEvent(EVENT_ALL_ACCESS, FALSE, EVENT_NAME_FROZEN);
4c1b8f1e 360 if (!hEventFrozen) {
b39297ae
TS
361 return E_FAIL;
362 }
363
364 hEventThaw = OpenEvent(EVENT_ALL_ACCESS, FALSE, EVENT_NAME_THAW);
4c1b8f1e 365 if (!hEventThaw) {
b39297ae
TS
366 CloseHandle(hEventFrozen);
367 return E_FAIL;
368 }
369
370 hEventTimeout = OpenEvent(EVENT_ALL_ACCESS, FALSE, EVENT_NAME_TIMEOUT);
4c1b8f1e 371 if (!hEventTimeout) {
b39297ae
TS
372 CloseHandle(hEventFrozen);
373 CloseHandle(hEventThaw);
374 return E_FAIL;
375 }
376
377 /* Send event to qemu-ga to notify filesystem is frozen */
378 SetEvent(hEventFrozen);
379
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);
b39297ae
TS
384 }
385
386 CloseHandle(hEventThaw);
387 CloseHandle(hEventFrozen);
388 CloseHandle(hEventTimeout);
389 return hr;
390}
391
392STDMETHODIMP CQGAVssProvider::PostCommitSnapshots(
393 VSS_ID SnapshotSetId, LONG lSnapshotsCount)
394{
395 return S_OK;
396}
397
398STDMETHODIMP CQGAVssProvider::PreFinalCommitSnapshots(VSS_ID SnapshotSetId)
399{
400 return S_OK;
401}
402
403STDMETHODIMP CQGAVssProvider::PostFinalCommitSnapshots(VSS_ID SnapshotSetId)
404{
405 return S_OK;
406}
407
408STDMETHODIMP CQGAVssProvider::AbortSnapshots(VSS_ID SnapshotSetId)
409{
410 return S_OK;
411}
412
413/*
414 * IVssProviderNotifications methods
415 */
416
417STDMETHODIMP CQGAVssProvider::OnLoad(IUnknown *pCallback)
418{
419 return S_OK;
420}
421
422STDMETHODIMP CQGAVssProvider::OnUnload(BOOL bForceUnload)
423{
424 return S_OK;
425}
426
427
428/*
429 * CQGAVssProviderFactory class
430 */
431
432class CQGAVssProviderFactory : public IClassFactory
433{
434public:
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; }
441
442 CQGAVssProviderFactory();
443 ~CQGAVssProviderFactory();
444
445private:
446 long m_nRefCount;
447};
448
449CQGAVssProviderFactory::CQGAVssProviderFactory()
450{
451 m_nRefCount = 0;
452 LockModule(TRUE);
453}
454
455CQGAVssProviderFactory::~CQGAVssProviderFactory()
456{
457 LockModule(FALSE);
458}
459
460STDMETHODIMP CQGAVssProviderFactory::QueryInterface(REFIID riid, void **ppv)
461{
462 if (riid == IID_IUnknown || riid == IID_IClassFactory) {
463 *ppv = static_cast<void*>(this);
464 AddRef();
465 return S_OK;
466 }
467 *ppv = NULL;
468 return E_NOINTERFACE;
469}
470
471STDMETHODIMP_(ULONG) CQGAVssProviderFactory::AddRef()
472{
473 return InterlockedIncrement(&m_nRefCount);
474}
475
476STDMETHODIMP_(ULONG) CQGAVssProviderFactory::Release()
477{
478 long nRefCount = InterlockedDecrement(&m_nRefCount);
479 if (m_nRefCount == 0) {
480 delete this;
481 }
482 return nRefCount;
483}
484
485STDMETHODIMP CQGAVssProviderFactory::CreateInstance(
486 IUnknown *pUnknownOuter, REFIID iid, void **ppv)
487{
488 CQGAVssProvider *pObj;
489
490 if (pUnknownOuter) {
491 return CLASS_E_NOAGGREGATION;
492 }
493 try {
494 pObj = new CQGAVssProvider;
495 } catch (...) {
496 return E_OUTOFMEMORY;
497 }
498 HRESULT hr = pObj->QueryInterface(iid, ppv);
499 if (FAILED(hr)) {
500 delete pObj;
501 }
502 return hr;
503}
504
505
506/*
507 * DLL functions
508 */
509
510STDAPI DllGetClassObject(REFCLSID rclsid, REFIID riid, LPVOID *ppv)
511{
512 CQGAVssProviderFactory *factory;
513 try {
514 factory = new CQGAVssProviderFactory;
515 } catch (...) {
516 return E_OUTOFMEMORY;
517 }
518 factory->AddRef();
519 HRESULT hr = factory->QueryInterface(riid, ppv);
520 factory->Release();
521 return hr;
522}
523
524STDAPI DllCanUnloadNow()
525{
526 return g_nComObjsInUse == 0 ? S_OK : S_FALSE;
527}
528
529EXTERN_C
530BOOL WINAPI DllMain(HINSTANCE hinstDll, DWORD dwReason, LPVOID lpReserved)
531{
532 if (dwReason == DLL_PROCESS_ATTACH) {
533 g_hinstDll = hinstDll;
534 DisableThreadLibraryCalls(hinstDll);
535 }
536 return TRUE;
537}