2 * PROJECT: ReactOS Kernel
3 * LICENSE: GPL - See COPYING in the top level directory
4 * FILE: lib/cmlib/cmvalue.c
5 * PURPOSE: Configuration Manager Library - Cell Values
6 * PROGRAMMERS: Alex Ionescu (alex.ionescu@reactos.org)
9 /* INCLUDES ******************************************************************/
15 /* FUNCTIONS *****************************************************************/
19 CmpMarkValueDataDirty(IN PHHIVE Hive
,
20 IN PCM_KEY_VALUE Value
)
25 /* Make sure there's actually any data */
26 if (Value
->Data
!= HCELL_NIL
)
28 /* If this is a small key, there's no need to have it dirty */
29 if (CmpIsKeyValueSmall(&KeySize
, Value
->DataLength
)) return TRUE
;
31 /* Check if this is a big key */
32 ASSERT_VALUE_BIG(Hive
, KeySize
);
34 /* Normal value, just mark it dirty */
35 HvMarkCellDirty(Hive
, Value
->Data
, FALSE
);
38 /* Operation complete */
44 CmpFreeValueData(IN PHHIVE Hive
,
45 IN HCELL_INDEX DataCell
,
51 /* If this is a small key, the data is built-in */
52 if (!CmpIsKeyValueSmall(&KeySize
, DataLength
))
54 /* If there's no data cell, there's nothing to do */
55 if (DataCell
== HCELL_NIL
) return TRUE
;
57 /* Make sure the data cell is allocated */
58 //ASSERT(HvIsCellAllocated(Hive, DataCell));
60 /* Unsupported value type */
61 ASSERT_VALUE_BIG(Hive
, KeySize
);
63 /* Normal value, just free the data cell */
64 HvFreeCell(Hive
, DataCell
);
67 /* Operation complete */
73 CmpFreeValue(IN PHHIVE Hive
,
79 /* Get the cell data */
80 Value
= (PCM_KEY_VALUE
)HvGetCell(Hive
, Cell
);
81 if (!Value
) ASSERT(FALSE
);
84 if (!CmpFreeValueData(Hive
, Value
->Data
, Value
->DataLength
))
86 /* We failed to free the data, return failure */
87 HvReleaseCell(Hive
, Cell
);
91 /* Release the cell and free it */
92 HvReleaseCell(Hive
, Cell
);
93 HvFreeCell(Hive
, Cell
);
99 CmpFindValueByName(IN PHHIVE Hive
,
100 IN PCM_KEY_NODE KeyNode
,
101 IN PUNICODE_STRING Name
)
103 HCELL_INDEX CellIndex
;
105 /* Call the main function */
106 if (!CmpFindNameInList(Hive
,
113 ASSERT(CellIndex
== HCELL_NIL
);
116 /* Return the index */
121 * NOTE: This function should support big values, contrary to CmpValueToData.
125 CmpGetValueData(IN PHHIVE Hive
,
126 IN PCM_KEY_VALUE Value
,
129 OUT PBOOLEAN BufferAllocated
,
130 OUT PHCELL_INDEX CellToRelease
)
135 ASSERT(Value
->Signature
== CM_KEY_VALUE_SIGNATURE
);
137 /* Set failure defaults */
138 *BufferAllocated
= FALSE
;
140 *CellToRelease
= HCELL_NIL
;
142 /* Check if this is a small key */
143 if (CmpIsKeyValueSmall(Length
, Value
->DataLength
))
145 /* Return the data immediately */
146 *Buffer
= &Value
->Data
;
150 /* Unsupported at the moment */
151 ASSERT_VALUE_BIG(Hive
, *Length
);
153 /* Get the data from the cell */
154 *Buffer
= HvGetCell(Hive
, Value
->Data
);
155 if (!(*Buffer
)) return FALSE
;
157 /* Return success and the cell to be released */
158 *CellToRelease
= Value
->Data
;
163 * NOTE: This function doesn't support big values, contrary to CmpGetValueData.
167 CmpValueToData(IN PHHIVE Hive
,
168 IN PCM_KEY_VALUE Value
,
172 BOOLEAN BufferAllocated
;
173 HCELL_INDEX CellToRelease
;
177 ASSERT(Hive
->ReleaseCellRoutine
== NULL
);
179 /* Get the actual data */
180 if (!CmpGetValueData(Hive
,
188 ASSERT(BufferAllocated
== FALSE
);
189 ASSERT(Buffer
== NULL
);
193 /* This should never happen! */
196 /* Free the buffer and bugcheck */
198 KeBugCheckEx(REGISTRY_ERROR
, 8, 0, (ULONG_PTR
)Hive
, (ULONG_PTR
)Value
);
201 /* Otherwise, return the cell data */
207 CmpAddValueToList(IN PHHIVE Hive
,
208 IN HCELL_INDEX ValueCell
,
210 IN HSTORAGE_TYPE StorageType
,
211 IN OUT PCHILD_LIST ChildList
)
213 HCELL_INDEX ListCell
;
214 ULONG ChildCount
, Length
, i
;
219 ASSERT((((LONG
)Index
) >= 0) && (Index
<= ChildList
->Count
));
221 /* Get the number of entries in the child list */
222 ChildCount
= ChildList
->Count
;
226 ASSERT(ChildList
->List
!= HCELL_NIL
);
228 /* The cell should be dirty at this point */
229 ASSERT(HvIsCellDirty(Hive
, ChildList
->List
));
231 /* Check if we have less then 100 children */
232 if (ChildCount
< 100)
234 /* Allocate just enough as requested */
235 Length
= ChildCount
* sizeof(HCELL_INDEX
);
239 /* Otherwise, we have quite a few, so allocate a batch */
240 Length
= ROUND_UP(ChildCount
, 100) * sizeof(HCELL_INDEX
);
241 if (Length
> HBLOCK_SIZE
)
243 /* But make sure we don't allocate beyond our block size */
244 Length
= ROUND_UP(Length
, HBLOCK_SIZE
);
248 /* Perform the allocation */
249 ListCell
= HvReallocateCell(Hive
, ChildList
->List
, Length
);
253 /* This is our first child, so allocate a single cell */
254 ASSERT(ChildList
->List
== HCELL_NIL
);
255 ListCell
= HvAllocateCell(Hive
, sizeof(HCELL_INDEX
), StorageType
, HCELL_NIL
);
258 /* Fail if we couldn't get a cell */
259 if (ListCell
== HCELL_NIL
) return STATUS_INSUFFICIENT_RESOURCES
;
261 /* Set this cell as the child list's list cell */
262 ChildList
->List
= ListCell
;
264 /* Get the actual key list memory */
265 CellData
= HvGetCell(Hive
, ListCell
);
266 ASSERT(CellData
!= NULL
);
268 /* Loop all the children */
269 for (i
= ChildCount
- 1; i
> Index
; i
--)
271 /* Move them all down */
272 CellData
->u
.KeyList
[i
] = CellData
->u
.KeyList
[i
- 1];
275 /* Insert us on top now */
276 CellData
->u
.KeyList
[Index
] = ValueCell
;
277 ChildList
->Count
= ChildCount
;
279 /* Release the list cell and make sure the value cell is dirty */
280 HvReleaseCell(Hive
, ListCell
);
281 ASSERT(HvIsCellDirty(Hive
, ValueCell
));
283 /* We're done here */
284 return STATUS_SUCCESS
;
289 CmpSetValueDataNew(IN PHHIVE Hive
,
292 IN HSTORAGE_TYPE StorageType
,
293 IN HCELL_INDEX ValueCell
,
294 OUT PHCELL_INDEX DataCell
)
298 ASSERT(DataSize
> CM_KEY_VALUE_SMALL
);
300 /* Check if this is a big key */
301 ASSERT_VALUE_BIG(Hive
, DataSize
);
303 /* Allocate a data cell */
304 *DataCell
= HvAllocateCell(Hive
, DataSize
, StorageType
, HCELL_NIL
);
305 if (*DataCell
== HCELL_NIL
) return STATUS_INSUFFICIENT_RESOURCES
;
307 /* Get the actual data */
308 CellData
= HvGetCell(Hive
, *DataCell
);
309 if (!CellData
) ASSERT(FALSE
);
311 /* Copy our buffer into it */
312 RtlCopyMemory(CellData
, Data
, DataSize
);
315 return STATUS_SUCCESS
;
320 CmpRemoveValueFromList(IN PHHIVE Hive
,
322 IN OUT PCHILD_LIST ChildList
)
330 ASSERT((((LONG
)Index
) >= 0) && (Index
<= ChildList
->Count
));
332 /* Get the new count after removal */
333 Count
= ChildList
->Count
- 1;
336 /* Get the actual list array */
337 CellData
= HvGetCell(Hive
, ChildList
->List
);
338 if (!CellData
) return STATUS_INSUFFICIENT_RESOURCES
;
340 /* Make sure cells data have been made dirty */
341 ASSERT(HvIsCellDirty(Hive
, ChildList
->List
));
342 ASSERT(HvIsCellDirty(Hive
, CellData
->u
.KeyList
[Index
]));
345 while (Index
< Count
)
347 /* Move everything up */
348 CellData
->u
.KeyList
[Index
] = CellData
->u
.KeyList
[Index
+ 1];
352 /* Re-allocate the cell for the list by decreasing the count */
353 NewCell
= HvReallocateCell(Hive
,
355 Count
* sizeof(HCELL_INDEX
));
356 ASSERT(NewCell
!= HCELL_NIL
);
357 HvReleaseCell(Hive
,ChildList
->List
);
359 /* Update the list cell */
360 ChildList
->List
= NewCell
;
364 /* Otherwise, we were the last entry, so free the list entirely */
365 HvFreeCell(Hive
, ChildList
->List
);
366 ChildList
->List
= HCELL_NIL
;
369 /* Update the child list with the new count */
370 ChildList
->Count
= Count
;
371 return STATUS_SUCCESS
;
376 CmpCopyCell(IN PHHIVE SourceHive
,
377 IN HCELL_INDEX SourceCell
,
378 IN PHHIVE DestinationHive
,
379 IN HSTORAGE_TYPE StorageType
)
381 PCELL_DATA SourceData
;
382 PCELL_DATA DestinationData
= NULL
;
383 HCELL_INDEX DestinationCell
= HCELL_NIL
;
388 /* Get the data and the size of the source cell */
389 SourceData
= HvGetCell(SourceHive
, SourceCell
);
390 DataSize
= HvGetCellSize(SourceHive
, SourceData
);
392 /* Allocate a new cell in the destination hive */
393 DestinationCell
= HvAllocateCell(DestinationHive
,
397 if (DestinationCell
== HCELL_NIL
) goto Cleanup
;
399 /* Get the data of the destination cell */
400 DestinationData
= HvGetCell(DestinationHive
, DestinationCell
);
402 /* Copy the data from the source cell to the destination cell */
403 RtlMoveMemory(DestinationData
, SourceData
, DataSize
);
407 /* Release the cells */
408 if (DestinationData
) HvReleaseCell(DestinationHive
, DestinationCell
);
409 if (SourceData
) HvReleaseCell(SourceHive
, SourceCell
);
411 /* Return the destination cell index */
412 return DestinationCell
;
417 CmpCopyValue(IN PHHIVE SourceHive
,
418 IN HCELL_INDEX SourceValueCell
,
419 IN PHHIVE DestinationHive
,
420 IN HSTORAGE_TYPE StorageType
)
422 PCM_KEY_VALUE Value
, NewValue
;
423 HCELL_INDEX NewValueCell
, NewDataCell
;
431 /* Get the actual source data */
432 Value
= (PCM_KEY_VALUE
)HvGetCell(SourceHive
, SourceValueCell
);
433 if (!Value
) ASSERT(FALSE
);
435 /* Copy the value cell body */
436 NewValueCell
= CmpCopyCell(SourceHive
,
440 if (NewValueCell
== HCELL_NIL
)
442 /* Not enough storage space */
446 /* Copy the value data */
447 IsSmall
= CmpIsKeyValueSmall(&DataSize
, Value
->DataLength
);
450 /* Nothing to copy */
452 NewValue
= (PCM_KEY_VALUE
)HvGetCell(DestinationHive
, NewValueCell
);
454 NewValue
->DataLength
= 0;
455 NewValue
->Data
= HCELL_NIL
;
456 HvReleaseCell(DestinationHive
, NewValueCell
);
461 if (DataSize
<= CM_KEY_VALUE_SMALL
)
465 /* Small value, copy directly */
466 SmallData
= Value
->Data
;
470 /* The value is small, but was stored in a regular cell. Get the data from it. */
471 CellData
= HvGetCell(SourceHive
, Value
->Data
);
473 SmallData
= *(PULONG
)CellData
;
474 HvReleaseCell(SourceHive
, Value
->Data
);
477 /* This is a small key, set the data directly inside */
478 NewValue
= (PCM_KEY_VALUE
)HvGetCell(DestinationHive
, NewValueCell
);
480 NewValue
->DataLength
= DataSize
+ CM_KEY_VALUE_SPECIAL_SIZE
;
481 NewValue
->Data
= SmallData
;
482 HvReleaseCell(DestinationHive
, NewValueCell
);
486 /* Big keys are currently unsupported */
487 ASSERT_VALUE_BIG(SourceHive
, DataSize
);
488 // Should use CmpGetValueData and CmpSetValueDataNew for big values!
492 /* Copy the data cell */
493 NewDataCell
= CmpCopyCell(SourceHive
,
497 if (NewDataCell
== HCELL_NIL
)
499 /* Not enough storage space */
500 HvFreeCell(DestinationHive
, NewValueCell
);
501 NewValueCell
= HCELL_NIL
;
505 NewValue
= (PCM_KEY_VALUE
)HvGetCell(DestinationHive
, NewValueCell
);
507 NewValue
->DataLength
= DataSize
;
508 NewValue
->Data
= NewDataCell
;
509 HvReleaseCell(DestinationHive
, NewValueCell
);
513 HvReleaseCell(SourceHive
, SourceValueCell
);
515 /* Return the copied value body cell index */
521 CmpCopyKeyValueList(IN PHHIVE SourceHive
,
522 IN PCHILD_LIST SrcValueList
,
523 IN PHHIVE DestinationHive
,
524 IN OUT PCHILD_LIST DestValueList
,
525 IN HSTORAGE_TYPE StorageType
)
527 NTSTATUS Status
= STATUS_SUCCESS
;
528 PCELL_DATA SrcListData
= NULL
, DestListData
= NULL
;
529 HCELL_INDEX NewValue
;
534 /* Reset the destination value list */
535 DestValueList
->Count
= 0;
536 DestValueList
->List
= HCELL_NIL
;
538 /* Check if the list is empty */
539 if (!SrcValueList
->Count
)
540 return STATUS_SUCCESS
;
542 /* Get the source value list */
543 SrcListData
= HvGetCell(SourceHive
, SrcValueList
->List
);
546 /* Copy the actual values */
547 for (Index
= 0; Index
< SrcValueList
->Count
; Index
++)
549 NewValue
= CmpCopyValue(SourceHive
,
550 SrcListData
->u
.KeyList
[Index
],
553 if (NewValue
== HCELL_NIL
)
555 /* Not enough storage space, stop there and cleanup afterwards */
556 Status
= STATUS_INSUFFICIENT_RESOURCES
;
560 /* Add this value cell to the child list */
561 Status
= CmpAddValueToList(DestinationHive
,
566 if (!NT_SUCCESS(Status
))
568 /* Not enough storage space, stop there */
570 /* Cleanup the newly-created value here, the other ones will be cleaned up afterwards */
571 if (!CmpFreeValue(DestinationHive
, NewValue
))
572 HvFreeCell(DestinationHive
, NewValue
);
577 /* Revert-cleanup if failure */
578 if (!NT_SUCCESS(Status
) && (DestValueList
->List
!= HCELL_NIL
))
580 /* Do not use CmpRemoveValueFromList but directly delete the data */
582 /* Get the destination value list */
583 DestListData
= HvGetCell(DestinationHive
, DestValueList
->List
);
584 ASSERT(DestListData
);
586 /* Delete each copied value */
589 NewValue
= DestListData
->u
.KeyList
[Index
];
590 if (!CmpFreeValue(DestinationHive
, NewValue
))
591 HvFreeCell(DestinationHive
, NewValue
);
594 /* Release and free the list */
595 HvReleaseCell(DestinationHive
, DestValueList
->List
);
596 HvFreeCell(DestinationHive
, DestValueList
->List
);
598 DestValueList
->Count
= 0;
599 DestValueList
->List
= HCELL_NIL
;
602 /* Release the cells */
603 HvReleaseCell(SourceHive
, SrcValueList
->List
);