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"
16 #include <vscoordint.h>
22 #define VSS_TIMEOUT_MSEC (60*1000)
24 static long g_nComObjsInUse
;
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
)
50 InterlockedIncrement(&g_nComObjsInUse
);
52 InterlockedDecrement(&g_nComObjsInUse
);
56 /* Empty enumerator for VssObject */
58 class CQGAVSSEnumObject
: public IVssEnumObject
61 STDMETHODIMP
QueryInterface(REFIID riid
, void **ppObj
);
62 STDMETHODIMP_(ULONG
) AddRef();
63 STDMETHODIMP_(ULONG
) Release();
65 /* IVssEnumObject Methods */
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 */
80 CQGAVSSEnumObject::CQGAVSSEnumObject()
86 CQGAVSSEnumObject::~CQGAVSSEnumObject()
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));
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) {
116 STDMETHODIMP
CQGAVSSEnumObject::Next(
117 ULONG celt
, VSS_OBJECT_PROP
*rgelt
, ULONG
*pceltFetched
)
123 STDMETHODIMP
CQGAVSSEnumObject::Skip(ULONG celt
)
128 STDMETHODIMP
CQGAVSSEnumObject::Reset(void)
133 STDMETHODIMP
CQGAVSSEnumObject::Clone(IVssEnumObject
**ppenum
)
141 class CQGAVssProvider
:
142 public IVssSoftwareSnapshotProvider
,
143 public IVssProviderCreateSnapshotSet
,
144 public IVssProviderNotifications
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
);
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
,
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 */
198 CQGAVssProvider::CQGAVssProvider()
204 CQGAVssProvider::~CQGAVssProvider()
209 STDMETHODIMP
CQGAVssProvider::QueryInterface(REFIID riid
, void **ppObj
)
211 if (riid
== IID_IUnknown
) {
212 *ppObj
= static_cast<void*>(this);
216 if (riid
== IID_IVssSoftwareSnapshotProvider
) {
217 *ppObj
= static_cast<void*>(
218 static_cast<IVssSoftwareSnapshotProvider
*>(this));
222 if (riid
== IID_IVssProviderCreateSnapshotSet
) {
223 *ppObj
= static_cast<void*>(
224 static_cast<IVssProviderCreateSnapshotSet
*>(this));
228 if (riid
== IID_IVssProviderNotifications
) {
229 *ppObj
= static_cast<void*>(
230 static_cast<IVssProviderNotifications
*>(this));
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) {
254 * IVssSoftwareSnapshotProvider methods
257 STDMETHODIMP
CQGAVssProvider::SetContext(LONG lContext
)
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
)
273 *ppEnum
= new CQGAVSSEnumObject
;
275 return E_OUTOFMEMORY
;
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
;
290 STDMETHODIMP
CQGAVssProvider::BeginPrepareSnapshot(
291 VSS_ID SnapshotSetId
, VSS_ID SnapshotId
,
292 VSS_PWSZ pwszVolumeName
, LONG lNewContext
)
297 STDMETHODIMP
CQGAVssProvider::IsVolumeSupported(
298 VSS_PWSZ pwszVolumeName
, BOOL
*pbSupportedByThisProvider
)
302 /* Check if a requester is qemu-ga by whether an event is created */
303 hEventFrozen
= OpenEvent(EVENT_ALL_ACCESS
, FALSE
, EVENT_NAME_FROZEN
);
305 *pbSupportedByThisProvider
= FALSE
;
308 CloseHandle(hEventFrozen
);
310 *pbSupportedByThisProvider
= TRUE
;
314 STDMETHODIMP
CQGAVssProvider::IsVolumeSnapshotted(VSS_PWSZ pwszVolumeName
,
315 BOOL
*pbSnapshotsPresent
, LONG
*plSnapshotCompatibility
)
317 *pbSnapshotsPresent
= FALSE
;
318 *plSnapshotCompatibility
= 0;
322 STDMETHODIMP
CQGAVssProvider::SetSnapshotProperty(VSS_ID SnapshotId
,
323 VSS_SNAPSHOT_PROPERTY_ID eSnapshotPropertyId
, VARIANT vProperty
)
328 STDMETHODIMP
CQGAVssProvider::RevertToSnapshot(VSS_ID SnapshotId
)
333 STDMETHODIMP
CQGAVssProvider::QueryRevertStatus(
334 VSS_PWSZ pwszVolume
, IVssAsync
**ppAsync
)
341 * IVssProviderCreateSnapshotSet methods
344 STDMETHODIMP
CQGAVssProvider::EndPrepareSnapshots(VSS_ID SnapshotSetId
)
349 STDMETHODIMP
CQGAVssProvider::PreCommitSnapshots(VSS_ID SnapshotSetId
)
354 STDMETHODIMP
CQGAVssProvider::CommitSnapshots(VSS_ID SnapshotSetId
)
357 HANDLE hEventFrozen
, hEventThaw
, hEventTimeout
;
359 hEventFrozen
= OpenEvent(EVENT_ALL_ACCESS
, FALSE
, EVENT_NAME_FROZEN
);
364 hEventThaw
= OpenEvent(EVENT_ALL_ACCESS
, FALSE
, EVENT_NAME_THAW
);
366 CloseHandle(hEventFrozen
);
370 hEventTimeout
= OpenEvent(EVENT_ALL_ACCESS
, FALSE
, EVENT_NAME_TIMEOUT
);
371 if (!hEventTimeout
) {
372 CloseHandle(hEventFrozen
);
373 CloseHandle(hEventThaw
);
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
);
392 STDMETHODIMP
CQGAVssProvider::PostCommitSnapshots(
393 VSS_ID SnapshotSetId
, LONG lSnapshotsCount
)
398 STDMETHODIMP
CQGAVssProvider::PreFinalCommitSnapshots(VSS_ID SnapshotSetId
)
403 STDMETHODIMP
CQGAVssProvider::PostFinalCommitSnapshots(VSS_ID SnapshotSetId
)
408 STDMETHODIMP
CQGAVssProvider::AbortSnapshots(VSS_ID SnapshotSetId
)
414 * IVssProviderNotifications methods
417 STDMETHODIMP
CQGAVssProvider::OnLoad(IUnknown
*pCallback
)
422 STDMETHODIMP
CQGAVssProvider::OnUnload(BOOL bForceUnload
)
429 * CQGAVssProviderFactory class
432 class CQGAVssProviderFactory
: public IClassFactory
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();
449 CQGAVssProviderFactory::CQGAVssProviderFactory()
455 CQGAVssProviderFactory::~CQGAVssProviderFactory()
460 STDMETHODIMP
CQGAVssProviderFactory::QueryInterface(REFIID riid
, void **ppv
)
462 if (riid
== IID_IUnknown
|| riid
== IID_IClassFactory
) {
463 *ppv
= static_cast<void*>(this);
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) {
485 STDMETHODIMP
CQGAVssProviderFactory::CreateInstance(
486 IUnknown
*pUnknownOuter
, REFIID iid
, void **ppv
)
488 CQGAVssProvider
*pObj
;
491 return CLASS_E_NOAGGREGATION
;
494 pObj
= new CQGAVssProvider
;
496 return E_OUTOFMEMORY
;
498 HRESULT hr
= pObj
->QueryInterface(iid
, ppv
);
510 STDAPI
DllGetClassObject(REFCLSID rclsid
, REFIID riid
, LPVOID
*ppv
)
512 CQGAVssProviderFactory
*factory
;
514 factory
= new CQGAVssProviderFactory
;
516 return E_OUTOFMEMORY
;
519 HRESULT hr
= factory
->QueryInterface(riid
, ppv
);
524 STDAPI
DllCanUnloadNow()
526 return g_nComObjsInUse
== 0 ? S_OK
: S_FALSE
;
530 BOOL WINAPI
DllMain(HINSTANCE hinstDll
, DWORD dwReason
, LPVOID lpReserved
)
532 if (dwReason
== DLL_PROCESS_ATTACH
) {
533 g_hinstDll
= hinstDll
;
534 DisableThreadLibraryCalls(hinstDll
);