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.

963 lines
34 KiB

  1. /*++
  2. Copyright (c) 1999 Microsoft Corporation
  3. Abstract:
  4. @doc
  5. @module vssadmin.cpp | Implementation of the Volume Snapshots demo
  6. @end
  7. Author:
  8. Adi Oltean [aoltean] 09/17/1999
  9. TBD:
  10. Add comments.
  11. Revision History:
  12. Name Date Comments
  13. aoltean 09/17/1999 Created
  14. --*/
  15. /////////////////////////////////////////////////////////////////////////////
  16. // Includes
  17. // The rest of includes are specified here
  18. #include "vssadmin.h"
  19. #include "versionspecific.h"
  20. #include "commandverifier.h"
  21. #include <locale.h>
  22. #include <winnlsp.h> // in public\internal\base\inc
  23. BOOL AssertPrivilege(
  24. IN LPCWSTR privName
  25. );
  26. ////////////////////////////////////////////////////////////////////////
  27. // Standard foo for file name aliasing. This code block must be after
  28. // all includes of VSS header files.
  29. //
  30. #ifdef VSS_FILE_ALIAS
  31. #undef VSS_FILE_ALIAS
  32. #endif
  33. #define VSS_FILE_ALIAS "ADMVADMC"
  34. //
  35. ////////////////////////////////////////////////////////////////////////
  36. //
  37. // List of hard coded option names. If you add options, make sure to keep this
  38. // list in alphabetical order.
  39. //
  40. const SVssAdmOption g_asAdmOptions[] =
  41. {
  42. { VSSADM_O_ALL, L"All", VSSADM_OT_BOOL },
  43. { VSSADM_O_AUTORETRY, L"AutoRetry", VSSADM_OT_NUM },
  44. { VSSADM_O_EXPOSE_USING, L"ExposeUsing", VSSADM_OT_STR },
  45. { VSSADM_O_FOR, L"For", VSSADM_OT_STR },
  46. { VSSADM_O_MAXSIZE, L"MaxSize", VSSADM_OT_NUM },
  47. { VSSADM_O_OLDEST, L"Oldest", VSSADM_OT_BOOL },
  48. { VSSADM_O_ON, L"On", VSSADM_OT_STR },
  49. { VSSADM_O_PROVIDER, L"Provider", VSSADM_OT_STR },
  50. { VSSADM_O_QUIET, L"Quiet", VSSADM_OT_BOOL },
  51. { VSSADM_O_SET, L"Set", VSSADM_OT_STR },
  52. { VSSADM_O_SHAREPATH, L"SharePath", VSSADM_OT_STR },
  53. { VSSADM_O_SNAPSHOT, L"Shadow", VSSADM_OT_STR },
  54. { VSSADM_O_SNAPTYPE, L"Type", VSSADM_OT_STR },
  55. { VSSADM_O_INVALID, NULL, VSSADM_OT_BOOL }
  56. };
  57. //
  58. // List of vssadmin commands. Keep this in alphabetical order. Also, keep the option flags in the same order as
  59. // the EVssAdmOption and g_asAdmOptions.
  60. //
  61. const SVssAdmCommandsEntry g_asAdmCommands[] =
  62. { // Major Minor Option SKUs MsgGen MsgDetail bShowSSTypes All AutoRtry ExpUsing For MaxSize Oldest On Provider Quiet Set ShrePath Snapshot Type
  63. { L"Add", L"ShadowStorage", VSSADM_C_ADD_DIFFAREA_INT, SKU_INT, MSG_USAGE_GEN_ADD_DIFFAREA, MSG_USAGE_DTL_ADD_DIFFAREA_INT, FALSE, { V_NO, V_NO, V_NO, V_YES, V_OPT, V_NO, V_YES, V_OPT, V_NO, V_NO, V_NO, V_NO, V_NO } },
  64. { L"Add", L"ShadowStorage", VSSADM_C_ADD_DIFFAREA_PUB, SKU_SN, MSG_USAGE_GEN_ADD_DIFFAREA, MSG_USAGE_DTL_ADD_DIFFAREA_PUB, FALSE, { V_NO, V_NO, V_NO, V_YES, V_OPT, V_NO, V_YES, V_NO, V_NO, V_NO, V_NO, V_NO, V_NO } },
  65. { L"Create", L"Shadow", VSSADM_C_CREATE_SNAPSHOT_INT, SKU_INT, MSG_USAGE_GEN_CREATE_SNAPSHOT, MSG_USAGE_DTL_CREATE_SNAPSHOT_INT, TRUE, { V_NO, V_OPT, V_NO, V_YES, V_NO, V_NO, V_NO, V_OPT, V_NO, V_NO, V_NO, V_NO, V_YES } },
  66. { L"Create", L"Shadow", VSSADM_C_CREATE_SNAPSHOT_PUB, SKU_SN, MSG_USAGE_GEN_CREATE_SNAPSHOT, MSG_USAGE_DTL_CREATE_SNAPSHOT_PUB, FALSE, { V_NO, V_OPT, V_NO, V_YES, V_NO, V_NO, V_NO, V_NO, V_NO, V_NO, V_NO, V_NO, V_NO } },
  67. { L"Delete", L"Shadows", VSSADM_C_DELETE_SNAPSHOTS_INT, SKU_INT, MSG_USAGE_GEN_DELETE_SNAPSHOTS, MSG_USAGE_DTL_DELETE_SNAPSHOTS_INT, TRUE, { V_OPT, V_NO, V_NO, V_OPT, V_NO, V_OPT, V_NO, V_NO, V_OPT, V_NO, V_NO, V_OPT, V_OPT } },
  68. { L"Delete", L"Shadows", VSSADM_C_DELETE_SNAPSHOTS_PUB, SKU_SN, MSG_USAGE_GEN_DELETE_SNAPSHOTS, MSG_USAGE_DTL_DELETE_SNAPSHOTS_PUB, FALSE, { V_OPT, V_NO, V_NO, V_OPT, V_NO, V_OPT, V_NO, V_NO, V_OPT, V_NO, V_NO, V_OPT, V_NO } },
  69. { L"Delete", L"ShadowStorage", VSSADM_C_DELETE_DIFFAREAS_INT, SKU_INT, MSG_USAGE_GEN_DELETE_DIFFAREAS, MSG_USAGE_DTL_DELETE_DIFFAREAS_INT, FALSE, { V_NO, V_NO, V_NO, V_YES, V_NO, V_NO, V_OPT, V_OPT, V_OPT, V_NO, V_NO, V_NO, V_NO } },
  70. { L"Delete", L"ShadowStorage", VSSADM_C_DELETE_DIFFAREAS_PUB, SKU_SN, MSG_USAGE_GEN_DELETE_DIFFAREAS, MSG_USAGE_DTL_DELETE_DIFFAREAS_PUB, FALSE, { V_NO, V_NO, V_NO, V_YES, V_NO, V_NO, V_OPT, V_NO, V_OPT, V_NO, V_NO, V_NO, V_NO } },
  71. { L"Expose", L"Shadow", VSSADM_C_EXPOSE_SNAPSHOT, SKU_INT, MSG_USAGE_GEN_EXPOSE_SNAPSHOT, MSG_USAGE_DTL_EXPOSE_SNAPSHOT, FALSE, { V_NO, V_NO, V_OPT, V_NO, V_NO, V_NO, V_NO, V_NO, V_NO, V_NO, V_OPT, V_YES, V_NO } },
  72. { L"List", L"Providers", VSSADM_C_LIST_PROVIDERS, SKU_A, MSG_USAGE_GEN_LIST_PROVIDERS, MSG_USAGE_DTL_LIST_PROVIDERS, FALSE, { V_NO, V_NO, V_NO, V_NO, V_NO, V_NO, V_NO, V_NO, V_NO, V_NO, V_NO, V_NO, V_NO } },
  73. { L"List", L"Shadows", VSSADM_C_LIST_SNAPSHOTS_INT, SKU_INT, MSG_USAGE_GEN_LIST_SNAPSHOTS, MSG_USAGE_DTL_LIST_SNAPSHOTS_INT, TRUE, { V_NO, V_NO, V_NO, V_OPT, V_NO, V_NO, V_NO, V_OPT, V_NO, V_OPT, V_NO, V_OPT, V_OPT } },
  74. { L"List", L"Shadows", VSSADM_C_LIST_SNAPSHOTS_PUB, SKU_A, MSG_USAGE_GEN_LIST_SNAPSHOTS, MSG_USAGE_DTL_LIST_SNAPSHOTS_PUB, FALSE, { V_NO, V_NO, V_NO, V_OPT, V_NO, V_NO, V_NO, V_NO, V_NO, V_OPT, V_NO, V_OPT, V_NO } },
  75. { L"List", L"ShadowStorage", VSSADM_C_LIST_DIFFAREAS_INT, SKU_INT, MSG_USAGE_GEN_LIST_DIFFAREAS, MSG_USAGE_DTL_LIST_DIFFAREAS_INT, FALSE, { V_NO, V_NO, V_NO, V_OPT, V_NO, V_NO, V_OPT, V_OPT, V_NO, V_NO, V_NO, V_NO, V_NO } },
  76. { L"List", L"ShadowStorage", VSSADM_C_LIST_DIFFAREAS_PUB, SKU_SN, MSG_USAGE_GEN_LIST_DIFFAREAS, MSG_USAGE_DTL_LIST_DIFFAREAS_PUB, FALSE, { V_NO, V_NO, V_NO, V_OPT, V_NO, V_NO, V_OPT, V_NO, V_NO, V_NO, V_NO, V_NO, V_NO } },
  77. { L"List", L"Volumes", VSSADM_C_LIST_VOLUMES_INT, SKU_INT, MSG_USAGE_GEN_LIST_VOLUMES, MSG_USAGE_DTL_LIST_VOLUMES_INT, TRUE, { V_NO, V_NO, V_NO, V_NO, V_NO, V_NO, V_NO, V_OPT, V_NO, V_NO, V_NO, V_NO, V_OPT } },
  78. { L"List", L"Volumes", VSSADM_C_LIST_VOLUMES_PUB, SKU_A, MSG_USAGE_GEN_LIST_VOLUMES, MSG_USAGE_DTL_LIST_VOLUMES_PUB, FALSE, { V_NO, V_NO, V_NO, V_NO, V_NO, V_NO, V_NO, V_NO, V_NO, V_NO, V_NO, V_NO, V_NO } },
  79. { L"List", L"Writers", VSSADM_C_LIST_WRITERS, SKU_A, MSG_USAGE_GEN_LIST_WRITERS, MSG_USAGE_DTL_LIST_WRITERS, FALSE, { V_NO, V_NO, V_NO, V_NO, V_NO, V_NO, V_NO, V_NO, V_NO, V_NO, V_NO, V_NO, V_NO } },
  80. { L"Resize", L"ShadowStorage", VSSADM_C_RESIZE_DIFFAREA_INT, SKU_INT, MSG_USAGE_GEN_RESIZE_DIFFAREA, MSG_USAGE_DTL_RESIZE_DIFFAREA_INT, FALSE, { V_NO, V_NO, V_NO, V_YES, V_OPT, V_NO, V_YES, V_OPT, V_NO, V_NO, V_NO, V_NO, V_NO } },
  81. { L"Resize", L"ShadowStorage", VSSADM_C_RESIZE_DIFFAREA_PUB, SKU_SN, MSG_USAGE_GEN_RESIZE_DIFFAREA, MSG_USAGE_DTL_RESIZE_DIFFAREA_PUB, FALSE, { V_NO, V_NO, V_NO, V_YES, V_OPT, V_NO, V_YES, V_NO, V_NO, V_NO, V_NO, V_NO, V_NO } },
  82. { NULL, NULL, VSSADM_C_NUM_COMMANDS, 0, 0, 0, FALSE, { V_NO, V_NO, V_NO, V_NO, V_NO, V_NO, V_NO, V_NO, V_NO, V_NO, V_NO, V_NO, V_NO } }
  83. };
  84. //
  85. // List of snapshot types that are supported by the command line
  86. //
  87. const SVssAdmSnapshotTypeName g_asAdmTypeNames[]=
  88. {
  89. { L"ClientAccessible", SKU_SNI, VSS_CTX_CLIENT_ACCESSIBLE, MSG_TYPE_DESCRIPTION_CLIENTACCESSIBLE},
  90. { L"DataVolumeRollback", SKU_SNI, VSS_CTX_NAS_ROLLBACK, MSG_TYPE_DESCRIPTION_DATAVOLUMEROLLBACK},
  91. { L"ApplicationRollback", SKU_I, VSS_CTX_APP_ROLLBACK, MSG_TYPE_DESCRIPTION_APPLICATIONROLLBACK},
  92. { L"FileShareRollback", SKU_I, VSS_CTX_FILE_SHARE_BACKUP, MSG_TYPE_DESCRIPTION_FILESHAREROLLBACK},
  93. { L"Backup", SKU_I, VSS_CTX_BACKUP, MSG_TYPE_DESCRIPTION_BACKUP},
  94. { NULL, 0, 0, 0 }
  95. };
  96. /////////////////////////////////////////////////////////////////////////////
  97. // Implementation
  98. CVssAdminCLI::CVssAdminCLI(
  99. IN INT argc,
  100. IN PWSTR argv[]
  101. )
  102. /*++
  103. Description:
  104. Standard constructor. Initializes internal members
  105. --*/
  106. {
  107. m_argc = argc;
  108. m_argv = argv;
  109. m_eFilterObjectType = VSS_OBJECT_UNKNOWN;
  110. m_eListedObjectType = VSS_OBJECT_UNKNOWN;
  111. m_FilterSnapshotId = GUID_NULL;
  112. m_nReturnValue = VSS_CMDRET_ERROR;
  113. m_hConsoleOutput = INVALID_HANDLE_VALUE;
  114. m_pMapVolumeNames = NULL;
  115. m_pVerifier = NULL;
  116. }
  117. CVssAdminCLI::~CVssAdminCLI()
  118. /*++
  119. Description:
  120. Standard destructor. Calls Finalize and eventually frees the
  121. memory allocated by internal members.
  122. --*/
  123. {
  124. // Release the cached resource strings
  125. for( int nIndex = 0; nIndex < m_mapCachedResourceStrings.GetSize(); nIndex++) {
  126. LPCWSTR& pwszResString = m_mapCachedResourceStrings.GetValueAt(nIndex);
  127. ::VssFreeString(pwszResString);
  128. }
  129. // Release the cached provider names
  130. for( int nIndex = 0; nIndex < m_mapCachedProviderNames.GetSize(); nIndex++) {
  131. LPCWSTR& pwszProvName = m_mapCachedProviderNames.GetValueAt(nIndex);
  132. ::VssFreeString(pwszProvName);
  133. }
  134. // Release the volume name map if necessary
  135. if ( m_pMapVolumeNames != NULL)
  136. {
  137. for( int nIndex = 0; nIndex < m_pMapVolumeNames->GetSize(); nIndex++)
  138. {
  139. LPCWSTR& pwsz = m_pMapVolumeNames->GetValueAt(nIndex);
  140. ::VssFreeString(pwsz);
  141. pwsz = m_pMapVolumeNames->GetKeyAt(nIndex);
  142. ::VssFreeString(pwsz);
  143. }
  144. delete m_pMapVolumeNames;
  145. }
  146. delete m_pVerifier;
  147. // Uninitialize the COM library
  148. Finalize();
  149. }
  150. /////////////////////////////////////////////////////////////////////////////
  151. // Implementation
  152. void CVssAdminCLI::GetProviderId(
  153. OUT VSS_ID *pProviderId
  154. )
  155. {
  156. CVssFunctionTracer ft( VSSDBG_VSSADMIN, L"CVssAdminCLI::GetProviderId" );
  157. // If a provider is not specified, always return babbage
  158. if (g_asAdmCommands[ m_sParsedCommand.eAdmCmd].aeOptionFlags[VSSADM_O_PROVIDER] == V_NO) {
  159. *pProviderId = VSS_SWPRV_ProviderId;
  160. return;
  161. }
  162. *pProviderId = GUID_NULL;
  163. //
  164. // If user specified a provider, process option
  165. //
  166. LPCWSTR pwszProvider = GetOptionValueStr( VSSADM_O_PROVIDER );
  167. if (pwszProvider != NULL )
  168. {
  169. //
  170. // Determine if this is an ID or a name
  171. //
  172. if ( !ScanGuid( pwszProvider, *pProviderId ) )
  173. {
  174. // Have a provider name, look it up
  175. if ( !GetProviderIdByName( pwszProvider, pProviderId ) )
  176. {
  177. // Provider name not found, print error
  178. OutputErrorMsg( MSG_ERROR_PROVIDER_NAME_NOT_FOUND, pwszProvider );
  179. // Throw S_OK since the error message has already been output
  180. ft.Throw( VSSDBG_VSSADMIN, S_OK, L"Already printed error message" );
  181. }
  182. }
  183. }
  184. }
  185. LPCWSTR CVssAdminCLI::GetProviderName(
  186. IN VSS_ID& ProviderId
  187. ) throw(HRESULT)
  188. {
  189. CVssFunctionTracer ft( VSSDBG_VSSADMIN, L"CVssAdminCLI::GetProviderName" );
  190. LPCWSTR wszReturnedString = m_mapCachedProviderNames.Lookup(ProviderId);
  191. if (wszReturnedString)
  192. return wszReturnedString;
  193. CComPtr<IVssCoordinator> pICoord;
  194. ft.CoCreateInstanceWithLog(
  195. VSSDBG_VSSADMIN,
  196. CLSID_VSSCoordinator,
  197. L"Coordinator",
  198. CLSCTX_ALL,
  199. IID_IVssCoordinator,
  200. (IUnknown**)&(pICoord));
  201. if ( ft.HrFailed() )
  202. ft.Throw( VSSDBG_VSSADMIN, E_UNEXPECTED, L"Connection failed with hr = 0x%08lx", ft.hr);
  203. CComPtr<IVssEnumObject> pIEnumProvider;
  204. ft.hr = pICoord->Query( GUID_NULL,
  205. VSS_OBJECT_NONE,
  206. VSS_OBJECT_PROVIDER,
  207. &pIEnumProvider );
  208. if ( ft.HrFailed() )
  209. ft.Throw( VSSDBG_VSSADMIN, ft.hr, L"Query failed with hr = 0x%08lx", ft.hr);
  210. VSS_OBJECT_PROP Prop;
  211. VSS_PROVIDER_PROP& Prov = Prop.Obj.Prov;
  212. // Go through the list of providers to find the one we are interested in.
  213. ULONG ulFetched;
  214. while( 1 )
  215. {
  216. ft.hr = pIEnumProvider->Next( 1, &Prop, &ulFetched );
  217. if ( ft.HrFailed() )
  218. ft.Throw( VSSDBG_VSSADMIN, ft.hr, L"Next failed with hr = 0x%08lx", ft.hr);
  219. if (ft.hr == S_FALSE) {
  220. // End of enumeration.
  221. // Provider not registered? Where did this snapshot come from?
  222. // It might be still possible if a snapshot provider was deleted
  223. // before querying the snapshot provider but after the snapshot attributes
  224. // were queried.
  225. BS_ASSERT(ulFetched == 0);
  226. return LoadString( IDS_UNKNOWN_PROVIDER );
  227. }
  228. ::VssFreeString( Prov.m_pwszProviderVersion );
  229. if (Prov.m_ProviderId == ProviderId)
  230. {
  231. break;
  232. }
  233. ::VssFreeString( Prov.m_pwszProviderName );
  234. }
  235. // Auto delete the string
  236. CVssAutoPWSZ awszProviderName( Prov.m_pwszProviderName );
  237. // Duplicate the new string
  238. LPWSTR wszNewString = NULL;
  239. BS_ASSERT( (LPCWSTR)awszProviderName != NULL );
  240. ::VssSafeDuplicateStr( ft, wszNewString, awszProviderName );
  241. wszReturnedString = wszNewString;
  242. // Save the string in the cache, transfer of pointer ownership.
  243. if (!m_mapCachedProviderNames.Add( ProviderId, wszReturnedString )) {
  244. ::VssFreeString( wszReturnedString );
  245. ft.Throw( VSSDBG_COORD, E_OUTOFMEMORY, L"Memory allocation error");
  246. }
  247. return wszReturnedString;
  248. }
  249. BOOL CVssAdminCLI::GetProviderIdByName(
  250. IN LPCWSTR pwszProviderName,
  251. OUT VSS_ID *pProviderId
  252. ) throw(HRESULT)
  253. {
  254. CVssFunctionTracer ft( VSSDBG_VSSADMIN, L"CVssAdminCLI::GetProviderIdByName" );
  255. CComPtr<IVssCoordinator> pICoord;
  256. ft.CoCreateInstanceWithLog(
  257. VSSDBG_VSSADMIN,
  258. CLSID_VSSCoordinator,
  259. L"Coordinator",
  260. CLSCTX_ALL,
  261. IID_IVssCoordinator,
  262. (IUnknown**)&(pICoord));
  263. if ( ft.HrFailed() )
  264. ft.Throw( VSSDBG_VSSADMIN, ft.hr, L"Connection failed with hr = 0x%08lx", ft.hr);
  265. CComPtr<IVssEnumObject> pIEnumProvider;
  266. ft.hr = pICoord->Query( GUID_NULL,
  267. VSS_OBJECT_NONE,
  268. VSS_OBJECT_PROVIDER,
  269. &pIEnumProvider );
  270. if ( ft.HrFailed() )
  271. ft.Throw( VSSDBG_VSSADMIN, ft.hr, L"Query failed with hr = 0x%08lx", ft.hr);
  272. VSS_OBJECT_PROP Prop;
  273. VSS_PROVIDER_PROP& Prov = Prop.Obj.Prov;
  274. // Go through the list of providers to find the one we are interested in.
  275. ULONG ulFetched;
  276. while( 1 )
  277. {
  278. ft.hr = pIEnumProvider->Next( 1, &Prop, &ulFetched );
  279. if ( ft.HrFailed() )
  280. ft.Throw( VSSDBG_VSSADMIN, ft.hr, L"Next failed with hr = 0x%08lx", ft.hr);
  281. if (ft.hr == S_FALSE) {
  282. // End of enumeration.
  283. // Provider not registered? Where did this snapshot come from?
  284. // It might be still possible if a snapshot provider was deleted
  285. // before querying the snapshot provider but after the snapshot attributes
  286. // were queried.
  287. BS_ASSERT(ulFetched == 0);
  288. *pProviderId = GUID_NULL;
  289. return FALSE;
  290. }
  291. ::VssFreeString( Prov.m_pwszProviderVersion );
  292. if (::_wcsicmp( Prov.m_pwszProviderName, pwszProviderName) == 0)
  293. {
  294. ::VssFreeString( Prov.m_pwszProviderName );
  295. break;
  296. }
  297. ::VssFreeString( Prov.m_pwszProviderName );
  298. }
  299. *pProviderId = Prov.m_ProviderId;
  300. return TRUE;
  301. }
  302. /////////////////////////////////////////////////////////////////////////////
  303. // Implementation
  304. void CVssAdminCLI::Initialize(
  305. ) throw(HRESULT)
  306. /*++
  307. Description:
  308. Initializes the COM library. Called explicitely after instantiating the CVssAdminCLI object.
  309. --*/
  310. {
  311. CVssFunctionTracer ft( VSSDBG_VSSADMIN, L"CVssAdminCLI::Initialize" );
  312. // Use the OEM code page ...
  313. ::setlocale(LC_ALL, ".OCP");
  314. // Use the console UI language
  315. ::SetThreadUILanguage( 0 );
  316. //
  317. // Use only the Console routines to output messages. To do so, need to open standard
  318. // output.
  319. //
  320. m_hConsoleOutput = ::GetStdHandle(STD_OUTPUT_HANDLE);
  321. if (m_hConsoleOutput == INVALID_HANDLE_VALUE)
  322. {
  323. ft.Throw( VSSDBG_VSSADMIN, HRESULT_FROM_WIN32( ::GetLastError() ),
  324. L"Initialize - Error from GetStdHandle(), rc: %d",
  325. ::GetLastError() );
  326. }
  327. // Initialize COM library
  328. ft.hr = CoInitializeEx(NULL, COINIT_MULTITHREADED);
  329. if (ft.HrFailed())
  330. ft.Throw( VSSDBG_VSSADMIN, ft.hr, L"Failure in initializing the COM library 0x%08lx", ft.hr);
  331. // Initialize COM security
  332. ft.hr = CoInitializeSecurity(
  333. NULL, // IN PSECURITY_DESCRIPTOR pSecDesc,
  334. -1, // IN LONG cAuthSvc,
  335. NULL, // IN SOLE_AUTHENTICATION_SERVICE *asAuthSvc,
  336. NULL, // IN void *pReserved1,
  337. RPC_C_AUTHN_LEVEL_PKT_PRIVACY, // IN DWORD dwAuthnLevel,
  338. RPC_C_IMP_LEVEL_IDENTIFY, // IN DWORD dwImpLevel,
  339. NULL, // IN void *pAuthList,
  340. EOAC_NONE, // IN DWORD dwCapabilities,
  341. NULL // IN void *pReserved3
  342. );
  343. if (ft.HrFailed()) {
  344. ft.Throw( VSSDBG_VSSADMIN, ft.hr,
  345. L" Error: CoInitializeSecurity() returned 0x%08lx", ft.hr );
  346. }
  347. // Turns off SEH exception handing for COM servers (BUG# 530092)
  348. ft.ComDisableSEH(VSSDBG_VSSADMIN);
  349. //
  350. // Assert the Backup privilage. Not worried about errors here since VSS will
  351. // return access denied return codes if the user doesn't have permission.
  352. //
  353. (void)::AssertPrivilege (SE_BACKUP_NAME);
  354. // Create an instance of the parameter checker
  355. m_pVerifier = CCommandVerifier::Instance();
  356. if (m_pVerifier == NULL)
  357. ft.Throw( VSSDBG_VSSADMIN, E_OUTOFMEMORY, L"Out of memory" );
  358. // Print the header
  359. OutputMsg( MSG_UTILITY_HEADER );
  360. }
  361. //
  362. // Returns true if the command line was parsed fine
  363. //
  364. BOOL CVssAdminCLI::ParseCmdLine(
  365. ) throw(HRESULT)
  366. /*++
  367. Description:
  368. Parses the command line.
  369. --*/
  370. {
  371. CVssFunctionTracer ft( VSSDBG_VSSADMIN, L"CVssAdminCLI::ParseCmdLine" );
  372. // Skip the executable name
  373. GetNextCmdlineToken( true );
  374. // Get the first token after the executable name
  375. LPCWSTR pwszMajor = GetNextCmdlineToken();
  376. LPCWSTR pwszMinor = NULL;
  377. if ( pwszMajor != NULL )
  378. {
  379. if ( ::wcscmp( pwszMajor, L"/?" ) == 0 || ::wcscmp( pwszMajor, L"-?" ) == 0 )
  380. return FALSE;
  381. pwszMinor = GetNextCmdlineToken();
  382. }
  383. if ( pwszMajor == NULL || pwszMinor == NULL )
  384. {
  385. ft.Throw( VSSDBG_VSSADMIN, VSSADM_E_INVALID_COMMAND, L"Incomplete command");
  386. }
  387. INT idx;
  388. // See if the command is found in list of commands
  389. for ( idx = VSSADM_C_FIRST; idx < VSSADM_C_NUM_COMMANDS; ++idx )
  390. {
  391. if ( ( dCurrentSKU & g_asAdmCommands[idx].dwSKUs ) &&
  392. Match( pwszMajor, g_asAdmCommands[idx].pwszMajorOption ) &&
  393. Match( pwszMinor, g_asAdmCommands[idx].pwszMinorOption ) )
  394. {
  395. //
  396. // Got a match
  397. //
  398. break;
  399. }
  400. }
  401. if ( idx == VSSADM_C_NUM_COMMANDS )
  402. {
  403. ft.Throw( VSSDBG_VSSADMIN, VSSADM_E_INVALID_COMMAND, L"Invalid command");
  404. }
  405. //
  406. // Found the command.
  407. //
  408. m_eCommandType = ( EVssAdmCommand )idx;
  409. m_sParsedCommand.eAdmCmd = ( EVssAdmCommand )idx;
  410. //
  411. // Now need to process command line options
  412. //
  413. LPCWSTR pwszOption = GetNextCmdlineToken();
  414. while ( pwszOption != NULL )
  415. {
  416. if ( pwszOption[0] == L'/' || pwszOption[0] == L'-' )
  417. {
  418. //
  419. // Got a named option, now see if it is a valid option
  420. // for the command.
  421. //
  422. // Skip past delimiter
  423. ++pwszOption;
  424. //
  425. // See if they want usage
  426. //
  427. if ( pwszOption[0] == L'?' )
  428. return FALSE;
  429. // Parse out the value part of the named option
  430. LPWSTR pwszValue = ::wcschr( pwszOption, L'=' );
  431. if ( pwszValue != NULL )
  432. {
  433. // Replace = with NULL char and set value to point to string after the =
  434. pwszValue[0] = L'\0';
  435. ++pwszValue;
  436. }
  437. // At this point, if pwszValue == NULL, it means the option had no = and so no specified value.
  438. // If pwszValue[0] == L'\0', then the value is an empty value
  439. INT eOpt;
  440. // Now figure out which named option this is
  441. for ( eOpt = VSSADM_O_FIRST; eOpt < VSSADM_O_NUM_OPTIONS; ++eOpt )
  442. {
  443. if ( Match( g_asAdmOptions[eOpt].pwszOptName, pwszOption ) )
  444. break;
  445. }
  446. // See if this is a bogus option
  447. if ( eOpt == VSSADM_O_NUM_OPTIONS )
  448. {
  449. ft.Throw( VSSDBG_VSSADMIN, VSSADM_E_INVALID_OPTION, L"Invalid option: %s", pwszOption);
  450. }
  451. // See if this option has already been specified
  452. if ( m_sParsedCommand.apwszOptionValues[eOpt] != NULL )
  453. {
  454. ft.Throw( VSSDBG_VSSADMIN, VSSADM_E_DUPLICATE_OPTION, L"Duplicate option given: %s", pwszOption);
  455. }
  456. // See if this option is allowed for the command
  457. if ( g_asAdmCommands[ m_sParsedCommand.eAdmCmd ].aeOptionFlags[ eOpt ] == V_NO )
  458. {
  459. ft.Throw( VSSDBG_VSSADMIN, VSSADM_E_OPTION_NOT_ALLOWED_FOR_COMMAND, L"Option not allowed for this command: %s", pwszOption);
  460. }
  461. // See if this option is supposed to have a value, BOOL options do not
  462. if ( ( g_asAdmOptions[eOpt].eOptType == VSSADM_OT_BOOL && pwszValue != NULL ) ||
  463. ( g_asAdmOptions[eOpt].eOptType != VSSADM_OT_BOOL && ( pwszValue == NULL || pwszValue[0] == L'\0' ) ) )
  464. {
  465. ft.Throw( VSSDBG_VSSADMIN, VSSADM_E_INVALID_OPTION_VALUE, L"Invalid option value: /%s=%s", pwszOption, pwszValue ? pwszValue : L"<MISSING>" );
  466. }
  467. // Finally, we have a valid option, save away the option value.
  468. // See if it is a boolean type. In the option array we store the wszVssOptBoolTrue string.
  469. // The convention is if the option is NULL, then the boolean option is false, else it
  470. // is true.
  471. if ( g_asAdmOptions[eOpt].eOptType == VSSADM_OT_BOOL )
  472. ::VssSafeDuplicateStr( ft, m_sParsedCommand.apwszOptionValues[eOpt], x_wszVssOptBoolTrue );
  473. else
  474. ::VssSafeDuplicateStr( ft, m_sParsedCommand.apwszOptionValues[eOpt], pwszValue );
  475. }
  476. else
  477. {
  478. //
  479. // Got an unnamed option, not valid in any command
  480. //
  481. ft.Throw( VSSDBG_VSSADMIN, VSSADM_E_INVALID_COMMAND, L"Invalid command");
  482. }
  483. pwszOption = GetNextCmdlineToken();
  484. }
  485. // We are done parsing the command-line. Now see if any mandatory named options were missing
  486. for ( idx = VSSADM_O_FIRST; idx < VSSADM_O_NUM_OPTIONS; ++idx )
  487. {
  488. if ( ( m_sParsedCommand.apwszOptionValues[idx] == NULL ) &&
  489. ( g_asAdmCommands[ m_sParsedCommand.eAdmCmd ].aeOptionFlags[ idx ] == V_YES ) )
  490. {
  491. ft.Throw( VSSDBG_VSSADMIN, VSSADM_E_REQUIRED_OPTION_MISSING, L"Required option missing");
  492. }
  493. }
  494. //
  495. // Now fix up certain options if needed
  496. //
  497. LPWSTR pwszStr;
  498. // Need a \ at the end of the FOR option
  499. pwszStr = m_sParsedCommand.apwszOptionValues[ VSSADM_O_FOR ];
  500. if ( pwszStr != NULL )
  501. {
  502. if ( pwszStr[ ::wcslen( pwszStr ) - 1 ] != L'\\' )
  503. {
  504. pwszStr = ::VssReallocString( ft, pwszStr, (LONG)::wcslen( pwszStr ) + 1 );
  505. ::wcscat( pwszStr, L"\\" );
  506. m_sParsedCommand.apwszOptionValues[ VSSADM_O_FOR ] = pwszStr;
  507. }
  508. }
  509. // Need a \ at the end of the ON option
  510. pwszStr = m_sParsedCommand.apwszOptionValues[ VSSADM_O_ON ];
  511. if ( pwszStr != NULL )
  512. {
  513. if ( pwszStr[ ::wcslen( pwszStr ) - 1 ] != L'\\' )
  514. {
  515. pwszStr = ::VssReallocString( ft, pwszStr, (LONG)::wcslen( pwszStr ) + 1 );
  516. ::wcscat( pwszStr, L"\\" );
  517. m_sParsedCommand.apwszOptionValues[ VSSADM_O_ON ] = pwszStr;
  518. }
  519. }
  520. return TRUE;
  521. }
  522. void CVssAdminCLI::DoProcessing(
  523. ) throw(HRESULT)
  524. {
  525. CVssFunctionTracer ft( VSSDBG_VSSADMIN, L"CVssAdminCLI::DoProcessing" );
  526. switch( m_sParsedCommand.eAdmCmd )
  527. {
  528. case VSSADM_C_CREATE_SNAPSHOT_INT:
  529. case VSSADM_C_CREATE_SNAPSHOT_PUB:
  530. CreateSnapshot();
  531. break;
  532. case VSSADM_C_LIST_PROVIDERS:
  533. ListProviders();
  534. break;
  535. case VSSADM_C_LIST_SNAPSHOTS_INT:
  536. case VSSADM_C_LIST_SNAPSHOTS_PUB:
  537. ListSnapshots();
  538. break;
  539. case VSSADM_C_LIST_WRITERS:
  540. ListWriters();
  541. break;
  542. case VSSADM_C_ADD_DIFFAREA_INT:
  543. case VSSADM_C_ADD_DIFFAREA_PUB:
  544. AddDiffArea();
  545. break;
  546. case VSSADM_C_RESIZE_DIFFAREA_INT:
  547. case VSSADM_C_RESIZE_DIFFAREA_PUB:
  548. ResizeDiffArea();
  549. break;
  550. case VSSADM_C_DELETE_DIFFAREAS_INT:
  551. case VSSADM_C_DELETE_DIFFAREAS_PUB:
  552. DeleteDiffAreas();
  553. break;
  554. case VSSADM_C_LIST_DIFFAREAS_INT:
  555. case VSSADM_C_LIST_DIFFAREAS_PUB:
  556. ListDiffAreas();
  557. break;
  558. case VSSADM_C_DELETE_SNAPSHOTS_INT:
  559. case VSSADM_C_DELETE_SNAPSHOTS_PUB:
  560. DeleteSnapshots();
  561. break;
  562. case VSSADM_C_EXPOSE_SNAPSHOT:
  563. ExposeSnapshot();
  564. break;
  565. case VSSADM_C_LIST_VOLUMES_INT:
  566. case VSSADM_C_LIST_VOLUMES_PUB:
  567. ListVolumes();
  568. break;
  569. default:
  570. ft.Throw( VSSDBG_COORD, E_UNEXPECTED,
  571. L"Invalid command type: %d", m_eCommandType);
  572. }
  573. }
  574. void CVssAdminCLI::Finalize()
  575. /*++
  576. Description:
  577. Uninitialize the COM library. Called in CVssAdminCLI destructor.
  578. --*/
  579. {
  580. // Uninitialize COM library
  581. CoUninitialize();
  582. }
  583. HRESULT CVssAdminCLI::Main(
  584. IN INT argc,
  585. IN PWSTR argv[]
  586. )
  587. /*++
  588. Function:
  589. CVssAdminCLI::Main
  590. Description:
  591. Static function used as the main entry point in the VSS CLI
  592. --*/
  593. {
  594. CVssFunctionTracer ft( VSSDBG_VSSADMIN, L"CVssAdminCLI::Main" );
  595. INT nReturnValue = VSS_CMDRET_ERROR;
  596. try
  597. {
  598. CVssAdminCLI program(argc, argv);
  599. try
  600. {
  601. // Initialize the program. This calls CoInitialize()
  602. program.Initialize();
  603. // Parse the command line
  604. if ( program.ParseCmdLine() )
  605. {
  606. // Do the work...
  607. program.DoProcessing();
  608. }
  609. else
  610. {
  611. // Error parsing the command line, print out usage
  612. program.PrintUsage();
  613. }
  614. ft.hr = S_OK; // Assume that the above methods printed error
  615. // messages if there was an error.
  616. }
  617. VSS_STANDARD_CATCH(ft)
  618. nReturnValue = program.GetReturnValue();
  619. //
  620. // Log the error if this is create snapshot
  621. //
  622. if ( ft.hr != S_OK && (program.m_eCommandType == VSSADM_C_CREATE_SNAPSHOT_INT ||
  623. program.m_eCommandType == VSSADM_C_CREATE_SNAPSHOT_PUB) &&
  624. !UnloggableError(ft.hr))
  625. {
  626. //
  627. // Log error message
  628. //
  629. LPWSTR pwszSnapshotErrMsg;
  630. pwszSnapshotErrMsg = program.GetMsg( FALSE, MSG_ERROR_UNABLE_TO_CREATE_SNAPSHOT );
  631. if ( pwszSnapshotErrMsg == NULL )
  632. {
  633. ft.Throw( VSSDBG_VSSADMIN, E_UNEXPECTED,
  634. L"Error on loading the message string id %d. 0x%08lx",
  635. MSG_ERROR_UNABLE_TO_CREATE_SNAPSHOT, ::GetLastError() );
  636. }
  637. LONG lMsgNum;
  638. LPWSTR pwszMsg = NULL;
  639. if ( ::MapVssErrorToMsg( ft.hr, &lMsgNum ) )
  640. {
  641. pwszMsg = program.GetMsg( FALSE, lMsgNum );
  642. if ( pwszMsg == NULL )
  643. {
  644. ft.Throw( VSSDBG_VSSADMIN, E_UNEXPECTED,
  645. L"Error on loading the message string id %d. 0x%08lx",
  646. lMsgNum, ::GetLastError() );
  647. }
  648. ft.LogError( VSS_ERROR_VSSADMIN_ERROR, VSSDBG_VSSADMIN << pwszSnapshotErrMsg << pwszMsg << ::GetCommandLineW() );
  649. ::VssFreeString( pwszMsg );
  650. }
  651. else
  652. {
  653. // Try to get the system error message
  654. pwszMsg = program.GetMsg( FALSE, ft.hr );
  655. if ( pwszMsg != NULL )
  656. {
  657. ft.LogError( VSS_ERROR_VSSADMIN_ERROR, VSSDBG_VSSADMIN << pwszSnapshotErrMsg << pwszMsg << ::GetCommandLineW() );
  658. ::VssFreeString( pwszMsg );
  659. }
  660. else
  661. {
  662. WCHAR wszHr[64];
  663. StringCchPrintfW( STRING_CCH_PARAM(wszHr), L"hr = 0x%08x", ft.hr );
  664. ft.LogError( VSS_ERROR_VSSADMIN_ERROR, VSSDBG_VSSADMIN << pwszSnapshotErrMsg << wszHr << ::GetCommandLineW() );
  665. }
  666. }
  667. ::VssFreeString( pwszSnapshotErrMsg );
  668. }
  669. //
  670. // Print the error on the display, if any
  671. //
  672. if ( ft.hr != S_OK )
  673. {
  674. LONG lMsgNum;
  675. // If the error is empty query, print out a message stating that
  676. if ( ft.hr == VSSADM_E_NO_ITEMS_IN_QUERY )
  677. {
  678. nReturnValue = VSS_CMDRET_EMPTY_RESULT;
  679. program.OutputMsg( MSG_ERROR_NO_ITEMS_FOUND );
  680. }
  681. else if ( ::MapVssErrorToMsg(ft.hr, &lMsgNum ) )
  682. {
  683. // This is a parsing or VSS error, map it to a msg id
  684. program.OutputErrorMsg( lMsgNum );
  685. if ( ft.hr >= VSSADM_E_FIRST_PARSING_ERROR && ft.hr <= VSSADM_E_LAST_PARSING_ERROR )
  686. {
  687. program.PrintUsage();
  688. }
  689. }
  690. else
  691. {
  692. // Unhandled error, try to get the error string from the system
  693. LPWSTR pwszMsg;
  694. // Try to get the system error message
  695. pwszMsg = program.GetMsg( FALSE, ft.hr );
  696. if ( pwszMsg != NULL )
  697. {
  698. program.OutputMsg( MSG_ERROR_UNEXPECTED_WITH_STRING, pwszMsg );
  699. ::VssFreeString( pwszMsg );
  700. }
  701. else
  702. {
  703. program.OutputMsg( MSG_ERROR_UNEXPECTED_WITH_HRESULT, ft.hr );
  704. }
  705. }
  706. }
  707. // The destructor automatically calls CoUninitialize()
  708. }
  709. VSS_STANDARD_CATCH(ft)
  710. return nReturnValue;
  711. }
  712. BOOL AssertPrivilege(
  713. IN LPCWSTR privName
  714. )
  715. {
  716. HANDLE tokenHandle;
  717. BOOL stat = FALSE;
  718. if ( ::OpenProcessToken (GetCurrentProcess(),
  719. TOKEN_ADJUST_PRIVILEGES|TOKEN_QUERY,
  720. &tokenHandle))
  721. {
  722. LUID value;
  723. if ( ::LookupPrivilegeValueW( NULL, privName, &value ) )
  724. {
  725. TOKEN_PRIVILEGES newState;
  726. DWORD error;
  727. newState.PrivilegeCount = 1;
  728. newState.Privileges[0].Luid = value;
  729. newState.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED_BY_DEFAULT|SE_PRIVILEGE_ENABLED;
  730. /*
  731. * We will always call GetLastError below, so clear
  732. * any prior error values on this thread.
  733. */
  734. ::SetLastError( ERROR_SUCCESS );
  735. stat = ::AdjustTokenPrivileges (tokenHandle,
  736. FALSE,
  737. &newState,
  738. (DWORD)0,
  739. NULL,
  740. NULL );
  741. /*
  742. * Supposedly, AdjustTokenPriveleges always returns TRUE
  743. * (even when it fails). So, call GetLastError to be
  744. * extra sure everything's cool.
  745. */
  746. if ( (error = ::GetLastError()) != ERROR_SUCCESS )
  747. {
  748. stat = FALSE;
  749. }
  750. }
  751. DWORD cbTokens;
  752. ::GetTokenInformation (tokenHandle,
  753. TokenPrivileges,
  754. NULL,
  755. 0,
  756. &cbTokens);
  757. TOKEN_PRIVILEGES *pTokens = (TOKEN_PRIVILEGES *) new BYTE[cbTokens];
  758. ::GetTokenInformation (tokenHandle,
  759. TokenPrivileges,
  760. pTokens,
  761. cbTokens,
  762. &cbTokens);
  763. delete pTokens;
  764. ::CloseHandle( tokenHandle );
  765. }
  766. return stat;
  767. }
  768. /////////////////////////////////////////////////////////////////////////////
  769. // WinMain
  770. extern "C" INT __cdecl wmain(
  771. IN INT argc,
  772. IN PWSTR argv[]
  773. )
  774. {
  775. return CVssAdminCLI::Main(argc, argv);
  776. }