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.

1228 lines
29 KiB

  1. /*++
  2. Copyright (c) 1991 Microsoft Corporation
  3. Module Name:
  4. RegvCls.c
  5. Abstract:
  6. This module contains helper functions for enumerating,
  7. setting, and querying registry values in win32
  8. Author:
  9. Adam Edwards (adamed) 06-May-1998
  10. Key Functions:
  11. Notes:
  12. --*/
  13. #ifdef LOCAL
  14. #include <rpc.h>
  15. #include "regrpc.h"
  16. #include "localreg.h"
  17. #include "regclass.h"
  18. #include "regvcls.h"
  19. #include <malloc.h>
  20. void ValStateGetPhysicalIndexFromLogical(
  21. ValueState* pValState,
  22. HKEY hkLogicalKey,
  23. DWORD dwLogicalIndex,
  24. PHKEY phkPhysicalKey,
  25. DWORD* pdwPhysicalIndex)
  26. /*++
  27. Routine Description:
  28. Retrieves a logical index for a value to a physical index
  29. Arguments:
  30. pValState - value state containing values for a logical key
  31. hkLogicalKey - logical key we wish to index
  32. dwLogicalIndex - logical index to map
  33. phkPhysicalKey - handle to key where value is physically located
  34. pdwPhysicalIndex - index of value in physical key
  35. Return Value:
  36. None.
  37. Notes:
  38. --*/
  39. {
  40. //
  41. // If no value state is supplied, this means no merging is necessary
  42. // and we can return the supplied logical index as the correct
  43. // physical index
  44. //
  45. if (!pValState) {
  46. *pdwPhysicalIndex = dwLogicalIndex;
  47. *phkPhysicalKey = hkLogicalKey;
  48. } else {
  49. *pdwPhysicalIndex = pValState->rgIndex[dwLogicalIndex].dwOffset;
  50. *phkPhysicalKey = pValState->rgIndex[dwLogicalIndex].fUser ?
  51. pValState->hkUser :
  52. pValState->hkMachine;
  53. }
  54. }
  55. NTSTATUS ValStateSetPhysicalIndexFromLogical(
  56. ValueState* pValState,
  57. DWORD dwLogicalIndex)
  58. /*++
  59. Routine Description:
  60. Updates a state's mapping of logical indexes to physical indexes
  61. Arguments:
  62. pValState - value state containing values for a logical key
  63. dwLogicalIndex - logical index used as a clue for whether
  64. or not we can used cached values or need to refresh the state --
  65. gives us an idea of what index the caller will be interested in
  66. mapping after this call.
  67. Return Value:
  68. None.
  69. Notes:
  70. --*/
  71. {
  72. NTSTATUS Status;
  73. Status = STATUS_SUCCESS;
  74. //
  75. // If no value state is supplied, this means no merging is necessary
  76. // and we can return the supplied logical index as the correct
  77. // physical index
  78. //
  79. if (!pValState) {
  80. return STATUS_SUCCESS;
  81. }
  82. if (dwLogicalIndex >= pValState->cValues) {
  83. pValState->fDelete = TRUE;
  84. return STATUS_NO_MORE_ENTRIES;
  85. }
  86. //
  87. // Always reset if they try to go backward, or
  88. // if they skip by more than 1, or if they
  89. // ask for the same index twice and we're
  90. // not expecting it
  91. //
  92. if ((dwLogicalIndex < pValState->dwCurrent) ||
  93. (dwLogicalIndex > (pValState->dwCurrent + 1)) ||
  94. ((dwLogicalIndex == pValState->dwCurrent) && !(pValState->fIgnoreResetOnRetry))) {
  95. Status = ValStateUpdate(pValState);
  96. if (!NT_SUCCESS(Status)) {
  97. return Status;
  98. }
  99. pValState->fIgnoreResetOnRetry = FALSE;
  100. }
  101. return Status;
  102. }
  103. void ValStateRelease(
  104. ValueState* pValState)
  105. /*++
  106. Routine Description:
  107. Frees resources (handles, memory) associated with a value state
  108. Arguments:
  109. pValState - value state containing values for a logical key
  110. Return Value:
  111. None.
  112. Notes:
  113. --*/
  114. {
  115. if (!pValState) {
  116. return;
  117. }
  118. if (pValState->hkUser && (pValState->hkUser != pValState->hkLogical)) {
  119. NtClose(pValState->hkUser);
  120. }
  121. if (pValState->hkMachine && (pValState->hkMachine != pValState->hkLogical)) {
  122. NtClose(pValState->hkMachine);
  123. }
  124. if (pValState->rgIndex) {
  125. RegClassHeapFree(pValState->rgIndex);
  126. }
  127. RegClassHeapFree(pValState);
  128. }
  129. NTSTATUS ValStateUpdate(ValueState* pValState)
  130. /*++
  131. Routine Description:
  132. Updates the value state to reflect the current state
  133. of the logical key's physical state -- it retrieves
  134. the names of the values for the logical key from
  135. the kernel, and re-indexes the table to properly
  136. merge user and machine state
  137. Arguments:
  138. pValState - value state containing values for a logical key
  139. Return Value:
  140. STATUS_SUCCESS for success, error code otherwise.
  141. Notes:
  142. --*/
  143. {
  144. NTSTATUS Status;
  145. DWORD cUserValues;
  146. DWORD cMachineValues;
  147. DWORD cMaxValues;
  148. DWORD cbMaxNameLen;
  149. DWORD cbMaxDataLen;
  150. DWORD cbBufferLen;
  151. ValueLocation* rgIndex;
  152. PKEY_VALUE_BASIC_INFORMATION* ppValueInfo;
  153. //
  154. // Init locals
  155. //
  156. cUserValues = 0;
  157. cMachineValues = 0;
  158. cbMaxNameLen = 0;
  159. rgIndex = NULL;
  160. pValState->cValues = 0;
  161. //
  162. // Get information about this value
  163. //
  164. Status = GetFixedKeyInfo(
  165. pValState->hkUser,
  166. pValState->hkMachine,
  167. &cUserValues,
  168. &cMachineValues,
  169. NULL,
  170. NULL,
  171. &cbMaxNameLen);
  172. if (!NT_SUCCESS(Status)) {
  173. return Status;
  174. }
  175. cMaxValues = cUserValues + cMachineValues;
  176. //
  177. // Nothing to do if there are no Values
  178. //
  179. if (!cMaxValues) {
  180. return STATUS_SUCCESS;
  181. }
  182. //
  183. // Now allocate necessary memory
  184. // First get memory for index vector
  185. //
  186. rgIndex = (ValueLocation*) RegClassHeapAlloc(cMaxValues * sizeof(*rgIndex));
  187. if (!rgIndex) {
  188. return STATUS_NO_MEMORY;
  189. }
  190. //
  191. // Now get memory for retrieving names -- first allocate an array
  192. // of pointers to values
  193. //
  194. ppValueInfo = (PKEY_VALUE_BASIC_INFORMATION*) RegClassHeapAlloc(
  195. sizeof(*ppValueInfo) * cMaxValues);
  196. if (!ppValueInfo) {
  197. RegClassHeapFree(rgIndex);
  198. return STATUS_NO_MEMORY;
  199. }
  200. RtlZeroMemory(ppValueInfo, sizeof(*ppValueInfo) * cMaxValues);
  201. cbBufferLen = sizeof(**ppValueInfo) + cbMaxNameLen;
  202. //
  203. // Now allocate each individual value
  204. //
  205. {
  206. DWORD dwValue;
  207. for (dwValue = 0; dwValue < cMaxValues; dwValue++)
  208. {
  209. ppValueInfo[dwValue] = (PKEY_VALUE_BASIC_INFORMATION) RegClassHeapAlloc(
  210. cbBufferLen);
  211. if (!(ppValueInfo)[dwValue]) {
  212. Status = STATUS_NO_MEMORY;
  213. break;
  214. }
  215. }
  216. }
  217. //
  218. // Now fetch the values. From this point on we are assuming success
  219. // and updating the index table
  220. //
  221. {
  222. HKEY hKeyPhysical;
  223. DWORD dwLimit;
  224. DWORD dwLogical;
  225. BOOL fUser;
  226. //
  227. // Free the existing index table
  228. //
  229. if (pValState->rgIndex) {
  230. RegClassHeapFree(pValState->rgIndex);
  231. }
  232. pValState->rgIndex = rgIndex;
  233. dwLogical = 0;
  234. for( hKeyPhysical = pValState->hkUser, fUser = TRUE,
  235. dwLimit = cUserValues;
  236. ;
  237. hKeyPhysical = pValState->hkMachine, fUser = FALSE,
  238. dwLimit = cMachineValues)
  239. {
  240. DWORD dwPhysical;
  241. for (dwPhysical = 0; dwPhysical < dwLimit; dwPhysical++)
  242. {
  243. BOOL fNewValue;
  244. //
  245. // Ask the kernel for the value
  246. //
  247. Status = EnumerateValue(
  248. hKeyPhysical,
  249. dwPhysical,
  250. ppValueInfo[dwLogical],
  251. cbBufferLen,
  252. NULL);
  253. //
  254. // If we encounter an error, just keep going and try to get
  255. // as many values as we can
  256. //
  257. if (!NT_SUCCESS(Status)) {
  258. continue;
  259. }
  260. //
  261. // Mark certain attributes about this value that will
  262. // be important later
  263. //
  264. ppValueInfo[dwLogical]->TitleIndex = dwPhysical;
  265. ppValueInfo[dwLogical]->Type = fUser;
  266. //
  267. // This will add the value to our sorted list. Since
  268. // the list is sorted, it is easy to eliminated duplicates --
  269. // don't add duplicates -- since we add
  270. // user keys first, this allows us to give user values precedence
  271. // over machine values of the same name. The logical key
  272. // index is also incremented if a key is added.
  273. //
  274. fNewValue = ValStateAddValueToSortedValues(
  275. ppValueInfo,
  276. dwLogical);
  277. if (fNewValue) {
  278. dwLogical++;
  279. }
  280. }
  281. //
  282. // Break out of this loop if we just added the user values
  283. // since those are the last values we add
  284. //
  285. if (!fUser) {
  286. break;
  287. }
  288. }
  289. pValState->cValues = dwLogical;
  290. }
  291. //
  292. // Now copy the results back to the state's index array
  293. //
  294. {
  295. DWORD dwLogical;
  296. for (dwLogical = 0; dwLogical < pValState->cValues; dwLogical++)
  297. {
  298. pValState->rgIndex[dwLogical].dwOffset =
  299. ppValueInfo[dwLogical]->TitleIndex;
  300. pValState->rgIndex[dwLogical].fUser =
  301. ppValueInfo[dwLogical]->Type;
  302. }
  303. }
  304. //
  305. // Release this
  306. //
  307. ValStateReleaseValues(
  308. ppValueInfo,
  309. cMaxValues);
  310. return STATUS_SUCCESS;
  311. }
  312. void ValStateReleaseValues(
  313. PKEY_VALUE_BASIC_INFORMATION* ppValueInfo,
  314. DWORD cMaxValues)
  315. /*++
  316. Routine Description:
  317. Releases resources associated with the values stored
  318. in the value state.
  319. Arguments:
  320. pValState - value state containing values for a logical key
  321. Return Value:
  322. None.
  323. Notes:
  324. --*/
  325. {
  326. DWORD dwValue;
  327. //
  328. // First, free each individual value
  329. //
  330. for (dwValue = 0; dwValue < cMaxValues; dwValue++)
  331. {
  332. //
  333. // Free memory for this value
  334. //
  335. if (ppValueInfo[dwValue]) {
  336. RegClassHeapFree(ppValueInfo[dwValue]);
  337. }
  338. }
  339. //
  340. // Now free the array that held all the values
  341. //
  342. RegClassHeapFree(ppValueInfo);
  343. }
  344. NTSTATUS ValStateInitialize(
  345. ValueState** ppValState,
  346. HKEY hKey)
  347. /*++
  348. Routine Description:
  349. Initializes a value state
  350. Arguments:
  351. pValState - value state containing values for a logical key
  352. hKey - logical key whose state this value state will represent
  353. Return Value:
  354. STATUS_SUCCESS for success, error code otherwise.
  355. Notes:
  356. --*/
  357. {
  358. NTSTATUS Status;
  359. ValueState* pValState;
  360. HKEY hkUser;
  361. HKEY hkMachine;
  362. //
  363. // Initialize conditionally freed resources
  364. //
  365. hkUser = NULL;
  366. hkMachine = NULL;
  367. pValState = NULL;
  368. //
  369. // Get the user and machine keys
  370. //
  371. Status = BaseRegGetUserAndMachineClass(
  372. NULL,
  373. hKey,
  374. MAXIMUM_ALLOWED,
  375. &hkMachine,
  376. &hkUser);
  377. if (NT_SUCCESS(Status)) {
  378. ASSERT(hkUser || hkMachine);
  379. //
  380. // We only need to create a state if there are
  381. // two keys -- if only one exists, we don't
  382. // need to do merging
  383. //
  384. if (!hkUser || !hkMachine) {
  385. *ppValState = NULL;
  386. return STATUS_SUCCESS;
  387. }
  388. //
  389. // Get memory for the value state
  390. //
  391. pValState = RegClassHeapAlloc( sizeof(*pValState) +
  392. sizeof(DWORD) * DEFAULT_VALUESTATE_SUBKEY_ALLOC );
  393. //
  394. // Be sure to release acquired resources on failure
  395. //
  396. if (!pValState) {
  397. if (hkUser != hKey) {
  398. NtClose(hkUser);
  399. } else {
  400. NtClose(hkMachine);
  401. }
  402. return STATUS_NO_MEMORY;
  403. }
  404. RtlZeroMemory(pValState, sizeof(*pValState));
  405. pValState->hkUser = hkUser;
  406. pValState->hkMachine = hkMachine;
  407. pValState->hkLogical = hKey;
  408. pValState->fIgnoreResetOnRetry = TRUE;
  409. //
  410. // Now update the state to reflect the current registry
  411. //
  412. Status = ValStateUpdate(pValState);
  413. }
  414. //
  415. // On success, set our out param
  416. //
  417. if (NT_SUCCESS(Status)) {
  418. *ppValState = pValState;
  419. } else {
  420. if (pValState) {
  421. ValStateRelease(pValState);
  422. }
  423. }
  424. return Status;
  425. }
  426. BOOL ValStateAddValueToSortedValues(
  427. PKEY_VALUE_BASIC_INFORMATION* ppValueInfo,
  428. LONG lNewValue)
  429. /*++
  430. Routine Description:
  431. Inserts a retrieved value into the sorted list
  432. of values in a value state
  433. Arguments:
  434. pValState - value state containing values for a logical key
  435. lNewValue - index of newly added value in the sorted list --
  436. this value needs to be moved elsewhere in the list to maintain
  437. the sorted nature of the list
  438. Return Value:
  439. TRUE if the state was added, FALSE if not.
  440. Notes:
  441. --*/
  442. {
  443. PKEY_VALUE_BASIC_INFORMATION pNewValue;
  444. LONG lFinalSpot;
  445. LONG lCurrent;
  446. UNICODE_STRING NewKeyName;
  447. lFinalSpot = 0;
  448. pNewValue = ppValueInfo[lNewValue];
  449. NewKeyName.Buffer = pNewValue->Name;
  450. NewKeyName.Length = (USHORT) pNewValue->NameLength;
  451. for (lCurrent = lNewValue - 1; lCurrent >= 0; lCurrent--)
  452. {
  453. UNICODE_STRING CurrentValueName;
  454. PKEY_VALUE_BASIC_INFORMATION pCurrentValue;
  455. LONG lCompareResult;
  456. pCurrentValue = ppValueInfo[lCurrent];
  457. CurrentValueName.Buffer = pCurrentValue->Name;
  458. CurrentValueName.Length = (USHORT) pCurrentValue->NameLength;
  459. lCompareResult = RtlCompareUnicodeString(
  460. &NewKeyName,
  461. &CurrentValueName,
  462. TRUE);
  463. if (lCompareResult < 0) {
  464. continue;
  465. } else if (0 == lCompareResult) {
  466. //
  467. // If it's a duplicate, don't add it
  468. //
  469. return FALSE;
  470. } else {
  471. lFinalSpot = lCurrent + 1;
  472. break;
  473. }
  474. }
  475. //
  476. // Now we know the final spot, add the value
  477. //
  478. //
  479. // Move everything up to make room for the new value
  480. //
  481. for (lCurrent = lNewValue - 1; lCurrent >= lFinalSpot; lCurrent--)
  482. {
  483. //
  484. // Move the current value up one
  485. //
  486. ppValueInfo[lCurrent + 1] = ppValueInfo[lCurrent];
  487. }
  488. //
  489. // Copy the value to its final destination
  490. //
  491. ppValueInfo[lFinalSpot] = pNewValue;
  492. //
  493. // This means we've found no duplicate value
  494. // so we add it
  495. //
  496. return TRUE;
  497. }
  498. NTSTATUS KeyStateGetValueState(
  499. HKEY hKey,
  500. ValueState** ppValState)
  501. /*++
  502. Routine Description:
  503. Gets the value state for a particular key
  504. Arguments:
  505. hKey - key whose state we need to retrieve
  506. ppValState - out param pointing to a pointer to the
  507. retrieved state.
  508. Return Value:
  509. STATUS_SUCCESS for success, error code otherwise.
  510. Notes:
  511. ATENTION: Right now, this always creates a new state -- in the future,
  512. we may want to change this to be cached in a table to avoid reconstructing
  513. on every call.
  514. --*/
  515. {
  516. //
  517. // Now build the value state
  518. //
  519. return ValStateInitialize(
  520. ppValState,
  521. hKey);
  522. }
  523. NTSTATUS BaseRegGetClassKeyValueState(
  524. HKEY hKey,
  525. DWORD dwLogicalIndex,
  526. ValueState** ppValState)
  527. /*++
  528. Routine Description:
  529. Gets the value state for a particular key and optimizes
  530. it for a given index
  531. Arguments:
  532. hKey - key whose state we need to retrieve
  533. dwLogicalIndex - hint that helps us to optimize the state for this
  534. index so the caller's use of the state is more efficient
  535. ppValState - out param pointing to a pointer to the
  536. retrieved state.
  537. Return Value:
  538. STATUS_SUCCESS for success, error code otherwise.
  539. Notes:
  540. --*/
  541. {
  542. NTSTATUS Status;
  543. ValueState* pValState;
  544. //
  545. // First retrieve the state for this key
  546. //
  547. Status = KeyStateGetValueState(hKey, &pValState);
  548. if (NT_SUCCESS(Status)) {
  549. //
  550. // Now map the logical index to a physical one
  551. //
  552. Status = ValStateSetPhysicalIndexFromLogical(pValState, dwLogicalIndex);
  553. if (!NT_SUCCESS(Status)) {
  554. ValStateRelease(pValState);
  555. } else {
  556. *ppValState = pValState;
  557. }
  558. }
  559. return Status;
  560. }
  561. NTSTATUS EnumerateValue(
  562. HKEY hKey,
  563. DWORD dwValue,
  564. PKEY_VALUE_BASIC_INFORMATION pSuggestedBuffer,
  565. DWORD dwSuggestedBufferLength,
  566. PKEY_VALUE_BASIC_INFORMATION* ppResult)
  567. /*++
  568. Routine Description:
  569. Retrieves a value for a physical key from the kernel
  570. Arguments:
  571. hKey - physical key for which we're trying to read a value
  572. dwValue - physical index of value to read
  573. pSuggestedBuffer - basinc info buffer to use by default, may not be large enough
  574. dwSuggestedBufferLength - size of suggested buffer
  575. ppResult - pointer to result basic info -- may be allocated by this function if
  576. suggested buffer was insufficient, which means caller will have to free
  577. this if it is not the same as the suggested buffer
  578. Return Value:
  579. STATUS_SUCCESS for success, error code otherwise.
  580. Notes:
  581. --*/
  582. {
  583. NTSTATUS Status;
  584. PKEY_VALUE_BASIC_INFORMATION pKeyValueInformation;
  585. DWORD dwResultLength;
  586. pKeyValueInformation = pSuggestedBuffer;
  587. //
  588. // Query for the necessary information about the supplied value.
  589. //
  590. Status = NtEnumerateValueKey( hKey,
  591. dwValue,
  592. KeyValueBasicInformation,
  593. pKeyValueInformation,
  594. dwSuggestedBufferLength,
  595. &dwResultLength);
  596. //
  597. // A return value of STATUS_BUFFER_TOO_SMALL would mean that there
  598. // was not enough room for even the known (i.e. fixed length portion)
  599. // of the structure.
  600. //
  601. ASSERT( Status != STATUS_BUFFER_TOO_SMALL );
  602. if (ppResult && (STATUS_BUFFER_OVERFLOW == Status)) {
  603. pKeyValueInformation = (PKEY_VALUE_BASIC_INFORMATION) RegClassHeapAlloc(
  604. dwResultLength);
  605. if (!pKeyValueInformation) {
  606. return STATUS_NO_MEMORY;
  607. }
  608. //
  609. // Query for the necessary information about the supplied value.
  610. //
  611. Status = NtEnumerateValueKey( hKey,
  612. dwValue,
  613. KeyValueBasicInformation,
  614. pKeyValueInformation,
  615. dwResultLength,
  616. &dwResultLength);
  617. ASSERT( Status != STATUS_BUFFER_TOO_SMALL );
  618. if (!NT_SUCCESS(Status)) {
  619. RegClassHeapFree(pKeyValueInformation);
  620. }
  621. }
  622. if (NT_SUCCESS(Status) && ppResult) {
  623. *ppResult = pKeyValueInformation;
  624. }
  625. return Status;
  626. }
  627. NTSTATUS BaseRegQueryMultipleClassKeyValues(
  628. HKEY hKey,
  629. PRVALENT val_list,
  630. DWORD num_vals,
  631. LPSTR lpvalueBuf,
  632. LPDWORD ldwTotsize,
  633. PULONG ldwRequiredLength)
  634. /*++
  635. Routine Description:
  636. Gets the value state for a particular key and optimizes
  637. it for a given index
  638. Arguments:
  639. hKey - Supplies a handle to the open key. The value entries returned
  640. are contained in the key pointed to by this key handle. Any of
  641. the predefined reserved handles or a previously opened key handle
  642. may be used for hKey.
  643. val_list - Supplies a pointer to an array of RVALENT structures, one for
  644. each value to be queried.
  645. num_vals - Supplies the size in bytes of the val_list array.
  646. lpValueBuf - Returns the data for each value
  647. ldwTotsize - Supplies the length of lpValueBuf. Returns the number of bytes
  648. written into lpValueBuf.
  649. ldwRequiredLength - If lpValueBuf is not large enough to
  650. contain all the data, returns the size of lpValueBuf required
  651. to return all the requested data.
  652. Return Value:
  653. STATUS_SUCCESS for success, error code otherwise.
  654. Notes:
  655. --*/
  656. {
  657. NTSTATUS Status;
  658. HKEY hkUser;
  659. HKEY hkMachine;
  660. HKEY hkQuery;
  661. //
  662. // Initialize conditionally freed resources
  663. //
  664. hkUser = NULL;
  665. hkMachine = NULL;
  666. //
  667. // First, get both user and machine keys
  668. //
  669. Status = BaseRegGetUserAndMachineClass(
  670. NULL,
  671. hKey,
  672. MAXIMUM_ALLOWED,
  673. &hkMachine,
  674. &hkUser);
  675. if (!NT_SUCCESS(Status)) {
  676. return Status;
  677. }
  678. //
  679. // If we have both, we call a routine
  680. // to merge the values
  681. //
  682. if (hkMachine && hkUser) {
  683. Status = BaseRegQueryAndMergeValues(
  684. hkUser,
  685. hkMachine,
  686. val_list,
  687. num_vals,
  688. lpvalueBuf,
  689. ldwTotsize,
  690. ldwRequiredLength);
  691. goto cleanup;
  692. }
  693. //
  694. // We have only one key -- query the one with the
  695. // highest precedence
  696. //
  697. hkQuery = hkUser ? hkUser : hkMachine;
  698. Status = NtQueryMultipleValueKey(hkQuery,
  699. (PKEY_VALUE_ENTRY)val_list,
  700. num_vals,
  701. lpvalueBuf,
  702. ldwTotsize,
  703. ldwRequiredLength);
  704. cleanup:
  705. //
  706. // Close extra kernel object
  707. //
  708. if (hKey != hkUser) {
  709. NtClose(hkUser);
  710. } else {
  711. NtClose(hkMachine);
  712. }
  713. return Status;
  714. }
  715. NTSTATUS BaseRegQueryAndMergeValues(
  716. HKEY hkUser,
  717. HKEY hkMachine,
  718. PRVALENT val_list,
  719. DWORD num_vals,
  720. LPSTR lpvalueBuf,
  721. LPDWORD ldwTotsize,
  722. PULONG ldwRequiredLength)
  723. /*++
  724. Routine Description:
  725. Gets the value state for a particular key and optimizes
  726. it for a given index
  727. Arguments:
  728. hkUser - user key to query for values
  729. hkMachine - machine key to query for values
  730. val_list - Supplies a pointer to an array of RVALENT structures, one for
  731. each value to be queried.
  732. num_vals - Supplies the size in bytes of the val_list array.
  733. lpValueBuf - Returns the data for each value
  734. ldwTotsize - Supplies the length of lpValueBuf. Returns the number of bytes
  735. written into lpValueBuf.
  736. ldwRequiredLength - If lpValueBuf is not large enough to
  737. contain all the data, returns the size of lpValueBuf required
  738. to return all the requested data.
  739. Return Value:
  740. STATUS_SUCCESS for success, error code otherwise.
  741. Notes:
  742. ATTENTION: this is non-atomic, unlike the regular RegQueryMultipleValues
  743. call. In the future, implementing this in the kernel would make this
  744. atomic again.
  745. --*/
  746. {
  747. NTSTATUS Status;
  748. DWORD dwVal;
  749. BOOL fOverflow;
  750. DWORD dwBufferLength;
  751. DWORD dwRequired;
  752. DWORD dwKeyInfoLength;
  753. DWORD dwBufferUsed;
  754. PKEY_VALUE_PARTIAL_INFORMATION pKeyInfo;
  755. //
  756. // Initialize locals
  757. //
  758. dwBufferLength = *ldwTotsize;
  759. dwRequired = 0;
  760. dwBufferUsed = 0;
  761. fOverflow = FALSE;
  762. //
  763. // Validate out params -- we assume that ldwTotsize and
  764. // ldwRequiredLength were given to us by winreg client,
  765. // so they should be safe to read / write from. lpValueBuf
  766. // comes from the caller of the win32 api, so we need to
  767. // validate it -- in previous versions of NT, this parameter
  768. // went straight to the kernel, which did the validation and
  769. // returned an error if it was pointing to inaccessible memory.
  770. // Since we're accessing it here in user mode, we need to do
  771. // our own validation
  772. //
  773. if (IsBadWritePtr( lpvalueBuf, dwBufferLength))
  774. {
  775. return STATUS_ACCESS_VIOLATION;
  776. }
  777. //
  778. // First, we need to allocate enough memory to retrieve
  779. // all the values -- we can't just use lpvalueBuf
  780. // because it doesn't include the overhead of the
  781. // KEY_VALUE_PARTIAL_INFORMATION structure. If we allocate
  782. // for the size of lpvalueBuf + the structure overhead,
  783. // we will always have enough for our queries.
  784. //
  785. dwKeyInfoLength = sizeof(*pKeyInfo) * num_vals + *ldwTotsize;
  786. pKeyInfo = (PKEY_VALUE_PARTIAL_INFORMATION)
  787. RegClassHeapAlloc( dwKeyInfoLength);
  788. if (!pKeyInfo) {
  789. return STATUS_NO_MEMORY;
  790. }
  791. //
  792. // For each value requested by the caller, try
  793. // to retrieve it from user or machine
  794. //
  795. for (dwVal = 0; dwVal < num_vals; dwVal++)
  796. {
  797. DWORD dwResultLength;
  798. //
  799. // Round up the used and required lengths to a ULONG boundary --
  800. // this means that the required size returned to the caller of the win32
  801. // api can be an overestimation, as much as 3 bytes per requested value.
  802. // We could do some work to avoid this, but since the kernel returns a rounded
  803. // up value in dwResultLength, the kernel api is itself overestimating, although
  804. // it only overestimates by at most 3 bytes over all the values. We could avoid
  805. // this by allocating enough memory ahead of time to query the largest value, either
  806. // as one large preallocation or continually allocating and reallocating, but this will
  807. // be slower and / or consume more memory
  808. //
  809. dwBufferUsed = (dwBufferUsed + sizeof(ULONG)-1) & ~(sizeof(ULONG)-1);
  810. dwRequired = (dwRequired + sizeof(ULONG)-1) & ~(sizeof(ULONG)-1);
  811. //
  812. // Query the user key first since it has highest precedence
  813. //
  814. Status = NtQueryValueKey(
  815. hkUser,
  816. val_list[dwVal].rv_valuename,
  817. KeyValuePartialInformation,
  818. pKeyInfo,
  819. dwKeyInfoLength,
  820. &dwResultLength);
  821. //
  822. // Check for errors -- if the value didn't exist, we'll look
  823. // in machine -- for buffer overflow, we'll proceed as if
  824. // this succeeded so that we can calculate the required
  825. // buffer size
  826. //
  827. if (!NT_SUCCESS(Status) &&
  828. (STATUS_BUFFER_OVERFLOW != Status)) {
  829. if (STATUS_OBJECT_NAME_NOT_FOUND != Status) {
  830. goto cleanup;
  831. }
  832. //
  833. // If there is no user value, query the machine key
  834. //
  835. Status = NtQueryValueKey(
  836. hkMachine,
  837. val_list[dwVal].rv_valuename,
  838. KeyValuePartialInformation,
  839. pKeyInfo,
  840. dwKeyInfoLength,
  841. &dwResultLength);
  842. //
  843. // Similar error handling to above -- if we don't have enough
  844. // buffer, pretend we've succeeded so we can calc the required size
  845. //
  846. if (!NT_SUCCESS(Status) &&
  847. (STATUS_BUFFER_OVERFLOW != Status)) {
  848. goto cleanup;
  849. }
  850. }
  851. ASSERT(NT_SUCCESS(Status) || (STATUS_BUFFER_OVERFLOW == Status));
  852. if (NT_SUCCESS(Status)) {
  853. dwResultLength = pKeyInfo->DataLength;
  854. }
  855. //
  856. // Check for buffer overflow
  857. //
  858. if ( ( (dwBufferUsed + pKeyInfo->DataLength) <= dwBufferLength) && !fOverflow) {
  859. ASSERT(NT_SUCCESS(Status));
  860. //
  861. // Copy the data to the fixed part of the client's structure
  862. //
  863. val_list[dwVal].rv_valuelen = dwResultLength;
  864. val_list[dwVal].rv_valueptr = dwRequired;
  865. val_list[dwVal].rv_type = pKeyInfo->Type;
  866. //
  867. // We didn't overflow, so we still have enough room to copy
  868. // the latest value
  869. //
  870. RtlCopyMemory(
  871. (BYTE*)lpvalueBuf + val_list[dwVal].rv_valueptr,
  872. &(pKeyInfo->Data),
  873. dwResultLength);
  874. dwBufferUsed += pKeyInfo->DataLength;
  875. } else {
  876. //
  877. // We're out of buffer -- set this flag to
  878. // signal this state
  879. //
  880. fOverflow = TRUE;
  881. }
  882. //
  883. // Update our required length with the size
  884. // of the data from the current value
  885. //
  886. dwRequired += dwResultLength;
  887. }
  888. //
  889. // At this point, we've succeeded in the sense that
  890. // we've copied all the data or we couldn't due to
  891. // insufficient buffer but we were able to calculate
  892. // the required size
  893. //
  894. Status = STATUS_SUCCESS;
  895. cleanup:
  896. //
  897. // Free the allocated memory
  898. //
  899. RegClassHeapFree(pKeyInfo);
  900. //
  901. // If we succeeded, this means we've either copied
  902. // the data or overflowed and copied the size -- handle
  903. // both below
  904. //
  905. if (NT_SUCCESS(Status)) {
  906. //
  907. // Always set this so the caller knows how much
  908. // was copied or needs to be allocated
  909. //
  910. *ldwRequiredLength = dwRequired;
  911. //
  912. // Return the appropriate error if we overflowed
  913. //
  914. if (fOverflow) {
  915. return STATUS_BUFFER_OVERFLOW;
  916. }
  917. //
  918. // Setting this, although winreg client actually
  919. // ignores this quantity
  920. //
  921. *ldwTotsize = dwBufferUsed;
  922. }
  923. return Status;
  924. }
  925. #endif LOCAL