- 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:
Aleksey Bragin 2007-08-11 19:03:00 +00:00
parent edaf84b215
commit 8dae7ddffe
5 changed files with 766 additions and 79 deletions

View file

@ -294,6 +294,21 @@ CmiConnectHive(POBJECT_ATTRIBUTES KeyObjectAttributes,
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(

View file

@ -138,7 +138,6 @@ NtCreateKey(OUT PHANDLE KeyHandle,
OUT PULONG Disposition)
{
UNICODE_STRING RemainingPath = {0};
BOOLEAN FreeRemainingPath = TRUE;
ULONG LocalDisposition;
PKEY_OBJECT KeyObject;
NTSTATUS Status = STATUS_SUCCESS;
@ -303,53 +302,27 @@ NtCreateKey(OUT PHANDLE KeyHandle,
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 @@ NtCreateKey(OUT PHANDLE KeyHandle,
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 @@ Cleanup:
PreviousMode);
}
if (ObjectName.Buffer) ObpFreeObjectNameBuffer(&ObjectName);
if (FreeRemainingPath) RtlFreeUnicodeString(&RemainingPath);
RtlFreeUnicodeString(&RemainingPath);
if (Object != NULL) ObDereferenceObject(Object);
return Status;

View file

@ -263,39 +263,19 @@ CmiConnectHive(IN POBJECT_ATTRIBUTES KeyObjectAttributes,
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);

View file

@ -15,6 +15,16 @@
/* 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 *****************************************************************/
LONG
@ -924,6 +934,396 @@ Quickie:
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
NTAPI
CmpRemoveSubKey(IN PHHIVE Hive,

View file

@ -73,3 +73,329 @@ CmpGetNextName(IN OUT PUNICODE_STRING RemainingName,
*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;
}