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 == INVALID_HANDLE_VALUE) { 346 return E_FAIL; 347 } 348 349 hEventThaw = OpenEvent(EVENT_ALL_ACCESS, FALSE, EVENT_NAME_THAW); 350 if (hEventThaw == INVALID_HANDLE_VALUE) { 351 CloseHandle(hEventFrozen); 352 return E_FAIL; 353 } 354 355 hEventTimeout = OpenEvent(EVENT_ALL_ACCESS, FALSE, EVENT_NAME_TIMEOUT); 356 if (hEventTimeout == INVALID_HANDLE_VALUE) { 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 } 524