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.

1440 lines
37 KiB

  1. /*
  2. **++
  3. **
  4. ** Copyright (c) 2000-2001 Microsoft Corporation
  5. **
  6. **
  7. ** Module Name:
  8. **
  9. ** SnapCp.cpp
  10. **
  11. **
  12. ** Abstract:
  13. **
  14. ** Test program to accept commands and drive the snapshot stuff
  15. **
  16. **
  17. ** Author:
  18. **
  19. ** Michael C. Johnson [mikejohn] 15-Mar-2001
  20. **
  21. ** Based in part on test programs :-
  22. ** BETEST by Brian Berkowitz
  23. ** metasnap by Michael C. Johnson
  24. **
  25. **
  26. ** Revision History:
  27. **
  28. ** X-3 Michael C. Johnson 7-May-2001
  29. ** Still more updates needed to keep up.
  30. **
  31. ** X-2 Michael C. Johnson 11-Apr-2001
  32. ** Update to cater for recent changes to AddToSnapshotSet() API
  33. ** Also clean up a few 64 bit compilation troubles.
  34. **
  35. **
  36. **
  37. ** ToDo:
  38. ** Allow for multiple (simultaneous) snapshot sets
  39. ** Assign drive letters (manual and automatically) (mapping?)
  40. ** Proper error handling
  41. ** Better user feedback for operation in progress...
  42. ** Logging
  43. ** Default drive list
  44. ** Comma separated drive list
  45. ** Command line prompt
  46. ** auto add all local hard drives
  47. **
  48. **--
  49. */
  50. #include <windows.h>
  51. #include <wtypes.h>
  52. #include <stddef.h>
  53. #include <stdlib.h>
  54. #include <stdio.h>
  55. #include <time.h>
  56. #include <string.h>
  57. #include <vss.h>
  58. #include <vswriter.h>
  59. #include <vsbackup.h>
  60. #include <oleauto.h>
  61. #define ATLASSERT(_condition)
  62. #include <atlconv.h>
  63. #include <atlbase.h>
  64. extern CComModule _Module;
  65. #include <atlcom.h>
  66. #define PROGRAM_TITLE L"SnapCp - Snapshot Control Program V0.3"
  67. #if !defined (SIZEOF_ARRAY)
  68. #define SIZEOF_ARRAY(_arrayname) (sizeof (_arrayname) / sizeof ((_arrayname)[0]))
  69. #endif
  70. #define MAX_COMMAND (SIZEOF_ARRAY (CommandTable))
  71. #define MAX_COMMAND_LINE_LENGTH (1024)
  72. #define MAX_VOLUMES_IN_SNAPSHOT_SET (64)
  73. #define VolumeNameTemplate "\\\\?\\Volume{XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX}\\"
  74. #define HandleInvalid(_Handle) ((NULL == (_Handle)) || (INVALID_HANDLE_VALUE == (_Handle)))
  75. #define GET_STATUS_FROM_BOOL(_bSucceeded) ((_bSucceeded) ? NOERROR : HRESULT_FROM_WIN32 (GetLastError()))
  76. #define GET_STATUS_FROM_HANDLE(_handle) ((!HandleInvalid(_handle)) ? NOERROR : HRESULT_FROM_WIN32 (GetLastError()))
  77. #define GET_STATUS_FROM_POINTER(_ptr) ((NULL != (_ptr)) ? NOERROR : E_OUTOFMEMORY)
  78. typedef IVssBackupComponents *PIVssBackupComponents;
  79. typedef IVssExamineWriterMetadata *PIVssExamineWriterMetadata;
  80. typedef IVssWMComponent *PIVssWMComponent;
  81. typedef IVssAsync *PIVssAsync;
  82. typedef enum _SnapshotSetState
  83. {
  84. STATE_MIN_STATE = 50
  85. ,STATE_INITIALISED
  86. ,STATE_SNAPSHOT_SET_CREATED
  87. ,STATE_SNAPSHOT_CREATED
  88. ,STATE_SNAPSHOT_BEING_DESTROYED
  89. ,STATE_UNKNOWN
  90. ,STATE_MAX_STATE
  91. } SNAPSHOTSET_STATE, *PSNAPSHOTSET_STATE;
  92. typedef enum _CommandCode
  93. {
  94. COMMAND_MIN_COMMAND = 20
  95. ,COMMAND_QUIT
  96. ,COMMAND_EXIT
  97. ,COMMAND_HELP
  98. ,COMMAND_SHOW_METADATA
  99. ,COMMAND_SHOW_WRITERS
  100. ,COMMAND_ADD_VOLUME
  101. ,COMMAND_CREATE_SNAPSHOT_SET
  102. ,COMMAND_CREATE_SNAPSHOT
  103. ,COMMAND_DELETE_SNAPSHOT_SET
  104. ,COMMAND_SET_DEFAULT_VOLUME_LIST
  105. ,COMMAND_SET_BACKUP_TYPE
  106. ,COMMAND_SET_LOGGING_LEVEL
  107. ,COMMAND_SET_LOGGING_FILE
  108. ,COMMAND_NOT_IMPLEMENTED
  109. ,COMMAND_UNKNOWN
  110. ,COMMAND_MAX_COMMAND
  111. } COMMAND_CODE, *PCOMMAND_CODE;
  112. typedef struct _CommandDescriptor
  113. {
  114. COMMAND_CODE eCommandCode;
  115. PWCHAR pwszCommandString;
  116. } COMMANDDESCRIPTOR, *PCOMMANDDESCRIPTOR;
  117. typedef struct _ContextSnapshotSet
  118. {
  119. COMMAND_CODE eCommand;
  120. SNAPSHOTSET_STATE eState;
  121. bool bIncludeBootableState;
  122. ULONG ulVolumesInSnapshotSet;
  123. PWSTR pwszVolumeArgument [MAX_VOLUMES_IN_SNAPSHOT_SET];
  124. PWSTR pwszVolumeName [MAX_VOLUMES_IN_SNAPSHOT_SET];
  125. PWSTR pwszVolumeDevice [MAX_VOLUMES_IN_SNAPSHOT_SET];
  126. PWSTR pwszSnapshotDevice [MAX_VOLUMES_IN_SNAPSHOT_SET];
  127. VSS_ID SnapshotId [MAX_VOLUMES_IN_SNAPSHOT_SET];
  128. VSS_SNAPSHOT_PROP SnapshotProperties [MAX_VOLUMES_IN_SNAPSHOT_SET];
  129. PIVssBackupComponents pIVssBackupComponents;
  130. PIVssAsync pIVssAsyncDoSnapshotSet;
  131. GUID guidSnapshotSetId;
  132. } CONTEXTSNAPSHOTSET, *PCONTEXTSNAPSHOTSET;
  133. inline void CHECK_SUCCESS (HRESULT hr);
  134. inline void CHECK_NOFAIL (HRESULT hr);
  135. BOOL WINAPI CtrlC_HandlerRoutine (DWORD dwCtrlType);
  136. HRESULT AssertPrivilege (LPCWSTR privName);
  137. ULONG FormatGUID (GUID guidValue, PWCHAR pszFormattedGUID, ULONG ulBufferLength);
  138. void PrintFiledesc (IVssWMFiledesc *pFiledesc, LPCWSTR wszDescription);
  139. LPCWSTR GetStringFromUsageType (VSS_USAGE_TYPE eUsageType);
  140. LPCWSTR GetStringFromSourceType (VSS_SOURCE_TYPE eSourceType);
  141. LPCWSTR GetStringFromRestoreMethod (VSS_RESTOREMETHOD_ENUM eRestoreMethod);
  142. LPCWSTR GetStringFromWriterRestoreMethod (VSS_WRITERRESTORE_ENUM eWriterRestoreMethod);
  143. LPCWSTR GetStringFromComponentType (VSS_COMPONENT_TYPE eComponentType);
  144. LPCWSTR GetStringFromFailureType (HRESULT hrStatus);
  145. HRESULT GetNextCommandLine (PWSTR pwszCommandLineBuffer, ULONG ulCommandLineBufferLength);
  146. HRESULT ParseCommandLine (PWSTR pwszCommandLineBuffer, PCOMMAND_CODE peReturnedCommandCode);
  147. HRESULT InitialiseSnapshotSetContext (PCONTEXTSNAPSHOTSET pctxSnapshotSet);
  148. HRESULT GetVolumeNameFromArgument (LPCWSTR pwszVolumeArgument, LPWSTR *ppwszReturnedVolumeName);
  149. HRESULT ShowAnnouncement (void);
  150. HRESULT ShowHelp (void);
  151. HRESULT ShowMetadata (void);
  152. HRESULT ShowWriters (void);
  153. HRESULT AddVolume (PCONTEXTSNAPSHOTSET pctxSnapshotSet);
  154. HRESULT CreateSnapshotSet (PCONTEXTSNAPSHOTSET pctxSnapshotSet);
  155. HRESULT CreateSnapshot (PCONTEXTSNAPSHOTSET pctxSnapshotSet);
  156. HRESULT DeleteSnapshot (PCONTEXTSNAPSHOTSET pctxSnapshotSet);
  157. HRESULT CleanupSnapshotSet (PCONTEXTSNAPSHOTSET pctxSnapshotSet);
  158. COMMANDDESCRIPTOR CommandTable [] =
  159. {
  160. { COMMAND_QUIT, L"Quit" },
  161. { COMMAND_EXIT, L"Exit" },
  162. { COMMAND_HELP, L"Help" },
  163. { COMMAND_SHOW_METADATA, L"Metadata" },
  164. { COMMAND_SHOW_WRITERS, L"Writers" },
  165. { COMMAND_ADD_VOLUME, L"Add" },
  166. { COMMAND_CREATE_SNAPSHOT_SET, L"Set" },
  167. { COMMAND_CREATE_SNAPSHOT, L"Create" },
  168. { COMMAND_DELETE_SNAPSHOT_SET, L"Delete" },
  169. { COMMAND_SET_DEFAULT_VOLUME_LIST, L"Default" },
  170. { COMMAND_SET_BACKUP_TYPE, L"Type" },
  171. { COMMAND_SET_LOGGING_LEVEL, L"Level" },
  172. { COMMAND_SET_LOGGING_FILE, L"File" }
  173. };
  174. WCHAR g_awchCommandLine [MAX_COMMAND_LINE_LENGTH];
  175. PWCHAR g_pwchNextArgument = NULL;
  176. PCONTEXTSNAPSHOTSET g_pctxSnapshotSet = NULL;
  177. BOOL g_bCoInitializeSucceeded = false;
  178. extern "C" __cdecl wmain(int argc, WCHAR **argv)
  179. {
  180. HRESULT hrStatus = NOERROR;
  181. PCONTEXTSNAPSHOTSET pctxSnapshotSet = NULL;
  182. CONTEXTSNAPSHOTSET ctxSnapshotSet;
  183. UNREFERENCED_PARAMETER (argc);
  184. UNREFERENCED_PARAMETER (argv);
  185. InitialiseSnapshotSetContext (&ctxSnapshotSet);
  186. g_pctxSnapshotSet = &ctxSnapshotSet;
  187. SetConsoleCtrlHandler (CtrlC_HandlerRoutine, TRUE);
  188. ShowAnnouncement ();
  189. hrStatus = CoInitializeEx (NULL, COINIT_MULTITHREADED);
  190. g_bCoInitializeSucceeded = SUCCEEDED (hrStatus);
  191. if (FAILED (hrStatus))
  192. {
  193. wprintf (L"SnapCp (wmain) - CoInitializeEx() returned error 0x%08X\n", hrStatus);
  194. }
  195. if (SUCCEEDED (hrStatus))
  196. {
  197. hrStatus = AssertPrivilege (SE_BACKUP_NAME);
  198. if (FAILED (hrStatus))
  199. {
  200. wprintf (L"SnapCp (wmain) - AssertPrivilege() returned error 0x%08X\n", hrStatus);
  201. }
  202. }
  203. /*
  204. ** Parse command loop here
  205. */
  206. while (SUCCEEDED (hrStatus) &&
  207. (COMMAND_EXIT != ctxSnapshotSet.eCommand) &&
  208. (COMMAND_QUIT != ctxSnapshotSet.eCommand))
  209. {
  210. hrStatus = GetNextCommandLine (g_awchCommandLine, sizeof (g_awchCommandLine));
  211. hrStatus = ParseCommandLine (g_awchCommandLine, &ctxSnapshotSet.eCommand);
  212. switch (ctxSnapshotSet.eCommand)
  213. {
  214. case COMMAND_EXIT: break;
  215. case COMMAND_QUIT: break;
  216. case COMMAND_HELP: hrStatus = ShowHelp (); break;
  217. case COMMAND_SHOW_METADATA: hrStatus = ShowMetadata (); break;
  218. case COMMAND_SHOW_WRITERS: hrStatus = ShowWriters (); break;
  219. case COMMAND_CREATE_SNAPSHOT_SET: hrStatus = CreateSnapshotSet (&ctxSnapshotSet); break;
  220. case COMMAND_ADD_VOLUME: hrStatus = AddVolume (&ctxSnapshotSet); break;
  221. case COMMAND_CREATE_SNAPSHOT: hrStatus = CreateSnapshot (&ctxSnapshotSet); break;
  222. case COMMAND_DELETE_SNAPSHOT_SET: hrStatus = DeleteSnapshot (&ctxSnapshotSet); break;
  223. case COMMAND_SET_DEFAULT_VOLUME_LIST:
  224. case COMMAND_SET_BACKUP_TYPE:
  225. case COMMAND_SET_LOGGING_LEVEL:
  226. case COMMAND_SET_LOGGING_FILE:
  227. default:
  228. ctxSnapshotSet.eCommand = COMMAND_UNKNOWN;
  229. break;
  230. }
  231. }
  232. pctxSnapshotSet = (PCONTEXTSNAPSHOTSET) InterlockedExchangePointer ((PVOID *)&g_pctxSnapshotSet, NULL);
  233. if (NULL != pctxSnapshotSet) CleanupSnapshotSet (pctxSnapshotSet);
  234. if (g_bCoInitializeSucceeded) CoUninitialize ();
  235. if (FAILED(hrStatus)) wprintf (L"Failed with 0x%08X.\n", hrStatus);
  236. return (0);
  237. }
  238. BOOL WINAPI CtrlC_HandlerRoutine (DWORD dwCtrlType)
  239. {
  240. PCONTEXTSNAPSHOTSET pctxSnapshotSet = NULL;
  241. UNREFERENCED_PARAMETER (dwCtrlType);
  242. pctxSnapshotSet = (PCONTEXTSNAPSHOTSET) InterlockedExchangePointer ((PVOID *)&g_pctxSnapshotSet, NULL);
  243. if (NULL != pctxSnapshotSet) CleanupSnapshotSet (pctxSnapshotSet);
  244. if (g_bCoInitializeSucceeded) CoUninitialize ();
  245. return (false);
  246. }
  247. HRESULT AssertPrivilege (LPCWSTR privName)
  248. {
  249. HRESULT hrStatus = NOERROR;
  250. BOOL bSucceeded = FALSE;
  251. TOKEN_PRIVILEGES *pTokens = NULL;
  252. TOKEN_PRIVILEGES newState;
  253. HANDLE tokenHandle;
  254. LUID value;
  255. DWORD cbTokens;
  256. if (OpenProcessToken (GetCurrentProcess(),
  257. TOKEN_ADJUST_PRIVILEGES|TOKEN_QUERY,
  258. &tokenHandle))
  259. {
  260. if (LookupPrivilegeValue (NULL, privName, &value))
  261. {
  262. newState.PrivilegeCount = 1;
  263. newState.Privileges [0].Luid = value;
  264. newState.Privileges [0].Attributes = SE_PRIVILEGE_ENABLED_BY_DEFAULT|SE_PRIVILEGE_ENABLED;
  265. /*
  266. ** We will always call GetLastError below, so clear
  267. ** any prior error values on this thread.
  268. */
  269. SetLastError (ERROR_SUCCESS);
  270. bSucceeded = AdjustTokenPrivileges (tokenHandle,
  271. FALSE,
  272. &newState,
  273. (DWORD)0,
  274. NULL,
  275. NULL);
  276. /*
  277. ** Supposedly, AdjustTokenPriveleges always returns TRUE
  278. ** (even when it fails). So, call GetLastError to be
  279. ** extra sure everything's cool.
  280. */
  281. hrStatus = GET_STATUS_FROM_BOOL (FALSE);
  282. if (FAILED (hrStatus))
  283. {
  284. wprintf (L"AdjustTokenPrivileges for %s failed with 0x%08X",
  285. privName,
  286. hrStatus);
  287. }
  288. }
  289. if (SUCCEEDED (hrStatus))
  290. {
  291. GetTokenInformation (tokenHandle,
  292. TokenPrivileges,
  293. NULL,
  294. 0,
  295. &cbTokens);
  296. pTokens = (TOKEN_PRIVILEGES *) new BYTE[cbTokens];
  297. GetTokenInformation (tokenHandle,
  298. TokenPrivileges,
  299. pTokens,
  300. cbTokens,
  301. &cbTokens);
  302. }
  303. delete pTokens;
  304. CloseHandle (tokenHandle);
  305. }
  306. return (hrStatus);
  307. }
  308. inline void CHECK_SUCCESS (HRESULT hr)
  309. {
  310. if (hr != S_OK)
  311. {
  312. wprintf(L"operation failed with HRESULT =0x%08x\n", hr);
  313. DebugBreak();
  314. }
  315. }
  316. inline void CHECK_NOFAIL (HRESULT hr)
  317. {
  318. if (FAILED(hr))
  319. {
  320. wprintf(L"operation failed with HRESULT =0x%08x\n", hr);
  321. DebugBreak();
  322. }
  323. }
  324. LPCWSTR GetStringFromUsageType (VSS_USAGE_TYPE eUsageType)
  325. {
  326. LPCWSTR pwszRetString = L"UNDEFINED";
  327. switch (eUsageType)
  328. {
  329. case VSS_UT_BOOTABLESYSTEMSTATE: pwszRetString = L"BootableSystemState"; break;
  330. case VSS_UT_SYSTEMSERVICE: pwszRetString = L"SystemService"; break;
  331. case VSS_UT_USERDATA: pwszRetString = L"UserData"; break;
  332. case VSS_UT_OTHER: pwszRetString = L"Other"; break;
  333. default:
  334. break;
  335. }
  336. return (pwszRetString);
  337. }
  338. LPCWSTR GetStringFromSourceType (VSS_SOURCE_TYPE eSourceType)
  339. {
  340. LPCWSTR pwszRetString = L"UNDEFINED";
  341. switch (eSourceType)
  342. {
  343. case VSS_ST_TRANSACTEDDB: pwszRetString = L"TransactionDb"; break;
  344. case VSS_ST_NONTRANSACTEDDB: pwszRetString = L"NonTransactionDb"; break;
  345. case VSS_ST_OTHER: pwszRetString = L"Other"; break;
  346. default:
  347. break;
  348. }
  349. return (pwszRetString);
  350. }
  351. LPCWSTR GetStringFromRestoreMethod (VSS_RESTOREMETHOD_ENUM eRestoreMethod)
  352. {
  353. LPCWSTR pwszRetString = L"UNDEFINED";
  354. switch (eRestoreMethod)
  355. {
  356. case VSS_RME_RESTORE_IF_NOT_THERE: pwszRetString = L"RestoreIfNotThere"; break;
  357. case VSS_RME_RESTORE_IF_CAN_REPLACE: pwszRetString = L"RestoreIfCanReplace"; break;
  358. case VSS_RME_STOP_RESTORE_START: pwszRetString = L"StopRestoreStart"; break;
  359. case VSS_RME_RESTORE_TO_ALTERNATE_LOCATION: pwszRetString = L"RestoreToAlternateLocation"; break;
  360. case VSS_RME_RESTORE_AT_REBOOT: pwszRetString = L"RestoreAtReboot"; break;
  361. case VSS_RME_CUSTOM: pwszRetString = L"Custom"; break;
  362. default:
  363. break;
  364. }
  365. return (pwszRetString);
  366. }
  367. LPCWSTR GetStringFromWriterRestoreMethod (VSS_WRITERRESTORE_ENUM eWriterRestoreMethod)
  368. {
  369. LPCWSTR pwszRetString = L"UNDEFINED";
  370. switch (eWriterRestoreMethod)
  371. {
  372. case VSS_WRE_NEVER: pwszRetString = L"RestoreNever"; break;
  373. case VSS_WRE_IF_REPLACE_FAILS: pwszRetString = L"RestoreIfReplaceFailsI"; break;
  374. case VSS_WRE_ALWAYS: pwszRetString = L"RestoreAlways"; break;
  375. default:
  376. break;
  377. }
  378. return (pwszRetString);
  379. }
  380. LPCWSTR GetStringFromComponentType (VSS_COMPONENT_TYPE eComponentType)
  381. {
  382. LPCWSTR pwszRetString = L"UNDEFINED";
  383. switch (eComponentType)
  384. {
  385. case VSS_CT_DATABASE: pwszRetString = L"Database"; break;
  386. case VSS_CT_FILEGROUP: pwszRetString = L"FileGroup"; break;
  387. default:
  388. break;
  389. }
  390. return (pwszRetString);
  391. }
  392. LPCWSTR GetStringFromFailureType (HRESULT hrStatus)
  393. {
  394. LPCWSTR pwszFailureType;
  395. switch (hrStatus)
  396. {
  397. case NOERROR: pwszFailureType = L""; break;
  398. case VSS_E_WRITERERROR_INCONSISTENTSNAPSHOT: pwszFailureType = L"InconsistentSnapshot"; break;
  399. case VSS_E_WRITERERROR_OUTOFRESOURCES: pwszFailureType = L"OutOfResources"; break;
  400. case VSS_E_WRITERERROR_TIMEOUT: pwszFailureType = L"Timeout"; break;
  401. case VSS_E_WRITERERROR_NONRETRYABLE: pwszFailureType = L"Non-Retryable"; break;
  402. case VSS_E_WRITERERROR_RETRYABLE: pwszFailureType = L"Retryable"; break;
  403. default: pwszFailureType = L"UNDEFINED"; break;
  404. }
  405. return (pwszFailureType);
  406. }
  407. /*
  408. ** {XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX}
  409. */
  410. ULONG FormatGUID (GUID guidValue, PWCHAR pszFormattedGUID, ULONG ulBufferLength)
  411. {
  412. DWORD dwStatus = 0;
  413. if (sizeof (L"{XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX}") > ulBufferLength)
  414. {
  415. dwStatus = ERROR_INSUFFICIENT_BUFFER;
  416. }
  417. if (0 == dwStatus)
  418. {
  419. _snwprintf (pszFormattedGUID,
  420. ulBufferLength / sizeof (WCHAR),
  421. L"{%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x}",
  422. guidValue.Data1,
  423. guidValue.Data2,
  424. guidValue.Data3,
  425. guidValue.Data4[0],
  426. guidValue.Data4[1],
  427. guidValue.Data4[2],
  428. guidValue.Data4[3],
  429. guidValue.Data4[4],
  430. guidValue.Data4[5],
  431. guidValue.Data4[6],
  432. guidValue.Data4[7]);
  433. }
  434. return (dwStatus);
  435. }
  436. void PrintFiledesc (IVssWMFiledesc *pFiledesc, LPCWSTR wszDescription)
  437. {
  438. CComBSTR bstrPath;
  439. CComBSTR bstrFilespec;
  440. CComBSTR bstrAlternate;
  441. bool bRecursive;
  442. CHECK_SUCCESS (pFiledesc->GetPath (&bstrPath));
  443. CHECK_SUCCESS (pFiledesc->GetFilespec (&bstrFilespec));
  444. CHECK_NOFAIL (pFiledesc->GetRecursive (&bRecursive));
  445. CHECK_NOFAIL (pFiledesc->GetAlternateLocation (&bstrAlternate));
  446. wprintf (L"%s\n Path = %s, Filespec = %s, Recursive = %s\n",
  447. wszDescription,
  448. bstrPath,
  449. bstrFilespec,
  450. bRecursive ? L"yes" : L"no");
  451. if (bstrAlternate && wcslen (bstrAlternate) > 0)
  452. {
  453. wprintf(L" Alternate Location = %s\n", bstrAlternate);
  454. }
  455. }
  456. HRESULT GetNextCommandLine (PWSTR pwszCommandLineBuffer, ULONG ulCommandLineBufferLength)
  457. {
  458. UNREFERENCED_PARAMETER (pwszCommandLineBuffer);
  459. UNREFERENCED_PARAMETER (ulCommandLineBufferLength);
  460. g_pwchNextArgument = NULL;
  461. _getws (pwszCommandLineBuffer);
  462. return (NOERROR);
  463. }
  464. HRESULT ParseCommandLine (PWSTR pwszCommandLineBuffer, PCOMMAND_CODE peReturnedCommandCode)
  465. {
  466. ULONG ulIndexCommandTable;
  467. COMMAND_CODE eCommandCode = COMMAND_UNKNOWN;
  468. for (ulIndexCommandTable = 0;
  469. (ulIndexCommandTable < MAX_COMMAND) && (COMMAND_UNKNOWN == eCommandCode);
  470. ulIndexCommandTable++)
  471. {
  472. if (0 == _wcsnicmp (pwszCommandLineBuffer,
  473. CommandTable [ulIndexCommandTable].pwszCommandString,
  474. wcslen (CommandTable [ulIndexCommandTable].pwszCommandString)))
  475. {
  476. size_t ulCommandStringLength = wcslen (CommandTable [ulIndexCommandTable].pwszCommandString);
  477. eCommandCode = CommandTable [ulIndexCommandTable].eCommandCode;
  478. if ((pwszCommandLineBuffer [ulCommandStringLength + 0] == ' ') &&
  479. (pwszCommandLineBuffer [ulCommandStringLength + 1] != '\0'))
  480. {
  481. g_pwchNextArgument = &pwszCommandLineBuffer [ulCommandStringLength + 1];
  482. }
  483. }
  484. }
  485. *peReturnedCommandCode = eCommandCode;
  486. return (NOERROR);
  487. }
  488. HRESULT InitialiseSnapshotSetContext (PCONTEXTSNAPSHOTSET pctxSnapshotSet)
  489. {
  490. HRESULT hrStatus = NOERROR;
  491. ULONG ulIndex;
  492. pctxSnapshotSet->eCommand = COMMAND_UNKNOWN;
  493. pctxSnapshotSet->bIncludeBootableState = false;
  494. pctxSnapshotSet->ulVolumesInSnapshotSet = 0;
  495. pctxSnapshotSet->pIVssBackupComponents = NULL;
  496. pctxSnapshotSet->pIVssAsyncDoSnapshotSet = NULL;
  497. pctxSnapshotSet->guidSnapshotSetId = GUID_NULL;
  498. for (ulIndex = 0; ulIndex < SIZEOF_ARRAY (pctxSnapshotSet->pwszVolumeName); ulIndex++)
  499. {
  500. pctxSnapshotSet->pwszVolumeArgument [ulIndex] = NULL;
  501. pctxSnapshotSet->pwszVolumeName [ulIndex] = NULL;
  502. pctxSnapshotSet->pwszVolumeDevice [ulIndex] = NULL;
  503. pctxSnapshotSet->pwszSnapshotDevice [ulIndex] = NULL;
  504. pctxSnapshotSet->SnapshotProperties [ulIndex].m_SnapshotId = GUID_NULL;
  505. pctxSnapshotSet->SnapshotId [ulIndex] = GUID_NULL;
  506. }
  507. pctxSnapshotSet->eState = STATE_INITIALISED;
  508. return (hrStatus);
  509. }
  510. HRESULT CleanupSnapshotSet (PCONTEXTSNAPSHOTSET pctxSnapshotSet)
  511. {
  512. HRESULT hrStatus = NOERROR;
  513. ULONG ulIndex;
  514. pctxSnapshotSet->eState = STATE_SNAPSHOT_BEING_DESTROYED;
  515. if (GUID_NULL != pctxSnapshotSet->guidSnapshotSetId)
  516. {
  517. hrStatus = pctxSnapshotSet->pIVssBackupComponents->AbortBackup ();
  518. hrStatus = pctxSnapshotSet->pIVssBackupComponents->DeleteSnapshots (pctxSnapshotSet->guidSnapshotSetId,
  519. VSS_OBJECT_SNAPSHOT_SET,
  520. true,
  521. NULL,
  522. NULL);
  523. }
  524. for (ulIndex = 0; ulIndex < pctxSnapshotSet->ulVolumesInSnapshotSet; ulIndex++)
  525. {
  526. if (NULL != pctxSnapshotSet->pwszVolumeArgument [ulIndex])
  527. {
  528. free (pctxSnapshotSet->pwszVolumeArgument [ulIndex]);
  529. }
  530. if (NULL != pctxSnapshotSet->pwszVolumeName [ulIndex])
  531. {
  532. free (pctxSnapshotSet->pwszVolumeName [ulIndex]);
  533. }
  534. if (NULL != pctxSnapshotSet->pwszVolumeDevice [ulIndex])
  535. {
  536. free (pctxSnapshotSet->pwszVolumeDevice [ulIndex]);
  537. }
  538. if (NULL != pctxSnapshotSet->pwszSnapshotDevice [ulIndex])
  539. {
  540. CoTaskMemFree (pctxSnapshotSet->pwszSnapshotDevice [ulIndex]);
  541. }
  542. if (GUID_NULL != pctxSnapshotSet->SnapshotProperties [ulIndex].m_SnapshotId)
  543. {
  544. VssFreeSnapshotProperties (&pctxSnapshotSet->SnapshotProperties [ulIndex]);
  545. }
  546. }
  547. if (NULL != pctxSnapshotSet->pIVssBackupComponents) pctxSnapshotSet->pIVssBackupComponents->Release ();
  548. if (NULL != pctxSnapshotSet->pIVssAsyncDoSnapshotSet) pctxSnapshotSet->pIVssAsyncDoSnapshotSet->Release ();
  549. InitialiseSnapshotSetContext (pctxSnapshotSet);
  550. return (hrStatus);
  551. }
  552. HRESULT GetVolumeNameFromArgument (LPCWSTR pwszVolumeArgument, LPWSTR *ppwszReturnedVolumeName)
  553. {
  554. HRESULT hrStatus = NOERROR;
  555. PWCHAR pwszPath = NULL;
  556. PWCHAR pwszMountPointName = NULL;
  557. PWCHAR pwszVolumeName = NULL;
  558. ULONG ulPathLength = 0;
  559. ULONG ulMountpointBufferLength = 0;
  560. BOOL bSucceeded = FALSE;
  561. ULONG ulVolumeNameCharacterCount = sizeof (VolumeNameTemplate);
  562. pwszVolumeName = (PWCHAR) calloc (ulVolumeNameCharacterCount, sizeof (WCHAR));
  563. bSucceeded = (NULL != pwszVolumeName);
  564. if (bSucceeded)
  565. {
  566. ulPathLength = ExpandEnvironmentStringsW (pwszVolumeArgument, NULL, 0);
  567. pwszPath = (PWCHAR) calloc (ulPathLength, sizeof (WCHAR));
  568. bSucceeded = (NULL != pwszPath);
  569. }
  570. if (bSucceeded)
  571. {
  572. ulPathLength = ExpandEnvironmentStringsW (pwszVolumeArgument, pwszPath, ulPathLength);
  573. ulMountpointBufferLength = GetFullPathName (pwszPath, 0, NULL, NULL);
  574. pwszMountPointName = (PWCHAR) calloc (ulMountpointBufferLength, sizeof (WCHAR));
  575. bSucceeded = (NULL != pwszMountPointName);
  576. }
  577. if (bSucceeded)
  578. {
  579. bSucceeded = GetVolumePathNameW (pwszPath, pwszMountPointName, ulMountpointBufferLength);
  580. }
  581. if (bSucceeded)
  582. {
  583. bSucceeded = GetVolumeNameForVolumeMountPointW (pwszMountPointName,
  584. pwszVolumeName,
  585. ulVolumeNameCharacterCount);
  586. }
  587. if (bSucceeded)
  588. {
  589. *ppwszReturnedVolumeName = pwszVolumeName;
  590. pwszVolumeName = NULL;
  591. }
  592. hrStatus = GET_STATUS_FROM_BOOL (bSucceeded);
  593. if (NULL != pwszPath) free (pwszPath);
  594. if (NULL != pwszMountPointName) free (pwszMountPointName);
  595. if (NULL != pwszVolumeName) free (pwszVolumeName);
  596. return (hrStatus);
  597. }
  598. HRESULT ShowMetadata (void)
  599. {
  600. HRESULT hr = NOERROR;
  601. try
  602. {
  603. unsigned cWriters;
  604. CComBSTR bstrXML;
  605. CComBSTR bstrXMLOut;
  606. CComBSTR strSnapshotSetId = "12345678-1234-1234-1234-1234567890ab";
  607. CComPtr<IVssBackupComponents> pvbc;
  608. CComPtr<IVssAsync> pAsync;
  609. CHECK_SUCCESS (CreateVssBackupComponents (&pvbc));
  610. CHECK_SUCCESS (pvbc->InitializeForBackup ());
  611. CHECK_SUCCESS (pvbc->SetBackupState (true, false, VSS_BT_FULL));
  612. CHECK_NOFAIL (pvbc->GatherWriterMetadata (&pAsync));
  613. CHECK_NOFAIL (pAsync->Wait ());
  614. CHECK_NOFAIL (pvbc->GetWriterMetadataCount (&cWriters));
  615. for (unsigned iWriter = 0; iWriter < cWriters; iWriter++)
  616. {
  617. CComPtr<IVssExamineWriterMetadata> pMetadata;
  618. VSS_ID idInstance;
  619. VSS_ID idInstanceT;
  620. VSS_ID idWriter;
  621. CComBSTR bstrWriterName;
  622. VSS_USAGE_TYPE usage;
  623. VSS_SOURCE_TYPE source;
  624. WCHAR *pwszInstanceId;
  625. WCHAR *pwszWriterId;
  626. unsigned cIncludeFiles, cExcludeFiles, cComponents;
  627. CComBSTR bstrPath;
  628. CComBSTR bstrFilespec;
  629. CComBSTR bstrAlternate;
  630. CComBSTR bstrDestination;
  631. CHECK_SUCCESS (pvbc->GetWriterMetadata(iWriter, &idInstance, &pMetadata));
  632. CHECK_SUCCESS (pMetadata->GetIdentity (&idInstanceT,
  633. &idWriter,
  634. &bstrWriterName,
  635. &usage,
  636. &source));
  637. wprintf (L"\n\n");
  638. if (memcmp (&idInstance, &idInstanceT, sizeof(VSS_ID)) != 0)
  639. {
  640. wprintf(L"Instance id mismatch\n");
  641. DebugBreak();
  642. }
  643. UuidToString (&idInstance, &pwszInstanceId);
  644. UuidToString (&idWriter, &pwszWriterId);
  645. wprintf (L"WriterName = %s\n\n"
  646. L" WriterId = %s\n"
  647. L" InstanceId = %s\n"
  648. L" UsageType = %d (%s)\n"
  649. L" SourceType = %d (%s)\n",
  650. bstrWriterName,
  651. pwszWriterId,
  652. pwszInstanceId,
  653. usage,
  654. GetStringFromUsageType (usage),
  655. source,
  656. GetStringFromSourceType (source));
  657. RpcStringFree (&pwszInstanceId);
  658. RpcStringFree (&pwszWriterId);
  659. CHECK_SUCCESS(pMetadata->GetFileCounts (&cIncludeFiles,
  660. &cExcludeFiles,
  661. &cComponents));
  662. for(unsigned i = 0; i < cIncludeFiles; i++)
  663. {
  664. CComPtr<IVssWMFiledesc> pFiledesc;
  665. CHECK_SUCCESS (pMetadata->GetIncludeFile (i, &pFiledesc));
  666. PrintFiledesc(pFiledesc, L"\n Include File");
  667. }
  668. for(i = 0; i < cExcludeFiles; i++)
  669. {
  670. CComPtr<IVssWMFiledesc> pFiledesc;
  671. CHECK_SUCCESS (pMetadata->GetExcludeFile (i, &pFiledesc));
  672. PrintFiledesc (pFiledesc, L"\n Exclude File");
  673. }
  674. for(unsigned iComponent = 0; iComponent < cComponents; iComponent++)
  675. {
  676. CComPtr<IVssWMComponent> pComponent;
  677. PVSSCOMPONENTINFO pInfo;
  678. CHECK_SUCCESS (pMetadata->GetComponent (iComponent, &pComponent));
  679. CHECK_SUCCESS (pComponent->GetComponentInfo (&pInfo));
  680. wprintf (L"\n"
  681. L" Component %d, type = %d (%s)\n"
  682. L" LogicalPath = %s\n"
  683. L" Name = %s\n"
  684. L" Caption = %s\n",
  685. iComponent,
  686. pInfo->type,
  687. GetStringFromComponentType (pInfo->type),
  688. pInfo->bstrLogicalPath,
  689. pInfo->bstrComponentName,
  690. pInfo->bstrCaption);
  691. if (pInfo->cbIcon > 0)
  692. {
  693. if (pInfo->cbIcon != 10 ||
  694. pInfo->pbIcon[0] != 1 ||
  695. pInfo->pbIcon[1] != 2 ||
  696. pInfo->pbIcon[2] != 3 ||
  697. pInfo->pbIcon[3] != 4 ||
  698. pInfo->pbIcon[4] != 5 ||
  699. pInfo->pbIcon[5] != 6 ||
  700. pInfo->pbIcon[6] != 7 ||
  701. pInfo->pbIcon[7] != 8 ||
  702. pInfo->pbIcon[8] != 9 ||
  703. pInfo->pbIcon[9] != 10)
  704. {
  705. wprintf(L" Icon is not valid.\n");
  706. DebugBreak();
  707. }
  708. else
  709. wprintf(L" Icon is valid.\n");
  710. }
  711. wprintf (L" RestoreMetadata = %s\n"
  712. L" NotifyOnBackupComplete = %s\n"
  713. L" Selectable = %s\n",
  714. pInfo->bRestoreMetadata ? L"yes" : L"no",
  715. pInfo->bNotifyOnBackupComplete ? L"yes" : L"no",
  716. pInfo->bSelectable ? L"yes" : L"no");
  717. if (pInfo->cFileCount > 0)
  718. {
  719. for(i = 0; i < pInfo->cFileCount; i++)
  720. {
  721. CComPtr<IVssWMFiledesc> pFiledesc;
  722. CHECK_SUCCESS (pComponent->GetFile (i, &pFiledesc));
  723. PrintFiledesc (pFiledesc, L" FileGroupFile");
  724. }
  725. }
  726. if (pInfo->cDatabases > 0)
  727. {
  728. for(i = 0; i < pInfo->cDatabases; i++)
  729. {
  730. CComPtr<IVssWMFiledesc> pFiledesc;
  731. CHECK_SUCCESS (pComponent->GetDatabaseFile (i, &pFiledesc));
  732. PrintFiledesc (pFiledesc, L" DatabaseFile");
  733. }
  734. }
  735. if (pInfo->cLogFiles > 0)
  736. {
  737. for(i = 0; i < pInfo->cLogFiles; i++)
  738. {
  739. CComPtr<IVssWMFiledesc> pFiledesc;
  740. CHECK_SUCCESS (pComponent->GetDatabaseLogFile (i, &pFiledesc));
  741. PrintFiledesc (pFiledesc, L" DatabaseLogFile");
  742. }
  743. }
  744. pComponent->FreeComponentInfo (pInfo);
  745. }
  746. VSS_RESTOREMETHOD_ENUM method;
  747. CComBSTR bstrUserProcedure;
  748. CComBSTR bstrService;
  749. VSS_WRITERRESTORE_ENUM writerRestore;
  750. unsigned cMappings;
  751. bool bRebootRequired;
  752. CHECK_NOFAIL (pMetadata->GetRestoreMethod (&method,
  753. &bstrService,
  754. &bstrUserProcedure,
  755. &writerRestore,
  756. &bRebootRequired,
  757. &cMappings));
  758. wprintf (L"\n"
  759. L" Restore method = %d (%s)\n"
  760. L" Service = %d\n"
  761. L" User Procedure = %s\n"
  762. L" WriterRestore = %d (%s)\n"
  763. L" RebootRequired = %s\n",
  764. method,
  765. GetStringFromRestoreMethod (method),
  766. bstrService,
  767. bstrUserProcedure,
  768. writerRestore,
  769. GetStringFromWriterRestoreMethod (writerRestore),
  770. bRebootRequired ? L"yes" : L"no");
  771. for(i = 0; i < cMappings; i++)
  772. {
  773. CComPtr<IVssWMFiledesc> pFiledesc;
  774. CHECK_SUCCESS (pMetadata->GetAlternateLocationMapping (i, &pFiledesc));
  775. PrintFiledesc (pFiledesc, L" AlternateMapping");
  776. }
  777. }
  778. CHECK_SUCCESS (pvbc->FreeWriterMetadata());
  779. }
  780. catch(...)
  781. {
  782. hr = E_UNEXPECTED;
  783. }
  784. if (FAILED(hr)) wprintf (L"Failed with 0x%08X.\n", hr);
  785. return (hr);
  786. }
  787. HRESULT ShowWriters (void)
  788. {
  789. HRESULT hr = NOERROR;
  790. try
  791. {
  792. unsigned cWriters;
  793. CComBSTR bstrXML;
  794. CComBSTR bstrXMLOut;
  795. CComBSTR strSnapshotSetId = "12345678-1234-1234-1234-1234567890ab";
  796. CComPtr<IVssBackupComponents> pvbc;
  797. CComPtr<IVssAsync> pIVssAsync;
  798. CHECK_SUCCESS (CreateVssBackupComponents (&pvbc));
  799. CHECK_SUCCESS (pvbc->InitializeForBackup ());
  800. CHECK_SUCCESS (pvbc->SetBackupState (true, false, VSS_BT_FULL));
  801. CHECK_NOFAIL (pvbc->GatherWriterMetadata (&pIVssAsync));
  802. CHECK_NOFAIL (pIVssAsync->Wait ());
  803. CHECK_NOFAIL (pvbc->GetWriterMetadataCount (&cWriters));
  804. for (unsigned iWriter = 0; iWriter < cWriters; iWriter++)
  805. {
  806. CComPtr<IVssExamineWriterMetadata> pMetadata;
  807. VSS_ID idInstance;
  808. VSS_ID idInstanceT;
  809. VSS_ID idWriter;
  810. CComBSTR bstrWriterName;
  811. VSS_USAGE_TYPE usage;
  812. VSS_SOURCE_TYPE source;
  813. WCHAR *pwszInstanceId;
  814. WCHAR *pwszWriterId;
  815. CComBSTR bstrPath;
  816. CComBSTR bstrFilespec;
  817. CComBSTR bstrAlternate;
  818. CComBSTR bstrDestination;
  819. CHECK_SUCCESS (pvbc->GetWriterMetadata(iWriter, &idInstance, &pMetadata));
  820. CHECK_SUCCESS (pMetadata->GetIdentity (&idInstanceT,
  821. &idWriter,
  822. &bstrWriterName,
  823. &usage,
  824. &source));
  825. wprintf (L"\n\n");
  826. if (memcmp (&idInstance, &idInstanceT, sizeof(VSS_ID)) != 0)
  827. {
  828. wprintf(L"Instance id mismatch\n");
  829. DebugBreak();
  830. }
  831. UuidToString (&idInstance, &pwszInstanceId);
  832. UuidToString (&idWriter, &pwszWriterId);
  833. wprintf (L"WriterName = %s\n\n"
  834. L" WriterId = %s\n"
  835. L" InstanceId = %s\n"
  836. L" UsageType = %d (%s)\n"
  837. L" SourceType = %d (%s)\n",
  838. bstrWriterName,
  839. pwszWriterId,
  840. pwszInstanceId,
  841. usage,
  842. GetStringFromUsageType (usage),
  843. source,
  844. GetStringFromSourceType (source));
  845. RpcStringFree (&pwszInstanceId);
  846. RpcStringFree (&pwszWriterId);
  847. }
  848. CHECK_SUCCESS (pvbc->FreeWriterMetadata());
  849. }
  850. catch(...)
  851. {
  852. hr = E_UNEXPECTED;
  853. }
  854. if (FAILED(hr)) wprintf (L"Failed with 0x%08X.\n", hr);
  855. return (hr);
  856. }
  857. HRESULT ShowAnnouncement (void)
  858. {
  859. wprintf (L"\n"
  860. L"\t%s\n\n"
  861. L"\t\n",
  862. PROGRAM_TITLE);
  863. return (NOERROR);
  864. }
  865. HRESULT ShowHelp (void)
  866. {
  867. wprintf (L"\n\n"
  868. L"\t%s\n\n"
  869. L"\t\n"
  870. L"\t Commands:\n"
  871. L"\t\n"
  872. L"\t help\n"
  873. L"\t exit\n"
  874. L"\t quit\n"
  875. L"\t metadata\n"
  876. L"\t writers\n"
  877. L"\t set\n"
  878. L"\t add\n"
  879. L"\t create\n"
  880. L"\t delete\n"
  881. L"\t\n"
  882. L"\t\n"
  883. L"\tOnce the snapshots are created use DosDev to map a drive letter to\n"
  884. L"\tthe snapshot devices for convenient access\n"
  885. L"\t\n"
  886. L"\te.g. DosDev u: \\\\?\\GLOBALROOT\\Device\\HarddiskVolumeSnapshot1\n"
  887. L"\t\n",
  888. PROGRAM_TITLE);
  889. return (NOERROR);
  890. }
  891. HRESULT CreateSnapshotSet (PCONTEXTSNAPSHOTSET pctxSnapshotSet)
  892. {
  893. HRESULT hrStatus = NOERROR;
  894. PIVssAsync pIVssAsync;
  895. hrStatus = CreateVssBackupComponents (&pctxSnapshotSet->pIVssBackupComponents);
  896. hrStatus = pctxSnapshotSet->pIVssBackupComponents->InitializeForBackup ();
  897. hrStatus = pctxSnapshotSet->pIVssBackupComponents->GatherWriterMetadata (&pIVssAsync);
  898. hrStatus = pIVssAsync->Wait ();
  899. hrStatus = pIVssAsync->QueryStatus (&hrStatus, NULL);
  900. hrStatus = pctxSnapshotSet->pIVssBackupComponents->SetBackupState (true,
  901. pctxSnapshotSet->bIncludeBootableState,
  902. VSS_BT_FULL);
  903. hrStatus = pctxSnapshotSet->pIVssBackupComponents->StartSnapshotSet (&pctxSnapshotSet->guidSnapshotSetId);
  904. if (SUCCEEDED (hrStatus))
  905. {
  906. WCHAR awchGuidBuffer [65];
  907. FormatGUID (pctxSnapshotSet->guidSnapshotSetId,
  908. awchGuidBuffer,
  909. sizeof (awchGuidBuffer));
  910. wprintf (L"Created snapshot set %s\n\n", awchGuidBuffer);
  911. pctxSnapshotSet->eState = STATE_SNAPSHOT_SET_CREATED;
  912. }
  913. else
  914. {
  915. wprintf (L"ERROR - Unable to create snapshot set (0x%08X)\n\n", hrStatus);
  916. }
  917. return (hrStatus);
  918. }
  919. HRESULT AddVolume (PCONTEXTSNAPSHOTSET pctxSnapshotSet)
  920. {
  921. HRESULT hrStatus = NOERROR;
  922. size_t ulArgumentLength = 0;
  923. ULONG ulIndexVolume = 0;
  924. BOOL bSupported = FALSE;
  925. if (STATE_SNAPSHOT_SET_CREATED != pctxSnapshotSet->eState)
  926. {
  927. wprintf (L"ERROR - Unable to add volumes add this time (%d)\n\n", pctxSnapshotSet->eState);
  928. }
  929. else if (pctxSnapshotSet->ulVolumesInSnapshotSet >= SIZEOF_ARRAY (pctxSnapshotSet->pwszVolumeArgument))
  930. {
  931. wprintf (L"ERROR - Maximum number of volumes already present in snapshot set\n\n");
  932. }
  933. else if ((NULL != g_pwchNextArgument) && (ulArgumentLength = wcslen (g_pwchNextArgument)) > 0)
  934. {
  935. ulIndexVolume = pctxSnapshotSet->ulVolumesInSnapshotSet;
  936. pctxSnapshotSet->pwszVolumeArgument [ulIndexVolume] = (PWSTR) calloc (ulArgumentLength + 1, sizeof (WCHAR));
  937. wcscpy (pctxSnapshotSet->pwszVolumeArgument [ulIndexVolume], g_pwchNextArgument);
  938. hrStatus = GetVolumeNameFromArgument (pctxSnapshotSet->pwszVolumeArgument [ulIndexVolume],
  939. &pctxSnapshotSet->pwszVolumeName [ulIndexVolume]);
  940. hrStatus = pctxSnapshotSet->pIVssBackupComponents->IsVolumeSupported (GUID_NULL,
  941. pctxSnapshotSet->pwszVolumeName [ulIndexVolume],
  942. &bSupported);
  943. if (bSupported)
  944. {
  945. hrStatus = pctxSnapshotSet->pIVssBackupComponents->AddToSnapshotSet (pctxSnapshotSet->pwszVolumeName [ulIndexVolume],
  946. GUID_NULL,
  947. &pctxSnapshotSet->SnapshotId [ulIndexVolume]);
  948. if (SUCCEEDED (hrStatus))
  949. {
  950. pctxSnapshotSet->ulVolumesInSnapshotSet++;
  951. wprintf (L"Added volume '%s' (%s) to snapshot set\n\n",
  952. pctxSnapshotSet->pwszVolumeName [ulIndexVolume],
  953. pctxSnapshotSet->pwszVolumeArgument [ulIndexVolume]);
  954. }
  955. else
  956. {
  957. wprintf (L"ERROR - Unable to add volume '%s' (%s) to snapshot set (0x%08X)\n\n",
  958. pctxSnapshotSet->pwszVolumeName [ulIndexVolume],
  959. pctxSnapshotSet->pwszVolumeArgument [ulIndexVolume],
  960. hrStatus);
  961. }
  962. }
  963. }
  964. else
  965. {
  966. wprintf (L"ERROR - Missing argument\n\n");
  967. }
  968. return (hrStatus);
  969. }
  970. HRESULT CreateSnapshot (PCONTEXTSNAPSHOTSET pctxSnapshotSet)
  971. {
  972. HRESULT hrStatus = NOERROR;
  973. ULONG ulIndexVolume = 0;
  974. PIVssAsync pIVssAsync;
  975. hrStatus = pctxSnapshotSet->pIVssBackupComponents->PrepareForBackup (&pIVssAsync);
  976. hrStatus = pIVssAsync->Wait ();
  977. hrStatus = pIVssAsync->QueryStatus (&hrStatus, NULL);
  978. /*
  979. ** Could check the status of all the writers at this point but we choose to press on regardless.
  980. */
  981. hrStatus = pctxSnapshotSet->pIVssBackupComponents->DoSnapshotSet (&pctxSnapshotSet->pIVssAsyncDoSnapshotSet);
  982. hrStatus = pctxSnapshotSet->pIVssAsyncDoSnapshotSet->Wait ();
  983. hrStatus = pctxSnapshotSet->pIVssAsyncDoSnapshotSet->QueryStatus (&hrStatus, NULL);
  984. /*
  985. ** Could check the status of all the writers at this point but we choose to press on regardless.
  986. */
  987. for (ulIndexVolume = 0; ulIndexVolume < pctxSnapshotSet->ulVolumesInSnapshotSet; ulIndexVolume++)
  988. {
  989. hrStatus = pctxSnapshotSet->pIVssBackupComponents->GetSnapshotProperties (pctxSnapshotSet->SnapshotId [ulIndexVolume],
  990. &pctxSnapshotSet->SnapshotProperties [ulIndexVolume]);
  991. }
  992. wprintf (L"Created snapshots for the following volume%s:\n",
  993. pctxSnapshotSet->ulVolumesInSnapshotSet > 1 ? "s" : "");
  994. for (ulIndexVolume = 0; ulIndexVolume < pctxSnapshotSet->ulVolumesInSnapshotSet; ulIndexVolume++)
  995. {
  996. wprintf (L" %s for volume %s (%s)\n",
  997. pctxSnapshotSet->SnapshotProperties [ulIndexVolume].m_pwszSnapshotDeviceObject,
  998. pctxSnapshotSet->pwszVolumeName [ulIndexVolume], // or SnapshotProperties [ulIndexVolume].m_pwszSnapshotOriginalVolumeName
  999. pctxSnapshotSet->pwszVolumeArgument [ulIndexVolume]);
  1000. }
  1001. wprintf (L"\n");
  1002. return (hrStatus);
  1003. }
  1004. HRESULT DeleteSnapshot (PCONTEXTSNAPSHOTSET pctxSnapshotSet)
  1005. {
  1006. HRESULT hrStatus = NOERROR;
  1007. CleanupSnapshotSet (pctxSnapshotSet);
  1008. return (hrStatus);
  1009. }