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
);