Author: fireball
Date: Sat Aug 11 23:03:00 2007
New Revision: 28292
URL:
http://svn.reactos.org/svn/reactos?rev=28292&view=rev
Log:
- 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.
Modified:
trunk/reactos/ntoskrnl/cm/cm.h
trunk/reactos/ntoskrnl/cm/ntfunc.c
trunk/reactos/ntoskrnl/cm/registry.c
trunk/reactos/ntoskrnl/config/cmindex.c
trunk/reactos/ntoskrnl/config/cmparse.c
Modified: trunk/reactos/ntoskrnl/cm/cm.h
URL:
http://svn.reactos.org/svn/reactos/trunk/reactos/ntoskrnl/cm/cm.h?rev=28292…
==============================================================================
--- trunk/reactos/ntoskrnl/cm/cm.h (original)
+++ trunk/reactos/ntoskrnl/cm/cm.h Sat Aug 11 23:03:00 2007
@@ -294,6 +294,21 @@
NTSTATUS
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
NTAPI
CmpFindValueByName(
Modified: trunk/reactos/ntoskrnl/cm/ntfunc.c
URL:
http://svn.reactos.org/svn/reactos/trunk/reactos/ntoskrnl/cm/ntfunc.c?rev=2…
==============================================================================
--- trunk/reactos/ntoskrnl/cm/ntfunc.c (original)
+++ trunk/reactos/ntoskrnl/cm/ntfunc.c Sat Aug 11 23:03:00 2007
@@ -138,7 +138,6 @@
OUT PULONG Disposition)
{
UNICODE_STRING RemainingPath = {0};
- BOOLEAN FreeRemainingPath = TRUE;
ULONG LocalDisposition;
PKEY_OBJECT KeyObject;
NTSTATUS Status = STATUS_SUCCESS;
@@ -303,53 +302,27 @@
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 */
KeEnterCriticalRegion();
ExAcquireResourceExclusiveLite(&CmpRegistryLock, TRUE);
- InsertTailList(&CmiKeyObjectListHead, &KeyObject->ListEntry);
-
- /* add key to subkeys of parent if needed */
- Status = CmiAddSubKey(KeyObject->RegistryHive,
- KeyObject->ParentKey,
- KeyObject,
- &RemainingPath,
- TitleIndex,
- &CapturedClass,
- CreateOptions);
+ /* Create the key */
+ Status = CmpDoCreate(&((PKEY_OBJECT)Object)->RegistryHive->Hive,
+ ((PKEY_OBJECT)Object)->KeyCellOffset,
+ NULL,
+ &RemainingPath,
+ KernelMode,
+ Class,
+ CreateOptions,
+ (PKEY_OBJECT)Object,
+ NULL,
+ (PVOID*)&KeyObject);
if (!NT_SUCCESS(Status))
{
DPRINT1("CmiAddSubKey() failed (Status %lx)\n", Status);
/* Release hive lock */
ExReleaseResourceLite(&CmpRegistryLock);
KeLeaveCriticalRegion();
- ObDereferenceObject(KeyObject);
PostCreateKeyInfo.Object = NULL;
PostCreateKeyInfo.Status = STATUS_UNSUCCESSFUL;
@@ -359,15 +332,8 @@
goto Cleanup;
}
- if (Start == RemainingPath.Buffer)
- {
- KeyObject->Name = RemainingPath;
- FreeRemainingPath = FALSE;
- }
- else
- {
- RtlCreateUnicodeString(&KeyObject->Name, Start);
- }
+ InsertTailList(&CmiKeyObjectListHead, &KeyObject->ListEntry);
+ RtlCreateUnicodeString(&KeyObject->Name, Start);
KeyObject->KeyCell->Parent = KeyObject->ParentKey->KeyCellOffset;
KeyObject->KeyCell->SecurityKeyOffset =
KeyObject->ParentKey->KeyCell->SecurityKeyOffset;
@@ -437,7 +403,7 @@
PreviousMode);
}
if (ObjectName.Buffer) ObpFreeObjectNameBuffer(&ObjectName);
- if (FreeRemainingPath) RtlFreeUnicodeString(&RemainingPath);
+ RtlFreeUnicodeString(&RemainingPath);
if (Object != NULL) ObDereferenceObject(Object);
return Status;
Modified: trunk/reactos/ntoskrnl/cm/registry.c
URL:
http://svn.reactos.org/svn/reactos/trunk/reactos/ntoskrnl/cm/registry.c?rev…
==============================================================================
--- trunk/reactos/ntoskrnl/cm/registry.c (original)
+++ trunk/reactos/ntoskrnl/cm/registry.c Sat Aug 11 23:03:00 2007
@@ -263,39 +263,19 @@
DPRINT("RemainingPath %wZ ParentKey %p\n",
&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);
- Status = CmiAddSubKey(ParentKey->RegistryHive,
- ParentKey,
- NewKey,
- &RemainingPath,
- 0,
- NULL,
- REG_OPTION_VOLATILE);
+ /* Create the key */
+ Status = CmpDoCreate(&ParentKey->RegistryHive->Hive,
+ ParentKey->KeyCellOffset,
+ NULL,
+ &RemainingPath,
+ KernelMode,
+ NULL,
+ REG_OPTION_VOLATILE,
+ ParentKey,
+ NULL,
+ (PVOID*)&NewKey);
if (!NT_SUCCESS(Status))
{
DPRINT1("CmiAddSubKey() failed (Status %lx)\n", Status);
Modified: trunk/reactos/ntoskrnl/config/cmindex.c
URL:
http://svn.reactos.org/svn/reactos/trunk/reactos/ntoskrnl/config/cmindex.c?…
==============================================================================
--- trunk/reactos/ntoskrnl/config/cmindex.c (original)
+++ trunk/reactos/ntoskrnl/config/cmindex.c Sat Aug 11 23:03:00 2007
@@ -14,6 +14,16 @@
#include "debug.h"
/* 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 *****************************************************************/
@@ -922,6 +932,396 @@
/* Free the search name and return failure */
if (IsCompressed) ExFreePool(SearchName.Buffer);
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
Modified: trunk/reactos/ntoskrnl/config/cmparse.c
URL:
http://svn.reactos.org/svn/reactos/trunk/reactos/ntoskrnl/config/cmparse.c?…
==============================================================================
--- trunk/reactos/ntoskrnl/config/cmparse.c (original)
+++ trunk/reactos/ntoskrnl/config/cmparse.c Sat Aug 11 23:03:00 2007
@@ -73,3 +73,329 @@
*LastName = !RemainingName->Length;
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;
+}