xref: /openbmc/qemu/qga/vss-win32/provider.cpp (revision b917da4c)
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 "qemu/osdep.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     *plDeletedSnapshots = 0;
282     *pNondeletedSnapshotID = SourceObjectId;
283     return S_OK;
284 }
285 
286 STDMETHODIMP CQGAVssProvider::BeginPrepareSnapshot(
287     VSS_ID SnapshotSetId, VSS_ID SnapshotId,
288     VSS_PWSZ pwszVolumeName, LONG lNewContext)
289 {
290     return S_OK;
291 }
292 
293 STDMETHODIMP CQGAVssProvider::IsVolumeSupported(
294     VSS_PWSZ pwszVolumeName, BOOL *pbSupportedByThisProvider)
295 {
296     HANDLE hEventFrozen;
297 
298     /* Check if a requester is qemu-ga by whether an event is created */
299     hEventFrozen = OpenEvent(EVENT_ALL_ACCESS, FALSE, EVENT_NAME_FROZEN);
300     if (!hEventFrozen) {
301         *pbSupportedByThisProvider = FALSE;
302         return S_OK;
303     }
304     CloseHandle(hEventFrozen);
305 
306     *pbSupportedByThisProvider = TRUE;
307     return S_OK;
308 }
309 
310 STDMETHODIMP CQGAVssProvider::IsVolumeSnapshotted(VSS_PWSZ pwszVolumeName,
311     BOOL *pbSnapshotsPresent, LONG *plSnapshotCompatibility)
312 {
313     *pbSnapshotsPresent = FALSE;
314     *plSnapshotCompatibility = 0;
315     return S_OK;
316 }
317 
318 STDMETHODIMP CQGAVssProvider::SetSnapshotProperty(VSS_ID SnapshotId,
319     VSS_SNAPSHOT_PROPERTY_ID eSnapshotPropertyId, VARIANT vProperty)
320 {
321     return E_NOTIMPL;
322 }
323 
324 STDMETHODIMP CQGAVssProvider::RevertToSnapshot(VSS_ID SnapshotId)
325 {
326     return E_NOTIMPL;
327 }
328 
329 STDMETHODIMP CQGAVssProvider::QueryRevertStatus(
330     VSS_PWSZ pwszVolume, IVssAsync **ppAsync)
331 {
332     return E_NOTIMPL;
333 }
334 
335 
336 /*
337  * IVssProviderCreateSnapshotSet methods
338  */
339 
340 STDMETHODIMP CQGAVssProvider::EndPrepareSnapshots(VSS_ID SnapshotSetId)
341 {
342     return S_OK;
343 }
344 
345 STDMETHODIMP CQGAVssProvider::PreCommitSnapshots(VSS_ID SnapshotSetId)
346 {
347     return S_OK;
348 }
349 
350 STDMETHODIMP CQGAVssProvider::CommitSnapshots(VSS_ID SnapshotSetId)
351 {
352     HRESULT hr = S_OK;
353     HANDLE hEventFrozen, hEventThaw, hEventTimeout;
354 
355     hEventFrozen = OpenEvent(EVENT_ALL_ACCESS, FALSE, EVENT_NAME_FROZEN);
356     if (!hEventFrozen) {
357         return E_FAIL;
358     }
359 
360     hEventThaw = OpenEvent(EVENT_ALL_ACCESS, FALSE, EVENT_NAME_THAW);
361     if (!hEventThaw) {
362         CloseHandle(hEventFrozen);
363         return E_FAIL;
364     }
365 
366     hEventTimeout = OpenEvent(EVENT_ALL_ACCESS, FALSE, EVENT_NAME_TIMEOUT);
367     if (!hEventTimeout) {
368         CloseHandle(hEventFrozen);
369         CloseHandle(hEventThaw);
370         return E_FAIL;
371     }
372 
373     /* Send event to qemu-ga to notify filesystem is frozen */
374     SetEvent(hEventFrozen);
375 
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);
380         hr = E_ABORT;
381     }
382 
383     CloseHandle(hEventThaw);
384     CloseHandle(hEventFrozen);
385     CloseHandle(hEventTimeout);
386     return hr;
387 }
388 
389 STDMETHODIMP CQGAVssProvider::PostCommitSnapshots(
390     VSS_ID SnapshotSetId, LONG lSnapshotsCount)
391 {
392     return S_OK;
393 }
394 
395 STDMETHODIMP CQGAVssProvider::PreFinalCommitSnapshots(VSS_ID SnapshotSetId)
396 {
397     return S_OK;
398 }
399 
400 STDMETHODIMP CQGAVssProvider::PostFinalCommitSnapshots(VSS_ID SnapshotSetId)
401 {
402     return S_OK;
403 }
404 
405 STDMETHODIMP CQGAVssProvider::AbortSnapshots(VSS_ID SnapshotSetId)
406 {
407     return S_OK;
408 }
409 
410 /*
411  * IVssProviderNotifications methods
412  */
413 
414 STDMETHODIMP CQGAVssProvider::OnLoad(IUnknown *pCallback)
415 {
416     return S_OK;
417 }
418 
419 STDMETHODIMP CQGAVssProvider::OnUnload(BOOL bForceUnload)
420 {
421     return S_OK;
422 }
423 
424 
425 /*
426  * CQGAVssProviderFactory class
427  */
428 
429 class CQGAVssProviderFactory : public IClassFactory
430 {
431 public:
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; }
438 
439     CQGAVssProviderFactory();
440     ~CQGAVssProviderFactory();
441 
442 private:
443     long m_nRefCount;
444 };
445 
446 CQGAVssProviderFactory::CQGAVssProviderFactory()
447 {
448     m_nRefCount = 0;
449     LockModule(TRUE);
450 }
451 
452 CQGAVssProviderFactory::~CQGAVssProviderFactory()
453 {
454     LockModule(FALSE);
455 }
456 
457 STDMETHODIMP CQGAVssProviderFactory::QueryInterface(REFIID riid, void **ppv)
458 {
459     if (riid == IID_IUnknown || riid == IID_IClassFactory) {
460         *ppv = static_cast<void*>(this);
461         AddRef();
462         return S_OK;
463     }
464     *ppv = NULL;
465     return E_NOINTERFACE;
466 }
467 
468 STDMETHODIMP_(ULONG) CQGAVssProviderFactory::AddRef()
469 {
470     return InterlockedIncrement(&m_nRefCount);
471 }
472 
473 STDMETHODIMP_(ULONG) CQGAVssProviderFactory::Release()
474 {
475     long nRefCount = InterlockedDecrement(&m_nRefCount);
476     if (m_nRefCount == 0) {
477         delete this;
478     }
479     return nRefCount;
480 }
481 
482 STDMETHODIMP CQGAVssProviderFactory::CreateInstance(
483     IUnknown *pUnknownOuter, REFIID iid, void **ppv)
484 {
485     CQGAVssProvider *pObj;
486 
487     if (pUnknownOuter) {
488         return CLASS_E_NOAGGREGATION;
489     }
490     try {
491         pObj = new CQGAVssProvider;
492     } catch (...) {
493         return E_OUTOFMEMORY;
494     }
495     HRESULT hr = pObj->QueryInterface(iid, ppv);
496     if (FAILED(hr)) {
497         delete pObj;
498     }
499     return hr;
500 }
501 
502 
503 /*
504  * DLL functions
505  */
506 
507 STDAPI DllGetClassObject(REFCLSID rclsid, REFIID riid, LPVOID *ppv)
508 {
509     CQGAVssProviderFactory *factory;
510     try {
511         factory = new CQGAVssProviderFactory;
512     } catch (...) {
513         return E_OUTOFMEMORY;
514     }
515     factory->AddRef();
516     HRESULT hr = factory->QueryInterface(riid, ppv);
517     factory->Release();
518     return hr;
519 }
520 
521 STDAPI DllCanUnloadNow()
522 {
523     return g_nComObjsInUse == 0 ? S_OK : S_FALSE;
524 }
525 
526 EXTERN_C
527 BOOL WINAPI DllMain(HINSTANCE hinstDll, DWORD dwReason, LPVOID lpReserved)
528 {
529     if (dwReason == DLL_PROCESS_ATTACH) {
530         g_hinstDll = hinstDll;
531         DisableThreadLibraryCalls(hinstDll);
532     }
533     return TRUE;
534 }
535