2 * QEMU Guest Agent win32 VSS Provider implementations
4 * Copyright Hitachi Data Systems Corp. 2013
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 "inc/win2003/vscoordint.h"
16 #include "inc/win2003/vsprov.h"
18 #define VSS_TIMEOUT_MSEC (60*1000)
20 static long g_nComObjsInUse;
23 /* VSS common GUID's */
25 const CLSID CLSID_VSSCoordinator = { 0xE579AB5F, 0x1CC4, 0x44b4,
26 {0xBE, 0xD9, 0xDE, 0x09, 0x91, 0xFF, 0x06, 0x23} };
27 const IID IID_IVssAdmin = { 0x77ED5996, 0x2F63, 0x11d3,
28 {0x8A, 0x39, 0x00, 0xC0, 0x4F, 0x72, 0xD8, 0xE3} };
30 const IID IID_IVssHardwareSnapshotProvider = { 0x9593A157, 0x44E9, 0x4344,
31 {0xBB, 0xEB, 0x44, 0xFB, 0xF9, 0xB0, 0x6B, 0x10} };
32 const IID IID_IVssSoftwareSnapshotProvider = { 0x609e123e, 0x2c5a, 0x44d3,
33 {0x8f, 0x01, 0x0b, 0x1d, 0x9a, 0x47, 0xd1, 0xff} };
34 const IID IID_IVssProviderCreateSnapshotSet = { 0x5F894E5B, 0x1E39, 0x4778,
35 {0x8E, 0x23, 0x9A, 0xBA, 0xD9, 0xF0, 0xE0, 0x8C} };
36 const IID IID_IVssProviderNotifications = { 0xE561901F, 0x03A5, 0x4afe,
37 {0x86, 0xD0, 0x72, 0xBA, 0xEE, 0xCE, 0x70, 0x04} };
39 const IID IID_IVssEnumObject = { 0xAE1C7110, 0x2F60, 0x11d3,
40 {0x8A, 0x39, 0x00, 0xC0, 0x4F, 0x72, 0xD8, 0xE3} };
43 void LockModule(BOOL lock)
46 InterlockedIncrement(&g_nComObjsInUse);
48 InterlockedDecrement(&g_nComObjsInUse);
52 /* Empty enumerator for VssObject */
54 class CQGAVSSEnumObject : public IVssEnumObject
57 STDMETHODIMP QueryInterface(REFIID riid, void **ppObj);
58 STDMETHODIMP_(ULONG) AddRef();
59 STDMETHODIMP_(ULONG) Release();
61 /* IVssEnumObject Methods */
63 ULONG celt, VSS_OBJECT_PROP *rgelt, ULONG *pceltFetched);
64 STDMETHODIMP Skip(ULONG celt);
65 STDMETHODIMP Reset(void);
66 STDMETHODIMP Clone(IVssEnumObject **ppenum);
68 /* CQGAVSSEnumObject Methods */
76 CQGAVSSEnumObject::CQGAVSSEnumObject()
82 CQGAVSSEnumObject::~CQGAVSSEnumObject()
87 STDMETHODIMP CQGAVSSEnumObject::QueryInterface(REFIID riid, void **ppObj)
89 if (riid == IID_IUnknown || riid == IID_IVssEnumObject) {
90 *ppObj = static_cast<void*>(static_cast<IVssEnumObject*>(this));
98 STDMETHODIMP_(ULONG) CQGAVSSEnumObject::AddRef()
100 return InterlockedIncrement(&m_nRefCount);
103 STDMETHODIMP_(ULONG) CQGAVSSEnumObject::Release()
105 long nRefCount = InterlockedDecrement(&m_nRefCount);
106 if (m_nRefCount == 0) {
112 STDMETHODIMP CQGAVSSEnumObject::Next(
113 ULONG celt, VSS_OBJECT_PROP *rgelt, ULONG *pceltFetched)
119 STDMETHODIMP CQGAVSSEnumObject::Skip(ULONG celt)
124 STDMETHODIMP CQGAVSSEnumObject::Reset(void)
129 STDMETHODIMP CQGAVSSEnumObject::Clone(IVssEnumObject **ppenum)
137 class CQGAVssProvider :
138 public IVssSoftwareSnapshotProvider,
139 public IVssProviderCreateSnapshotSet,
140 public IVssProviderNotifications
143 STDMETHODIMP QueryInterface(REFIID riid, void **ppObj);
144 STDMETHODIMP_(ULONG) AddRef();
145 STDMETHODIMP_(ULONG) Release();
147 /* IVssSoftwareSnapshotProvider Methods */
148 STDMETHODIMP SetContext(LONG lContext);
149 STDMETHODIMP GetSnapshotProperties(
150 VSS_ID SnapshotId, VSS_SNAPSHOT_PROP *pProp);
152 VSS_ID QueriedObjectId, VSS_OBJECT_TYPE eQueriedObjectType,
153 VSS_OBJECT_TYPE eReturnedObjectsType, IVssEnumObject **ppEnum);
154 STDMETHODIMP DeleteSnapshots(
155 VSS_ID SourceObjectId, VSS_OBJECT_TYPE eSourceObjectType,
156 BOOL bForceDelete, LONG *plDeletedSnapshots,
157 VSS_ID *pNondeletedSnapshotID);
158 STDMETHODIMP BeginPrepareSnapshot(
159 VSS_ID SnapshotSetId, VSS_ID SnapshotId,
160 VSS_PWSZ pwszVolumeName, LONG lNewContext);
161 STDMETHODIMP IsVolumeSupported(
162 VSS_PWSZ pwszVolumeName, BOOL *pbSupportedByThisProvider);
163 STDMETHODIMP IsVolumeSnapshotted(
164 VSS_PWSZ pwszVolumeName, BOOL *pbSnapshotsPresent,
165 LONG *plSnapshotCompatibility);
166 STDMETHODIMP SetSnapshotProperty(
167 VSS_ID SnapshotId, VSS_SNAPSHOT_PROPERTY_ID eSnapshotPropertyId,
169 STDMETHODIMP RevertToSnapshot(VSS_ID SnapshotId);
170 STDMETHODIMP QueryRevertStatus(VSS_PWSZ pwszVolume, IVssAsync **ppAsync);
172 /* IVssProviderCreateSnapshotSet Methods */
173 STDMETHODIMP EndPrepareSnapshots(VSS_ID SnapshotSetId);
174 STDMETHODIMP PreCommitSnapshots(VSS_ID SnapshotSetId);
175 STDMETHODIMP CommitSnapshots(VSS_ID SnapshotSetId);
176 STDMETHODIMP PostCommitSnapshots(
177 VSS_ID SnapshotSetId, LONG lSnapshotsCount);
178 STDMETHODIMP PreFinalCommitSnapshots(VSS_ID SnapshotSetId);
179 STDMETHODIMP PostFinalCommitSnapshots(VSS_ID SnapshotSetId);
180 STDMETHODIMP AbortSnapshots(VSS_ID SnapshotSetId);
182 /* IVssProviderNotifications Methods */
183 STDMETHODIMP OnLoad(IUnknown *pCallback);
184 STDMETHODIMP OnUnload(BOOL bForceUnload);
186 /* CQGAVssProvider Methods */
194 CQGAVssProvider::CQGAVssProvider()
200 CQGAVssProvider::~CQGAVssProvider()
205 STDMETHODIMP CQGAVssProvider::QueryInterface(REFIID riid, void **ppObj)
207 if (riid == IID_IUnknown) {
208 *ppObj = static_cast<void*>(this);
212 if (riid == IID_IVssSoftwareSnapshotProvider) {
213 *ppObj = static_cast<void*>(
214 static_cast<IVssSoftwareSnapshotProvider*>(this));
218 if (riid == IID_IVssProviderCreateSnapshotSet) {
219 *ppObj = static_cast<void*>(
220 static_cast<IVssProviderCreateSnapshotSet*>(this));
224 if (riid == IID_IVssProviderNotifications) {
225 *ppObj = static_cast<void*>(
226 static_cast<IVssProviderNotifications*>(this));
231 return E_NOINTERFACE;
234 STDMETHODIMP_(ULONG) CQGAVssProvider::AddRef()
236 return InterlockedIncrement(&m_nRefCount);
239 STDMETHODIMP_(ULONG) CQGAVssProvider::Release()
241 long nRefCount = InterlockedDecrement(&m_nRefCount);
242 if (m_nRefCount == 0) {
250 * IVssSoftwareSnapshotProvider methods
253 STDMETHODIMP CQGAVssProvider::SetContext(LONG lContext)
258 STDMETHODIMP CQGAVssProvider::GetSnapshotProperties(
259 VSS_ID SnapshotId, VSS_SNAPSHOT_PROP *pProp)
261 return VSS_E_OBJECT_NOT_FOUND;
264 STDMETHODIMP CQGAVssProvider::Query(
265 VSS_ID QueriedObjectId, VSS_OBJECT_TYPE eQueriedObjectType,
266 VSS_OBJECT_TYPE eReturnedObjectsType, IVssEnumObject **ppEnum)
269 *ppEnum = new CQGAVSSEnumObject;
271 return E_OUTOFMEMORY;
277 STDMETHODIMP CQGAVssProvider::DeleteSnapshots(
278 VSS_ID SourceObjectId, VSS_OBJECT_TYPE eSourceObjectType,
279 BOOL bForceDelete, LONG *plDeletedSnapshots, VSS_ID *pNondeletedSnapshotID)
281 *plDeletedSnapshots = 0;
282 *pNondeletedSnapshotID = SourceObjectId;
286 STDMETHODIMP CQGAVssProvider::BeginPrepareSnapshot(
287 VSS_ID SnapshotSetId, VSS_ID SnapshotId,
288 VSS_PWSZ pwszVolumeName, LONG lNewContext)
293 STDMETHODIMP CQGAVssProvider::IsVolumeSupported(
294 VSS_PWSZ pwszVolumeName, BOOL *pbSupportedByThisProvider)
298 /* Check if a requester is qemu-ga by whether an event is created */
299 hEventFrozen = OpenEvent(EVENT_ALL_ACCESS, FALSE, EVENT_NAME_FROZEN);
301 *pbSupportedByThisProvider = FALSE;
304 CloseHandle(hEventFrozen);
306 *pbSupportedByThisProvider = TRUE;
310 STDMETHODIMP CQGAVssProvider::IsVolumeSnapshotted(VSS_PWSZ pwszVolumeName,
311 BOOL *pbSnapshotsPresent, LONG *plSnapshotCompatibility)
313 *pbSnapshotsPresent = FALSE;
314 *plSnapshotCompatibility = 0;
318 STDMETHODIMP CQGAVssProvider::SetSnapshotProperty(VSS_ID SnapshotId,
319 VSS_SNAPSHOT_PROPERTY_ID eSnapshotPropertyId, VARIANT vProperty)
324 STDMETHODIMP CQGAVssProvider::RevertToSnapshot(VSS_ID SnapshotId)
329 STDMETHODIMP CQGAVssProvider::QueryRevertStatus(
330 VSS_PWSZ pwszVolume, IVssAsync **ppAsync)
337 * IVssProviderCreateSnapshotSet methods
340 STDMETHODIMP CQGAVssProvider::EndPrepareSnapshots(VSS_ID SnapshotSetId)
345 STDMETHODIMP CQGAVssProvider::PreCommitSnapshots(VSS_ID SnapshotSetId)
350 STDMETHODIMP CQGAVssProvider::CommitSnapshots(VSS_ID SnapshotSetId)
353 HANDLE hEventFrozen, hEventThaw, hEventTimeout;
355 hEventFrozen = OpenEvent(EVENT_ALL_ACCESS, FALSE, EVENT_NAME_FROZEN);
360 hEventThaw = OpenEvent(EVENT_ALL_ACCESS, FALSE, EVENT_NAME_THAW);
362 CloseHandle(hEventFrozen);
366 hEventTimeout = OpenEvent(EVENT_ALL_ACCESS, FALSE, EVENT_NAME_TIMEOUT);
367 if (!hEventTimeout) {
368 CloseHandle(hEventFrozen);
369 CloseHandle(hEventThaw);
373 /* Send event to qemu-ga to notify filesystem is frozen */
374 SetEvent(hEventFrozen);
376 /* Wait until the snapshot is taken by the host. */
377 if (WaitForSingleObject(hEventThaw, VSS_TIMEOUT_MSEC) != WAIT_OBJECT_0) {
378 /* Send event to qemu-ga to notify the provider is timed out */
379 SetEvent(hEventTimeout);
383 CloseHandle(hEventThaw);
384 CloseHandle(hEventFrozen);
385 CloseHandle(hEventTimeout);
389 STDMETHODIMP CQGAVssProvider::PostCommitSnapshots(
390 VSS_ID SnapshotSetId, LONG lSnapshotsCount)
395 STDMETHODIMP CQGAVssProvider::PreFinalCommitSnapshots(VSS_ID SnapshotSetId)
400 STDMETHODIMP CQGAVssProvider::PostFinalCommitSnapshots(VSS_ID SnapshotSetId)
405 STDMETHODIMP CQGAVssProvider::AbortSnapshots(VSS_ID SnapshotSetId)
411 * IVssProviderNotifications methods
414 STDMETHODIMP CQGAVssProvider::OnLoad(IUnknown *pCallback)
419 STDMETHODIMP CQGAVssProvider::OnUnload(BOOL bForceUnload)
426 * CQGAVssProviderFactory class
429 class CQGAVssProviderFactory : public IClassFactory
432 STDMETHODIMP QueryInterface(REFIID riid, void **ppv);
433 STDMETHODIMP_(ULONG) AddRef();
434 STDMETHODIMP_(ULONG) Release();
435 STDMETHODIMP CreateInstance(
436 IUnknown *pUnknownOuter, REFIID iid, void **ppv);
437 STDMETHODIMP LockServer(BOOL lock) { return E_NOTIMPL; }
439 CQGAVssProviderFactory();
440 ~CQGAVssProviderFactory();
446 CQGAVssProviderFactory::CQGAVssProviderFactory()
452 CQGAVssProviderFactory::~CQGAVssProviderFactory()
457 STDMETHODIMP CQGAVssProviderFactory::QueryInterface(REFIID riid, void **ppv)
459 if (riid == IID_IUnknown || riid == IID_IClassFactory) {
460 *ppv = static_cast<void*>(this);
465 return E_NOINTERFACE;
468 STDMETHODIMP_(ULONG) CQGAVssProviderFactory::AddRef()
470 return InterlockedIncrement(&m_nRefCount);
473 STDMETHODIMP_(ULONG) CQGAVssProviderFactory::Release()
475 long nRefCount = InterlockedDecrement(&m_nRefCount);
476 if (m_nRefCount == 0) {
482 STDMETHODIMP CQGAVssProviderFactory::CreateInstance(
483 IUnknown *pUnknownOuter, REFIID iid, void **ppv)
485 CQGAVssProvider *pObj;
488 return CLASS_E_NOAGGREGATION;
491 pObj = new CQGAVssProvider;
493 return E_OUTOFMEMORY;
495 HRESULT hr = pObj->QueryInterface(iid, ppv);
507 STDAPI DllGetClassObject(REFCLSID rclsid, REFIID riid, LPVOID *ppv)
509 CQGAVssProviderFactory *factory;
511 factory = new CQGAVssProviderFactory;
513 return E_OUTOFMEMORY;
516 HRESULT hr = factory->QueryInterface(riid, ppv);
521 STDAPI DllCanUnloadNow()
523 return g_nComObjsInUse == 0 ? S_OK : S_FALSE;
527 BOOL WINAPI DllMain(HINSTANCE hinstDll, DWORD dwReason, LPVOID lpReserved)
529 if (dwReason == DLL_PROCESS_ATTACH) {
530 g_hinstDll = hinstDll;
531 DisableThreadLibraryCalls(hinstDll);