static NTSTATUS CmiAllocateHashTableCell ( IN PCMHIVE RegistryHive, OUT PCM_KEY_FAST_INDEX *HashBlock, OUT HCELL_INDEX *HBOffset, IN USHORT SubKeyCount, IN HSTORAGE_TYPE Storage) { PCM_KEY_FAST_INDEX NewHashBlock; ULONG NewHashSize; NTSTATUS Status; Status = STATUS_SUCCESS; *HashBlock = NULL; NewHashSize = FIELD_OFFSET(CM_KEY_FAST_INDEX, List) + (SubKeyCount * sizeof(CM_INDEX)); *HBOffset = HvAllocateCell(&RegistryHive->Hive, NewHashSize, Storage, HCELL_NIL); if (*HBOffset == HCELL_NIL) { Status = STATUS_INSUFFICIENT_RESOURCES; } else { NewHashBlock = (PCM_KEY_FAST_INDEX)HvGetCell (&RegistryHive->Hive, *HBOffset); NewHashBlock->Signature = CM_KEY_FAST_LEAF; NewHashBlock->Count = 0; *HashBlock = NewHashBlock; } return Status; }
static NTSTATUS CmiAllocateValueCell( IN PCMHIVE RegistryHive, OUT PCM_KEY_VALUE *ValueCell, OUT HCELL_INDEX *VBOffset, IN PCUNICODE_STRING ValueName, IN HSTORAGE_TYPE Storage) { PCM_KEY_VALUE NewValueCell; BOOLEAN Packable; USHORT NameLength, i; NTSTATUS Status; Status = STATUS_SUCCESS; NameLength = CmiGetPackedNameLength(ValueName, &Packable); DPRINT("ValueName->Length %u NameLength %u\n", ValueName->Length, NameLength); *VBOffset = HvAllocateCell(&RegistryHive->Hive, sizeof(CM_KEY_VALUE) + NameLength, Storage, HCELL_NIL); if (*VBOffset == HCELL_NIL) { Status = STATUS_INSUFFICIENT_RESOURCES; } else { NewValueCell = (PCM_KEY_VALUE)HvGetCell (&RegistryHive->Hive, *VBOffset); NewValueCell->Signature = CM_KEY_VALUE_SIGNATURE; NewValueCell->NameLength = (USHORT)NameLength; if (Packable) { /* Pack the value name */ for (i = 0; i < NameLength; i++) ((PCHAR)NewValueCell->Name)[i] = (CHAR)ValueName->Buffer[i]; NewValueCell->Flags |= VALUE_COMP_NAME; } else { /* Copy the value name */ RtlCopyMemory( NewValueCell->Name, ValueName->Buffer, NameLength); NewValueCell->Flags = 0; } NewValueCell->Type = 0; NewValueCell->DataLength = 0; NewValueCell->Data = HCELL_NIL; *ValueCell = NewValueCell; } return Status; }
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; }