root / qga / vss-win32 / provider.cpp @ 4c1b8f1e
History | View | Annotate | Download (12.5 kB)
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 |
|
13 |
#include <stdio.h> |
14 |
#include "vss-common.h" |
15 |
#include "inc/win2003/vscoordint.h" |
16 |
#include "inc/win2003/vsprov.h" |
17 |
|
18 |
#define VSS_TIMEOUT_MSEC (60*1000) |
19 |
|
20 |
static long g_nComObjsInUse; |
21 |
HINSTANCE g_hinstDll; |
22 |
|
23 |
/* VSS common GUID's */
|
24 |
|
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} }; |
29 |
|
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} }; |
38 |
|
39 |
const IID IID_IVssEnumObject = { 0xAE1C7110, 0x2F60, 0x11d3, |
40 |
{0x8A, 0x39, 0x00, 0xC0, 0x4F, 0x72, 0xD8, 0xE3} }; |
41 |
|
42 |
|
43 |
void LockModule(BOOL lock)
|
44 |
{ |
45 |
if (lock) {
|
46 |
InterlockedIncrement(&g_nComObjsInUse); |
47 |
} else {
|
48 |
InterlockedDecrement(&g_nComObjsInUse); |
49 |
} |
50 |
} |
51 |
|
52 |
/* Empty enumerator for VssObject */
|
53 |
|
54 |
class CQGAVSSEnumObject : public IVssEnumObject |
55 |
{ |
56 |
public:
|
57 |
STDMETHODIMP QueryInterface(REFIID riid, void **ppObj);
|
58 |
STDMETHODIMP_(ULONG) AddRef(); |
59 |
STDMETHODIMP_(ULONG) Release(); |
60 |
|
61 |
/* IVssEnumObject Methods */
|
62 |
STDMETHODIMP Next( |
63 |
ULONG celt, VSS_OBJECT_PROP *rgelt, ULONG *pceltFetched); |
64 |
STDMETHODIMP Skip(ULONG celt); |
65 |
STDMETHODIMP Reset(void);
|
66 |
STDMETHODIMP Clone(IVssEnumObject **ppenum); |
67 |
|
68 |
/* CQGAVSSEnumObject Methods */
|
69 |
CQGAVSSEnumObject(); |
70 |
~CQGAVSSEnumObject(); |
71 |
|
72 |
private:
|
73 |
long m_nRefCount;
|
74 |
}; |
75 |
|
76 |
CQGAVSSEnumObject::CQGAVSSEnumObject() |
77 |
{ |
78 |
m_nRefCount = 0;
|
79 |
LockModule(TRUE); |
80 |
} |
81 |
|
82 |
CQGAVSSEnumObject::~CQGAVSSEnumObject() |
83 |
{ |
84 |
LockModule(FALSE); |
85 |
} |
86 |
|
87 |
STDMETHODIMP CQGAVSSEnumObject::QueryInterface(REFIID riid, void **ppObj)
|
88 |
{ |
89 |
if (riid == IID_IUnknown || riid == IID_IVssEnumObject) {
|
90 |
*ppObj = static_cast<void*>(static_cast<IVssEnumObject*>(this)); |
91 |
AddRef(); |
92 |
return S_OK;
|
93 |
} |
94 |
*ppObj = NULL;
|
95 |
return E_NOINTERFACE;
|
96 |
} |
97 |
|
98 |
STDMETHODIMP_(ULONG) CQGAVSSEnumObject::AddRef() |
99 |
{ |
100 |
return InterlockedIncrement(&m_nRefCount);
|
101 |
} |
102 |
|
103 |
STDMETHODIMP_(ULONG) CQGAVSSEnumObject::Release() |
104 |
{ |
105 |
long nRefCount = InterlockedDecrement(&m_nRefCount);
|
106 |
if (m_nRefCount == 0) { |
107 |
delete this; |
108 |
} |
109 |
return nRefCount;
|
110 |
} |
111 |
|
112 |
STDMETHODIMP CQGAVSSEnumObject::Next( |
113 |
ULONG celt, VSS_OBJECT_PROP *rgelt, ULONG *pceltFetched) |
114 |
{ |
115 |
*pceltFetched = 0;
|
116 |
return S_FALSE;
|
117 |
} |
118 |
|
119 |
STDMETHODIMP CQGAVSSEnumObject::Skip(ULONG celt) |
120 |
{ |
121 |
return S_FALSE;
|
122 |
} |
123 |
|
124 |
STDMETHODIMP CQGAVSSEnumObject::Reset(void)
|
125 |
{ |
126 |
return S_OK;
|
127 |
} |
128 |
|
129 |
STDMETHODIMP CQGAVSSEnumObject::Clone(IVssEnumObject **ppenum) |
130 |
{ |
131 |
return E_NOTIMPL;
|
132 |
} |
133 |
|
134 |
|
135 |
/* QGAVssProvider */
|
136 |
|
137 |
class CQGAVssProvider : |
138 |
public IVssSoftwareSnapshotProvider,
|
139 |
public IVssProviderCreateSnapshotSet,
|
140 |
public IVssProviderNotifications
|
141 |
{ |
142 |
public:
|
143 |
STDMETHODIMP QueryInterface(REFIID riid, void **ppObj);
|
144 |
STDMETHODIMP_(ULONG) AddRef(); |
145 |
STDMETHODIMP_(ULONG) Release(); |
146 |
|
147 |
/* IVssSoftwareSnapshotProvider Methods */
|
148 |
STDMETHODIMP SetContext(LONG lContext); |
149 |
STDMETHODIMP GetSnapshotProperties( |
150 |
VSS_ID SnapshotId, VSS_SNAPSHOT_PROP *pProp); |
151 |
STDMETHODIMP Query( |
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, |
168 |
VARIANT vProperty); |
169 |
STDMETHODIMP RevertToSnapshot(VSS_ID SnapshotId); |
170 |
STDMETHODIMP QueryRevertStatus(VSS_PWSZ pwszVolume, IVssAsync **ppAsync); |
171 |
|
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); |
181 |
|
182 |
/* IVssProviderNotifications Methods */
|
183 |
STDMETHODIMP OnLoad(IUnknown *pCallback); |
184 |
STDMETHODIMP OnUnload(BOOL bForceUnload); |
185 |
|
186 |
/* CQGAVssProvider Methods */
|
187 |
CQGAVssProvider(); |
188 |
~CQGAVssProvider(); |
189 |
|
190 |
private:
|
191 |
long m_nRefCount;
|
192 |
}; |
193 |
|
194 |
CQGAVssProvider::CQGAVssProvider() |
195 |
{ |
196 |
m_nRefCount = 0;
|
197 |
LockModule(TRUE); |
198 |
} |
199 |
|
200 |
CQGAVssProvider::~CQGAVssProvider() |
201 |
{ |
202 |
LockModule(FALSE); |
203 |
} |
204 |
|
205 |
STDMETHODIMP CQGAVssProvider::QueryInterface(REFIID riid, void **ppObj)
|
206 |
{ |
207 |
if (riid == IID_IUnknown) {
|
208 |
*ppObj = static_cast<void*>(this); |
209 |
AddRef(); |
210 |
return S_OK;
|
211 |
} |
212 |
if (riid == IID_IVssSoftwareSnapshotProvider) {
|
213 |
*ppObj = static_cast<void*>( |
214 |
static_cast<IVssSoftwareSnapshotProvider*>(this)); |
215 |
AddRef(); |
216 |
return S_OK;
|
217 |
} |
218 |
if (riid == IID_IVssProviderCreateSnapshotSet) {
|
219 |
*ppObj = static_cast<void*>( |
220 |
static_cast<IVssProviderCreateSnapshotSet*>(this)); |
221 |
AddRef(); |
222 |
return S_OK;
|
223 |
} |
224 |
if (riid == IID_IVssProviderNotifications) {
|
225 |
*ppObj = static_cast<void*>( |
226 |
static_cast<IVssProviderNotifications*>(this)); |
227 |
AddRef(); |
228 |
return S_OK;
|
229 |
} |
230 |
*ppObj = NULL;
|
231 |
return E_NOINTERFACE;
|
232 |
} |
233 |
|
234 |
STDMETHODIMP_(ULONG) CQGAVssProvider::AddRef() |
235 |
{ |
236 |
return InterlockedIncrement(&m_nRefCount);
|
237 |
} |
238 |
|
239 |
STDMETHODIMP_(ULONG) CQGAVssProvider::Release() |
240 |
{ |
241 |
long nRefCount = InterlockedDecrement(&m_nRefCount);
|
242 |
if (m_nRefCount == 0) { |
243 |
delete this; |
244 |
} |
245 |
return nRefCount;
|
246 |
} |
247 |
|
248 |
|
249 |
/*
|
250 |
* IVssSoftwareSnapshotProvider methods
|
251 |
*/
|
252 |
|
253 |
STDMETHODIMP CQGAVssProvider::SetContext(LONG lContext) |
254 |
{ |
255 |
return S_OK;
|
256 |
} |
257 |
|
258 |
STDMETHODIMP CQGAVssProvider::GetSnapshotProperties( |
259 |
VSS_ID SnapshotId, VSS_SNAPSHOT_PROP *pProp) |
260 |
{ |
261 |
return VSS_E_OBJECT_NOT_FOUND;
|
262 |
} |
263 |
|
264 |
STDMETHODIMP CQGAVssProvider::Query( |
265 |
VSS_ID QueriedObjectId, VSS_OBJECT_TYPE eQueriedObjectType, |
266 |
VSS_OBJECT_TYPE eReturnedObjectsType, IVssEnumObject **ppEnum) |
267 |
{ |
268 |
try {
|
269 |
*ppEnum = new CQGAVSSEnumObject;
|
270 |
} catch (...) {
|
271 |
return E_OUTOFMEMORY;
|
272 |
} |
273 |
(*ppEnum)->AddRef(); |
274 |
return S_OK;
|
275 |
} |
276 |
|
277 |
STDMETHODIMP CQGAVssProvider::DeleteSnapshots( |
278 |
VSS_ID SourceObjectId, VSS_OBJECT_TYPE eSourceObjectType, |
279 |
BOOL bForceDelete, LONG *plDeletedSnapshots, VSS_ID *pNondeletedSnapshotID) |
280 |
{ |
281 |
return E_NOTIMPL;
|
282 |
} |
283 |
|
284 |
STDMETHODIMP CQGAVssProvider::BeginPrepareSnapshot( |
285 |
VSS_ID SnapshotSetId, VSS_ID SnapshotId, |
286 |
VSS_PWSZ pwszVolumeName, LONG lNewContext) |
287 |
{ |
288 |
return S_OK;
|
289 |
} |
290 |
|
291 |
STDMETHODIMP CQGAVssProvider::IsVolumeSupported( |
292 |
VSS_PWSZ pwszVolumeName, BOOL *pbSupportedByThisProvider) |
293 |
{ |
294 |
*pbSupportedByThisProvider = TRUE; |
295 |
|
296 |
return S_OK;
|
297 |
} |
298 |
|
299 |
STDMETHODIMP CQGAVssProvider::IsVolumeSnapshotted(VSS_PWSZ pwszVolumeName, |
300 |
BOOL *pbSnapshotsPresent, LONG *plSnapshotCompatibility) |
301 |
{ |
302 |
*pbSnapshotsPresent = FALSE; |
303 |
*plSnapshotCompatibility = 0;
|
304 |
return S_OK;
|
305 |
} |
306 |
|
307 |
STDMETHODIMP CQGAVssProvider::SetSnapshotProperty(VSS_ID SnapshotId, |
308 |
VSS_SNAPSHOT_PROPERTY_ID eSnapshotPropertyId, VARIANT vProperty) |
309 |
{ |
310 |
return E_NOTIMPL;
|
311 |
} |
312 |
|
313 |
STDMETHODIMP CQGAVssProvider::RevertToSnapshot(VSS_ID SnapshotId) |
314 |
{ |
315 |
return E_NOTIMPL;
|
316 |
} |
317 |
|
318 |
STDMETHODIMP CQGAVssProvider::QueryRevertStatus( |
319 |
VSS_PWSZ pwszVolume, IVssAsync **ppAsync) |
320 |
{ |
321 |
return E_NOTIMPL;
|
322 |
} |
323 |
|
324 |
|
325 |
/*
|
326 |
* IVssProviderCreateSnapshotSet methods
|
327 |
*/
|
328 |
|
329 |
STDMETHODIMP CQGAVssProvider::EndPrepareSnapshots(VSS_ID SnapshotSetId) |
330 |
{ |
331 |
return S_OK;
|
332 |
} |
333 |
|
334 |
STDMETHODIMP CQGAVssProvider::PreCommitSnapshots(VSS_ID SnapshotSetId) |
335 |
{ |
336 |
return S_OK;
|
337 |
} |
338 |
|
339 |
STDMETHODIMP CQGAVssProvider::CommitSnapshots(VSS_ID SnapshotSetId) |
340 |
{ |
341 |
HRESULT hr = S_OK; |
342 |
HANDLE hEventFrozen, hEventThaw, hEventTimeout; |
343 |
|
344 |
hEventFrozen = OpenEvent(EVENT_ALL_ACCESS, FALSE, EVENT_NAME_FROZEN); |
345 |
if (!hEventFrozen) {
|
346 |
return E_FAIL;
|
347 |
} |
348 |
|
349 |
hEventThaw = OpenEvent(EVENT_ALL_ACCESS, FALSE, EVENT_NAME_THAW); |
350 |
if (!hEventThaw) {
|
351 |
CloseHandle(hEventFrozen); |
352 |
return E_FAIL;
|
353 |
} |
354 |
|
355 |
hEventTimeout = OpenEvent(EVENT_ALL_ACCESS, FALSE, EVENT_NAME_TIMEOUT); |
356 |
if (!hEventTimeout) {
|
357 |
CloseHandle(hEventFrozen); |
358 |
CloseHandle(hEventThaw); |
359 |
return E_FAIL;
|
360 |
} |
361 |
|
362 |
/* Send event to qemu-ga to notify filesystem is frozen */
|
363 |
SetEvent(hEventFrozen); |
364 |
|
365 |
/* Wait until the snapshot is taken by the host. */
|
366 |
if (WaitForSingleObject(hEventThaw, VSS_TIMEOUT_MSEC) != WAIT_OBJECT_0) {
|
367 |
/* Send event to qemu-ga to notify the provider is timed out */
|
368 |
SetEvent(hEventTimeout); |
369 |
hr = E_ABORT; |
370 |
} |
371 |
|
372 |
CloseHandle(hEventThaw); |
373 |
CloseHandle(hEventFrozen); |
374 |
CloseHandle(hEventTimeout); |
375 |
return hr;
|
376 |
} |
377 |
|
378 |
STDMETHODIMP CQGAVssProvider::PostCommitSnapshots( |
379 |
VSS_ID SnapshotSetId, LONG lSnapshotsCount) |
380 |
{ |
381 |
return S_OK;
|
382 |
} |
383 |
|
384 |
STDMETHODIMP CQGAVssProvider::PreFinalCommitSnapshots(VSS_ID SnapshotSetId) |
385 |
{ |
386 |
return S_OK;
|
387 |
} |
388 |
|
389 |
STDMETHODIMP CQGAVssProvider::PostFinalCommitSnapshots(VSS_ID SnapshotSetId) |
390 |
{ |
391 |
return S_OK;
|
392 |
} |
393 |
|
394 |
STDMETHODIMP CQGAVssProvider::AbortSnapshots(VSS_ID SnapshotSetId) |
395 |
{ |
396 |
return S_OK;
|
397 |
} |
398 |
|
399 |
/*
|
400 |
* IVssProviderNotifications methods
|
401 |
*/
|
402 |
|
403 |
STDMETHODIMP CQGAVssProvider::OnLoad(IUnknown *pCallback) |
404 |
{ |
405 |
return S_OK;
|
406 |
} |
407 |
|
408 |
STDMETHODIMP CQGAVssProvider::OnUnload(BOOL bForceUnload) |
409 |
{ |
410 |
return S_OK;
|
411 |
} |
412 |
|
413 |
|
414 |
/*
|
415 |
* CQGAVssProviderFactory class
|
416 |
*/
|
417 |
|
418 |
class CQGAVssProviderFactory : public IClassFactory |
419 |
{ |
420 |
public:
|
421 |
STDMETHODIMP QueryInterface(REFIID riid, void **ppv);
|
422 |
STDMETHODIMP_(ULONG) AddRef(); |
423 |
STDMETHODIMP_(ULONG) Release(); |
424 |
STDMETHODIMP CreateInstance( |
425 |
IUnknown *pUnknownOuter, REFIID iid, void **ppv);
|
426 |
STDMETHODIMP LockServer(BOOL lock) { return E_NOTIMPL; }
|
427 |
|
428 |
CQGAVssProviderFactory(); |
429 |
~CQGAVssProviderFactory(); |
430 |
|
431 |
private:
|
432 |
long m_nRefCount;
|
433 |
}; |
434 |
|
435 |
CQGAVssProviderFactory::CQGAVssProviderFactory() |
436 |
{ |
437 |
m_nRefCount = 0;
|
438 |
LockModule(TRUE); |
439 |
} |
440 |
|
441 |
CQGAVssProviderFactory::~CQGAVssProviderFactory() |
442 |
{ |
443 |
LockModule(FALSE); |
444 |
} |
445 |
|
446 |
STDMETHODIMP CQGAVssProviderFactory::QueryInterface(REFIID riid, void **ppv)
|
447 |
{ |
448 |
if (riid == IID_IUnknown || riid == IID_IClassFactory) {
|
449 |
*ppv = static_cast<void*>(this); |
450 |
AddRef(); |
451 |
return S_OK;
|
452 |
} |
453 |
*ppv = NULL;
|
454 |
return E_NOINTERFACE;
|
455 |
} |
456 |
|
457 |
STDMETHODIMP_(ULONG) CQGAVssProviderFactory::AddRef() |
458 |
{ |
459 |
return InterlockedIncrement(&m_nRefCount);
|
460 |
} |
461 |
|
462 |
STDMETHODIMP_(ULONG) CQGAVssProviderFactory::Release() |
463 |
{ |
464 |
long nRefCount = InterlockedDecrement(&m_nRefCount);
|
465 |
if (m_nRefCount == 0) { |
466 |
delete this; |
467 |
} |
468 |
return nRefCount;
|
469 |
} |
470 |
|
471 |
STDMETHODIMP CQGAVssProviderFactory::CreateInstance( |
472 |
IUnknown *pUnknownOuter, REFIID iid, void **ppv)
|
473 |
{ |
474 |
CQGAVssProvider *pObj; |
475 |
|
476 |
if (pUnknownOuter) {
|
477 |
return CLASS_E_NOAGGREGATION;
|
478 |
} |
479 |
try {
|
480 |
pObj = new CQGAVssProvider;
|
481 |
} catch (...) {
|
482 |
return E_OUTOFMEMORY;
|
483 |
} |
484 |
HRESULT hr = pObj->QueryInterface(iid, ppv); |
485 |
if (FAILED(hr)) {
|
486 |
delete pObj;
|
487 |
} |
488 |
return hr;
|
489 |
} |
490 |
|
491 |
|
492 |
/*
|
493 |
* DLL functions
|
494 |
*/
|
495 |
|
496 |
STDAPI DllGetClassObject(REFCLSID rclsid, REFIID riid, LPVOID *ppv) |
497 |
{ |
498 |
CQGAVssProviderFactory *factory; |
499 |
try {
|
500 |
factory = new CQGAVssProviderFactory;
|
501 |
} catch (...) {
|
502 |
return E_OUTOFMEMORY;
|
503 |
} |
504 |
factory->AddRef(); |
505 |
HRESULT hr = factory->QueryInterface(riid, ppv); |
506 |
factory->Release(); |
507 |
return hr;
|
508 |
} |
509 |
|
510 |
STDAPI DllCanUnloadNow() |
511 |
{ |
512 |
return g_nComObjsInUse == 0 ? S_OK : S_FALSE; |
513 |
} |
514 |
|
515 |
EXTERN_C |
516 |
BOOL WINAPI DllMain(HINSTANCE hinstDll, DWORD dwReason, LPVOID lpReserved) |
517 |
{ |
518 |
if (dwReason == DLL_PROCESS_ATTACH) {
|
519 |
g_hinstDll = hinstDll; |
520 |
DisableThreadLibraryCalls(hinstDll); |
521 |
} |
522 |
return TRUE;
|
523 |
} |