Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

670 lines
20 KiB

  1. /*++
  2. Copyright (c) 2000-2001 Microsoft Corporation
  3. Module Name:
  4. vssapi.cpp
  5. Abstract:
  6. Contains the exported DLL functions for VssAPI.dll.
  7. BUGBUG: Uses code that currently sets the SE handler. Since the SEH is process
  8. wide, this can/will effect the user of this DLL. Need to fix.
  9. Author:
  10. reuvenl 5/01/2002
  11. Revision History:
  12. Name Date Comments
  13. reuvenl 5/01/2002 Created from old wrtrshim.cpp
  14. --*/
  15. #include "stdafx.h"
  16. /*
  17. ** ATL
  18. */
  19. CComModule _Module;
  20. #include <atlcom.h>
  21. #include "vs_sec.hxx"
  22. #include "vs_reg.hxx"
  23. #include "ntddsnap.h"
  24. BEGIN_OBJECT_MAP(ObjectMap)
  25. END_OBJECT_MAP()
  26. ////////////////////////////////////////////////////////////////////////
  27. // Standard foo for file name aliasing. This code block must be after
  28. // all includes of VSS header files.
  29. //
  30. #ifdef VSS_FILE_ALIAS
  31. #undef VSS_FILE_ALIAS
  32. #endif
  33. #define VSS_FILE_ALIAS "VSSAPICP"
  34. // the name of the Volume Snapshot Service
  35. const LPCWSTR wszVssvcServiceName = L"VSS";
  36. static ULONG g_ulThreadAttaches = 0;
  37. static ULONG g_ulThreadDetaches = 0;
  38. static CBsCritSec g_cCritSec;
  39. static GUID g_guidSnapshotInProgress = GUID_NULL;
  40. static IVssShim *g_pIShim = NULL; // Used by the simulate functions.
  41. /*
  42. **++
  43. **
  44. ** Routine Description:
  45. **
  46. ** The DllMain entry point for this DLL. Note that this must be called by the
  47. ** CRT DLL Start function since the CRT must be initialized.
  48. **
  49. **
  50. ** Arguments:
  51. ** hInstance
  52. ** dwReason
  53. ** lpReserved
  54. **
  55. **
  56. ** Return Value:
  57. **
  58. ** TRUE - Successful function execution
  59. ** FALSE - Error when executing the function
  60. **
  61. **--
  62. */
  63. BOOL APIENTRY DllMain (IN HINSTANCE hInstance,
  64. IN DWORD dwReason,
  65. IN LPVOID lpReserved)
  66. {
  67. BOOL bSuccessful = TRUE;
  68. UNREFERENCED_PARAMETER (hInstance);
  69. UNREFERENCED_PARAMETER (lpReserved);
  70. if (DLL_PROCESS_ATTACH == dwReason)
  71. {
  72. try
  73. {
  74. /*
  75. ** Set the correct tracing context. This is an inproc DLL
  76. */
  77. g_cDbgTrace.SetContextNum (VSS_CONTEXT_DELAYED_DLL);
  78. }
  79. catch (...)
  80. {
  81. /*
  82. ** Can't trace from here so just ASSERT() (checked builds only)
  83. */
  84. bSuccessful = FALSE;
  85. BS_ASSERT (bSuccessful && "FAILED to initialise tracing sub-system");
  86. }
  87. }
  88. if (bSuccessful)
  89. {
  90. try
  91. {
  92. switch (dwReason)
  93. {
  94. case DLL_PROCESS_ATTACH:
  95. BsDebugTrace (0,
  96. DEBUG_TRACE_VSSAPI,
  97. (L"VssAPI: DllMain - DLL_PROCESS_ATTACH called, %s",
  98. lpReserved ? L"Static load" : L"Dynamic load"));
  99. /*
  100. ** Don't need to know when threads start and stop - Wrong
  101. **
  102. ** DisableThreadLibraryCalls (hInstance);
  103. */
  104. _Module.Init (ObjectMap, hInstance);
  105. break;
  106. case DLL_PROCESS_DETACH:
  107. BsDebugTrace (0,
  108. DEBUG_TRACE_VSSAPI,
  109. (L"VssAPI: DllMain - DLL_PROCESS_DETACH called %s",
  110. lpReserved ? L"during process termination" : L"by FreeLibrary"));
  111. _Module.Term();
  112. break;
  113. case DLL_THREAD_ATTACH:
  114. g_ulThreadAttaches++;
  115. if (0 == (g_ulThreadAttaches % 1000))
  116. {
  117. BsDebugTrace (0,
  118. DEBUG_TRACE_VSSAPI,
  119. (L"VssAPI: DllMain thread attaches = %u, detaches = %u, outstanding = %u",
  120. g_ulThreadAttaches,
  121. g_ulThreadDetaches,
  122. g_ulThreadAttaches - g_ulThreadDetaches));
  123. }
  124. break;
  125. case DLL_THREAD_DETACH:
  126. g_ulThreadDetaches++;
  127. if (0 == (g_ulThreadDetaches % 1000))
  128. {
  129. BsDebugTrace (0,
  130. DEBUG_TRACE_VSSAPI,
  131. (L"VssAPI: DllMain thread attaches = %u, detaches = %u, outstanding = %u",
  132. g_ulThreadAttaches,
  133. g_ulThreadDetaches,
  134. g_ulThreadAttaches - g_ulThreadDetaches));
  135. }
  136. break;
  137. default:
  138. BsDebugTrace (0,
  139. DEBUG_TRACE_VSSAPI,
  140. (L"VssAPI: DllMain got unexpected reason code, lpReserved: %sNULL",
  141. dwReason,
  142. lpReserved ? L"non-" : L""));
  143. break;
  144. }
  145. }
  146. catch (...)
  147. {
  148. BsDebugTraceAlways (0,
  149. DEBUG_TRACE_VSSAPI,
  150. (L"VssAPI: DllMain - Error, unknown exception caught"));
  151. bSuccessful = FALSE;
  152. }
  153. }
  154. return (bSuccessful);
  155. } /* DllMain () */
  156. /*
  157. **++
  158. **
  159. ** Routine Description:
  160. **
  161. ** The exported function that is called to simulate a snapshot creation to allow
  162. ** backup to drive the shim writers rather than having the snapshot co-ordinator
  163. ** do so.
  164. **
  165. **
  166. ** Arguments:
  167. **
  168. ** guidSnapshotSetId Identifier used to identify the simulated prepare/freeze
  169. ** ulOptionFlags Options required for this freeze selected from the following list:-
  170. ** VSS_SW_BOOTABLE_STATE
  171. **
  172. ** ulVolumeCount Number of volumes in the volume array
  173. ** ppwszVolumeNamesArray Array of pointer to volume name strings
  174. ** hCompletionEvent Handle to an event which will be set when the asynchronous freeze completes
  175. ** phrCompletionStatus Pointer to an HRESULT which will receive the completion status when the
  176. ** asynchronous freeze completes
  177. **
  178. **
  179. ** Return Value:
  180. **
  181. ** Any HRESULT from the Snapshot writer PrepareForFreeze or Freeze functions.
  182. **
  183. **--
  184. */
  185. __declspec(dllexport) HRESULT APIENTRY SimulateSnapshotFreeze (
  186. IN GUID guidSnapshotSetId,
  187. IN ULONG ulOptionFlags,
  188. IN ULONG ulVolumeCount,
  189. IN LPWSTR *ppwszVolumeNamesArray,
  190. OUT IVssAsync **ppAsync )
  191. {
  192. CVssFunctionTracer ft (VSSDBG_VSSAPI, L"VssAPI::SimulateSnapshotFreeze");
  193. BOOL bSucceeded;
  194. try
  195. {
  196. CBsAutoLock cAutoLock (g_cCritSec);
  197. BOOL bPrivilegesSufficient = FALSE;
  198. bPrivilegesSufficient = IsProcessBackupOperator ();
  199. ft.ThrowIf (!bPrivilegesSufficient,
  200. VSSDBG_VSSAPI,
  201. E_ACCESSDENIED,
  202. L"FAILED as insufficient privileges to call shim");
  203. //
  204. // Most parameter checks should be done here in the VssApi DLL and not in the
  205. // IVssCoordinator::SimulateSnapshotFreeze method since the shim DLL can be
  206. // changed independently from the service. The service is just a forwarding
  207. // agent to get SimulateSnapshotFreezeInternal called within one of the
  208. // service's threads.
  209. //
  210. ft.ThrowIf ((ulOptionFlags & ~VSS_SW_BOOTABLE_STATE) != 0,
  211. VSSDBG_VSSAPI,
  212. E_INVALIDARG,
  213. L"FAILED as illegal option flags set");
  214. ft.ThrowIf (!((ulOptionFlags & VSS_SW_BOOTABLE_STATE) || (ulVolumeCount > 0)),
  215. VSSDBG_VSSAPI,
  216. E_INVALIDARG,
  217. L"FAILED as need either BootableState or a volume list");
  218. ft.ThrowIf ((ulVolumeCount > 0) && (NULL == ppwszVolumeNamesArray),
  219. VSSDBG_VSSAPI,
  220. E_INVALIDARG,
  221. L"FAILED as need at least a one volume in the list if not bootable state");
  222. ft.ThrowIf ((GUID_NULL == guidSnapshotSetId),
  223. VSSDBG_VSSAPI,
  224. E_INVALIDARG,
  225. L"FAILED as supplied SnapshotSetId should not be GUID_NULL");
  226. ft.ThrowIf ((NULL == ppAsync),
  227. VSSDBG_VSSAPI,
  228. E_INVALIDARG,
  229. L"FAILED as supplied ppAsync parameter is NULL");
  230. *ppAsync = NULL;
  231. /*
  232. ** Try to scan all the volume names in an attempt to trigger
  233. ** an access violation to catch it here rather than in an
  234. ** unfortunate spot later on. It also gives us the
  235. ** opportinutiy to do some very basic validity checks.
  236. */
  237. for (ULONG ulIndex = 0; ulIndex < ulVolumeCount; ulIndex++)
  238. {
  239. ft.ThrowIf (NULL == ppwszVolumeNamesArray [ulIndex],
  240. VSSDBG_VSSAPI,
  241. E_INVALIDARG,
  242. L"FAILED as NULL value in volume array");
  243. ft.ThrowIf (wcslen (L"C:") > wcslen (ppwszVolumeNamesArray [ulIndex]),
  244. VSSDBG_VSSAPI,
  245. E_INVALIDARG,
  246. L"FAILED as volume name too short");
  247. }
  248. /*
  249. ** Now we need to connect to the VssSvc service's IVssCoordinator object
  250. ** and make the simulate freeze happen.
  251. */
  252. ft.ThrowIf ( g_pIShim != NULL,
  253. VSSDBG_VSSAPI,
  254. VSS_E_SNAPSHOT_SET_IN_PROGRESS,
  255. L"SimulateSnapshotThaw() must first be called by this process before calling SimulateSnapshotFreeze() again." );
  256. ft.LogVssStartupAttempt();
  257. ft.CoCreateInstanceWithLog(
  258. VSSDBG_VSSAPI,
  259. CLSID_VSSCoordinator,
  260. L"Coordinator",
  261. CLSCTX_ALL,
  262. IID_IVssShim,
  263. (IUnknown**)&(g_pIShim));
  264. ft.CheckForError(VSSDBG_VSSAPI, L"CoCreateInstance( CLSID_VSSCoordinator, IID_IVssShim)");
  265. BS_ASSERT( g_pIShim != NULL );
  266. g_guidSnapshotInProgress = guidSnapshotSetId;
  267. /*
  268. ** Now call the simulate freeze method in the coordinator
  269. */
  270. ft.hr = g_pIShim->SimulateSnapshotFreeze(
  271. guidSnapshotSetId,
  272. ulOptionFlags,
  273. ulVolumeCount,
  274. ppwszVolumeNamesArray,
  275. ppAsync );
  276. ft.CheckForError(VSSDBG_VSSAPI, L"IVssShim::SimulateSnapshotFreeze()");
  277. /*
  278. ** The simulate freeze operation is now running in a thread in VssSvc.
  279. */
  280. }
  281. VSS_STANDARD_CATCH (ft);
  282. return (ft.hr);
  283. } /* SimulateSnapshotFreeze () */
  284. /*
  285. **++
  286. **
  287. ** Routine Description:
  288. **
  289. ** The exported function that is called to simulate a snapshot thaw to allow
  290. ** backup to drive the shim writers rather than having the snapshot co-ordinator
  291. ** do so.
  292. **
  293. **
  294. ** Arguments:
  295. **
  296. ** guidSnapshotSetId Identifier used to identify the simulated prepare/freeze
  297. **
  298. **
  299. ** Return Value:
  300. **
  301. ** Any HRESULT from the Snapshot writer Thaw functions.
  302. **
  303. **--
  304. */
  305. __declspec(dllexport) HRESULT APIENTRY SimulateSnapshotThaw (
  306. IN GUID guidSnapshotSetId )
  307. {
  308. CVssFunctionTracer ft (VSSDBG_VSSAPI, L"VssAPI::SimulateSnapshotThaw");
  309. BOOL bPrivilegesSufficient = FALSE;
  310. HRESULT hrBootableState = NOERROR;
  311. HRESULT hrSimulateOnly = NOERROR;
  312. try
  313. {
  314. CBsAutoLock cAutoLock (g_cCritSec);
  315. bPrivilegesSufficient = IsProcessBackupOperator ();
  316. ft.ThrowIf (!bPrivilegesSufficient,
  317. VSSDBG_VSSAPI,
  318. E_ACCESSDENIED,
  319. L"FAILED as inssuficient privileges to call shim");
  320. /*
  321. ** We need to make sure a prior SimulateSnapshotFreeze happened.
  322. */
  323. ft.ThrowIf ( g_pIShim == NULL,
  324. VSSDBG_VSSAPI,
  325. VSS_E_BAD_STATE,
  326. L"Called SimulateSnapshotThaw() without first calling SimulateSnapshotFreeze()" );
  327. ft.ThrowIf ( g_guidSnapshotInProgress != guidSnapshotSetId,
  328. VSSDBG_VSSAPI,
  329. VSS_E_BAD_STATE,
  330. L"Mismatch between guidSnapshotSetId and the one passed into SimulateSnapshotFreeze()" );
  331. /*
  332. ** Now call the simulate thaw method in the coordinator
  333. */
  334. ft.hr = g_pIShim->SimulateSnapshotThaw( guidSnapshotSetId );
  335. /*
  336. ** Regardless of the outcome of the SimulateSnapshotThaw, get rid of the shim interface.
  337. */
  338. g_pIShim->Release();
  339. g_pIShim = NULL;
  340. g_guidSnapshotInProgress = GUID_NULL;
  341. ft.CheckForError(VSSDBG_VSSAPI, L"IVssShim::SimulateSnapshotThaw()");
  342. }
  343. VSS_STANDARD_CATCH (ft);
  344. return (ft.hr);
  345. } /* SimulateSnapshotThaw () */
  346. /*
  347. **++
  348. **
  349. ** Routine Description:
  350. **
  351. ** The exported function that is called to check if a volume is snapshotted
  352. **
  353. **
  354. ** Arguments:
  355. **
  356. ** IN VSS_PWSZ pwszVolumeName - The volume to be checked.
  357. ** OUT BOOL * pbSnapshotsPresent - Returns TRUE if the volume is snapshotted.
  358. **
  359. **
  360. ** Return Value:
  361. **
  362. ** Any HRESULT from the IVssCoordinator::IsVolumeSnapshotted.
  363. **
  364. **--
  365. */
  366. __declspec(dllexport) HRESULT APIENTRY IsVolumeSnapshotted (
  367. IN VSS_PWSZ pwszVolumeName,
  368. OUT BOOL * pbSnapshotsPresent,
  369. OUT LONG * plSnapshotCompatibility
  370. )
  371. {
  372. CVssFunctionTracer ft (VSSDBG_VSSAPI, L"VssAPI::IsVolumeSnapshotted");
  373. BOOL bPrivilegesSufficient = FALSE;
  374. SC_HANDLE shSCManager = NULL;
  375. SC_HANDLE shSCService = NULL;
  376. DWORD dwOldState = 0;
  377. try
  378. {
  379. // Zero out the out parameter
  380. ::VssZeroOut(pbSnapshotsPresent);
  381. ::VssZeroOut(plSnapshotCompatibility);
  382. bPrivilegesSufficient = IsProcessAdministrator ();
  383. ft.ThrowIf (!bPrivilegesSufficient,
  384. VSSDBG_VSSAPI,
  385. E_ACCESSDENIED,
  386. L"FAILED as insufficient privileges to call shim");
  387. ft.ThrowIf ( (pwszVolumeName == NULL) || (pbSnapshotsPresent == NULL) ||
  388. (plSnapshotCompatibility == NULL),
  389. VSSDBG_VSSAPI,
  390. E_INVALIDARG,
  391. L"FAILED as invalid parameters");
  392. CBsAutoLock cAutoLock (g_cCritSec);
  393. //
  394. // Check to see if VSSVC is running. If not ,we are supposing that no snapshots are present on the system.
  395. //
  396. // Connect to the local service control manager
  397. shSCManager = OpenSCManager (NULL, NULL, SC_MANAGER_CONNECT);
  398. if (!shSCManager)
  399. ft.TranslateGenericError(VSSDBG_VSSAPI, HRESULT_FROM_WIN32(GetLastError()),
  400. L"OpenSCManager(NULL,NULL,SC_MANAGER_CONNECT)");
  401. // Get a handle to the service
  402. shSCService = OpenService (shSCManager, wszVssvcServiceName, SERVICE_QUERY_STATUS);
  403. if (!shSCService)
  404. ft.TranslateGenericError(VSSDBG_VSSAPI, HRESULT_FROM_WIN32(GetLastError()),
  405. L" OpenService (shSCManager, \'%s\', SERVICE_QUERY_STATUS)", wszVssvcServiceName);
  406. // Now query the service to see what state it is in at the moment.
  407. SERVICE_STATUS sSStat;
  408. if (!QueryServiceStatus (shSCService, &sSStat))
  409. ft.TranslateGenericError(VSSDBG_VSSAPI, HRESULT_FROM_WIN32(GetLastError()),
  410. L"QueryServiceStatus (shSCService, &sSStat)");
  411. // BUG 250943: Only if the service is running then check to see if there are any snapsnots
  412. if (sSStat.dwCurrentState == SERVICE_RUNNING) {
  413. // Create the coordinator interface
  414. CComPtr<IVssCoordinator> pCoord;
  415. // The service is already started, but...
  416. // We still log here in order to make our code more robust.
  417. ft.LogVssStartupAttempt();
  418. // Create the instance.
  419. ft.CoCreateInstanceWithLog(
  420. VSSDBG_VSSAPI,
  421. CLSID_VSSCoordinator,
  422. L"Coordinator",
  423. CLSCTX_ALL,
  424. IID_IVssCoordinator,
  425. (IUnknown**)&(pCoord));
  426. if (ft.HrFailed())
  427. ft.TranslateGenericError(VSSDBG_VSSAPI, ft.hr, L"CoCreateInstance(CLSID_VSSCoordinator)");
  428. BS_ASSERT(pCoord);
  429. // Call IsVolumeSnapshotted on the coordinator
  430. ft.hr = pCoord->IsVolumeSnapshotted(
  431. GUID_NULL,
  432. pwszVolumeName,
  433. pbSnapshotsPresent,
  434. plSnapshotCompatibility);
  435. }
  436. else
  437. {
  438. // If the service is not running, then try to see if we have only MS Software Provider installed
  439. // Open the "Providers" key. Throw an error if the key does not exist.
  440. CVssRegistryKey keyProviders;
  441. if (!keyProviders.Open( HKEY_LOCAL_MACHINE, L"%s\\%s", x_wszVSSKey, x_wszVSSKeyProviders))
  442. ft.TranslateGenericError(VSSDBG_VSSAPI, ft.hr, L"RegOpenKeyExW(%ld,%s\\%s,...) = ERROR_FILE_NOT_FOUND",
  443. HKEY_LOCAL_MACHINE, x_wszVSSKey, x_wszVSSKeyProviders);
  444. // Attach an enumerator to the subkeys the subkeys
  445. CVssRegistryKeyIterator iter;
  446. iter.Attach(keyProviders);
  447. BS_ASSERT(!iter.IsEOF());
  448. // Get the number of subkeys. If different than one, the we sould go with the standard path
  449. // If it is only one, this is the MS software provider (since it is always registered)
  450. if (iter.GetSubkeysCount() != 1)
  451. {
  452. // Create the instance.
  453. CComPtr<IVssCoordinator> pCoord;
  454. ft.CoCreateInstanceWithLog(
  455. VSSDBG_VSSAPI,
  456. CLSID_VSSCoordinator,
  457. L"Coordinator",
  458. CLSCTX_ALL,
  459. IID_IVssCoordinator,
  460. (IUnknown**)&(pCoord));
  461. if (ft.HrFailed())
  462. ft.TranslateGenericError(VSSDBG_VSSAPI, ft.hr, L"CoCreateInstance(CLSID_VSSCoordinator)");
  463. BS_ASSERT(pCoord);
  464. // Call IsVolumeSnapshotted on the coordinator
  465. ft.hr = pCoord->IsVolumeSnapshotted(
  466. GUID_NULL,
  467. pwszVolumeName,
  468. pbSnapshotsPresent,
  469. plSnapshotCompatibility);
  470. }
  471. else
  472. {
  473. // Getting the volume name
  474. WCHAR wszVolumeNameInternal[x_nLengthOfVolMgmtVolumeName + 1];
  475. if (!::GetVolumeNameForVolumeMountPointW( pwszVolumeName,
  476. wszVolumeNameInternal, ARRAY_LEN(wszVolumeNameInternal)))
  477. ft.Throw( VSSDBG_VSSAPI, VSS_E_OBJECT_NOT_FOUND,
  478. L"GetVolumeNameForVolumeMountPoint(%s,...) "
  479. L"failed with error code 0x%08lx", pwszVolumeName, GetLastError());
  480. BS_ASSERT(::wcslen(wszVolumeNameInternal) != 0);
  481. BS_ASSERT(::IsVolMgmtVolumeName( wszVolumeNameInternal ));
  482. // Check if the volume is fixed (i.e. no CD-ROM, no removable)
  483. UINT uDriveType = ::GetDriveTypeW(wszVolumeNameInternal);
  484. if ( uDriveType != DRIVE_FIXED)
  485. ft.Throw( VSSDBG_VSSAPI, VSS_E_VOLUME_NOT_SUPPORTED,
  486. L"Encountering a non-fixed volume (%s) - %ud",
  487. pwszVolumeName, uDriveType);
  488. // Open the volume. Throw "object not found" if needed.
  489. CVssIOCTLChannel volumeIChannel;
  490. ft.hr = volumeIChannel.Open(ft, wszVolumeNameInternal, true, false, VSS_ICHANNEL_LOG_NONE, 0);
  491. if (ft.HrFailed())
  492. ft.Throw( VSSDBG_VSSAPI, VSS_E_VOLUME_NOT_SUPPORTED,
  493. L"Volume (%s) not supported for snapshots 0x%08lx",
  494. pwszVolumeName, ft.hr);
  495. // Check to see if there are existing snapshots
  496. ft.hr = volumeIChannel.Call(ft, IOCTL_VOLSNAP_QUERY_NAMES_OF_SNAPSHOTS, false);
  497. if (ft.HrFailed())
  498. ft.Throw( VSSDBG_VSSAPI, VSS_E_VOLUME_NOT_SUPPORTED,
  499. L"Volume (%s) not supported for snapshots 0x%08lx",
  500. pwszVolumeName, ft.hr);
  501. // Get the length of snapshot names multistring
  502. ULONG ulMultiszLen;
  503. volumeIChannel.Unpack(ft, &ulMultiszLen);
  504. // If the multistring is empty, then ulMultiszLen is necesarily 2
  505. // (i.e. two l"\0' characters)
  506. // Then mark the volume as snapshotted.
  507. if (ulMultiszLen != x_nEmptyVssMultiszLen)
  508. {
  509. (*pbSnapshotsPresent) = TRUE;
  510. // Bug 500069: Allow DEFRAG on Babbage snapshotted volumes
  511. (*plSnapshotCompatibility) = (/*VSS_SC_DISABLE_DEFRAG|*/VSS_SC_DISABLE_CONTENTINDEX);
  512. }
  513. }
  514. }
  515. } VSS_STANDARD_CATCH (ft);
  516. // Close handles
  517. if (NULL != shSCService) CloseServiceHandle (shSCService);
  518. if (NULL != shSCManager) CloseServiceHandle (shSCManager);
  519. // Convert the "volume not supported into S_OK.
  520. if (ft.hr == VSS_E_VOLUME_NOT_SUPPORTED)
  521. ft.hr = S_OK;
  522. return (ft.hr);
  523. } /* IsVolumeSnapshotted () */
  524. /*
  525. **++
  526. **
  527. ** Routine Description:
  528. **
  529. ** This routine is used to free the contents of hte VSS_SNASPHOT_PROP structure
  530. **
  531. **
  532. ** Arguments:
  533. **
  534. ** IN VSS_SNAPSHOT_PROP* pProp
  535. **
  536. **--
  537. */
  538. __declspec(dllexport) void APIENTRY VssFreeSnapshotProperties (
  539. IN VSS_SNAPSHOT_PROP* pProp
  540. )
  541. {
  542. CVssFunctionTracer ft (VSSDBG_VSSAPI, L"VssAPI::VssFreeSnapshotProperties");
  543. if (pProp) {
  544. ::CoTaskMemFree(pProp->m_pwszSnapshotDeviceObject);
  545. ::CoTaskMemFree(pProp->m_pwszOriginalVolumeName);
  546. ::CoTaskMemFree(pProp->m_pwszOriginatingMachine);
  547. ::CoTaskMemFree(pProp->m_pwszServiceMachine);
  548. ::CoTaskMemFree(pProp->m_pwszExposedName);
  549. ::CoTaskMemFree(pProp->m_pwszExposedPath);
  550. }
  551. } /* VssFreeSnapshotProperties () */