- 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:
Alex Ionescu 2007-05-13 18:39:35 +00:00
parent 39932ced34
commit cfb706a690
8 changed files with 423 additions and 366 deletions

View file

@ -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);

View file

@ -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,

View file

@ -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)

View file

@ -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,

View file

@ -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
//

View 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;
}

View file

@ -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);

View file

@ -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>