qemu

FORK: QEMU emulator
git clone https://git.neptards.moe/neptards/qemu.git
Log | Files | Refs | Submodules | LICENSE

provider.cpp (13211B)


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