ULONG CmpCheckValueList( PHHIVE Hive, PCELL_DATA List, ULONG Count ) /*++ Routine Description: Check consistency of a value list. . Each element allocated? . Each element have valid signature? . Data properly allocated? Arguments: Hive - containing Hive. List - pointer to an array of HCELL_INDEX entries. Count - number of entries in list. Return Value: 0 if Hive is OK. Error return indicator if not. RANGE: 5000 - 5999 --*/ { ULONG i; HCELL_INDEX Cell; PCELL_DATA pcell; ULONG size; ULONG usedlen; ULONG DataLength; HCELL_INDEX Data; ULONG rc = 0; CmpCheckValueListDebug.Hive = Hive; CmpCheckValueListDebug.Status = 0; CmpCheckValueListDebug.List = List; CmpCheckValueListDebug.Index = (ULONG)-1; CmpCheckValueListDebug.Cell = 0; // NOT HCELL_NIL CmpCheckValueListDebug.CellPoint = NULL; for (i = 0; i < Count; i++) { // // Check out value entry's refs. // Cell = List->u.KeyList[i]; if (Cell == HCELL_NIL) { KdPrint(("CmpCheckValueList: List:%08lx i:%08lx\n", List, i)); KdPrint(("\tEntry is null\n")); rc = 5010; CmpCheckValueListDebug.Status = rc; CmpCheckValueListDebug.Index = i; CmpCheckValueListDebug.Cell = Cell; return rc; } if (HvIsCellAllocated(Hive, Cell) == FALSE) { KdPrint(("CmpCheckValueList: List:%08lx i:%08lx\n", List, i)); KdPrint(("\tEntry is not allocated\n")); rc = 5020; CmpCheckValueListDebug.Status = rc; CmpCheckValueListDebug.Index = i; CmpCheckValueListDebug.Cell = Cell; return rc; } else { SetUsed(Hive, Cell); } // // Check out the value entry itself // pcell = HvGetCell(Hive, Cell); size = HvGetCellSize(Hive, pcell); if (pcell->u.KeyValue.Signature != CM_KEY_VALUE_SIGNATURE) { KdPrint(("CmpCheckValueList: List:%08lx i:%08lx\n", List, i)); KdPrint(("\tCell:%08lx - invalid value signature\n", Cell)); rc = 5030; CmpCheckValueListDebug.Status = rc; CmpCheckValueListDebug.Index = i; CmpCheckValueListDebug.Cell = Cell; CmpCheckValueListDebug.CellPoint = pcell; return rc; } usedlen = FIELD_OFFSET(CM_KEY_VALUE, Name) + pcell->u.KeyValue.NameLength; if (usedlen > size) { KdPrint(("CmpCheckValueList: List:%08lx i:%08lx\n", List, i)); KdPrint(("\tCell:%08lx - value bigger than containing cell\n", Cell)); rc = 5040; CmpCheckValueListDebug.Status = rc; CmpCheckValueListDebug.Index = i; CmpCheckValueListDebug.Cell = Cell; CmpCheckValueListDebug.CellPoint = pcell; return rc; } // // Check out value entry's data // DataLength = pcell->u.KeyValue.DataLength; if (DataLength < CM_KEY_VALUE_SPECIAL_SIZE) { Data = pcell->u.KeyValue.Data; if ((DataLength == 0) && (Data != HCELL_NIL)) { KdPrint(("CmpCheckValueList: List:%08lx i:%08lx\n", List, i)); KdPrint(("\tCell:%08lx Data:%08lx - data not null\n", Cell, Data)); rc = 5050; CmpCheckValueListDebug.Status = rc; CmpCheckValueListDebug.Index = i; CmpCheckValueListDebug.Cell = Cell; CmpCheckValueListDebug.CellPoint = pcell; return rc; } if (DataLength > 0) { if (HvIsCellAllocated(Hive, Data) == FALSE) { KdPrint(("CmpCheckValueList: List:%08lx i:%08lx\n", List, i)); KdPrint(("\tCell:%08lx Data:%08lx - unallocated\n", Cell, Data)); rc = 5060; CmpCheckValueListDebug.Status = rc; CmpCheckValueListDebug.Index = i; CmpCheckValueListDebug.Cell = Cell; CmpCheckValueListDebug.CellPoint = pcell; return rc; } else { SetUsed(Hive, Data); } } } } return rc; }
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; }
VALUE_SEARCH_RETURN_TYPE CmpGetValueKeyFromCache( IN PCM_KEY_CONTROL_BLOCK KeyControlBlock, IN PCELL_DATA List, IN ULONG Index, OUT PPCM_CACHED_VALUE *ContainingList, OUT PCM_KEY_VALUE *Value, IN BOOLEAN IndexCached, OUT BOOLEAN *ValueCached, OUT PHCELL_INDEX CellToRelease ) /*++ Routine Description: Get the Valve Node. Check if it is already cached, if not but the index is cached, cache and return the value node. Arguments: Hive - pointer to hive control structure for hive of interest. List - pointer to the Value Index Array (of ULONG_PTR if cached and ULONG if non-cached) Index - Index in the Value index array ContainlingList - The address of the entry that will receive the found cached value. IndexCached - Indicate if the index list is cached. If not, everything is from the original registry data. ValueCached - Indicating whether Value is cached or not. Return Value: Pointer to the Value Node. NULL when we couldn't map a view --*/ { PULONG_PTR CachedList; ULONG AllocSize; ULONG CopySize; PCM_CACHED_VALUE CachedValue; PHHIVE Hive; *CellToRelease = HCELL_NIL; Hive = KeyControlBlock->KeyHive; *Value = NULL; if (IndexCached) { // // The index array is cached, so List is pointing to an array of ULONG_PTR. // Use CachedList. // CachedList = (PULONG_PTR) List; *ValueCached = TRUE; if (CMP_IS_CELL_CACHED(CachedList[Index])) { *Value = CMP_GET_CACHED_KEYVALUE(CachedList[Index]); *ContainingList = &((PCM_CACHED_VALUE) CachedList[Index]); } else { // // ensure exclusive lock. // if( (CmpIsKCBLockedExclusive(KeyControlBlock) == FALSE) && (CmpTryConvertKCBLockSharedToExclusive(KeyControlBlock) == FALSE) ) { // // need to upgrade lock to exclusive // return SearchNeedExclusiveLock; } *Value = (PCM_KEY_VALUE) HvGetCell(Hive, List->u.KeyList[Index]); if( *Value == NULL ) { // // we couldn't map a view for this cell // just return NULL; the caller must handle it gracefully // return SearchFail; } *CellToRelease = List->u.KeyList[Index]; // // Allocate a PagedPool to cache the value node. // CopySize = (ULONG) HvGetCellSize(Hive, *Value); AllocSize = CopySize + FIELD_OFFSET(CM_CACHED_VALUE, KeyValue); CachedValue = (PCM_CACHED_VALUE) ExAllocatePoolWithTag(PagedPool, AllocSize, CM_CACHE_VALUE_TAG); if (CachedValue) { // // Set the information for later use if we need to cache data as well. // if ((*Value)->Flags & VALUE_COMP_NAME) { CachedValue->HashKey = CmpComputeHashKeyForCompressedName(0,(*Value)->Name,(*Value)->NameLength); } else { UNICODE_STRING TmpStr; TmpStr.Length = (*Value)->NameLength; TmpStr.Buffer = (*Value)->Name; CachedValue->HashKey = CmpComputeHashKey(0,&TmpStr #if DBG , TRUE #endif ); } CachedValue->DataCacheType = CM_CACHE_DATA_NOT_CACHED; CachedValue->ValueKeySize = (USHORT) CopySize; RtlCopyMemory((PVOID)&(CachedValue->KeyValue), *Value, CopySize); // Trying to catch the BAD guy who writes over our pool. CmpMakeSpecialPoolReadWrite( CMP_GET_CACHED_ADDRESS(CachedList) ); CachedList[Index] = CMP_MARK_CELL_CACHED(CachedValue); // Trying to catch the BAD guy who writes over our pool. CmpMakeSpecialPoolReadOnly( CMP_GET_CACHED_ADDRESS(CachedList) ); // Trying to catch the BAD guy who writes over our pool. CmpMakeSpecialPoolReadOnly(CachedValue); *ContainingList = &((PCM_CACHED_VALUE) CachedList[Index]); // // Now we have the stuff cached, use the cache data. // (*Value) = CMP_GET_CACHED_KEYVALUE(CachedValue); } else { // // If the allocation fails, just do not cache it. continue. // *ValueCached = FALSE; } } } else { // // The Valve Index Array is from the registry hive, just get the cell and move on. // (*Value) = (PCM_KEY_VALUE) HvGetCell(Hive, List->u.KeyList[Index]); *ValueCached = FALSE; if( *Value == NULL ) { // // we couldn't map a view for this cell // just return NULL; the caller must handle it gracefully // OBS: we may remove this as we return pchild anyway; just for clarity // return SearchFail; } *CellToRelease = List->u.KeyList[Index]; } return SearchSuccess; }
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; }