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.

725 lines
20 KiB

  1. //-----------------------------------------------------------------------//
  2. //
  3. // File: delete.cpp
  4. // Created: April 1997
  5. // By: Martin Holladay (a-martih)
  6. // Purpose: Registry Delete Support for REG.CPP
  7. // Modification History:
  8. // Copied from Update.cpp and modificd - April 1997 (a-martih)
  9. // April 1999 Zeyong Xu: re-design, revision -> version 2.0
  10. //
  11. //------------------------------------------------------------------------//
  12. #include "stdafx.h"
  13. #include "reg.h"
  14. //
  15. // function prototypes
  16. //
  17. LONG DeleteValues( PTREG_PARAMS pParams );
  18. LONG RecursiveDeleteKey( HKEY hKey, LPCWSTR pwszName,
  19. DWORD dwDepth, PTREG_PARAMS pParams );
  20. BOOL ParseDeleteCmdLine( DWORD argc, LPCWSTR argv[],
  21. PTREG_PARAMS pParams, BOOL* pbUsage );
  22. //
  23. // implementation
  24. //
  25. //-----------------------------------------------------------------------//
  26. //
  27. // DeleteRegistry()
  28. //
  29. //-----------------------------------------------------------------------//
  30. LONG
  31. DeleteRegistry( DWORD argc, LPCWSTR argv[] )
  32. {
  33. // local variables
  34. LONG lResult = 0;
  35. BOOL bUsage = FALSE;
  36. BOOL bResult = TRUE;
  37. TREG_PARAMS params;
  38. LPCWSTR pwszList = NULL;
  39. LPCWSTR pwszFormat = NULL;
  40. // check the input
  41. if( argc == 0 || argv == NULL )
  42. {
  43. SaveErrorMessage( ERROR_INVALID_PARAMETER );
  44. ShowLastErrorEx( stderr, SLE_INTERNAL );
  45. return 1;
  46. }
  47. // initialize the global data structure
  48. InitGlobalData( REG_DELETE, &params );
  49. //
  50. // Parse the cmd-line
  51. //
  52. bResult = ParseDeleteCmdLine( argc, argv, &params, &bUsage );
  53. if( bResult == FALSE )
  54. {
  55. ShowLastErrorEx( stderr, SLE_INTERNAL );
  56. FreeGlobalData( &params );
  57. return 1;
  58. }
  59. // check whether we need to display the usage
  60. if ( bUsage == TRUE )
  61. {
  62. Usage( REG_DELETE );
  63. FreeGlobalData( &params );
  64. return 0;
  65. }
  66. //
  67. // Connect to the Remote Machine(s) - if applicable
  68. //
  69. bResult = RegConnectMachine( &params );
  70. if( bResult == FALSE )
  71. {
  72. SaveErrorMessage( -1 );
  73. ShowLastErrorEx( stderr, SLE_TYPE_ERROR | SLE_INTERNAL );
  74. }
  75. // if delete a value or delete all values under this key
  76. else if( params.pwszValueName != NULL || params.bAllValues == TRUE )
  77. {
  78. lResult = DeleteValues( &params );
  79. }
  80. //
  81. // if delete the key
  82. else
  83. {
  84. pwszFormat = GetResString2( IDS_DELETE_PERMANENTLY, 0 );
  85. pwszList = GetResString2( IDS_CONFIRM_CHOICE_LIST, 1 );
  86. do
  87. {
  88. lResult = Prompt( pwszFormat,
  89. params.pwszFullKey, pwszList, params.bForce );
  90. } while ( lResult > 2 );
  91. if ( lResult == 1 )
  92. {
  93. lResult = RecursiveDeleteKey(
  94. params.hRootKey, params.pwszSubKey, 0, &params );
  95. }
  96. else
  97. {
  98. SaveErrorMessage( ERROR_CANCELLED );
  99. ShowLastErrorEx( stdout, SLE_INTERNAL );
  100. lResult = ERROR_SUCCESS;
  101. }
  102. }
  103. // return
  104. FreeGlobalData( &params );
  105. return ((lResult == ERROR_SUCCESS) ? 0 : 1);
  106. }
  107. //------------------------------------------------------------------------//
  108. //
  109. // ParseDeleteCmdLine()
  110. //
  111. //------------------------------------------------------------------------//
  112. BOOL
  113. ParseDeleteCmdLine( DWORD argc, LPCWSTR argv[],
  114. PTREG_PARAMS pParams, BOOL* pbUsage )
  115. {
  116. // local variables
  117. DWORD dw = 0;
  118. LONG lResult = 0;
  119. DWORD dwLength = 0;
  120. BOOL bResult = FALSE;
  121. BOOL bHasValue = FALSE;
  122. // check the input
  123. if ( argc == 0 || argv == NULL || pParams == NULL || pbUsage == NULL )
  124. {
  125. SaveErrorMessage( ERROR_INVALID_PARAMETER );
  126. return FALSE;
  127. }
  128. // check whether this function is being called for
  129. // valid operation or not
  130. if ( pParams->lOperation < 0 || pParams->lOperation >= REG_OPTIONS_COUNT )
  131. {
  132. SaveErrorMessage( ERROR_INVALID_PARAMETER );
  133. return FALSE;
  134. }
  135. if( argc < 3 || argc > 6 )
  136. {
  137. SetLastError( (DWORD) MK_E_SYNTAX );
  138. SetReason2( 1, ERROR_INVALID_SYNTAX_WITHOPT, g_wszOptions[ REG_DELETE ] );
  139. return FALSE;
  140. }
  141. else if ( StringCompareEx( argv[ 1 ], L"DELETE", TRUE, 0 ) != 0 )
  142. {
  143. SaveErrorMessage( ERROR_INVALID_PARAMETER );
  144. return FALSE;
  145. }
  146. else if ( InString( argv[ 2 ], L"-?|/?|-h|/h", TRUE ) == TRUE )
  147. {
  148. if ( argc == 3 )
  149. {
  150. *pbUsage = TRUE;
  151. return TRUE;
  152. }
  153. else
  154. {
  155. SetLastError( (DWORD) MK_E_SYNTAX );
  156. SetReason2( 1, ERROR_INVALID_SYNTAX_WITHOPT, g_wszOptions[ REG_DELETE ] );
  157. return FALSE;
  158. }
  159. }
  160. // Machine Name and Registry key
  161. //
  162. bResult = BreakDownKeyString( argv[ 2 ], pParams );
  163. if( bResult == FALSE )
  164. {
  165. return FALSE;
  166. }
  167. // parsing
  168. bResult = TRUE;
  169. lResult = ERROR_SUCCESS;
  170. for( dw = 3; dw < argc; dw++ )
  171. {
  172. if( StringCompareEx( argv[ dw ], L"/v", TRUE, 0 ) == 0 )
  173. {
  174. if( bHasValue == TRUE )
  175. {
  176. bResult = FALSE;
  177. lResult = IDS_ERROR_INVALID_SYNTAX_WITHOPT;
  178. break;
  179. }
  180. dw++;
  181. if( dw < argc )
  182. {
  183. dwLength = StringLength( argv[ dw ], 0 ) + 1;
  184. pParams->pwszValueName =
  185. (LPWSTR) AllocateMemory( (dwLength + 5) * sizeof( WCHAR ) );
  186. if ( pParams->pwszValueName == NULL )
  187. {
  188. lResult = ERROR_OUTOFMEMORY;
  189. break;
  190. }
  191. bHasValue = TRUE;
  192. StringCopy( pParams->pwszValueName, argv[ dw ], dwLength );
  193. }
  194. else
  195. {
  196. bResult = FALSE;
  197. lResult = IDS_ERROR_INVALID_SYNTAX_WITHOPT;
  198. break;
  199. }
  200. }
  201. else if( StringCompareEx( argv[ dw ], L"/ve", TRUE, 0 ) == 0 )
  202. {
  203. if( bHasValue == TRUE )
  204. {
  205. bResult = FALSE;
  206. lResult = IDS_ERROR_INVALID_SYNTAX_WITHOPT;
  207. break;
  208. }
  209. pParams->pwszValueName =
  210. (LPWSTR) AllocateMemory( 2 * sizeof( WCHAR ) );
  211. if ( pParams->pwszValueName == NULL )
  212. {
  213. lResult = ERROR_OUTOFMEMORY;
  214. break;
  215. }
  216. bHasValue = TRUE;
  217. }
  218. else if( StringCompareEx( argv[ dw ], L"/va", TRUE, 0 ) == 0 )
  219. {
  220. if( bHasValue == TRUE )
  221. {
  222. bResult = FALSE;
  223. lResult = IDS_ERROR_INVALID_SYNTAX_WITHOPT;
  224. break;
  225. }
  226. bHasValue = TRUE;
  227. pParams->bAllValues = TRUE;
  228. }
  229. else if( StringCompareEx( argv[ dw ], L"/f", TRUE, 0 ) == 0 )
  230. {
  231. if ( pParams->bForce == TRUE )
  232. {
  233. bResult = FALSE;
  234. lResult = IDS_ERROR_INVALID_SYNTAX_WITHOPT;
  235. break;
  236. }
  237. pParams->bForce = TRUE;
  238. }
  239. else
  240. {
  241. bResult = FALSE;
  242. lResult = IDS_ERROR_INVALID_SYNTAX_WITHOPT;
  243. break;
  244. }
  245. }
  246. if( lResult != ERROR_SUCCESS )
  247. {
  248. if( bResult == FALSE )
  249. {
  250. SetLastError( (DWORD) MK_E_SYNTAX );
  251. SetReason2( 1,
  252. ERROR_INVALID_SYNTAX_WITHOPT, g_wszOptions[ REG_DELETE ] );
  253. }
  254. else
  255. {
  256. SaveErrorMessage( lResult );
  257. }
  258. }
  259. return (lResult == ERROR_SUCCESS);
  260. }
  261. //-----------------------------------------------------------------------//
  262. //
  263. // RecursiveDeleteKey() - Recursive registry key delete
  264. //
  265. //-----------------------------------------------------------------------//
  266. LONG
  267. RecursiveDeleteKey( HKEY hKey,
  268. LPCWSTR pwszName,
  269. DWORD dwDepth,
  270. PTREG_PARAMS pParams )
  271. {
  272. // local variables
  273. LONG lResult = 0;
  274. DWORD dw = 0;
  275. DWORD dwIndex = 0;
  276. DWORD dwCount = 0;
  277. HKEY hSubKey = NULL;
  278. LONG lLastResult = 0;
  279. DWORD dwNumOfSubkey = 0;
  280. DWORD dwLenOfKeyName = 0;
  281. LPWSTR pwszNameBuf = NULL;
  282. TARRAY arrValues = NULL;
  283. LPCWSTR pwszTemp = NULL;
  284. if( hKey == NULL || pwszName == NULL || pParams == NULL )
  285. {
  286. lResult = ERROR_INVALID_PARAMETER;
  287. goto exitarea;
  288. }
  289. //
  290. // Open the SubKey
  291. //
  292. lResult = RegOpenKeyEx( hKey, pwszName, 0, KEY_ALL_ACCESS, &hSubKey );
  293. if( lResult != ERROR_SUCCESS )
  294. {
  295. goto exitarea;
  296. }
  297. // query key info
  298. lResult = RegQueryInfoKey( hSubKey,
  299. NULL, NULL, NULL,
  300. &dwNumOfSubkey, &dwLenOfKeyName,
  301. NULL, NULL, NULL, NULL, NULL, NULL );
  302. if( lResult != ERROR_SUCCESS )
  303. {
  304. SafeCloseKey( &hSubKey );
  305. goto exitarea;
  306. }
  307. else if ( dwNumOfSubkey == 0 )
  308. {
  309. SafeCloseKey( &hSubKey );
  310. lResult = RegDeleteKey( hKey, pwszName );
  311. goto exitarea;
  312. }
  313. //
  314. // SPECIAL CASE:
  315. // -------------
  316. // For HKLM\SYSTEM\CONTROLSET002 it is found to be API returning value 0 for dwMaxLength
  317. // though there are subkeys underneath this -- to handle this, we are doing a workaround
  318. // by assuming the max registry key length
  319. //
  320. if ( dwLenOfKeyName == 0 )
  321. {
  322. dwLenOfKeyName = 256;
  323. }
  324. else if ( dwLenOfKeyName < 256 )
  325. {
  326. // always assume 100% more length that what is returned by the API
  327. dwLenOfKeyName *= 2;
  328. }
  329. // create the dynamic array
  330. arrValues = CreateDynamicArray();
  331. if ( arrValues == NULL )
  332. {
  333. SafeCloseKey( &hSubKey );
  334. lResult = ERROR_OUTOFMEMORY;
  335. goto exitarea;
  336. }
  337. // create buffer
  338. //
  339. // bump the length to take into account the terminator.
  340. dwLenOfKeyName++;
  341. pwszNameBuf = (LPWSTR) AllocateMemory( (dwLenOfKeyName + 2) * sizeof( WCHAR ) );
  342. if ( pwszNameBuf == NULL )
  343. {
  344. SafeCloseKey( &hSubKey );
  345. DestroyDynamicArray( &arrValues );
  346. lResult = ERROR_OUTOFMEMORY;
  347. goto exitarea;
  348. }
  349. // Now Enumerate all of the keys
  350. dwIndex = 0;
  351. lResult = ERROR_SUCCESS;
  352. lLastResult = ERROR_SUCCESS;
  353. while( dwIndex < dwNumOfSubkey )
  354. {
  355. dw = dwLenOfKeyName;
  356. SecureZeroMemory( pwszNameBuf, dw * sizeof( WCHAR ) );
  357. lResult = RegEnumKeyEx( hSubKey,
  358. dwIndex, pwszNameBuf,
  359. &dw, NULL, NULL, NULL, NULL);
  360. // check the result
  361. if ( lResult == ERROR_SUCCESS )
  362. {
  363. if ( DynArrayAppendString( arrValues, pwszNameBuf, 0 ) == -1 )
  364. {
  365. lResult = lLastResult = ERROR_OUTOFMEMORY;
  366. break;
  367. }
  368. }
  369. else if ( lLastResult == ERROR_SUCCESS )
  370. {
  371. lLastResult = lResult;
  372. }
  373. dwIndex++;
  374. }
  375. // free memory
  376. FreeMemory( &pwszNameBuf );
  377. dwCount = DynArrayGetCount( arrValues );
  378. if ( lResult != ERROR_OUTOFMEMORY && dwCount != 0 )
  379. {
  380. //
  381. // start recurise delete
  382. //
  383. dw = 0;
  384. lResult = ERROR_SUCCESS;
  385. lLastResult = ERROR_SUCCESS;
  386. for( dwIndex = 0; dwIndex < dwCount; dwIndex++ )
  387. {
  388. // get the item
  389. pwszTemp = DynArrayItemAsString( arrValues, dwIndex );
  390. // try to delete the sub key
  391. lResult = RecursiveDeleteKey( hSubKey, pwszTemp, dwDepth + 1, pParams );
  392. if ( lResult != ERROR_SUCCESS )
  393. {
  394. if ( lLastResult == ERROR_SUCCESS )
  395. {
  396. lLastResult = lResult;
  397. }
  398. }
  399. else
  400. {
  401. dw++;
  402. }
  403. }
  404. if ( dw == 0 )
  405. {
  406. lResult = lLastResult;
  407. }
  408. else if ( dwCount != dwNumOfSubkey || dw != dwCount )
  409. {
  410. lResult = STG_E_INCOMPLETE;
  411. }
  412. else
  413. {
  414. lResult = ERROR_SUCCESS;
  415. }
  416. }
  417. else
  418. {
  419. lResult = lLastResult;
  420. }
  421. // release the memory allocate for dynamic array
  422. DestroyDynamicArray( &arrValues );
  423. // close this subkey and delete it
  424. SafeCloseKey( &hSubKey );
  425. // delete the key if the result is success
  426. if ( lResult == ERROR_SUCCESS )
  427. {
  428. lResult = RegDeleteKey( hKey, pwszName );
  429. }
  430. exitarea:
  431. // check the result and display the error message
  432. // NOTE: error message display should be done only at the exit point
  433. if ( dwDepth == 0 )
  434. {
  435. if ( lResult != ERROR_SUCCESS )
  436. {
  437. if ( lResult == STG_E_INCOMPLETE )
  438. {
  439. SetReason( ERROR_DELETEPARTIAL );
  440. }
  441. else
  442. {
  443. SaveErrorMessage( lResult );
  444. }
  445. // display the error
  446. ShowLastErrorEx( stderr, SLE_TYPE_ERROR | SLE_INTERNAL );
  447. }
  448. else
  449. {
  450. SaveErrorMessage( ERROR_SUCCESS );
  451. ShowLastErrorEx( stdout, SLE_INTERNAL );
  452. }
  453. }
  454. // return
  455. return lResult;
  456. }
  457. LONG
  458. DeleteValues( PTREG_PARAMS pParams )
  459. {
  460. // local variables
  461. DWORD dw = 0;
  462. DWORD dwCount = 0;
  463. DWORD dwIndex = 0;
  464. LONG lResult = 0;
  465. HKEY hSubKey = NULL;
  466. LONG lLastResult = 0;
  467. LPCWSTR pwszTemp = NULL;
  468. LPCWSTR pwszList = NULL;
  469. LPCWSTR pwszFormat = NULL;
  470. DWORD dwNumOfValues = 0;
  471. DWORD dwLengthOfValueName = 0;
  472. LPWSTR pwszNameBuf = NULL;
  473. TARRAY arrValues = NULL;
  474. // check the input
  475. if ( pParams == NULL )
  476. {
  477. SaveErrorMessage( ERROR_INVALID_PARAMETER );
  478. ShowLastErrorEx( stderr, SLE_INTERNAL );
  479. return ERROR_INVALID_PARAMETER;
  480. }
  481. pwszList = GetResString2( IDS_CONFIRM_CHOICE_LIST, 1 );
  482. if( pParams->bAllValues == TRUE )
  483. {
  484. pwszTemp = pParams->pwszFullKey;
  485. pwszFormat = GetResString2( IDS_DELETEALL_CONFIRM, 0 );
  486. }
  487. else if ( pParams->pwszValueName != NULL )
  488. {
  489. if ( StringLength( pParams->pwszValueName, 0 ) == 0 )
  490. {
  491. pwszTemp = GetResString2( IDS_NONAME, 0 );
  492. }
  493. else
  494. {
  495. pwszTemp = pParams->pwszValueName;
  496. }
  497. // ...
  498. pwszFormat = GetResString2( IDS_DELETE_CONFIRM, 2 );
  499. }
  500. else
  501. {
  502. SaveErrorMessage( ERROR_INVALID_PARAMETER );
  503. ShowLastErrorEx( stderr, SLE_INTERNAL );
  504. return ERROR_INVALID_PARAMETER;
  505. }
  506. do
  507. {
  508. lResult = Prompt( pwszFormat,
  509. pwszTemp, pwszList, pParams->bForce );
  510. } while ( lResult > 2 );
  511. if ( lResult == 2 )
  512. {
  513. SaveErrorMessage( ERROR_CANCELLED );
  514. ShowLastErrorEx( stdout, SLE_INTERNAL );
  515. return ERROR_CANCELLED;
  516. }
  517. // Open the registry key
  518. lResult = RegOpenKeyEx( pParams->hRootKey,
  519. pParams->pwszSubKey, 0, KEY_ALL_ACCESS, &hSubKey );
  520. if( lResult != ERROR_SUCCESS )
  521. {
  522. SaveErrorMessage( lResult );
  523. ShowLastErrorEx( stderr, SLE_TYPE_ERROR | SLE_INTERNAL );
  524. return lResult;
  525. }
  526. // create the dynamic array
  527. arrValues = CreateDynamicArray();
  528. if ( arrValues == NULL )
  529. {
  530. SafeCloseKey( &hSubKey );
  531. SaveErrorMessage( ERROR_OUTOFMEMORY );
  532. ShowLastErrorEx( stderr, SLE_TYPE_ERROR | SLE_INTERNAL );
  533. return ERROR_OUTOFMEMORY;
  534. }
  535. if( pParams->pwszValueName != NULL ) // delete a single value
  536. {
  537. lResult = RegDeleteValue( hSubKey, pParams->pwszValueName );
  538. }
  539. else if( pParams->bAllValues == TRUE ) // delete all values
  540. {
  541. // query source key info
  542. lResult = RegQueryInfoKey( hSubKey,
  543. NULL, NULL, NULL, NULL, NULL, NULL,
  544. &dwNumOfValues, &dwLengthOfValueName, NULL, NULL, NULL);
  545. if( lResult == ERROR_SUCCESS && dwNumOfValues != 0 )
  546. {
  547. // create buffer
  548. // bump the length to take into account the terminator.
  549. dwLengthOfValueName++;
  550. pwszNameBuf =
  551. (LPWSTR) AllocateMemory( (dwLengthOfValueName + 2) * sizeof(WCHAR) );
  552. if ( pwszNameBuf == NULL )
  553. {
  554. lResult = ERROR_OUTOFMEMORY;
  555. }
  556. else
  557. {
  558. // Now Enumerate all values
  559. dwIndex = 0;
  560. lResult = ERROR_SUCCESS;
  561. lLastResult = ERROR_SUCCESS;
  562. while( dwIndex < dwNumOfValues )
  563. {
  564. dw = dwLengthOfValueName;
  565. SecureZeroMemory( pwszNameBuf, dw * sizeof( WCHAR ) );
  566. lResult = RegEnumValue( hSubKey, dwIndex,
  567. pwszNameBuf, &dw, NULL, NULL, NULL, NULL);
  568. if ( lResult == ERROR_SUCCESS )
  569. {
  570. if ( DynArrayAppendString( arrValues,
  571. pwszNameBuf, 0 ) == -1 )
  572. {
  573. lResult = lLastResult = ERROR_OUTOFMEMORY;
  574. break;
  575. }
  576. }
  577. else if ( lLastResult == ERROR_SUCCESS )
  578. {
  579. lLastResult = lResult;
  580. }
  581. dwIndex++;
  582. }
  583. // free memory
  584. FreeMemory( &pwszNameBuf );
  585. dwCount = DynArrayGetCount( arrValues );
  586. if ( lResult != ERROR_OUTOFMEMORY && dwCount != 0 )
  587. {
  588. dw = 0;
  589. dwIndex = 0;
  590. lResult = ERROR_SUCCESS;
  591. lLastResult = ERROR_SUCCESS;
  592. for( dwIndex = 0; dwIndex < dwCount; dwIndex++ )
  593. {
  594. // delete the value
  595. pwszTemp = DynArrayItemAsString( arrValues, dwIndex );
  596. lResult = RegDeleteValue( hSubKey, pwszTemp );
  597. if ( lResult != ERROR_SUCCESS )
  598. {
  599. if ( lLastResult == ERROR_SUCCESS )
  600. {
  601. lLastResult = lResult;
  602. }
  603. }
  604. else
  605. {
  606. dw++;
  607. }
  608. }
  609. if ( dw == 0 )
  610. {
  611. lResult = lLastResult;
  612. }
  613. else if ( dwCount != dwNumOfValues || dw != dwCount )
  614. {
  615. lResult = STG_E_INCOMPLETE;
  616. }
  617. else
  618. {
  619. lResult = ERROR_SUCCESS;
  620. }
  621. }
  622. else
  623. {
  624. lResult = lLastResult;
  625. }
  626. }
  627. }
  628. }
  629. // close the sub key
  630. SafeCloseKey( &hSubKey );
  631. // check the result
  632. if ( lResult != ERROR_SUCCESS )
  633. {
  634. if ( lResult == STG_E_INCOMPLETE )
  635. {
  636. SetReason( ERROR_DELETEPARTIAL );
  637. }
  638. else
  639. {
  640. SaveErrorMessage( lResult );
  641. }
  642. // display the error
  643. ShowLastErrorEx( stderr, SLE_TYPE_ERROR | SLE_INTERNAL );
  644. }
  645. else
  646. {
  647. SaveErrorMessage( ERROR_SUCCESS );
  648. ShowLastErrorEx( stdout, SLE_INTERNAL );
  649. }
  650. return lResult;
  651. }