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=28... ============================================================================== --- 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?r... ============================================================================== --- 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?r... ============================================================================== --- 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; +}