Statistics
| Branch: | Revision:

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
}