BOOLEAN NTAPI CmpFreeKeyBody(IN PHHIVE Hive, IN HCELL_INDEX Cell) { PCELL_DATA CellData; /* Get the key node */ CellData = HvGetCell(Hive, Cell); if (!CellData) ASSERT(FALSE); /* Check if we can delete the child cells */ if (!(CellData->u.KeyNode.Flags & KEY_HIVE_EXIT)) { /* Check if we have a security cell */ if (CellData->u.KeyNode.Security != HCELL_NIL) { /* Free the security cell */ HvFreeCell(Hive, CellData->u.KeyNode.Security); } /* Check if we have a class */ if (CellData->u.KeyNode.ClassLength > 0) { /* Free it */ HvFreeCell(Hive, CellData->u.KeyNode.Class); } } /* Release and free the cell */ HvReleaseCell(Hive, Cell); HvFreeCell(Hive, Cell); return TRUE; }
VOID CmpFreeKeyBody( PHHIVE Hive, HCELL_INDEX Cell ) /*++ Routine Description: Free storage for the key entry Hive.Cell refers to, including its class and security data. Will NOT free child list or value list. Arguments: Hive - supplies a pointer to the hive control structure for the hive Cell - supplies index of key to free Return Value: NTSTATUS - Result code from call, among the following: <TBS> --*/ { PCELL_DATA key; // // map in the cell // key = HvGetCell(Hive, Cell); if (!(key->u.KeyNode.Flags & KEY_HIVE_EXIT)) { if (key->u.KeyNode.Security != HCELL_NIL) { HvFreeCell(Hive, key->u.KeyNode.Security); } if (key->u.KeyNode.ClassLength > 0) { HvFreeCell(Hive, key->u.KeyNode.Class); } } // // unmap the cell itself and free it // HvFreeCell(Hive, Cell); return; }
NTSTATUS NTAPI CmpFreeKeyByCell(IN PHHIVE Hive, IN HCELL_INDEX Cell, IN BOOLEAN Unlink) { PCELL_DATA CellData, ParentData, ListData; ULONG i; BOOLEAN Result; /* Mark the entire key dirty */ CmpMarkKeyDirty(Hive, Cell ,TRUE); /* Get the target node and release it */ CellData = HvGetCell(Hive, Cell); if (!CellData) ASSERT(FALSE); HvReleaseCell(Hive, Cell); /* Make sure we don't have subkeys */ ASSERT((CellData->u.KeyNode.SubKeyCounts[Stable] + CellData->u.KeyNode.SubKeyCounts[Volatile]) == 0); /* Check if we have to unlink */ if (Unlink) { /* Remove the subkey */ Result = CmpRemoveSubKey(Hive, CellData->u.KeyNode.Parent, Cell); if (!Result) return STATUS_INSUFFICIENT_RESOURCES; /* Get the parent node and release it */ ParentData = HvGetCell(Hive, CellData->u.KeyNode.Parent); if (!ParentData) ASSERT(FALSE); HvReleaseCell(Hive, CellData->u.KeyNode.Parent); /* Check if the parent node has no more subkeys */ if (!(ParentData->u.KeyNode.SubKeyCounts[Stable] + ParentData->u.KeyNode.SubKeyCounts[Volatile])) { /* Then free the cached name/class lengths */ ParentData->u.KeyNode.MaxNameLen = 0; ParentData->u.KeyNode.MaxClassLen = 0; } } /* Check if we have any values */ if (CellData->u.KeyNode.ValueList.Count > 0) { /* Get the value list and release it */ ListData = HvGetCell(Hive, CellData->u.KeyNode.ValueList.List); if (!ListData) ASSERT(FALSE); HvReleaseCell(Hive, CellData->u.KeyNode.ValueList.List); /* Loop every value */ for (i = 0; i < CellData->u.KeyNode.ValueList.Count; i++) { /* Free it */ if (!CmpFreeValue(Hive, ListData->u.KeyList[i])) ASSERT(FALSE); } /* Free the value list */ HvFreeCell(Hive, CellData->u.KeyNode.ValueList.List); } /* Free the key body itself, and then return our status */ if (!CmpFreeKeyBody(Hive, Cell)) return STATUS_INSUFFICIENT_RESOURCES; return STATUS_SUCCESS; }
NTSTATUS NTAPI CmpFreeKeyByCell(IN PHHIVE Hive, IN HCELL_INDEX Cell, IN BOOLEAN Unlink) { PCM_KEY_NODE CellData, ParentData; PCELL_DATA ListData; ULONG i; BOOLEAN Result; /* Mark the entire key dirty */ CmpMarkKeyDirty(Hive, Cell, TRUE); /* Get the target node and release it */ CellData = HvGetCell(Hive, Cell); if (!CellData) ASSERT(FALSE); HvReleaseCell(Hive, Cell); /* Make sure we don't have subkeys */ ASSERT(CellData->SubKeyCounts[Stable] + CellData->SubKeyCounts[Volatile] == 0); /* Check if we have to unlink */ if (Unlink) { /* Remove the subkey */ Result = CmpRemoveSubKey(Hive, CellData->Parent, Cell); if (!Result) return STATUS_INSUFFICIENT_RESOURCES; /* Get the parent node and release it */ ParentData = HvGetCell(Hive, CellData->Parent); if (!ParentData) ASSERT(FALSE); HvReleaseCell(Hive, CellData->Parent); /* Check if the parent node has no more subkeys */ if (ParentData->SubKeyCounts[Stable] + ParentData->SubKeyCounts[Volatile] == 0) { /* Then free the cached name/class lengths */ ParentData->MaxNameLen = 0; ParentData->MaxClassLen = 0; } } // TODO: Handle predefined keys (Flags: KEY_PREDEF_HANDLE) /* If this is an exit node, we don't have values */ if (!(CellData->Flags & KEY_HIVE_EXIT)) { /* Check if we have any values */ if (CellData->ValueList.Count > 0) { /* Get the value list and release it */ ListData = HvGetCell(Hive, CellData->ValueList.List); if (!ListData) ASSERT(FALSE); HvReleaseCell(Hive, CellData->ValueList.List); /* Loop every value */ for (i = 0; i < CellData->ValueList.Count; i++) { /* Free it */ if (!CmpFreeValue(Hive, ListData->u.KeyList[i])) ASSERT(FALSE); } /* Free the value list */ HvFreeCell(Hive, CellData->ValueList.List); } /* Free the key security descriptor */ CmpFreeSecurityDescriptor(Hive, Cell); } /* Free the key body itself, and then return our status */ if (!CmpFreeKeyBody(Hive, Cell)) return STATUS_INSUFFICIENT_RESOURCES; return STATUS_SUCCESS; }
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 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; }