diff --git a/reactos/lib/cmlib/hivecell.c b/reactos/lib/cmlib/hivecell.c index 28d2b9e7eef..ebde802e542 100644 --- a/reactos/lib/cmlib/hivecell.c +++ b/reactos/lib/cmlib/hivecell.c @@ -82,17 +82,16 @@ HvpGetCellFullSize( } LONG CMAPI -HvGetCellSize( - PHHIVE RegistryHive, - PVOID Cell) +HvGetCellSize(IN PHHIVE Hive, + IN PVOID Address) { - PHCELL CellHeader; + PHCELL CellHeader; + LONG Size; - CellHeader = (PHCELL)Cell - 1; - if (CellHeader->Size < 0) - return CellHeader->Size + sizeof(HCELL); - else - return CellHeader->Size - sizeof(HCELL); + CellHeader = (PHCELL)Address - 1; + Size = CellHeader->Size * -1; + Size -= sizeof(HCELL); + return Size; } VOID CMAPI @@ -375,8 +374,8 @@ HvReallocateCell( OldCell = HvGetCell(RegistryHive, CellIndex); OldCellSize = HvGetCellSize(RegistryHive, OldCell); - ASSERT(OldCellSize < 0); - + ASSERT(OldCellSize > 0); + /* * If new data size is larger than the current, destroy current * data block and allocate a new one. @@ -384,14 +383,14 @@ HvReallocateCell( * FIXME: Merge with adjacent free cell if possible. * FIXME: Implement shrinking. */ - if (Size > (ULONG)-OldCellSize) + if (Size > OldCellSize) { NewCellIndex = HvAllocateCell(RegistryHive, Size, Storage); if (NewCellIndex == HCELL_NULL) return HCELL_NULL; NewCell = HvGetCell(RegistryHive, NewCellIndex); - RtlCopyMemory(NewCell, OldCell, (SIZE_T)-OldCellSize); + RtlCopyMemory(NewCell, OldCell, (SIZE_T)OldCellSize); HvFreeCell(RegistryHive, CellIndex); diff --git a/reactos/ntoskrnl/cm/cm.h b/reactos/ntoskrnl/cm/cm.h index 28bb4c62419..f39581586c4 100644 --- a/reactos/ntoskrnl/cm/cm.h +++ b/reactos/ntoskrnl/cm/cm.h @@ -260,14 +260,6 @@ CmiGetValueFromKeyByIndex(IN PEREGISTRY_HIVE RegistryHive, IN ULONG Index, OUT PCM_KEY_VALUE *ValueCell); -NTSTATUS -CmiAddValueToKey(IN PEREGISTRY_HIVE RegistryHive, - IN PCM_KEY_NODE KeyCell, - IN HCELL_INDEX KeyCellOffset, - IN PUNICODE_STRING ValueName, - OUT PCM_KEY_VALUE *pValueCell, - OUT HCELL_INDEX *pValueCellOffset); - NTSTATUS CmiDeleteValueFromKey(IN PEREGISTRY_HIVE RegistryHive, IN PCM_KEY_NODE KeyCell, @@ -294,18 +286,19 @@ CmiAddKeyToHashTable(PEREGISTRY_HIVE RegistryHive, PCM_KEY_NODE NewKeyCell, HCELL_INDEX NKBOffset); +NTSTATUS +NTAPI +CmSetValueKey(IN PKEY_OBJECT KeyObject, + IN PUNICODE_STRING ValueName, + IN ULONG Type, + IN PVOID Data, + IN ULONG DataSize); + NTSTATUS CmiRemoveKeyFromHashTable(PEREGISTRY_HIVE RegistryHive, PHASH_TABLE_CELL HashBlock, HCELL_INDEX NKBOffset); -NTSTATUS -CmiAllocateValueCell(IN PEREGISTRY_HIVE RegistryHive, - OUT PCM_KEY_VALUE *ValueCell, - OUT HCELL_INDEX *VBOffset, - IN PUNICODE_STRING ValueName, - IN HV_STORAGE_TYPE Storage); - NTSTATUS CmiDestroyValueCell(PEREGISTRY_HIVE RegistryHive, PCM_KEY_VALUE ValueCell, diff --git a/reactos/ntoskrnl/cm/ntfunc.c b/reactos/ntoskrnl/cm/ntfunc.c index a5b0206267f..30fb057e0d6 100644 --- a/reactos/ntoskrnl/cm/ntfunc.c +++ b/reactos/ntoskrnl/cm/ntfunc.c @@ -1799,194 +1799,61 @@ ByeBye:; return Status; } - -NTSTATUS STDCALL +NTSTATUS +NTAPI NtSetValueKey(IN HANDLE KeyHandle, - IN PUNICODE_STRING ValueName, - IN ULONG TitleIndex, - IN ULONG Type, - IN PVOID Data, - IN ULONG DataSize) + IN PUNICODE_STRING ValueName, + IN ULONG TitleIndex, + IN ULONG Type, + IN PVOID Data, + IN ULONG DataSize) { - NTSTATUS Status; - PKEY_OBJECT KeyObject; - PEREGISTRY_HIVE RegistryHive; - PCM_KEY_NODE KeyCell; - PCM_KEY_VALUE ValueCell; - HCELL_INDEX ValueCellOffset; - PVOID DataCell; - ULONG DesiredAccess; - REG_SET_VALUE_KEY_INFORMATION SetValueKeyInfo; - REG_POST_OPERATION_INFORMATION PostOperationInfo; - ULONG DataCellSize; + NTSTATUS Status; + PKEY_OBJECT KeyObject; + REG_SET_VALUE_KEY_INFORMATION SetValueKeyInfo; + REG_POST_OPERATION_INFORMATION PostOperationInfo; + PAGED_CODE(); - PAGED_CODE(); + /* Verify that the handle is valid and is a registry key */ + Status = ObReferenceObjectByHandle(KeyHandle, + KEY_SET_VALUE, + CmpKeyObjectType, + ExGetPreviousMode(), + (PVOID *)&KeyObject, + NULL); + if (!NT_SUCCESS(Status)) return(Status); - DPRINT("NtSetValueKey(KeyHandle 0x%p ValueName '%wZ' Type %d)\n", - KeyHandle, ValueName, Type); + /* Setup callback */ + PostOperationInfo.Object = (PVOID)KeyObject; + SetValueKeyInfo.Object = (PVOID)KeyObject; + SetValueKeyInfo.ValueName = ValueName; + SetValueKeyInfo.TitleIndex = TitleIndex; + SetValueKeyInfo.Type = Type; + SetValueKeyInfo.Data = Data; + SetValueKeyInfo.DataSize = DataSize; - DesiredAccess = KEY_SET_VALUE; - - /* Verify that the handle is valid and is a registry key */ - Status = ObReferenceObjectByHandle(KeyHandle, - DesiredAccess, - CmpKeyObjectType, - ExGetPreviousMode(), - (PVOID *)&KeyObject, - NULL); - if (!NT_SUCCESS(Status)) - return(Status); - - PostOperationInfo.Object = (PVOID)KeyObject; - SetValueKeyInfo.Object = (PVOID)KeyObject; - SetValueKeyInfo.ValueName = ValueName; - SetValueKeyInfo.TitleIndex = TitleIndex; - SetValueKeyInfo.Type = Type; - SetValueKeyInfo.Data = Data; - SetValueKeyInfo.DataSize = DataSize; - Status = CmiCallRegisteredCallbacks(RegNtPreSetValueKey, &SetValueKeyInfo); - if (!NT_SUCCESS(Status)) + /* Do the callback */ + Status = CmiCallRegisteredCallbacks(RegNtPreSetValueKey, &SetValueKeyInfo); + if (NT_SUCCESS(Status)) { - PostOperationInfo.Status = Status; - CmiCallRegisteredCallbacks(RegNtPostSetValueKey, &PostOperationInfo); - ObDereferenceObject(KeyObject); - return Status; + /* Call the internal API */ + Status = CmSetValueKey(KeyObject, + ValueName, + Type, + Data, + DataSize); } - /* Acquire hive lock exclucively */ - KeEnterCriticalRegion(); - ExAcquireResourceExclusiveLite(&CmpRegistryLock, TRUE); + /* Do the post-callback and de-reference the key object */ + PostOperationInfo.Status = Status; + CmiCallRegisteredCallbacks(RegNtPostSetValueKey, &PostOperationInfo); + ObDereferenceObject(KeyObject); - VERIFY_KEY_OBJECT(KeyObject); - - /* Get pointer to key cell */ - KeyCell = KeyObject->KeyCell; - RegistryHive = KeyObject->RegistryHive; - Status = CmiScanKeyForValue(RegistryHive, - KeyCell, - ValueName, - &ValueCell, - &ValueCellOffset); - if (Status == STATUS_OBJECT_NAME_NOT_FOUND) - { - DPRINT("Allocate new value cell\n"); - Status = CmiAddValueToKey(RegistryHive, - KeyCell, - KeyObject->KeyCellOffset, - ValueName, - &ValueCell, - &ValueCellOffset); - } - - if (!NT_SUCCESS(Status)) - { - DPRINT("Cannot add value. Status 0x%X\n", Status); - - ExReleaseResourceLite(&CmpRegistryLock); - KeLeaveCriticalRegion(); - PostOperationInfo.Status = Status; - CmiCallRegisteredCallbacks(RegNtPostSetValueKey, &PostOperationInfo); - ObDereferenceObject(KeyObject); - return Status; - } - - DPRINT("DataSize %lu\n", DataSize); - DPRINT("ValueCell %p\n", ValueCell); - DPRINT("ValueCell->DataSize %lu\n", ValueCell->DataSize); - - if (!(ValueCell->DataSize & REG_DATA_IN_OFFSET) && - (ValueCell->DataSize & REG_DATA_SIZE_MASK) != 0) - { - DataCell = HvGetCell (&RegistryHive->Hive, ValueCell->DataOffset); - DataCellSize = -HvGetCellSize (&RegistryHive->Hive, DataCell); - } - else - { - DataCell = NULL; - DataCellSize = 0; - } - - - if (DataSize <= sizeof(HCELL_INDEX)) - { - /* If data size <= sizeof(HCELL_INDEX) then store data in the data offset */ - DPRINT("ValueCell->DataSize %lu\n", ValueCell->DataSize); - if (DataCell) - { - HvFreeCell(&RegistryHive->Hive, ValueCell->DataOffset); - } - - RtlCopyMemory(&ValueCell->DataOffset, Data, DataSize); - ValueCell->DataSize = DataSize | REG_DATA_IN_OFFSET; - ValueCell->DataType = Type; - HvMarkCellDirty(&RegistryHive->Hive, ValueCellOffset); - } - else - { - if (DataSize > DataCellSize) - { - /* - * New data size is larger than the current, destroy current - * data block and allocate a new one. - */ - HCELL_INDEX NewOffset; - - DPRINT("ValueCell->DataSize %lu\n", ValueCell->DataSize); - - NewOffset = HvAllocateCell (&RegistryHive->Hive, DataSize, HvStable); - if (NewOffset == HCELL_NULL) - { - DPRINT("CmiAllocateBlock() failed (Status %lx)\n", Status); - - ExReleaseResourceLite(&CmpRegistryLock); - KeLeaveCriticalRegion(); - PostOperationInfo.Status = Status; - CmiCallRegisteredCallbacks(RegNtPostSetValueKey, &PostOperationInfo); - ObDereferenceObject(KeyObject); - - return Status; - } - - if (DataCell) - { - HvFreeCell(&RegistryHive->Hive, ValueCell->DataOffset); - } - - ValueCell->DataOffset = NewOffset; - DataCell = HvGetCell(&RegistryHive->Hive, NewOffset); - } - - RtlCopyMemory(DataCell, Data, DataSize); - ValueCell->DataSize = DataSize & REG_DATA_SIZE_MASK; - ValueCell->DataType = Type; - HvMarkCellDirty(&RegistryHive->Hive, ValueCell->DataOffset); - HvMarkCellDirty(&RegistryHive->Hive, ValueCellOffset); - } - - /* Mark link key */ - if ((Type == REG_LINK) && - (_wcsicmp(ValueName->Buffer, L"SymbolicLinkValue") == 0)) - { - KeyCell->Flags |= REG_KEY_LINK_CELL; - } - - KeQuerySystemTime (&KeyCell->LastWriteTime); - HvMarkCellDirty (&RegistryHive->Hive, KeyObject->KeyCellOffset); - - ExReleaseResourceLite(&CmpRegistryLock); - KeLeaveCriticalRegion(); - PostOperationInfo.Status = Status; - CmiCallRegisteredCallbacks(RegNtPostSetValueKey, &PostOperationInfo); - ObDereferenceObject(KeyObject); - - CmiSyncHives(); - - DPRINT("Return Status 0x%X\n", Status); - - return Status; + /* Synchronize the hives and return */ + CmiSyncHives(); + return Status; } - NTSTATUS STDCALL NtDeleteValueKey (IN HANDLE KeyHandle, IN PUNICODE_STRING ValueName) diff --git a/reactos/ntoskrnl/cm/regfile.c b/reactos/ntoskrnl/cm/regfile.c index 5b8e3d5a1f2..e02878e5ddd 100644 --- a/reactos/ntoskrnl/cm/regfile.c +++ b/reactos/ntoskrnl/cm/regfile.c @@ -59,22 +59,6 @@ CmiLoadHive(IN POBJECT_ATTRIBUTES KeyObjectAttributes, return Status; } - -NTSTATUS -CmiRemoveRegistaryHive(PEREGISTRY_HIVE RegistryHive) -{ - /* Remove hive from hive list */ - RemoveEntryList (&RegistryHive->HiveList); - - /* Release file names */ - RtlFreeUnicodeString (&RegistryHive->HiveFileName); - - /* Release hive */ - HvFree (&RegistryHive->Hive); - - return STATUS_SUCCESS; -} - VOID CmCloseHiveFiles(PEREGISTRY_HIVE RegistryHive) { @@ -680,93 +664,6 @@ CmiGetValueFromKeyByIndex(IN PEREGISTRY_HIVE RegistryHive, return STATUS_SUCCESS; } - -NTSTATUS -CmiAddValueToKey(IN PEREGISTRY_HIVE RegistryHive, - IN PCM_KEY_NODE KeyCell, - IN HCELL_INDEX KeyCellOffset, - IN PUNICODE_STRING ValueName, - OUT PCM_KEY_VALUE *pValueCell, - OUT HCELL_INDEX *pValueCellOffset) -{ - PVALUE_LIST_CELL ValueListCell; - PCM_KEY_VALUE NewValueCell; - HCELL_INDEX ValueListCellOffset; - HCELL_INDEX NewValueCellOffset; - ULONG CellSize; - HV_STORAGE_TYPE Storage; - NTSTATUS Status; - - DPRINT("KeyCell->ValuesOffset %lu\n", (ULONG)KeyCell->ValueList.List); - - Storage = (KeyCell->Flags & REG_KEY_VOLATILE_CELL) ? HvVolatile : HvStable; - if (KeyCell->ValueList.List == HCELL_NULL) - { - CellSize = sizeof(VALUE_LIST_CELL) + - (3 * sizeof(HCELL_INDEX)); - ValueListCellOffset = HvAllocateCell (&RegistryHive->Hive, CellSize, Storage); - if (ValueListCellOffset == HCELL_NULL) - { - return STATUS_INSUFFICIENT_RESOURCES; - } - - ValueListCell = HvGetCell (&RegistryHive->Hive, ValueListCellOffset); - KeyCell->ValueList.List = ValueListCellOffset; - HvMarkCellDirty(&RegistryHive->Hive, KeyCellOffset); - } - else - { - ValueListCell = (PVALUE_LIST_CELL) HvGetCell (&RegistryHive->Hive, KeyCell->ValueList.List); - CellSize = ABS_VALUE(HvGetCellSize(&RegistryHive->Hive, ValueListCell)); - - if (KeyCell->ValueList.Count >= - (CellSize / sizeof(HCELL_INDEX))) - { - CellSize *= 2; - ValueListCellOffset = HvReallocateCell (&RegistryHive->Hive, KeyCell->ValueList.List, CellSize); - if (ValueListCellOffset == HCELL_NULL) - { - return STATUS_INSUFFICIENT_RESOURCES; - } - - ValueListCell = HvGetCell (&RegistryHive->Hive, ValueListCellOffset); - KeyCell->ValueList.List = ValueListCellOffset; - HvMarkCellDirty (&RegistryHive->Hive, KeyCellOffset); - } - } - -#if 0 - DPRINT("KeyCell->ValueList.Count %lu, ValueListCell->Size %lu (%lu %lx)\n", - KeyCell->ValueList.Count, - (ULONG)ABS_VALUE(ValueListCell->Size), - ((ULONG)ABS_VALUE(ValueListCell->Size) - sizeof(HCELL)) / sizeof(HCELL_INDEX), - ((ULONG)ABS_VALUE(ValueListCell->Size) - sizeof(HCELL)) / sizeof(HCELL_INDEX)); -#endif - - Status = CmiAllocateValueCell(RegistryHive, - &NewValueCell, - &NewValueCellOffset, - ValueName, - Storage); - if (!NT_SUCCESS(Status)) - { - return Status; - } - - ValueListCell->ValueOffset[KeyCell->ValueList.Count] = NewValueCellOffset; - KeyCell->ValueList.Count++; - - HvMarkCellDirty(&RegistryHive->Hive, KeyCellOffset); - HvMarkCellDirty(&RegistryHive->Hive, KeyCell->ValueList.List); - HvMarkCellDirty(&RegistryHive->Hive, NewValueCellOffset); - - *pValueCell = NewValueCell; - *pValueCellOffset = NewValueCellOffset; - - return STATUS_SUCCESS; -} - - NTSTATUS CmiDeleteValueFromKey(IN PEREGISTRY_HIVE RegistryHive, IN PCM_KEY_NODE KeyCell, @@ -934,63 +831,6 @@ CmiRemoveKeyFromHashTable(PEREGISTRY_HIVE RegistryHive, return STATUS_UNSUCCESSFUL; } - -NTSTATUS -CmiAllocateValueCell(PEREGISTRY_HIVE RegistryHive, - PCM_KEY_VALUE *ValueCell, - HCELL_INDEX *VBOffset, - IN PUNICODE_STRING ValueName, - IN HV_STORAGE_TYPE Storage) -{ - PCM_KEY_VALUE NewValueCell; - NTSTATUS Status; - BOOLEAN Packable; - ULONG NameSize; - ULONG i; - - Status = STATUS_SUCCESS; - - NameSize = CmiGetPackedNameLength(ValueName, - &Packable); - - DPRINT("ValueName->Length %lu NameSize %lu\n", ValueName->Length, NameSize); - - *VBOffset = HvAllocateCell (&RegistryHive->Hive, sizeof(CM_KEY_VALUE) + NameSize, Storage); - if (*VBOffset == HCELL_NULL) - { - Status = STATUS_INSUFFICIENT_RESOURCES; - } - else - { - ASSERT(NameSize <= 0xffff); /* should really be USHORT_MAX or similar */ - NewValueCell = HvGetCell (&RegistryHive->Hive, *VBOffset); - NewValueCell->Id = REG_VALUE_CELL_ID; - NewValueCell->NameSize = (USHORT)NameSize; - if (Packable) - { - /* Pack the value name */ - for (i = 0; i < NameSize; i++) - NewValueCell->Name[i] = (CHAR)ValueName->Buffer[i]; - NewValueCell->Flags |= REG_VALUE_NAME_PACKED; - } - else - { - /* Copy the value name */ - RtlCopyMemory(NewValueCell->Name, - ValueName->Buffer, - NameSize); - NewValueCell->Flags = 0; - } - NewValueCell->DataType = 0; - NewValueCell->DataSize = 0; - NewValueCell->DataOffset = (HCELL_INDEX)-1; - *ValueCell = NewValueCell; - } - - return Status; -} - - NTSTATUS CmiDestroyValueCell(PEREGISTRY_HIVE RegistryHive, PCM_KEY_VALUE ValueCell, diff --git a/reactos/ntoskrnl/config/cm.h b/reactos/ntoskrnl/config/cm.h index 6abc1ffc64d..a12ebbb681a 100644 --- a/reactos/ntoskrnl/config/cm.h +++ b/reactos/ntoskrnl/config/cm.h @@ -1049,6 +1049,21 @@ CmpFreeValue( IN HCELL_INDEX Cell ); +BOOLEAN +NTAPI +CmpMarkValueDataDirty( + IN PHHIVE Hive, + IN PCM_KEY_VALUE Value +); + +BOOLEAN +NTAPI +CmpFreeValueData( + IN PHHIVE Hive, + IN HCELL_INDEX DataCell, + IN ULONG DataLength +); + // // Boot Routines // diff --git a/reactos/ntoskrnl/config/cmapi.c b/reactos/ntoskrnl/config/cmapi.c new file mode 100644 index 00000000000..c9cad213779 --- /dev/null +++ b/reactos/ntoskrnl/config/cmapi.c @@ -0,0 +1,342 @@ +/* + * PROJECT: ReactOS Kernel + * LICENSE: GPL - See COPYING in the top level directory + * FILE: ntoskrnl/config/cmapi.c + * PURPOSE: Configuration Manager - Internal Registry APIs + * PROGRAMMERS: Alex Ionescu (alex.ionescu@reactos.org) + */ + +/* INCLUDES ******************************************************************/ + +#include "ntoskrnl.h" +#include "cm.h" +#define NDEBUG +#include "debug.h" + +/* FUNCTIONS *****************************************************************/ + +NTSTATUS +NTAPI +CmpSetValueKeyNew(IN PHHIVE Hive, + IN PCM_KEY_NODE Parent, + IN PUNICODE_STRING ValueName, + IN ULONG Index, + IN ULONG Type, + IN PVOID Data, + IN ULONG DataSize, + IN ULONG StorageType, + IN ULONG SmallData) +{ + PCELL_DATA CellData; + HCELL_INDEX ValueCell; + NTSTATUS Status; + + /* Check if we already have a value list */ + if (Parent->ValueList.Count) + { + /* Then make sure it's valid and dirty it */ + ASSERT(Parent->ValueList.List != HCELL_NIL); + HvMarkCellDirty(Hive, Parent->ValueList.List); + } + + /* Allocate avalue cell */ + ValueCell = HvAllocateCell(Hive, + FIELD_OFFSET(CM_KEY_VALUE, Name) + + CmpNameSize(Hive, ValueName), + StorageType); + if (ValueCell == HCELL_NIL) return STATUS_INSUFFICIENT_RESOURCES; + + /* Get the actual data for it */ + CellData = HvGetCell(Hive, ValueCell); + if (!CellData) ASSERT(FALSE); + + /* Now we can release it, make sure it's also dirty */ + HvReleaseCell(Hive, ValueCell); + ASSERT(HvIsCellDirty(Hive, ValueCell)); + + /* Set it up and copy the name */ + CellData->u.KeyValue.Signature = CM_KEY_VALUE_SIGNATURE; + CellData->u.KeyValue.Flags = 0; + CellData->u.KeyValue.Type = Type; + CellData->u.KeyValue.NameLength = CmpCopyName(Hive, + CellData->u.KeyValue.Name, + ValueName); + if (CellData->u.KeyValue.NameLength < ValueName->Length) + { + /* This is a compressed name */ + CellData->u.KeyValue.Flags = VALUE_COMP_NAME; + } + + /* Check if this is a normal key */ + if (DataSize > CM_KEY_VALUE_SMALL) + { + /* Build a data cell for it */ + Status = CmpSetValueDataNew(Hive, + Data, + DataSize, + StorageType, + ValueCell, + &CellData->u.KeyValue.Data); + if (!NT_SUCCESS(Status)) + { + /* We failed, free the cell */ + HvFreeCell(Hive, ValueCell); + return Status; + } + + /* Otherwise, set the data length, and make sure the data is dirty */ + CellData->u.KeyValue.DataLength = DataSize; + ASSERT(HvIsCellDirty(Hive,CellData->u.KeyValue.Data)); + } + else + { + /* This is a small key, set the data directly inside */ + CellData->u.KeyValue.DataLength = DataSize + CM_KEY_VALUE_SPECIAL_SIZE; + CellData->u.KeyValue.Data = SmallData; + } + + /* Add this value cell to the child list */ + Status = CmpAddValueToList(Hive, + ValueCell, + Index, + StorageType, + &Parent->ValueList); + + /* If we failed, free the entire cell, including the data */ + if (!NT_SUCCESS(Status)) CmpFreeValue(Hive, ValueCell); + + /* Return status */ + return Status; +} + +NTSTATUS +NTAPI +CmpSetValueKeyExisting(IN PHHIVE Hive, + IN HCELL_INDEX OldChild, + IN PCM_KEY_VALUE Value, + IN ULONG Type, + IN PVOID Data, + IN ULONG DataSize, + IN ULONG StorageType, + IN ULONG TempData) +{ + HCELL_INDEX DataCell, NewCell; + PCELL_DATA CellData; + ULONG Length; + BOOLEAN WasSmall, IsSmall; + + /* Mark the old child cell dirty */ + HvMarkCellDirty(Hive, OldChild); + + /* See if this is a small or normal key */ + WasSmall = CmpIsKeyValueSmall(&Length, Value->DataLength); + + /* See if our new data can fit in a small key */ + IsSmall = (DataSize <= CM_KEY_VALUE_SMALL) ? TRUE: FALSE; + + /* Big keys are unsupported */ + ASSERT_VALUE_BIG(Hive, Length); + ASSERT_VALUE_BIG(Hive, DataSize); + + /* Mark the old value dirty */ + CmpMarkValueDataDirty(Hive, Value); + + /* Check if we have a small key */ + if (IsSmall) + { + /* Check if we had a normal key with some data in it */ + if (!(WasSmall) && (Length > 0)) + { + /* Free the previous data */ + CmpFreeValueData(Hive, Value->Data, Length); + } + + /* Write our data directly */ + Value->DataLength = DataSize + CM_KEY_VALUE_SPECIAL_SIZE; + Value->Data = TempData; + Value->Type = Type; + return STATUS_SUCCESS; + } + else + { + /* We have a normal key. Was the old cell also normal and had data? */ + if (!(WasSmall) && (Length > 0)) + { + /* Get the current data cell and actual data inside it */ + DataCell = Value->Data; + ASSERT(DataCell != HCELL_NIL); + CellData = HvGetCell(Hive, DataCell); + if (!CellData) return STATUS_INSUFFICIENT_RESOURCES; + + /* Immediately release the cell */ + HvReleaseCell(Hive, DataCell); + + /* Make sure that the data cell actually has a size */ + ASSERT(HvGetCellSize(Hive, CellData) > 0); + + /* Check if the previous data cell could fit our new data */ + if (DataSize <= (ULONG)(HvGetCellSize(Hive, CellData))) + { + /* Re-use it then */ + NewCell = DataCell; + } + else + { + /* Otherwise, re-allocate the current data cell */ + NewCell = HvReallocateCell(Hive, DataCell, DataSize); + if (NewCell == HCELL_NIL) return STATUS_INSUFFICIENT_RESOURCES; + } + } + else + { + /* This was a small key, or a key with no data, allocate a cell */ + NewCell = HvAllocateCell(Hive, DataSize, StorageType); + if (NewCell == HCELL_NIL) return STATUS_INSUFFICIENT_RESOURCES; + } + + /* Now get the actual data for our data cell */ + CellData = HvGetCell(Hive, NewCell); + if (!CellData) ASSERT(FALSE); + + /* Release it immediately */ + HvReleaseCell(Hive, NewCell); + + /* Copy our data into the data cell's buffer, and set up the value */ + RtlCopyMemory(CellData, Data, DataSize); + Value->Data = NewCell; + Value->DataLength = DataSize; + Value->Type = Type; + + /* Return success */ + ASSERT(HvIsCellDirty(Hive, NewCell)); + return STATUS_SUCCESS; + } +} + +NTSTATUS +NTAPI +CmSetValueKey(IN PKEY_OBJECT KeyObject, + IN PUNICODE_STRING ValueName, + IN ULONG Type, + IN PVOID Data, + IN ULONG DataLength) +{ + PHHIVE Hive; + PCM_KEY_NODE Parent; + PCM_KEY_VALUE Value = NULL; + HCELL_INDEX CurrentChild, Cell; + NTSTATUS Status; + BOOLEAN Found, Result; + ULONG Count, ChildIndex, SmallData, Storage; + + /* Acquire hive lock exclusively */ + KeEnterCriticalRegion(); + ExAcquireResourceExclusiveLite(&CmpRegistryLock, TRUE); + + /* Get pointer to key cell */ + Parent = KeyObject->KeyCell; + Hive = &KeyObject->RegistryHive->Hive; + Cell = KeyObject->KeyCellOffset; + + /* Prepare to scan the key node */ + Count = Parent->ValueList.Count; + Found = FALSE; + if (Count > 0) + { + /* Try to find the existing name */ + Result = CmpFindNameInList(Hive, + &Parent->ValueList, + ValueName, + &ChildIndex, + &CurrentChild); + if (!Result) + { + /* Fail */ + Status = STATUS_INSUFFICIENT_RESOURCES; + goto Quickie; + } + + /* Check if we found something */ + if (CurrentChild != HCELL_NIL) + { + /* Get its value */ + Value = (PCM_KEY_VALUE)HvGetCell(Hive, CurrentChild); + if (!Value) + { + /* Fail */ + Status = STATUS_INSUFFICIENT_RESOURCES; + goto Quickie; + } + + /* Remember that we found it */ + Found = TRUE; + } + } + else + { + /* No child list, we'll need to add it */ + ChildIndex = 0; + } + + /* Mark the cell dirty */ + HvMarkCellDirty(Hive, Cell); + + /* Get the storage type */ + Storage = HvGetCellType(Cell); + + /* Check if this is small data */ + SmallData = 0; + if ((DataLength <= CM_KEY_VALUE_SMALL) && (DataLength > 0)) + { + /* Copy it */ + RtlCopyMemory(&SmallData, Data, DataLength); + } + + /* Check if we didn't find a matching key */ + if (!Found) + { + /* Call the internal routine */ + Status = CmpSetValueKeyNew(Hive, + Parent, + ValueName, + ChildIndex, + Type, + Data, + DataLength, + Storage, + SmallData); + } + else + { + /* Call the internal routine */ + Status = CmpSetValueKeyExisting(Hive, + CurrentChild, + Value, + Type, + Data, + DataLength, + Storage, + SmallData); + } + + /* Mark link key */ + if ((Type == REG_LINK) && + (_wcsicmp(ValueName->Buffer, L"SymbolicLinkValue") == 0)) + { + Parent->Flags |= KEY_SYM_LINK; + } + + /* Check for success */ +Quickie: + if (NT_SUCCESS(Status)) + { + /* Save the write time */ + KeQuerySystemTime(&Parent->LastWriteTime); + } + + /* Release the lock */ + ExReleaseResourceLite(&CmpRegistryLock); + KeLeaveCriticalRegion(); + return Status; +} + diff --git a/reactos/ntoskrnl/config/cmvalue.c b/reactos/ntoskrnl/config/cmvalue.c index be39fb4da31..77b2099df76 100644 --- a/reactos/ntoskrnl/config/cmvalue.c +++ b/reactos/ntoskrnl/config/cmvalue.c @@ -56,7 +56,7 @@ CmpFreeValueData(IN PHHIVE Hive, if (DataCell == HCELL_NIL) return TRUE; /* Make sure the data cell is allocated */ - ASSERT(HvIsCellAllocated(Hive, DataCell)); + //ASSERT(HvIsCellAllocated(Hive, DataCell)); /* Unsupported value type */ ASSERT_VALUE_BIG(Hive, KeySize); diff --git a/reactos/ntoskrnl/ntoskrnl.rbuild b/reactos/ntoskrnl/ntoskrnl.rbuild index 958d526e9be..1a90add0f38 100644 --- a/reactos/ntoskrnl/ntoskrnl.rbuild +++ b/reactos/ntoskrnl/ntoskrnl.rbuild @@ -89,6 +89,7 @@ cmhardwr.c + cmapi.c cmboot.c cmcheck.c cmcontrl.c