provider.cpp (13181B)
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}