Source code of Windows XP (NT5)
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.

2130 lines
66 KiB

  1. //--------------------------------------------------------------
  2. //
  3. // File: loaduser
  4. //
  5. // Contents: Load a user hive.
  6. //
  7. //---------------------------------------------------------------
  8. #include "loadhead.cxx"
  9. #pragma hdrstop
  10. #include <common.hxx>
  11. #include <objerror.h>
  12. #include <userenv.h>
  13. #include <userenvp.h>
  14. #include <loadstate.hxx>
  15. #include <bothchar.cxx>
  16. class CRegFileList
  17. {
  18. public:
  19. inline CRegFileList(TCHAR *ptsRoot,
  20. TCHAR *ptsKey,
  21. TCHAR *ptsVal,
  22. TCHAR *ptsData,
  23. DWORD dwValueType);
  24. inline ~CRegFileList();
  25. inline void SetNext(CRegFileList *prfl);
  26. inline CRegFileList * GetNext(void) const;
  27. inline void GetData(const TCHAR **pptsRoot,
  28. const TCHAR **pptsKey,
  29. const TCHAR **pptsVal,
  30. const TCHAR **pptsData,
  31. DWORD *pdwValType) const;
  32. private:
  33. TCHAR _tsRootName[MAX_PATH + 1];
  34. TCHAR _tsKeyName[MAX_PATH + 1];
  35. TCHAR _tsValueName[MAX_PATH + 1];
  36. TCHAR _tsData[MAX_PATH + 1];
  37. DWORD _dwValueType;
  38. CRegFileList *_prflNext;
  39. };
  40. inline CRegFileList::CRegFileList(TCHAR *ptsRoot,
  41. TCHAR *ptsKey,
  42. TCHAR *ptsVal,
  43. TCHAR *ptsData,
  44. DWORD dwValueType)
  45. {
  46. if (ptsRoot != NULL && _tcslen(ptsRoot) <= MAX_PATH)
  47. _tcscpy(_tsRootName, ptsRoot);
  48. else
  49. _tsRootName[0] = 0;
  50. if (ptsKey != NULL && _tcslen(ptsKey) <= MAX_PATH)
  51. _tcscpy(_tsKeyName, ptsKey);
  52. else
  53. _tsKeyName[0] = 0;
  54. if (ptsVal != NULL && _tcslen(ptsVal) <= MAX_PATH)
  55. _tcscpy(_tsValueName, ptsVal);
  56. else
  57. _tsValueName[0] = 0;
  58. if (ptsData != NULL && _tcslen(ptsData) <= MAX_PATH)
  59. _tcscpy(_tsData, ptsData);
  60. else
  61. _tsData[0] = 0;
  62. _dwValueType = dwValueType;
  63. _prflNext = NULL;
  64. }
  65. inline CRegFileList::~CRegFileList(void)
  66. {
  67. }
  68. inline void CRegFileList::SetNext(CRegFileList *prfl)
  69. {
  70. _prflNext = prfl;
  71. }
  72. inline CRegFileList * CRegFileList::GetNext(void) const
  73. {
  74. return _prflNext;
  75. }
  76. inline void CRegFileList::GetData(const TCHAR **pptsRoot,
  77. const TCHAR **pptsKey,
  78. const TCHAR **pptsVal,
  79. const TCHAR **pptsData,
  80. DWORD *pdwValType) const
  81. {
  82. *pptsRoot = _tsRootName;
  83. *pptsKey = _tsKeyName;
  84. *pptsVal = _tsValueName;
  85. *pptsData = _tsData;
  86. *pdwValType = _dwValueType;
  87. }
  88. CRegFileList *g_prflStart;
  89. //---------------------------------------------------------------
  90. // Constants.
  91. const DWORD SID_GUESS = 80;
  92. const TCHAR HIVEFILE[] = TEXT("\\ntuser.dat");
  93. const TCHAR HIVEPATH[] = TEXT("%temp%\\ntuser.dat");
  94. const DWORD NUM_HASH_BUCKETS = 121;
  95. const TCHAR FORCE_SECTION[] = TEXT("Force Win9x Settings");
  96. const TCHAR RENAME_SECTION[] = TEXT("Map Win9x to WinNT");
  97. const TCHAR FUNCTION_SECTION[] = TEXT("Win9x Data Conversion");
  98. const TCHAR SUPPRESS_SECTION[] = TEXT("Suppress Win9x Settings");
  99. const TCHAR FILE_SECTION[] = TEXT("Map paths");
  100. const TCHAR DELETE_SECTION[] = TEXT("Suppress WinNT Settings");
  101. //---------------------------------------------------------------
  102. // Macros
  103. // If this symbol is defined, loaduser will apply the state to the
  104. // specified user and cannot be run as that user.
  105. // If this symbols is not defined, loaduser will apply state to the
  106. // current user.
  107. #define SPECIFIC_USER 1
  108. //---------------------------------------------------------------
  109. // Globals.
  110. HASH_HEAD HashTable[NUM_HASH_BUCKETS];
  111. FUNCTION_FA_MAP FunctionTable[] = {
  112. { TEXT("ConvertRecentDocsMRU"), ConvertRecentDocsMRU },
  113. { TEXT("ConvertAppearanceScheme"), ConvertAppearanceScheme },
  114. { TEXT("ConvertLogFont"), ConvertLogFont },
  115. { TEXT("ConvertToDword"), ConvertToDword },
  116. { TEXT("ConvertToString"), ConvertToString },
  117. { TEXT("AntiAlias"), AntiAlias },
  118. { TEXT("FixActiveDesktop"), FixActiveDesktop },
  119. { NULL, NULL }
  120. };
  121. //---------------------------------------------------------------
  122. DWORD ShiftXOR( DWORD x, TCHAR c )
  123. {
  124. if (x & 0x80000000)
  125. return (x << 1) ^ c | 1;
  126. else
  127. return (x << 1) ^ c;
  128. }
  129. //---------------------------------------------------------------
  130. // Create a case insensitive hash of the input.
  131. DWORD Hash( TCHAR *ptsRoot, TCHAR *ptsKey, TCHAR *ptsValue )
  132. {
  133. DWORD x = 0;
  134. DWORD i;
  135. // Hash the ptsRoot.
  136. if (ptsRoot != NULL)
  137. for (i = 0; ptsRoot[i] != 0; i++)
  138. x = ShiftXOR( x, _totupper(ptsRoot[i]) );
  139. // Hash the key.
  140. if (ptsKey != NULL)
  141. for (i = 0; ptsKey[i] != 0; i++)
  142. x = ShiftXOR( x, _totupper(ptsKey[i]) );
  143. // Hash the value.
  144. if (ptsValue != NULL)
  145. for (i = 0; ptsValue[i] != 0; i++)
  146. x = ShiftXOR( x, _totupper(ptsValue[i]) );
  147. return x;
  148. }
  149. //---------------------------------------------------------------
  150. DWORD null_tcsicmp( TCHAR *x, TCHAR *y )
  151. {
  152. if (x == NULL)
  153. if (y == NULL)
  154. return 0;
  155. else
  156. return -1;
  157. else
  158. if (y == NULL)
  159. return 1;
  160. else
  161. return _tcsicmp( x, y );
  162. }
  163. //---------------------------------------------------------------
  164. // Do a case insensitive comparision of the input.
  165. BOOL Match( HASH_NODE *phnCurrent,
  166. DWORD dwHash,
  167. TCHAR *ptsRoot,
  168. TCHAR *ptsKey,
  169. TCHAR *ptsValue)
  170. {
  171. return phnCurrent->dwHash == dwHash &&
  172. null_tcsicmp( phnCurrent->ptsRoot, ptsRoot ) == 0 &&
  173. null_tcsicmp( phnCurrent->ptsKey, ptsKey ) == 0 &&
  174. null_tcsicmp( phnCurrent->ptsValue, ptsValue ) == 0;
  175. }
  176. //---------------------------------------------------------------
  177. HASH_NODE *Lookup( TCHAR *ptsRoot, TCHAR *ptsKey, TCHAR *ptsValue )
  178. {
  179. DWORD dwHash = Hash( ptsRoot, ptsKey, ptsValue );
  180. DWORD dwBucket = dwHash % NUM_HASH_BUCKETS;
  181. HASH_NODE *phnCurrent = (HASH_NODE *) HashTable[dwBucket].phhNext;
  182. // Look at all the nodes in the bucket.
  183. while (phnCurrent != (HASH_NODE *) &HashTable[dwBucket])
  184. if (Match( phnCurrent, dwHash, ptsRoot, ptsKey, ptsValue ))
  185. return phnCurrent;
  186. else
  187. phnCurrent = phnCurrent->phnNext;
  188. return NULL;
  189. }
  190. //---------------------------------------------------------------
  191. void Insert( HASH_NODE *phnNode )
  192. {
  193. DWORD dwHash = Hash( phnNode->ptsRoot,
  194. phnNode->ptsKey,
  195. phnNode->ptsValue );
  196. DWORD dwBucket = dwHash % NUM_HASH_BUCKETS;
  197. HASH_NODE *phnCurrent;
  198. // Look for an existing node.
  199. phnCurrent = Lookup( phnNode->ptsRoot,
  200. phnNode->ptsKey,
  201. phnNode->ptsValue );
  202. // If found, copy in the state of the new node and free it.
  203. if (phnCurrent != NULL)
  204. {
  205. // Assume that the new value or key have not been set.
  206. if (phnNode->dwAction & rename_value_fa)
  207. {
  208. if (phnCurrent->ptsNewValue != NULL)
  209. {
  210. //Skip
  211. if (_tcsicmp(phnCurrent->ptsNewValue, phnNode->ptsNewValue))
  212. Win32Printf(LogFile,
  213. "Warning: Skipping rename rule for %s\\%s [%s]"
  214. " to %s due to previous rename rule "
  215. "to %s.\r\n",
  216. phnNode->ptsRoot,
  217. phnNode->ptsKey,
  218. phnNode->ptsValue,
  219. phnNode->ptsNewValue,
  220. phnCurrent->ptsNewValue);
  221. goto cleanup;
  222. }
  223. else
  224. phnCurrent->ptsNewValue = phnNode->ptsNewValue;
  225. }
  226. if (phnNode->dwAction & (rename_leaf_fa | rename_path_fa))
  227. {
  228. if (phnCurrent->ptsNewKey != NULL)
  229. {
  230. //Skip
  231. if (_tcsicmp(phnCurrent->ptsNewKey, phnNode->ptsNewKey))
  232. Win32Printf(LogFile,
  233. "Warning: Skipping rename rule for %s\\%s "
  234. "to %s due to previous rename rule to %s.\r\n",
  235. phnNode->ptsRoot,
  236. phnNode->ptsKey,
  237. phnNode->ptsNewKey,
  238. phnCurrent->ptsNewKey);
  239. goto cleanup;
  240. }
  241. else
  242. phnCurrent->ptsNewKey = phnNode->ptsNewKey;
  243. }
  244. if (phnNode->dwAction & function_fa)
  245. {
  246. if (phnCurrent->ptsFunction != NULL)
  247. {
  248. //Skip
  249. if (_tcsicmp(phnCurrent->ptsNewKey, phnNode->ptsNewKey))
  250. Win32Printf(LogFile,
  251. "Warning: Skipping function rule for %s\\%s "
  252. "to %s due to previous function call"
  253. " to %s.\r\n",
  254. phnNode->ptsRoot,
  255. phnNode->ptsKey,
  256. phnNode->ptsNewKey,
  257. phnCurrent->ptsFunction);
  258. goto cleanup;
  259. }
  260. else
  261. phnCurrent->ptsFunction = phnNode->ptsNewKey;
  262. }
  263. phnCurrent->dwAction |= phnNode->dwAction;
  264. if (VerboseReg)
  265. LogReadRule( phnNode );
  266. cleanup:
  267. free( phnNode->ptsRoot );
  268. free( phnNode->ptsKey );
  269. free( phnNode->ptsValue );
  270. free( phnNode );
  271. }
  272. // Insert the node.
  273. else
  274. {
  275. phnCurrent = (HASH_NODE *) &HashTable[dwBucket];
  276. phnNode->dwHash = dwHash;
  277. phnNode->phnNext = phnCurrent->phnNext;
  278. phnNode->phnPrev = phnCurrent;
  279. phnCurrent->phnNext->phnPrev = phnNode;
  280. phnCurrent->phnNext = phnNode;
  281. if (phnNode->dwAction & function_fa)
  282. {
  283. phnNode->ptsFunction = phnNode->ptsNewKey;
  284. phnNode->ptsNewKey = NULL;
  285. }
  286. if (VerboseReg)
  287. LogReadRule( phnNode );
  288. }
  289. }
  290. //+---------------------------------------------------------------------------
  291. //
  292. // Function: DeleteInf
  293. //
  294. // Synopsis: deletes values copied from .DEFAULT user hive
  295. //
  296. // Arguments:
  297. //
  298. // Returns: Appropriate status code
  299. //
  300. // History: 20-Sep-99 HenryLee Created
  301. //
  302. //----------------------------------------------------------------------------
  303. DWORD DeleteInf ()
  304. {
  305. DWORD dwResult = ERROR_SUCCESS;
  306. HKEY hRootKey = NULL;
  307. HKEY hKey = NULL;
  308. for (DWORD dwBucket = 0; dwBucket < NUM_HASH_BUCKETS; dwBucket++)
  309. {
  310. HASH_NODE *phnCurrent = (HASH_NODE *) HashTable[dwBucket].phhNext;
  311. // Look at all the nodes in the bucket.
  312. while (phnCurrent != (HASH_NODE *) &HashTable[dwBucket])
  313. {
  314. if (phnCurrent->dwAction & delete_fa)
  315. {
  316. if (phnCurrent->ptsRoot != NULL)
  317. {
  318. if (_tcsicmp( TEXT("HKLM"), phnCurrent->ptsRoot ) == 0)
  319. hRootKey = HKEY_LOCAL_MACHINE;
  320. else
  321. hRootKey = CurrentUser;
  322. dwResult = RegOpenKeyEx( hRootKey,
  323. phnCurrent->ptsKey,
  324. NULL,
  325. KEY_ALL_ACCESS,
  326. &hKey );
  327. if (dwResult == ERROR_SUCCESS)
  328. {
  329. dwResult = RegDeleteValue (hKey, phnCurrent->ptsValue);
  330. RegCloseKey (hKey);
  331. if (dwResult != ERROR_SUCCESS)
  332. {
  333. if (Verbose)
  334. Win32Printf(LogFile,
  335. "Warning. Cannot delete %s\\%s\n",
  336. phnCurrent->ptsKey,
  337. phnCurrent->ptsValue);
  338. dwResult = ERROR_SUCCESS;
  339. }
  340. }
  341. else dwResult = ERROR_SUCCESS; // keep on going
  342. }
  343. }
  344. phnCurrent = phnCurrent->phnNext;
  345. }
  346. }
  347. return dwResult;
  348. }
  349. DWORD ApplyRule(HASH_NODE *phnRule,
  350. TCHAR *ptsKeyMatch,
  351. TCHAR **pptsRoot,
  352. TCHAR **pptsKey,
  353. TCHAR **pptsValue,
  354. DWORD *pdwType,
  355. BYTE **ppbData,
  356. DWORD *pdwDataLen,
  357. BOOL *pfForce)
  358. {
  359. DWORD dwResult = ERROR_SUCCESS;
  360. if (phnRule->dwAction & force_fa)
  361. {
  362. if (DebugOutput || VerboseReg)
  363. Win32Printf(LogFile,
  364. "Applying force rule to %s\\%s [%s]\r\n",
  365. *pptsRoot,
  366. *pptsKey,
  367. (*pptsValue) ? *pptsValue : TEXT("NULL"));
  368. *pfForce = TRUE;
  369. }
  370. if (phnRule->dwAction & function_fa)
  371. {
  372. FUNCTION_FA_MAP *pMap = FunctionTable;
  373. while (pMap != NULL && pMap->ptsName != NULL)
  374. {
  375. if (lstrcmp (pMap->ptsName, phnRule->ptsFunction) == 0 &&
  376. pMap->pfunction)
  377. {
  378. dwResult = (pMap->pfunction) (pdwType,
  379. ppbData,
  380. pdwDataLen);
  381. LOG_ASSERT (dwResult);
  382. }
  383. pMap++;
  384. }
  385. if (DebugOutput || VerboseReg)
  386. Win32Printf(LogFile,
  387. "Applying function_fa rule to %s\\%s [%s] "
  388. "(function %s)\r\n",
  389. *pptsRoot,
  390. *pptsKey,
  391. (*pptsValue) ? *pptsValue : TEXT("NULL"),
  392. phnRule->ptsFunction);
  393. }
  394. // Replace the path matched with the new path and leave the
  395. // portion of the path that was not matched.
  396. if (phnRule->dwAction & rename_path_fa)
  397. {
  398. DWORD dwLen = _tcslen( phnRule->ptsNewKey ) + _tcslen(ptsKeyMatch);
  399. TCHAR * ptsBuffer = (TCHAR *) malloc( (dwLen + 1) *sizeof(TCHAR) );
  400. LOG_ASSERT_EXPR( ptsBuffer != NULL,
  401. IDS_NOT_ENOUGH_MEMORY,
  402. dwResult,
  403. ERROR_NOT_ENOUGH_MEMORY );
  404. _tcscpy( ptsBuffer, phnRule->ptsNewKey );
  405. _tcscat( ptsBuffer, ptsKeyMatch );
  406. if (DebugOutput || VerboseReg)
  407. Win32Printf(LogFile,
  408. "Applying rename_path rule to %s\\%s [%s], "
  409. "result %s\r\n",
  410. *pptsRoot,
  411. *pptsKey,
  412. (*pptsValue) ? *pptsValue : TEXT("NULL"),
  413. ptsBuffer);
  414. free( *pptsKey );
  415. *pptsKey = ptsBuffer;
  416. }
  417. // Replace the entire key with the new key.
  418. if (phnRule->dwAction & rename_leaf_fa)
  419. {
  420. DWORD dwLen = _tcslen( phnRule->ptsNewKey ) + 1;
  421. TCHAR *ptsBuffer = (TCHAR *) malloc( dwLen*sizeof(TCHAR) );
  422. LOG_ASSERT_EXPR( ptsBuffer != NULL,
  423. IDS_NOT_ENOUGH_MEMORY,
  424. dwResult,
  425. ERROR_NOT_ENOUGH_MEMORY );
  426. _tcscpy( ptsBuffer, phnRule->ptsNewKey );
  427. if (DebugOutput || VerboseReg)
  428. Win32Printf(LogFile,
  429. "Applying rename_leaf rule to %s\\%s [%s], "
  430. "result %s\r\n",
  431. *pptsRoot,
  432. *pptsKey,
  433. (*pptsValue) ? *pptsValue : TEXT("NULL"),
  434. ptsBuffer);
  435. free( *pptsKey );
  436. *pptsKey = ptsBuffer;
  437. }
  438. // Replace the entire value with the new value.
  439. if (phnRule->dwAction & rename_value_fa)
  440. {
  441. DWORD dwLen = _tcslen( phnRule->ptsNewValue ) + 1;
  442. TCHAR *ptsBuffer = (TCHAR *) malloc( dwLen*sizeof(TCHAR) );
  443. LOG_ASSERT_EXPR( ptsBuffer != NULL,
  444. IDS_NOT_ENOUGH_MEMORY,
  445. dwResult,
  446. ERROR_NOT_ENOUGH_MEMORY );
  447. _tcscpy( ptsBuffer, phnRule->ptsNewValue );
  448. if (DebugOutput || VerboseReg)
  449. Win32Printf(LogFile,
  450. "Applying rename_value rule to %s\\%s [%s], "
  451. "result %s\r\n",
  452. *pptsRoot,
  453. *pptsKey,
  454. (*pptsValue) ? *pptsValue : TEXT("NULL"),
  455. ptsBuffer);
  456. free( *pptsValue );
  457. *pptsValue = ptsBuffer;
  458. }
  459. // Ask what the new path should be.
  460. if ((phnRule->dwAction & file_fa) && *pptsValue != NULL)
  461. {
  462. //Nothing to do here, we'll do this in Filter
  463. }
  464. if (!(SourceVersion & 0x80000000))
  465. *pfForce = TRUE;
  466. cleanup:
  467. return dwResult;
  468. }
  469. /***************************************************************************
  470. Filter
  471. Look for a rule for each component of the path. If found, apply it.
  472. ***************************************************************************/
  473. DWORD Filter( TCHAR **pptsRoot,
  474. TCHAR **pptsKey,
  475. TCHAR **pptsValue,
  476. DWORD *pdwType,
  477. BYTE **ppbData,
  478. DWORD *pdwDataLen,
  479. BOOL *pfForce )
  480. {
  481. DWORD dwKeyLen = _tcslen( *pptsKey ) + 1;
  482. TCHAR *ptsKeyPath = (TCHAR *) _alloca( dwKeyLen*sizeof(TCHAR) );
  483. TCHAR *ptsFrom;
  484. TCHAR *ptsTo;
  485. TCHAR *ptsEnd;
  486. HASH_NODE *phnRule = NULL;
  487. DWORD dwResult = ERROR_SUCCESS;
  488. BOOL fSuppress = FALSE;
  489. BOOL fFileRuleFound = FALSE;
  490. //Make copies of all the initial keys
  491. TCHAR *ptsRootBuf = (TCHAR *) _alloca((_tcslen(*pptsRoot) + 1) *
  492. sizeof(TCHAR));
  493. TCHAR *ptsKeyBuf = (TCHAR *) _alloca( dwKeyLen * sizeof(TCHAR) );
  494. TCHAR *ptsValBuf = NULL;
  495. if (*pptsValue)
  496. {
  497. ptsValBuf = (TCHAR *) _alloca((_tcslen(*pptsValue) + 1) *
  498. sizeof(TCHAR));
  499. _tcscpy(ptsValBuf, *pptsValue);
  500. }
  501. _tcscpy(ptsRootBuf, *pptsRoot);
  502. _tcscpy(ptsKeyBuf, *pptsKey);
  503. ptsFrom = ptsKeyBuf;
  504. phnRule = NULL;
  505. // Loop over each part of the key path.
  506. ptsTo = ptsKeyPath;
  507. while (ptsFrom[0] != 0)
  508. {
  509. // Copy the next segment from pptsKey to ptsKeyPath.
  510. ptsEnd = _tcschr( &ptsFrom[1], L'\\' );
  511. if (ptsEnd == NULL)
  512. ptsEnd = ptsKeyBuf+dwKeyLen-1;
  513. _tcsncpy( ptsTo, ptsFrom, ptsEnd-ptsFrom );
  514. ptsTo[ptsEnd-ptsFrom] = 0;
  515. ptsTo += ptsEnd-ptsFrom;
  516. ptsFrom = ptsEnd;
  517. if ( *pptsValue != NULL )
  518. {
  519. // First look up each piece with value attached
  520. phnRule = Lookup( ptsRootBuf, ptsKeyPath, ptsValBuf );
  521. // Apply only if recursive or at the end of the key
  522. if (phnRule != NULL &&
  523. ((phnRule->dwAction & recursive_fa) || (ptsFrom[0]==0)))
  524. {
  525. dwResult = ApplyRule(phnRule,
  526. ptsFrom,
  527. pptsRoot,
  528. pptsKey,
  529. pptsValue,
  530. pdwType,
  531. ppbData,
  532. pdwDataLen,
  533. pfForce);
  534. if (dwResult)
  535. goto cleanup;
  536. if (phnRule->dwAction & suppress_fa)
  537. {
  538. fSuppress = TRUE;
  539. }
  540. if (phnRule->dwAction & file_fa &&
  541. (REG_SZ == *pdwType || REG_EXPAND_SZ == *pdwType || REG_MULTI_SZ == *pdwType))
  542. {
  543. fSuppress = TRUE;
  544. fFileRuleFound = TRUE;
  545. }
  546. }
  547. }
  548. // Check with no value attached
  549. phnRule = Lookup( ptsRootBuf, ptsKeyPath, NULL );
  550. // Apply only if recursive or at the end of the key
  551. if (phnRule != NULL &&
  552. ((phnRule->dwAction & recursive_fa) || (ptsFrom[0]==0)))
  553. {
  554. dwResult = ApplyRule(phnRule,
  555. ptsFrom,
  556. pptsRoot,
  557. pptsKey,
  558. pptsValue,
  559. pdwType,
  560. ppbData,
  561. pdwDataLen,
  562. pfForce);
  563. if (dwResult)
  564. goto cleanup;
  565. if (phnRule->dwAction & suppress_fa)
  566. {
  567. fSuppress = TRUE;
  568. }
  569. if (phnRule->dwAction & file_fa &&
  570. (REG_SZ == *pdwType || REG_EXPAND_SZ == *pdwType || REG_MULTI_SZ == *pdwType))
  571. {
  572. fSuppress = TRUE;
  573. fFileRuleFound = TRUE;
  574. }
  575. }
  576. }
  577. if (fFileRuleFound)
  578. {
  579. //Add to the list of files to be fixed up later.
  580. CRegFileList *prfl = new CRegFileList(*pptsRoot,
  581. *pptsKey,
  582. *pptsValue,
  583. (TCHAR *)*ppbData,
  584. *pdwType);
  585. if (prfl == NULL)
  586. {
  587. Win32PrintfResource(LogFile,
  588. IDS_NOT_ENOUGH_MEMORY);
  589. dwResult = ERROR_NOT_ENOUGH_MEMORY;
  590. goto cleanup;
  591. }
  592. if (DebugOutput || VerboseReg)
  593. Win32Printf(LogFile,
  594. "Applying file_fa rule to %s\\%s [%s], "
  595. "data = %s\r\n",
  596. *pptsRoot,
  597. *pptsKey,
  598. (*pptsValue) ? *pptsValue : TEXT("NULL"),
  599. (TCHAR *)*ppbData);
  600. prfl->SetNext(g_prflStart);
  601. g_prflStart = prfl;
  602. }
  603. if (fSuppress)
  604. {
  605. free(*pptsKey);
  606. free(*pptsValue);
  607. *pptsRoot = NULL;
  608. *pptsKey = NULL;
  609. *pptsValue = NULL;
  610. }
  611. cleanup:
  612. if (Verbose && dwResult != ERROR_SUCCESS)
  613. printf( "Filter failed with 0x%x\r\n", dwResult );
  614. return dwResult;
  615. }
  616. //---------------------------------------------------------------
  617. DWORD LoadSectionRules( const TCHAR *ptsSection, DWORD dwFlags )
  618. {
  619. INFCONTEXT ic;
  620. DWORD dwResult = ERROR_SUCCESS;
  621. BOOL fSuccess;
  622. HASH_NODE *phnRule;
  623. // Open the section.
  624. fSuccess = SetupFindFirstLine( InputInf, ptsSection, NULL, &ic );
  625. // Read all the rules in the section.
  626. while (fSuccess)
  627. {
  628. // Parse the rule.
  629. dwResult = ParseRule( &ic, &phnRule );
  630. FAIL_ON_ERROR( dwResult );
  631. if (dwFlags == function_fa) // remove the rename flags
  632. {
  633. phnRule->dwAction = function_fa;
  634. }
  635. else
  636. {
  637. phnRule->dwAction |= dwFlags;
  638. }
  639. // Save the rule in the hash table.
  640. Insert( phnRule );
  641. phnRule = NULL;
  642. // Advance to the next line.
  643. fSuccess = SetupFindNextLine( &ic, &ic );
  644. }
  645. cleanup:
  646. return dwResult;
  647. }
  648. /***************************************************************************
  649. InitializeHash
  650. Read the filtering rules from the specified INF file. Read the rules
  651. from the sections for forcing, suppressing, renaming, and functions.
  652. ***************************************************************************/
  653. DWORD InitializeHash()
  654. {
  655. DWORD i;
  656. DWORD dwResult = ERROR_SUCCESS;
  657. INFCONTEXT ic;
  658. BOOL fSuccess;
  659. TCHAR *ptsBuffer;
  660. CStringList *pslAdd = NULL;
  661. CStringList *pslRen = NULL;
  662. CStringList *pslFile = NULL;
  663. CStringList *pslDel = NULL;
  664. CStringList *pslCurr;
  665. // Initialize the hash table.
  666. for (i = 0; i < NUM_HASH_BUCKETS; i++)
  667. {
  668. HashTable[i].phhNext = &HashTable[i];
  669. HashTable[i].phhPrev = &HashTable[i];
  670. }
  671. // Load rules from the filter sections.
  672. // Since we try to force by default, it is okay to load in the Win9x force rules
  673. // and apply them even if the source is NT. If they exist, we'll force overwriting,
  674. // but if not, no harm done.
  675. dwResult = LoadSectionRules( FORCE_SECTION, force_fa );
  676. LOG_ASSERT( dwResult );
  677. // We shouldn't write these keys regardless of the source OS
  678. dwResult = LoadSectionRules( SUPPRESS_SECTION, suppress_fa );
  679. LOG_ASSERT( dwResult );
  680. // This section describes keys that should be removed from the default hive before
  681. // migrating the settings. It is not specific to any source OS.
  682. dwResult = LoadSectionRules( DELETE_SECTION, delete_fa );
  683. LOG_ASSERT( dwResult );
  684. if (SourceVersion & 0x80000000)
  685. {
  686. dwResult = LoadSectionRules( RENAME_SECTION, 0 );
  687. LOG_ASSERT( dwResult );
  688. dwResult = LoadSectionRules( FILE_SECTION, file_fa );
  689. LOG_ASSERT( dwResult );
  690. dwResult = LoadSectionRules( FUNCTION_SECTION, function_fa );
  691. LOG_ASSERT( dwResult );
  692. }
  693. // Load from copied rules sections.
  694. dwResult = LoadSectionRules( EXTENSION_ADDREG_SECTION, force_fa );
  695. LOG_ASSERT( dwResult );
  696. dwResult = LoadSectionRules( EXTENSION_RENREG_SECTION, 0 );
  697. LOG_ASSERT( dwResult );
  698. dwResult = LoadSectionRules( EXTENSION_REGFILE_SECTION, file_fa );
  699. LOG_ASSERT( dwResult );
  700. dwResult = LoadSectionRules( EXTENSION_DELREG_SECTION, suppress_fa );
  701. LOG_ASSERT( dwResult );
  702. // Open the section list.
  703. fSuccess = SetupFindFirstLine( InputInf, EXTENSION_SECTION, NULL, &ic );
  704. if (!fSuccess)
  705. return ERROR_SUCCESS;
  706. // Allocate the section name lists.
  707. pslAdd = new CStringList( 0 );
  708. pslRen = new CStringList( 0 );
  709. pslFile = new CStringList( 0 );
  710. pslDel = new CStringList( 0 );
  711. if (pslAdd == NULL || pslRen == NULL || pslFile == NULL || pslDel == NULL)
  712. {
  713. dwResult = ERROR_NOT_ENOUGH_MEMORY;
  714. LOG_ASSERT( dwResult );
  715. }
  716. // Make lists of the names of sections of each type.
  717. do
  718. {
  719. // Parse the line.
  720. dwResult = ParseSectionList( &ic, &ptsBuffer, &pslCurr );
  721. FAIL_ON_ERROR( dwResult );
  722. // Save the value if its one of the ones we are looking for.
  723. if (ptsBuffer != NULL)
  724. {
  725. if (_tcsicmp( ptsBuffer, ADDREG_LABEL ) == 0)
  726. pslAdd->Add( pslCurr );
  727. else if (_tcsicmp( ptsBuffer, RENREG_LABEL ) == 0)
  728. pslRen->Add( pslCurr );
  729. else if (_tcsicmp( ptsBuffer, REGFILE_LABEL ) == 0)
  730. pslFile->Add( pslCurr );
  731. else if (_tcsicmp( ptsBuffer, DELREG_LABEL ) == 0)
  732. pslDel->Add( pslCurr );
  733. else if (!_tcsicmp( ptsBuffer, COPYFILES_LABEL ) &&
  734. !_tcsicmp( ptsBuffer, DELFILES_LABEL ))
  735. LOG_ASSERT_EXPR( FALSE, IDS_INF_ERROR, dwResult, SPAPI_E_GENERAL_SYNTAX );
  736. free( ptsBuffer );
  737. }
  738. // Advance to the next line.
  739. fSuccess = SetupFindNextLine( &ic, &ic );
  740. } while( fSuccess);
  741. // Process all the addreg sections.
  742. for (pslCurr = pslAdd->Next();
  743. pslCurr != pslAdd;
  744. pslCurr = pslCurr->Next())
  745. {
  746. dwResult = LoadSectionRules( pslCurr->String(), force_fa );
  747. LOG_ASSERT( dwResult );
  748. }
  749. // Process all the renreg sections.
  750. for (pslCurr = pslRen->Next();
  751. pslCurr != pslRen;
  752. pslCurr = pslCurr->Next())
  753. {
  754. dwResult = LoadSectionRules( pslCurr->String(), 0 );
  755. LOG_ASSERT( dwResult );
  756. }
  757. // Process all the regfile sections.
  758. for (pslCurr = pslFile->Next();
  759. pslCurr != pslFile;
  760. pslCurr = pslCurr->Next())
  761. {
  762. dwResult = LoadSectionRules( pslCurr->String(), file_fa );
  763. LOG_ASSERT( dwResult );
  764. }
  765. // Process all the delreg sections.
  766. for (pslCurr = pslDel->Next();
  767. pslCurr != pslDel;
  768. pslCurr = pslCurr->Next())
  769. {
  770. dwResult = LoadSectionRules( pslCurr->String(), suppress_fa );
  771. LOG_ASSERT( dwResult );
  772. }
  773. cleanup:
  774. if (pslAdd != NULL)
  775. delete pslAdd;
  776. if (pslRen != NULL)
  777. delete pslRen;
  778. if (pslFile != NULL)
  779. delete pslFile;
  780. if (pslDel != NULL)
  781. delete pslDel;
  782. return dwResult;
  783. }
  784. /***************************************************************************
  785. ParseAssignment
  786. Parse the line into a variable name and a value name. Allow optional
  787. whitespace and quotes around the variable or value names. This function
  788. allocates buffers for the variable and value names which the caller must
  789. free. Return a NULL pointer for the variable name if the line cannot be
  790. parsed.
  791. Note: The caller is required to free the following variables even if
  792. this function fails.
  793. pptsVar
  794. pptsValue
  795. ***************************************************************************/
  796. DWORD ParseAssignment( INFCONTEXT *pic,
  797. DWORD dwLen,
  798. TCHAR **pptsVar,
  799. TCHAR **pptsValue )
  800. {
  801. BOOL fSuccess;
  802. DWORD dwResult = ERROR_SUCCESS;
  803. DWORD dwVarLen;
  804. DWORD dwValueLen;
  805. // Initialize out params
  806. *pptsVar = *pptsValue = NULL;
  807. // Query the two lengths we need
  808. fSuccess = SetupGetStringField( pic, 0, NULL, 0, &dwVarLen );
  809. LOG_ASSERT_GLE( fSuccess, dwResult );
  810. fSuccess = SetupGetStringField( pic, 1, NULL, 0, &dwValueLen );
  811. LOG_ASSERT_GLE( fSuccess, dwResult );
  812. // Allocate memory for both
  813. *pptsVar = (TCHAR *) malloc( dwVarLen * sizeof(TCHAR) );
  814. *pptsValue = (TCHAR *) malloc( dwValueLen * sizeof(TCHAR) );
  815. if( *pptsVar == NULL || *pptsValue == NULL )
  816. {
  817. free(*pptsVar);
  818. free(*pptsValue);
  819. *pptsVar = *pptsValue = NULL;
  820. Win32PrintfResource( LogFile, IDS_NOT_ENOUGH_MEMORY );
  821. return ERROR_NOT_ENOUGH_MEMORY;
  822. }
  823. // Read the variable name
  824. fSuccess = SetupGetStringField( pic, 0, *pptsVar, dwVarLen, NULL );
  825. LOG_ASSERT_EXPR(fSuccess, IDS_GETSTRINGFIELD_ERROR,
  826. dwResult, SPAPI_E_SECTION_NAME_TOO_LONG);
  827. // Read the value name
  828. fSuccess = SetupGetStringField( pic, 1, *pptsValue, dwValueLen, NULL );
  829. LOG_ASSERT_EXPR(fSuccess, IDS_GETSTRINGFIELD_ERROR,
  830. dwResult, SPAPI_E_SECTION_NAME_TOO_LONG);
  831. cleanup:
  832. return dwResult;
  833. }
  834. /***************************************************************************
  835. ReadUser
  836. Read the user section of migration.inf and return the values for the
  837. name of the settings section, the user name, and the domain name.
  838. Note: The caller is required to free the following variables even if
  839. this function fails.
  840. pptsSettingsSection
  841. pptsDomainName
  842. pptsUsername
  843. ***************************************************************************/
  844. DWORD ReadUser( TCHAR **pptsSettingsSection,
  845. TCHAR **pptsDomainName,
  846. TCHAR **pptsUsername )
  847. {
  848. DWORD dwResult;
  849. BOOL fSuccess;
  850. INFCONTEXT ic;
  851. DWORD dwReqLen;
  852. TCHAR *var;
  853. TCHAR *value;
  854. TCHAR *user_section = NULL;
  855. // Find the section for users.
  856. fSuccess = SetupFindFirstLine( InputInf, USERS_SECTION, NULL, &ic );
  857. if (fSuccess == FALSE)
  858. {
  859. dwResult = GetLastError();
  860. if (Verbose)
  861. Win32Printf(LogFile,
  862. "ERROR: Could not find %s in Input INF: %d\r\n",
  863. USERS_SECTION, dwResult);
  864. LOG_ASSERT( dwResult );
  865. }
  866. // Find the name of the section containing user info.
  867. do
  868. {
  869. // Find the length of the line.
  870. dwReqLen = 0;
  871. fSuccess = SetupGetLineText( &ic, NULL, NULL, NULL, NULL, 0, &dwReqLen );
  872. if (dwReqLen == 0)
  873. LOG_ASSERT_GLE( fSuccess, dwResult );
  874. // Parse the line.
  875. dwResult = ParseAssignment( &ic, dwReqLen, &var, &value );
  876. FAIL_ON_ERROR( dwResult );
  877. // Save the value if its one of the ones we are looking for.
  878. if (var != NULL)
  879. {
  880. if (_tcsicmp( var, TEXT("section") ) == 0)
  881. user_section = value;
  882. else
  883. free( value );
  884. free( var );
  885. }
  886. // Advance to the next line.
  887. fSuccess = SetupFindNextLine( &ic, &ic );
  888. } while( fSuccess);
  889. // Find the section for the user.
  890. fSuccess = SetupFindFirstLine( InputInf, user_section, NULL, &ic );
  891. LOG_ASSERT_GLE( fSuccess, dwResult );
  892. // Read each line in the section.
  893. do
  894. {
  895. // Find the length of the line.
  896. dwReqLen = 0;
  897. fSuccess = SetupGetLineText( &ic, NULL, NULL, NULL, NULL, 0, &dwReqLen );
  898. if (dwReqLen == 0)
  899. LOG_ASSERT_GLE( fSuccess, dwResult );
  900. // Parse the line.
  901. dwResult = ParseAssignment( &ic, dwReqLen, &var, &value );
  902. FAIL_ON_ERROR( dwResult );
  903. // Save the value if its one of the ones we are looking for.
  904. if (var != NULL)
  905. {
  906. if (_tcsicmp( var, TEXT("user") ) == 0)
  907. *pptsUsername = value;
  908. else if (_tcsicmp( var, TEXT("domain") ) == 0)
  909. *pptsDomainName = value;
  910. else if (_tcsicmp( var, TEXT("section") ) == 0)
  911. *pptsSettingsSection = value;
  912. else
  913. free( value );
  914. free( var );
  915. }
  916. // Advance to the next line.
  917. fSuccess = SetupFindNextLine( &ic, &ic );
  918. } while( fSuccess);
  919. // It is an error if the username, domainname, or settings section
  920. // isn't specified.
  921. if (*pptsUsername == NULL || *pptsDomainName == NULL || *pptsSettingsSection == NULL)
  922. {
  923. Win32PrintfResource( LogFile, IDS_INF_ERROR );
  924. dwResult = SPAPI_E_GENERAL_SYNTAX;
  925. }
  926. cleanup:
  927. if (user_section != NULL)
  928. free( user_section );
  929. return dwResult;
  930. }
  931. /***************************************************************************
  932. ParseRegistry
  933. Parse a line describing a registry key or value.
  934. reg-root-string, [subkey], [value-name], [flags], [value]
  935. reg-root-string One of HKCR, HKCU, HKLM, HKU, HKR
  936. subkey String name of subkey, may be quoted.
  937. value-name String name of value, may be quoted.
  938. flags One of the following
  939. 0x0 REG_SZ
  940. 0x10000 REG_MULTI_SZ
  941. 0x20000 REG_EXPAND_SZ
  942. 0x1 REG_BINARY
  943. 0x10001 REG_DWORD
  944. 0x100001 REG_MULTI_SZ stored as binary because it
  945. contains embedded newlines.
  946. 0x200001 REG_EXPAND_SZ stored as binary because it
  947. contains embedded newlines.
  948. 0x400001 REG_SZ stored as binary because it
  949. contains embedded newlines.
  950. 0x800000 REG_NONE
  951. other custom registry type directly copied
  952. value Depends on flags
  953. REG_SZ String, may be quoted.
  954. REG_MULTI_SZ List of comma separated strings, each of
  955. which may be quoted.
  956. REG_EXPAND_SZ String, may be quoted.
  957. REG_BINARY List of comma separated bytes in hex.
  958. REG_DWORD Integer
  959. Note: The caller is required to free the following variables even if
  960. this function fails.
  961. pptsRootName
  962. key_name
  963. value_name
  964. data
  965. ***************************************************************************/
  966. DWORD ParseRegistry( INFCONTEXT *pic, DWORD line_len,
  967. TCHAR **pptsRootName, TCHAR **key_name,
  968. TCHAR **value_name,
  969. DWORD *value_type, TCHAR **data, DWORD *data_len )
  970. {
  971. DWORD len;
  972. DWORD temp;
  973. BYTE *bytes;
  974. DWORD size = line_len*sizeof(TCHAR);
  975. DWORD req_size;
  976. BOOL fSuccess;
  977. DWORD dwResult = ERROR_SUCCESS;
  978. // Allocate memory for all the parameters.
  979. *key_name = (TCHAR *) malloc( size );
  980. *value_name = (TCHAR *) malloc( size );
  981. *data = (TCHAR *) malloc( size );
  982. *pptsRootName = (TCHAR *) malloc( size );
  983. if (*key_name == NULL || *value_name == NULL || *data == NULL ||
  984. *pptsRootName == NULL)
  985. {
  986. free( *key_name );
  987. free( *value_name );
  988. free( *data );
  989. free( *pptsRootName );
  990. *key_name = NULL;
  991. *value_name = NULL;
  992. *data = NULL;
  993. *pptsRootName = NULL;
  994. Win32PrintfResource( LogFile, IDS_NOT_ENOUGH_MEMORY );
  995. return ERROR_NOT_ENOUGH_MEMORY;
  996. }
  997. // Get the reg-root-string.
  998. fSuccess = SetupGetStringField( pic, 1, *pptsRootName, line_len, &req_size );
  999. LOG_ASSERT_EXPR( fSuccess, IDS_INF_ERROR, dwResult, SPAPI_E_GENERAL_SYNTAX );
  1000. // Verify that it is HKR or HKLM.
  1001. fSuccess = (_tcsicmp( TEXT("HKR"), *pptsRootName ) == 0) ||
  1002. (_tcsicmp( TEXT("HKLM"), *pptsRootName ) == 0);
  1003. LOG_ASSERT_EXPR( fSuccess, IDS_INF_ERROR, dwResult, SPAPI_E_GENERAL_SYNTAX );
  1004. // Get the subkey.
  1005. fSuccess = SetupGetStringField( pic, 2, *key_name, line_len, &req_size );
  1006. LOG_ASSERT_EXPR( fSuccess, IDS_INF_ERROR, dwResult, SPAPI_E_GENERAL_SYNTAX );
  1007. // Get the value name.
  1008. fSuccess = SetupGetStringField( pic, 3, *value_name, line_len, &req_size );
  1009. LOG_ASSERT_EXPR( fSuccess, IDS_INF_ERROR, dwResult, SPAPI_E_GENERAL_SYNTAX );
  1010. // Get the flags. _tcstol detects a leading 0x and converts from hex.
  1011. fSuccess = SetupGetIntField( pic, 4, (int *) value_type );
  1012. // Read the data based on the data type.
  1013. if (fSuccess) // value_type is valid
  1014. {
  1015. // Read a string.
  1016. if (*value_type == 0)
  1017. {
  1018. fSuccess = SetupGetStringField( pic, 5, *data, line_len, &req_size );
  1019. LOG_ASSERT_EXPR( fSuccess, IDS_INF_ERROR, dwResult, SPAPI_E_GENERAL_SYNTAX );
  1020. *data_len = req_size*sizeof(TCHAR);
  1021. *value_type = REG_SZ;
  1022. }
  1023. // Read an expand string.
  1024. else if (*value_type == 0x20000)
  1025. {
  1026. fSuccess = SetupGetStringField( pic, 5, *data, line_len, &req_size );
  1027. LOG_ASSERT_EXPR( fSuccess, IDS_INF_ERROR, dwResult, SPAPI_E_GENERAL_SYNTAX );
  1028. *data_len = req_size*sizeof(TCHAR);
  1029. *value_type = REG_EXPAND_SZ;
  1030. }
  1031. // Read a multi string.
  1032. else if (*value_type == 0x10000)
  1033. {
  1034. fSuccess = SetupGetMultiSzField( pic, 5, *data, line_len, &req_size );
  1035. LOG_ASSERT_EXPR( fSuccess, IDS_INF_ERROR, dwResult, SPAPI_E_GENERAL_SYNTAX );
  1036. *data_len = req_size*sizeof(TCHAR);
  1037. *value_type = REG_MULTI_SZ;
  1038. }
  1039. // Read a dword.
  1040. else if (*value_type == 0x10001)
  1041. {
  1042. fSuccess = SetupGetIntField( pic, 5, (int *) *data );
  1043. LOG_ASSERT_EXPR( fSuccess, IDS_INF_ERROR, dwResult, SPAPI_E_GENERAL_SYNTAX );
  1044. *data_len = sizeof(DWORD);
  1045. *value_type = REG_DWORD;
  1046. }
  1047. // Read a binary.
  1048. else
  1049. {
  1050. fSuccess = SetupGetBinaryField( pic, 5, (BYTE *) *data, size, &req_size );
  1051. LOG_ASSERT_EXPR( fSuccess, IDS_INF_ERROR, dwResult, SPAPI_E_GENERAL_SYNTAX );
  1052. *data_len = req_size;
  1053. if (*value_type == 1)
  1054. *value_type = REG_BINARY;
  1055. else if (*value_type == 0x100001)
  1056. *value_type = REG_MULTI_SZ;
  1057. else if (*value_type == 0x200001)
  1058. *value_type = REG_EXPAND_SZ;
  1059. else if (*value_type == 0x400001)
  1060. *value_type = REG_SZ;
  1061. else if (*value_type == 0x800000)
  1062. *value_type = REG_NONE;
  1063. }
  1064. }
  1065. else
  1066. {
  1067. *value_type = REG_NONE;
  1068. *data_len = 0;
  1069. *data = NULL;
  1070. }
  1071. cleanup:
  1072. return dwResult;
  1073. }
  1074. //---------------------------------------------------------------
  1075. DWORD CopyInf( const TCHAR *ptsSettingsSection )
  1076. {
  1077. DWORD dwResult;
  1078. BOOL fSuccess;
  1079. INFCONTEXT ic;
  1080. DWORD line_len = 0;
  1081. DWORD dwReqLen;
  1082. TCHAR *ptsKeyName = NULL;
  1083. TCHAR *ptsValueName = NULL;
  1084. TCHAR *ptsRootName = NULL;
  1085. DWORD dwValueType;
  1086. BYTE *data = NULL;
  1087. DWORD dwDataLen;
  1088. HKEY hKey = NULL;
  1089. BOOL fForce;
  1090. BOOL fExist;
  1091. HKEY hRootKey;
  1092. if (Verbose)
  1093. {
  1094. Win32Printf(LogFile, "Processing Section [%s]\r\n", ptsSettingsSection);
  1095. }
  1096. // Find the section.
  1097. fSuccess = SetupFindFirstLine( InputInf, ptsSettingsSection, NULL, &ic );
  1098. if (!fSuccess)
  1099. return ERROR_SUCCESS;
  1100. // Process each line in the section.
  1101. do
  1102. {
  1103. // Determine the line length.
  1104. fForce = FALSE;
  1105. fSuccess = SetupGetLineText( &ic,
  1106. NULL,
  1107. NULL,
  1108. NULL,
  1109. NULL,
  1110. 0,
  1111. &dwReqLen );
  1112. if (dwReqLen == 0)
  1113. LOG_ASSERT_GLE( fSuccess, dwResult );
  1114. // Parse the line.
  1115. dwResult = ParseRegistry( &ic,
  1116. dwReqLen,
  1117. &ptsRootName,
  1118. &ptsKeyName,
  1119. &ptsValueName,
  1120. &dwValueType,
  1121. (TCHAR **) &data,
  1122. &dwDataLen );
  1123. FAIL_ON_ERROR( dwResult );
  1124. if (ptsKeyName != NULL)
  1125. {
  1126. if ( VerboseReg )
  1127. {
  1128. Win32Printf(LogFile,
  1129. "Processing Key: ");
  1130. WriteKey( LogFile, dwValueType, ptsRootName, ptsKeyName, ptsValueName, data, dwDataLen);
  1131. }
  1132. dwResult = Filter( &ptsRootName,
  1133. &ptsKeyName,
  1134. &ptsValueName,
  1135. &dwValueType,
  1136. &data,
  1137. &dwDataLen,
  1138. &fForce );
  1139. FAIL_ON_ERROR( dwResult );
  1140. // Create or open the key.
  1141. if (ptsRootName != NULL)
  1142. {
  1143. if (_tcsicmp( TEXT("HKLM"), ptsRootName ) == 0)
  1144. {
  1145. if (UserPortion)
  1146. {
  1147. goto cleanup;
  1148. }
  1149. hRootKey = HKEY_LOCAL_MACHINE;
  1150. }
  1151. else
  1152. {
  1153. hRootKey = CurrentUser;
  1154. }
  1155. dwResult = RegCreateKeyEx( hRootKey,
  1156. ptsKeyName,
  1157. 0,
  1158. NULL,
  1159. REG_OPTION_NON_VOLATILE,
  1160. KEY_ALL_ACCESS,
  1161. NULL,
  1162. &hKey,
  1163. NULL );
  1164. #ifndef SPECIFIC_USER
  1165. if (dwResult == ERROR_ACCESS_DENIED)
  1166. {
  1167. Win32PrintfResource( LogFile,
  1168. IDS_REG_ACCESS,
  1169. ptsRootName,
  1170. ptsKeyName,
  1171. NULL );
  1172. dwResult = ERROR_SUCCESS;
  1173. }
  1174. else
  1175. #endif
  1176. if (data != NULL)
  1177. {
  1178. LOG_ASSERT( dwResult );
  1179. // ptsValueName == NULL means key's unnamed
  1180. // or default value
  1181. if (!fForce)
  1182. fExist = RegQueryValueEx( hKey,
  1183. ptsValueName,
  1184. NULL,
  1185. NULL,
  1186. NULL,
  1187. NULL ) == ERROR_SUCCESS;
  1188. // Set values that don't exist or are forced.
  1189. if (fForce || !fExist)
  1190. {
  1191. if ( VerboseReg )
  1192. {
  1193. Win32Printf(LogFile,
  1194. "=> Writing Key: ");
  1195. WriteKey( LogFile, dwValueType, ptsRootName, ptsKeyName, ptsValueName, data, dwDataLen);
  1196. }
  1197. dwResult = RegSetValueEx( hKey,
  1198. ptsValueName,
  1199. NULL,
  1200. dwValueType,
  1201. data,
  1202. dwDataLen );
  1203. LOG_ASSERT( dwResult );
  1204. }
  1205. }
  1206. }
  1207. // Free strings from the parser.
  1208. free( ptsRootName );
  1209. free( ptsKeyName );
  1210. free( ptsValueName );
  1211. free( data );
  1212. RegCloseKey( hKey );
  1213. ptsRootName = NULL;
  1214. hKey = NULL;
  1215. ptsKeyName = NULL;
  1216. ptsValueName = NULL;
  1217. data = NULL;
  1218. }
  1219. // Skip to the next line.
  1220. fSuccess = SetupFindNextLine( &ic, &ic );
  1221. } while(fSuccess);
  1222. cleanup:
  1223. // Close the key.
  1224. if (hKey != NULL)
  1225. RegCloseKey( hKey );
  1226. // Free strings from the parser.
  1227. free( ptsRootName );
  1228. free( ptsKeyName );
  1229. free( ptsValueName );
  1230. free( data );
  1231. return dwResult;
  1232. }
  1233. /***************************************************************************
  1234. BuildHive
  1235. This function creates a hive for the specified user by copying the
  1236. default hive and adding all the registry keys in migration.inf according
  1237. to the registry rules. The function returns the path to the hive. The
  1238. caller is required to free the path to the hive even when this function
  1239. fails.
  1240. ***************************************************************************/
  1241. DWORD BuildHive( TCHAR *ptsSettingsSection, TCHAR **pptsHiveName )
  1242. {
  1243. TCHAR tsDefaultUser[MAX_PATH];
  1244. DWORD dwDefaultUserLen = sizeof(tsDefaultUser);
  1245. DWORD dwResult = ERROR_SUCCESS;
  1246. DWORD dwLen;
  1247. BOOL fSuccess;
  1248. #ifdef SPECIFIC_USER
  1249. // Find the location of the default user profile.
  1250. fSuccess = GetDefaultUserProfileDirectory( tsDefaultUser,
  1251. &dwDefaultUserLen );
  1252. LOG_ASSERT_GLE( fSuccess, dwResult );
  1253. if (dwDefaultUserLen + sizeof(HIVEFILE)+2 > MAX_PATH*sizeof(TCHAR) )
  1254. {
  1255. Win32PrintfResource( LogFile, IDS_FAILED );
  1256. dwResult = ERROR_INTERNAL_ERROR;
  1257. goto cleanup;
  1258. }
  1259. _tcscat( tsDefaultUser, HIVEFILE );
  1260. // Compute a path for the temporary hive.
  1261. *pptsHiveName = (TCHAR *) malloc( MAX_PATH*sizeof(TCHAR) );
  1262. LOG_ASSERT_EXPR( *pptsHiveName != NULL, IDS_NOT_ENOUGH_MEMORY, dwResult,
  1263. ERROR_NOT_ENOUGH_MEMORY );
  1264. dwLen = ExpandEnvironmentStrings( HIVEPATH, *pptsHiveName, MAX_PATH );
  1265. LOG_ASSERT_EXPR( dwLen != 0 && dwLen <= MAX_PATH, IDS_FAILED, dwResult,
  1266. ERROR_INTERNAL_ERROR );
  1267. // To handle errors better, preemptively unload any old key in the
  1268. // registry at the path this function uses.
  1269. RegUnLoadKey( HKEY_USERS, BUILDKEY );
  1270. // Copy the default user hive to the temporary location.
  1271. fSuccess = CopyFile( tsDefaultUser, *pptsHiveName, FALSE );
  1272. LOG_ASSERT_GLE( fSuccess, dwResult );
  1273. if (DebugOutput)
  1274. Win32Printf(LogFile, "Loading the hive from %s\r\n", *pptsHiveName);
  1275. // Load the hive.
  1276. dwResult = RegLoadKey( HKEY_USERS, BUILDKEY, *pptsHiveName );
  1277. LOG_ASSERT( dwResult );
  1278. // Open the registry key.
  1279. dwResult = RegOpenKeyEx( HKEY_USERS,
  1280. BUILDKEY,
  1281. 0,
  1282. KEY_ALL_ACCESS,
  1283. &CurrentUser );
  1284. LOG_ASSERT( dwResult );
  1285. #else
  1286. dwResult = RegOpenKeyEx( HKEY_CURRENT_USER,
  1287. NULL,
  1288. 0,
  1289. KEY_ALL_ACCESS,
  1290. &CurrentUser );
  1291. LOG_ASSERT( dwResult );
  1292. #endif
  1293. dwResult = DeleteInf (); // delete unwanted .DEFAULT values
  1294. FAIL_ON_ERROR (dwResult);
  1295. // Process the INF file.
  1296. dwResult = CopyInf( ptsSettingsSection );
  1297. FAIL_ON_ERROR( dwResult );
  1298. cleanup:
  1299. return dwResult;
  1300. }
  1301. //---------------------------------------------------------------
  1302. void CleanupUser()
  1303. {
  1304. // Close the key.
  1305. if (CurrentUser != NULL)
  1306. {
  1307. RegCloseKey( CurrentUser );
  1308. CurrentUser = NULL;
  1309. }
  1310. // Unload the hive.
  1311. RegUnLoadKey( HKEY_USERS, BUILDKEY );
  1312. }
  1313. //---------------------------------------------------------------
  1314. DWORD CreateUserProfileFromName( TCHAR *ptsDomainName,
  1315. TCHAR *ptsUsername,
  1316. TCHAR *ptsHiveName )
  1317. {
  1318. SID *pSid;
  1319. DWORD dwSidLen = SID_GUESS;
  1320. TCHAR *ptsFullName;
  1321. DWORD dwDomainLen;
  1322. DWORD dwUserLen;
  1323. SID_NAME_USE sid_use;
  1324. DWORD dwResult = ERROR_SUCCESS;
  1325. BOOL fSuccess;
  1326. #ifdef SPECIFIC_USER
  1327. // Create the user profile when /u or (/f without /q flag) was used
  1328. if ((FALSE == CopyUser) &&
  1329. ((FALSE == CopyFiles) || (TRUE == TestMode)))
  1330. #endif
  1331. return ERROR_SUCCESS;
  1332. #ifdef SPECIFIC_USER
  1333. //Close the registry keys and stuff, we'll get them back after we create
  1334. //the profile.
  1335. CleanupUser();
  1336. dwDomainLen = _tcslen( ptsDomainName ) + 1;
  1337. dwUserLen = _tcslen( ptsUsername ) + 1;
  1338. // Allocate space to hold the sid and construct the full domain\username.
  1339. pSid = (SID *) _alloca( dwSidLen );
  1340. ptsFullName = (TCHAR *) _alloca( (dwDomainLen + dwUserLen + 2) *
  1341. sizeof(TCHAR) );
  1342. _tcscpy( ptsFullName, ptsDomainName );
  1343. ptsFullName[dwDomainLen-1] = L'\\';
  1344. _tcscpy( &ptsFullName[dwDomainLen], ptsUsername );
  1345. // Get the SID for the specified user.
  1346. fSuccess = LookupAccountName( NULL,
  1347. ptsFullName,
  1348. pSid,
  1349. &dwSidLen,
  1350. ptsDomainName,
  1351. &dwDomainLen,
  1352. &sid_use);
  1353. if (!fSuccess)
  1354. {
  1355. // Try allocating a bigger buffer.
  1356. if (dwSidLen > SID_GUESS)
  1357. {
  1358. pSid = (SID *) _alloca( dwSidLen );
  1359. fSuccess = LookupAccountName( NULL,
  1360. ptsFullName,
  1361. pSid,
  1362. &dwSidLen,
  1363. ptsDomainName,
  1364. &dwDomainLen,
  1365. &sid_use);
  1366. }
  1367. if (fSuccess == FALSE)
  1368. {
  1369. dwResult = GetLastError();
  1370. if (DebugOutput)
  1371. {
  1372. Win32Printf(LogFile,
  1373. "Could not find account name for %s: %d\r\n",
  1374. ptsFullName, dwResult);
  1375. }
  1376. }
  1377. LOG_ASSERT( dwResult );
  1378. }
  1379. // Allocate memory to hold the path to the user profile.
  1380. UserPath = (TCHAR *) malloc( MAX_PATH*sizeof(TCHAR) );
  1381. UserPath[0]=0;
  1382. LOG_ASSERT_EXPR( UserPath != NULL, IDS_NOT_ENOUGH_MEMORY, dwResult,
  1383. ERROR_NOT_ENOUGH_MEMORY );
  1384. // Create the user profile directory.
  1385. fSuccess = CreateUserProfile( pSid,
  1386. ptsUsername,
  1387. ptsHiveName,
  1388. UserPath,
  1389. MAX_PATH*sizeof(TCHAR) );
  1390. if (DebugOutput)
  1391. Win32Printf(LogFile,
  1392. "Creating Profile for %s in %s from %s\r\n",
  1393. ptsUsername, UserPath, ptsHiveName);
  1394. if (fSuccess == FALSE)
  1395. {
  1396. dwResult = GetLastError();
  1397. if (dwResult == ERROR_SHARING_VIOLATION)
  1398. {
  1399. Win32PrintfResource( LogFile, IDS_CANT_LOAD_CURRENT_USER );
  1400. goto cleanup;
  1401. }
  1402. LOG_ASSERT( dwResult );
  1403. }
  1404. if (0 == UserPath[0])
  1405. {
  1406. Win32PrintfResource( LogFile, IDS_USER_PROFILE_FAILED );
  1407. dwResult = ERROR_INTERNAL_ERROR;
  1408. goto cleanup;
  1409. }
  1410. //Reopen the new hive
  1411. TCHAR _tcsHivePath[MAX_PATH + 1];
  1412. if (_tcslen(UserPath) + _tcslen(HIVEFILE) > MAX_PATH)
  1413. {
  1414. if (DebugOutput)
  1415. {
  1416. Win32Printf(LogFile, "Error: hivepath too long %s%s\r\n", UserPath, HIVEFILE);
  1417. }
  1418. dwResult = ERROR_FILENAME_EXCED_RANGE;
  1419. goto cleanup;
  1420. }
  1421. _tcscpy(_tcsHivePath, UserPath);
  1422. _tcscat(_tcsHivePath, HIVEFILE);
  1423. dwResult = RegLoadKey(HKEY_USERS, BUILDKEY, _tcsHivePath);
  1424. if (DebugOutput)
  1425. Win32Printf(LogFile, "Loading hive from %s\r\n", _tcsHivePath);
  1426. if (dwResult)
  1427. {
  1428. LOG_ASSERT( dwResult );
  1429. }
  1430. //Reopen the registry from the new location
  1431. dwResult = RegOpenKeyEx(HKEY_USERS,
  1432. BUILDKEY,
  1433. 0,
  1434. KEY_ALL_ACCESS,
  1435. &CurrentUser);
  1436. if (dwResult)
  1437. {
  1438. LOG_ASSERT(dwResult);
  1439. }
  1440. cleanup:
  1441. return dwResult;
  1442. #endif
  1443. }
  1444. //---------------------------------------------------------------
  1445. DWORD FixSpecial()
  1446. {
  1447. CRegFileList *prfl = g_prflStart;
  1448. DWORD dwResult = ERROR_SUCCESS;
  1449. while (prfl != NULL)
  1450. {
  1451. const TCHAR *ptsRoot, *ptsKey, *ptsVal, *ptsData;
  1452. DWORD dwValueType;
  1453. TCHAR *ptsLocation, *ptsFinalValue;
  1454. TCHAR tsExpand[MAX_PATH + 1];
  1455. TCHAR tsTemp[MAX_PATH + 1];
  1456. prfl->GetData(&ptsRoot, &ptsKey, &ptsVal, &ptsData, &dwValueType);
  1457. dwResult = WhereIsThisFile(ptsData, &ptsLocation);
  1458. if (ERROR_NOT_FOUND == dwResult)
  1459. {
  1460. ptsLocation = (TCHAR *)ptsData;
  1461. }
  1462. else if (ERROR_SUCCESS != dwResult)
  1463. {
  1464. return dwResult;
  1465. }
  1466. //Expand any environment strings in the original data with
  1467. //the values for the user we're loading for. If the final
  1468. //paths match, we'll retain the version of the data with the
  1469. //unexpanded environment variables in it. Otherwise, we take
  1470. //the full path.
  1471. if (_tcslen(ptsData) > MAX_PATH)
  1472. {
  1473. if (DebugOutput)
  1474. {
  1475. Win32Printf(LogFile, "Error: ptsData too long %s\r\n", ptsData);
  1476. }
  1477. return ERROR_FILENAME_EXCED_RANGE;
  1478. }
  1479. _tcscpy(tsExpand, ptsData);
  1480. dwResult = ExpandEnvStringForUser(tsExpand,
  1481. tsTemp,
  1482. &ptsFinalValue);
  1483. if (dwResult)
  1484. return dwResult;
  1485. if (_tcsicmp(ptsLocation, ptsFinalValue) == 0)
  1486. {
  1487. //They're the same, use the string with the environment
  1488. //variables in it.
  1489. ptsFinalValue = (TCHAR *)ptsData;
  1490. }
  1491. else
  1492. {
  1493. ptsFinalValue = ptsLocation;
  1494. }
  1495. if (ptsRoot != NULL)
  1496. {
  1497. HKEY hRootKey;
  1498. HKEY hKey;
  1499. if (_tcsicmp(TEXT("HKLM"), ptsRoot) == 0)
  1500. hRootKey = HKEY_LOCAL_MACHINE;
  1501. else
  1502. hRootKey = CurrentUser;
  1503. dwResult = RegCreateKeyEx(hRootKey,
  1504. ptsKey,
  1505. NULL,
  1506. NULL,
  1507. REG_OPTION_NON_VOLATILE,
  1508. KEY_ALL_ACCESS,
  1509. NULL,
  1510. &hKey,
  1511. NULL);
  1512. LOG_ASSERT(dwResult);
  1513. if ( VerboseReg )
  1514. {
  1515. Win32Printf(LogFile,
  1516. "=> Writing Key: ");
  1517. WriteKey(LogFile,
  1518. dwValueType, (TCHAR *)ptsRoot, (TCHAR *)ptsKey, (TCHAR *)ptsVal, (UCHAR *)ptsFinalValue, _tcslen(ptsFinalValue)+1);
  1519. }
  1520. dwResult = RegSetValueEx(hKey,
  1521. ptsVal,
  1522. NULL,
  1523. dwValueType,
  1524. (BYTE *)ptsFinalValue,
  1525. (_tcslen(ptsFinalValue) + 1) *
  1526. sizeof(TCHAR));
  1527. RegCloseKey(hKey);
  1528. LOG_ASSERT(dwResult);
  1529. }
  1530. free(ptsLocation);
  1531. // Next:
  1532. CRegFileList *prflPrev;
  1533. prflPrev = prfl;
  1534. prfl = prfl->GetNext();
  1535. delete prflPrev;
  1536. g_prflStart = prfl;
  1537. }
  1538. cleanup:
  1539. return dwResult;
  1540. }
  1541. //---------------------------------------------------------------
  1542. DWORD LoadUser( TCHAR **pptsDomainName,
  1543. TCHAR **pptsUsername,
  1544. TCHAR **pptsHiveName )
  1545. {
  1546. TCHAR *ptsSettingsSection = NULL;
  1547. DWORD dwResult;
  1548. // Initialize the hash table with the filter rules.
  1549. dwResult = InitializeHash( );
  1550. FAIL_ON_ERROR( dwResult );
  1551. // Fetch user info only if /u or (/f without /q) flag was used
  1552. if ((FALSE == CopyUser) &&
  1553. ((FALSE == CopyFiles) || (TRUE == TestMode)))
  1554. {
  1555. // Open the registry key.
  1556. dwResult = RegOpenKeyEx( HKEY_CURRENT_USER,
  1557. NULL,
  1558. 0,
  1559. KEY_ALL_ACCESS,
  1560. &CurrentUser );
  1561. LOG_ASSERT( dwResult );
  1562. return ERROR_SUCCESS;
  1563. }
  1564. // Read the user information from the inf file.
  1565. dwResult = ReadUser( &ptsSettingsSection, pptsDomainName, pptsUsername );
  1566. FAIL_ON_ERROR( dwResult );
  1567. #ifdef SPECIFIC_USER
  1568. // Enable some privileges.
  1569. dwResult = EnableBackupPrivilege();
  1570. FAIL_ON_ERROR( dwResult );
  1571. #endif
  1572. // If the user was on a Win9x machine,
  1573. // apply all the settings to a new hive.
  1574. dwResult = BuildHive( ptsSettingsSection, pptsHiveName );
  1575. FAIL_ON_ERROR( dwResult );
  1576. cleanup:
  1577. if (ptsSettingsSection != NULL)
  1578. free( ptsSettingsSection );
  1579. return dwResult;
  1580. }
  1581. //---------------------------------------------------------------
  1582. DWORD ProcessExtensions()
  1583. {
  1584. // Apply registry keys in the copied state section.
  1585. return CopyInf( EXTENSION_STATE_SECTION );
  1586. }
  1587. //*****************************************************************
  1588. //
  1589. // Synopsis: Build a file list string out of a CStringList.
  1590. //
  1591. // History: 11/14/1999 Created by WeiruC.
  1592. //
  1593. // Return Value: Win32 error code.
  1594. //
  1595. //*****************************************************************
  1596. DWORD BuildFileListString(CStringList* fileList, TCHAR** tcsFileList)
  1597. {
  1598. DWORD cFileListBuffer = 10240; // length of file list string buffer
  1599. DWORD cFileListString = 0; // length of file list string
  1600. DWORD rv = ERROR_SUCCESS; // return value
  1601. TCHAR* tcsTargetFileName = NULL;
  1602. TCHAR* tmpStringBuffer;
  1603. CStringList* cur;
  1604. *tcsFileList = new TCHAR[cFileListBuffer];
  1605. **tcsFileList = TEXT('\0');
  1606. if(fileList == NULL || (fileList->String())[0] == TEXT('\0'))
  1607. {
  1608. return rv;
  1609. }
  1610. cur = fileList->Next();
  1611. //
  1612. // For every file in the source file list, call Phil's code to figure out
  1613. // where that file is migrated to, and then add it to the target file list
  1614. // string.
  1615. //
  1616. do
  1617. {
  1618. rv = WhereIsThisFile(cur->String(), &tcsTargetFileName);
  1619. if(rv == ERROR_SUCCESS)
  1620. {
  1621. if(cFileListBuffer - cFileListString <= _tcslen(tcsTargetFileName))
  1622. {
  1623. //
  1624. // String buffer is not big enough. Double it.
  1625. //
  1626. tmpStringBuffer = *tcsFileList;
  1627. *tcsFileList = new TCHAR[cFileListBuffer *= 2];
  1628. _tcscpy(*tcsFileList, tmpStringBuffer);
  1629. delete []tmpStringBuffer;
  1630. }
  1631. //
  1632. // Add the new file name to the new file list.
  1633. //
  1634. _tcscat(*tcsFileList, tcsTargetFileName);
  1635. _tcscat(*tcsFileList, TEXT(" "));
  1636. cFileListString += _tcslen(tcsTargetFileName) + 1;
  1637. }
  1638. if(tcsTargetFileName != NULL)
  1639. {
  1640. free(tcsTargetFileName);
  1641. tcsTargetFileName = NULL;
  1642. }
  1643. if(cur == fileList)
  1644. {
  1645. break;
  1646. }
  1647. //
  1648. // Go to the next file.
  1649. //
  1650. cur = cur->Next();
  1651. }
  1652. while(TRUE);
  1653. if(tcsTargetFileName != NULL)
  1654. {
  1655. free(tcsTargetFileName);
  1656. }
  1657. return rv;
  1658. }
  1659. //*****************************************************************
  1660. //
  1661. // Synopsis: Run an executable in a child process.
  1662. //
  1663. // History: 11/14/1999 Created by WeiruC.
  1664. //
  1665. // Return Value: Win32 error code.
  1666. //
  1667. //*****************************************************************
  1668. DWORD RunCommandInChildProcess(CStringList* command, CStringList* fileList)
  1669. {
  1670. SECURITY_ATTRIBUTES sa; // allow handles to be inherited
  1671. DWORD rv = ERROR_SUCCESS; // return value
  1672. STARTUPINFO si;
  1673. PROCESS_INFORMATION pi;
  1674. TCHAR* tcsFileList = NULL;
  1675. TCHAR* cur;
  1676. CStringList* tmp; // used when growing the string
  1677. TCHAR fileName[MAX_PATH + 1];
  1678. TCHAR* commandLine = NULL; // command line
  1679. DWORD commandLineLen = 0; // command line length
  1680. DWORD cFileList = 10240; // string length of tcsFileList
  1681. ZeroMemory(&si, sizeof(STARTUPINFO));
  1682. si.cb = sizeof(STARTUPINFO);
  1683. //
  1684. // Build the file list string. We ignore error here. If a file is not picked
  1685. // up, we'll still pass it to the command. We'll let the user's executable
  1686. // handle the error.
  1687. //
  1688. BuildFileListString(fileList, &tcsFileList);
  1689. //
  1690. // Initialize the command line. We can either do two loops to count how big
  1691. // a string we need for the command line, or do one loops and just set a
  1692. // max limit on how long the command line is allowed. We probably won't
  1693. // have that many commands or arguments anyway.
  1694. //
  1695. commandLineLen += _tcslen(command->String()) + 3; // '"' + '"' + ' '
  1696. commandLineLen += _tcslen(tcsFileList) + 1; // ' '
  1697. for(tmp = command->Next(); tmp != command; tmp = tmp->Next())
  1698. {
  1699. commandLineLen += _tcslen(tmp->String()) + 3; // '"' + '"' + ' '
  1700. }
  1701. commandLine = new TCHAR[commandLineLen + _tcslen(tcsFileList) + 1];
  1702. commandLine[0] = TEXT('\0');
  1703. MakeCommandLine(command, command->Next(), commandLine);
  1704. _tcscat(commandLine, tcsFileList);
  1705. if(!CreateProcess(NULL,
  1706. commandLine,
  1707. NULL,
  1708. NULL,
  1709. TRUE,
  1710. 0,
  1711. NULL,
  1712. NULL,
  1713. &si,
  1714. &pi))
  1715. {
  1716. rv = GetLastError();
  1717. goto cleanup;
  1718. }
  1719. cleanup:
  1720. if(tcsFileList != NULL)
  1721. {
  1722. delete []tcsFileList;
  1723. }
  1724. if(commandLine != NULL)
  1725. {
  1726. delete []commandLine;
  1727. }
  1728. return rv;
  1729. }
  1730. //*****************************************************************
  1731. //
  1732. // Synopsis: Process the [Run These Commands] extension section in an inf
  1733. // file.
  1734. //
  1735. // History: 11/14/1999 Created by WeiruC.
  1736. //
  1737. // Return Value: Win32 error code.
  1738. //
  1739. //*****************************************************************
  1740. DWORD ProcessExecExtensions()
  1741. {
  1742. DWORD rv = ERROR_SUCCESS; // return value
  1743. BOOL success = TRUE; // value returned by setup functions
  1744. INFCONTEXT context; // used by setup inf functions
  1745. INFCONTEXT contextOutput; // Run These Commands Output section
  1746. TCHAR* label = NULL; // label in inf file
  1747. TCHAR* labelOutput = NULL; // label in inf file
  1748. CStringList* command = NULL; // command
  1749. CStringList* fileList = NULL; // file list from Scanstate
  1750. if(InputInf == INVALID_HANDLE_VALUE)
  1751. {
  1752. return ERROR_SUCCESS;
  1753. }
  1754. //
  1755. // Find the section in the inf file. If it doesn't exist, do nothing and
  1756. // return ERROR_SUCCESS.
  1757. //
  1758. if(!SetupFindFirstLine(InputInf, EXECUTABLE_EXT_SECTION, NULL, &context))
  1759. {
  1760. return ERROR_SUCCESS;
  1761. }
  1762. //
  1763. // Process each line in the section:
  1764. // Find matching file list from Scanstate
  1765. // run the command
  1766. //
  1767. do
  1768. {
  1769. //
  1770. // Parse the line.
  1771. //
  1772. rv = ParseSectionList(&context, &label, &command);
  1773. FAIL_ON_ERROR(rv);
  1774. if((command->String())[0] != TEXT('\0'))
  1775. {
  1776. //
  1777. // Find matching output from Scanstate.
  1778. //
  1779. if(SetupFindFirstLine(InputInf,
  1780. EXECUTABLE_EXTOUT_SECTION,
  1781. label,
  1782. &contextOutput))
  1783. {
  1784. //
  1785. // Parse the line.
  1786. //
  1787. rv = ParseSectionList(&contextOutput, &labelOutput, &fileList);
  1788. FAIL_ON_ERROR(rv);
  1789. }
  1790. //
  1791. // Create a child process to run the command. Ignore error and
  1792. // continue to run the next command.
  1793. //
  1794. RunCommandInChildProcess(command, fileList);
  1795. }
  1796. //
  1797. // Clean up and reinitialize.
  1798. //
  1799. if(label)
  1800. {
  1801. free(label);
  1802. label = NULL;
  1803. }
  1804. if(labelOutput)
  1805. {
  1806. free(labelOutput);
  1807. labelOutput = NULL;
  1808. }
  1809. if(command)
  1810. {
  1811. delete command;
  1812. command = NULL;
  1813. }
  1814. if(fileList)
  1815. {
  1816. delete fileList;
  1817. fileList = NULL;
  1818. }
  1819. }
  1820. while(SetupFindNextLine(&context, &context));
  1821. cleanup:
  1822. if(label)
  1823. {
  1824. free(label);
  1825. }
  1826. if(labelOutput)
  1827. {
  1828. free(labelOutput);
  1829. labelOutput = NULL;
  1830. }
  1831. if(command)
  1832. {
  1833. delete command;
  1834. }
  1835. if(fileList)
  1836. {
  1837. delete fileList;
  1838. fileList = NULL;
  1839. }
  1840. return rv;
  1841. }