예제 #1
0
파일: cmi.c 프로젝트: hackbunny/reactos
static NTSTATUS
CmiAddKeyToHashTable(
	IN PCMHIVE RegistryHive,
	IN OUT PCM_KEY_FAST_INDEX HashCell,
   IN HCELL_INDEX HashCellIndex,
	IN PCM_KEY_NODE NewKeyCell,
	IN HCELL_INDEX NKBOffset)
{
	ULONG i;
	ULONG HashKey = 0;

	if (NewKeyCell->Flags & KEY_COMP_NAME)
	{
		RtlCopyMemory(
			&HashKey,
			NewKeyCell->Name,
			min(NewKeyCell->NameLength, sizeof(ULONG)));
	}

	for (i = 0; i < HashCell->Count; i++)
	{
		if (HashCell->List[i].HashKey > HashKey)
			break;
	}

	if (i < HashCell->Count)
	{
		RtlMoveMemory(HashCell->List + i + 1,
		              HashCell->List + i,
		              (HashCell->Count - i) *
		              sizeof(HashCell->List[0]));
	}

	HashCell->List[i].Cell = NKBOffset;
	HashCell->List[i].HashKey = HashKey;
   HashCell->Count++;
	HvMarkCellDirty(&RegistryHive->Hive, HashCellIndex, FALSE);
	return STATUS_SUCCESS;
}
예제 #2
0
BOOLEAN
NTAPI
CmpMarkKeyDirty(IN PHHIVE Hive,
                IN HCELL_INDEX Cell,
                IN BOOLEAN CheckNoSubkeys)
{
    PCELL_DATA CellData, ListData, SecurityData, ValueData;
    ULONG i;

    /* Get the cell data for our target */
    CellData = HvGetCell(Hive, Cell);
    if (!CellData) return FALSE;

    /* Check if sanity checks requested */
    if (CheckNoSubkeys)
    {
        /* Do them */
        ASSERT(CellData->u.KeyNode.SubKeyCounts[Stable] == 0);
        ASSERT(CellData->u.KeyNode.SubKeyCounts[Volatile] == 0);
    }

    /* If this is an exit hive, there's nothing to do */
    if (CellData->u.KeyNode.Flags & KEY_HIVE_EXIT)
    {
        /* Release the cell and get out */
        HvReleaseCell(Hive, Cell);
        return TRUE;
    }

    /* Otherwise, mark it dirty and release it */
    HvMarkCellDirty(Hive, Cell, FALSE);
    HvReleaseCell(Hive, Cell);

    /* Check if we have a class */
    if (CellData->u.KeyNode.Class != HCELL_NIL)
    {
        /* Mark it dirty */
        HvMarkCellDirty(Hive, CellData->u.KeyNode.Class, FALSE);
    }

    /* Check if we have security */
    if (CellData->u.KeyNode.Security != HCELL_NIL)
    {
        /* Mark it dirty */
        HvMarkCellDirty(Hive, CellData->u.KeyNode.Security, FALSE);

        /* Get the security data and release it */
        SecurityData = HvGetCell(Hive, CellData->u.KeyNode.Security);
        if (!SecurityData) ASSERT(FALSE);
        HvReleaseCell(Hive, CellData->u.KeyNode.Security);

        /* Mark the security links dirty too */
        HvMarkCellDirty(Hive, SecurityData->u.KeySecurity.Flink, FALSE);
        HvMarkCellDirty(Hive, SecurityData->u.KeySecurity.Blink, FALSE);
    }

    /* Check if we have any values */
    if (CellData->u.KeyNode.ValueList.Count > 0)
    {
        /* Dirty the value list */
        HvMarkCellDirty(Hive, CellData->u.KeyNode.ValueList.List, FALSE);

        /* Get the list data itself, and release it */
        ListData = HvGetCell(Hive, CellData->u.KeyNode.ValueList.List);
        if (!ListData) ASSERT(FALSE);
        HvReleaseCell(Hive, CellData->u.KeyNode.ValueList.List);

        /* Loop all values */
        for (i = 0; i < CellData->u.KeyNode.ValueList.Count; i++)
        {
            /* Dirty each value */
            HvMarkCellDirty(Hive, ListData->u.KeyList[i], FALSE);

            /* Get the value data and release it */
            ValueData = HvGetCell(Hive, ListData->u.KeyList[i]);
            ASSERT(ValueData);
            HvReleaseCell(Hive,ListData->u.KeyList[i]);

            /* Mark the value data dirty too */
            if (!CmpMarkValueDataDirty(Hive, &ValueData->u.KeyValue))
            {
                /* Failure */
                return FALSE;
            }
        }
    }

    /* If this is an entry hive, we're done */
    if (CellData->u.KeyNode.Flags & KEY_HIVE_ENTRY) return TRUE;

    /* Otherwise mark the index dirty too */
    if (!CmpMarkIndexDirty(Hive, CellData->u.KeyNode.Parent, Cell))
    {
        /* Failure */
        return FALSE;
    }

    /* Finally, mark the parent dirty */
    HvMarkCellDirty(Hive, CellData->u.KeyNode.Parent, FALSE);
    return TRUE;
}
예제 #3
0
파일: cmchek.c 프로젝트: chunhualiu/OpenNT
ULONG
CmpCheckKey(
    HCELL_INDEX Cell,
    HCELL_INDEX ParentCell
    )
/*++

Routine Description:

    Check consistency of the registry, for a particular cell

        .   Check that the cell's value list, child key list, class,
            security are OK.
        .   Check that each value entry IN the list is OK.

Globals:

    CmpCheckHive - hive we're working on

    CmpCheckClean - flag TRUE -> clean off volatiles, FALSE -> don't

Arguments:

    Cell - HCELL_INDEX of subkey to work on.

    ParentCell - expected value of parent cell for Cell, unless
                 HCELL_NIL, in which case ignore.

Return Value:

    0 if Hive is OK.  Error return indicator if not.

    RANGE:  4000 - 4999

--*/
{
    PCELL_DATA      pcell;
    ULONG           size;
    ULONG           usedlen;
    ULONG           ClassLength;
    HCELL_INDEX     Class;
    ULONG           ValueCount;
    HCELL_INDEX     ValueList;
    HCELL_INDEX     Security;
    ULONG           rc = 0;
    ULONG           nrc = 0;
    ULONG           i;
    PCM_KEY_INDEX   Root;
    PCM_KEY_INDEX   Leaf;
    ULONG           SubCount;

    CmpCheckKeyDebug.Hive = CmpCheckHive;
    CmpCheckKeyDebug.Status = 0;
    CmpCheckKeyDebug.Cell = Cell;
    CmpCheckKeyDebug.CellPoint = NULL;
    CmpCheckKeyDebug.RootPoint = NULL;
    CmpCheckKeyDebug.Index = (ULONG)-1;

    //
    // Check key itself
    //
    if (! HvIsCellAllocated(CmpCheckHive, Cell)) {
        KdPrint(("CmpCheckKey: CmpCheckHive:%08lx Cell:%08lx\n", CmpCheckHive, Cell));
        KdPrint(("\tNot allocated\n"));
        rc = 4010;
        CmpCheckKeyDebug.Status = rc;
        return rc;
    }
    pcell = HvGetCell(CmpCheckHive, Cell);
    SetUsed(CmpCheckHive, Cell);

    CmpCheckKeyDebug.CellPoint = pcell;

    size = HvGetCellSize(CmpCheckHive, pcell);
    if (size > REG_MAX_PLAUSIBLE_KEY_SIZE) {
        KdPrint(("CmpCheckKey: CmpCheckHive:%08lx Cell:%08lx\n", CmpCheckHive, Cell));
        KdPrint(("\tImplausible size %lx\n", size));
        rc = 4020;
        CmpCheckKeyDebug.Status = rc;
        return rc;
    }
    usedlen = FIELD_OFFSET(CM_KEY_NODE, Name) + pcell->u.KeyNode.NameLength;
    if (usedlen > size) {
        KdPrint(("CmpCheckKey: CmpCheckHive:%08lx Cell:%08lx\n", CmpCheckHive, Cell));
        KdPrint(("\tKey is bigger than containing cell.\n"));
        rc = 4030;
        CmpCheckKeyDebug.Status = rc;
        return rc;
    }
    if (pcell->u.KeyNode.Signature != CM_KEY_NODE_SIGNATURE) {
        KdPrint(("CmpCheckKey: CmpCheckHive:%08lx Cell:%08lx\n", CmpCheckHive, Cell));
        KdPrint(("\tNo key signature\n"));
        rc = 4040;
        CmpCheckKeyDebug.Status = rc;
        return rc;
    }
    if (ParentCell != HCELL_NIL) {
        if (pcell->u.KeyNode.Parent != ParentCell) {
            KdPrint(("CmpCheckKey: CmpCheckHive:%08lx Cell:%08lx\n", CmpCheckHive, Cell));
            KdPrint(("\tWrong parent value.\n"));
            rc = 4045;
            CmpCheckKeyDebug.Status = rc;
            return rc;
        }
    }
    ClassLength = pcell->u.KeyNode.ClassLength;
    Class = pcell->u.KeyNode.Class;
    ValueCount = pcell->u.KeyNode.ValueList.Count;
    ValueList = pcell->u.KeyNode.ValueList.List;
    Security = pcell->u.KeyNode.Security;

    //
    // Check simple non-empty cases
    //
    if (ClassLength > 0) {
        if( Class == HCELL_NIL ) {
            pcell->u.KeyNode.ClassLength = 0;
            HvMarkCellDirty(CmpCheckHive, Cell);
            KdPrint(("CmpCheckKey: CmpCheckHive:%08lx Cell:%08lx has ClassLength = %lu and Class == HCELL_NIL\n", CmpCheckHive, Cell,ClassLength));
        } else {
            if (HvIsCellAllocated(CmpCheckHive, Class) == FALSE) {
                    KdPrint(("CmpCheckKey: CmpCheckHive:%08lx Cell:%08lx\n", CmpCheckHive, Cell));
                    KdPrint(("\tClass:%08lx - unallocated class\n", Class));
                    rc = 4080;
                    CmpCheckKeyDebug.Status = rc;
                    return rc;
                } else {
                    SetUsed(CmpCheckHive, Class);
                }
        }
    }

    if (Security != HCELL_NIL) {
        if (HvIsCellAllocated(CmpCheckHive, Security) == FALSE) {
            KdPrint(("CmpCheckKey: CmpCheckHive:%08lx Cell:%08lx\n", CmpCheckHive, Cell));
            KdPrint(("\tSecurity:%08lx - unallocated security\n", Security));
            rc = 4090;
            CmpCheckKeyDebug.Status = rc;
            return rc;
        } else if (HvGetCellType(Security) == Volatile) {
            SetUsed(CmpCheckHive, Security);
        }
        //
        // Else CmpValidateHiveSecurityDescriptors must do computation
        //
    }

    //
    // Check value list case
    //
    if (ValueCount > 0) {
        if (HvIsCellAllocated(CmpCheckHive, ValueList) == FALSE) {
            KdPrint(("CmpCheckKey: CmpCheckHive:%08lx Cell:%08lx\n", CmpCheckHive, Cell));
            KdPrint(("\tValueList:%08lx - unallocated valuelist\n", ValueList));
            rc = 4100;
            CmpCheckKeyDebug.Status = rc;
            return rc;
        } else {
            SetUsed(CmpCheckHive, ValueList);
            pcell = HvGetCell(CmpCheckHive, ValueList);
            nrc = CmpCheckValueList(CmpCheckHive, pcell, ValueCount);
            if (nrc != 0) {
                KdPrint(("List was for CmpCheckHive:%08lx Cell:%08lx\n", CmpCheckHive, Cell));
                rc = nrc;
                CmpCheckKeyDebug.CellPoint = pcell;
                CmpCheckKeyDebug.Status = rc;
                return rc;
            }
        }
    }


    //
    // Check subkey list case
    //

    pcell = HvGetCell(CmpCheckHive, Cell);
    CmpCheckKeyDebug.CellPoint = pcell;
    if ((HvGetCellType(Cell) == Volatile) &&
        (pcell->u.KeyNode.SubKeyCounts[Stable] != 0))
    {
        KdPrint(("CmpCheckKey: CmpCheckHive:%08lx Cell:%08lx\n", CmpCheckHive, Cell));
        KdPrint(("\tVolatile Cell has Stable children\n"));
        rc = 4108;
        CmpCheckKeyDebug.Status = rc;
        return rc;
    } else if (pcell->u.KeyNode.SubKeyCounts[Stable] > 0) {
        if (! HvIsCellAllocated(CmpCheckHive, pcell->u.KeyNode.SubKeyLists[Stable])) {
            KdPrint(("CmpCheckKey: CmpCheckHive:%08lx Cell:%08lx\n", CmpCheckHive, Cell));
            KdPrint(("\tStableKeyList:%08lx - unallocated\n", pcell->u.KeyNode.SubKeyLists[Stable]));
            rc = 4110;
            CmpCheckKeyDebug.Status = rc;
            return rc;
        } else {
            SetUsed(CmpCheckHive, pcell->u.KeyNode.SubKeyLists[Stable]);

            //
            // Prove that the index is OK
            //
            Root = (PCM_KEY_INDEX)HvGetCell(
                                    CmpCheckHive,
                                    pcell->u.KeyNode.SubKeyLists[Stable]
                                    );
            CmpCheckKeyDebug.RootPoint = Root;
            if ((Root->Signature == CM_KEY_INDEX_LEAF) ||
                (Root->Signature == CM_KEY_FAST_LEAF)) {
                if ((ULONG)Root->Count != pcell->u.KeyNode.SubKeyCounts[Stable]) {
                    KdPrint(("CmpCheckKey: CmpCheckHive:%08lx Cell:%08lx\n", CmpCheckHive, Cell));
                    KdPrint(("\tBad Index count @%08lx\n", Root));
                    rc = 4120;
                    CmpCheckKeyDebug.Status = rc;
                    return rc;
                }
            } else if (Root->Signature == CM_KEY_INDEX_ROOT) {
                SubCount = 0;
                for (i = 0; i < Root->Count; i++) {
                    CmpCheckKeyDebug.Index = i;
                    if (! HvIsCellAllocated(CmpCheckHive, Root->List[i])) {
                        KdPrint(("CmpCheckKey: Hive:%08lx Cell:%08lx\n", CmpCheckHive, Cell));
                        KdPrint(("\tBad Leaf Cell %08lx Root@%08lx\n", Root->List[i], Root));
                        rc = 4130;
                        CmpCheckKeyDebug.Status = rc;
                        return rc;
                    }
                    Leaf = (PCM_KEY_INDEX)HvGetCell(CmpCheckHive,
                                                    Root->List[i]);
                    if ((Leaf->Signature != CM_KEY_INDEX_LEAF) &&
                        (Leaf->Signature != CM_KEY_FAST_LEAF)) {
                        KdPrint(("CmpCheckKey: CmpCheckHive:%08lx Cell:%08lx\n", CmpCheckHive, Cell));
                        KdPrint(("\tBad Leaf Index @%08lx Root@%08lx\n", Leaf, Root));
                        rc = 4140;
                        CmpCheckKeyDebug.Status = rc;
                        return rc;
                    }
                    SetUsed(CmpCheckHive, Root->List[i]);
                    SubCount += Leaf->Count;
                }
                if (pcell->u.KeyNode.SubKeyCounts[Stable] != SubCount) {
                    KdPrint(("CmpCheckKey: CmpCheckHive:%08lx Cell:%08lx\n", CmpCheckHive, Cell));
                    KdPrint(("\tBad count in index, SubCount=%08lx\n", SubCount));
                    rc = 4150;
                    CmpCheckKeyDebug.Status = rc;
                    return rc;
                }
            } else {
                KdPrint(("CmpCheckKey: CmpCheckHive:%08lx Cell:%08lx\n", CmpCheckHive, Cell));
                KdPrint(("\tBad Root index signature @%08lx\n", Root));
                rc = 4120;
                CmpCheckKeyDebug.Status = rc;
                return rc;
            }
        }
    }
    //
    // force volatiles to be empty, if this is a load operation
    //
    if (CmpCheckClean == TRUE) {
        pcell->u.KeyNode.SubKeyCounts[Volatile] = 0;
        pcell->u.KeyNode.SubKeyLists[Volatile] = HCELL_NIL;
    }

    return rc;
}
예제 #4
0
LONG WINAPI
RegSetValueExW(
	IN HKEY hKey,
	IN LPCWSTR lpValueName OPTIONAL,
	IN ULONG Reserved,
	IN ULONG dwType,
	IN const UCHAR* lpData,
	IN USHORT cbData)
{
	MEMKEY Key, DestKey;
	PHKEY phKey;
	PCM_KEY_VALUE ValueCell;
	HCELL_INDEX ValueCellOffset;
	PVOID DataCell;
	LONG DataCellSize;
	NTSTATUS Status;

	if (dwType == REG_LINK)
	{
		/* Special handling of registry links */
		if (cbData != sizeof(PVOID))
			return STATUS_INVALID_PARAMETER;
		phKey = (PHKEY)lpData;
		Key = HKEY_TO_MEMKEY(hKey);
		DestKey = HKEY_TO_MEMKEY(*phKey);

		/* Create the link in memory */
		Key->DataType = REG_LINK;
		Key->LinkedKey = DestKey;

		/* Create the link in registry hive (if applicable) */
		if (Key->RegistryHive != DestKey->RegistryHive)
			return STATUS_SUCCESS;
		DPRINT1("Save link to registry\n");
		return STATUS_NOT_IMPLEMENTED;
	}

	if ((cbData & REG_DATA_SIZE_MASK) != cbData)
		return STATUS_UNSUCCESSFUL;

	Key = HKEY_TO_MEMKEY(hKey);

	Status = RegpOpenOrCreateValue(hKey, lpValueName, TRUE, &ValueCell, &ValueCellOffset);
	if (!NT_SUCCESS(Status))
		return ERROR_UNSUCCESSFUL;

	/* Get size of the allocated cellule (if any) */
	if (!(ValueCell->DataLength & REG_DATA_IN_OFFSET) &&
		(ValueCell->DataLength & REG_DATA_SIZE_MASK) != 0)
	{
		DataCell = HvGetCell(&Key->RegistryHive->Hive, ValueCell->Data);
		if (!DataCell)
			return ERROR_UNSUCCESSFUL;
		DataCellSize = -HvGetCellSize(&Key->RegistryHive->Hive, DataCell);
	}
	else
	{
		DataCell = NULL;
		DataCellSize = 0;
	}

	if (cbData <= sizeof(HCELL_INDEX))
	{
		/* If data size <= sizeof(HCELL_INDEX) then store data in the data offset */
		DPRINT("ValueCell->DataLength %u\n", ValueCell->DataLength);
		if (DataCell)
			HvFreeCell(&Key->RegistryHive->Hive, ValueCell->Data);

		RtlCopyMemory(&ValueCell->Data, lpData, cbData);
		ValueCell->DataLength = (ULONG)(cbData | REG_DATA_IN_OFFSET);
		ValueCell->Type = dwType;
		HvMarkCellDirty(&Key->RegistryHive->Hive, ValueCellOffset, FALSE);
	}
	else
	{
		if (cbData > (SIZE_T)DataCellSize)
		{
			/* New data size is larger than the current, destroy current
			 * data block and allocate a new one. */
			HCELL_INDEX NewOffset;

			DPRINT("ValueCell->DataLength %u\n", ValueCell->DataLength);

			NewOffset = HvAllocateCell(&Key->RegistryHive->Hive, cbData, Stable, HCELL_NIL);
			if (NewOffset == HCELL_NIL)
			{
				DPRINT("HvAllocateCell() failed with status 0x%08x\n", Status);
				return ERROR_UNSUCCESSFUL;
			}

			if (DataCell)
				HvFreeCell(&Key->RegistryHive->Hive, ValueCell->Data);

			ValueCell->Data = NewOffset;
			DataCell = (PVOID)HvGetCell(&Key->RegistryHive->Hive, NewOffset);
		}

		/* Copy new contents to cellule */
		RtlCopyMemory(DataCell, lpData, cbData);
		ValueCell->DataLength = (ULONG)(cbData & REG_DATA_SIZE_MASK);
		ValueCell->Type = dwType;
		HvMarkCellDirty(&Key->RegistryHive->Hive, ValueCell->Data, FALSE);
		HvMarkCellDirty(&Key->RegistryHive->Hive, ValueCellOffset, FALSE);
	}

	HvMarkCellDirty(&Key->RegistryHive->Hive, Key->KeyCellOffset, FALSE);

	DPRINT("Return status 0x%08x\n", Status);
	return Status;
}
예제 #5
0
파일: cmi.c 프로젝트: hackbunny/reactos
NTSTATUS
CmiAddValueKey(
	IN PCMHIVE RegistryHive,
	IN PCM_KEY_NODE KeyCell,
	IN HCELL_INDEX KeyCellOffset,
	IN PCUNICODE_STRING ValueName,
	OUT PCM_KEY_VALUE *pValueCell,
	OUT HCELL_INDEX *pValueCellOffset)
{
	PVALUE_LIST_CELL ValueListCell;
	PCM_KEY_VALUE NewValueCell;
	HCELL_INDEX ValueListCellOffset;
	HCELL_INDEX NewValueCellOffset;
	ULONG CellSize;
	HSTORAGE_TYPE Storage;
	NTSTATUS Status;

	Storage = (KeyCell->Flags & KEY_IS_VOLATILE) ? Volatile : Stable;
	if (KeyCell->ValueList.List == HCELL_NIL)
	{
		/* Allocate some room for the value list */
		CellSize = sizeof(VALUE_LIST_CELL) + (3 * sizeof(HCELL_INDEX));
		ValueListCellOffset = HvAllocateCell(&RegistryHive->Hive, CellSize, Storage, HCELL_NIL);
		if (ValueListCellOffset == HCELL_NIL)
			return STATUS_INSUFFICIENT_RESOURCES;

		ValueListCell = (PVALUE_LIST_CELL)HvGetCell(&RegistryHive->Hive, ValueListCellOffset);
		if (!ValueListCell)
			return STATUS_UNSUCCESSFUL;
		KeyCell->ValueList.List = ValueListCellOffset;
		HvMarkCellDirty(&RegistryHive->Hive, KeyCellOffset, FALSE);
	}
	else
	{
		ValueListCell = (PVALUE_LIST_CELL)HvGetCell(&RegistryHive->Hive, KeyCell->ValueList.List);
		if (!ValueListCell)
			return STATUS_UNSUCCESSFUL;
		CellSize = ABS_VALUE(HvGetCellSize(&RegistryHive->Hive, ValueListCell));

		if (KeyCell->ValueList.Count >= CellSize / sizeof(HCELL_INDEX))
		{
			CellSize *= 2;
			ValueListCellOffset = HvReallocateCell(&RegistryHive->Hive, KeyCell->ValueList.List, CellSize);
			if (ValueListCellOffset == HCELL_NIL)
				return STATUS_INSUFFICIENT_RESOURCES;

			ValueListCell = (PVALUE_LIST_CELL)HvGetCell(&RegistryHive->Hive, ValueListCellOffset);
			if (!ValueListCell)
				return STATUS_UNSUCCESSFUL;
			KeyCell->ValueList.List = ValueListCellOffset;
			HvMarkCellDirty(&RegistryHive->Hive, KeyCellOffset, FALSE);
        }
	}

	Status = CmiAllocateValueCell(
		RegistryHive,
		&NewValueCell,
		&NewValueCellOffset,
		ValueName,
		Storage);
	if (!NT_SUCCESS(Status))
		return Status;

	ValueListCell->ValueOffset[KeyCell->ValueList.Count] = NewValueCellOffset;
	KeyCell->ValueList.Count++;
	if (NewValueCell->Flags & VALUE_COMP_NAME)
	{
	    if (NewValueCell->NameLength*sizeof(WCHAR) > KeyCell->MaxValueNameLen)
            KeyCell->MaxValueNameLen = NewValueCell->NameLength*sizeof(WCHAR);
	}
	else
	{
	    if (NewValueCell->NameLength > KeyCell->MaxValueNameLen)
            KeyCell->MaxValueNameLen = NewValueCell->NameLength;
	}

	HvMarkCellDirty(&RegistryHive->Hive, KeyCellOffset, FALSE);
	HvMarkCellDirty(&RegistryHive->Hive, KeyCell->ValueList.List, FALSE);
	HvMarkCellDirty(&RegistryHive->Hive, NewValueCellOffset, FALSE);

	*pValueCell = NewValueCell;
	*pValueCellOffset = NewValueCellOffset;

	return STATUS_SUCCESS;
}
예제 #6
0
파일: cmi.c 프로젝트: hackbunny/reactos
NTSTATUS
CmiAddSubKey(
	IN PCMHIVE RegistryHive,
	IN PCM_KEY_NODE ParentKeyCell,
	IN HCELL_INDEX ParentKeyCellOffset,
	IN PCUNICODE_STRING SubKeyName,
	IN ULONG CreateOptions,
	OUT PCM_KEY_NODE *pSubKeyCell,
	OUT HCELL_INDEX *pBlockOffset)
{
	PCM_KEY_FAST_INDEX HashBlock;
	HCELL_INDEX NKBOffset;
	PCM_KEY_NODE NewKeyCell;
	ULONG NewBlockSize;
	NTSTATUS Status;
	USHORT NameLength;
	PWSTR NamePtr;
	BOOLEAN Packable;
	HSTORAGE_TYPE Storage;
	ULONG i;

	VERIFY_KEY_CELL(ParentKeyCell);

	/* Skip leading backslash */
	if (SubKeyName->Buffer[0] == L'\\')
	{
		NamePtr = &SubKeyName->Buffer[1];
		NameLength = SubKeyName->Length - sizeof(WCHAR);
	}
	else
	{
		NamePtr = SubKeyName->Buffer;
		NameLength = SubKeyName->Length;
	}

	/* Check whether key name can be packed */
	Packable = TRUE;
	for (i = 0; i < NameLength / sizeof(WCHAR); i++)
	{
		if (NamePtr[i] & 0xFF00)
		{
			Packable = FALSE;
			break;
		}
	}

	/* Adjust name size */
	if (Packable)
	{
		NameLength = NameLength / sizeof(WCHAR);
	}

	Status = STATUS_SUCCESS;

	Storage = (CreateOptions & REG_OPTION_VOLATILE) ? Volatile : Stable;
	NewBlockSize = FIELD_OFFSET(CM_KEY_NODE, Name) + NameLength;
	NKBOffset = HvAllocateCell(&RegistryHive->Hive, NewBlockSize, Storage, HCELL_NIL);
	if (NKBOffset == HCELL_NIL)
	{
		Status = STATUS_INSUFFICIENT_RESOURCES;
	}
	else
	{
		NewKeyCell = (PCM_KEY_NODE)HvGetCell (&RegistryHive->Hive, NKBOffset);
		NewKeyCell->Signature = CM_KEY_NODE_SIGNATURE;
		if (CreateOptions & REG_OPTION_VOLATILE)
		{
			NewKeyCell->Flags = KEY_IS_VOLATILE;
		}
		else
		{
			NewKeyCell->Flags = 0;
		}
		KeQuerySystemTime(&NewKeyCell->LastWriteTime);
		NewKeyCell->Parent = ParentKeyCellOffset;
		NewKeyCell->SubKeyCounts[Stable] = 0;
		NewKeyCell->SubKeyCounts[Volatile] = 0;
		NewKeyCell->SubKeyLists[Stable] = HCELL_NIL;
		NewKeyCell->SubKeyLists[Volatile] = HCELL_NIL;
		NewKeyCell->ValueList.Count = 0;
		NewKeyCell->ValueList.List = HCELL_NIL;
		NewKeyCell->Security = HCELL_NIL;
		NewKeyCell->Class = HCELL_NIL;

		/* Pack the key name */
		NewKeyCell->NameLength = NameLength;
		if (Packable)
		{
			NewKeyCell->Flags |= KEY_COMP_NAME;
			for (i = 0; i < NameLength; i++)
			{
				((PCHAR)NewKeyCell->Name)[i] = (CHAR)(NamePtr[i] & 0x00FF);
			}
		}
		else
		{
			RtlCopyMemory(
				NewKeyCell->Name,
				NamePtr,
				NameLength);
		}

		VERIFY_KEY_CELL(NewKeyCell);
	}

	if (!NT_SUCCESS(Status))
	{
		return Status;
	}

	if (ParentKeyCell->SubKeyLists[Storage] == HCELL_NIL)
	{
		Status = CmiAllocateHashTableCell (
			RegistryHive,
			&HashBlock,
			&ParentKeyCell->SubKeyLists[Storage],
			REG_INIT_HASH_TABLE_SIZE,
			Storage);
		if (!NT_SUCCESS(Status))
		{
			return(Status);
		}
	}
	else
	{
		HashBlock = (PCM_KEY_FAST_INDEX)HvGetCell (
			&RegistryHive->Hive,
			ParentKeyCell->SubKeyLists[Storage]);
		ASSERT(HashBlock->Signature == CM_KEY_FAST_LEAF);

		if (HashBlock->Count ==
		    ((HvGetCellSize(&RegistryHive->Hive, HashBlock) - FIELD_OFFSET(CM_KEY_FAST_INDEX, List)) / sizeof(CM_INDEX)))
		{
			PCM_KEY_FAST_INDEX NewHashBlock;
			HCELL_INDEX HTOffset;

			/* Reallocate the hash table cell */
			Status = CmiAllocateHashTableCell (
				RegistryHive,
				&NewHashBlock,
				&HTOffset,
				HashBlock->Count +
				REG_EXTEND_HASH_TABLE_SIZE,
				Storage);
			if (!NT_SUCCESS(Status))
			{
				return Status;
			}
			RtlCopyMemory(
				&NewHashBlock->List[0],
				&HashBlock->List[0],
				sizeof(NewHashBlock->List[0]) * HashBlock->Count);
         NewHashBlock->Count = HashBlock->Count;
			HvFreeCell (&RegistryHive->Hive, ParentKeyCell->SubKeyLists[Storage]);
			ParentKeyCell->SubKeyLists[Storage] = HTOffset;
			HashBlock = NewHashBlock;
		}
	}

	Status = CmiAddKeyToHashTable(
		RegistryHive,
		HashBlock,
      ParentKeyCell->SubKeyLists[Storage],
		NewKeyCell,
		NKBOffset);
	if (NT_SUCCESS(Status))
	{
		ParentKeyCell->SubKeyCounts[Storage]++;
		if (Packable)
        {
            if (NameLength*sizeof(WCHAR) > ParentKeyCell->MaxNameLen)
                ParentKeyCell->MaxNameLen = NameLength*sizeof(WCHAR);
        }
        else
        {
            if (NameLength > ParentKeyCell->MaxNameLen)
                ParentKeyCell->MaxNameLen = NameLength;
        }
        if (NewKeyCell->ClassLength > ParentKeyCell->MaxClassLen)
            ParentKeyCell->MaxClassLen = NewKeyCell->ClassLength;

		*pSubKeyCell = NewKeyCell;
		*pBlockOffset = NKBOffset;
	}

	KeQuerySystemTime(&ParentKeyCell->LastWriteTime);
	HvMarkCellDirty(&RegistryHive->Hive, ParentKeyCellOffset, FALSE);

	return Status;
}