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 "vss-debug.h"
17 #include <vscoordint.h>
23 #define VSS_TIMEOUT_MSEC (60*1000)
25 static long g_nComObjsInUse
;
28 /* VSS common GUID's */
30 const CLSID CLSID_VSSCoordinator
= { 0xE579AB5F, 0x1CC4, 0x44b4,
31 {0xBE, 0xD9, 0xDE, 0x09, 0x91, 0xFF, 0x06, 0x23} };
32 const IID IID_IVssAdmin
= { 0x77ED5996, 0x2F63, 0x11d3,
33 {0x8A, 0x39, 0x00, 0xC0, 0x4F, 0x72, 0xD8, 0xE3} };
35 const IID IID_IVssHardwareSnapshotProvider
= { 0x9593A157, 0x44E9, 0x4344,
36 {0xBB, 0xEB, 0x44, 0xFB, 0xF9, 0xB0, 0x6B, 0x10} };
37 const IID IID_IVssSoftwareSnapshotProvider
= { 0x609e123e, 0x2c5a, 0x44d3,
38 {0x8f, 0x01, 0x0b, 0x1d, 0x9a, 0x47, 0xd1, 0xff} };
39 const IID IID_IVssProviderCreateSnapshotSet
= { 0x5F894E5B, 0x1E39, 0x4778,
40 {0x8E, 0x23, 0x9A, 0xBA, 0xD9, 0xF0, 0xE0, 0x8C} };
41 const IID IID_IVssProviderNotifications
= { 0xE561901F, 0x03A5, 0x4afe,
42 {0x86, 0xD0, 0x72, 0xBA, 0xEE, 0xCE, 0x70, 0x04} };
44 const IID IID_IVssEnumObject
= { 0xAE1C7110, 0x2F60, 0x11d3,
45 {0x8A, 0x39, 0x00, 0xC0, 0x4F, 0x72, 0xD8, 0xE3} };
48 void LockModule(BOOL lock
)
51 InterlockedIncrement(&g_nComObjsInUse
);
53 InterlockedDecrement(&g_nComObjsInUse
);
57 /* Empty enumerator for VssObject */
59 class CQGAVSSEnumObject
: public IVssEnumObject
62 STDMETHODIMP
QueryInterface(REFIID riid
, void **ppObj
);
63 STDMETHODIMP_(ULONG
) AddRef();
64 STDMETHODIMP_(ULONG
) Release();
66 /* IVssEnumObject Methods */
68 ULONG celt
, VSS_OBJECT_PROP
*rgelt
, ULONG
*pceltFetched
);
69 STDMETHODIMP
Skip(ULONG celt
);
70 STDMETHODIMP
Reset(void);
71 STDMETHODIMP
Clone(IVssEnumObject
**ppenum
);
73 /* CQGAVSSEnumObject Methods */
81 CQGAVSSEnumObject::CQGAVSSEnumObject()
87 CQGAVSSEnumObject::~CQGAVSSEnumObject()
92 STDMETHODIMP
CQGAVSSEnumObject::QueryInterface(REFIID riid
, void **ppObj
)
94 if (riid
== IID_IUnknown
|| riid
== IID_IVssEnumObject
) {
95 *ppObj
= static_cast<void*>(static_cast<IVssEnumObject
*>(this));
100 return E_NOINTERFACE
;
103 STDMETHODIMP_(ULONG
) CQGAVSSEnumObject::AddRef()
105 return InterlockedIncrement(&m_nRefCount
);
108 STDMETHODIMP_(ULONG
) CQGAVSSEnumObject::Release()
110 long nRefCount
= InterlockedDecrement(&m_nRefCount
);
111 if (m_nRefCount
== 0) {
117 STDMETHODIMP
CQGAVSSEnumObject::Next(
118 ULONG celt
, VSS_OBJECT_PROP
*rgelt
, ULONG
*pceltFetched
)
124 STDMETHODIMP
CQGAVSSEnumObject::Skip(ULONG celt
)
129 STDMETHODIMP
CQGAVSSEnumObject::Reset(void)
134 STDMETHODIMP
CQGAVSSEnumObject::Clone(IVssEnumObject
**ppenum
)
142 class CQGAVssProvider
:
143 public IVssSoftwareSnapshotProvider
,
144 public IVssProviderCreateSnapshotSet
,
145 public IVssProviderNotifications
148 STDMETHODIMP
QueryInterface(REFIID riid
, void **ppObj
);
149 STDMETHODIMP_(ULONG
) AddRef();
150 STDMETHODIMP_(ULONG
) Release();
152 /* IVssSoftwareSnapshotProvider Methods */
153 STDMETHODIMP
SetContext(LONG lContext
);
154 STDMETHODIMP
GetSnapshotProperties(
155 VSS_ID SnapshotId
, VSS_SNAPSHOT_PROP
*pProp
);
157 VSS_ID QueriedObjectId
, VSS_OBJECT_TYPE eQueriedObjectType
,
158 VSS_OBJECT_TYPE eReturnedObjectsType
, IVssEnumObject
**ppEnum
);
159 STDMETHODIMP
DeleteSnapshots(
160 VSS_ID SourceObjectId
, VSS_OBJECT_TYPE eSourceObjectType
,
161 BOOL bForceDelete
, LONG
*plDeletedSnapshots
,
162 VSS_ID
*pNondeletedSnapshotID
);
163 STDMETHODIMP
BeginPrepareSnapshot(
164 VSS_ID SnapshotSetId
, VSS_ID SnapshotId
,
165 VSS_PWSZ pwszVolumeName
, LONG lNewContext
);
166 STDMETHODIMP
IsVolumeSupported(
167 VSS_PWSZ pwszVolumeName
, BOOL
*pbSupportedByThisProvider
);
168 STDMETHODIMP
IsVolumeSnapshotted(
169 VSS_PWSZ pwszVolumeName
, BOOL
*pbSnapshotsPresent
,
170 LONG
*plSnapshotCompatibility
);
171 STDMETHODIMP
SetSnapshotProperty(
172 VSS_ID SnapshotId
, VSS_SNAPSHOT_PROPERTY_ID eSnapshotPropertyId
,
174 STDMETHODIMP
RevertToSnapshot(VSS_ID SnapshotId
);
175 STDMETHODIMP
QueryRevertStatus(VSS_PWSZ pwszVolume
, IVssAsync
**ppAsync
);
177 /* IVssProviderCreateSnapshotSet Methods */
178 STDMETHODIMP
EndPrepareSnapshots(VSS_ID SnapshotSetId
);
179 STDMETHODIMP
PreCommitSnapshots(VSS_ID SnapshotSetId
);
180 STDMETHODIMP
CommitSnapshots(VSS_ID SnapshotSetId
);
181 STDMETHODIMP
PostCommitSnapshots(
182 VSS_ID SnapshotSetId
, LONG lSnapshotsCount
);
183 STDMETHODIMP
PreFinalCommitSnapshots(VSS_ID SnapshotSetId
);
184 STDMETHODIMP
PostFinalCommitSnapshots(VSS_ID SnapshotSetId
);
185 STDMETHODIMP
AbortSnapshots(VSS_ID SnapshotSetId
);
187 /* IVssProviderNotifications Methods */
188 STDMETHODIMP
OnLoad(IUnknown
*pCallback
);
189 STDMETHODIMP
OnUnload(BOOL bForceUnload
);
191 /* CQGAVssProvider Methods */
199 CQGAVssProvider::CQGAVssProvider()
205 CQGAVssProvider::~CQGAVssProvider()
210 STDMETHODIMP
CQGAVssProvider::QueryInterface(REFIID riid
, void **ppObj
)
212 if (riid
== IID_IUnknown
) {
213 *ppObj
= static_cast<void*>(this);
217 if (riid
== IID_IVssSoftwareSnapshotProvider
) {
218 *ppObj
= static_cast<void*>(
219 static_cast<IVssSoftwareSnapshotProvider
*>(this));
223 if (riid
== IID_IVssProviderCreateSnapshotSet
) {
224 *ppObj
= static_cast<void*>(
225 static_cast<IVssProviderCreateSnapshotSet
*>(this));
229 if (riid
== IID_IVssProviderNotifications
) {
230 *ppObj
= static_cast<void*>(
231 static_cast<IVssProviderNotifications
*>(this));
236 return E_NOINTERFACE
;
239 STDMETHODIMP_(ULONG
) CQGAVssProvider::AddRef()
241 return InterlockedIncrement(&m_nRefCount
);
244 STDMETHODIMP_(ULONG
) CQGAVssProvider::Release()
246 long nRefCount
= InterlockedDecrement(&m_nRefCount
);
247 if (m_nRefCount
== 0) {
255 * IVssSoftwareSnapshotProvider methods
258 STDMETHODIMP
CQGAVssProvider::SetContext(LONG lContext
)
263 STDMETHODIMP
CQGAVssProvider::GetSnapshotProperties(
264 VSS_ID SnapshotId
, VSS_SNAPSHOT_PROP
*pProp
)
266 return VSS_E_OBJECT_NOT_FOUND
;
269 STDMETHODIMP
CQGAVssProvider::Query(
270 VSS_ID QueriedObjectId
, VSS_OBJECT_TYPE eQueriedObjectType
,
271 VSS_OBJECT_TYPE eReturnedObjectsType
, IVssEnumObject
**ppEnum
)
274 *ppEnum
= new CQGAVSSEnumObject
;
276 return E_OUTOFMEMORY
;
282 STDMETHODIMP
CQGAVssProvider::DeleteSnapshots(
283 VSS_ID SourceObjectId
, VSS_OBJECT_TYPE eSourceObjectType
,
284 BOOL bForceDelete
, LONG
*plDeletedSnapshots
, VSS_ID
*pNondeletedSnapshotID
)
286 *plDeletedSnapshots
= 0;
287 *pNondeletedSnapshotID
= SourceObjectId
;
291 STDMETHODIMP
CQGAVssProvider::BeginPrepareSnapshot(
292 VSS_ID SnapshotSetId
, VSS_ID SnapshotId
,
293 VSS_PWSZ pwszVolumeName
, LONG lNewContext
)
298 STDMETHODIMP
CQGAVssProvider::IsVolumeSupported(
299 VSS_PWSZ pwszVolumeName
, BOOL
*pbSupportedByThisProvider
)
303 /* Check if a requester is qemu-ga by whether an event is created */
304 hEventFrozen
= OpenEvent(EVENT_ALL_ACCESS
, FALSE
, EVENT_NAME_FROZEN
);
306 *pbSupportedByThisProvider
= FALSE
;
309 CloseHandle(hEventFrozen
);
311 *pbSupportedByThisProvider
= TRUE
;
315 STDMETHODIMP
CQGAVssProvider::IsVolumeSnapshotted(VSS_PWSZ pwszVolumeName
,
316 BOOL
*pbSnapshotsPresent
, LONG
*plSnapshotCompatibility
)
318 *pbSnapshotsPresent
= FALSE
;
319 *plSnapshotCompatibility
= 0;
323 STDMETHODIMP
CQGAVssProvider::SetSnapshotProperty(VSS_ID SnapshotId
,
324 VSS_SNAPSHOT_PROPERTY_ID eSnapshotPropertyId
, VARIANT vProperty
)
329 STDMETHODIMP
CQGAVssProvider::RevertToSnapshot(VSS_ID SnapshotId
)
334 STDMETHODIMP
CQGAVssProvider::QueryRevertStatus(
335 VSS_PWSZ pwszVolume
, IVssAsync
**ppAsync
)
342 * IVssProviderCreateSnapshotSet methods
345 STDMETHODIMP
CQGAVssProvider::EndPrepareSnapshots(VSS_ID SnapshotSetId
)
350 STDMETHODIMP
CQGAVssProvider::PreCommitSnapshots(VSS_ID SnapshotSetId
)
355 STDMETHODIMP
CQGAVssProvider::CommitSnapshots(VSS_ID SnapshotSetId
)
358 HANDLE hEventFrozen
, hEventThaw
, hEventTimeout
;
360 hEventFrozen
= OpenEvent(EVENT_ALL_ACCESS
, FALSE
, EVENT_NAME_FROZEN
);
365 hEventThaw
= OpenEvent(EVENT_ALL_ACCESS
, FALSE
, EVENT_NAME_THAW
);
367 CloseHandle(hEventFrozen
);
371 hEventTimeout
= OpenEvent(EVENT_ALL_ACCESS
, FALSE
, EVENT_NAME_TIMEOUT
);
372 if (!hEventTimeout
) {
373 CloseHandle(hEventFrozen
);
374 CloseHandle(hEventThaw
);
378 /* Send event to qemu-ga to notify filesystem is frozen */
379 SetEvent(hEventFrozen
);
381 /* Wait until the snapshot is taken by the host. */
382 if (WaitForSingleObject(hEventThaw
, VSS_TIMEOUT_MSEC
) != WAIT_OBJECT_0
) {
383 /* Send event to qemu-ga to notify the provider is timed out */
384 SetEvent(hEventTimeout
);
387 CloseHandle(hEventThaw
);
388 CloseHandle(hEventFrozen
);
389 CloseHandle(hEventTimeout
);
393 STDMETHODIMP
CQGAVssProvider::PostCommitSnapshots(
394 VSS_ID SnapshotSetId
, LONG lSnapshotsCount
)
399 STDMETHODIMP
CQGAVssProvider::PreFinalCommitSnapshots(VSS_ID SnapshotSetId
)
404 STDMETHODIMP
CQGAVssProvider::PostFinalCommitSnapshots(VSS_ID SnapshotSetId
)
409 STDMETHODIMP
CQGAVssProvider::AbortSnapshots(VSS_ID SnapshotSetId
)
415 * IVssProviderNotifications methods
418 STDMETHODIMP
CQGAVssProvider::OnLoad(IUnknown
*pCallback
)
423 STDMETHODIMP
CQGAVssProvider::OnUnload(BOOL bForceUnload
)
430 * CQGAVssProviderFactory class
433 class CQGAVssProviderFactory
: public IClassFactory
436 STDMETHODIMP
QueryInterface(REFIID riid
, void **ppv
);
437 STDMETHODIMP_(ULONG
) AddRef();
438 STDMETHODIMP_(ULONG
) Release();
439 STDMETHODIMP
CreateInstance(
440 IUnknown
*pUnknownOuter
, REFIID iid
, void **ppv
);
441 STDMETHODIMP
LockServer(BOOL lock
) { return E_NOTIMPL
; }
443 CQGAVssProviderFactory();
444 ~CQGAVssProviderFactory();
450 CQGAVssProviderFactory::CQGAVssProviderFactory()
456 CQGAVssProviderFactory::~CQGAVssProviderFactory()
461 STDMETHODIMP
CQGAVssProviderFactory::QueryInterface(REFIID riid
, void **ppv
)
463 if (riid
== IID_IUnknown
|| riid
== IID_IClassFactory
) {
464 *ppv
= static_cast<void*>(this);
469 return E_NOINTERFACE
;
472 STDMETHODIMP_(ULONG
) CQGAVssProviderFactory::AddRef()
474 return InterlockedIncrement(&m_nRefCount
);
477 STDMETHODIMP_(ULONG
) CQGAVssProviderFactory::Release()
479 long nRefCount
= InterlockedDecrement(&m_nRefCount
);
480 if (m_nRefCount
== 0) {
486 STDMETHODIMP
CQGAVssProviderFactory::CreateInstance(
487 IUnknown
*pUnknownOuter
, REFIID iid
, void **ppv
)
489 CQGAVssProvider
*pObj
;
492 return CLASS_E_NOAGGREGATION
;
495 pObj
= new CQGAVssProvider
;
497 return E_OUTOFMEMORY
;
499 HRESULT hr
= pObj
->QueryInterface(iid
, ppv
);
511 STDAPI
DllGetClassObject(REFCLSID rclsid
, REFIID riid
, LPVOID
*ppv
)
513 CQGAVssProviderFactory
*factory
;
515 factory
= new CQGAVssProviderFactory
;
517 return E_OUTOFMEMORY
;
520 HRESULT hr
= factory
->QueryInterface(riid
, ppv
);
525 STDAPI
DllCanUnloadNow()
527 return g_nComObjsInUse
== 0 ? S_OK
: S_FALSE
;
531 BOOL WINAPI
DllMain(HINSTANCE hinstDll
, DWORD dwReason
, LPVOID lpReserved
)
533 qga_debug("begin, reason = %lu", dwReason
);
534 if (dwReason
== DLL_PROCESS_ATTACH
) {
535 g_hinstDll
= hinstDll
;
536 DisableThreadLibraryCalls(hinstDll
);