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.

884 lines
24 KiB

  1. //*************************************************************
  2. //
  3. // Hash table for registry Rsop data
  4. //
  5. // Microsoft Confidential
  6. // Copyright (c) Microsoft Corporation 1999
  7. // All rights reserved
  8. //
  9. // History: 7-Jun-99 SitaramR Created
  10. //
  11. //*************************************************************
  12. #include "uenv.h"
  13. #include "reghash.h"
  14. #include "rsop.h"
  15. REGKEYENTRY * AllocRegKeyEntry( WCHAR *pwszKeyName );
  16. void FreeRegKeyEntry( REGKEYENTRY *pKeyEntry );
  17. REGVALUEENTRY *AllocValueEntry( WCHAR *pwszValueName );
  18. void FreeValueEntry( REGVALUEENTRY *pValueEntry );
  19. REGDATAENTRY * AllocDataEntry( REGOPERATION opnType,
  20. DWORD dwType,
  21. DWORD dwLen,
  22. BYTE *pData,
  23. WCHAR *pwszGPO,
  24. WCHAR *pwszSOM,
  25. WCHAR *pwszCommand);
  26. void FreeDataEntry( REGDATAENTRY *pDataEntry );
  27. BOOL DeleteRegTree( REGHASHTABLE *pHashTable,
  28. WCHAR *pwszKeyName,
  29. WCHAR *pwszGPO,
  30. WCHAR *pwszSOM,
  31. WCHAR *szCommand);
  32. REGKEYENTRY * FindRegKeyEntry( REGHASHTABLE *pHashTable,
  33. WCHAR *pwszKeyName,
  34. BOOL bCreate );
  35. REGVALUEENTRY * FindValueEntry( REGHASHTABLE *pHashTable,
  36. WCHAR *pwszKeyName,
  37. WCHAR *pwszValueName,
  38. BOOL bCreate );
  39. BOOL AddDataEntry( REGVALUEENTRY *pValueEntry,
  40. REGOPERATION opnType,
  41. DWORD dwType,
  42. DWORD dwLen,
  43. BYTE *pData,
  44. WCHAR *pwszGPO,
  45. WCHAR *pwszSOM,
  46. WCHAR *pwszCommand);
  47. ////////////////////////////////////////////////////////////////////////
  48. // Hash Table for registry policies
  49. // ----------------------------------
  50. //
  51. // This hash table is used to log rsop data for registry policies.
  52. // A hash table entry is created for each registry entry. The registry entry
  53. // name itself is used to calculate the hash table.
  54. //
  55. // Each Registry entry has a link to each of the values modified by policy.
  56. // These values are in a link list and sorted by the valueNames.
  57. //
  58. // Each Value has the list of Data that are being set on the Values. This
  59. // sorted by the order of execution. The topmost value will contain the final value.
  60. // The Data entries have fields that mark the value as deleted and the Command
  61. // associated with the action. To look for the possible commands look in the
  62. // ParseRegistryFile.
  63. //
  64. // Additionally, in the hash table 2 special case values exist.
  65. // a. **Command Value. The Data under this value will contain all the commands
  66. // that are executed under this key.
  67. //
  68. // b. An ""(Empty ValueName) This valuename represents the modifications happening
  69. // to the key itself. For example a key can deleted or added..
  70. //
  71. // Note:
  72. // The szCommand that is passed in has to be non NULL but can be an empty string.
  73. // There is a dependency on it in AddDataEntry and in logger.cpp. There is an Assert
  74. // for this in AddRegHashEntry
  75. //
  76. ////////////////////////////////////////////////////////////////////////
  77. //*************************************************************
  78. //
  79. // AllocHashTable
  80. //
  81. // Purpose: Allocates a new hash table
  82. //
  83. // Returns: Pointer to hash table
  84. //
  85. //*************************************************************
  86. REGHASHTABLE * AllocHashTable()
  87. {
  88. DWORD i;
  89. REGHASHTABLE *pHashTable = (REGHASHTABLE *) LocalAlloc (LPTR, sizeof(REGHASHTABLE));
  90. if ( pHashTable == NULL ) {
  91. DebugMsg((DM_WARNING, TEXT("AllocHashTable: Failed to alloc hashtable.")));
  92. return NULL;
  93. }
  94. for ( i=0; i<HASH_TABLE_SIZE; i++) {
  95. pHashTable->aHashTable[i] = 0;
  96. }
  97. pHashTable->hrError = S_OK;
  98. return pHashTable;
  99. }
  100. //*************************************************************
  101. //
  102. // FreeHashTable
  103. //
  104. // Purpose: Deletes a hash table
  105. //
  106. // Parameters: pHashTable - Hash table to delete
  107. //
  108. //*************************************************************
  109. void FreeHashTable( REGHASHTABLE *pHashTable )
  110. {
  111. DWORD i;
  112. if ( pHashTable == NULL )
  113. return;
  114. for ( i=0; i<HASH_TABLE_SIZE; i++ ) {
  115. REGKEYENTRY *pKeyEntry = pHashTable->aHashTable[i];
  116. while ( pKeyEntry ) {
  117. REGKEYENTRY *pNext = pKeyEntry->pNext;
  118. FreeRegKeyEntry( pKeyEntry );
  119. pKeyEntry = pNext;
  120. }
  121. }
  122. }
  123. //*************************************************************
  124. //
  125. // AllocRegKey
  126. //
  127. // Purpose: Allocates a new registry key entry
  128. //
  129. // Returns: Pointer to registr key entry
  130. //
  131. //*************************************************************
  132. REGKEYENTRY * AllocRegKeyEntry( WCHAR *pwszKeyName )
  133. {
  134. REGKEYENTRY *pKeyEntry = (REGKEYENTRY *) LocalAlloc (LPTR, sizeof(REGKEYENTRY));
  135. if ( pKeyEntry == NULL ) {
  136. DebugMsg((DM_WARNING, TEXT("AllocRegKeyEntry: Failed to alloc key entry.")));
  137. return NULL;
  138. }
  139. pKeyEntry->pwszKeyName = (WCHAR *) LocalAlloc (LPTR, (lstrlen(pwszKeyName) + 1 ) * sizeof(WCHAR));
  140. if ( pKeyEntry->pwszKeyName == NULL ) {
  141. DebugMsg((DM_WARNING, TEXT("AllocRegKeyEntry: Failed to alloc key name.")));
  142. LocalFree( pKeyEntry );
  143. return NULL;
  144. }
  145. lstrcpy( pKeyEntry->pwszKeyName, pwszKeyName );
  146. return pKeyEntry;
  147. }
  148. //*************************************************************
  149. //
  150. // FreeRegKeyEntry
  151. //
  152. // Purpose: Deletes a registry key entry
  153. //
  154. // Parameters: pKeyEntry - Entry to delete
  155. //
  156. //*************************************************************
  157. void FreeRegKeyEntry( REGKEYENTRY *pKeyEntry )
  158. {
  159. REGVALUEENTRY *pValueEntry = NULL;
  160. if ( pKeyEntry == NULL )
  161. return;
  162. LocalFree( pKeyEntry->pwszKeyName );
  163. pValueEntry = pKeyEntry->pValueList;
  164. while ( pValueEntry ) {
  165. REGVALUEENTRY *pNext = pValueEntry->pNext;
  166. FreeValueEntry( pValueEntry );
  167. pValueEntry = pNext;
  168. }
  169. LocalFree( pKeyEntry );
  170. }
  171. //*************************************************************
  172. //
  173. // AllocValueEntry
  174. //
  175. // Purpose: Allocates a new value entry
  176. //
  177. // Returns: Pointer to value entry
  178. //
  179. //*************************************************************
  180. REGVALUEENTRY *AllocValueEntry( WCHAR *pwszValueName )
  181. {
  182. REGVALUEENTRY *pValueEntry = (REGVALUEENTRY *) LocalAlloc (LPTR, sizeof(REGVALUEENTRY));
  183. if ( pValueEntry == NULL ) {
  184. DebugMsg((DM_WARNING, TEXT("AllocValueEntry: Failed to alloc value entry.")));
  185. return NULL;
  186. }
  187. pValueEntry->pwszValueName = (WCHAR *) LocalAlloc (LPTR, (lstrlen(pwszValueName) + 1 ) * sizeof(WCHAR));
  188. if ( pValueEntry->pwszValueName == NULL ) {
  189. DebugMsg((DM_WARNING, TEXT("AllocValueEntry: Failed to alloc key name.")));
  190. LocalFree( pValueEntry );
  191. return NULL;
  192. }
  193. lstrcpy( pValueEntry->pwszValueName, pwszValueName );
  194. return pValueEntry;
  195. }
  196. //*************************************************************
  197. //
  198. // FreeValueEntry
  199. //
  200. // Purpose: Deletes a value entry
  201. //
  202. // Parameters: pValueEntry - Entry to delete
  203. //
  204. //*************************************************************
  205. void FreeValueEntry( REGVALUEENTRY *pValueEntry )
  206. {
  207. REGDATAENTRY *pDataEntry = NULL;
  208. if ( pValueEntry == NULL )
  209. return;
  210. LocalFree( pValueEntry->pwszValueName );
  211. pDataEntry = pValueEntry->pDataList;
  212. while ( pDataEntry ) {
  213. REGDATAENTRY *pNext = pDataEntry->pNext;
  214. FreeDataEntry( pDataEntry );
  215. pDataEntry = pNext;
  216. }
  217. LocalFree( pValueEntry );
  218. }
  219. //*************************************************************
  220. //
  221. // AllocDataEntry
  222. //
  223. // Purpose: Allocates a new data entry
  224. //
  225. // Returns: Pointer to data entry
  226. //
  227. //*************************************************************
  228. REGDATAENTRY * AllocDataEntry( REGOPERATION opnType,
  229. DWORD dwType,
  230. DWORD dwLen,
  231. BYTE *pData,
  232. WCHAR *pwszGPO,
  233. WCHAR *pwszSOM,
  234. WCHAR *pwszCommand)
  235. {
  236. BOOL bResult = FALSE;
  237. REGDATAENTRY *pDataEntry = (REGDATAENTRY *) LocalAlloc (LPTR, sizeof(REGDATAENTRY));
  238. if ( pDataEntry == NULL ) {
  239. DebugMsg((DM_WARNING, TEXT("AllocDataEntry: Failed to alloc data entry.")));
  240. return NULL;
  241. }
  242. if ( opnType == REG_ADDVALUE )
  243. pDataEntry->bDeleted = FALSE;
  244. else
  245. pDataEntry->bDeleted = TRUE;
  246. pDataEntry->bAdmPolicy = FALSE;
  247. pDataEntry->dwValueType = dwType;
  248. pDataEntry->dwDataLen = dwLen;
  249. if ( pData ) {
  250. pDataEntry->pData = (BYTE *) LocalAlloc (LPTR, dwLen);
  251. if ( pDataEntry->pData == NULL ) {
  252. DebugMsg((DM_WARNING, TEXT("AllocDataEntry: Failed to alloc data.")));
  253. goto Exit;
  254. }
  255. CopyMemory( pDataEntry->pData, pData, dwLen );
  256. }
  257. DmAssert( pwszGPO != NULL && pwszSOM != NULL );
  258. pDataEntry->pwszGPO = (WCHAR *) LocalAlloc (LPTR, (lstrlen(pwszGPO) + 1 ) * sizeof(WCHAR));
  259. if ( pDataEntry->pwszGPO == NULL ) {
  260. DebugMsg((DM_WARNING, TEXT("AllocDataEntry: Failed to alloc Gpo name.")));
  261. goto Exit;
  262. }
  263. lstrcpy( pDataEntry->pwszGPO, pwszGPO );
  264. pDataEntry->pwszSOM = (WCHAR *) LocalAlloc (LPTR, (lstrlen(pwszSOM) + 1 ) * sizeof(WCHAR));
  265. if ( pDataEntry->pwszSOM == NULL ) {
  266. DebugMsg((DM_WARNING, TEXT("AllocDataEntry: Failed to alloc Sdou name.")));
  267. goto Exit;
  268. }
  269. lstrcpy( pDataEntry->pwszSOM, pwszSOM );
  270. pDataEntry->pwszCommand = (WCHAR *) LocalAlloc (LPTR, (lstrlen(pwszCommand) + 1 ) * sizeof(WCHAR));
  271. if ( pDataEntry->pwszCommand == NULL ) {
  272. DebugMsg((DM_WARNING, TEXT("AllocDataEntry: Failed to alloc Sdou name.")));
  273. goto Exit;
  274. }
  275. lstrcpy( pDataEntry->pwszCommand, pwszCommand );
  276. bResult = TRUE;
  277. Exit:
  278. if ( !bResult ) {
  279. LocalFree( pDataEntry->pData );
  280. LocalFree( pDataEntry->pwszGPO );
  281. LocalFree( pDataEntry->pwszSOM );
  282. if (pDataEntry->pwszCommand)
  283. LocalFree(pDataEntry->pwszCommand);
  284. LocalFree( pDataEntry);
  285. return NULL;
  286. }
  287. return pDataEntry;
  288. }
  289. //*************************************************************
  290. //
  291. // FreeDataEntry
  292. //
  293. // Purpose: Deletes a data entry
  294. //
  295. // Parameters: pDataEntry - Entry to delete
  296. //
  297. //*************************************************************
  298. void FreeDataEntry( REGDATAENTRY *pDataEntry )
  299. {
  300. if ( pDataEntry ) {
  301. LocalFree( pDataEntry->pData );
  302. LocalFree( pDataEntry->pwszGPO );
  303. LocalFree( pDataEntry->pwszSOM );
  304. LocalFree( pDataEntry);
  305. }
  306. }
  307. //*************************************************************
  308. //
  309. // Hash
  310. //
  311. // Purpose: Maps a key name to a hash bucket
  312. //
  313. // Parameters: pwszName - Key name
  314. //
  315. // Returns: Hash bucket
  316. //
  317. //*************************************************************
  318. DWORD Hash( WCHAR *pwszName )
  319. {
  320. DWORD dwLen = lstrlen( pwszName );
  321. DWORD dwHashValue = 0;
  322. for ( ; dwLen>0; pwszName++ ) {
  323. dwHashValue = toupper(*pwszName) + 31 * dwHashValue;
  324. dwLen--;
  325. }
  326. return dwHashValue % HASH_TABLE_SIZE;
  327. }
  328. //*************************************************************
  329. //
  330. // AddRegHashEntry
  331. //
  332. // Purpose: Adds a registry key to the hash table
  333. //
  334. // Parameters: pwszName - Key name
  335. //
  336. //*************************************************************
  337. BOOL AddRegHashEntry( REGHASHTABLE *pHashTable,
  338. REGOPERATION opnType,
  339. WCHAR *pwszKeyName,
  340. WCHAR *pwszValueName,
  341. DWORD dwType,
  342. DWORD dwDataLen,
  343. BYTE *pData,
  344. WCHAR *pwszGPO,
  345. WCHAR *pwszSOM,
  346. WCHAR *szCommand,
  347. BOOL bCreateCommand)
  348. {
  349. REGVALUEENTRY *pValueEntry = NULL;
  350. BOOL bResult = FALSE;
  351. REGKEYENTRY *pKeyEntry=NULL;
  352. switch (opnType) {
  353. case REG_DELETEKEY:
  354. bResult = DeleteRegTree( pHashTable, pwszKeyName, pwszGPO, pwszSOM, szCommand );
  355. break;
  356. case REG_INTERNAL_DELETESINGLEKEY:
  357. case REG_DELETEALLVALUES:
  358. pKeyEntry = FindRegKeyEntry( pHashTable,
  359. pwszKeyName,
  360. FALSE );
  361. if ( pKeyEntry == NULL ) {
  362. //
  363. // Delete all values is similar to policy being disabled and
  364. // so do nothing.
  365. //
  366. if (opnType == REG_DELETEALLVALUES) {
  367. bResult = TRUE;
  368. break;
  369. }
  370. else
  371. // no command entry in this case.
  372. return TRUE;
  373. }
  374. pValueEntry = pKeyEntry->pValueList;
  375. while ( pValueEntry ) {
  376. if (lstrcmp(pValueEntry->pwszValueName, TEXT("")) != 0) {
  377. if (lstrcmpi(pValueEntry->pwszValueName, STARCOMMAND) != 0) {
  378. //
  379. // Mark the value as deleted
  380. //
  381. bResult = AddDataEntry( pValueEntry, opnType, 0, 0, NULL,
  382. pwszGPO, pwszSOM, szCommand );
  383. if ( !bResult )
  384. return FALSE;
  385. }
  386. }
  387. else {
  388. //
  389. // Mark the key as deleted
  390. //
  391. if (opnType == REG_INTERNAL_DELETESINGLEKEY) {
  392. bResult = AddDataEntry( pValueEntry, opnType, 0, 0, NULL,
  393. pwszGPO, pwszSOM, szCommand );
  394. if ( !bResult )
  395. return FALSE;
  396. }
  397. }
  398. pValueEntry = pValueEntry->pNext;
  399. }
  400. bResult = TRUE;
  401. break;
  402. case REG_ADDVALUE:
  403. case REG_SOFTADDVALUE:
  404. //
  405. // We have to make a value with no name to represent the creation of key itself..
  406. //
  407. pValueEntry = FindValueEntry( pHashTable, pwszKeyName,
  408. TEXT(""), TRUE );
  409. if ( pValueEntry == NULL )
  410. return FALSE;
  411. bResult = AddDataEntry( pValueEntry, opnType, 0, 0, NULL,
  412. pwszGPO, pwszSOM, szCommand );
  413. if (!bResult)
  414. return FALSE;
  415. if ((!pwszValueName) || (!(*pwszValueName)) ||
  416. (dwDataLen == 0) || (dwType == REG_NONE))
  417. break;
  418. // fall through
  419. case REG_DELETEVALUE:
  420. pValueEntry = FindValueEntry( pHashTable, pwszKeyName,
  421. pwszValueName, TRUE );
  422. if ( pValueEntry == NULL )
  423. return FALSE;
  424. //
  425. // In case of SOFTADDVALUE the final decision to add the value is made in
  426. // AddDataEntry
  427. //
  428. bResult = AddDataEntry( pValueEntry, opnType, dwType, dwDataLen, pData,
  429. pwszGPO, pwszSOM, szCommand );
  430. break;
  431. default:
  432. DmAssert(FALSE && "Unknown Case Selector for AddRegHashEntry");
  433. }
  434. DmAssert(szCommand);
  435. //
  436. // If everything succeeded, then log the command if
  437. // bCreateCommand is true. This is done creating or adding
  438. // to a value called **Command. This means that this value is not
  439. // Settable by adm file..
  440. //
  441. if ((bResult) && (bCreateCommand) && (opnType != REG_INTERNAL_DELETESINGLEKEY) && (*szCommand != TEXT('\0'))) {
  442. pValueEntry = FindValueEntry( pHashTable, pwszKeyName,
  443. STARCOMMAND, TRUE );
  444. if ( pValueEntry == NULL )
  445. return FALSE;
  446. bResult = AddDataEntry( pValueEntry, REG_ADDVALUE, 0,
  447. sizeof(TCHAR)*(lstrlen(szCommand)+1), (BYTE *)szCommand,
  448. pwszGPO, pwszSOM, szCommand);
  449. }
  450. return bResult;
  451. }
  452. //*************************************************************
  453. //
  454. // DeleteRegTree
  455. //
  456. // Purpose: Deletes a key and all its subkeys
  457. //
  458. // Parameters: pHashTable - Hash table
  459. // pwszKeyName - Key name to delete
  460. // pwszGPO - Gpo
  461. // pwszSOM - Sdou that the Gpo is linked to
  462. //
  463. //*************************************************************
  464. BOOL DeleteRegTree( REGHASHTABLE *pHashTable,
  465. WCHAR *pwszKeyName,
  466. WCHAR *pwszGPO,
  467. WCHAR *pwszSOM,
  468. WCHAR *szCommand)
  469. {
  470. DWORD i=0;
  471. DWORD dwKeyLen = lstrlen( pwszKeyName );
  472. for ( i=0; i<HASH_TABLE_SIZE; i++ ) {
  473. REGKEYENTRY *pKeyEntry = pHashTable->aHashTable[i];
  474. while ( pKeyEntry ) {
  475. BOOL bAdd = FALSE;
  476. DWORD dwKeyLen2 = lstrlen(pKeyEntry->pwszKeyName);
  477. if ( dwKeyLen2 >= dwKeyLen
  478. && CompareString (LOCALE_USER_DEFAULT, NORM_IGNORECASE,
  479. pKeyEntry->pwszKeyName, dwKeyLen,
  480. pwszKeyName, dwKeyLen ) == CSTR_EQUAL) {
  481. //
  482. // It's a prefix if length and strings match, or if one
  483. // string is bigger and there is a '\' at the right place.
  484. //
  485. if ( dwKeyLen2 > dwKeyLen ) {
  486. if ( pKeyEntry->pwszKeyName[dwKeyLen] == L'\\' )
  487. bAdd = TRUE;
  488. } else
  489. bAdd = TRUE;
  490. if ( bAdd ) {
  491. BOOL bResult = AddRegHashEntry( pHashTable,
  492. REG_INTERNAL_DELETESINGLEKEY,
  493. pKeyEntry->pwszKeyName,
  494. NULL, 0, 0, NULL,
  495. pwszGPO, pwszSOM, szCommand, FALSE );
  496. if ( !bResult )
  497. return FALSE;
  498. }
  499. } // if dwKeyLen2 >= dwKeyLen
  500. pKeyEntry = pKeyEntry->pNext;
  501. } // while
  502. } // for
  503. return TRUE;
  504. }
  505. //*************************************************************
  506. //
  507. // FindRegKeyEntry
  508. //
  509. // Purpose: Looks up a reg key entry in hash table
  510. //
  511. // Parameters: pHashTable - Hash table
  512. // pwszKeyName - Key name to find
  513. // bCreate - Should key be created if not found ?
  514. //
  515. //*************************************************************
  516. REGKEYENTRY * FindRegKeyEntry( REGHASHTABLE *pHashTable,
  517. WCHAR *pwszKeyName,
  518. BOOL bCreate )
  519. {
  520. DWORD dwHashValue = Hash( pwszKeyName );
  521. REGKEYENTRY *pCurPtr = pHashTable->aHashTable[dwHashValue];
  522. REGKEYENTRY *pTrailPtr = NULL;
  523. while ( pCurPtr != NULL ) {
  524. INT iResult = CompareString( LOCALE_USER_DEFAULT, NORM_IGNORECASE,
  525. pwszKeyName, -1,
  526. pCurPtr->pwszKeyName, -1 );
  527. if ( iResult == CSTR_EQUAL ) {
  528. return pCurPtr;
  529. } else if ( iResult == CSTR_LESS_THAN ) {
  530. //
  531. // Keys are in ascending order, so insert if bCreate
  532. //
  533. if ( bCreate ) {
  534. REGKEYENTRY *pKeyEntry = AllocRegKeyEntry( pwszKeyName );
  535. if ( pKeyEntry == NULL )
  536. return 0;
  537. pKeyEntry->pNext = pCurPtr;
  538. if ( pTrailPtr == NULL )
  539. pHashTable->aHashTable[dwHashValue] = pKeyEntry;
  540. else
  541. pTrailPtr->pNext = pKeyEntry;
  542. return pKeyEntry;
  543. } else
  544. return NULL;
  545. } else {
  546. //
  547. // Advance down the list
  548. //
  549. pTrailPtr = pCurPtr;
  550. pCurPtr = pCurPtr->pNext;
  551. }
  552. }
  553. //
  554. // End of list or null list case
  555. //
  556. if ( bCreate ) {
  557. REGKEYENTRY *pKeyEntry = AllocRegKeyEntry( pwszKeyName );
  558. if ( pKeyEntry == NULL )
  559. return 0;
  560. pKeyEntry->pNext = 0;
  561. if ( pTrailPtr == NULL )
  562. pHashTable->aHashTable[dwHashValue] = pKeyEntry;
  563. else
  564. pTrailPtr->pNext = pKeyEntry;
  565. return pKeyEntry;
  566. }
  567. return NULL;
  568. }
  569. //*************************************************************
  570. //
  571. // FindValueEntry
  572. //
  573. // Purpose: Looks up a value entry in hash table
  574. //
  575. // Parameters: pHashTable - Hash table
  576. // pwszKeyName - Key name to find
  577. // pwszValueName - Value name to find
  578. // bCreate - Should key be created if not found ?
  579. //
  580. //*************************************************************
  581. REGVALUEENTRY * FindValueEntry( REGHASHTABLE *pHashTable,
  582. WCHAR *pwszKeyName,
  583. WCHAR *pwszValueName,
  584. BOOL bCreate )
  585. {
  586. REGVALUEENTRY *pCurPtr = NULL;
  587. REGVALUEENTRY *pTrailPtr = NULL;
  588. REGKEYENTRY *pKeyEntry = FindRegKeyEntry( pHashTable, pwszKeyName, bCreate );
  589. if ( pKeyEntry == NULL )
  590. return NULL;
  591. pCurPtr = pKeyEntry->pValueList;
  592. pTrailPtr = NULL;
  593. while ( pCurPtr != NULL ) {
  594. INT iResult = CompareString( LOCALE_USER_DEFAULT, NORM_IGNORECASE,
  595. pwszValueName, -1,
  596. pCurPtr->pwszValueName, -1 );
  597. if ( iResult == CSTR_EQUAL ) {
  598. return pCurPtr;
  599. } else if ( iResult == CSTR_LESS_THAN ) {
  600. //
  601. // Keys are in ascending order, so insert if bCreate
  602. //
  603. if ( bCreate ) {
  604. REGVALUEENTRY *pValueEntry = AllocValueEntry( pwszValueName );
  605. if ( pValueEntry == NULL )
  606. return 0;
  607. pValueEntry->pNext = pCurPtr;
  608. if ( pTrailPtr == NULL )
  609. pKeyEntry->pValueList = pValueEntry;
  610. else
  611. pTrailPtr->pNext = pValueEntry;
  612. return pValueEntry;
  613. } else
  614. return NULL;
  615. } else {
  616. //
  617. // Advance down the list
  618. //
  619. pTrailPtr = pCurPtr;
  620. pCurPtr = pCurPtr->pNext;
  621. }
  622. }
  623. //
  624. // End of list or null list case
  625. //
  626. if ( bCreate ) {
  627. REGVALUEENTRY *pValueEntry = AllocValueEntry( pwszValueName );
  628. if ( pValueEntry == NULL )
  629. return 0;
  630. pValueEntry->pNext = 0;
  631. if ( pTrailPtr == NULL )
  632. pKeyEntry->pValueList = pValueEntry;
  633. else
  634. pTrailPtr->pNext = pValueEntry;
  635. return pValueEntry;
  636. }
  637. return NULL;
  638. }
  639. //*************************************************************
  640. //
  641. // AddDataEntry
  642. //
  643. // Purpose: Adds a data entry to a value entry struct
  644. //
  645. // Parameters: pValueEntry - Value entry
  646. // opnType - Operation type
  647. // dwType - Type of registry data
  648. // dwLen - Length of registry data
  649. // pData - Data
  650. // pwszGPO - Gpo that set this value
  651. // pwszSOM - Sdou that the Gpo is linked to
  652. //
  653. //*************************************************************
  654. BOOL AddDataEntry( REGVALUEENTRY *pValueEntry,
  655. REGOPERATION opnType,
  656. DWORD dwType,
  657. DWORD dwLen,
  658. BYTE *pData,
  659. WCHAR *pwszGPO,
  660. WCHAR *pwszSOM,
  661. WCHAR *pwszCommand)
  662. {
  663. REGDATAENTRY *pDataEntry = NULL;
  664. if (opnType == REG_SOFTADDVALUE) {
  665. //
  666. // if the data list is null or if the first value (highest precedence value is deleted)
  667. // then add it to the list
  668. //
  669. if ((pValueEntry->pDataList == NULL) || (pValueEntry->pDataList->pNext->bDeleted))
  670. opnType = REG_ADDVALUE;
  671. else
  672. return TRUE;
  673. // return without adding the value.
  674. }
  675. pDataEntry = AllocDataEntry( opnType, dwType, dwLen, pData,
  676. pwszGPO, pwszSOM, pwszCommand );
  677. if ( pDataEntry == NULL )
  678. return FALSE;
  679. //
  680. // Prepend to data list because entries at beginning of list have higher precedence
  681. //
  682. pDataEntry->pNext = pValueEntry->pDataList;
  683. pValueEntry->pDataList = pDataEntry;
  684. return TRUE;
  685. }