qemu/qga/vss-win32/provider.cpp
<<
>>
Prefs
   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
  20static long g_nComObjsInUse;
  21HINSTANCE g_hinstDll;
  22
  23/* VSS common GUID's */
  24
  25const CLSID CLSID_VSSCoordinator = { 0xE579AB5F, 0x1CC4, 0x44b4,
  26    {0xBE, 0xD9, 0xDE, 0x09, 0x91, 0xFF, 0x06, 0x23} };
  27const IID IID_IVssAdmin = { 0x77ED5996, 0x2F63, 0x11d3,
  28    {0x8A, 0x39, 0x00, 0xC0, 0x4F, 0x72, 0xD8, 0xE3} };
  29
  30const IID IID_IVssHardwareSnapshotProvider = { 0x9593A157, 0x44E9, 0x4344,
  31    {0xBB, 0xEB, 0x44, 0xFB, 0xF9, 0xB0, 0x6B, 0x10} };
  32const IID IID_IVssSoftwareSnapshotProvider = { 0x609e123e, 0x2c5a, 0x44d3,
  33    {0x8f, 0x01, 0x0b, 0x1d, 0x9a, 0x47, 0xd1, 0xff} };
  34const IID IID_IVssProviderCreateSnapshotSet = { 0x5F894E5B, 0x1E39, 0x4778,
  35    {0x8E, 0x23, 0x9A, 0xBA, 0xD9, 0xF0, 0xE0, 0x8C} };
  36const IID IID_IVssProviderNotifications = { 0xE561901F, 0x03A5, 0x4afe,
  37    {0x86, 0xD0, 0x72, 0xBA, 0xEE, 0xCE, 0x70, 0x04} };
  38
  39const IID IID_IVssEnumObject = { 0xAE1C7110, 0x2F60, 0x11d3,
  40    {0x8A, 0x39, 0x00, 0xC0, 0x4F, 0x72, 0xD8, 0xE3} };
  41
  42
  43void 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
  54class CQGAVSSEnumObject : public IVssEnumObject
  55{
  56public:
  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
  72private:
  73    long m_nRefCount;
  74};
  75
  76CQGAVSSEnumObject::CQGAVSSEnumObject()
  77{
  78    m_nRefCount = 0;
  79    LockModule(TRUE);
  80}
  81
  82CQGAVSSEnumObject::~CQGAVSSEnumObject()
  83{
  84    LockModule(FALSE);
  85}
  86
  87STDMETHODIMP 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
  98STDMETHODIMP_(ULONG) CQGAVSSEnumObject::AddRef()
  99{
 100    return InterlockedIncrement(&m_nRefCount);
 101}
 102
 103STDMETHODIMP_(ULONG) CQGAVSSEnumObject::Release()
 104{
 105    long nRefCount = InterlockedDecrement(&m_nRefCount);
 106    if (m_nRefCount == 0) {
 107        delete this;
 108    }
 109    return nRefCount;
 110}
 111
 112STDMETHODIMP CQGAVSSEnumObject::Next(
 113    ULONG celt, VSS_OBJECT_PROP *rgelt, ULONG *pceltFetched)
 114{
 115    *pceltFetched = 0;
 116    return S_FALSE;
 117}
 118
 119STDMETHODIMP CQGAVSSEnumObject::Skip(ULONG celt)
 120{
 121    return S_FALSE;
 122}
 123
 124STDMETHODIMP CQGAVSSEnumObject::Reset(void)
 125{
 126    return S_OK;
 127}
 128
 129STDMETHODIMP CQGAVSSEnumObject::Clone(IVssEnumObject **ppenum)
 130{
 131    return E_NOTIMPL;
 132}
 133
 134
 135/* QGAVssProvider */
 136
 137class CQGAVssProvider :
 138    public IVssSoftwareSnapshotProvider,
 139    public IVssProviderCreateSnapshotSet,
 140    public IVssProviderNotifications
 141{
 142public:
 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
 190private:
 191    long m_nRefCount;
 192};
 193
 194CQGAVssProvider::CQGAVssProvider()
 195{
 196    m_nRefCount = 0;
 197    LockModule(TRUE);
 198}
 199
 200CQGAVssProvider::~CQGAVssProvider()
 201{
 202    LockModule(FALSE);
 203}
 204
 205STDMETHODIMP 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
 234STDMETHODIMP_(ULONG) CQGAVssProvider::AddRef()
 235{
 236    return InterlockedIncrement(&m_nRefCount);
 237}
 238
 239STDMETHODIMP_(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
 253STDMETHODIMP CQGAVssProvider::SetContext(LONG lContext)
 254{
 255    return S_OK;
 256}
 257
 258STDMETHODIMP CQGAVssProvider::GetSnapshotProperties(
 259    VSS_ID SnapshotId, VSS_SNAPSHOT_PROP *pProp)
 260{
 261    return VSS_E_OBJECT_NOT_FOUND;
 262}
 263
 264STDMETHODIMP 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
 277STDMETHODIMP 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
 286STDMETHODIMP CQGAVssProvider::BeginPrepareSnapshot(
 287    VSS_ID SnapshotSetId, VSS_ID SnapshotId,
 288    VSS_PWSZ pwszVolumeName, LONG lNewContext)
 289{
 290    return S_OK;
 291}
 292
 293STDMETHODIMP 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
 310STDMETHODIMP CQGAVssProvider::IsVolumeSnapshotted(VSS_PWSZ pwszVolumeName,
 311    BOOL *pbSnapshotsPresent, LONG *plSnapshotCompatibility)
 312{
 313    *pbSnapshotsPresent = FALSE;
 314    *plSnapshotCompatibility = 0;
 315    return S_OK;
 316}
 317
 318STDMETHODIMP CQGAVssProvider::SetSnapshotProperty(VSS_ID SnapshotId,
 319    VSS_SNAPSHOT_PROPERTY_ID eSnapshotPropertyId, VARIANT vProperty)
 320{
 321    return E_NOTIMPL;
 322}
 323
 324STDMETHODIMP CQGAVssProvider::RevertToSnapshot(VSS_ID SnapshotId)
 325{
 326    return E_NOTIMPL;
 327}
 328
 329STDMETHODIMP CQGAVssProvider::QueryRevertStatus(
 330    VSS_PWSZ pwszVolume, IVssAsync **ppAsync)
 331{
 332    return E_NOTIMPL;
 333}
 334
 335
 336/*
 337 * IVssProviderCreateSnapshotSet methods
 338 */
 339
 340STDMETHODIMP CQGAVssProvider::EndPrepareSnapshots(VSS_ID SnapshotSetId)
 341{
 342    return S_OK;
 343}
 344
 345STDMETHODIMP CQGAVssProvider::PreCommitSnapshots(VSS_ID SnapshotSetId)
 346{
 347    return S_OK;
 348}
 349
 350STDMETHODIMP 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    }
 381
 382    CloseHandle(hEventThaw);
 383    CloseHandle(hEventFrozen);
 384    CloseHandle(hEventTimeout);
 385    return hr;
 386}
 387
 388STDMETHODIMP CQGAVssProvider::PostCommitSnapshots(
 389    VSS_ID SnapshotSetId, LONG lSnapshotsCount)
 390{
 391    return S_OK;
 392}
 393
 394STDMETHODIMP CQGAVssProvider::PreFinalCommitSnapshots(VSS_ID SnapshotSetId)
 395{
 396    return S_OK;
 397}
 398
 399STDMETHODIMP CQGAVssProvider::PostFinalCommitSnapshots(VSS_ID SnapshotSetId)
 400{
 401    return S_OK;
 402}
 403
 404STDMETHODIMP CQGAVssProvider::AbortSnapshots(VSS_ID SnapshotSetId)
 405{
 406    return S_OK;
 407}
 408
 409/*
 410 * IVssProviderNotifications methods
 411 */
 412
 413STDMETHODIMP CQGAVssProvider::OnLoad(IUnknown *pCallback)
 414{
 415    return S_OK;
 416}
 417
 418STDMETHODIMP CQGAVssProvider::OnUnload(BOOL bForceUnload)
 419{
 420    return S_OK;
 421}
 422
 423
 424/*
 425 * CQGAVssProviderFactory class
 426 */
 427
 428class CQGAVssProviderFactory : public IClassFactory
 429{
 430public:
 431    STDMETHODIMP QueryInterface(REFIID riid, void **ppv);
 432    STDMETHODIMP_(ULONG) AddRef();
 433    STDMETHODIMP_(ULONG) Release();
 434    STDMETHODIMP CreateInstance(
 435        IUnknown *pUnknownOuter, REFIID iid, void **ppv);
 436    STDMETHODIMP LockServer(BOOL lock) { return E_NOTIMPL; }
 437
 438    CQGAVssProviderFactory();
 439    ~CQGAVssProviderFactory();
 440
 441private:
 442    long m_nRefCount;
 443};
 444
 445CQGAVssProviderFactory::CQGAVssProviderFactory()
 446{
 447    m_nRefCount = 0;
 448    LockModule(TRUE);
 449}
 450
 451CQGAVssProviderFactory::~CQGAVssProviderFactory()
 452{
 453    LockModule(FALSE);
 454}
 455
 456STDMETHODIMP CQGAVssProviderFactory::QueryInterface(REFIID riid, void **ppv)
 457{
 458    if (riid == IID_IUnknown || riid == IID_IClassFactory) {
 459        *ppv = static_cast<void*>(this);
 460        AddRef();
 461        return S_OK;
 462    }
 463    *ppv = NULL;
 464    return E_NOINTERFACE;
 465}
 466
 467STDMETHODIMP_(ULONG) CQGAVssProviderFactory::AddRef()
 468{
 469    return InterlockedIncrement(&m_nRefCount);
 470}
 471
 472STDMETHODIMP_(ULONG) CQGAVssProviderFactory::Release()
 473{
 474    long nRefCount = InterlockedDecrement(&m_nRefCount);
 475    if (m_nRefCount == 0) {
 476        delete this;
 477    }
 478    return nRefCount;
 479}
 480
 481STDMETHODIMP CQGAVssProviderFactory::CreateInstance(
 482    IUnknown *pUnknownOuter, REFIID iid, void **ppv)
 483{
 484    CQGAVssProvider *pObj;
 485
 486    if (pUnknownOuter) {
 487        return CLASS_E_NOAGGREGATION;
 488    }
 489    try {
 490        pObj = new CQGAVssProvider;
 491    } catch (...) {
 492        return E_OUTOFMEMORY;
 493    }
 494    HRESULT hr = pObj->QueryInterface(iid, ppv);
 495    if (FAILED(hr)) {
 496        delete pObj;
 497    }
 498    return hr;
 499}
 500
 501
 502/*
 503 * DLL functions
 504 */
 505
 506STDAPI DllGetClassObject(REFCLSID rclsid, REFIID riid, LPVOID *ppv)
 507{
 508    CQGAVssProviderFactory *factory;
 509    try {
 510        factory = new CQGAVssProviderFactory;
 511    } catch (...) {
 512        return E_OUTOFMEMORY;
 513    }
 514    factory->AddRef();
 515    HRESULT hr = factory->QueryInterface(riid, ppv);
 516    factory->Release();
 517    return hr;
 518}
 519
 520STDAPI DllCanUnloadNow()
 521{
 522    return g_nComObjsInUse == 0 ? S_OK : S_FALSE;
 523}
 524
 525EXTERN_C
 526BOOL WINAPI DllMain(HINSTANCE hinstDll, DWORD dwReason, LPVOID lpReserved)
 527{
 528    if (dwReason == DLL_PROCESS_ATTACH) {
 529        g_hinstDll = hinstDll;
 530        DisableThreadLibraryCalls(hinstDll);
 531    }
 532    return TRUE;
 533}
 534