mirror of
https://github.com/reactos/reactos.git
synced 2024-07-21 11:48:04 +00: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
|
LONG CMAPI
|
||||||
HvGetCellSize(
|
HvGetCellSize(IN PHHIVE Hive,
|
||||||
PHHIVE RegistryHive,
|
IN PVOID Address)
|
||||||
PVOID Cell)
|
|
||||||
{
|
{
|
||||||
PHCELL CellHeader;
|
PHCELL CellHeader;
|
||||||
|
LONG Size;
|
||||||
|
|
||||||
CellHeader = (PHCELL)Cell - 1;
|
CellHeader = (PHCELL)Address - 1;
|
||||||
if (CellHeader->Size < 0)
|
Size = CellHeader->Size * -1;
|
||||||
return CellHeader->Size + sizeof(HCELL);
|
Size -= sizeof(HCELL);
|
||||||
else
|
return Size;
|
||||||
return CellHeader->Size - sizeof(HCELL);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
VOID CMAPI
|
VOID CMAPI
|
||||||
|
@ -375,8 +374,8 @@ HvReallocateCell(
|
||||||
|
|
||||||
OldCell = HvGetCell(RegistryHive, CellIndex);
|
OldCell = HvGetCell(RegistryHive, CellIndex);
|
||||||
OldCellSize = HvGetCellSize(RegistryHive, OldCell);
|
OldCellSize = HvGetCellSize(RegistryHive, OldCell);
|
||||||
ASSERT(OldCellSize < 0);
|
ASSERT(OldCellSize > 0);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If new data size is larger than the current, destroy current
|
* If new data size is larger than the current, destroy current
|
||||||
* data block and allocate a new one.
|
* data block and allocate a new one.
|
||||||
|
@ -384,14 +383,14 @@ HvReallocateCell(
|
||||||
* FIXME: Merge with adjacent free cell if possible.
|
* FIXME: Merge with adjacent free cell if possible.
|
||||||
* FIXME: Implement shrinking.
|
* FIXME: Implement shrinking.
|
||||||
*/
|
*/
|
||||||
if (Size > (ULONG)-OldCellSize)
|
if (Size > OldCellSize)
|
||||||
{
|
{
|
||||||
NewCellIndex = HvAllocateCell(RegistryHive, Size, Storage);
|
NewCellIndex = HvAllocateCell(RegistryHive, Size, Storage);
|
||||||
if (NewCellIndex == HCELL_NULL)
|
if (NewCellIndex == HCELL_NULL)
|
||||||
return HCELL_NULL;
|
return HCELL_NULL;
|
||||||
|
|
||||||
NewCell = HvGetCell(RegistryHive, NewCellIndex);
|
NewCell = HvGetCell(RegistryHive, NewCellIndex);
|
||||||
RtlCopyMemory(NewCell, OldCell, (SIZE_T)-OldCellSize);
|
RtlCopyMemory(NewCell, OldCell, (SIZE_T)OldCellSize);
|
||||||
|
|
||||||
HvFreeCell(RegistryHive, CellIndex);
|
HvFreeCell(RegistryHive, CellIndex);
|
||||||
|
|
||||||
|
|
|
@ -260,14 +260,6 @@ CmiGetValueFromKeyByIndex(IN PEREGISTRY_HIVE RegistryHive,
|
||||||
IN ULONG Index,
|
IN ULONG Index,
|
||||||
OUT PCM_KEY_VALUE *ValueCell);
|
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
|
NTSTATUS
|
||||||
CmiDeleteValueFromKey(IN PEREGISTRY_HIVE RegistryHive,
|
CmiDeleteValueFromKey(IN PEREGISTRY_HIVE RegistryHive,
|
||||||
IN PCM_KEY_NODE KeyCell,
|
IN PCM_KEY_NODE KeyCell,
|
||||||
|
@ -294,18 +286,19 @@ CmiAddKeyToHashTable(PEREGISTRY_HIVE RegistryHive,
|
||||||
PCM_KEY_NODE NewKeyCell,
|
PCM_KEY_NODE NewKeyCell,
|
||||||
HCELL_INDEX NKBOffset);
|
HCELL_INDEX NKBOffset);
|
||||||
|
|
||||||
|
NTSTATUS
|
||||||
|
NTAPI
|
||||||
|
CmSetValueKey(IN PKEY_OBJECT KeyObject,
|
||||||
|
IN PUNICODE_STRING ValueName,
|
||||||
|
IN ULONG Type,
|
||||||
|
IN PVOID Data,
|
||||||
|
IN ULONG DataSize);
|
||||||
|
|
||||||
NTSTATUS
|
NTSTATUS
|
||||||
CmiRemoveKeyFromHashTable(PEREGISTRY_HIVE RegistryHive,
|
CmiRemoveKeyFromHashTable(PEREGISTRY_HIVE RegistryHive,
|
||||||
PHASH_TABLE_CELL HashBlock,
|
PHASH_TABLE_CELL HashBlock,
|
||||||
HCELL_INDEX NKBOffset);
|
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
|
NTSTATUS
|
||||||
CmiDestroyValueCell(PEREGISTRY_HIVE RegistryHive,
|
CmiDestroyValueCell(PEREGISTRY_HIVE RegistryHive,
|
||||||
PCM_KEY_VALUE ValueCell,
|
PCM_KEY_VALUE ValueCell,
|
||||||
|
|
|
@ -1799,194 +1799,61 @@ ByeBye:;
|
||||||
return Status;
|
return Status;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
NTSTATUS
|
||||||
NTSTATUS STDCALL
|
NTAPI
|
||||||
NtSetValueKey(IN HANDLE KeyHandle,
|
NtSetValueKey(IN HANDLE KeyHandle,
|
||||||
IN PUNICODE_STRING ValueName,
|
IN PUNICODE_STRING ValueName,
|
||||||
IN ULONG TitleIndex,
|
IN ULONG TitleIndex,
|
||||||
IN ULONG Type,
|
IN ULONG Type,
|
||||||
IN PVOID Data,
|
IN PVOID Data,
|
||||||
IN ULONG DataSize)
|
IN ULONG DataSize)
|
||||||
{
|
{
|
||||||
NTSTATUS Status;
|
NTSTATUS Status;
|
||||||
PKEY_OBJECT KeyObject;
|
PKEY_OBJECT KeyObject;
|
||||||
PEREGISTRY_HIVE RegistryHive;
|
REG_SET_VALUE_KEY_INFORMATION SetValueKeyInfo;
|
||||||
PCM_KEY_NODE KeyCell;
|
REG_POST_OPERATION_INFORMATION PostOperationInfo;
|
||||||
PCM_KEY_VALUE ValueCell;
|
PAGED_CODE();
|
||||||
HCELL_INDEX ValueCellOffset;
|
|
||||||
PVOID DataCell;
|
|
||||||
ULONG DesiredAccess;
|
|
||||||
REG_SET_VALUE_KEY_INFORMATION SetValueKeyInfo;
|
|
||||||
REG_POST_OPERATION_INFORMATION PostOperationInfo;
|
|
||||||
ULONG DataCellSize;
|
|
||||||
|
|
||||||
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",
|
/* Setup callback */
|
||||||
KeyHandle, ValueName, Type);
|
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;
|
/* Do the callback */
|
||||||
|
Status = CmiCallRegisteredCallbacks(RegNtPreSetValueKey, &SetValueKeyInfo);
|
||||||
/* Verify that the handle is valid and is a registry key */
|
if (NT_SUCCESS(Status))
|
||||||
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))
|
|
||||||
{
|
{
|
||||||
PostOperationInfo.Status = Status;
|
/* Call the internal API */
|
||||||
CmiCallRegisteredCallbacks(RegNtPostSetValueKey, &PostOperationInfo);
|
Status = CmSetValueKey(KeyObject,
|
||||||
ObDereferenceObject(KeyObject);
|
ValueName,
|
||||||
return Status;
|
Type,
|
||||||
|
Data,
|
||||||
|
DataSize);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Acquire hive lock exclucively */
|
/* Do the post-callback and de-reference the key object */
|
||||||
KeEnterCriticalRegion();
|
PostOperationInfo.Status = Status;
|
||||||
ExAcquireResourceExclusiveLite(&CmpRegistryLock, TRUE);
|
CmiCallRegisteredCallbacks(RegNtPostSetValueKey, &PostOperationInfo);
|
||||||
|
ObDereferenceObject(KeyObject);
|
||||||
|
|
||||||
VERIFY_KEY_OBJECT(KeyObject);
|
/* Synchronize the hives and return */
|
||||||
|
CmiSyncHives();
|
||||||
/* Get pointer to key cell */
|
return Status;
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
NTSTATUS STDCALL
|
NTSTATUS STDCALL
|
||||||
NtDeleteValueKey (IN HANDLE KeyHandle,
|
NtDeleteValueKey (IN HANDLE KeyHandle,
|
||||||
IN PUNICODE_STRING ValueName)
|
IN PUNICODE_STRING ValueName)
|
||||||
|
|
|
@ -59,22 +59,6 @@ CmiLoadHive(IN POBJECT_ATTRIBUTES KeyObjectAttributes,
|
||||||
return Status;
|
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
|
VOID
|
||||||
CmCloseHiveFiles(PEREGISTRY_HIVE RegistryHive)
|
CmCloseHiveFiles(PEREGISTRY_HIVE RegistryHive)
|
||||||
{
|
{
|
||||||
|
@ -680,93 +664,6 @@ CmiGetValueFromKeyByIndex(IN PEREGISTRY_HIVE RegistryHive,
|
||||||
return STATUS_SUCCESS;
|
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
|
NTSTATUS
|
||||||
CmiDeleteValueFromKey(IN PEREGISTRY_HIVE RegistryHive,
|
CmiDeleteValueFromKey(IN PEREGISTRY_HIVE RegistryHive,
|
||||||
IN PCM_KEY_NODE KeyCell,
|
IN PCM_KEY_NODE KeyCell,
|
||||||
|
@ -934,63 +831,6 @@ CmiRemoveKeyFromHashTable(PEREGISTRY_HIVE RegistryHive,
|
||||||
return STATUS_UNSUCCESSFUL;
|
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
|
NTSTATUS
|
||||||
CmiDestroyValueCell(PEREGISTRY_HIVE RegistryHive,
|
CmiDestroyValueCell(PEREGISTRY_HIVE RegistryHive,
|
||||||
PCM_KEY_VALUE ValueCell,
|
PCM_KEY_VALUE ValueCell,
|
||||||
|
|
|
@ -1049,6 +1049,21 @@ CmpFreeValue(
|
||||||
IN HCELL_INDEX Cell
|
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
|
// 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;
|
if (DataCell == HCELL_NIL) return TRUE;
|
||||||
|
|
||||||
/* Make sure the data cell is allocated */
|
/* Make sure the data cell is allocated */
|
||||||
ASSERT(HvIsCellAllocated(Hive, DataCell));
|
//ASSERT(HvIsCellAllocated(Hive, DataCell));
|
||||||
|
|
||||||
/* Unsupported value type */
|
/* Unsupported value type */
|
||||||
ASSERT_VALUE_BIG(Hive, KeySize);
|
ASSERT_VALUE_BIG(Hive, KeySize);
|
||||||
|
|
|
@ -89,6 +89,7 @@
|
||||||
<file>cmhardwr.c</file>
|
<file>cmhardwr.c</file>
|
||||||
</directory>
|
</directory>
|
||||||
</if>
|
</if>
|
||||||
|
<file>cmapi.c</file>
|
||||||
<file>cmboot.c</file>
|
<file>cmboot.c</file>
|
||||||
<file>cmcheck.c</file>
|
<file>cmcheck.c</file>
|
||||||
<file>cmcontrl.c</file>
|
<file>cmcontrl.c</file>
|
||||||
|
|
Loading…
Reference in a new issue