[ros-diffs] [fireball] 28292: - 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.

fireball at svn.reactos.org fireball at svn.reactos.org
Sat Aug 11 21:03:00 CEST 2007


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&r1=28291&r2=28292&view=diff
==============================================================================
--- 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=28292&r1=28291&r2=28292&view=diff
==============================================================================
--- 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=28292&r1=28291&r2=28292&view=diff
==============================================================================
--- 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?rev=28292&r1=28291&r2=28292&view=diff
==============================================================================
--- 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?rev=28292&r1=28291&r2=28292&view=diff
==============================================================================
--- 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;
+}




More information about the Ros-diffs mailing list