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.

2457 lines
84 KiB

  1. #include "stdafx.hxx"
  2. #include "vs_idl.hxx"
  3. #include "vss.h"
  4. #include "vswriter.h"
  5. #include "vsbackup.h"
  6. #include "vs_seh.hxx"
  7. #include "vs_trace.hxx"
  8. #include "vscoordint.h"
  9. //#include "vs_debug.hxx"
  10. #include "compont.h"
  11. #include <debug.h>
  12. #include <cwriter.h>
  13. #include <lmshare.h>
  14. #include <lmaccess.h>
  15. #include <time.h>
  16. // Globals
  17. BOOL g_bDebug = TRUE;
  18. BOOL g_bComponentBackup = TRUE;
  19. BOOL g_bBackupOnly = FALSE;
  20. BOOL g_bRestoreOnly = FALSE;
  21. BOOL g_bExcludeTestWriter = FALSE;
  22. WCHAR g_wszBackupDocumentFileName[MAX_PATH];
  23. WCHAR g_wszComponentsFileName[MAX_PATH];
  24. WCHAR g_wszSavedFilesDirectory[MAX_PATH];
  25. LONG g_lWriterWait = 0;
  26. bool g_bRestoreTest = false;
  27. bool g_lRestoreTestOptions = 0;
  28. VSS_BACKUP_TYPE g_BackupType = VSS_BT_DIFFERENTIAL;
  29. bool g_bBootableSystemState = false;
  30. bool g_bTestNewInterfaces = false;
  31. CComPtr<CWritersSelection> g_pWriterSelection;
  32. void TestSnapshotXML();
  33. void EnumVolumes();
  34. // forward declarations
  35. void CheckStatus(IVssBackupComponents *pvbc, LPCWSTR wszWhen,
  36. CSimpleMap<VSS_ID, HRESULT>* failedWriters = NULL);
  37. HRESULT ParseCommnadLine (int argc, WCHAR **argv);
  38. BOOL SaveBackupDocument(CComBSTR &bstr);
  39. BOOL LoadBackupDocument(CComBSTR &bstr);
  40. void LoadMetadataFile
  41. (
  42. VSS_ID idInstance,
  43. IVssExamineWriterMetadata **ppMetadataSaved
  44. );
  45. void DoCopyFile(LPCWSTR, LPCWSTR);
  46. void RestoreFiles(IVssBackupComponents *pvbc, const CSimpleMap<VSS_ID, HRESULT>& failedWriters);
  47. void SetSubcomponentsSelectedForRestore
  48. (
  49. IVssBackupComponents *pvbc,
  50. VSS_ID idInstance,
  51. IVssComponent *pComponent
  52. );
  53. void SaveFiles(IVssBackupComponents *pvbc, VSS_ID *rgSnapshotId, UINT cSnapshots);
  54. bool FindComponent
  55. (
  56. IVssExamineWriterMetadata *pMetadata,
  57. LPCWSTR wszLogicalPath,
  58. LPCWSTR wszComponentName,
  59. IVssWMComponent **ppComponent
  60. );
  61. BOOL AssertPrivilege( LPCWSTR privName )
  62. {
  63. HANDLE tokenHandle;
  64. BOOL stat = FALSE;
  65. if ( OpenProcessToken (GetCurrentProcess(),
  66. TOKEN_ADJUST_PRIVILEGES|TOKEN_QUERY,
  67. &tokenHandle))
  68. {
  69. LUID value;
  70. if ( LookupPrivilegeValue( NULL, privName, &value ) )
  71. {
  72. TOKEN_PRIVILEGES newState;
  73. DWORD error;
  74. newState.PrivilegeCount = 1;
  75. newState.Privileges[0].Luid = value;
  76. newState.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED_BY_DEFAULT|SE_PRIVILEGE_ENABLED;
  77. /*
  78. * We will always call GetLastError below, so clear
  79. * any prior error values on this thread.
  80. */
  81. SetLastError( ERROR_SUCCESS );
  82. stat = AdjustTokenPrivileges (tokenHandle,
  83. FALSE,
  84. &newState,
  85. (DWORD)0,
  86. NULL,
  87. NULL );
  88. /*
  89. * Supposedly, AdjustTokenPriveleges always returns TRUE
  90. * (even when it fails). So, call GetLastError to be
  91. * extra sure everything's cool.
  92. */
  93. if ( (error = GetLastError()) != ERROR_SUCCESS )
  94. {
  95. stat = FALSE;
  96. }
  97. if ( !stat )
  98. {
  99. wprintf( L"AdjustTokenPrivileges for %s failed with %d",
  100. privName,
  101. error );
  102. }
  103. }
  104. DWORD cbTokens;
  105. GetTokenInformation (tokenHandle,
  106. TokenPrivileges,
  107. NULL,
  108. 0,
  109. &cbTokens);
  110. TOKEN_PRIVILEGES *pTokens = (TOKEN_PRIVILEGES *) new BYTE[cbTokens];
  111. GetTokenInformation (tokenHandle,
  112. TokenPrivileges,
  113. pTokens,
  114. cbTokens,
  115. &cbTokens);
  116. delete pTokens;
  117. CloseHandle( tokenHandle );
  118. }
  119. return stat;
  120. }
  121. LPCWSTR GetStringFromUsageType (VSS_USAGE_TYPE eUsageType)
  122. {
  123. LPCWSTR pwszRetString = L"UNDEFINED";
  124. switch (eUsageType)
  125. {
  126. case VSS_UT_BOOTABLESYSTEMSTATE: pwszRetString = L"BootableSystemState"; break;
  127. case VSS_UT_SYSTEMSERVICE: pwszRetString = L"SystemService"; break;
  128. case VSS_UT_USERDATA: pwszRetString = L"UserData"; break;
  129. case VSS_UT_OTHER: pwszRetString = L"Other"; break;
  130. default:
  131. break;
  132. }
  133. return (pwszRetString);
  134. }
  135. LPCWSTR GetStringFromSourceType (VSS_SOURCE_TYPE eSourceType)
  136. {
  137. LPCWSTR pwszRetString = L"UNDEFINED";
  138. switch (eSourceType)
  139. {
  140. case VSS_ST_TRANSACTEDDB: pwszRetString = L"TransactionDb"; break;
  141. case VSS_ST_NONTRANSACTEDDB: pwszRetString = L"NonTransactionDb"; break;
  142. case VSS_ST_OTHER: pwszRetString = L"Other"; break;
  143. default:
  144. break;
  145. }
  146. return (pwszRetString);
  147. }
  148. LPCWSTR GetStringFromRestoreMethod (VSS_RESTOREMETHOD_ENUM eRestoreMethod)
  149. {
  150. LPCWSTR pwszRetString = L"UNDEFINED";
  151. switch (eRestoreMethod)
  152. {
  153. case VSS_RME_RESTORE_IF_NOT_THERE: pwszRetString = L"RestoreIfNotThere"; break;
  154. case VSS_RME_RESTORE_IF_CAN_REPLACE: pwszRetString = L"RestoreIfCanReplace"; break;
  155. case VSS_RME_STOP_RESTORE_START: pwszRetString = L"StopRestoreStart"; break;
  156. case VSS_RME_RESTORE_TO_ALTERNATE_LOCATION: pwszRetString = L"RestoreToAlternateLocation"; break;
  157. case VSS_RME_RESTORE_AT_REBOOT: pwszRetString = L"RestoreAtReboot"; break;
  158. case VSS_RME_RESTORE_AT_REBOOT_IF_CANNOT_REPLACE: pwszRetString = L"RestoreAtRebootIfCannotReplace"; break;
  159. case VSS_RME_CUSTOM: pwszRetString = L"Custom"; break;
  160. default:
  161. break;
  162. }
  163. return (pwszRetString);
  164. }
  165. LPCWSTR GetStringFromWriterRestoreMethod (VSS_WRITERRESTORE_ENUM eWriterRestoreMethod)
  166. {
  167. LPCWSTR pwszRetString = L"UNDEFINED";
  168. switch (eWriterRestoreMethod)
  169. {
  170. case VSS_WRE_NEVER: pwszRetString = L"RestoreNever"; break;
  171. case VSS_WRE_IF_REPLACE_FAILS: pwszRetString = L"RestoreIfReplaceFails"; break;
  172. case VSS_WRE_ALWAYS: pwszRetString = L"RestoreAlways"; break;
  173. default:
  174. break;
  175. }
  176. return (pwszRetString);
  177. }
  178. LPCWSTR GetStringFromComponentType (VSS_COMPONENT_TYPE eComponentType)
  179. {
  180. LPCWSTR pwszRetString = L"UNDEFINED";
  181. switch (eComponentType)
  182. {
  183. case VSS_CT_DATABASE: pwszRetString = L"Database"; break;
  184. case VSS_CT_FILEGROUP: pwszRetString = L"FileGroup"; break;
  185. default:
  186. break;
  187. }
  188. return (pwszRetString);
  189. }
  190. void PrintFiledesc(IVssWMFiledesc *pFiledesc, LPCWSTR wszDescription)
  191. {
  192. CComBSTR bstrPath;
  193. CComBSTR bstrFilespec;
  194. CComBSTR bstrAlternate;
  195. CComBSTR bstrDestination;
  196. bool bRecursive;
  197. DWORD dwTypeMask;
  198. HRESULT hr;
  199. CHECK_SUCCESS(pFiledesc->GetPath(&bstrPath));
  200. CHECK_SUCCESS(pFiledesc->GetFilespec(&bstrFilespec));
  201. CHECK_NOFAIL(pFiledesc->GetRecursive(&bRecursive));
  202. CHECK_NOFAIL(pFiledesc->GetAlternateLocation(&bstrAlternate));
  203. CHECK_NOFAIL(pFiledesc->GetBackupTypeMask(&dwTypeMask));
  204. wprintf (L"%s\n Path = %s, Filespec = %s, Recursive = %s, BackupTypeMask = 0x%x\n",
  205. wszDescription,
  206. bstrPath,
  207. bstrFilespec,
  208. bRecursive ? L"yes" : L"no",
  209. dwTypeMask);
  210. if (bstrAlternate && wcslen(bstrAlternate) > 0)
  211. wprintf(L" Alternate Location = %s\n", bstrAlternate);
  212. }
  213. // wait a maximum number of seconds before cancelling the operation
  214. void LoopWait
  215. (
  216. IVssAsync *pAsync,
  217. LONG seconds,
  218. LPCWSTR wszOperation
  219. )
  220. {
  221. // if debugging, allow one hour before cancelling operation
  222. if (g_bDebug)
  223. seconds = 3600;
  224. if (g_bTestNewInterfaces)
  225. {
  226. HRESULT hr = pAsync->Wait(seconds * 1000);
  227. if (hr != E_NOTIMPL)
  228. Error(hr, L"Expected IVssAsyncWait to return E_NOTIMPL for non-infinite argument");
  229. }
  230. clock_t start = clock();
  231. HRESULT hr, hrStatus;
  232. while(TRUE)
  233. {
  234. Sleep(1000);
  235. CHECK_SUCCESS(pAsync->QueryStatus(&hrStatus, NULL));
  236. if (hrStatus != VSS_S_ASYNC_PENDING)
  237. break;
  238. if (((clock() - start)/CLOCKS_PER_SEC) >= seconds)
  239. break;
  240. }
  241. if (hrStatus == VSS_S_ASYNC_PENDING)
  242. {
  243. CHECK_NOFAIL(pAsync->Cancel());
  244. wprintf(L"Called cancelled for %s.\n", wszOperation);
  245. }
  246. CHECK_SUCCESS(pAsync->QueryStatus(&hrStatus, NULL));
  247. CHECK_NOFAIL(hrStatus);
  248. }
  249. void UpdatePartialFileRanges(IVssComponent* pComponent, IVssBackupComponents* pvbc,
  250. VSS_ID id, VSS_COMPONENT_TYPE ct, BSTR bstrLogicalPath, BSTR bstrName)
  251. {
  252. UINT cPartialFiles;
  253. HRESULT hr;
  254. CHECK_SUCCESS(pComponent->GetPartialFileCount(&cPartialFiles));
  255. for(UINT iFile = 0; iFile < cPartialFiles; iFile++)
  256. {
  257. CComBSTR bstrPath;
  258. CComBSTR bstrFilename;
  259. CComBSTR bstrRanges;
  260. CComBSTR bstrMetadata;
  261. CHECK_SUCCESS(pComponent->GetPartialFile
  262. (
  263. iFile,
  264. &bstrPath,
  265. &bstrFilename,
  266. &bstrRanges,
  267. &bstrMetadata
  268. ));
  269. // always call this function to see what it does if there is no ranges file
  270. CHECK_SUCCESS(pvbc->SetRangesFilePath(id, ct, bstrLogicalPath, bstrName, iFile,bstrRanges ));
  271. }
  272. }
  273. void AddNewTargets(IVssBackupComponents* pvbc, VSS_ID id, VSS_COMPONENT_TYPE ct, BSTR bstrLogicalPath, BSTR bstrName)
  274. {
  275. // add a nonsensical new target. this is usually illegal, but this is a test program...
  276. pvbc->AddNewTarget(id, ct, bstrLogicalPath, bstrName, L"C:\\", L"foo.txt", false, L"D:\\");
  277. }
  278. void DoPrepareBackup(IVssBackupComponents *pvbc)
  279. {
  280. CComPtr<IVssAsync> pAsync;
  281. INT nPercentDone;
  282. HRESULT hrResult;
  283. HRESULT hr;
  284. CHECK_SUCCESS(pvbc->PrepareForBackup(&pAsync));
  285. LoopWait(pAsync, 5, L"PrepareForBackup");
  286. CHECK_SUCCESS(pAsync->QueryStatus(&hrResult, &nPercentDone));
  287. CHECK_NOFAIL(hrResult);
  288. }
  289. void DoSnapshotSet(IVssBackupComponents *pvbc, HRESULT &hrResult)
  290. {
  291. CComPtr<IVssAsync> pAsync;
  292. INT nPercentDone;
  293. HRESULT hr;
  294. CHECK_SUCCESS(pvbc->DoSnapshotSet (&pAsync));
  295. CHECK_SUCCESS(pAsync->Wait());
  296. CHECK_SUCCESS(pAsync->QueryStatus(&hrResult, &nPercentDone));
  297. }
  298. void DoBackupComplete(IVssBackupComponents *pvbc)
  299. {
  300. CComPtr<IVssAsync> pAsync;
  301. HRESULT hr;
  302. CHECK_SUCCESS(pvbc->BackupComplete(&pAsync));
  303. LoopWait(pAsync, 5, L"BackupComplete");
  304. }
  305. void DoRestore(IVssBackupComponents *pvbc)
  306. {
  307. CComPtr<IVssAsync> pAsync;
  308. HRESULT hr;
  309. if (g_bTestNewInterfaces)
  310. pvbc->SetRestoreState(VSS_RTYPE_OTHER);
  311. pvbc->GatherWriterMetadata(&pAsync);
  312. LoopWait(pAsync, 60, L"GetherWriterMetadata");
  313. pAsync = NULL;
  314. UINT cWriters, iWriter;
  315. CVssSimpleMap<VSS_ID, DWORD> schemas;
  316. CHECK_SUCCESS(pvbc->GetWriterMetadataCount(&cWriters));
  317. for(iWriter = 0; iWriter < cWriters; iWriter++)
  318. {
  319. CComPtr<IVssExamineWriterMetadata> pMetadata;
  320. VSS_ID idInstance, idWriter;
  321. CComBSTR bstrName;
  322. VSS_USAGE_TYPE usage;
  323. VSS_SOURCE_TYPE source;
  324. CHECK_SUCCESS(pvbc->GetWriterMetadata(iWriter, &idInstance, &pMetadata));
  325. CHECK_SUCCESS(pMetadata->GetIdentity(&idInstance, &idWriter, &bstrName, &usage, &source));
  326. DWORD schema = 0;
  327. CHECK_SUCCESS(pMetadata->GetBackupSchema(&schema));
  328. schemas.Add(idWriter, schema);
  329. }
  330. UINT cWriterComponents;
  331. CHECK_SUCCESS(pvbc->GetWriterComponentsCount(&cWriterComponents));
  332. for(UINT iWriterComponent = 0; iWriterComponent < cWriterComponents; iWriterComponent++)
  333. {
  334. CComPtr<IVssWriterComponentsExt> pWriter;
  335. CHECK_SUCCESS(pvbc->GetWriterComponents(iWriterComponent, &pWriter));
  336. VSS_ID idInstance;
  337. VSS_ID idWriter;
  338. UINT cComponents;
  339. CHECK_SUCCESS(pWriter->GetComponentCount(&cComponents));
  340. CHECK_SUCCESS(pWriter->GetWriterInfo(&idInstance, &idWriter));
  341. CComPtr<IVssExamineWriterMetadata> pStoredMetadata;
  342. if (g_wszSavedFilesDirectory[0] != L'\0')
  343. LoadMetadataFile(idInstance, &pStoredMetadata);
  344. for(UINT iComponent = 0; iComponent < cComponents; iComponent++)
  345. {
  346. CComPtr<IVssComponent> pComponent;
  347. CHECK_SUCCESS(pWriter->GetComponent(iComponent, &pComponent));
  348. CComBSTR bstrLogicalPath;
  349. CComBSTR bstrComponentName;
  350. CHECK_NOFAIL(pComponent->GetLogicalPath(&bstrLogicalPath));
  351. CHECK_SUCCESS(pComponent->GetComponentName(&bstrComponentName));
  352. // For RestoreOnly case, we check if the user provided a component selection
  353. BOOL bSelected = TRUE;
  354. if (g_bRestoreOnly && g_pWriterSelection)
  355. {
  356. // User provided a valid selection file
  357. bSelected = g_pWriterSelection->IsComponentSelected(idWriter, bstrLogicalPath, bstrComponentName);
  358. if (bSelected)
  359. {
  360. wprintf (L"\n Component \"%s\" is selected for Restore\n", bstrComponentName);
  361. }
  362. else
  363. {
  364. wprintf (L"\n Component \"%s\" is NOT selected for Restore\n", bstrComponentName);
  365. }
  366. }
  367. // get the matching component from the writer metadata document
  368. CComPtr<IVssWMComponent> pWriterComponent;
  369. PVSSCOMPONENTINFO pInfo = NULL;
  370. bool bSelectable = true, bSelectableForRestore = false;
  371. if (g_wszSavedFilesDirectory[0] != L'\0')
  372. {
  373. BS_VERIFY(FindComponent(pStoredMetadata, bstrLogicalPath, bstrComponentName, &pWriterComponent));
  374. CHECK_SUCCESS(pWriterComponent->GetComponentInfo(&pInfo));
  375. // BS_ASSERT(!bSelected || (pInfo->bSelectable || pInfo->bSelectableForRestore));
  376. bSelectable = pInfo->bSelectable;
  377. bSelectableForRestore = pInfo->bSelectableForRestore;
  378. }
  379. // get the component type
  380. VSS_COMPONENT_TYPE ct;
  381. CHECK_SUCCESS(pComponent->GetComponentType(&ct));
  382. if (bSelected)
  383. {
  384. hr = pvbc->SetSelectedForRestore
  385. (
  386. idWriter,
  387. ct,
  388. bstrLogicalPath,
  389. bstrComponentName,
  390. true
  391. );
  392. if (hr == VSS_E_OBJECT_NOT_FOUND)
  393. {
  394. wprintf(L"component %s\\%s was selected for restore, but the writer no longer "
  395. L"exists on the system\n", bstrLogicalPath, bstrComponentName);
  396. // BUGBUG: huge hack to fix the AD case. We eventually need to
  397. // BUGBUG: do something better here, but this is easiest for now.
  398. CHECK_SUCCESS(pvbc->SetRestoreOptions(idWriter,
  399. ct,
  400. bstrLogicalPath,
  401. bstrComponentName,
  402. L"RESTORE"
  403. ));
  404. }
  405. else
  406. {
  407. CHECK_SUCCESS(hr);
  408. }
  409. // SetSubcomponentsSelectedForRestore(pvbc, idInstance, pComponent);
  410. }
  411. if (g_wszSavedFilesDirectory[0] != L'\0')
  412. {
  413. pWriterComponent->FreeComponentInfo(pInfo);
  414. pInfo = NULL;
  415. }
  416. }
  417. UINT nSubcomponents = 0;
  418. const WCHAR* const * ppwszSubcomponents = NULL;
  419. if (g_bRestoreOnly && g_pWriterSelection)
  420. {
  421. nSubcomponents = g_pWriterSelection->GetSubcomponentsCount(idWriter);
  422. ppwszSubcomponents = g_pWriterSelection->GetSubcomponents(idWriter);
  423. };
  424. for (UINT iSubcomponent = 0; g_wszSavedFilesDirectory[0] != L'\0' &&
  425. iSubcomponent < nSubcomponents; iSubcomponent++)
  426. {
  427. // pull apart the logical path and component name
  428. CComBSTR bstrLogicalPath, bstrComponentName;
  429. WCHAR* lastSlash = wcsrchr(ppwszSubcomponents[iSubcomponent], L'\\');
  430. if (lastSlash != NULL)
  431. {
  432. *lastSlash = L'\0';
  433. bstrLogicalPath = ppwszSubcomponents[iSubcomponent];
  434. bstrComponentName = lastSlash + 1;
  435. *lastSlash = L'\\';
  436. }
  437. else
  438. {
  439. bstrComponentName = ppwszSubcomponents[iSubcomponent];
  440. }
  441. // look for the closest parent component that has been backed up
  442. CComBSTR bstrLogicalPathParent;
  443. CComBSTR bstrComponentNameParent;
  444. CComPtr<IVssComponent> pCurrentParent;
  445. unsigned int maxLength = 0;
  446. for(UINT iParentComponent = 0; iParentComponent < cComponents; iParentComponent++)
  447. {
  448. CComPtr<IVssComponent> pParentComponent ;
  449. CComBSTR bstrCurrentLPath;
  450. CComBSTR bstrCurrentCName;
  451. CHECK_SUCCESS(pWriter->GetComponent(iParentComponent, &pParentComponent));
  452. CHECK_NOFAIL(pParentComponent->GetLogicalPath(&bstrCurrentLPath));
  453. CHECK_SUCCESS(pParentComponent->GetComponentName(&bstrCurrentCName));
  454. CComBSTR bstrFullPath = bstrCurrentLPath;
  455. if (bstrFullPath)
  456. bstrFullPath += L"\\";
  457. bstrFullPath += bstrCurrentCName;
  458. if (!bstrFullPath)
  459. Error(E_OUTOFMEMORY, L"Ran out of memory");
  460. // check to see if we've found a parent component that's larger
  461. unsigned int currentLength = bstrFullPath.Length();
  462. if (bstrLogicalPath && wcsstr(bstrLogicalPath, bstrFullPath) == bstrLogicalPath &&
  463. currentLength > maxLength)
  464. {
  465. bstrLogicalPathParent = bstrCurrentLPath;
  466. bstrComponentNameParent = bstrCurrentCName;
  467. maxLength = currentLength;
  468. pCurrentParent = pParentComponent;
  469. }
  470. }
  471. // if maxLength is zero, we're trying to restore a subcomponent for a component
  472. // that wasn't backed up.
  473. BS_ASSERT(maxLength > 0);
  474. wprintf (L"\n SubComponent \"%s\" is selected for Restore\n", ppwszSubcomponents[iSubcomponent]);
  475. VSS_COMPONENT_TYPE ct;
  476. CHECK_SUCCESS(pCurrentParent->GetComponentType(&ct));
  477. // the parent component must be selected for restore
  478. hr = pvbc->SetSelectedForRestore
  479. (
  480. idWriter,
  481. ct,
  482. bstrLogicalPathParent,
  483. bstrComponentNameParent,
  484. true
  485. );
  486. if (hr != VSS_E_OBJECT_NOT_FOUND)
  487. CHECK_SUCCESS(hr);
  488. // BUGBUG: Should check bSelectableForRestore first
  489. CHECK_SUCCESS(pvbc->AddRestoreSubcomponent
  490. (
  491. idWriter,
  492. ct,
  493. bstrLogicalPathParent,
  494. bstrComponentNameParent,
  495. bstrLogicalPath,
  496. bstrComponentName,
  497. false
  498. ));
  499. }
  500. }
  501. CHECK_SUCCESS(pvbc->PreRestore(&pAsync));
  502. LoopWait(pAsync, 600, L"PreRestore");
  503. pAsync = NULL;
  504. CSimpleMap<VSS_ID, HRESULT> failedWriters;
  505. // CheckStatus(pvbc, L"After PreRestore");
  506. CheckStatus(pvbc, L"After PreRestore", &failedWriters);
  507. for(UINT iWriterComponent = 0; iWriterComponent < cWriterComponents; iWriterComponent++)
  508. {
  509. CComPtr<IVssWriterComponentsExt> pWriter;
  510. VSS_ID idWriter;
  511. VSS_ID idInstance;
  512. CHECK_SUCCESS(pvbc->GetWriterComponents(iWriterComponent, &pWriter));
  513. UINT cComponents;
  514. CHECK_SUCCESS(pWriter->GetComponentCount(&cComponents));
  515. CHECK_SUCCESS(pWriter->GetWriterInfo(&idInstance, &idWriter));
  516. for(UINT iComponent = 0; iComponent < cComponents; iComponent++)
  517. {
  518. CComPtr<IVssComponent> pComponent;
  519. CComBSTR bstrLogicalPath;
  520. CComBSTR bstrComponentName;
  521. CComBSTR bstrFailureMsg;
  522. CHECK_SUCCESS(pWriter->GetComponent(iComponent, &pComponent));
  523. VSS_COMPONENT_TYPE ct;
  524. CHECK_SUCCESS(pComponent->GetComponentType(&ct));
  525. CHECK_NOFAIL(pComponent->GetLogicalPath(&bstrLogicalPath));
  526. CHECK_SUCCESS(pComponent->GetComponentName(&bstrComponentName));
  527. CHECK_NOFAIL(pComponent->GetPreRestoreFailureMsg(&bstrFailureMsg));
  528. VSS_RESTORE_TARGET rt;
  529. CHECK_SUCCESS(pComponent->GetRestoreTarget(&rt));
  530. if (bstrFailureMsg || rt != VSS_RT_ORIGINAL)
  531. {
  532. wprintf(L"\nComponent Path=%s Name=%s\n",
  533. bstrLogicalPath ? bstrLogicalPath : L"",
  534. bstrComponentName);
  535. if (bstrFailureMsg)
  536. wprintf(L"\nPreRestoreFailureMsg=%s\n", bstrFailureMsg);
  537. wprintf(L"restore target = %s\n", WszFromRestoreTarget(rt));
  538. if (rt == VSS_RT_DIRECTED)
  539. PrintDirectedTargets(pComponent);
  540. wprintf(L"\n");
  541. }
  542. // we start off by saying that no files were restored. we will reset this attribute later
  543. CHECK_SUCCESS(pvbc->SetFileRestoreStatus(idWriter, ct, bstrLogicalPath, bstrComponentName, VSS_RS_NONE));
  544. if (g_bTestNewInterfaces)
  545. {
  546. UpdatePartialFileRanges(pComponent, pvbc, idWriter, ct, bstrLogicalPath, bstrComponentName);
  547. PrintPartialFiles(pComponent);
  548. PrintDifferencedFiles(pComponent);
  549. if (schemas.Lookup(idWriter) & VSS_BS_WRITER_SUPPORTS_NEW_TARGET)
  550. AddNewTargets(pvbc, idWriter, ct, bstrLogicalPath, bstrComponentName);
  551. }
  552. }
  553. wprintf(L"\n");
  554. }
  555. if (g_wszSavedFilesDirectory[0] != L'\0')
  556. RestoreFiles(pvbc, failedWriters);
  557. CHECK_SUCCESS(pvbc->PostRestore(&pAsync));
  558. LoopWait(pAsync, 600, L"PostRestore");
  559. pAsync = NULL;
  560. CheckStatus(pvbc, L"After PostRestore");
  561. for(UINT iWriterComponent = 0; iWriterComponent < cWriterComponents; iWriterComponent++)
  562. {
  563. CComPtr<IVssWriterComponentsExt> pWriter;
  564. CHECK_SUCCESS(pvbc->GetWriterComponents(iWriterComponent, &pWriter));
  565. UINT cComponents;
  566. CHECK_SUCCESS(pWriter->GetComponentCount(&cComponents));
  567. for(UINT iComponent = 0; iComponent < cComponents; iComponent++)
  568. {
  569. CComPtr<IVssComponent> pComponent;
  570. CComBSTR bstrLogicalPath;
  571. CComBSTR bstrComponentName;
  572. CComBSTR bstrFailureMsg;
  573. CHECK_SUCCESS(pWriter->GetComponent(iComponent, &pComponent));
  574. VSS_COMPONENT_TYPE ct;
  575. CHECK_SUCCESS(pComponent->GetComponentType(&ct));
  576. CHECK_NOFAIL(pComponent->GetLogicalPath(&bstrLogicalPath));
  577. CHECK_SUCCESS(pComponent->GetComponentName(&bstrComponentName));
  578. CHECK_NOFAIL(pComponent->GetPostRestoreFailureMsg(&bstrFailureMsg));
  579. if (bstrFailureMsg)
  580. {
  581. wprintf(L"\nComponent Path=%s Name=%s\n",
  582. bstrLogicalPath ? bstrLogicalPath : L"",
  583. bstrComponentName);
  584. if (bstrFailureMsg)
  585. wprintf(L"\nPostRestoreFailureMsg=%s\n", bstrFailureMsg);
  586. wprintf(L"\n");
  587. }
  588. }
  589. }
  590. wprintf(L"\n");
  591. }
  592. void DoAddToSnapshotSet
  593. (
  594. IN IVssBackupComponents *pvbc,
  595. IN BSTR bstrPath,
  596. IN LPWSTR wszVolumes,
  597. VSS_ID *rgpSnapshotId,
  598. UINT *pcSnapshot
  599. )
  600. {
  601. PWCHAR pwszPath = NULL;
  602. PWCHAR pwszMountPointName = NULL;
  603. WCHAR wszVolumeName [50];
  604. ULONG ulPathLength;
  605. ULONG ulMountpointBufferLength;
  606. HRESULT hr;
  607. ulPathLength = ExpandEnvironmentStringsW (bstrPath, NULL, 0);
  608. pwszPath = (PWCHAR) malloc (ulPathLength * sizeof (WCHAR));
  609. ulPathLength = ExpandEnvironmentStringsW (bstrPath, pwszPath, ulPathLength);
  610. ulMountpointBufferLength = GetFullPathName (pwszPath, 0, NULL, NULL);
  611. pwszMountPointName = (PWCHAR) malloc (ulMountpointBufferLength * sizeof (WCHAR));
  612. bool fSuccess = false;
  613. if (wcslen(pwszPath) >= 3 && pwszPath[1] == L':' && pwszPath[2] == L'\\')
  614. {
  615. wcsncpy(pwszMountPointName, pwszPath, 3);
  616. pwszMountPointName[3] = L'\0';
  617. fSuccess = true;
  618. }
  619. else
  620. {
  621. if (GetVolumePathNameW (pwszPath, pwszMountPointName, ulMountpointBufferLength))
  622. fSuccess = true;
  623. else
  624. {
  625. BS_ASSERT(FALSE);
  626. printf("GetVolumeMountPointW failed with error %d\nfor path %s.\n", GetLastError(), pwszPath);
  627. }
  628. }
  629. if (fSuccess)
  630. {
  631. if (!GetVolumeNameForVolumeMountPointW (pwszMountPointName, wszVolumeName, sizeof (wszVolumeName) / sizeof (WCHAR)))
  632. printf("GetVolumeNameForVolumeMountPointW failed with error %d\nfor path %s.\n", GetLastError(), wszVolumeName);
  633. else
  634. {
  635. // wprintf(L"EXTRADBG: Volume <%s> <%s> is required for snapshot\n", wszVolumeName, pwszMountPointName);
  636. if (NULL == wcsstr (wszVolumes, wszVolumeName))
  637. {
  638. if (L'\0' != wszVolumes [0])
  639. wcscat (wszVolumes, L";");
  640. wcscat (wszVolumes, wszVolumeName);
  641. CHECK_SUCCESS
  642. (
  643. pvbc->AddToSnapshotSet
  644. (
  645. wszVolumeName,
  646. GUID_NULL,
  647. &rgpSnapshotId[*pcSnapshot]
  648. )
  649. );
  650. wprintf(L"Volume <%s> <%s>\n", wszVolumeName, pwszMountPointName);
  651. wprintf(L"is added to the snapshot set\n\n");
  652. *pcSnapshot += 1;
  653. }
  654. }
  655. }
  656. if (NULL != pwszPath) free (pwszPath);
  657. if (NULL != pwszMountPointName) free (pwszMountPointName);
  658. }
  659. static LPCWSTR s_rgwszStates[] =
  660. {
  661. NULL,
  662. L"STABLE",
  663. L"WAIT_FOR_FREEZE",
  664. L"WAIT_FOR_THAW",
  665. L"WAIT_FOR_POST_SNAPSHOT",
  666. L"WAIT_FOR_BACKUP_COMPLETE",
  667. L"FAILED_AT_IDENTIFY",
  668. L"FAILED_AT_PREPARE_BACKUP",
  669. L"FAILED_AT_PREPARE_SNAPSHOT",
  670. L"FAILED_AT_FREEZE",
  671. L"FAILED_AT_THAW",
  672. L"FAILED_AT_POST_SNAPSHOT",
  673. L"FAILED_AT_BACKUP_COMPLETE",
  674. L"FAILED_AT_PRE_RESTORE",
  675. L"FAILED_AT_POST_RESTORE"
  676. };
  677. void CheckStatus(IVssBackupComponents *pvbc, LPCWSTR wszWhen,
  678. CSimpleMap<VSS_ID, HRESULT>* failedWriters)
  679. {
  680. unsigned cWriters;
  681. CComPtr<IVssAsync> pAsync;
  682. HRESULT hr;
  683. CHECK_NOFAIL(pvbc->GatherWriterStatus(&pAsync));
  684. CHECK_NOFAIL(pAsync->Wait());
  685. CHECK_NOFAIL(pvbc->GetWriterStatusCount(&cWriters));
  686. wprintf(L"\n\nstatus %s (%d writers)\n\n", wszWhen, cWriters);
  687. for(unsigned iWriter = 0; iWriter < cWriters; iWriter++)
  688. {
  689. VSS_ID idInstance;
  690. VSS_ID idWriter;
  691. VSS_WRITER_STATE status;
  692. CComBSTR bstrWriter;
  693. HRESULT hrWriterFailure;
  694. CHECK_SUCCESS(pvbc->GetWriterStatus (iWriter,
  695. &idInstance,
  696. &idWriter,
  697. &bstrWriter,
  698. &status,
  699. &hrWriterFailure));
  700. wprintf (L"Status for writer %s: %s(0x%08lx%s%s)\n",
  701. bstrWriter,
  702. s_rgwszStates[status],
  703. hrWriterFailure,
  704. SUCCEEDED (hrWriterFailure) ? L"" : L" - ",
  705. GetStringFromFailureType (hrWriterFailure));
  706. if (failedWriters && FAILED(hrWriterFailure))
  707. failedWriters->Add(idInstance, hrWriterFailure);
  708. }
  709. pvbc->FreeWriterStatus();
  710. }
  711. void PrintDifferencedFilesForComponents(IVssBackupComponents* pvbc)
  712. {
  713. HRESULT hr;
  714. UINT cWriterComponents;
  715. CHECK_SUCCESS(pvbc->GetWriterComponentsCount(&cWriterComponents));
  716. for(UINT iWriterComponent = 0; iWriterComponent < cWriterComponents; iWriterComponent++)
  717. {
  718. CComPtr<IVssWriterComponentsExt> pWriter;
  719. CHECK_SUCCESS(pvbc->GetWriterComponents(iWriterComponent, &pWriter));
  720. UINT cComponents;
  721. CHECK_SUCCESS(pWriter->GetComponentCount(&cComponents));
  722. for(UINT iComponent = 0; iComponent < cComponents; iComponent++)
  723. {
  724. CComPtr<IVssComponent> pComponent;
  725. CHECK_SUCCESS(pWriter->GetComponent(iComponent, &pComponent));
  726. CComBSTR bstrLogicalPath;
  727. CComBSTR bstrComponentName;
  728. CHECK_NOFAIL(pComponent->GetLogicalPath(&bstrLogicalPath));
  729. CHECK_SUCCESS(pComponent->GetComponentName(&bstrComponentName));
  730. UINT cDifferencedFiles;
  731. CHECK_SUCCESS(pComponent->GetDifferencedFilesCount(&cDifferencedFiles));
  732. if (cDifferencedFiles > 0)
  733. {
  734. wprintf(L"\nDifferenced files for Component Path=%s Name=%s\n",
  735. bstrLogicalPath ? bstrLogicalPath : L"",
  736. bstrComponentName);
  737. PrintDifferencedFiles(pComponent);
  738. }
  739. }
  740. }
  741. }
  742. void PrintPartialFilesForComponents(IVssBackupComponents *pvbc)
  743. {
  744. HRESULT hr;
  745. UINT cWriterComponents;
  746. CHECK_SUCCESS(pvbc->GetWriterComponentsCount(&cWriterComponents));
  747. for(UINT iWriterComponent = 0; iWriterComponent < cWriterComponents; iWriterComponent++)
  748. {
  749. CComPtr<IVssWriterComponentsExt> pWriter;
  750. CHECK_SUCCESS(pvbc->GetWriterComponents(iWriterComponent, &pWriter));
  751. UINT cComponents;
  752. CHECK_SUCCESS(pWriter->GetComponentCount(&cComponents));
  753. for(UINT iComponent = 0; iComponent < cComponents; iComponent++)
  754. {
  755. CComPtr<IVssComponent> pComponent;
  756. CHECK_SUCCESS(pWriter->GetComponent(iComponent, &pComponent));
  757. CComBSTR bstrLogicalPath;
  758. CComBSTR bstrComponentName;
  759. CHECK_NOFAIL(pComponent->GetLogicalPath(&bstrLogicalPath));
  760. CHECK_SUCCESS(pComponent->GetComponentName(&bstrComponentName));
  761. UINT cPartialFiles;
  762. CHECK_SUCCESS(pComponent->GetPartialFileCount(&cPartialFiles));
  763. if (cPartialFiles > 0)
  764. {
  765. wprintf(L"\nPartial files for Component Path=%s Name=%s\n",
  766. bstrLogicalPath ? bstrLogicalPath : L"",
  767. bstrComponentName);
  768. PrintPartialFiles(pComponent);
  769. }
  770. }
  771. }
  772. }
  773. BOOL SaveBackupDocument(CComBSTR &bstr)
  774. {
  775. HANDLE hFile = INVALID_HANDLE_VALUE;
  776. DWORD dwByteToWrite = (bstr.Length() + 1) * sizeof(WCHAR);
  777. DWORD dwBytesWritten;
  778. // Create the file (override if exists)
  779. hFile = CreateFile(g_wszBackupDocumentFileName, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
  780. if (hFile == INVALID_HANDLE_VALUE)
  781. {
  782. return FALSE;
  783. }
  784. // Write the XML string
  785. if (! WriteFile(hFile, (LPVOID)(BSTR)bstr, dwByteToWrite, &dwBytesWritten, NULL))
  786. {
  787. CloseHandle(hFile);
  788. return FALSE;
  789. }
  790. CloseHandle(hFile);
  791. return TRUE;
  792. }
  793. BOOL LoadBackupDocument(CComBSTR &bstr)
  794. {
  795. HANDLE hFile = INVALID_HANDLE_VALUE;
  796. DWORD dwBytesToRead = 0;
  797. DWORD dwBytesRead;
  798. // Create the file (must exist)
  799. hFile = CreateFile(g_wszBackupDocumentFileName, GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
  800. if (hFile == INVALID_HANDLE_VALUE)
  801. {
  802. return FALSE;
  803. }
  804. if ((dwBytesToRead = GetFileSize(hFile, NULL)) <= 0)
  805. {
  806. CloseHandle(hFile);
  807. return FALSE;
  808. }
  809. WCHAR *pwszBuffer = NULL;
  810. DWORD dwNofChars = 0;
  811. if ((dwBytesToRead % sizeof(WCHAR)) != 0)
  812. {
  813. CloseHandle(hFile);
  814. wprintf(L"Invalid file lenght %lu for backup document file\n", dwBytesToRead);
  815. return FALSE;
  816. }
  817. else
  818. {
  819. dwNofChars = dwBytesToRead / sizeof(WCHAR);
  820. }
  821. pwszBuffer = (PWCHAR) malloc (dwNofChars * sizeof (WCHAR));
  822. if (! pwszBuffer)
  823. {
  824. CloseHandle(hFile);
  825. wprintf(L"Failed to allocate memory for backup document buffer\n");
  826. return FALSE;
  827. }
  828. // Read the XML string
  829. if (! ReadFile(hFile, (LPVOID)pwszBuffer, dwBytesToRead, &dwBytesRead, NULL))
  830. {
  831. CloseHandle(hFile);
  832. free (pwszBuffer);
  833. return FALSE;
  834. }
  835. CloseHandle(hFile);
  836. if (dwBytesToRead != dwBytesRead)
  837. {
  838. free (pwszBuffer);
  839. wprintf(L"Backup document file is supposed to have %lu bytes but only %lu bytes are read\n", dwBytesToRead, dwBytesRead);
  840. return FALSE;
  841. }
  842. // Copy to output bstr
  843. bstr.Empty();
  844. if (bstr.Append(pwszBuffer, dwNofChars) != S_OK) // don't copy the NULL
  845. {
  846. free (pwszBuffer);
  847. wprintf(L"Failed to copy from temporary buffer into Backup Document XML string\n");
  848. return FALSE;
  849. }
  850. return TRUE;
  851. }
  852. HRESULT ParseCommandLine (int argc, WCHAR **argv)
  853. {
  854. HRESULT hr = S_OK;
  855. int iArg;
  856. g_wszBackupDocumentFileName[0] = L'\0';
  857. g_wszComponentsFileName[0] = L'\0';
  858. g_wszSavedFilesDirectory[0] = L'\0';
  859. try
  860. {
  861. for (iArg=1; iArg<argc; iArg++)
  862. {
  863. if ((_wcsicmp(argv[iArg], L"/W") == 0) || (_wcsicmp(argv[iArg], L"-W") == 0))
  864. {
  865. iArg++;
  866. if (iArg >= argc)
  867. {
  868. wprintf(L"/W switch missing wait-time argument\n");
  869. throw(E_INVALIDARG);
  870. }
  871. if (argv[iArg][0] >= L'0' && argv[iArg][0] <= L'9'||
  872. argv[iArg][0] >= L'a' && argv[iArg][0] <= L'f')
  873. {
  874. if (argv[iArg][0] >= L'0' && argv[iArg][0] <= L'9')
  875. g_lWriterWait = argv[iArg][0] - L'0';
  876. else
  877. g_lWriterWait = argv[iArg][0] - L'a' + 10;
  878. wprintf(L"Writer wait parameter=%ld.\n", g_lWriterWait);
  879. }
  880. else
  881. {
  882. wprintf(L"/W switch is followed by invalid wait-time argument\n");
  883. throw(E_INVALIDARG);
  884. }
  885. }
  886. else if ((_wcsicmp(argv[iArg], L"/B") == 0) || (_wcsicmp(argv[iArg], L"-B") == 0))
  887. {
  888. g_bBackupOnly = TRUE;
  889. wprintf(L"Asked to do Backup only\n");
  890. }
  891. else if ((_wcsicmp(argv[iArg], L"/R") == 0) || (_wcsicmp(argv[iArg], L"-R") == 0))
  892. {
  893. g_bRestoreOnly = TRUE;
  894. wprintf(L"Asked to do Restore only\n");
  895. }
  896. else if ((_wcsicmp(argv[iArg], L"/E") == 0) || (_wcsicmp(argv[iArg], L"-E") == 0))
  897. {
  898. g_bExcludeTestWriter = TRUE;
  899. wprintf(L"Asked to exclude BETEST test writer\n");
  900. }
  901. else if ((_wcsicmp(argv[iArg], L"/O") == 0) || (_wcsicmp(argv[iArg], L"-O") == 0))
  902. {
  903. g_bBootableSystemState = true;
  904. wprintf(L"Asked to specify BootableSystemState backup\n");
  905. }
  906. else if ((_wcsicmp(argv[iArg], L"/T") == 0) || (_wcsicmp(argv[iArg], L"-T") == 0))
  907. {
  908. iArg++;
  909. if (iArg >= argc)
  910. {
  911. wprintf(L"/T switch missing backup-type parameter\n");
  912. throw(E_INVALIDARG);
  913. }
  914. int nBackupType = _wtoi(argv[iArg]);
  915. if ((nBackupType <= (int)VSS_BT_UNDEFINED) || (nBackupType > (int)VSS_BT_OTHER))
  916. {
  917. wprintf(L"backup-type parameter is invalid\n");
  918. throw(E_INVALIDARG);
  919. }
  920. g_BackupType = (VSS_BACKUP_TYPE)nBackupType;
  921. wprintf(L"backup-type to use is %d\n", nBackupType);
  922. }
  923. else if ((_wcsicmp(argv[iArg], L"/S") == 0) || (_wcsicmp(argv[iArg], L"-S") == 0))
  924. {
  925. iArg++;
  926. if (iArg >= argc)
  927. {
  928. wprintf(L"/S switch missing file-name to save/load backup document\n");
  929. throw(E_INVALIDARG);
  930. }
  931. if (wcslen(argv[iArg]) >= MAX_PATH - 1)
  932. {
  933. wprintf(L"Path for file-name to save/load backup document is limited to %d\n", MAX_PATH - 2);
  934. throw(E_INVALIDARG);
  935. }
  936. wcscpy(g_wszBackupDocumentFileName, argv[iArg]);
  937. wprintf(L"File name to save/load Backup Document is \"%s\"\n", g_wszBackupDocumentFileName);
  938. }
  939. else if ((_wcsicmp(argv[iArg], L"/D") == 0) || (_wcsicmp(argv[iArg], L"-D") == 0))
  940. {
  941. iArg++;
  942. if (iArg >= argc)
  943. {
  944. wprintf(L"/D switch missing directory path to save/load backup document\n");
  945. throw(E_INVALIDARG);
  946. }
  947. if (wcslen(argv[iArg]) >= MAX_PATH - 2)
  948. {
  949. wprintf(L"Path to save/restore backup files is limited to %d\n", MAX_PATH - 2);
  950. throw(E_INVALIDARG);
  951. }
  952. wcscpy(g_wszSavedFilesDirectory, argv[iArg]);
  953. if (g_wszSavedFilesDirectory[wcslen(g_wszSavedFilesDirectory)-1] != L'\\')
  954. wcscat(g_wszSavedFilesDirectory, L"\\");
  955. wprintf(L"Directory to save/restore backup files is \"%s\"\n", g_wszSavedFilesDirectory);
  956. DoCopyFile(NULL, g_wszSavedFilesDirectory);
  957. // replace test writer so that it tests restore options
  958. g_bRestoreTest = true;
  959. }
  960. else if ((_wcsicmp(argv[iArg], L"/C") == 0) || (_wcsicmp(argv[iArg], L"-C") == 0))
  961. {
  962. iArg++;
  963. if (iArg >= argc)
  964. {
  965. wprintf(L"/C switch missing file-name to load components selection from\n");
  966. throw(E_INVALIDARG);
  967. }
  968. if (wcslen(argv[iArg]) >= MAX_PATH)
  969. {
  970. wprintf(L"Path for file-name to load components selection is limited to %d\n", MAX_PATH);
  971. throw(E_INVALIDARG);
  972. }
  973. wcscpy(g_wszComponentsFileName, argv[iArg]);
  974. wprintf(L"File name for Components Selection is \"%s\"\n", g_wszComponentsFileName);
  975. }
  976. else if ((_wcsicmp(argv[iArg], L"/N") == 0) || (_wcsicmp(argv[iArg], L"-N") == 0))
  977. {
  978. g_bTestNewInterfaces = true;
  979. wprintf(L"Asked to test new interfaces\n");
  980. }
  981. else if ((_wcsicmp(argv[iArg], L"/?") == 0) || (_wcsicmp(argv[iArg], L"-?") == 0))
  982. {
  983. // Print help
  984. wprintf(L"BETEST [/B] [/R] [/E] [/T backup-type] [/S filename] [/C filename] [/D path]\n\n");
  985. wprintf(L"/B\t\t Performs backup only\n");
  986. wprintf(L"/R\t\t Performs restore only\n");
  987. wprintf(L"\t\t Restore-only must be used with /S for a backup document file\n\n");
  988. wprintf(L"/E\t\t Excludes BETEST test writer\n");
  989. wprintf(L"/O\t\t Specifies BootableSystemState backup\n");
  990. wprintf(L"/T\t\t Chooses backup type\n");
  991. wprintf(L"\t\t <backup-type> parameter should be one of VSS_BACKUP_TYPE\n");
  992. wprintf(L"\t\t enum values (Look in vss.h for VSS_BACKUP_TYPE type)\n");
  993. wprintf(L"\t\t Default is VSS_BT_DIFFERENTIAL\n\n");
  994. wprintf(L"/S filename\t In case of backup, saves the backup document to file\n");
  995. wprintf(L"\t\t In case of restore-only, loads the backup document from file\n\n");
  996. wprintf(L"/D path\t In case of backup, saves the files to be backed up to this location.\n");
  997. wprintf(L"\t\t In case of restore, restores the backed up files from this location.\n\n");
  998. wprintf(L"/N Test new backup infrastructure interfaces.\n\n");
  999. wprintf(L"/C filename\t Selects which components to backup/restore based on the file\n\n");
  1000. wprintf(L"Components selection file format:\n");
  1001. wprintf(L"\"<writer-id>\": \"<component-logical-path>\", ...\"<component-logical-path>\" : '\"<subcomponent-logical-path>,...\";\n\n");
  1002. wprintf(L"\t\twhere several writers may be specified, each one with its own components and subcomponents\n");
  1003. wprintf(L"\t\t<writer-id> is in standard GUID format\n");
  1004. wprintf(L"\t\t<component-logical-path> is either logical-path, logical-path\\component-name\n");
  1005. wprintf(L"\t\tor component-name-only (if there's no logical path)\n\n");
  1006. wprintf(L"For example:\n");
  1007. wprintf(L"\t\t\"{c0577ae6-d741-452a-8cba-99d744008c04}\": \"\\mydatabases\", \"\\mylogfiles\";\n");
  1008. wprintf(L"\t\t\"{f2436e37-09f5-41af-9b2a-4ca2435dbfd5}\" : \"Registry\" ;\n\n");
  1009. wprintf(L"If no argument is specified, BETEST performs a backup followed by a restore\n");
  1010. wprintf(L"choosing all components reported by all writers\n\n");
  1011. // Set hr such that program terminates
  1012. hr = S_FALSE;
  1013. }
  1014. else
  1015. {
  1016. wprintf(L"Invalid switch\n");
  1017. throw(E_INVALIDARG);
  1018. }
  1019. }
  1020. // Check for invalid combinations
  1021. if (g_bBackupOnly && g_bRestoreOnly)
  1022. {
  1023. wprintf(L"Cannot backup-only and restore-only at the same time...\n");
  1024. throw(E_INVALIDARG);
  1025. }
  1026. if (g_bRestoreOnly && (wcslen(g_wszBackupDocumentFileName) == 0))
  1027. {
  1028. wprintf(L"Cannot restore-only with no backup-document to use.\nUse the /S switch for specifying a file name with backup document from a previous BETEST backup");
  1029. throw(E_INVALIDARG);
  1030. }
  1031. }
  1032. catch (HRESULT hrParse)
  1033. {
  1034. hr = hrParse;
  1035. }
  1036. return hr;
  1037. }
  1038. bool IsWriterPath(LPCWSTR wszPath)
  1039. {
  1040. if (wszPath[0] == L'{')
  1041. {
  1042. LPCWSTR wszNext = wcschr(wszPath + 1, L'}');
  1043. if (wszNext == NULL)
  1044. return false;
  1045. if (wszNext - wszPath != 37)
  1046. return false;
  1047. WCHAR buf[39];
  1048. memcpy(buf, wszPath, 38*sizeof(WCHAR));
  1049. buf[38] = L'\0';
  1050. VSS_ID id;
  1051. if (FAILED(CLSIDFromString(buf, &id)))
  1052. return false;
  1053. return wcslen(wszNext) >= 3 &&
  1054. wszNext[1] == L':' &&
  1055. wszNext[2] == L'\\';
  1056. }
  1057. return false;
  1058. }
  1059. typedef VSS_ID *PVSS_ID;
  1060. bool DoAddComponent
  1061. (
  1062. IVssBackupComponents *pvbc,
  1063. IVssExamineWriterMetadata *pMetadata,
  1064. VSS_ID idInstance,
  1065. VSS_ID idWriter,
  1066. LPCWSTR wszLogicalPath,
  1067. LPCWSTR wszComponentName,
  1068. LPWSTR wszVolumes,
  1069. PVSS_ID &rgpSnapshotId,
  1070. UINT &cSnapshot
  1071. );
  1072. // add a child component to the backup components document
  1073. bool AddChildComponent
  1074. (
  1075. IVssBackupComponents *pvbc,
  1076. VSS_ID id,
  1077. CComBSTR bstrLogicalPath,
  1078. CComBSTR bstrComponentName,
  1079. LPWSTR wszVolumes,
  1080. PVSS_ID &rgpSnapshotId,
  1081. UINT &cSnapshot
  1082. )
  1083. {
  1084. HRESULT hr;
  1085. UINT cWriters, iWriter;
  1086. CHECK_SUCCESS(pvbc->GetWriterMetadataCount(&cWriters));
  1087. CComPtr<IVssExamineWriterMetadata> pMetadata;
  1088. VSS_ID idInstance = GUID_NULL;
  1089. for(iWriter = 0; iWriter < cWriters; iWriter++)
  1090. {
  1091. CHECK_SUCCESS(pvbc->GetWriterMetadata(iWriter, &idInstance, &pMetadata));
  1092. VSS_ID idInstanceT;
  1093. VSS_ID idWriter;
  1094. CComBSTR bstrWriterName;
  1095. VSS_USAGE_TYPE usage;
  1096. VSS_SOURCE_TYPE source;
  1097. CHECK_SUCCESS(pMetadata->GetIdentity
  1098. (
  1099. &idInstanceT,
  1100. &idWriter,
  1101. &bstrWriterName,
  1102. &usage,
  1103. &source
  1104. ));
  1105. if (idWriter == id)
  1106. break;
  1107. pMetadata = NULL;
  1108. }
  1109. if (iWriter > cWriters)
  1110. {
  1111. wprintf(L"Cannot backup component: %s\\%s\nWriter doesn't exist.\n\n", bstrLogicalPath, bstrComponentName);
  1112. return false;
  1113. }
  1114. wprintf(L"Backing up subcomponent: %s\\%s.\n\n", bstrLogicalPath, bstrComponentName);
  1115. return DoAddComponent
  1116. (
  1117. pvbc,
  1118. pMetadata,
  1119. idInstance,
  1120. id,
  1121. bstrLogicalPath,
  1122. bstrComponentName,
  1123. wszVolumes,
  1124. rgpSnapshotId,
  1125. cSnapshot
  1126. );
  1127. }
  1128. bool FindComponent
  1129. (
  1130. IVssExamineWriterMetadata *pMetadata,
  1131. LPCWSTR wszLogicalPath,
  1132. LPCWSTR wszComponentName,
  1133. IVssWMComponent **ppComponent
  1134. )
  1135. {
  1136. HRESULT hr;
  1137. UINT cIncludeFiles, cExcludeFiles, cComponents;
  1138. CHECK_SUCCESS(pMetadata->GetFileCounts(
  1139. &cIncludeFiles,
  1140. &cExcludeFiles,
  1141. &cComponents));
  1142. for(UINT iComponent = 0; iComponent < cComponents; iComponent++)
  1143. {
  1144. CComPtr<IVssWMComponent> pComponent;
  1145. CHECK_SUCCESS(pMetadata->GetComponent(iComponent, &pComponent));
  1146. PVSSCOMPONENTINFO pInfo;
  1147. CHECK_SUCCESS(pComponent->GetComponentInfo(&pInfo));
  1148. if (_wcsicmp(wszComponentName, pInfo->bstrComponentName) == 0 &&
  1149. ((wszLogicalPath == NULL &&
  1150. (pInfo->bstrLogicalPath == NULL ||
  1151. wcslen(pInfo->bstrLogicalPath) == 0)) ||
  1152. (wszLogicalPath != NULL &&
  1153. pInfo->bstrLogicalPath != NULL &&
  1154. _wcsicmp(wszLogicalPath, pInfo->bstrLogicalPath) == 0)))
  1155. {
  1156. pComponent->FreeComponentInfo(pInfo);
  1157. break;
  1158. }
  1159. pComponent->FreeComponentInfo(pInfo);
  1160. }
  1161. if (iComponent < cComponents)
  1162. {
  1163. CHECK_SUCCESS(pMetadata->GetComponent(iComponent, ppComponent));
  1164. return true;
  1165. }
  1166. return false;
  1167. }
  1168. bool UpdateSnapshotSet
  1169. (
  1170. IVssBackupComponents *pvbc,
  1171. IVssWMComponent* pComponent,
  1172. PVSSCOMPONENTINFO pInfo,
  1173. LPWSTR wszVolumes,
  1174. PVSS_ID &rgpSnapshotId,
  1175. UINT &cSnapshot
  1176. )
  1177. {
  1178. HRESULT hr = S_OK;
  1179. bool bOneSelected = false;
  1180. for(UINT i = 0; i < pInfo->cFileCount; i++)
  1181. {
  1182. CComPtr<IVssWMFiledesc> pFiledesc;
  1183. CHECK_SUCCESS(pComponent->GetFile(i, &pFiledesc));
  1184. CComBSTR bstrPath;
  1185. CHECK_SUCCESS(pFiledesc->GetPath(&bstrPath));
  1186. DoAddToSnapshotSet(pvbc, bstrPath, wszVolumes, rgpSnapshotId, &cSnapshot);
  1187. bOneSelected = true;
  1188. PrintFiledesc(pFiledesc, L" FileGroupFile");
  1189. }
  1190. for(UINT i = 0; i < pInfo->cDatabases; i++)
  1191. {
  1192. CComPtr<IVssWMFiledesc> pFiledesc;
  1193. CHECK_SUCCESS(pComponent->GetDatabaseFile(i, &pFiledesc));
  1194. CComBSTR bstrPath;
  1195. CHECK_SUCCESS(pFiledesc->GetPath(&bstrPath));
  1196. DoAddToSnapshotSet(pvbc, bstrPath, wszVolumes, rgpSnapshotId, &cSnapshot);
  1197. bOneSelected = true;
  1198. PrintFiledesc(pFiledesc, L" DatabaseFile");
  1199. }
  1200. for(UINT i = 0; i < pInfo->cLogFiles; i++)
  1201. {
  1202. CComPtr<IVssWMFiledesc> pFiledesc;
  1203. CHECK_SUCCESS(pComponent->GetDatabaseLogFile(i, &pFiledesc));
  1204. CComBSTR bstrPath;
  1205. CHECK_SUCCESS(pFiledesc->GetPath(&bstrPath));
  1206. DoAddToSnapshotSet(pvbc, bstrPath, wszVolumes, rgpSnapshotId, &cSnapshot);
  1207. bOneSelected = true;
  1208. PrintFiledesc(pFiledesc, L" DatabaseLogFile");
  1209. }
  1210. return bOneSelected;
  1211. }
  1212. bool DoAddComponent
  1213. (
  1214. IVssBackupComponents *pvbc,
  1215. IVssExamineWriterMetadata *pMetadata,
  1216. VSS_ID idInstance,
  1217. VSS_ID idWriter,
  1218. LPCWSTR wszLogicalPath,
  1219. LPCWSTR wszComponentName,
  1220. LPWSTR wszVolumes,
  1221. PVSS_ID &rgpSnapshotId,
  1222. UINT &cSnapshot
  1223. )
  1224. {
  1225. HRESULT hr;
  1226. // was at least one file selected
  1227. bool bAtLeastOneSelected = false;
  1228. CComPtr<IVssWMComponent> pComponent;
  1229. if (!FindComponent
  1230. (
  1231. pMetadata,
  1232. wszLogicalPath,
  1233. wszComponentName,
  1234. &pComponent
  1235. ))
  1236. {
  1237. wprintf(L"Component is not found: " WSTR_GUID_FMT L":\\%s\\%s",
  1238. GUID_PRINTF_ARG(idWriter),
  1239. wszLogicalPath ? wszLogicalPath : L"",
  1240. wszComponentName);
  1241. return false;
  1242. }
  1243. PVSSCOMPONENTINFO pInfo;
  1244. CHECK_SUCCESS(pComponent->GetComponentInfo(&pInfo));
  1245. hr = pvbc->AddComponent
  1246. (
  1247. idInstance,
  1248. idWriter,
  1249. pInfo->type,
  1250. pInfo->bstrLogicalPath,
  1251. pInfo->bstrComponentName
  1252. );
  1253. if (hr == VSS_E_OBJECT_ALREADY_EXISTS)
  1254. return false;
  1255. CHECK_SUCCESS(hr);
  1256. if (pInfo->type == VSS_CT_DATABASE &&
  1257. pInfo->bstrLogicalPath &&
  1258. wcscmp(pInfo->bstrLogicalPath, L"\\mydatabases") == 0 &&
  1259. wcscmp(pInfo->bstrComponentName, L"db1") == 0)
  1260. {
  1261. CHECK_SUCCESS(pvbc->SetPreviousBackupStamp
  1262. (
  1263. idWriter,
  1264. pInfo->type,
  1265. pInfo->bstrLogicalPath,
  1266. pInfo->bstrComponentName,
  1267. L"LASTFULLBACKUP"
  1268. ));
  1269. CHECK_SUCCESS(pvbc->SetBackupOptions
  1270. (
  1271. idWriter,
  1272. pInfo->type,
  1273. pInfo->bstrLogicalPath,
  1274. pInfo->bstrComponentName,
  1275. L"DOFASTINCREMENAL"
  1276. ));
  1277. }
  1278. // add volumes to the current snapshot set
  1279. bAtLeastOneSelected = UpdateSnapshotSet(pvbc, pComponent, pInfo, wszVolumes, rgpSnapshotId, cSnapshot);
  1280. // add volumes to the current snapshot set for all implicitly-selected components
  1281. CComBSTR bstrFullPath = wszLogicalPath;
  1282. if (bstrFullPath)
  1283. bstrFullPath += L"\\";
  1284. bstrFullPath += wszComponentName;
  1285. if (!bstrFullPath)
  1286. Error(E_OUTOFMEMORY, L"Ran out of memory");
  1287. UINT cIncludeFiles = 0, cExcludeFiles = 0, cComponents = 0;
  1288. CHECK_SUCCESS(pMetadata->GetFileCounts(&cIncludeFiles, &cExcludeFiles, &cComponents));
  1289. for (UINT iComponent = 0; iComponent < cComponents; iComponent++)
  1290. {
  1291. CComPtr<IVssWMComponent> pCurrent;
  1292. CHECK_SUCCESS(pMetadata->GetComponent(iComponent, &pCurrent));
  1293. PVSSCOMPONENTINFO pCurrentInfo = NULL;
  1294. CHECK_SUCCESS(pCurrent->GetComponentInfo(&pCurrentInfo));
  1295. if (pCurrentInfo->bstrLogicalPath &&
  1296. wcsstr(pCurrentInfo->bstrLogicalPath, bstrFullPath) == pCurrentInfo->bstrLogicalPath)
  1297. {
  1298. bAtLeastOneSelected = UpdateSnapshotSet(pvbc, pCurrent, pCurrentInfo, wszVolumes, rgpSnapshotId, cSnapshot)
  1299. || bAtLeastOneSelected;
  1300. }
  1301. pCurrent->FreeComponentInfo(pCurrentInfo);
  1302. }
  1303. if (g_bTestNewInterfaces)
  1304. {
  1305. for (unsigned i = 0; i < pInfo->cDependencies; i++)
  1306. {
  1307. CComPtr<IVssWMDependency> pDependency;
  1308. CHECK_SUCCESS(pComponent->GetDependency(i, &pDependency));
  1309. VSS_ID writerId;
  1310. CComBSTR logicalPath, componentName;
  1311. CHECK_SUCCESS(pDependency->GetWriterId(&writerId));
  1312. CHECK_NOFAIL(pDependency->GetLogicalPath(&logicalPath));
  1313. CHECK_SUCCESS(pDependency->GetComponentName(&componentName));
  1314. if (AddChildComponent(pvbc, writerId, logicalPath, componentName, wszVolumes, rgpSnapshotId, cSnapshot))
  1315. bAtLeastOneSelected = TRUE;
  1316. }
  1317. }
  1318. pComponent->FreeComponentInfo(pInfo);
  1319. return bAtLeastOneSelected;
  1320. }
  1321. // find component in the backup components document
  1322. bool FindComponentInDoc
  1323. (
  1324. IVssBackupComponents *pvbc,
  1325. VSS_ID idWriter,
  1326. LPCWSTR wszLogicalPath,
  1327. LPCWSTR wszComponentName,
  1328. IVssComponent **ppComponent,
  1329. VSS_ID *pidInstance
  1330. )
  1331. {
  1332. HRESULT hr;
  1333. UINT cWriterComponents;
  1334. CHECK_SUCCESS(pvbc->GetWriterComponentsCount(&cWriterComponents));
  1335. for(UINT iWriterComponent = 0; iWriterComponent < cWriterComponents; iWriterComponent++)
  1336. {
  1337. CComPtr<IVssWriterComponentsExt> pWriter;
  1338. CHECK_SUCCESS(pvbc->GetWriterComponents(iWriterComponent, &pWriter));
  1339. VSS_ID idInstanceT;
  1340. VSS_ID idWriterT;
  1341. CHECK_SUCCESS(pWriter->GetWriterInfo(&idInstanceT, &idWriterT));
  1342. if (idWriter == idWriterT)
  1343. {
  1344. UINT cComponents;
  1345. CHECK_SUCCESS(pWriter->GetComponentCount(&cComponents));
  1346. for(UINT iComponent = 0; iComponent < cComponents; iComponent++)
  1347. {
  1348. CComPtr<IVssComponent> pComponent;
  1349. CHECK_SUCCESS(pWriter->GetComponent(iComponent, &pComponent));
  1350. CComBSTR bstrLogicalPath;
  1351. CComBSTR bstrComponentName;
  1352. CHECK_NOFAIL(pComponent->GetLogicalPath(&bstrLogicalPath));
  1353. CHECK_SUCCESS(pComponent->GetComponentName(&bstrComponentName));
  1354. if (_wcsicmp(bstrComponentName, wszComponentName) == 0 &&
  1355. ((!wszLogicalPath && !bstrLogicalPath) ||
  1356. (wszLogicalPath && bstrLogicalPath &&
  1357. _wcsicmp(wszLogicalPath, bstrLogicalPath) == 0)))
  1358. {
  1359. CHECK_SUCCESS(pWriter->GetComponent(iComponent, ppComponent));
  1360. *pidInstance = idInstanceT;
  1361. return true;
  1362. }
  1363. }
  1364. }
  1365. }
  1366. return false;
  1367. }
  1368. void SetSubcomponentSelectedForRestore
  1369. (
  1370. IVssBackupComponents *pvbc,
  1371. LPCWSTR wszComponentPath,
  1372. LPCWSTR wszComponentName
  1373. )
  1374. {
  1375. HRESULT hr;
  1376. BS_ASSERT(IsWriterPath(wszComponentPath));
  1377. VSS_ID id;
  1378. WCHAR buf[39];
  1379. memcpy(buf, wszComponentPath, 38*sizeof(WCHAR));
  1380. buf[38] = L'\0';
  1381. CLSIDFromString(buf, &id);
  1382. LPCWSTR wszLogicalPath = NULL;
  1383. if (wcslen(wszComponentPath) > 40)
  1384. wszLogicalPath = wszComponentPath + 40;
  1385. CComPtr<IVssComponent> pComponent;
  1386. VSS_ID idInstance;
  1387. if (!FindComponentInDoc
  1388. (
  1389. pvbc,
  1390. id,
  1391. wszLogicalPath,
  1392. wszComponentName,
  1393. &pComponent,
  1394. &idInstance
  1395. ))
  1396. {
  1397. wprintf(L"Subcomponent %s\\%s was not found.\n\n", wszComponentPath, wszComponentName);
  1398. BS_ASSERT(FALSE);
  1399. throw E_UNEXPECTED;
  1400. }
  1401. bool bSelectedForRestore;
  1402. CHECK_SUCCESS(pComponent->IsSelectedForRestore(&bSelectedForRestore))
  1403. // if component is already selected for restore, then do nothing.
  1404. if (!bSelectedForRestore)
  1405. {
  1406. VSS_COMPONENT_TYPE ct;
  1407. CComBSTR bstrLogicalPath;
  1408. CComBSTR bstrComponentName;
  1409. CHECK_SUCCESS(pComponent->GetComponentType(&ct));
  1410. CHECK_NOFAIL(pComponent->GetLogicalPath(&bstrLogicalPath));
  1411. CHECK_NOFAIL(pComponent->GetComponentName(&bstrComponentName));
  1412. CHECK_SUCCESS(pvbc->SetSelectedForRestore(
  1413. id,
  1414. ct,
  1415. bstrLogicalPath,
  1416. bstrComponentName,
  1417. true
  1418. ));
  1419. SetSubcomponentsSelectedForRestore(pvbc, idInstance, pComponent);
  1420. }
  1421. }
  1422. // determine if any subcomponents of a component selected for restore
  1423. // should also be selected for restore
  1424. void SetSubcomponentsSelectedForRestore
  1425. (
  1426. IVssBackupComponents *pvbc,
  1427. VSS_ID idInstance,
  1428. IVssComponent *pComponent
  1429. )
  1430. {
  1431. HRESULT hr;
  1432. CComPtr<IVssExamineWriterMetadata> pWriterMetadata;
  1433. if (g_wszSavedFilesDirectory[0] == L'\0')
  1434. return;
  1435. LoadMetadataFile(idInstance, &pWriterMetadata);
  1436. CComBSTR bstrLogicalPath;
  1437. CComBSTR bstrComponentName;
  1438. CHECK_NOFAIL(pComponent->GetLogicalPath(&bstrLogicalPath));
  1439. CHECK_SUCCESS(pComponent->GetComponentName(&bstrComponentName));
  1440. CComPtr<IVssWMComponent> pWMComponent;
  1441. if (!FindComponent
  1442. (
  1443. pWriterMetadata,
  1444. bstrLogicalPath,
  1445. bstrComponentName,
  1446. &pWMComponent
  1447. ))
  1448. {
  1449. wprintf(L"Component %s\\%s cannot be found.\n", bstrLogicalPath, bstrComponentName);
  1450. BS_ASSERT(FALSE);
  1451. throw E_UNEXPECTED;
  1452. }
  1453. PVSSCOMPONENTINFO pInfo;
  1454. CHECK_SUCCESS(pWMComponent->GetComponentInfo(&pInfo));
  1455. unsigned i;
  1456. for(i = 0; i < pInfo->cFileCount; i++)
  1457. {
  1458. CComPtr<IVssWMFiledesc> pFiledesc;
  1459. CHECK_SUCCESS(pWMComponent->GetFile(i, &pFiledesc));
  1460. CComBSTR bstrPath;
  1461. CHECK_SUCCESS(pFiledesc->GetPath(&bstrPath));
  1462. if (IsWriterPath(bstrPath))
  1463. {
  1464. CComBSTR bstrComponentName;
  1465. CHECK_SUCCESS(pFiledesc->GetFilespec(&bstrComponentName));
  1466. SetSubcomponentSelectedForRestore(pvbc, bstrPath, bstrComponentName);
  1467. }
  1468. }
  1469. for(i = 0; i < pInfo->cDatabases; i++)
  1470. {
  1471. CComPtr<IVssWMFiledesc> pFiledesc;
  1472. CHECK_SUCCESS(pWMComponent->GetDatabaseFile(i, &pFiledesc));
  1473. CComBSTR bstrPath;
  1474. CHECK_SUCCESS(pFiledesc->GetPath(&bstrPath));
  1475. if (IsWriterPath(bstrPath))
  1476. {
  1477. CComBSTR bstrComponentName;
  1478. CHECK_SUCCESS(pFiledesc->GetFilespec(&bstrComponentName));
  1479. SetSubcomponentSelectedForRestore(pvbc, bstrPath, bstrComponentName);
  1480. }
  1481. }
  1482. for(i = 0; i < pInfo->cLogFiles; i++)
  1483. {
  1484. CComPtr<IVssWMFiledesc> pFiledesc;
  1485. CHECK_SUCCESS(pWMComponent->GetDatabaseLogFile(i, &pFiledesc));
  1486. CComBSTR bstrPath;
  1487. CHECK_SUCCESS(pFiledesc->GetPath(&bstrPath));
  1488. if (IsWriterPath(bstrPath))
  1489. {
  1490. CComBSTR bstrComponentName;
  1491. CHECK_SUCCESS(pFiledesc->GetFilespec(&bstrComponentName));
  1492. SetSubcomponentSelectedForRestore(pvbc, bstrPath, bstrComponentName);
  1493. }
  1494. }
  1495. pWMComponent->FreeComponentInfo(pInfo);
  1496. }
  1497. void TestRevertInterfaces()
  1498. {
  1499. HRESULT hr = S_OK;
  1500. CComPtr<IVssBackupComponents> pComp;
  1501. CHECK_SUCCESS(::CreateVssBackupComponents(&pComp));
  1502. if (pComp->RevertToSnapshot(GUID_NULL, true) != E_NOTIMPL)
  1503. Error(E_NOTIMPL, L"Expected IVssBackupComponents::RevertToSnapshot to return E_NOTIMPL");
  1504. CComPtr<IVssAsync> pAsync;
  1505. if(pComp->QueryRevertStatus(L"C:", &pAsync) != E_NOTIMPL)
  1506. Error(E_NOTIMPL, L"Expected IVssBackupComponents::QueryRevertStatus to return E_NOTIMPL");
  1507. CComPtr<IVssCoordinator> pCoord;
  1508. CHECK_SUCCESS(::CoCreateInstance
  1509. (
  1510. CLSID_VSSCoordinator,
  1511. NULL,
  1512. CLSCTX_ALL,
  1513. IID_IVssCoordinator,
  1514. (void**)&(pCoord)));
  1515. if (pCoord->RevertToSnapshot(GUID_NULL, true) != E_NOTIMPL)
  1516. Error(E_NOTIMPL, L"Expected IVssCoordinator::RevertToSnapshot to return E_NOTIMPL");
  1517. if(pCoord->QueryRevertStatus(L"C:", &pAsync) != E_NOTIMPL)
  1518. Error(E_NOTIMPL, L"Expected IVssCoordinator::QueryRevertStatus to return E_NOTIMPL");
  1519. }
  1520. void TestBackupShutdown()
  1521. {
  1522. HRESULT hr = S_OK;
  1523. HRESULT hrStatus = S_OK;
  1524. VSS_ID* writerInstances = NULL;
  1525. UINT cWriters = 0;
  1526. wprintf(L"Testing BackupShutdown interface\n");
  1527. CComPtr<IVssBackupComponents> pComp;
  1528. CHECK_SUCCESS(::CreateVssBackupComponents(&pComp));
  1529. CHECK_SUCCESS(pComp->InitializeForBackup());
  1530. CHECK_SUCCESS(pComp->SetBackupState(false, true, VSS_BT_OTHER, false));
  1531. CComPtr<IVssAsync> pAsync;
  1532. CHECK_SUCCESS(pComp->GatherWriterMetadata(&pAsync));
  1533. CHECK_SUCCESS(pAsync->Wait());
  1534. CHECK_SUCCESS(pAsync->QueryStatus(&hrStatus, NULL));
  1535. CHECK_NOFAIL(hrStatus);
  1536. pAsync = NULL;
  1537. VSS_ID idSet, idSnap;
  1538. CHECK_SUCCESS(pComp->StartSnapshotSet(&idSet));
  1539. CHECK_SUCCESS(pComp->AddToSnapshotSet(L"C:\\", GUID_NULL, &idSnap));
  1540. wprintf(L"BackupShutdown should not now be called\n");
  1541. pComp = NULL;
  1542. CHECK_SUCCESS(::CreateVssBackupComponents(&pComp));
  1543. CHECK_SUCCESS(pComp->InitializeForBackup());
  1544. CHECK_SUCCESS(pComp->SetBackupState(false, true, VSS_BT_OTHER, false));
  1545. CHECK_SUCCESS(pComp->GatherWriterMetadata(&pAsync));
  1546. CHECK_SUCCESS(pAsync->Wait());
  1547. CHECK_SUCCESS(pAsync->QueryStatus(&hrStatus, NULL));
  1548. CHECK_NOFAIL(hrStatus);
  1549. pAsync = NULL;
  1550. // store a list of writer instances
  1551. CHECK_SUCCESS(pComp->GetWriterMetadataCount(&cWriters));
  1552. writerInstances = new VSS_ID[cWriters];
  1553. if (writerInstances == NULL)
  1554. Error(E_OUTOFMEMORY, L"Ran out of memory");
  1555. for (UINT x = 0; x < cWriters; x++)
  1556. {
  1557. CComPtr<IVssExamineWriterMetadata> pMeta;
  1558. CHECK_SUCCESS(pComp->GetWriterMetadata(x, &writerInstances[x], &pMeta));
  1559. }
  1560. CHECK_SUCCESS(pComp->StartSnapshotSet(&idSet));
  1561. CHECK_SUCCESS(pComp->AddToSnapshotSet(L"C:\\", GUID_NULL, &idSnap));
  1562. CHECK_SUCCESS(pComp->PrepareForBackup(&pAsync));
  1563. CHECK_SUCCESS(pAsync->Wait());
  1564. CHECK_SUCCESS(pAsync->QueryStatus(&hrStatus, NULL));
  1565. CHECK_NOFAIL(hrStatus);
  1566. pAsync = NULL;
  1567. CHECK_SUCCESS(pComp->DoSnapshotSet(&pAsync));
  1568. CHECK_SUCCESS(pAsync->Wait());
  1569. CHECK_SUCCESS(pAsync->QueryStatus(&hrStatus, NULL));
  1570. CHECK_NOFAIL(hrStatus);
  1571. pAsync = NULL;
  1572. wprintf(L"BackupSutdown should now be called for snapshot-set id " WSTR_GUID_FMT
  1573. L"\n", GUID_PRINTF_ARG(idSet));
  1574. pComp = NULL;
  1575. CComPtr<IVssCoordinator> pCoord;
  1576. CHECK_SUCCESS(::CoCreateInstance
  1577. (
  1578. CLSID_VSSCoordinator,
  1579. NULL,
  1580. CLSCTX_ALL,
  1581. IID_IVssCoordinator,
  1582. (void**)&(pCoord)));
  1583. CHECK_SUCCESS(pCoord->StartSnapshotSet(&idSet));
  1584. CHECK_SUCCESS(pCoord->AddToSnapshotSet(L"C:\\", GUID_NULL, &idSnap));
  1585. CHECK_SUCCESS(pCoord->SetWriterInstances(cWriters, writerInstances));
  1586. CHECK_SUCCESS(pCoord->DoSnapshotSet(NULL, &pAsync));
  1587. CHECK_SUCCESS(pAsync->Wait());
  1588. CHECK_SUCCESS(pAsync->QueryStatus(&hrStatus, NULL));
  1589. CHECK_NOFAIL(hrStatus);
  1590. pAsync = NULL;
  1591. wprintf(L"BackupSutdown should now be called for snapshot-set id " WSTR_GUID_FMT
  1592. L"\n", GUID_PRINTF_ARG(idSet));
  1593. CHECK_SUCCESS(pCoord->StartSnapshotSet(&idSet));
  1594. delete [] writerInstances;
  1595. }
  1596. extern "C" __cdecl wmain(int argc, WCHAR **argv)
  1597. {
  1598. WCHAR wszVolumes[2048];
  1599. wszVolumes[0] = L'\0';
  1600. UINT cSnapshot = 0;
  1601. VSS_ID rgpSnapshotId[64];
  1602. CTestVssWriter *pInstance = NULL;
  1603. bool bCreated = false;
  1604. bool bSubscribed = false;
  1605. HRESULT hrMain = S_OK;
  1606. bool bCoInitializeSucceeded = false;
  1607. HRESULT hr = S_OK;
  1608. CComBSTR bstrXML;
  1609. BOOL bXMLSaved = FALSE;
  1610. // Parse command line arguments
  1611. if (ParseCommandLine(argc, argv) != S_OK)
  1612. {
  1613. // Don't throw since we want to avoid assertions here - we can return safely
  1614. return (3);
  1615. }
  1616. CHECK_SUCCESS(CoInitializeEx(NULL, COINIT_MULTITHREADED));
  1617. // Initialize COM security
  1618. CHECK_SUCCESS
  1619. (
  1620. CoInitializeSecurity
  1621. (
  1622. NULL, // IN PSECURITY_DESCRIPTOR pSecDesc,
  1623. -1, // IN LONG cAuthSvc,
  1624. NULL, // IN SOLE_AUTHENTICATION_SERVICE *asAuthSvc,
  1625. NULL, // IN void *pReserved1,
  1626. RPC_C_AUTHN_LEVEL_CONNECT, // IN DWORD dwAuthnLevel,
  1627. RPC_C_IMP_LEVEL_IMPERSONATE, // IN DWORD dwImpLevel,
  1628. NULL, // IN void *pAuthList,
  1629. EOAC_NONE, // IN DWORD dwCapabilities,
  1630. NULL // IN void *pReserved3
  1631. )
  1632. );
  1633. bCoInitializeSucceeded = true;
  1634. if ( !AssertPrivilege( SE_BACKUP_NAME ) )
  1635. {
  1636. wprintf( L"AssertPrivilege returned error, rc:%d\n", GetLastError() );
  1637. return 2;
  1638. }
  1639. // Get chosen components for backup and/or restore
  1640. if (wcslen(g_wszComponentsFileName) > 0)
  1641. {
  1642. g_pWriterSelection = CWritersSelection::CreateInstance();
  1643. if (g_pWriterSelection == NULL)
  1644. {
  1645. wprintf(L"allocation failure\n");
  1646. DebugBreak();
  1647. }
  1648. if (g_pWriterSelection->BuildChosenComponents(g_wszComponentsFileName) != S_OK)
  1649. {
  1650. wprintf(L"Component selection in %s is ignored due to a failure in processing the file\n", g_wszComponentsFileName);
  1651. g_pWriterSelection = 0;
  1652. }
  1653. }
  1654. // EnumVolumes();
  1655. // TestSnapshotXML();
  1656. if (! g_bExcludeTestWriter) {
  1657. pInstance = new CTestVssWriter(g_bRestoreTest, g_bTestNewInterfaces, g_lWriterWait, g_lRestoreTestOptions);
  1658. if (pInstance == NULL)
  1659. {
  1660. wprintf(L"allocation failure\n");
  1661. DebugBreak();
  1662. }
  1663. bCreated = true;
  1664. pInstance->Initialize();
  1665. CHECK_SUCCESS(pInstance->Subscribe());
  1666. bSubscribed = true;
  1667. }
  1668. if (g_bTestNewInterfaces)
  1669. {
  1670. TestRevertInterfaces();
  1671. TestBackupShutdown();
  1672. }
  1673. if (! g_bRestoreOnly)
  1674. {
  1675. CComBSTR strSnapshotSetId = "12345678-1234-1234-1234-1234567890ab";
  1676. CComPtr<IVssBackupComponents> pvbc;
  1677. CHECK_SUCCESS(CreateVssBackupComponents(&pvbc));
  1678. CHECK_SUCCESS(pvbc->InitializeForBackup());
  1679. CHECK_SUCCESS(pvbc->SetBackupState (true,
  1680. g_bBootableSystemState,
  1681. g_BackupType,
  1682. true));
  1683. unsigned cWriters;
  1684. CComPtr<IVssAsync> pAsync;
  1685. CHECK_NOFAIL(pvbc->GatherWriterMetadata(&pAsync));
  1686. LoopWait(pAsync, 30, L"GatherWriterMetadata");
  1687. CHECK_NOFAIL(pvbc->GetWriterMetadataCount(&cWriters));
  1688. VSS_ID id;
  1689. while(TRUE)
  1690. {
  1691. hr = pvbc->StartSnapshotSet(&id);
  1692. if (hr == S_OK)
  1693. break;
  1694. if (hr == VSS_E_SNAPSHOT_SET_IN_PROGRESS)
  1695. Sleep(1000);
  1696. else
  1697. CHECK_SUCCESS(hr);
  1698. }
  1699. BOOL bAtLeastOneSelected = FALSE;
  1700. for(unsigned iWriter = 0; iWriter < cWriters; iWriter++)
  1701. {
  1702. CComPtr<IVssExamineWriterMetadata> pMetadata;
  1703. VSS_ID idInstance;
  1704. CHECK_SUCCESS(pvbc->GetWriterMetadata(iWriter, &idInstance, &pMetadata));
  1705. VSS_ID idInstanceT;
  1706. VSS_ID idWriter;
  1707. CComBSTR bstrWriterName;
  1708. VSS_USAGE_TYPE usage;
  1709. VSS_SOURCE_TYPE source;
  1710. CHECK_SUCCESS(pMetadata->GetIdentity
  1711. (
  1712. &idInstanceT,
  1713. &idWriter,
  1714. &bstrWriterName,
  1715. &usage,
  1716. &source
  1717. ));
  1718. wprintf (L"\n\n");
  1719. if (memcmp(&idInstance, &idInstanceT, sizeof(VSS_ID)) != 0)
  1720. {
  1721. wprintf(L"Instance id mismatch\n");
  1722. DebugBreak();
  1723. }
  1724. WCHAR *pwszInstanceId;
  1725. WCHAR *pwszWriterId;
  1726. UuidToString(&idInstance, &pwszInstanceId);
  1727. UuidToString(&idWriter, &pwszWriterId);
  1728. wprintf (L"WriterName = %s\n\n"
  1729. L" WriterId = %s\n"
  1730. L" InstanceId = %s\n"
  1731. L" UsageType = %d (%s)\n"
  1732. L" SourceType = %d (%s)\n",
  1733. bstrWriterName,
  1734. pwszWriterId,
  1735. pwszInstanceId,
  1736. usage,
  1737. GetStringFromUsageType (usage),
  1738. source,
  1739. GetStringFromSourceType (source));
  1740. RpcStringFree(&pwszInstanceId);
  1741. RpcStringFree(&pwszWriterId);
  1742. unsigned cIncludeFiles, cExcludeFiles, cComponents;
  1743. CHECK_SUCCESS(pMetadata->GetFileCounts (&cIncludeFiles,
  1744. &cExcludeFiles,
  1745. &cComponents));
  1746. CComBSTR bstrPath;
  1747. CComBSTR bstrFilespec;
  1748. CComBSTR bstrAlternate;
  1749. CComBSTR bstrDestination;
  1750. unsigned i;
  1751. for(i = 0; i < cIncludeFiles; i++)
  1752. {
  1753. CComPtr<IVssWMFiledesc> pFiledesc;
  1754. CHECK_SUCCESS(pMetadata->GetIncludeFile(i, &pFiledesc));
  1755. PrintFiledesc(pFiledesc, L"\n Include File");
  1756. }
  1757. for(i = 0; i < cExcludeFiles; i++)
  1758. {
  1759. CComPtr<IVssWMFiledesc> pFiledesc;
  1760. CHECK_SUCCESS(pMetadata->GetExcludeFile(i, &pFiledesc));
  1761. PrintFiledesc(pFiledesc, L"\n Exclude File");
  1762. }
  1763. if (g_bTestNewInterfaces)
  1764. {
  1765. DWORD schema = 0;
  1766. CHECK_SUCCESS(pMetadata->GetBackupSchema(&schema));
  1767. wprintf(L" BackupSchema = 0x%x\n", schema);
  1768. }
  1769. for(unsigned iComponent = 0; iComponent < cComponents; iComponent++)
  1770. {
  1771. CComPtr<IVssWMComponent> pComponent;
  1772. PVSSCOMPONENTINFO pInfo;
  1773. CHECK_SUCCESS(pMetadata->GetComponent(iComponent, &pComponent));
  1774. CHECK_SUCCESS(pComponent->GetComponentInfo(&pInfo));
  1775. wprintf (L"\n"
  1776. L" Component %d, type = %d (%s)\n"
  1777. L" LogicalPath = %s\n"
  1778. L" Name = %s\n"
  1779. L" Caption = %s\n",
  1780. iComponent,
  1781. pInfo->type,
  1782. GetStringFromComponentType (pInfo->type),
  1783. pInfo->bstrLogicalPath,
  1784. pInfo->bstrComponentName,
  1785. pInfo->bstrCaption);
  1786. wprintf (L" RestoreMetadata = %s\n"
  1787. L" NotifyOnBackupComplete = %s\n"
  1788. L" Selectable = %s\n"
  1789. L" SelectableForRestore = %s\n"
  1790. L" ComponentFlags = 0x%x\n",
  1791. pInfo->bRestoreMetadata ? L"yes" : L"no",
  1792. pInfo->bNotifyOnBackupComplete ? L"yes" : L"no",
  1793. pInfo->bSelectable ? L"yes" : L"no",
  1794. pInfo->bSelectableForRestore ? L"yes" : L"no",
  1795. pInfo->dwComponentFlags);
  1796. if (g_bTestNewInterfaces)
  1797. {
  1798. for (unsigned iDependency = 0; iDependency < pInfo->cDependencies; iDependency++)
  1799. {
  1800. CComPtr<IVssWMDependency> pDependency;
  1801. CHECK_NOFAIL(pComponent->GetDependency(iDependency, &pDependency));
  1802. VSS_ID writerId;
  1803. CComBSTR logicalPath, componentName;
  1804. CHECK_SUCCESS(pDependency->GetWriterId(&writerId));
  1805. CHECK_NOFAIL(pDependency->GetLogicalPath(&logicalPath));
  1806. CHECK_SUCCESS(pDependency->GetComponentName(&componentName));
  1807. wprintf (L" (Dependent Component): WriterId " WSTR_GUID_FMT L"\n"
  1808. L" Logical Path %s\n"
  1809. L" Name %s\n",
  1810. GUID_PRINTF_ARG(writerId),
  1811. logicalPath,
  1812. componentName);
  1813. }
  1814. }
  1815. BOOL bSelected = TRUE;
  1816. if (g_pWriterSelection)
  1817. {
  1818. // User provided a valid selection file
  1819. bSelected = g_pWriterSelection->IsComponentSelected(idWriter, pInfo->bstrLogicalPath, pInfo->bstrComponentName);
  1820. if (bSelected)
  1821. {
  1822. // if (!pInfo->bSelectable && !pInfo->bSelectableForRestore)
  1823. // {
  1824. // Error(E_UNEXPECTED, L"\na completely non-selectable component was selected!\n");
  1825. // }
  1826. wprintf (L"\n Component \"%s\" IS selected for Backup\n\n", pInfo->bstrComponentName);
  1827. }
  1828. else
  1829. {
  1830. wprintf (L"\n Component \"%s\" is NOT selected for Backup\n\n", pInfo->bstrComponentName);
  1831. }
  1832. }
  1833. // only add selectable components to the document
  1834. // BUGBUG: should add non-selectable components only if no selectable ancestor
  1835. if (bSelected)
  1836. {
  1837. PVSS_ID rgSnapshotIds = rgpSnapshotId;
  1838. if (DoAddComponent
  1839. (
  1840. pvbc,
  1841. pMetadata,
  1842. idInstance,
  1843. idWriter,
  1844. pInfo->bstrLogicalPath,
  1845. pInfo->bstrComponentName,
  1846. wszVolumes,
  1847. rgSnapshotIds,
  1848. cSnapshot
  1849. ))
  1850. bAtLeastOneSelected = true;
  1851. }
  1852. pComponent->FreeComponentInfo(pInfo);
  1853. }
  1854. VSS_RESTOREMETHOD_ENUM method;
  1855. CComBSTR bstrUserProcedure;
  1856. CComBSTR bstrService;
  1857. VSS_WRITERRESTORE_ENUM writerRestore;
  1858. unsigned cMappings;
  1859. bool bRebootRequired;
  1860. CHECK_NOFAIL(pMetadata->GetRestoreMethod (&method,
  1861. &bstrService,
  1862. &bstrUserProcedure,
  1863. &writerRestore,
  1864. &bRebootRequired,
  1865. &cMappings));
  1866. wprintf (L"\n"
  1867. L" Restore method = %d (%s)\n"
  1868. L" Service = %s\n"
  1869. L" User Procedure = %s\n"
  1870. L" WriterRestore = %d (%s)\n"
  1871. L" RebootRequired = %s\n",
  1872. method,
  1873. GetStringFromRestoreMethod (method),
  1874. bstrService,
  1875. bstrUserProcedure,
  1876. writerRestore,
  1877. GetStringFromWriterRestoreMethod (writerRestore),
  1878. bRebootRequired ? L"yes" : L"no");
  1879. for(i = 0; i < cMappings; i++)
  1880. {
  1881. CComPtr<IVssWMFiledesc> pFiledesc;
  1882. CHECK_SUCCESS(pMetadata->GetAlternateLocationMapping(i, &pFiledesc));
  1883. PrintFiledesc(pFiledesc, L"AlternateMapping");
  1884. }
  1885. CComBSTR bstrMetadata;
  1886. CHECK_SUCCESS(pMetadata->SaveAsXML(&bstrMetadata));
  1887. CComPtr<IVssExamineWriterMetadata> pMetadataNew;
  1888. CHECK_SUCCESS(CreateVssExamineWriterMetadata(bstrMetadata, &pMetadataNew));
  1889. CHECK_SUCCESS(pMetadataNew->GetIdentity (&idInstanceT,
  1890. &idWriter,
  1891. &bstrWriterName,
  1892. &usage,
  1893. &source));
  1894. wprintf (L"\n\n");
  1895. if (memcmp(&idInstance, &idInstanceT, sizeof(VSS_ID)) != 0)
  1896. {
  1897. wprintf(L"Instance id mismatch\n");
  1898. DebugBreak();
  1899. }
  1900. UuidToString(&idInstance, &pwszInstanceId);
  1901. UuidToString(&idWriter, &pwszWriterId);
  1902. wprintf (L"WriterName = %s\n\n"
  1903. L" WriterId = %s\n"
  1904. L" InstanceId = %s\n"
  1905. L" UsageType = %d (%s)\n"
  1906. L" SourceType = %d (%s)\n",
  1907. bstrWriterName,
  1908. pwszWriterId,
  1909. pwszInstanceId,
  1910. usage,
  1911. GetStringFromUsageType (usage),
  1912. source,
  1913. GetStringFromSourceType (source));
  1914. RpcStringFree(&pwszInstanceId);
  1915. RpcStringFree(&pwszWriterId);
  1916. }
  1917. //
  1918. // Proceed with backup only if at least one component and one volume was selected for backup
  1919. //
  1920. if (bAtLeastOneSelected)
  1921. {
  1922. DoPrepareBackup(pvbc);
  1923. CheckStatus(pvbc, L"After Prepare Backup");
  1924. HRESULT hrResult;
  1925. DoSnapshotSet(pvbc, hrResult);
  1926. if (FAILED(hrResult))
  1927. {
  1928. wprintf(L"Creating the snapshot failed. hr = 0x%08lx\n", hrResult);
  1929. CheckStatus(pvbc, L"After Do Snapshot");
  1930. }
  1931. else
  1932. {
  1933. CheckStatus(pvbc, L"After Do Snapshot");
  1934. PrintPartialFilesForComponents(pvbc);
  1935. PrintDifferencedFilesForComponents(pvbc);
  1936. SaveFiles(pvbc, rgpSnapshotId, cSnapshot);
  1937. DoBackupComplete(pvbc);
  1938. CheckStatus(pvbc, L"After Backup Complete");
  1939. // Save backup document in a string
  1940. CHECK_SUCCESS(pvbc->SaveAsXML(&bstrXML));
  1941. bXMLSaved = TRUE;
  1942. // Save backup document (XML string) in a file
  1943. if (wcslen(g_wszBackupDocumentFileName) > 0)
  1944. {
  1945. if (SaveBackupDocument(bstrXML))
  1946. {
  1947. wprintf(L"Backup document saved successfully in %s\n", g_wszBackupDocumentFileName);
  1948. }
  1949. else
  1950. {
  1951. wprintf(L"Failed to save backup document: SaveBackupDocument returned error %d\n", GetLastError());
  1952. }
  1953. }
  1954. // Delete the snapshot set
  1955. LONG lSnapshotsNotDeleted;
  1956. VSS_ID rgSnapshotsNotDeleted[10];
  1957. hr = pvbc->DeleteSnapshots (id,
  1958. VSS_OBJECT_SNAPSHOT_SET,
  1959. false,
  1960. &lSnapshotsNotDeleted,
  1961. rgSnapshotsNotDeleted);
  1962. if (FAILED(hr))
  1963. wprintf(L"Deletion of Snapshots failed. hr = 0x%08lx\n", hr);
  1964. }
  1965. }
  1966. else
  1967. {
  1968. wprintf(L"\nBackup test is aborted since no component is selected, therefore, there are no volumes added to the snapshot set\n\n");
  1969. }
  1970. CHECK_SUCCESS(pvbc->FreeWriterMetadata());
  1971. }
  1972. // Restore is done if
  1973. // 1. User did not ask backup-only AND
  1974. // 2. User asked restore-only OR user asked both, and backup succeeded
  1975. if (! g_bBackupOnly)
  1976. {
  1977. if (g_bRestoreOnly || bXMLSaved)
  1978. {
  1979. BOOL bXMLLoaded = FALSE;
  1980. // Load XML string only in Restore-only case
  1981. if (g_bRestoreOnly)
  1982. {
  1983. if (LoadBackupDocument(bstrXML))
  1984. {
  1985. bXMLLoaded = TRUE;
  1986. wprintf(L"Backup document was loaded from %s\n", g_wszBackupDocumentFileName);
  1987. }
  1988. else
  1989. {
  1990. wprintf(L"Failed to load backup document: LoadBackupDocument returned error %d\n", GetLastError());
  1991. }
  1992. }
  1993. // If we have a backup document from current backup or loaded successfully froma previous backup
  1994. if (bXMLSaved || bXMLLoaded)
  1995. {
  1996. // Prepare for restore
  1997. CComPtr<IVssBackupComponents> pvbcRestore;
  1998. CHECK_SUCCESS(CreateVssBackupComponents(&pvbcRestore));
  1999. CHECK_SUCCESS(pvbcRestore->InitializeForRestore(bstrXML));
  2000. wprintf(L"InitializeForRestore succeeded.\n");
  2001. // Do the restore
  2002. DoRestore(pvbcRestore);
  2003. }
  2004. }
  2005. else
  2006. {
  2007. wprintf(L"\nRestore test is not done due to a failure in the preceding Backup test\n\n");
  2008. }
  2009. }
  2010. if (bSubscribed)
  2011. pInstance->Unsubscribe();
  2012. if (bCreated)
  2013. delete pInstance;
  2014. if (FAILED(hrMain))
  2015. wprintf(L"Failed with %08x.\n", hrMain);
  2016. if (bCoInitializeSucceeded)
  2017. CoUninitialize();
  2018. return(0);
  2019. }