Something went wrong. Try again.
Reactos
Something went wrong. Try again.
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607/* * PROJECT: ReactOS Kernel * LICENSE: GPL - See COPYING in the top level directory * FILE: lib/cmlib/cmvalue.c * PURPOSE: Configuration Manager Library - Cell Values * PROGRAMMERS: Alex Ionescu (alex.ionescu@reactos.org) */
/* INCLUDES ******************************************************************/
#include "cmlib.h"#define NDEBUG#include <debug.h>
/* FUNCTIONS *****************************************************************/
BOOLEANNTAPICmpMarkValueDataDirty(IN PHHIVE Hive, IN PCM_KEY_VALUE Value){ ULONG KeySize; PAGED_CODE();
/* Make sure there's actually any data */ if (Value->Data != HCELL_NIL) { /* If this is a small key, there's no need to have it dirty */ if (CmpIsKeyValueSmall(&KeySize, Value->DataLength)) return TRUE;
/* Check if this is a big key */ ASSERT_VALUE_BIG(Hive, KeySize);
/* Normal value, just mark it dirty */ HvMarkCellDirty(Hive, Value->Data, FALSE); }
/* Operation complete */ return TRUE;}
BOOLEANNTAPICmpFreeValueData(IN PHHIVE Hive, IN HCELL_INDEX DataCell, IN ULONG DataLength){ ULONG KeySize; PAGED_CODE();
/* If this is a small key, the data is built-in */ if (!CmpIsKeyValueSmall(&KeySize, DataLength)) { /* If there's no data cell, there's nothing to do */ if (DataCell == HCELL_NIL) return TRUE;
/* Make sure the data cell is allocated */ //ASSERT(HvIsCellAllocated(Hive, DataCell));
/* Unsupported value type */ ASSERT_VALUE_BIG(Hive, KeySize);
/* Normal value, just free the data cell */ HvFreeCell(Hive, DataCell); }
/* Operation complete */ return TRUE;}
BOOLEANNTAPICmpFreeValue(IN PHHIVE Hive, IN HCELL_INDEX Cell){ PCM_KEY_VALUE Value; PAGED_CODE();
/* Get the cell data */ Value = (PCM_KEY_VALUE)HvGetCell(Hive, Cell); if (!Value) ASSERT(FALSE);
/* Free it */ if (!CmpFreeValueData(Hive, Value->Data, Value->DataLength)) { /* We failed to free the data, return failure */ HvReleaseCell(Hive, Cell); return FALSE; }
/* Release the cell and free it */ HvReleaseCell(Hive, Cell); HvFreeCell(Hive, Cell); return TRUE;}
HCELL_INDEXNTAPICmpFindValueByName(IN PHHIVE Hive, IN PCM_KEY_NODE KeyNode, IN PCUNICODE_STRING Name){ HCELL_INDEX CellIndex;
/* Call the main function */ if (!CmpFindNameInList(Hive, &KeyNode->ValueList, Name, NULL, &CellIndex)) { /* Sanity check */ ASSERT(CellIndex == HCELL_NIL); }
/* Return the index */ return CellIndex;}
/* * NOTE: This function should support big values, contrary to CmpValueToData. */BOOLEANNTAPICmpGetValueData(IN PHHIVE Hive, IN PCM_KEY_VALUE Value, OUT PULONG Length, OUT PVOID *Buffer, OUT PBOOLEAN BufferAllocated, OUT PHCELL_INDEX CellToRelease){ PAGED_CODE();
/* Sanity check */ ASSERT(Value->Signature == CM_KEY_VALUE_SIGNATURE);
/* Set failure defaults */ *BufferAllocated = FALSE; *Buffer = NULL; *CellToRelease = HCELL_NIL;
/* Check if this is a small key */ if (CmpIsKeyValueSmall(Length, Value->DataLength)) { /* Return the data immediately */ *Buffer = &Value->Data; return TRUE; }
/* Unsupported at the moment */ ASSERT_VALUE_BIG(Hive, *Length);
/* Get the data from the cell */ *Buffer = HvGetCell(Hive, Value->Data); if (!(*Buffer)) return FALSE;
/* Return success and the cell to be released */ *CellToRelease = Value->Data; return TRUE;}
/* * NOTE: This function doesn't support big values, contrary to CmpGetValueData. */PCELL_DATANTAPICmpValueToData(IN PHHIVE Hive, IN PCM_KEY_VALUE Value, OUT PULONG Length){ PCELL_DATA Buffer; BOOLEAN BufferAllocated; HCELL_INDEX CellToRelease; PAGED_CODE();
/* Sanity check */ ASSERT(Hive->ReleaseCellRoutine == NULL);
/* Get the actual data */ if (!CmpGetValueData(Hive, Value, Length, (PVOID*)&Buffer, &BufferAllocated, &CellToRelease)) { /* We failed */ ASSERT(BufferAllocated == FALSE); ASSERT(Buffer == NULL); return NULL; }
/* This should never happen! */ if (BufferAllocated) { /* Free the buffer and bugcheck */ Hive->Free(Buffer, 0); KeBugCheckEx(REGISTRY_ERROR, 8, 0, (ULONG_PTR)Hive, (ULONG_PTR)Value); }
/* Otherwise, return the cell data */ return Buffer;}
NTSTATUSNTAPICmpAddValueToList(IN PHHIVE Hive, IN HCELL_INDEX ValueCell, IN ULONG Index, IN HSTORAGE_TYPE StorageType, IN OUT PCHILD_LIST ChildList){ HCELL_INDEX ListCell; ULONG ChildCount, Length, i; PCELL_DATA CellData; PAGED_CODE();
/* Sanity check */ ASSERT((((LONG)Index) >= 0) && (Index <= ChildList->Count));
/* Get the number of entries in the child list */ ChildCount = ChildList->Count; ChildCount++; if (ChildCount > 1) { ASSERT(ChildList->List != HCELL_NIL);
/* The cell should be dirty at this point */ ASSERT(HvIsCellDirty(Hive, ChildList->List));
/* Check if we have less then 100 children */ if (ChildCount < 100) { /* Allocate just enough as requested */ Length = ChildCount * sizeof(HCELL_INDEX); } else { /* Otherwise, we have quite a few, so allocate a batch */ Length = ROUND_UP(ChildCount, 100) * sizeof(HCELL_INDEX); if (Length > HBLOCK_SIZE) { /* But make sure we don't allocate beyond our block size */ Length = ROUND_UP(Length, HBLOCK_SIZE); } }
/* Perform the allocation */ ListCell = HvReallocateCell(Hive, ChildList->List, Length); } else { /* This is our first child, so allocate a single cell */ ASSERT(ChildList->List == HCELL_NIL); ListCell = HvAllocateCell(Hive, sizeof(HCELL_INDEX), StorageType, HCELL_NIL); }
/* Fail if we couldn't get a cell */ if (ListCell == HCELL_NIL) return STATUS_INSUFFICIENT_RESOURCES;
/* Set this cell as the child list's list cell */ ChildList->List = ListCell;
/* Get the actual key list memory */ CellData = HvGetCell(Hive, ListCell); ASSERT(CellData != NULL);
/* Loop all the children */ for (i = ChildCount - 1; i > Index; i--) { /* Move them all down */ CellData->u.KeyList[i] = CellData->u.KeyList[i - 1]; }
/* Insert us on top now */ CellData->u.KeyList[Index] = ValueCell; ChildList->Count = ChildCount;
/* Release the list cell and make sure the value cell is dirty */ HvReleaseCell(Hive, ListCell); ASSERT(HvIsCellDirty(Hive, ValueCell));
/* We're done here */ return STATUS_SUCCESS;}
NTSTATUSNTAPICmpSetValueDataNew(IN PHHIVE Hive, IN PVOID Data, IN ULONG DataSize, IN HSTORAGE_TYPE StorageType, IN HCELL_INDEX ValueCell, OUT PHCELL_INDEX DataCell){ PCELL_DATA CellData; PAGED_CODE(); ASSERT(DataSize > CM_KEY_VALUE_SMALL);
/* Check if this is a big key */ ASSERT_VALUE_BIG(Hive, DataSize);
/* Allocate a data cell */ *DataCell = HvAllocateCell(Hive, DataSize, StorageType, HCELL_NIL); if (*DataCell == HCELL_NIL) return STATUS_INSUFFICIENT_RESOURCES;
/* Get the actual data */ CellData = HvGetCell(Hive, *DataCell); if (!CellData) ASSERT(FALSE);
/* Copy our buffer into it */ RtlCopyMemory(CellData, Data, DataSize);
/* All done */ return STATUS_SUCCESS;}
NTSTATUSNTAPICmpRemoveValueFromList(IN PHHIVE Hive, IN ULONG Index, IN OUT PCHILD_LIST ChildList){ ULONG Count; PCELL_DATA CellData; HCELL_INDEX NewCell; PAGED_CODE();
/* Sanity check */ ASSERT((((LONG)Index) >= 0) && (Index <= ChildList->Count));
/* Get the new count after removal */ Count = ChildList->Count - 1; if (Count > 0) { /* Get the actual list array */ CellData = HvGetCell(Hive, ChildList->List); if (!CellData) return STATUS_INSUFFICIENT_RESOURCES;
/* Make sure cells data have been made dirty */ ASSERT(HvIsCellDirty(Hive, ChildList->List)); ASSERT(HvIsCellDirty(Hive, CellData->u.KeyList[Index]));
/* Loop the list */ while (Index < Count) { /* Move everything up */ CellData->u.KeyList[Index] = CellData->u.KeyList[Index + 1]; Index++; }
/* Re-allocate the cell for the list by decreasing the count */ NewCell = HvReallocateCell(Hive, ChildList->List, Count * sizeof(HCELL_INDEX)); ASSERT(NewCell != HCELL_NIL); HvReleaseCell(Hive,ChildList->List);
/* Update the list cell */ ChildList->List = NewCell; } else { /* Otherwise, we were the last entry, so free the list entirely */ HvFreeCell(Hive, ChildList->List); ChildList->List = HCELL_NIL; }
/* Update the child list with the new count */ ChildList->Count = Count; return STATUS_SUCCESS;}
HCELL_INDEXNTAPICmpCopyCell(IN PHHIVE SourceHive, IN HCELL_INDEX SourceCell, IN PHHIVE DestinationHive, IN HSTORAGE_TYPE StorageType){ PCELL_DATA SourceData; PCELL_DATA DestinationData = NULL; HCELL_INDEX DestinationCell = HCELL_NIL; LONG DataSize;
PAGED_CODE();
/* Get the data and the size of the source cell */ SourceData = HvGetCell(SourceHive, SourceCell); DataSize = HvGetCellSize(SourceHive, SourceData);
/* Allocate a new cell in the destination hive */ DestinationCell = HvAllocateCell(DestinationHive, DataSize, StorageType, HCELL_NIL); if (DestinationCell == HCELL_NIL) goto Cleanup;
/* Get the data of the destination cell */ DestinationData = HvGetCell(DestinationHive, DestinationCell);
/* Copy the data from the source cell to the destination cell */ RtlMoveMemory(DestinationData, SourceData, DataSize);
Cleanup:
/* Release the cells */ if (DestinationData) HvReleaseCell(DestinationHive, DestinationCell); if (SourceData) HvReleaseCell(SourceHive, SourceCell);
/* Return the destination cell index */ return DestinationCell;}
HCELL_INDEXNTAPICmpCopyValue(IN PHHIVE SourceHive, IN HCELL_INDEX SourceValueCell, IN PHHIVE DestinationHive, IN HSTORAGE_TYPE StorageType){ PCM_KEY_VALUE Value, NewValue; HCELL_INDEX NewValueCell, NewDataCell; PCELL_DATA CellData; ULONG SmallData; ULONG DataSize; BOOLEAN IsSmall;
PAGED_CODE();
/* Get the actual source data */ Value = (PCM_KEY_VALUE)HvGetCell(SourceHive, SourceValueCell); if (!Value) ASSERT(FALSE);
/* Copy the value cell body */ NewValueCell = CmpCopyCell(SourceHive, SourceValueCell, DestinationHive, StorageType); if (NewValueCell == HCELL_NIL) { /* Not enough storage space */ goto Quit; }
/* Copy the value data */ IsSmall = CmpIsKeyValueSmall(&DataSize, Value->DataLength); if (DataSize == 0) { /* Nothing to copy */
NewValue = (PCM_KEY_VALUE)HvGetCell(DestinationHive, NewValueCell); ASSERT(NewValue); NewValue->DataLength = 0; NewValue->Data = HCELL_NIL; HvReleaseCell(DestinationHive, NewValueCell);
goto Quit; }
if (DataSize <= CM_KEY_VALUE_SMALL) { if (IsSmall) { /* Small value, copy directly */ SmallData = Value->Data; } else { /* The value is small, but was stored in a regular cell. Get the data from it. */ CellData = HvGetCell(SourceHive, Value->Data); ASSERT(CellData); SmallData = *(PULONG)CellData; HvReleaseCell(SourceHive, Value->Data); }
/* This is a small key, set the data directly inside */ NewValue = (PCM_KEY_VALUE)HvGetCell(DestinationHive, NewValueCell); ASSERT(NewValue); NewValue->DataLength = DataSize + CM_KEY_VALUE_SPECIAL_SIZE; NewValue->Data = SmallData; HvReleaseCell(DestinationHive, NewValueCell); } else { /* Big keys are currently unsupported */ ASSERT_VALUE_BIG(SourceHive, DataSize); // Should use CmpGetValueData and CmpSetValueDataNew for big values!
/* Regular value */
/* Copy the data cell */ NewDataCell = CmpCopyCell(SourceHive, Value->Data, DestinationHive, StorageType); if (NewDataCell == HCELL_NIL) { /* Not enough storage space */ HvFreeCell(DestinationHive, NewValueCell); NewValueCell = HCELL_NIL; goto Quit; }
NewValue = (PCM_KEY_VALUE)HvGetCell(DestinationHive, NewValueCell); ASSERT(NewValue); NewValue->DataLength = DataSize; NewValue->Data = NewDataCell; HvReleaseCell(DestinationHive, NewValueCell); }
Quit: HvReleaseCell(SourceHive, SourceValueCell);
/* Return the copied value body cell index */ return NewValueCell;}
NTSTATUSNTAPICmpCopyKeyValueList(IN PHHIVE SourceHive, IN PCHILD_LIST SrcValueList, IN PHHIVE DestinationHive, IN OUT PCHILD_LIST DestValueList, IN HSTORAGE_TYPE StorageType){ NTSTATUS Status = STATUS_SUCCESS; PCELL_DATA SrcListData = NULL, DestListData = NULL; HCELL_INDEX NewValue; ULONG Index;
PAGED_CODE();
/* Reset the destination value list */ DestValueList->Count = 0; DestValueList->List = HCELL_NIL;
/* Check if the list is empty */ if (!SrcValueList->Count) return STATUS_SUCCESS;
/* Get the source value list */ SrcListData = HvGetCell(SourceHive, SrcValueList->List); ASSERT(SrcListData);
/* Copy the actual values */ for (Index = 0; Index < SrcValueList->Count; Index++) { NewValue = CmpCopyValue(SourceHive, SrcListData->u.KeyList[Index], DestinationHive, StorageType); if (NewValue == HCELL_NIL) { /* Not enough storage space, stop there and cleanup afterwards */ Status = STATUS_INSUFFICIENT_RESOURCES; break; }
/* Add this value cell to the child list */ Status = CmpAddValueToList(DestinationHive, NewValue, Index, StorageType, DestValueList); if (!NT_SUCCESS(Status)) { /* Not enough storage space, stop there */
/* Cleanup the newly-created value here, the other ones will be cleaned up afterwards */ if (!CmpFreeValue(DestinationHive, NewValue)) HvFreeCell(DestinationHive, NewValue); break; } }
/* Revert-cleanup if failure */ if (!NT_SUCCESS(Status) && (DestValueList->List != HCELL_NIL)) { /* Do not use CmpRemoveValueFromList but directly delete the data */
/* Get the destination value list */ DestListData = HvGetCell(DestinationHive, DestValueList->List); ASSERT(DestListData);
/* Delete each copied value */ while (Index--) { NewValue = DestListData->u.KeyList[Index]; if (!CmpFreeValue(DestinationHive, NewValue)) HvFreeCell(DestinationHive, NewValue); }
/* Release and free the list */ HvReleaseCell(DestinationHive, DestValueList->List); HvFreeCell(DestinationHive, DestValueList->List);
DestValueList->Count = 0; DestValueList->List = HCELL_NIL; }
/* Release the cells */ HvReleaseCell(SourceHive, SrcValueList->List);
return Status;}