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.

624 lines
18 KiB

  1. //-----------------------------------------------------------------------//
  2. //
  3. // File: copy.cpp
  4. // Created: April 1997
  5. // By: Martin Holladay (a-martih)
  6. // Purpose: Registry Copy 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 CopyValue( HKEY hKey, LPCWSTR pwszValueName,
  18. HKEY hDestKey, LPCWSTR pwszDestValueName,
  19. BOOL* pbForce, LPCWSTR pwszSubKey );
  20. LONG CopyEnumerateKey( HKEY hKey, LPCWSTR pwszSubKey,
  21. HKEY hDestKey, LPCWSTR pwszDestSubKey,
  22. BOOL* pbForce, BOOL bRecurseSubKeys, DWORD dwDepth );
  23. BOOL ParseCopyCmdLine( DWORD argc,
  24. LPCWSTR argv[],
  25. PTREG_PARAMS pParams,
  26. PTREG_PARAMS pDestParams, BOOL* pbUsage );
  27. //
  28. // implementation
  29. //
  30. //-----------------------------------------------------------------------//
  31. //
  32. // CopyRegistry()
  33. //
  34. //-----------------------------------------------------------------------//
  35. LONG
  36. CopyRegistry( DWORD argc, LPCWSTR argv[] )
  37. {
  38. // local variables
  39. LONG lResult = 0;
  40. HKEY hKey = NULL;
  41. HKEY hDestKey = NULL;
  42. BOOL bUsage = FALSE;
  43. BOOL bResult = FALSE;
  44. DWORD dwDisposition = 0;
  45. TREG_PARAMS params;
  46. TREG_PARAMS paramsDest;
  47. if ( argc == 0 || argv == NULL )
  48. {
  49. SetLastError( ERROR_INVALID_PARAMETER );
  50. ShowLastError( stderr );
  51. return 1;
  52. }
  53. // initialize the global data structure
  54. InitGlobalData( REG_COPY, &params );
  55. InitGlobalData( REG_COPY, &paramsDest );
  56. //
  57. // Parse the cmd-line
  58. //
  59. bResult = ParseCopyCmdLine( argc, argv, &params, &paramsDest, &bUsage );
  60. if( bResult == FALSE )
  61. {
  62. ShowLastErrorEx( stderr, SLE_INTERNAL );
  63. FreeGlobalData( &params );
  64. FreeGlobalData( &paramsDest );
  65. return 1;
  66. }
  67. // check whether we need to display the usage
  68. if ( bUsage == TRUE )
  69. {
  70. Usage( REG_COPY );
  71. FreeGlobalData( &params );
  72. FreeGlobalData( &paramsDest );
  73. return 0;
  74. }
  75. //
  76. // Connect to the Remote Machine(s) - if applicable
  77. //
  78. bResult = RegConnectMachine( &params );
  79. if( bResult == FALSE )
  80. {
  81. SaveErrorMessage( -1 );
  82. ShowLastErrorEx( stderr, SLE_TYPE_ERROR | SLE_INTERNAL );
  83. FreeGlobalData( &params );
  84. FreeGlobalData( &paramsDest );
  85. return 1;
  86. }
  87. bResult = RegConnectMachine( &paramsDest );
  88. if( bResult == FALSE )
  89. {
  90. SaveErrorMessage( -1 );
  91. ShowLastErrorEx( stderr, SLE_TYPE_ERROR | SLE_INTERNAL );
  92. FreeGlobalData( &params );
  93. FreeGlobalData( &paramsDest );
  94. return 1;
  95. }
  96. // check whether source and destination are different or not
  97. if ( params.hRootKey == paramsDest.hRootKey &&
  98. StringCompare( params.pwszFullKey, paramsDest.pwszFullKey, TRUE, 0 ) == 0 )
  99. {
  100. SetLastError( (DWORD) MK_E_SYNTAX );
  101. SetReason( ERROR_COPYTOSELF_COPY );
  102. ShowLastErrorEx( stderr, SLE_INTERNAL );
  103. FreeGlobalData( &params );
  104. FreeGlobalData( &paramsDest );
  105. return 1;
  106. }
  107. //
  108. // Now implement the body of the Copy Operation
  109. //
  110. lResult = RegOpenKeyEx(
  111. params.hRootKey, params.pwszSubKey, 0, KEY_READ, &hKey );
  112. if( lResult != ERROR_SUCCESS )
  113. {
  114. SaveErrorMessage( lResult );
  115. ShowLastErrorEx( stderr, SLE_TYPE_ERROR | SLE_INTERNAL );
  116. FreeGlobalData( &params );
  117. FreeGlobalData( &paramsDest );
  118. return 1;
  119. }
  120. //
  121. // Different Key or Different Root or Different Machine
  122. // So Create/Open it
  123. //
  124. lResult = RegCreateKeyEx( paramsDest.hRootKey,paramsDest.pwszSubKey,
  125. 0, NULL, REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, &hDestKey, &dwDisposition);
  126. if( lResult != ERROR_SUCCESS )
  127. {
  128. SafeCloseKey( &hKey );
  129. SaveErrorMessage( lResult );
  130. ShowLastErrorEx( stderr, SLE_TYPE_ERROR | SLE_INTERNAL );
  131. FreeGlobalData( &params );
  132. FreeGlobalData( &paramsDest );
  133. return 1;
  134. }
  135. //
  136. // Recursively copy all subkeys and values
  137. //
  138. lResult = CopyEnumerateKey( hKey, params.pwszSubKey,
  139. hDestKey, params.pwszSubKey, &params.bForce, params.bRecurseSubKeys, 0 );
  140. //
  141. // lets clean up
  142. //
  143. SafeCloseKey( &hDestKey );
  144. SafeCloseKey( &hKey );
  145. FreeGlobalData( &params );
  146. FreeGlobalData( &paramsDest );
  147. // return
  148. return ((lResult == ERROR_SUCCESS) ? 0 : 1);
  149. }
  150. BOOL
  151. ParseCopyCmdLine( DWORD argc, LPCWSTR argv[],
  152. PTREG_PARAMS pParams, PTREG_PARAMS pDestParams, BOOL* pbUsage )
  153. {
  154. // local variables
  155. DWORD dw = 0;
  156. BOOL bResult = FALSE;
  157. // check the input
  158. if ( argc == 0 || argv == NULL ||
  159. pParams == NULL || pDestParams == NULL || pbUsage == NULL )
  160. {
  161. SaveErrorMessage( ERROR_INVALID_PARAMETER );
  162. return FALSE;
  163. }
  164. // check whether this function is being called for
  165. // valid operation or not
  166. if ( pParams->lOperation < 0 || pParams->lOperation >= REG_OPTIONS_COUNT )
  167. {
  168. SaveErrorMessage( ERROR_INVALID_PARAMETER );
  169. return FALSE;
  170. }
  171. //
  172. // Do we have a *valid* number of cmd-line params
  173. //
  174. if ( argc >= 3 && InString( argv[ 2 ], L"-?|/?|-h|/h", TRUE ) == TRUE )
  175. {
  176. if ( argc == 3 )
  177. {
  178. *pbUsage = TRUE;
  179. return TRUE;
  180. }
  181. else
  182. {
  183. SetLastError( (DWORD) MK_E_SYNTAX );
  184. SetReason2( 1, ERROR_INVALID_SYNTAX_WITHOPT, g_wszOptions[ REG_COPY ] );
  185. return FALSE;
  186. }
  187. }
  188. else if( argc < 4 || argc > 6 )
  189. {
  190. SetLastError( (DWORD) MK_E_SYNTAX );
  191. SetReason2( 1, ERROR_INVALID_SYNTAX_WITHOPT, g_wszOptions[ REG_COPY ] );
  192. return FALSE;
  193. }
  194. else if ( StringCompareEx( argv[ 1 ], L"COPY", TRUE, 0 ) != 0 )
  195. {
  196. SaveErrorMessage( ERROR_INVALID_PARAMETER );
  197. return FALSE;
  198. }
  199. //
  200. // Source Machine Name and Registry key
  201. //
  202. bResult = BreakDownKeyString( argv[ 2 ], pParams );
  203. if( bResult == FALSE )
  204. {
  205. return FALSE;
  206. }
  207. //
  208. // Destination Machine Name and Registry key
  209. //
  210. bResult = BreakDownKeyString( argv[ 3 ], pDestParams );
  211. if( bResult == FALSE )
  212. {
  213. return FALSE;
  214. }
  215. // parsing
  216. for( dw = 4; dw < argc; dw++ )
  217. {
  218. if( StringCompareEx( argv[ dw ], L"/f", TRUE, 0 ) == 0 )
  219. {
  220. if ( pParams->bForce == TRUE )
  221. {
  222. SetLastError( (DWORD) MK_E_SYNTAX );
  223. SetReason2( 1, ERROR_INVALID_SYNTAX_WITHOPT, g_wszOptions[ REG_COPY ] );
  224. return FALSE;
  225. }
  226. pParams->bForce = TRUE;
  227. }
  228. else if( StringCompare( argv[ dw ], L"/s", TRUE, 0 ) == 0 )
  229. {
  230. if ( pParams->bRecurseSubKeys == TRUE )
  231. {
  232. SetLastError( (DWORD) MK_E_SYNTAX );
  233. SetReason2( 1, ERROR_INVALID_SYNTAX_WITHOPT, g_wszOptions[ REG_COPY ] );
  234. return FALSE;
  235. }
  236. pParams->bRecurseSubKeys = TRUE;
  237. }
  238. else
  239. {
  240. SetLastError( (DWORD) MK_E_SYNTAX );
  241. SetReason2( 1, ERROR_INVALID_SYNTAX_WITHOPT, g_wszOptions[ REG_COPY ] );
  242. return FALSE;
  243. }
  244. }
  245. return TRUE;
  246. }
  247. //-----------------------------------------------------------------------//
  248. //
  249. // CopyValue()
  250. //
  251. //-----------------------------------------------------------------------//
  252. LONG CopyValue( HKEY hKey, LPCWSTR pwszValueName,
  253. HKEY hDestKey, LPCWSTR pwszDestValueName,
  254. BOOL* pbForce, LPCWSTR pwszSubKey )
  255. {
  256. // local variables
  257. LONG lResult = 0;
  258. DWORD dwType = 0;
  259. DWORD dwSize = 0;
  260. BYTE* pBuffer = NULL;
  261. LPCWSTR pwszList = NULL;
  262. LPCWSTR pwszTemp = NULL;
  263. LPCWSTR pwszFormat = NULL;
  264. // check the input
  265. if ( hKey == NULL || pwszValueName == NULL ||
  266. hDestKey == NULL || pwszDestValueName == NULL ||
  267. pbForce == NULL || pwszSubKey == NULL )
  268. {
  269. SaveErrorMessage( ERROR_INVALID_PARAMETER );
  270. return ERROR_INVALID_PARAMETER;
  271. }
  272. //
  273. // First find out how much memory to allocate.
  274. //
  275. lResult = RegQueryValueEx( hKey, pwszValueName, NULL, &dwType, NULL, &dwSize );
  276. if( lResult != ERROR_SUCCESS )
  277. {
  278. SaveErrorMessage( lResult );
  279. return lResult;
  280. }
  281. // allocate memory for getting the value from the registry
  282. pBuffer = (BYTE*) AllocateMemory( (dwSize + 1) * sizeof(BYTE) );
  283. if ( pBuffer == NULL )
  284. {
  285. SaveErrorMessage( ERROR_OUTOFMEMORY );
  286. return ERROR_OUTOFMEMORY;
  287. }
  288. //
  289. // Now get the data
  290. //
  291. lResult = RegQueryValueEx( hKey, pwszValueName, NULL, &dwType, pBuffer, &dwSize );
  292. if( lResult != ERROR_SUCCESS )
  293. {
  294. FreeMemory( &pBuffer );
  295. SaveErrorMessage( lResult );
  296. return lResult;
  297. }
  298. //
  299. // Copy it to the destination
  300. //
  301. if ( *pbForce == FALSE )
  302. {
  303. //
  304. // See if it already exists
  305. //
  306. lResult = RegQueryValueEx( hDestKey, pwszDestValueName, 0, NULL, NULL, NULL );
  307. if( lResult == ERROR_SUCCESS )
  308. {
  309. //
  310. // prepare the prompt message
  311. //
  312. pwszFormat = GetResString2( IDS_OVERWRITE, 0 );
  313. pwszList = GetResString2( IDS_CONFIRM_CHOICE_LIST, 1 );
  314. if ( StringLength( pwszDestValueName, 0 ) == 0 )
  315. {
  316. pwszTemp = GetResString2( IDS_NONAME, 2 );
  317. }
  318. else
  319. {
  320. pwszTemp = pwszDestValueName;
  321. }
  322. // we will make use of the reason buffer for formatting
  323. // the value name along with the sub key
  324. SetReason2( 2, L"%s\\%s", pwszSubKey, pwszTemp );
  325. pwszTemp = GetReason();
  326. do
  327. {
  328. lResult = Prompt( pwszFormat, pwszTemp, pwszList, *pbForce );
  329. } while ( lResult > 3 );
  330. if ( lResult == 3 )
  331. {
  332. *pbForce = TRUE;
  333. }
  334. else if ( lResult != 1 )
  335. {
  336. FreeMemory( &pBuffer );
  337. SaveErrorMessage( ERROR_CANCELLED );
  338. return ERROR_CANCELLED;
  339. }
  340. }
  341. }
  342. //
  343. // Write the Value
  344. //
  345. lResult = RegSetValueEx( hDestKey, pwszDestValueName, 0, dwType, pBuffer, dwSize );
  346. // release memory
  347. FreeMemory( &pBuffer );
  348. return lResult;
  349. }
  350. //-----------------------------------------------------------------------//
  351. //
  352. // EnumerateKey() - Recursive
  353. //
  354. //-----------------------------------------------------------------------//
  355. LONG CopyEnumerateKey( HKEY hKey, LPCWSTR pwszSubKey,
  356. HKEY hDestKey, LPCWSTR pwszDestSubKey,
  357. BOOL* pbForce, BOOL bRecurseSubKeys, DWORD dwDepth )
  358. {
  359. // local variables
  360. DWORD dw = 0;
  361. LONG lResult = 0;
  362. DWORD dwValues = 0;
  363. DWORD dwSubKeys = 0;
  364. DWORD dwLengthOfKeyName = 0;
  365. DWORD dwLengthOfValueName = 0;
  366. DWORD dwSize = 0;
  367. DWORD dwDisposition = 0;
  368. HKEY hSubKey = NULL;
  369. HKEY hDestSubKey = NULL;
  370. LPWSTR pwszNameBuf = NULL;
  371. LPWSTR pwszNewSubKey = NULL;
  372. LPWSTR pwszNewDestSubKey = NULL;
  373. // check the input
  374. if ( hKey == NULL || pwszSubKey == NULL ||
  375. hDestKey == NULL || pwszDestSubKey == NULL || pbForce == NULL )
  376. {
  377. lResult = ERROR_INVALID_PARAMETER;
  378. goto exitarea;
  379. }
  380. // query source key info
  381. lResult = RegQueryInfoKey(
  382. hKey, NULL, NULL, NULL,
  383. &dwSubKeys, &dwLengthOfKeyName, NULL,
  384. &dwValues, &dwLengthOfValueName, NULL, NULL, NULL );
  385. if( lResult != ERROR_SUCCESS )
  386. {
  387. goto exitarea;
  388. }
  389. //
  390. // SPECIAL CASE:
  391. // -------------
  392. // For HKLM\SYSTEM\CONTROLSET002 it is found to be API returning value 0 for dwMaxLength
  393. // though there are subkeys underneath this -- to handle this, we are doing a workaround
  394. // by assuming the max registry key length
  395. //
  396. if ( dwSubKeys != 0 && dwLengthOfKeyName == 0 )
  397. {
  398. dwLengthOfKeyName = 256;
  399. }
  400. else if ( dwLengthOfKeyName < 256 )
  401. {
  402. // always assume 100% more length that what is returned by the API
  403. dwLengthOfKeyName *= 2;
  404. }
  405. //
  406. // First enumerate all of the values
  407. //
  408. // bump the length to take into account the terminator.
  409. dwLengthOfValueName++;
  410. pwszNameBuf = (LPWSTR) AllocateMemory( dwLengthOfValueName * sizeof(WCHAR) );
  411. if( pwszNameBuf == NULL)
  412. {
  413. lResult = ERROR_OUTOFMEMORY;
  414. }
  415. else
  416. {
  417. lResult = ERROR_SUCCESS;
  418. for( dw = 0; dw < dwValues && lResult == ERROR_SUCCESS; dw++ )
  419. {
  420. dwSize = dwLengthOfValueName;
  421. lResult = RegEnumValue( hKey, dw, pwszNameBuf, &dwSize, NULL, NULL, NULL, NULL);
  422. if( lResult == ERROR_SUCCESS )
  423. {
  424. lResult = CopyValue( hKey, pwszNameBuf,
  425. hDestKey, pwszNameBuf, pbForce, pwszSubKey );
  426. if ( lResult == ERROR_CANCELLED )
  427. {
  428. // user chosed to just to skip this
  429. lResult = ERROR_SUCCESS;
  430. }
  431. }
  432. }
  433. // release memory
  434. FreeMemory( &pwszNameBuf );
  435. if( bRecurseSubKeys == FALSE || lResult != ERROR_SUCCESS )
  436. {
  437. goto exitarea;
  438. }
  439. //
  440. // Now Enumerate all of the keys
  441. //
  442. dwLengthOfKeyName++;
  443. pwszNameBuf = (LPWSTR) AllocateMemory( dwLengthOfKeyName * sizeof(WCHAR) );
  444. if( pwszNameBuf == NULL )
  445. {
  446. lResult = ERROR_NOT_ENOUGH_MEMORY;
  447. }
  448. else
  449. {
  450. hSubKey = NULL;
  451. hDestSubKey = NULL;
  452. for( dw = 0; dw < dwSubKeys; dw++ )
  453. {
  454. dwSize = dwLengthOfKeyName;
  455. lResult = RegEnumKeyEx( hKey, dw,
  456. pwszNameBuf, &dwSize, NULL, NULL, NULL, NULL );
  457. if( lResult != ERROR_SUCCESS )
  458. {
  459. break;
  460. }
  461. //
  462. // open up the subkey, create the destination key
  463. // and enumerate it
  464. //
  465. lResult = RegOpenKeyEx( hKey, pwszNameBuf, 0, KEY_READ, &hSubKey );
  466. if( lResult != ERROR_SUCCESS )
  467. {
  468. break;
  469. }
  470. lResult = RegCreateKeyEx( hDestKey,
  471. pwszNameBuf, 0, NULL, REG_OPTION_NON_VOLATILE,
  472. KEY_ALL_ACCESS, NULL, &hDestSubKey, &dwDisposition );
  473. if( lResult != ERROR_SUCCESS )
  474. {
  475. break;
  476. }
  477. //
  478. // Build up the needed string and go to town enumerating again
  479. //
  480. //
  481. // new source sub key
  482. dwSize = StringLength( pwszSubKey, 0 ) + StringLength( pwszNameBuf, 0 ) + 3;
  483. pwszNewSubKey = (LPWSTR) AllocateMemory( dwSize * sizeof( WCHAR ) );
  484. if( pwszNewSubKey == NULL )
  485. {
  486. lResult = ERROR_OUTOFMEMORY;
  487. break;
  488. }
  489. if( StringLength( pwszSubKey, 0 ) > 0 )
  490. {
  491. StringCopy( pwszNewSubKey, pwszSubKey, dwSize );
  492. StringConcat( pwszNewSubKey, L"\\", dwSize );
  493. }
  494. // ...
  495. StringConcat( pwszNewSubKey, pwszNameBuf, dwSize );
  496. //
  497. // new destination sub key
  498. dwSize = StringLength( pwszDestSubKey, 0 ) + StringLength( pwszNameBuf, 0 ) + 3;
  499. pwszNewDestSubKey = (LPWSTR) AllocateMemory( dwSize * sizeof( WCHAR ) );
  500. if( pwszDestSubKey == NULL )
  501. {
  502. lResult = ERROR_OUTOFMEMORY;
  503. break;
  504. }
  505. if( StringLength( pwszDestSubKey, 0 ) > 0 )
  506. {
  507. StringCopy( pwszNewDestSubKey, pwszDestSubKey, dwSize);
  508. StringConcat( pwszNewDestSubKey, L"\\", dwSize );
  509. }
  510. // ...
  511. StringConcat( pwszNewDestSubKey, pwszNameBuf, dwSize );
  512. // recursive copy
  513. lResult = CopyEnumerateKey( hSubKey, pwszNewSubKey,
  514. hDestSubKey, pwszNewDestSubKey, pbForce, bRecurseSubKeys, dwDepth + 1 );
  515. SafeCloseKey( &hSubKey );
  516. SafeCloseKey( &hDestSubKey );
  517. FreeMemory( &pwszNewSubKey );
  518. FreeMemory( &pwszNewDestSubKey );
  519. }
  520. // release all the key handles and memory allocated
  521. if ( hSubKey != NULL )
  522. {
  523. SafeCloseKey( &hSubKey );
  524. }
  525. if ( hDestSubKey != NULL )
  526. {
  527. SafeCloseKey( &hDestSubKey );
  528. }
  529. // ...
  530. FreeMemory( &pwszNameBuf );
  531. FreeMemory( &pwszNewSubKey );
  532. FreeMemory( &pwszNewDestSubKey );
  533. }
  534. }
  535. exitarea:
  536. // check the result and display the error message
  537. // NOTE: error message display should be done only at the exit point
  538. if ( dwDepth == 0 )
  539. {
  540. if ( lResult != ERROR_SUCCESS )
  541. {
  542. // display the error
  543. SaveErrorMessage( lResult );
  544. ShowLastErrorEx( stderr, SLE_TYPE_ERROR | SLE_INTERNAL );
  545. }
  546. else
  547. {
  548. SaveErrorMessage( ERROR_SUCCESS );
  549. ShowLastErrorEx( stdout, SLE_INTERNAL );
  550. }
  551. }
  552. // return
  553. return lResult;
  554. }