mirror of
https://github.com/reactos/reactos.git
synced 2025-01-15 08:03:53 +08:00
- HvGetCellSize should return the correct positive length instead of the raw negative length. Update code and callers to match.
- Add cmapi.c file containing internal Cm* APIs for the Nt counterparts and to make it easier to seperate the handle->object code, SEH and callback parts. - Remove CmiAddValueToKey, CmiAllocateValueCell since we have new routines for this. - Make NtSetValueKey a simple wrapper around CmSetValueKey. - Implement CmSetValueKey based on previous code, but use newer Cm APIs instead (this also fixes some cell allocation bugs regarding Stable/Volatile storage). - New code is more conservative with HvMakeCellDirty calls when they're not needed, and is more scalable to support big cells in the future. svn path=/trunk/; revision=26760
This commit is contained in:
parent
39932ced34
commit
cfb706a690
@ -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);
|
||||
|
||||
|
@ -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,
|
||||
|
@ -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)
|
||||
|
@ -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,
|
||||
|
@ -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
|
||||
//
|
||||
|
342
reactos/ntoskrnl/config/cmapi.c
Normal file
342
reactos/ntoskrnl/config/cmapi.c
Normal file
@ -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;
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -89,6 +89,7 @@
|
||||
<file>cmhardwr.c</file>
|
||||
</directory>
|
||||
</if>
|
||||
<file>cmapi.c</file>
|
||||
<file>cmboot.c</file>
|
||||
<file>cmcheck.c</file>
|
||||
<file>cmcontrl.c</file>
|
||||
|
Loading…
Reference in New Issue
Block a user