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.

1509 lines
39 KiB

  1. /*++
  2. Copyright (c) 1999 Microsoft Corporation
  3. Module Name:
  4. cmvalue.c
  5. Abstract:
  6. This module contains cm routines for operating on (sorted)
  7. value list. Insertion, Deletion,Searching ...
  8. Routines to deal with a KeyValue data; whether it is small,
  9. big - new hives format - , or normal
  10. Author:
  11. Dragos C. Sambotin (dragoss) 12-Aug-1999
  12. Revision History:
  13. --*/
  14. #include "cmp.h"
  15. #ifdef ALLOC_PRAGMA
  16. #pragma alloc_text(PAGE,CmpFindValueByName)
  17. #pragma alloc_text(PAGE,CmpFindNameInList)
  18. #pragma alloc_text(PAGE,CmpAddValueToList)
  19. #pragma alloc_text(PAGE,CmpRemoveValueFromList)
  20. #pragma alloc_text(PAGE,CmpGetValueData)
  21. #pragma alloc_text(PAGE,CmpMarkValueDataDirty)
  22. #pragma alloc_text(PAGE,CmpFreeValue)
  23. #pragma alloc_text(PAGE,CmpSetValueDataNew)
  24. #pragma alloc_text(PAGE,CmpSetValueDataExisting)
  25. #pragma alloc_text(PAGE,CmpFreeValueData)
  26. #pragma alloc_text(PAGE,CmpValueToData)
  27. #endif
  28. HCELL_INDEX
  29. CmpFindValueByName(
  30. PHHIVE Hive,
  31. PCM_KEY_NODE KeyNode,
  32. PUNICODE_STRING Name
  33. )
  34. /*++
  35. Routine Description:
  36. Underlying CmpFindNameInList was changed to return an error code;
  37. Had to make it a function instead of a macro
  38. Arguments:
  39. Hive - pointer to hive control structure for hive of interest
  40. Return Value:
  41. HCELL_INDEX or HCELL_NIL on error
  42. --*/
  43. {
  44. HCELL_INDEX CellIndex;
  45. #ifndef _CM_LDR_
  46. PAGED_CODE();
  47. #endif //_CM_LDR_
  48. if( CmpFindNameInList(Hive,&((KeyNode)->ValueList),Name,NULL,&CellIndex) == FALSE ) {
  49. //
  50. // above should set this right
  51. //
  52. ASSERT( CellIndex == HCELL_NIL );
  53. }
  54. return CellIndex;
  55. }
  56. BOOLEAN
  57. CmpFindNameInList(
  58. IN PHHIVE Hive,
  59. IN PCHILD_LIST ChildList,
  60. IN PUNICODE_STRING Name,
  61. IN OPTIONAL PULONG ChildIndex,
  62. OUT PHCELL_INDEX CellIndex
  63. )
  64. /*++
  65. Routine Description:
  66. Find a child object in an object list. Child List must be sorted
  67. based on the name. (for new hives format)
  68. Arguments:
  69. Hive - pointer to hive control structure for hive of interest
  70. List - pointer to mapped in list structure
  71. Count - number of elements in list structure
  72. Name - name of child object to find
  73. ChildIndex - pointer to variable to receive index for child;
  74. CellIndex - pointer to receive the index of the child.
  75. On return, this is:
  76. HCELL_INDEX for the found cell
  77. HCELL_NIL if not found
  78. Return Value:
  79. TRUE - success
  80. FALSE - error, insufficient resources
  81. Notes:
  82. ChildIndex is always filled with the position where Name should be in the list.
  83. The difference whether Name is in the list or not is made upon CellIndex
  84. - CellIndex == HCELL_NIL ==> Name not found in the list
  85. - CellIndex <> HCELL_NIL ==> Name already exists in the list
  86. --*/
  87. {
  88. NTSTATUS status;
  89. PCM_KEY_VALUE pchild;
  90. UNICODE_STRING Candidate;
  91. LONG Result;
  92. PCELL_DATA List = NULL;
  93. ULONG Current;
  94. HCELL_INDEX CellToRelease = HCELL_NIL;
  95. BOOLEAN ReturnValue = FALSE;
  96. #ifndef _CM_LDR_
  97. PAGED_CODE();
  98. #endif //_CM_LDR_
  99. if (ChildList->Count != 0) {
  100. List = (PCELL_DATA)HvGetCell(Hive,ChildList->List);
  101. if( List == NULL ) {
  102. //
  103. // we could not map the view containing the cell
  104. //
  105. *CellIndex = HCELL_NIL;
  106. return FALSE;
  107. }
  108. //
  109. // old plain hive; simulate a for
  110. //
  111. Current = 0;
  112. while( TRUE ) {
  113. if( CellToRelease != HCELL_NIL ) {
  114. HvReleaseCell(Hive,CellToRelease);
  115. CellToRelease = HCELL_NIL;
  116. }
  117. pchild = (PCM_KEY_VALUE)HvGetCell(Hive, List->u.KeyList[Current]);
  118. if( pchild == NULL ) {
  119. //
  120. // we could not map the view containing the cell
  121. //
  122. *CellIndex = HCELL_NIL;
  123. ReturnValue = FALSE;
  124. goto JustReturn;
  125. }
  126. CellToRelease = List->u.KeyList[Current];
  127. if (pchild->Flags & VALUE_COMP_NAME) {
  128. Result = CmpCompareCompressedName(Name,
  129. pchild->Name,
  130. pchild->NameLength,
  131. 0);
  132. } else {
  133. Candidate.Length = pchild->NameLength;
  134. Candidate.MaximumLength = Candidate.Length;
  135. Candidate.Buffer = pchild->Name;
  136. Result = RtlCompareUnicodeString(Name,
  137. &Candidate,
  138. TRUE);
  139. }
  140. if (Result == 0) {
  141. //
  142. // Success, return data to caller and exit
  143. //
  144. if (ARGUMENT_PRESENT(ChildIndex)) {
  145. *ChildIndex = Current;
  146. }
  147. *CellIndex = List->u.KeyList[Current];
  148. ReturnValue = TRUE;
  149. goto JustReturn;
  150. }
  151. //
  152. // compute the next index to try: old'n plain hive; go on
  153. //
  154. Current++;
  155. if( Current == ChildList->Count ) {
  156. //
  157. // we've reached the end of the list
  158. //
  159. if (ARGUMENT_PRESENT(ChildIndex)) {
  160. *ChildIndex = Current;
  161. }
  162. //
  163. // nicely return
  164. //
  165. *CellIndex = HCELL_NIL;
  166. ReturnValue = TRUE;
  167. goto JustReturn;
  168. }
  169. }
  170. }
  171. //
  172. // in the new design we shouldn't get here; we should exit the while loop with return
  173. //
  174. ASSERT( ChildList->Count == 0 );
  175. // add it first; as it's the only one
  176. if (ARGUMENT_PRESENT(ChildIndex)) {
  177. *ChildIndex = 0;
  178. }
  179. *CellIndex = HCELL_NIL;
  180. return TRUE;
  181. JustReturn:
  182. if( List != NULL ) {
  183. HvReleaseCell(Hive,ChildList->List);
  184. }
  185. if( CellToRelease != HCELL_NIL ) {
  186. HvReleaseCell(Hive,CellToRelease);
  187. }
  188. return ReturnValue;
  189. }
  190. BOOLEAN
  191. CmpGetValueData(IN PHHIVE Hive,
  192. IN PCM_KEY_VALUE Value,
  193. OUT PULONG realsize,
  194. IN OUT PVOID *Buffer,
  195. OUT PBOOLEAN Allocated,
  196. OUT PHCELL_INDEX CellToRelease
  197. )
  198. /*++
  199. Routine Description:
  200. Retrieves the real valueData, given the key value.
  201. Arguments:
  202. Hive - pointer to hive control structure for hive of interest
  203. Value - CM_KEY_VALUE to retrieve the data for.
  204. realsize - the actual size of the data (in bytes)
  205. Buffer - pointer to the data; if the cell is a BIG_CELL
  206. we should allocate a buffer
  207. Allocated - here we signal the caller that he has to free the
  208. buffer on return;
  209. TRUE - a new buffer was allocated to gather together the BIG_CELL data
  210. FALSE - Buffer points directly in the hive, the caller shouldn't free it
  211. CellToRelease - Cell to release after finishing work with Buffer
  212. Return Value:
  213. TRUE - success
  214. FALSE - not enough resources available; (to map a cell or to allocate the buffer)
  215. Notes:
  216. The caller is responsible to remove the buffer, when Allocated is set on TRUE on return;
  217. --*/
  218. {
  219. #ifndef _CM_LDR_
  220. PAGED_CODE();
  221. #endif //_CM_LDR_
  222. ASSERT_KEY_VALUE(Value);
  223. //
  224. // normally we don't allocate buffer
  225. //
  226. *Allocated = FALSE;
  227. *Buffer = NULL;
  228. *CellToRelease = HCELL_NIL;
  229. //
  230. // check for small values
  231. //
  232. if( CmpIsHKeyValueSmall(*realsize, Value->DataLength) == TRUE ) {
  233. //
  234. // data is stored inside the cell
  235. //
  236. *Buffer = &Value->Data;
  237. return TRUE;
  238. }
  239. #ifndef _CM_LDR_
  240. //
  241. // check for big values
  242. //
  243. if( CmpIsHKeyValueBig(Hive,*realsize) == TRUE ) {
  244. //
  245. //
  246. //
  247. PCM_BIG_DATA BigData = NULL;
  248. PUCHAR WorkBuffer;
  249. ULONG Length;
  250. USHORT i;
  251. PUCHAR PartialData;
  252. PHCELL_INDEX Plist = NULL;
  253. #ifndef _CM_LDR_
  254. try {
  255. #endif //_CM_LDR_
  256. BigData = (PCM_BIG_DATA)HvGetCell(Hive,Value->Data);
  257. if( BigData == NULL ) {
  258. //
  259. // cannot map view containing the cell; bail out
  260. //
  261. return FALSE;
  262. }
  263. ASSERT_BIG_DATA(BigData);
  264. Plist = (PHCELL_INDEX)HvGetCell(Hive,BigData->List);
  265. if( Plist == NULL ) {
  266. //
  267. // cannot map view containing the cell; bail out
  268. //
  269. return FALSE;
  270. }
  271. Length = Value->DataLength;
  272. //
  273. // sanity check
  274. //
  275. ASSERT( Length <= (ULONG)(BigData->Count * CM_KEY_VALUE_BIG) );
  276. //
  277. // allocate a buffer to merge bring all the pieces together
  278. //
  279. WorkBuffer = (PUCHAR)ExAllocatePoolWithTag(PagedPool, Length, CM_POOL_TAG);
  280. if( WorkBuffer == NULL ){
  281. return FALSE;
  282. }
  283. for(i=0;i<BigData->Count;i++) {
  284. //
  285. // sanity check
  286. //
  287. ASSERT( Length > 0 );
  288. PartialData = (PUCHAR)HvGetCell(Hive,Plist[i]);
  289. if( PartialData == NULL ){
  290. //
  291. // cannot map view containing the cell; bail out
  292. //
  293. ExFreePool(WorkBuffer);
  294. return FALSE;
  295. }
  296. //
  297. // copy this piece of data to the work buffer
  298. //
  299. RtlCopyMemory(WorkBuffer + CM_KEY_VALUE_BIG*i,PartialData,(Length>CM_KEY_VALUE_BIG)?CM_KEY_VALUE_BIG:Length);
  300. HvReleaseCell(Hive,Plist[i]);
  301. //
  302. // adjust the data still to copy.
  303. // All cells in Plist should be of size CM_KEY_VALUE_BIG, except the last one, which is the remaining
  304. //
  305. Length -= CM_KEY_VALUE_BIG;
  306. }
  307. #ifndef _CM_LDR_
  308. } finally {
  309. if( BigData != NULL ) {
  310. HvReleaseCell(Hive,Value->Data);
  311. if( Plist != NULL ) {
  312. HvReleaseCell(Hive,BigData->List);
  313. }
  314. }
  315. }
  316. #endif //_CM_LDR_
  317. //
  318. // if we are here; we successfuly have copied all data into WorkBuffer.
  319. // update the return buffer and return; Caller is responsible to free the return buffer
  320. // We signal the caller by setting Allocated on TRUE
  321. //
  322. *Buffer = WorkBuffer;
  323. *Allocated = TRUE;
  324. return TRUE;
  325. }
  326. #endif //_CM_LDR_
  327. //
  328. // normal, old plain case
  329. //
  330. *Buffer = HvGetCell(Hive,Value->Data);
  331. if( *Buffer == NULL ) {
  332. //
  333. // insufficient resources to map the view containing this cell
  334. //
  335. return FALSE;
  336. }
  337. //
  338. // signal to the caller to release this cell after finishing with buffer
  339. //
  340. *CellToRelease = Value->Data;
  341. return TRUE;
  342. }
  343. PCELL_DATA
  344. CmpValueToData(IN PHHIVE Hive,
  345. IN PCM_KEY_VALUE Value,
  346. OUT PULONG realsize
  347. )
  348. /*++
  349. Routine Description:
  350. Retrieves the real valueData, given the key value.
  351. Arguments:
  352. Hive - pointer to hive control structure for hive of interest
  353. Value - CM_KEY_VALUE to retrieve the data for.
  354. realsize - the actual size of the data (in bytes)
  355. Return Value:
  356. pointer to the value data; NULL if any error (insuficient resources)
  357. Notes:
  358. This function doesn't support big cells; It is intended to be called just
  359. by the loader, which doesn't store large data. It'll bugcheck if big cell
  360. is queried.
  361. --*/
  362. {
  363. PCELL_DATA Buffer;
  364. BOOLEAN BufferAllocated;
  365. HCELL_INDEX CellToRelease;
  366. #ifndef _CM_LDR_
  367. PAGED_CODE();
  368. #endif //_CM_LDR_
  369. ASSERT( Hive->ReleaseCellRoutine == NULL );
  370. if( CmpGetValueData(Hive,Value,realsize,&Buffer,&BufferAllocated,&CellToRelease) == FALSE ) {
  371. //
  372. // insufficient resources; return NULL
  373. //
  374. ASSERT( BufferAllocated == FALSE );
  375. ASSERT( Buffer == NULL );
  376. return NULL;
  377. }
  378. //
  379. // we specificallly ignore CellToRelease as this is not a mapped view
  380. //
  381. if( BufferAllocated == TRUE ) {
  382. //
  383. // this function is not intended for big cells;
  384. //
  385. #ifndef _CM_LDR_
  386. ExFreePool( Buffer );
  387. #endif //_CM_LDR_
  388. CM_BUGCHECK( REGISTRY_ERROR,BIG_CELL_ERROR,0,Hive,Value);
  389. return NULL;
  390. }
  391. //
  392. // success
  393. //
  394. return Buffer;
  395. }
  396. #ifndef _CM_LDR_
  397. NTSTATUS
  398. CmpAddValueToList(
  399. IN PHHIVE Hive,
  400. IN HCELL_INDEX ValueCell,
  401. IN ULONG Index,
  402. IN ULONG Type,
  403. IN OUT PCHILD_LIST ChildList
  404. )
  405. /*++
  406. Routine Description:
  407. Adds a value to the value list, keeping the list sorted
  408. (for new hives format)
  409. Arguments:
  410. Hive - pointer to hive control structure for hive of interest
  411. ValueCell - value index
  412. Index - index at which to add the value
  413. ChildList - pointer to the list of values
  414. Return Value:
  415. STATUS_SUCCESS - success
  416. STATUS_INSUFFICIENT_RESOURCES - an error occured
  417. --*/
  418. {
  419. HCELL_INDEX NewCell;
  420. ULONG count;
  421. ULONG AllocateSize;
  422. ULONG i;
  423. PCELL_DATA pdata;
  424. PAGED_CODE();
  425. //
  426. // we have the lock exclusive or nobody is operating inside this hive
  427. //
  428. //ASSERT_CM_LOCK_OWNED_EXCLUSIVE();
  429. ASSERT_CM_EXCLUSIVE_HIVE_ACCESS(Hive);
  430. //
  431. // sanity check for index range
  432. //
  433. ASSERT( (((LONG)Index) >= 0) && (Index <= ChildList->Count) );
  434. count = ChildList->Count;
  435. count++;
  436. if (count > 1) {
  437. ASSERT_CELL_DIRTY(Hive,ChildList->List);
  438. if (count < CM_MAX_REASONABLE_VALUES) {
  439. //
  440. // A reasonable number of values, allocate just enough
  441. // space.
  442. //
  443. AllocateSize = count * sizeof(HCELL_INDEX);
  444. } else {
  445. //
  446. // An excessive number of values, pad the allocation out
  447. // to avoid fragmentation. (if there's this many values,
  448. // there'll probably be more pretty soon)
  449. //
  450. AllocateSize = ROUND_UP(count, CM_MAX_REASONABLE_VALUES) * sizeof(HCELL_INDEX);
  451. if (AllocateSize > HBLOCK_SIZE) {
  452. AllocateSize = ROUND_UP(AllocateSize, HBLOCK_SIZE);
  453. }
  454. }
  455. NewCell = HvReallocateCell(
  456. Hive,
  457. ChildList->List,
  458. AllocateSize
  459. );
  460. } else {
  461. NewCell = HvAllocateCell(Hive, sizeof(HCELL_INDEX), Type,ValueCell);
  462. }
  463. //
  464. // put ourselves on the list
  465. //
  466. if (NewCell != HCELL_NIL) {
  467. // sanity
  468. ChildList->List = NewCell;
  469. pdata = HvGetCell(Hive, NewCell);
  470. if( pdata == NULL ) {
  471. //
  472. // we couldn't map a view for the bin containing this cell
  473. //
  474. //
  475. // normally this shouldn't happen as we just allocated ValueCell
  476. // i.e. the bin containing NewCell should be mapped in memory at this point.
  477. //
  478. ASSERT( FALSE );
  479. return STATUS_INSUFFICIENT_RESOURCES;
  480. }
  481. //
  482. // make room for the new cell; move values in the reverse order !
  483. // adding at the end makes this a nop
  484. //
  485. for( i = count - 1; i > Index; i-- ) {
  486. pdata->u.KeyList[i] = pdata->u.KeyList[i-1];
  487. }
  488. pdata->u.KeyList[Index] = ValueCell;
  489. ChildList->Count = count;
  490. HvReleaseCell(Hive,NewCell);
  491. // sanity
  492. ASSERT_CELL_DIRTY(Hive,ValueCell);
  493. } else {
  494. return STATUS_INSUFFICIENT_RESOURCES;
  495. }
  496. return STATUS_SUCCESS;
  497. }
  498. NTSTATUS
  499. CmpRemoveValueFromList(
  500. IN PHHIVE Hive,
  501. IN ULONG Index,
  502. IN OUT PCHILD_LIST ChildList
  503. )
  504. /*++
  505. Routine Description:
  506. Removes the value at the specified index from the value list
  507. Arguments:
  508. Hive - pointer to hive control structure for hive of interest
  509. Index - index at which to add the value
  510. ChildList - pointer to the list of values
  511. Return Value:
  512. STATUS_SUCCESS - success
  513. STATUS_INSUFFICIENT_RESOURCES - an error occured
  514. Notes:
  515. The caller is responsible for freeing the removed value
  516. --*/
  517. {
  518. ULONG newcount;
  519. HCELL_INDEX newcell;
  520. PAGED_CODE();
  521. ASSERT_CM_LOCK_OWNED_EXCLUSIVE();
  522. //
  523. // sanity check for index range
  524. //
  525. ASSERT( (((LONG)Index) >= 0) && (Index <= ChildList->Count) );
  526. newcount = ChildList->Count - 1;
  527. if (newcount > 0) {
  528. PCELL_DATA pvector;
  529. //
  530. // more than one entry list, squeeze
  531. //
  532. pvector = HvGetCell(Hive, ChildList->List);
  533. if( pvector == NULL ) {
  534. //
  535. // we couldn't map a view for the bin containing this cell
  536. //
  537. return STATUS_INSUFFICIENT_RESOURCES;
  538. }
  539. // release the cell here as the reglock is held exclusive
  540. HvReleaseCell(Hive,ChildList->List);
  541. // sanity
  542. ASSERT_CELL_DIRTY(Hive,ChildList->List);
  543. ASSERT_CELL_DIRTY(Hive,pvector->u.KeyList[Index]);
  544. for ( ; Index < newcount; Index++) {
  545. pvector->u.KeyList[ Index ] = pvector->u.KeyList[ Index + 1 ];
  546. }
  547. newcell = HvReallocateCell(
  548. Hive,
  549. ChildList->List,
  550. newcount * sizeof(HCELL_INDEX)
  551. );
  552. ASSERT(newcell != HCELL_NIL);
  553. ChildList->List = newcell;
  554. } else {
  555. //
  556. // list is empty, free it
  557. //
  558. HvFreeCell(Hive, ChildList->List);
  559. ChildList->List = HCELL_NIL;
  560. }
  561. ChildList->Count = newcount;
  562. return STATUS_SUCCESS;
  563. }
  564. BOOLEAN
  565. CmpMarkValueDataDirty( IN PHHIVE Hive,
  566. IN PCM_KEY_VALUE Value
  567. )
  568. /*++
  569. Routine Description:
  570. Marks the cell(s) storing the value data as dirty;
  571. Knows how to deal with bigcells
  572. Arguments:
  573. Hive - pointer to hive control structure for hive of interest
  574. Value - CM_KEY_VALUE to retrieve the data for.
  575. Return Value:
  576. TRUE - success
  577. FALSE - failure to mark all the cells involved;
  578. --*/
  579. {
  580. ULONG realsize;
  581. PAGED_CODE();
  582. //
  583. // we have the lock exclusive or nobody is operating inside this hive
  584. //
  585. //ASSERT_CM_LOCK_OWNED_EXCLUSIVE();
  586. ASSERT_CM_EXCLUSIVE_HIVE_ACCESS(Hive);
  587. ASSERT_KEY_VALUE(Value);
  588. if( Value->Data != HCELL_NIL ) {
  589. //
  590. // Could be that value was just partially initialized (CmpSetValueKeyNew case)
  591. //
  592. //
  593. // check for small values
  594. //
  595. if( CmpIsHKeyValueSmall(realsize, Value->DataLength) == TRUE ) {
  596. //
  597. // data is stored inside the cell
  598. //
  599. return TRUE;
  600. }
  601. //
  602. // check for big values
  603. //
  604. if( CmpIsHKeyValueBig(Hive,realsize) == TRUE ) {
  605. //
  606. //
  607. //
  608. PCM_BIG_DATA BigData;
  609. PHCELL_INDEX Plist;
  610. USHORT i;
  611. BigData = (PCM_BIG_DATA)HvGetCell(Hive,Value->Data);
  612. if( BigData == NULL ) {
  613. //
  614. // cannot map view containing the cell; bail out
  615. //
  616. return FALSE;
  617. }
  618. ASSERT_BIG_DATA(BigData);
  619. if( BigData->List != HCELL_NIL ) {
  620. Plist = (PHCELL_INDEX)HvGetCell(Hive,BigData->List);
  621. if( Plist == NULL ) {
  622. //
  623. // cannot map view containing the cell; bail out
  624. //
  625. HvReleaseCell(Hive,Value->Data);
  626. return FALSE;
  627. }
  628. for(i=0;i<BigData->Count;i++) {
  629. //
  630. // mark this chunk dirty
  631. //
  632. if( Plist[i] != HCELL_NIL ) {
  633. if (! HvMarkCellDirty(Hive, Plist[i])) {
  634. HvReleaseCell(Hive,Value->Data);
  635. HvReleaseCell(Hive,BigData->List);
  636. return FALSE;
  637. }
  638. }
  639. }
  640. //
  641. // mark the list as dirty
  642. //
  643. if (! HvMarkCellDirty(Hive, BigData->List)) {
  644. HvReleaseCell(Hive,Value->Data);
  645. HvReleaseCell(Hive,BigData->List);
  646. return FALSE;
  647. }
  648. //
  649. // we can safely remove it here as it is now dirty/pinned
  650. //
  651. HvReleaseCell(Hive,BigData->List);
  652. }
  653. //
  654. // we don't need this cell anymore
  655. //
  656. HvReleaseCell(Hive,Value->Data);
  657. //
  658. // fall through to mark the cell itself as dirty
  659. //
  660. }
  661. //
  662. // Data is a HCELL_INDEX; mark it dirty
  663. //
  664. if (! HvMarkCellDirty(Hive, Value->Data)) {
  665. return FALSE;
  666. }
  667. }
  668. return TRUE;
  669. }
  670. BOOLEAN
  671. CmpFreeValueData(
  672. PHHIVE Hive,
  673. HCELL_INDEX DataCell,
  674. ULONG DataLength
  675. )
  676. /*++
  677. Routine Description:
  678. Free the Value Data DataCell carries with.
  679. Arguments:
  680. Hive - supplies a pointer to the hive control structure for the hive
  681. DataCell - supplies index of value who's data to free
  682. DataLength - length of the data; used to detect the type of the cell
  683. Return Value:
  684. TRUE: Success
  685. FALSE: Error
  686. Notes:
  687. Knows how to deal with big cell(s)
  688. --*/
  689. {
  690. ULONG realsize;
  691. PAGED_CODE();
  692. ASSERT_CM_LOCK_OWNED_EXCLUSIVE();
  693. //
  694. // check for small values
  695. //
  696. if( CmpIsHKeyValueSmall(realsize, DataLength) == TRUE ) {
  697. //
  698. // data is stored inside the cell; this is a nop
  699. //
  700. } else {
  701. //
  702. // Could be that value was just partially initialized (CmpSetValueKeyNew case)
  703. //
  704. if( DataCell == HCELL_NIL ) {
  705. return TRUE;
  706. }
  707. ASSERT(HvIsCellAllocated(Hive,DataCell));
  708. //
  709. // check for big values
  710. //
  711. if( CmpIsHKeyValueBig(Hive,realsize) == TRUE ) {
  712. //
  713. //
  714. //
  715. PCM_BIG_DATA BigData;
  716. PHCELL_INDEX Plist;
  717. USHORT i;
  718. BigData = (PCM_BIG_DATA)HvGetCell(Hive,DataCell);
  719. if( BigData == NULL ) {
  720. //
  721. // cannot map view containing the cell; bail out
  722. //
  723. // This shouldn't happen as this cell is marked ditry by
  724. // this time (i.e. its view is pinned in memory)
  725. //
  726. ASSERT( FALSE );
  727. return FALSE;
  728. }
  729. // release the cell here as the reglock is held exclusive
  730. HvReleaseCell(Hive,DataCell);
  731. ASSERT_BIG_DATA(BigData);
  732. if( BigData->List != HCELL_NIL ) {
  733. Plist = (PHCELL_INDEX)HvGetCell(Hive,BigData->List);
  734. if( Plist == NULL ) {
  735. //
  736. // cannot map view containing the cell; bail out
  737. //
  738. //
  739. // This shouldn't happen as this cell is marked ditry by
  740. // this time (i.e. its view is pinned in memory)
  741. //
  742. ASSERT( FALSE );
  743. return FALSE;
  744. }
  745. // release the cell here as the reglock is held exclusive
  746. HvReleaseCell(Hive,BigData->List);
  747. for(i=0;i<BigData->Count;i++) {
  748. //
  749. // mark this chunk dirty
  750. //
  751. if( Plist[i] != HCELL_NIL ) {
  752. HvFreeCell(Hive, Plist[i]);
  753. }
  754. }
  755. //
  756. // mark the list as dirty
  757. //
  758. HvFreeCell(Hive, BigData->List);
  759. }
  760. //
  761. // fall through to free the cell data itself
  762. //
  763. }
  764. //
  765. // normal case free the Data cell
  766. //
  767. HvFreeCell(Hive, DataCell);
  768. }
  769. return TRUE;
  770. }
  771. BOOLEAN
  772. CmpFreeValue(
  773. PHHIVE Hive,
  774. HCELL_INDEX Cell
  775. )
  776. /*++
  777. Routine Description:
  778. Free the value entry Hive.Cell refers to, including
  779. its name and data cells.
  780. Arguments:
  781. Hive - supplies a pointer to the hive control structure for the hive
  782. Cell - supplies index of value to delete
  783. Return Value:
  784. TRUE: Success
  785. FALSE: Error
  786. --*/
  787. {
  788. PCM_KEY_VALUE Value;
  789. ULONG realsize;
  790. PAGED_CODE();
  791. ASSERT_CM_LOCK_OWNED_EXCLUSIVE();
  792. //
  793. // map in the cell
  794. //
  795. Value = (PCM_KEY_VALUE)HvGetCell(Hive, Cell);
  796. if( Value == NULL ) {
  797. //
  798. // we couldn't map the bin containing this cell
  799. // sorry we cannot free value
  800. //
  801. // This shouldn't happen as the value is marked ditry by
  802. // this time (i.e. its view is pinned in memory)
  803. //
  804. ASSERT( FALSE );
  805. return FALSE;
  806. }
  807. // release the cell here as the reglock is held exclusive
  808. HvReleaseCell(Hive,Cell);
  809. if( CmpFreeValueData(Hive,Value->Data,Value->DataLength) == FALSE ) {
  810. return FALSE;
  811. }
  812. //
  813. // free the cell itself
  814. //
  815. HvFreeCell(Hive, Cell);
  816. return TRUE;
  817. }
  818. NTSTATUS
  819. CmpSetValueDataNew(
  820. IN PHHIVE Hive,
  821. IN PVOID Data,
  822. IN ULONG DataSize,
  823. IN ULONG StorageType,
  824. IN HCELL_INDEX ValueCell,
  825. OUT PHCELL_INDEX DataCell
  826. )
  827. /*++
  828. Routine Description:
  829. Allocates a new cell (or big data cell) to accomodate DataSize;
  830. Initialize and copy information from Data to the new cell;
  831. Arguments:
  832. Hive - supplies a pointer to the hive control structure for the hive
  833. Data - data buffer (possibly from user-mode)
  834. DataSize - size of the buffer
  835. StorageType - Stable or Volatile
  836. ValueCell - The value setting the data for (locality purposes).
  837. DataCell - return value:HCELL_INDEX of the new cell; HCELL_NIL on some error
  838. Return Value:
  839. Status of the operation (STATUS_SUCCESS or the exception code - if any)
  840. Notes:
  841. Knows how to deal with big cell(s)
  842. Data buffer comes from user mode, so it should be guarded by a try-except
  843. --*/
  844. {
  845. PCELL_DATA pdata;
  846. PAGED_CODE();
  847. ASSERT_CM_EXCLUSIVE_HIVE_ACCESS(Hive);
  848. //
  849. // bogus args; we don't deal with small values here!
  850. //
  851. ASSERT(DataSize > CM_KEY_VALUE_SMALL);
  852. if( CmpIsHKeyValueBig(Hive,DataSize) == TRUE ) {
  853. //
  854. // request for a big data value
  855. //
  856. PCM_BIG_DATA BigData = NULL;
  857. USHORT Count;
  858. PHCELL_INDEX Plist = NULL;
  859. NTSTATUS status = STATUS_INSUFFICIENT_RESOURCES;
  860. //
  861. // allocate the embedding cell
  862. //
  863. *DataCell = HvAllocateCell(Hive, sizeof(CM_BIG_DATA), StorageType,ValueCell);
  864. if (*DataCell == HCELL_NIL) {
  865. return status;
  866. }
  867. //
  868. // init the BIG_DATA cell
  869. //
  870. BigData = (PCM_BIG_DATA)HvGetCell(Hive,*DataCell);
  871. if( BigData == NULL) {
  872. //
  873. // couldn't map view for this cell
  874. // this shouldn't happen as we just allocated this cell
  875. // (i.e. its view should be pinned in memory)
  876. //
  877. ASSERT( FALSE );
  878. goto Cleanup;
  879. }
  880. // release the cell here as the reglock is held exclusive
  881. HvReleaseCell(Hive,*DataCell);
  882. BigData->Signature = CM_BIG_DATA_SIGNATURE;
  883. BigData->Count = 0;
  884. BigData->List = HCELL_NIL;
  885. //
  886. // Compute the number of cells needed
  887. //
  888. Count = (USHORT)((DataSize + CM_KEY_VALUE_BIG - 1) / CM_KEY_VALUE_BIG);
  889. //
  890. // allocate the embeded list
  891. //
  892. BigData->List = HvAllocateCell(Hive, Count * sizeof(HCELL_INDEX), StorageType,*DataCell);
  893. if( BigData->List == HCELL_NIL ) {
  894. goto Cleanup;
  895. }
  896. Plist = (PHCELL_INDEX)HvGetCell(Hive,BigData->List);
  897. if( Plist == NULL ) {
  898. //
  899. // cannot map view containing the cell; bail out
  900. //
  901. //
  902. // This shouldn't happen as this cell is marked ditry by
  903. // this time (i.e. its view is pinned in memory)
  904. //
  905. ASSERT( FALSE );
  906. goto Cleanup;
  907. }
  908. // release the cell here as the reglock is held exclusive
  909. HvReleaseCell(Hive,BigData->List);
  910. //
  911. // allocate each chunk and copy the data; if we fail part through, we'll free the already allocated values
  912. //
  913. for( ;BigData->Count < Count;(BigData->Count)++) {
  914. //
  915. // allocate this chunk
  916. //
  917. Plist[BigData->Count] = HvAllocateCell(Hive, CM_KEY_VALUE_BIG, StorageType,BigData->List);
  918. if( Plist[BigData->Count] == HCELL_NIL ) {
  919. goto Cleanup;
  920. }
  921. pdata = HvGetCell(Hive,Plist[BigData->Count]);
  922. if( pdata == NULL ) {
  923. //
  924. // cannot map view containing the cell; bail out
  925. //
  926. //
  927. // This shouldn't happen as this cell is marked ditry by
  928. // this time (i.e. its view is pinned in memory)
  929. //
  930. ASSERT( FALSE );
  931. goto Cleanup;
  932. }
  933. // release the cell here as the reglock is held exclusive
  934. HvReleaseCell(Hive,Plist[BigData->Count]);
  935. //
  936. // now, copy this chunk data
  937. //
  938. try {
  939. RtlCopyMemory(pdata, (PUCHAR)Data, (DataSize>CM_KEY_VALUE_BIG)?CM_KEY_VALUE_BIG:DataSize);
  940. } except (EXCEPTION_EXECUTE_HANDLER) {
  941. CmKdPrintEx((DPFLTR_CONFIG_ID,CML_EXCEPTION,"!!CmpSetValueDataNew: code:%08lx\n", GetExceptionCode()));
  942. status = GetExceptionCode();
  943. goto Cleanup;
  944. }
  945. //
  946. // update the data pointer and the remaining size
  947. //
  948. ((PUCHAR)Data) += CM_KEY_VALUE_BIG;
  949. DataSize -= CM_KEY_VALUE_BIG;
  950. }
  951. ASSERT( Count == BigData->Count );
  952. return STATUS_SUCCESS;
  953. Cleanup:
  954. //
  955. // free what we already allocated
  956. //
  957. if( BigData != NULL) {
  958. if( Plist != NULL ) {
  959. for(;BigData->Count;BigData->Count--) {
  960. if( Plist[BigData->Count] != HCELL_NIL ) {
  961. HvFreeCell(Hive, Plist[BigData->Count]);
  962. }
  963. }
  964. } else {
  965. ASSERT( BigData->Count == 0 );
  966. }
  967. if( BigData->List != HCELL_NIL ) {
  968. HvFreeCell(Hive, BigData->List);
  969. }
  970. }
  971. HvFreeCell(Hive, *DataCell);
  972. *DataCell = HCELL_NIL;
  973. return status;
  974. } else {
  975. //
  976. // normal old'n plain value
  977. //
  978. *DataCell = HvAllocateCell(Hive, DataSize, StorageType,ValueCell);
  979. if (*DataCell == HCELL_NIL) {
  980. return STATUS_INSUFFICIENT_RESOURCES;
  981. }
  982. pdata = HvGetCell(Hive, *DataCell);
  983. if( pdata == NULL ) {
  984. //
  985. // we couldn't map a view for the bin containing this cell
  986. //
  987. //
  988. // normally this shouldn't happen as we just allocated ValueCell
  989. // i.e. the bin containing DataCell should be mapped in memory at this point.
  990. //
  991. ASSERT( FALSE );
  992. if (*DataCell != HCELL_NIL) {
  993. HvFreeCell(Hive, *DataCell);
  994. *DataCell = HCELL_NIL;
  995. }
  996. return STATUS_INSUFFICIENT_RESOURCES;
  997. }
  998. // release the cell here as the reglock is held exclusive
  999. HvReleaseCell(Hive,*DataCell);
  1000. //
  1001. // copy the actual data, guarding the buffer as it may be a user-mode buffer
  1002. //
  1003. try {
  1004. RtlCopyMemory(pdata, Data, DataSize);
  1005. } except (EXCEPTION_EXECUTE_HANDLER) {
  1006. CmKdPrintEx((DPFLTR_CONFIG_ID,CML_EXCEPTION,"!!CmpSetValueDataNew: code:%08lx\n", GetExceptionCode()));
  1007. //
  1008. // We have bombed out loading user data, clean up and exit.
  1009. //
  1010. if (*DataCell != HCELL_NIL) {
  1011. HvFreeCell(Hive, *DataCell);
  1012. *DataCell = HCELL_NIL;
  1013. }
  1014. return GetExceptionCode();
  1015. }
  1016. }
  1017. return STATUS_SUCCESS;
  1018. }
  1019. NTSTATUS
  1020. CmpSetValueDataExisting(
  1021. IN PHHIVE Hive,
  1022. IN PVOID Data,
  1023. IN ULONG DataSize,
  1024. IN ULONG StorageType,
  1025. IN HCELL_INDEX OldDataCell
  1026. )
  1027. /*++
  1028. Routine Description:
  1029. Grows an existing big data cell and copies the new data into it.
  1030. Arguments:
  1031. Hive - supplies a pointer to the hive control structure for the hive
  1032. Data - data buffer (possibly from user-mode)
  1033. DataSize - size of the buffer
  1034. StorageType - Stable or Volatile
  1035. OldDataCell - old big data cell
  1036. NewDataCell - return value:HCELL_INDEX of the new cell; HCELL_NIL on some error
  1037. Return Value:
  1038. Status of the operation (STATUS_SUCCESS or the exception code - if any)
  1039. Notes:
  1040. Knows how to deal with big cell(s)
  1041. Data buffer is secured by the time this function is called
  1042. --*/
  1043. {
  1044. PCELL_DATA pdata;
  1045. PCM_BIG_DATA BigData = NULL;
  1046. USHORT NewCount,i;
  1047. PHCELL_INDEX Plist = NULL;
  1048. HCELL_INDEX NewList;
  1049. PAGED_CODE();
  1050. ASSERT_CM_LOCK_OWNED_EXCLUSIVE();
  1051. //
  1052. // bogus args; we deal only with big data cells!
  1053. //
  1054. ASSERT(DataSize > CM_KEY_VALUE_BIG );
  1055. BigData = (PCM_BIG_DATA)HvGetCell(Hive,OldDataCell);
  1056. if( BigData == NULL) {
  1057. //
  1058. // couldn't map view for this cell
  1059. // this shouldn't happen as we just marked it as dirty
  1060. // (i.e. its view should be pinned in memory)
  1061. //
  1062. ASSERT( FALSE );
  1063. return STATUS_INSUFFICIENT_RESOURCES;
  1064. }
  1065. // release the cell here as the reglock is held exclusive
  1066. HvReleaseCell(Hive,OldDataCell);
  1067. ASSERT_BIG_DATA(BigData);
  1068. Plist = (PHCELL_INDEX)HvGetCell(Hive,BigData->List);
  1069. if( Plist == NULL ) {
  1070. //
  1071. // cannot map view containing the cell; bail out
  1072. // this shouldn't happen as we just marked it as dirty
  1073. // (i.e. its view should be pinned in memory)
  1074. //
  1075. ASSERT(FALSE);
  1076. return STATUS_INSUFFICIENT_RESOURCES;
  1077. }
  1078. // release the cell here as the reglock is held exclusive
  1079. HvReleaseCell(Hive,BigData->List);
  1080. //
  1081. // what's the new size?
  1082. //
  1083. NewCount = (USHORT)((DataSize + CM_KEY_VALUE_BIG - 1) / CM_KEY_VALUE_BIG);
  1084. if( NewCount > BigData->Count ) {
  1085. //
  1086. // grow the list and allocate additional cells to it
  1087. //
  1088. NewList = HvReallocateCell(Hive,BigData->List,NewCount * sizeof(HCELL_INDEX));
  1089. if( NewList == HCELL_NIL ) {
  1090. return STATUS_INSUFFICIENT_RESOURCES;
  1091. }
  1092. //
  1093. // we can now safely alter the list; if allocating the aditional cells below fails
  1094. // we'll end up with some wasted space, but we'll be safe
  1095. //
  1096. BigData->List = NewList;
  1097. //
  1098. // read the new list
  1099. //
  1100. Plist = (PHCELL_INDEX)HvGetCell(Hive,NewList);
  1101. if( Plist == NULL ) {
  1102. //
  1103. // cannot map view containing the cell; bail out
  1104. // this shouldn't happen as we just reallocated the cell
  1105. // (i.e. its view should be pinned in memory)
  1106. //
  1107. ASSERT(FALSE);
  1108. return STATUS_INSUFFICIENT_RESOURCES;
  1109. }
  1110. // release the cell here as the reglock is held exclusive
  1111. HvReleaseCell(Hive,NewList);
  1112. for(i= BigData->Count;i<NewCount;i++) {
  1113. Plist[i] = HvAllocateCell(Hive, CM_KEY_VALUE_BIG, StorageType,NewList);
  1114. if( Plist[i] == HCELL_NIL ) {
  1115. return STATUS_INSUFFICIENT_RESOURCES;
  1116. }
  1117. }
  1118. } else if( NewCount < BigData->Count ) {
  1119. //
  1120. // shrink the list and free additional unneccessary cells
  1121. //
  1122. for(i=NewCount;i<BigData->Count;i++) {
  1123. //
  1124. // this CANNOT fail as the cell is already marked dirty (i.e. pinned in memory).
  1125. //
  1126. HvFreeCell(Hive,Plist[i]);
  1127. }
  1128. //
  1129. // this WON'T fail, 'cause it's a shrink
  1130. //
  1131. NewList = HvReallocateCell(Hive,BigData->List,NewCount * sizeof(HCELL_INDEX));
  1132. if( NewList == HCELL_NIL ) {
  1133. ASSERT( FALSE );
  1134. return STATUS_INSUFFICIENT_RESOURCES;
  1135. }
  1136. //
  1137. // read the new list (in the current implementation we don't shrink cells,
  1138. // so this is not really needed - just to be consistent)
  1139. //
  1140. Plist = (PHCELL_INDEX)HvGetCell(Hive,NewList);
  1141. if( Plist == NULL ) {
  1142. //
  1143. // cannot map view containing the cell; bail out
  1144. // this shouldn't happen as we just reallocated the cell
  1145. // (i.e. its view should be pinned in memory)
  1146. //
  1147. ASSERT(FALSE);
  1148. return STATUS_INSUFFICIENT_RESOURCES;
  1149. }
  1150. // release the cell here as the reglock is held exclusive
  1151. HvReleaseCell(Hive,NewList);
  1152. //
  1153. // we can now safely alter the list
  1154. //
  1155. BigData->List = NewList;
  1156. }
  1157. //
  1158. // if we came to this point, we have successfully grown the list and
  1159. // allocated the additional space; nothing should go wrong further
  1160. //
  1161. //
  1162. // go on and fill in the data onto the (new) big data cell
  1163. //
  1164. for( i=0;i<NewCount;i++) {
  1165. pdata = HvGetCell(Hive,Plist[i]);
  1166. if( pdata == NULL ) {
  1167. //
  1168. // cannot map view containing the cell; bail out
  1169. //
  1170. //
  1171. // This shouldn't happen as this cell is marked dirty by
  1172. // this time - or is a new allocated cell
  1173. // (i.e. its view is pinned in memory)
  1174. //
  1175. ASSERT( FALSE );
  1176. return STATUS_INSUFFICIENT_RESOURCES;
  1177. }
  1178. // release the cell here as the reglock is held exclusive
  1179. HvReleaseCell(Hive,Plist[i]);
  1180. //
  1181. // now, copy this chunk data
  1182. //
  1183. RtlCopyMemory(pdata, (PUCHAR)Data, (DataSize>CM_KEY_VALUE_BIG)?CM_KEY_VALUE_BIG:DataSize);
  1184. //
  1185. // update the data pointer and the remaining size
  1186. //
  1187. Data = (PVOID)((PCHAR)Data + CM_KEY_VALUE_BIG);
  1188. DataSize -= CM_KEY_VALUE_BIG;
  1189. }
  1190. BigData->Count = NewCount;
  1191. return STATUS_SUCCESS;
  1192. }
  1193. #endif //_CM_LDR_