Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

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