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; }
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; }
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; }
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; }
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; }
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; }