provider.cpp 13 KB

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