mirror of
https://github.com/reactos/reactos.git
synced 2025-08-04 00:25:41 +00:00
- Last part of Alex's work on CM before he left ReactOS development. It was unfinished, so I had to insert a few hacks and comment out some code to make it working in trunk.
- Implement subkey creation code (for NtCreateKey and CmiConnectHive) based on the new Cm branch code (just as all the other routines were changed previously). - Also support creating hash leaves, used in XP hives, since all the new code was already able to read them. svn path=/trunk/; revision=28292
This commit is contained in:
parent
edaf84b215
commit
8dae7ddffe
5 changed files with 766 additions and 79 deletions
|
@ -294,6 +294,21 @@ CmiConnectHive(POBJECT_ATTRIBUTES KeyObjectAttributes,
|
||||||
NTSTATUS
|
NTSTATUS
|
||||||
CmiInitHives(BOOLEAN SetupBoot);
|
CmiInitHives(BOOLEAN SetupBoot);
|
||||||
|
|
||||||
|
NTSTATUS
|
||||||
|
NTAPI
|
||||||
|
CmpDoCreate(
|
||||||
|
IN PHHIVE Hive,
|
||||||
|
IN HCELL_INDEX Cell,
|
||||||
|
IN PACCESS_STATE AccessState,
|
||||||
|
IN PUNICODE_STRING Name,
|
||||||
|
IN KPROCESSOR_MODE AccessMode,
|
||||||
|
IN PUNICODE_STRING Class,
|
||||||
|
IN ULONG CreateOptions,
|
||||||
|
IN PKEY_OBJECT Parent,
|
||||||
|
IN PVOID OriginatingHive OPTIONAL,
|
||||||
|
OUT PVOID *Object
|
||||||
|
);
|
||||||
|
|
||||||
HCELL_INDEX
|
HCELL_INDEX
|
||||||
NTAPI
|
NTAPI
|
||||||
CmpFindValueByName(
|
CmpFindValueByName(
|
||||||
|
|
|
@ -138,7 +138,6 @@ NtCreateKey(OUT PHANDLE KeyHandle,
|
||||||
OUT PULONG Disposition)
|
OUT PULONG Disposition)
|
||||||
{
|
{
|
||||||
UNICODE_STRING RemainingPath = {0};
|
UNICODE_STRING RemainingPath = {0};
|
||||||
BOOLEAN FreeRemainingPath = TRUE;
|
|
||||||
ULONG LocalDisposition;
|
ULONG LocalDisposition;
|
||||||
PKEY_OBJECT KeyObject;
|
PKEY_OBJECT KeyObject;
|
||||||
NTSTATUS Status = STATUS_SUCCESS;
|
NTSTATUS Status = STATUS_SUCCESS;
|
||||||
|
@ -303,53 +302,27 @@ NtCreateKey(OUT PHANDLE KeyHandle,
|
||||||
|
|
||||||
DPRINT("RemainingPath %S ParentObject 0x%p\n", RemainingPath.Buffer, Object);
|
DPRINT("RemainingPath %S ParentObject 0x%p\n", RemainingPath.Buffer, Object);
|
||||||
|
|
||||||
Status = ObCreateObject(PreviousMode,
|
|
||||||
CmpKeyObjectType,
|
|
||||||
NULL,
|
|
||||||
PreviousMode,
|
|
||||||
NULL,
|
|
||||||
sizeof(KEY_OBJECT),
|
|
||||||
0,
|
|
||||||
0,
|
|
||||||
(PVOID*)&KeyObject);
|
|
||||||
if (!NT_SUCCESS(Status))
|
|
||||||
{
|
|
||||||
DPRINT1("ObCreateObject() failed!\n");
|
|
||||||
PostCreateKeyInfo.Object = NULL;
|
|
||||||
PostCreateKeyInfo.Status = Status;
|
|
||||||
CmiCallRegisteredCallbacks(RegNtPostCreateKey, &PostCreateKeyInfo);
|
|
||||||
|
|
||||||
goto Cleanup;
|
|
||||||
}
|
|
||||||
|
|
||||||
KeyObject->ParentKey = Object;
|
|
||||||
KeyObject->RegistryHive = KeyObject->ParentKey->RegistryHive;
|
|
||||||
KeyObject->Flags = 0;
|
|
||||||
KeyObject->SubKeyCounts = 0;
|
|
||||||
KeyObject->SizeOfSubKeys = 0;
|
|
||||||
KeyObject->SubKeys = NULL;
|
|
||||||
|
|
||||||
/* Acquire hive lock */
|
/* Acquire hive lock */
|
||||||
KeEnterCriticalRegion();
|
KeEnterCriticalRegion();
|
||||||
ExAcquireResourceExclusiveLite(&CmpRegistryLock, TRUE);
|
ExAcquireResourceExclusiveLite(&CmpRegistryLock, TRUE);
|
||||||
|
|
||||||
InsertTailList(&CmiKeyObjectListHead, &KeyObject->ListEntry);
|
/* Create the key */
|
||||||
|
Status = CmpDoCreate(&((PKEY_OBJECT)Object)->RegistryHive->Hive,
|
||||||
/* add key to subkeys of parent if needed */
|
((PKEY_OBJECT)Object)->KeyCellOffset,
|
||||||
Status = CmiAddSubKey(KeyObject->RegistryHive,
|
NULL,
|
||||||
KeyObject->ParentKey,
|
&RemainingPath,
|
||||||
KeyObject,
|
KernelMode,
|
||||||
&RemainingPath,
|
Class,
|
||||||
TitleIndex,
|
CreateOptions,
|
||||||
&CapturedClass,
|
(PKEY_OBJECT)Object,
|
||||||
CreateOptions);
|
NULL,
|
||||||
|
(PVOID*)&KeyObject);
|
||||||
if (!NT_SUCCESS(Status))
|
if (!NT_SUCCESS(Status))
|
||||||
{
|
{
|
||||||
DPRINT1("CmiAddSubKey() failed (Status %lx)\n", Status);
|
DPRINT1("CmiAddSubKey() failed (Status %lx)\n", Status);
|
||||||
/* Release hive lock */
|
/* Release hive lock */
|
||||||
ExReleaseResourceLite(&CmpRegistryLock);
|
ExReleaseResourceLite(&CmpRegistryLock);
|
||||||
KeLeaveCriticalRegion();
|
KeLeaveCriticalRegion();
|
||||||
ObDereferenceObject(KeyObject);
|
|
||||||
|
|
||||||
PostCreateKeyInfo.Object = NULL;
|
PostCreateKeyInfo.Object = NULL;
|
||||||
PostCreateKeyInfo.Status = STATUS_UNSUCCESSFUL;
|
PostCreateKeyInfo.Status = STATUS_UNSUCCESSFUL;
|
||||||
|
@ -359,15 +332,8 @@ NtCreateKey(OUT PHANDLE KeyHandle,
|
||||||
goto Cleanup;
|
goto Cleanup;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Start == RemainingPath.Buffer)
|
InsertTailList(&CmiKeyObjectListHead, &KeyObject->ListEntry);
|
||||||
{
|
RtlCreateUnicodeString(&KeyObject->Name, Start);
|
||||||
KeyObject->Name = RemainingPath;
|
|
||||||
FreeRemainingPath = FALSE;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
RtlCreateUnicodeString(&KeyObject->Name, Start);
|
|
||||||
}
|
|
||||||
|
|
||||||
KeyObject->KeyCell->Parent = KeyObject->ParentKey->KeyCellOffset;
|
KeyObject->KeyCell->Parent = KeyObject->ParentKey->KeyCellOffset;
|
||||||
KeyObject->KeyCell->SecurityKeyOffset = KeyObject->ParentKey->KeyCell->SecurityKeyOffset;
|
KeyObject->KeyCell->SecurityKeyOffset = KeyObject->ParentKey->KeyCell->SecurityKeyOffset;
|
||||||
|
@ -437,7 +403,7 @@ Cleanup:
|
||||||
PreviousMode);
|
PreviousMode);
|
||||||
}
|
}
|
||||||
if (ObjectName.Buffer) ObpFreeObjectNameBuffer(&ObjectName);
|
if (ObjectName.Buffer) ObpFreeObjectNameBuffer(&ObjectName);
|
||||||
if (FreeRemainingPath) RtlFreeUnicodeString(&RemainingPath);
|
RtlFreeUnicodeString(&RemainingPath);
|
||||||
if (Object != NULL) ObDereferenceObject(Object);
|
if (Object != NULL) ObDereferenceObject(Object);
|
||||||
|
|
||||||
return Status;
|
return Status;
|
||||||
|
|
|
@ -263,39 +263,19 @@ CmiConnectHive(IN POBJECT_ATTRIBUTES KeyObjectAttributes,
|
||||||
DPRINT("RemainingPath %wZ ParentKey %p\n",
|
DPRINT("RemainingPath %wZ ParentKey %p\n",
|
||||||
&RemainingPath, ParentKey);
|
&RemainingPath, ParentKey);
|
||||||
|
|
||||||
Status = ObCreateObject(KernelMode,
|
|
||||||
CmpKeyObjectType,
|
|
||||||
NULL,
|
|
||||||
KernelMode,
|
|
||||||
NULL,
|
|
||||||
sizeof(KEY_OBJECT),
|
|
||||||
0,
|
|
||||||
0,
|
|
||||||
(PVOID*)&NewKey);
|
|
||||||
|
|
||||||
if (!NT_SUCCESS(Status))
|
|
||||||
{
|
|
||||||
DPRINT1 ("ObCreateObject() failed (Status %lx)\n", Status);
|
|
||||||
ObDereferenceObject (ParentKey);
|
|
||||||
RtlFreeUnicodeString(&RemainingPath);
|
|
||||||
return Status;
|
|
||||||
}
|
|
||||||
|
|
||||||
NewKey->Flags = 0;
|
|
||||||
NewKey->SubKeyCounts = 0;
|
|
||||||
NewKey->SubKeys = NULL;
|
|
||||||
NewKey->SizeOfSubKeys = 0;
|
|
||||||
InsertTailList(&CmiKeyObjectListHead, &NewKey->ListEntry);
|
|
||||||
|
|
||||||
DPRINT ("SubName %S\n", SubName);
|
DPRINT ("SubName %S\n", SubName);
|
||||||
|
|
||||||
Status = CmiAddSubKey(ParentKey->RegistryHive,
|
/* Create the key */
|
||||||
ParentKey,
|
Status = CmpDoCreate(&ParentKey->RegistryHive->Hive,
|
||||||
NewKey,
|
ParentKey->KeyCellOffset,
|
||||||
&RemainingPath,
|
NULL,
|
||||||
0,
|
&RemainingPath,
|
||||||
NULL,
|
KernelMode,
|
||||||
REG_OPTION_VOLATILE);
|
NULL,
|
||||||
|
REG_OPTION_VOLATILE,
|
||||||
|
ParentKey,
|
||||||
|
NULL,
|
||||||
|
(PVOID*)&NewKey);
|
||||||
if (!NT_SUCCESS(Status))
|
if (!NT_SUCCESS(Status))
|
||||||
{
|
{
|
||||||
DPRINT1("CmiAddSubKey() failed (Status %lx)\n", Status);
|
DPRINT1("CmiAddSubKey() failed (Status %lx)\n", Status);
|
||||||
|
|
|
@ -15,6 +15,16 @@
|
||||||
|
|
||||||
/* GLOBALS *******************************************************************/
|
/* GLOBALS *******************************************************************/
|
||||||
|
|
||||||
|
ULONG CmpMaxFastIndexPerHblock =
|
||||||
|
(HBLOCK_SIZE - (sizeof(HBIN) +
|
||||||
|
sizeof(HCELL) +
|
||||||
|
FIELD_OFFSET(CM_KEY_FAST_INDEX, List))) / sizeof(CM_INDEX);
|
||||||
|
|
||||||
|
ULONG CmpMaxIndexPerHblock =
|
||||||
|
(HBLOCK_SIZE - (sizeof(HBIN) +
|
||||||
|
sizeof(HCELL) +
|
||||||
|
FIELD_OFFSET(CM_KEY_INDEX, List))) / sizeof(HCELL_INDEX) - 1;
|
||||||
|
|
||||||
/* FUNCTIONS *****************************************************************/
|
/* FUNCTIONS *****************************************************************/
|
||||||
|
|
||||||
LONG
|
LONG
|
||||||
|
@ -924,6 +934,396 @@ Quickie:
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
HCELL_INDEX
|
||||||
|
NTAPI
|
||||||
|
CmpAddToLeaf(IN PHHIVE Hive,
|
||||||
|
IN HCELL_INDEX LeafCell,
|
||||||
|
IN HCELL_INDEX NewKey,
|
||||||
|
IN PUNICODE_STRING Name)
|
||||||
|
{
|
||||||
|
PCM_KEY_INDEX Leaf;
|
||||||
|
PCM_KEY_FAST_INDEX FastLeaf;
|
||||||
|
ULONG Size, OldSize, EntrySize, i, j;
|
||||||
|
HCELL_INDEX NewCell, Child;
|
||||||
|
LONG Result;
|
||||||
|
|
||||||
|
/* Mark the leaf dirty */
|
||||||
|
HvMarkCellDirty(Hive, LeafCell);
|
||||||
|
|
||||||
|
/* Get the leaf cell */
|
||||||
|
Leaf = (PCM_KEY_INDEX)HvGetCell(Hive, LeafCell);
|
||||||
|
if (!Leaf)
|
||||||
|
{
|
||||||
|
/* Shouldn't happen */
|
||||||
|
ASSERT(FALSE);
|
||||||
|
return HCELL_NIL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Release it */
|
||||||
|
HvReleaseCell(Hive, LeafCell);
|
||||||
|
|
||||||
|
/* Check if this is an index leaf */
|
||||||
|
if (Leaf->Signature == CM_KEY_INDEX_LEAF)
|
||||||
|
{
|
||||||
|
/* This is an old-style leaf */
|
||||||
|
FastLeaf = NULL;
|
||||||
|
EntrySize = sizeof(HCELL_INDEX);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* Sanity check */
|
||||||
|
ASSERT((Leaf->Signature == CM_KEY_FAST_LEAF) ||
|
||||||
|
(Leaf->Signature == CM_KEY_HASH_LEAF));
|
||||||
|
|
||||||
|
/* This is a new-style optimized fast (or hash) leaf */
|
||||||
|
FastLeaf = (PCM_KEY_FAST_INDEX)Leaf;
|
||||||
|
EntrySize = sizeof(CM_INDEX);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Get the current size of the leaf */
|
||||||
|
OldSize = HvGetCellSize(Hive, Leaf);
|
||||||
|
|
||||||
|
/* Calculate the size of the free entries */
|
||||||
|
Size = OldSize;
|
||||||
|
Size -= EntrySize * Leaf->Count + FIELD_OFFSET(CM_KEY_INDEX, List);
|
||||||
|
|
||||||
|
/* Assume we'll re-use the same leaf */
|
||||||
|
NewCell = LeafCell;
|
||||||
|
|
||||||
|
/* Check if we're out of space */
|
||||||
|
if ((Size / EntrySize) < 1)
|
||||||
|
{
|
||||||
|
/* Grow the leaf by 1.5x, making sure we can at least fit this entry */
|
||||||
|
Size = OldSize + OldSize / 2;
|
||||||
|
if (Size < (OldSize + EntrySize)) Size = OldSize + EntrySize;
|
||||||
|
|
||||||
|
/* Re-allocate the leaf */
|
||||||
|
NewCell = HvReallocateCell(Hive, LeafCell, Size);
|
||||||
|
if (NewCell == HCELL_NIL) return HCELL_NIL;
|
||||||
|
|
||||||
|
/* Get the leaf cell */
|
||||||
|
Leaf = (PCM_KEY_INDEX)HvGetCell(Hive, NewCell);
|
||||||
|
if (!Leaf)
|
||||||
|
{
|
||||||
|
/* This shouldn't happen */
|
||||||
|
ASSERT(FALSE);
|
||||||
|
return HCELL_NIL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Release the cell */
|
||||||
|
HvReleaseCell(Hive, NewCell);
|
||||||
|
|
||||||
|
/* Update the fast leaf pointer if we had one */
|
||||||
|
if (FastLeaf) FastLeaf = (PCM_KEY_FAST_INDEX)Leaf;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Find the insertion point for our entry */
|
||||||
|
i = CmpFindSubKeyInLeaf(Hive, Leaf, Name, &Child);
|
||||||
|
if (i & 0x80000000) return HCELL_NIL;
|
||||||
|
ASSERT(Child == HCELL_NIL);
|
||||||
|
|
||||||
|
/* Check if we're not last */
|
||||||
|
if (i != Leaf->Count)
|
||||||
|
{
|
||||||
|
/* Find out where we should go */
|
||||||
|
Result = CmpCompareInIndex(Hive,
|
||||||
|
Name,
|
||||||
|
i,
|
||||||
|
Leaf,
|
||||||
|
&Child);
|
||||||
|
if (Result == 2) return HCELL_NIL;
|
||||||
|
ASSERT(Result != 0);
|
||||||
|
|
||||||
|
/* Check if we come after */
|
||||||
|
if (Result > 0)
|
||||||
|
{
|
||||||
|
/* We do, insert us after the key */
|
||||||
|
ASSERT(Result == 1);
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Check if we're still not last */
|
||||||
|
if (i != Leaf->Count)
|
||||||
|
{
|
||||||
|
/* Check if we had a fast leaf or not */
|
||||||
|
if (FastLeaf)
|
||||||
|
{
|
||||||
|
/* Copy the fast indexes */
|
||||||
|
RtlMoveMemory(&FastLeaf->List[i + 1],
|
||||||
|
&FastLeaf->List[i],
|
||||||
|
(FastLeaf->Count - i) * sizeof(CM_INDEX));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* Copy the indexes themselves */
|
||||||
|
RtlMoveMemory(&Leaf->List[i + 1],
|
||||||
|
&Leaf->List[i],
|
||||||
|
(Leaf->Count - i) * sizeof(HCELL_INDEX));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Check if this is a new-style leaf */
|
||||||
|
if (FastLeaf)
|
||||||
|
{
|
||||||
|
/* Set our cell */
|
||||||
|
FastLeaf->List[i].Cell = NewKey;
|
||||||
|
|
||||||
|
/* Check if this is a hash leaf */
|
||||||
|
if( FastLeaf->Signature == CM_KEY_HASH_LEAF )
|
||||||
|
{
|
||||||
|
/* Set our hash key */
|
||||||
|
FastLeaf->List[i].HashKey = CmpComputeHashKey(0, Name, FALSE);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* First, clear the name */
|
||||||
|
FastLeaf->List[i].NameHint[0] = 0;
|
||||||
|
FastLeaf->List[i].NameHint[1] = 0;
|
||||||
|
FastLeaf->List[i].NameHint[2] = 0;
|
||||||
|
FastLeaf->List[i].NameHint[3] = 0;
|
||||||
|
|
||||||
|
/* Now, figure out if we can fit */
|
||||||
|
if (Name->Length / sizeof(WCHAR) < 4)
|
||||||
|
{
|
||||||
|
/* We can fit, use our length */
|
||||||
|
j = Name->Length / sizeof(WCHAR);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* We can't, use a maximum of 4 */
|
||||||
|
j = 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Now fill out the name hint */
|
||||||
|
do
|
||||||
|
{
|
||||||
|
/* Look for invalid characters and break out if we found one */
|
||||||
|
if ((USHORT)Name->Buffer[j - 1] > (UCHAR)-1) break;
|
||||||
|
|
||||||
|
/* Otherwise, copy the a character */
|
||||||
|
FastLeaf->List[i].NameHint[j - 1] = (UCHAR)Name->Buffer[j - 1];
|
||||||
|
} while (--j > 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* This is an old-style leaf, just set our index directly */
|
||||||
|
Leaf->List[i] = NewKey;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Update the leaf count and return the new cell */
|
||||||
|
Leaf->Count += 1;
|
||||||
|
return NewCell;
|
||||||
|
}
|
||||||
|
|
||||||
|
BOOLEAN
|
||||||
|
NTAPI
|
||||||
|
CmpAddSubKey(IN PHHIVE Hive,
|
||||||
|
IN HCELL_INDEX Parent,
|
||||||
|
IN HCELL_INDEX Child)
|
||||||
|
{
|
||||||
|
PCM_KEY_NODE KeyNode;
|
||||||
|
PCM_KEY_INDEX Index;
|
||||||
|
UNICODE_STRING Name;
|
||||||
|
HCELL_INDEX IndexCell = HCELL_NIL, CellToRelease = HCELL_NIL, LeafCell;
|
||||||
|
PHCELL_INDEX RootPointer = NULL;
|
||||||
|
ULONG Type;
|
||||||
|
BOOLEAN IsCompressed;
|
||||||
|
PAGED_CODE();
|
||||||
|
|
||||||
|
/* Get the key node */
|
||||||
|
KeyNode = (PCM_KEY_NODE)HvGetCell(Hive, Child);
|
||||||
|
if (!KeyNode)
|
||||||
|
{
|
||||||
|
/* Shouldn't happen */
|
||||||
|
ASSERT(FALSE);
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Check if the name is compressed */
|
||||||
|
if (KeyNode->Flags & KEY_COMP_NAME)
|
||||||
|
{
|
||||||
|
/* Remember for later */
|
||||||
|
IsCompressed = TRUE;
|
||||||
|
|
||||||
|
/* Create the compressed name and allocate it */
|
||||||
|
Name.Length = CmpCompressedNameSize(KeyNode->Name, KeyNode->NameLength);
|
||||||
|
Name.MaximumLength = Name.Length;
|
||||||
|
Name.Buffer = Hive->Allocate(Name.Length, TRUE);
|
||||||
|
if (!Name.Buffer)
|
||||||
|
{
|
||||||
|
/* Release the cell and fail */
|
||||||
|
HvReleaseCell(Hive, Child);
|
||||||
|
ASSERT(FALSE);
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Copy the compressed name */
|
||||||
|
CmpCopyCompressedName(Name.Buffer,
|
||||||
|
Name.MaximumLength,
|
||||||
|
KeyNode->Name,
|
||||||
|
KeyNode->NameLength);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* Remember for later */
|
||||||
|
IsCompressed = FALSE;
|
||||||
|
|
||||||
|
/* Build the unicode string */
|
||||||
|
Name.Length = KeyNode->NameLength;
|
||||||
|
Name.MaximumLength = KeyNode->NameLength;
|
||||||
|
Name.Buffer = &KeyNode->Name[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Release the cell */
|
||||||
|
HvReleaseCell(Hive, Child);
|
||||||
|
|
||||||
|
/* Get the parent node */
|
||||||
|
KeyNode = (PCM_KEY_NODE)HvGetCell(Hive, Parent);
|
||||||
|
if (!KeyNode)
|
||||||
|
{
|
||||||
|
/* Not handled */
|
||||||
|
ASSERT(FALSE);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Find out the type of the cell, and check if this is the first subkey */
|
||||||
|
Type = HvGetCellType(Child);
|
||||||
|
if (!KeyNode->SubKeyCounts[Type])
|
||||||
|
{
|
||||||
|
/* Allocate a fast leaf */
|
||||||
|
IndexCell = HvAllocateCell(Hive, sizeof(CM_KEY_FAST_INDEX), Type);
|
||||||
|
if (IndexCell == HCELL_NIL)
|
||||||
|
{
|
||||||
|
/* Not handled */
|
||||||
|
ASSERT(FALSE);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Get the leaf cell */
|
||||||
|
Index = (PCM_KEY_INDEX)HvGetCell(Hive, IndexCell);
|
||||||
|
if (!Index)
|
||||||
|
{
|
||||||
|
/* Shouldn't happen */
|
||||||
|
ASSERT(FALSE);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Now check what kind of hive we're dealing with */
|
||||||
|
if (Hive->Version >= 5)
|
||||||
|
{
|
||||||
|
/* XP Hive: Use hash leaf */
|
||||||
|
Index->Signature = CM_KEY_HASH_LEAF;
|
||||||
|
}
|
||||||
|
else if (Hive->Version >= 3)
|
||||||
|
{
|
||||||
|
/* Windows 2000 and ReactOS: Use fast leaf */
|
||||||
|
Index->Signature = CM_KEY_FAST_LEAF;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* NT 4: Use index leaf */
|
||||||
|
Index->Signature = CM_KEY_INDEX_LEAF;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Setup the index list */
|
||||||
|
Index->Count = 0;
|
||||||
|
KeyNode->SubKeyLists[Type] = IndexCell;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* We already have an index, get it */
|
||||||
|
Index = (PCM_KEY_INDEX)HvGetCell(Hive, KeyNode->SubKeyLists[Type]);
|
||||||
|
if (!Index)
|
||||||
|
{
|
||||||
|
/* Not handled */
|
||||||
|
ASSERT(FALSE);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Remember to release the cell later */
|
||||||
|
CellToRelease = KeyNode->SubKeyLists[Type];
|
||||||
|
|
||||||
|
/* Check if this is a fast leaf that's gotten too full */
|
||||||
|
if ((Index->Signature == CM_KEY_FAST_LEAF) &&
|
||||||
|
(Index->Count >= CmpMaxFastIndexPerHblock))
|
||||||
|
{
|
||||||
|
/* Not handled yet */
|
||||||
|
DPRINT1("Fast->Slow Leaf Conversion not yet implemented!\n");
|
||||||
|
ASSERT(FALSE);
|
||||||
|
}
|
||||||
|
else if (((Index->Signature == CM_KEY_INDEX_LEAF) ||
|
||||||
|
(Index->Signature == CM_KEY_HASH_LEAF)) &&
|
||||||
|
(Index->Count >= CmpMaxIndexPerHblock))
|
||||||
|
{
|
||||||
|
/* This is an old/hashed leaf that's gotten too large, root it */
|
||||||
|
IndexCell = HvAllocateCell(Hive,
|
||||||
|
sizeof(CM_KEY_INDEX) +
|
||||||
|
sizeof(HCELL_INDEX),
|
||||||
|
Type);
|
||||||
|
if (IndexCell == HCELL_NIL)
|
||||||
|
{
|
||||||
|
/* Not handled */
|
||||||
|
ASSERT(FALSE);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Get the index cell */
|
||||||
|
Index = (PCM_KEY_INDEX)HvGetCell(Hive, IndexCell);
|
||||||
|
if (!Index)
|
||||||
|
{
|
||||||
|
/* Shouldn't happen */
|
||||||
|
ASSERT(FALSE);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Mark the index as a root, and set the index cell */
|
||||||
|
Index->Signature = CM_KEY_INDEX_ROOT;
|
||||||
|
Index->Count = 1;
|
||||||
|
Index->List[0] = KeyNode->SubKeyLists[Type];
|
||||||
|
KeyNode->SubKeyLists[Type] = IndexCell;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Now we can choose the leaf cell */
|
||||||
|
LeafCell = KeyNode->SubKeyLists[Type];
|
||||||
|
|
||||||
|
/* Check if we turned the index into a root */
|
||||||
|
if (Index->Signature == CM_KEY_INDEX_ROOT)
|
||||||
|
{
|
||||||
|
/* Not handled yet */
|
||||||
|
DPRINT1("Leaf->Root Index Conversion not yet implemented!\n");
|
||||||
|
ASSERT(FALSE);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Add our leaf cell */
|
||||||
|
LeafCell = CmpAddToLeaf(Hive, LeafCell, Child, &Name);
|
||||||
|
if (LeafCell == HCELL_NIL)
|
||||||
|
{
|
||||||
|
/* Not handled */
|
||||||
|
ASSERT(FALSE);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Update the key counts */
|
||||||
|
KeyNode->SubKeyCounts[Type]++;
|
||||||
|
|
||||||
|
/* Check if caller wants us to return the leaf */
|
||||||
|
if (RootPointer)
|
||||||
|
{
|
||||||
|
/* Return it */
|
||||||
|
*RootPointer = LeafCell;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* Otherwise, mark it as the list index for the cell */
|
||||||
|
KeyNode->SubKeyLists[Type] = LeafCell;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* If the name was compressed, free our copy */
|
||||||
|
if (IsCompressed) Hive->Free(Name.Buffer);
|
||||||
|
|
||||||
|
/* Release all our cells */
|
||||||
|
if (IndexCell != HCELL_NIL) HvReleaseCell(Hive, IndexCell);
|
||||||
|
if (CellToRelease != HCELL_NIL) HvReleaseCell(Hive, CellToRelease);
|
||||||
|
HvReleaseCell(Hive, Parent);
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
BOOLEAN
|
BOOLEAN
|
||||||
NTAPI
|
NTAPI
|
||||||
CmpRemoveSubKey(IN PHHIVE Hive,
|
CmpRemoveSubKey(IN PHHIVE Hive,
|
||||||
|
|
|
@ -73,3 +73,329 @@ CmpGetNextName(IN OUT PUNICODE_STRING RemainingName,
|
||||||
*LastName = !RemainingName->Length;
|
*LastName = !RemainingName->Length;
|
||||||
return NameValid;
|
return NameValid;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
NTSTATUS
|
||||||
|
NTAPI
|
||||||
|
CmpDoCreateChild(IN PHHIVE Hive,
|
||||||
|
IN HCELL_INDEX ParentCell,
|
||||||
|
IN PSECURITY_DESCRIPTOR ParentDescriptor OPTIONAL,
|
||||||
|
IN PACCESS_STATE AccessState,
|
||||||
|
IN PUNICODE_STRING Name,
|
||||||
|
IN KPROCESSOR_MODE AccessMode,
|
||||||
|
IN PUNICODE_STRING Class,
|
||||||
|
IN PKEY_OBJECT Parent,
|
||||||
|
IN ULONG CreateOptions,
|
||||||
|
OUT PHCELL_INDEX KeyCell,
|
||||||
|
OUT PVOID *Object)
|
||||||
|
{
|
||||||
|
NTSTATUS Status = STATUS_SUCCESS;
|
||||||
|
PKEY_OBJECT KeyBody;
|
||||||
|
HCELL_INDEX ClassCell = HCELL_NIL;
|
||||||
|
PCM_KEY_NODE KeyNode;
|
||||||
|
PCELL_DATA CellData;
|
||||||
|
ULONG StorageType;
|
||||||
|
LARGE_INTEGER SystemTime;
|
||||||
|
BOOLEAN Hack = FALSE;
|
||||||
|
|
||||||
|
/* ReactOS Hack */
|
||||||
|
if (Name->Buffer[0] == OBJ_NAME_PATH_SEPARATOR)
|
||||||
|
{
|
||||||
|
/* Skip initial path separator */
|
||||||
|
Name->Buffer++;
|
||||||
|
Name->Length -= sizeof(OBJ_NAME_PATH_SEPARATOR);
|
||||||
|
Name->MaximumLength -= sizeof(OBJ_NAME_PATH_SEPARATOR);
|
||||||
|
Hack = TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Get the storage type */
|
||||||
|
StorageType = HvStable;
|
||||||
|
if (CreateOptions & REG_OPTION_VOLATILE) StorageType = HvVolatile;
|
||||||
|
|
||||||
|
/* Allocate the child */
|
||||||
|
*KeyCell = HvAllocateCell(Hive,
|
||||||
|
FIELD_OFFSET(CM_KEY_NODE, Name) +
|
||||||
|
CmpNameSize(Hive, Name),
|
||||||
|
StorageType);
|
||||||
|
if (*KeyCell == HCELL_NIL)
|
||||||
|
{
|
||||||
|
/* Fail */
|
||||||
|
Status = STATUS_INSUFFICIENT_RESOURCES;
|
||||||
|
goto Quickie;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Get the key node */
|
||||||
|
KeyNode = (PCM_KEY_NODE)HvGetCell(Hive, *KeyCell);
|
||||||
|
if (!KeyNode)
|
||||||
|
{
|
||||||
|
/* Fail, this should never happen */
|
||||||
|
ASSERT(FALSE);
|
||||||
|
Status = STATUS_INSUFFICIENT_RESOURCES;
|
||||||
|
goto Quickie;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Release the cell */
|
||||||
|
HvReleaseCell(Hive, *KeyCell);
|
||||||
|
|
||||||
|
/* Check if we have a class name */
|
||||||
|
if (Class->Length > 0)
|
||||||
|
{
|
||||||
|
/* Allocate a class cell */
|
||||||
|
ClassCell = HvAllocateCell(Hive, Class->Length, StorageType);
|
||||||
|
if (ClassCell == HCELL_NIL)
|
||||||
|
{
|
||||||
|
/* Fail */
|
||||||
|
Status = STATUS_INSUFFICIENT_RESOURCES;
|
||||||
|
goto Quickie;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Allocate the Cm Object */
|
||||||
|
Status = ObCreateObject(AccessMode,
|
||||||
|
CmpKeyObjectType,
|
||||||
|
NULL,
|
||||||
|
AccessMode,
|
||||||
|
NULL,
|
||||||
|
sizeof(KEY_OBJECT),
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
Object);
|
||||||
|
if (!NT_SUCCESS(Status)) goto Quickie;
|
||||||
|
KeyBody = (PKEY_OBJECT)(*Object);
|
||||||
|
|
||||||
|
/* Check if we had a class */
|
||||||
|
if (Class->Length > 0)
|
||||||
|
{
|
||||||
|
/* Get the class cell */
|
||||||
|
CellData = HvGetCell(Hive, ClassCell);
|
||||||
|
if (!CellData)
|
||||||
|
{
|
||||||
|
/* Fail, this should never happen */
|
||||||
|
ASSERT(FALSE);
|
||||||
|
Status = STATUS_INSUFFICIENT_RESOURCES;
|
||||||
|
ObDereferenceObject(*Object);
|
||||||
|
goto Quickie;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Release the cell */
|
||||||
|
HvReleaseCell(Hive, ClassCell);
|
||||||
|
|
||||||
|
/* Copy the class data */
|
||||||
|
RtlCopyMemory(&CellData->u.KeyString[0],
|
||||||
|
Class->Buffer,
|
||||||
|
Class->Length);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Fill out the key node */
|
||||||
|
KeyNode->Signature = CM_KEY_NODE_SIGNATURE;
|
||||||
|
KeyNode->Flags = CreateOptions;
|
||||||
|
KeQuerySystemTime(&SystemTime);
|
||||||
|
KeyNode->LastWriteTime = SystemTime;
|
||||||
|
KeyNode->Spare = 0;
|
||||||
|
KeyNode->Parent = ParentCell;
|
||||||
|
KeyNode->SubKeyCounts[HvStable] = 0;
|
||||||
|
KeyNode->SubKeyCounts[HvVolatile] = 0;
|
||||||
|
KeyNode->SubKeyLists[HvStable] = HCELL_NIL;
|
||||||
|
KeyNode->SubKeyLists[HvVolatile] = HCELL_NIL;
|
||||||
|
KeyNode->ValueList.Count = 0;
|
||||||
|
KeyNode->ValueList.List = HCELL_NIL;
|
||||||
|
KeyNode->Security = HCELL_NIL;
|
||||||
|
KeyNode->Class = ClassCell;
|
||||||
|
KeyNode->ClassLength = Class->Length;
|
||||||
|
KeyNode->MaxValueDataLen = 0;
|
||||||
|
KeyNode->MaxNameLen = 0;
|
||||||
|
KeyNode->MaxValueNameLen = 0;
|
||||||
|
KeyNode->MaxClassLen = 0;
|
||||||
|
KeyNode->NameLength = CmpCopyName(Hive, KeyNode->Name, Name);
|
||||||
|
if (KeyNode->NameLength < Name->Length) KeyNode->Flags |= KEY_COMP_NAME;
|
||||||
|
|
||||||
|
/* Now fill out the Cm object */
|
||||||
|
KeyBody->KeyCell = KeyNode;
|
||||||
|
KeyBody->KeyCellOffset = *KeyCell;
|
||||||
|
KeyBody->Flags = 0;
|
||||||
|
KeyBody->SubKeyCounts = 0;
|
||||||
|
KeyBody->SubKeys = NULL;
|
||||||
|
KeyBody->SizeOfSubKeys = 0;
|
||||||
|
KeyBody->ParentKey = Parent;
|
||||||
|
KeyBody->RegistryHive = KeyBody->ParentKey->RegistryHive;
|
||||||
|
InsertTailList(&CmiKeyObjectListHead, &KeyBody->ListEntry);
|
||||||
|
|
||||||
|
Quickie:
|
||||||
|
/* Check if we got here because of failure */
|
||||||
|
if (!NT_SUCCESS(Status))
|
||||||
|
{
|
||||||
|
/* Free any cells we might've allocated */
|
||||||
|
if (Class->Length > 0) HvFreeCell(Hive, ClassCell);
|
||||||
|
HvFreeCell(Hive, *KeyCell);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Check if we applied ReactOS hack */
|
||||||
|
if (Hack)
|
||||||
|
{
|
||||||
|
/* Restore name */
|
||||||
|
Name->Buffer--;
|
||||||
|
Name->Length += sizeof(OBJ_NAME_PATH_SEPARATOR);
|
||||||
|
Name->MaximumLength += sizeof(OBJ_NAME_PATH_SEPARATOR);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Return status */
|
||||||
|
return Status;
|
||||||
|
}
|
||||||
|
|
||||||
|
NTSTATUS
|
||||||
|
NTAPI
|
||||||
|
CmpDoCreate(IN PHHIVE Hive,
|
||||||
|
IN HCELL_INDEX Cell,
|
||||||
|
IN PACCESS_STATE AccessState,
|
||||||
|
IN PUNICODE_STRING Name,
|
||||||
|
IN KPROCESSOR_MODE AccessMode,
|
||||||
|
IN PUNICODE_STRING Class OPTIONAL,
|
||||||
|
IN ULONG CreateOptions,
|
||||||
|
IN PKEY_OBJECT Parent,
|
||||||
|
IN PCMHIVE OriginatingHive OPTIONAL,
|
||||||
|
OUT PVOID *Object)
|
||||||
|
{
|
||||||
|
NTSTATUS Status;
|
||||||
|
PCELL_DATA CellData;
|
||||||
|
HCELL_INDEX KeyCell;
|
||||||
|
ULONG ParentType;
|
||||||
|
PKEY_OBJECT KeyBody;
|
||||||
|
PSECURITY_DESCRIPTOR SecurityDescriptor = NULL;
|
||||||
|
LARGE_INTEGER TimeStamp;
|
||||||
|
PCM_KEY_NODE KeyNode;
|
||||||
|
UNICODE_STRING LocalClass = {0};
|
||||||
|
if (!Class) Class = &LocalClass;
|
||||||
|
|
||||||
|
/* Acquire the flusher lock */
|
||||||
|
//ExAcquirePushLockShared((PVOID)&((PCMHIVE)Hive)->FlusherLock);
|
||||||
|
|
||||||
|
/* Check if the parent is being deleted */
|
||||||
|
#define KO_MARKED_FOR_DELETE 0x00000001
|
||||||
|
if (Parent->Flags & KO_MARKED_FOR_DELETE)
|
||||||
|
{
|
||||||
|
/* It has, quit */
|
||||||
|
ASSERT(FALSE);
|
||||||
|
Status = STATUS_OBJECT_NAME_NOT_FOUND;
|
||||||
|
goto Exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Get the parent node */
|
||||||
|
KeyNode = (PCM_KEY_NODE)HvGetCell(Hive, Cell);
|
||||||
|
if (!KeyNode)
|
||||||
|
{
|
||||||
|
/* Fail */
|
||||||
|
ASSERT(FALSE);
|
||||||
|
Status = STATUS_INSUFFICIENT_RESOURCES;
|
||||||
|
goto Exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Make sure nobody added us yet */
|
||||||
|
if (CmpFindSubKeyByName(Hive, KeyNode, Name) != HCELL_NIL)
|
||||||
|
{
|
||||||
|
/* Fail */
|
||||||
|
ASSERT(FALSE);
|
||||||
|
Status = STATUS_REPARSE;
|
||||||
|
goto Exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Sanity check */
|
||||||
|
ASSERT(Cell == Parent->KeyCellOffset);
|
||||||
|
|
||||||
|
/* Get the parent type */
|
||||||
|
ParentType = HvGetCellType(Cell);
|
||||||
|
if ((ParentType == HvVolatile) && !(CreateOptions & REG_OPTION_VOLATILE))
|
||||||
|
{
|
||||||
|
/* Children of volatile parents must also be volatile */
|
||||||
|
ASSERT(FALSE);
|
||||||
|
Status = STATUS_CHILD_MUST_BE_VOLATILE;
|
||||||
|
goto Exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Don't allow children under symlinks */
|
||||||
|
if (Parent->Flags & KEY_SYM_LINK)
|
||||||
|
{
|
||||||
|
/* Fail */
|
||||||
|
ASSERT(FALSE);
|
||||||
|
Status = STATUS_ACCESS_DENIED;
|
||||||
|
goto Exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Make the cell dirty for now */
|
||||||
|
HvMarkCellDirty(Hive, Cell);
|
||||||
|
|
||||||
|
/* Do the actual create operation */
|
||||||
|
Status = CmpDoCreateChild(Hive,
|
||||||
|
Cell,
|
||||||
|
SecurityDescriptor,
|
||||||
|
AccessState,
|
||||||
|
Name,
|
||||||
|
AccessMode,
|
||||||
|
Class,
|
||||||
|
Parent,
|
||||||
|
CreateOptions,
|
||||||
|
&KeyCell,
|
||||||
|
Object);
|
||||||
|
if (NT_SUCCESS(Status))
|
||||||
|
{
|
||||||
|
/* Get the key body */
|
||||||
|
KeyBody = (PKEY_OBJECT)(*Object);
|
||||||
|
|
||||||
|
/* Now add the subkey */
|
||||||
|
if (!CmpAddSubKey(Hive, Cell, KeyCell))
|
||||||
|
{
|
||||||
|
/* Failure! We don't handle this yet! */
|
||||||
|
ASSERT(FALSE);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Get the key node */
|
||||||
|
KeyNode = (PCM_KEY_NODE)HvGetCell(Hive, Cell);
|
||||||
|
if (!KeyNode)
|
||||||
|
{
|
||||||
|
/* Fail, this shouldn't happen */
|
||||||
|
ASSERT(FALSE);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Sanity checks */
|
||||||
|
ASSERT(KeyBody->ParentKey->KeyCellOffset == Cell);
|
||||||
|
ASSERT(&KeyBody->ParentKey->RegistryHive->Hive == Hive);
|
||||||
|
ASSERT(KeyBody->ParentKey == Parent);
|
||||||
|
|
||||||
|
/* Update the timestamp */
|
||||||
|
KeQuerySystemTime(&TimeStamp);
|
||||||
|
KeyNode->LastWriteTime = TimeStamp;
|
||||||
|
|
||||||
|
/* Check if we need to update name maximum */
|
||||||
|
if (KeyNode->MaxNameLen < Name->Length)
|
||||||
|
{
|
||||||
|
/* Do it */
|
||||||
|
KeyNode->MaxNameLen = Name->Length;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Check if we need toupdate class length maximum */
|
||||||
|
if (KeyNode->MaxClassLen < Class->Length)
|
||||||
|
{
|
||||||
|
/* Update it */
|
||||||
|
KeyNode->MaxClassLen = Class->Length;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Check if we're creating a symbolic link */
|
||||||
|
if (CreateOptions & REG_OPTION_CREATE_LINK)
|
||||||
|
{
|
||||||
|
/* Get the cell data */
|
||||||
|
CellData = HvGetCell(Hive, KeyCell);
|
||||||
|
if (!CellData)
|
||||||
|
{
|
||||||
|
/* This shouldn't happen */
|
||||||
|
ASSERT(FALSE);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Update the flags */
|
||||||
|
CellData->u.KeyNode.Flags |= KEY_SYM_LINK;
|
||||||
|
HvReleaseCell(Hive, KeyCell);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Exit:
|
||||||
|
/* Release the flusher lock and return status */
|
||||||
|
//ExReleasePushLock((PVOID)&((PCMHIVE)Hive)->FlusherLock);
|
||||||
|
return Status;
|
||||||
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue