diff --git a/reactos/lib/cmlib/hivecell.c b/reactos/lib/cmlib/hivecell.c index ebde802e542..cc3d5d5203d 100644 --- a/reactos/lib/cmlib/hivecell.c +++ b/reactos/lib/cmlib/hivecell.c @@ -221,7 +221,7 @@ HvpRemoveFree( pFreeCellOffset = FreeCellData; } - ASSERT(FALSE); + //ASSERT(FALSE); } static HCELL_INDEX CMAPI diff --git a/reactos/ntoskrnl/cm/cm.h b/reactos/ntoskrnl/cm/cm.h index 1791e671444..3b02e5a6c78 100644 --- a/reactos/ntoskrnl/cm/cm.h +++ b/reactos/ntoskrnl/cm/cm.h @@ -167,9 +167,6 @@ VOID CmiAddKeyToList(IN PKEY_OBJECT ParentKey, IN PKEY_OBJECT NewKey); -NTSTATUS -CmiRemoveKeyFromList(IN PKEY_OBJECT NewKey); - NTSTATUS CmiScanKeyList(IN PKEY_OBJECT Parent, IN PUNICODE_STRING KeyName, @@ -184,9 +181,6 @@ CmiLoadHive(POBJECT_ATTRIBUTES KeyObjectAttributes, NTSTATUS CmiFlushRegistryHive(PEREGISTRY_HIVE RegistryHive); -ULONG -CmiGetNumberOfSubKeys(PKEY_OBJECT KeyObject); - ULONG CmiGetMaxNameLength(IN PHHIVE RegistryHive, IN PCM_KEY_NODE KeyCell); @@ -219,11 +213,6 @@ CmiAddSubKey(IN PEREGISTRY_HIVE RegistryHive, IN PUNICODE_STRING Class, IN ULONG CreateOptions); -NTSTATUS -CmiRemoveSubKey(IN PEREGISTRY_HIVE RegistryHive, - IN PKEY_OBJECT Parent, - IN PKEY_OBJECT SubKey); - NTSTATUS CmiScanKeyForValue(IN PEREGISTRY_HIVE RegistryHive, IN PCM_KEY_NODE KeyCell, @@ -279,6 +268,10 @@ CmEnumerateKey(IN PKEY_OBJECT KeyObject, IN ULONG Length, IN PULONG ResultLength); +NTSTATUS +NTAPI +CmDeleteKey(IN PKEY_OBJECT KeyObject); + NTSTATUS CmiAllocateHashTableCell(IN PEREGISTRY_HIVE RegistryHive, OUT PHASH_TABLE_CELL *HashBlock, @@ -294,16 +287,6 @@ CmiAddKeyToHashTable(PEREGISTRY_HIVE RegistryHive, PCM_KEY_NODE NewKeyCell, HCELL_INDEX NKBOffset); -NTSTATUS -CmiRemoveKeyFromHashTable(PEREGISTRY_HIVE RegistryHive, - PHASH_TABLE_CELL HashBlock, - HCELL_INDEX NKBOffset); - -NTSTATUS -CmiDestroyValueCell(PEREGISTRY_HIVE RegistryHive, - PCM_KEY_VALUE ValueCell, - HCELL_INDEX VBOffset); - NTSTATUS CmiConnectHive(POBJECT_ATTRIBUTES KeyObjectAttributes, PEREGISTRY_HIVE RegistryHive); @@ -330,10 +313,6 @@ CmpFindSubKeyByName( VOID CmiSyncHives(VOID); -NTSTATUS -CmiSaveTempHive (PEREGISTRY_HIVE Hive, - HANDLE FileHandle); - NTSTATUS NTAPI CmFindObject( diff --git a/reactos/ntoskrnl/cm/ntfunc.c b/reactos/ntoskrnl/cm/ntfunc.c index 256da6b746f..d4a44199d3c 100644 --- a/reactos/ntoskrnl/cm/ntfunc.c +++ b/reactos/ntoskrnl/cm/ntfunc.c @@ -435,115 +435,6 @@ Cleanup: return Status; } - -NTSTATUS STDCALL -NtDeleteKey(IN HANDLE KeyHandle) -{ - KPROCESSOR_MODE PreviousMode; - PKEY_OBJECT KeyObject; - NTSTATUS Status; - REG_DELETE_KEY_INFORMATION DeleteKeyInfo; - REG_POST_OPERATION_INFORMATION PostOperationInfo; - - PAGED_CODE(); - - DPRINT("NtDeleteKey(KeyHandle 0x%p) called\n", KeyHandle); - - PreviousMode = ExGetPreviousMode(); - - /* Verify that the handle is valid and is a registry key */ - Status = ObReferenceObjectByHandle(KeyHandle, - DELETE, - CmpKeyObjectType, - PreviousMode, - (PVOID *)&KeyObject, - NULL); - if (!NT_SUCCESS(Status)) - { - DPRINT1("ObReferenceObjectByHandle() failed (Status %lx)\n", Status); - return Status; - } - - PostOperationInfo.Object = (PVOID)KeyObject; - DeleteKeyInfo.Object = (PVOID)KeyObject; - Status = CmiCallRegisteredCallbacks(RegNtPreDeleteKey, &DeleteKeyInfo); - if (!NT_SUCCESS(Status)) - { - PostOperationInfo.Status = Status; - CmiCallRegisteredCallbacks(RegNtPostDeleteKey, &PostOperationInfo); - ObDereferenceObject(KeyObject); - return Status; - } - - /* Acquire hive lock */ - KeEnterCriticalRegion(); - ExAcquireResourceExclusiveLite(&CmpRegistryLock, TRUE); - - VERIFY_KEY_OBJECT(KeyObject); - - /* Check for subkeys */ - if (KeyObject->KeyCell->SubKeyCounts[HvStable] != 0 || - KeyObject->KeyCell->SubKeyCounts[HvVolatile] != 0) - { - Status = STATUS_CANNOT_DELETE; - } - else - { - PKEY_OBJECT ParentKeyObject = KeyObject->ParentKey; - - if (!NT_SUCCESS(CmiRemoveKeyFromList(KeyObject))) - { - DPRINT1("Key not found in parent list ???\n"); - } - - CmiRemoveSubKey(KeyObject->RegistryHive, - ParentKeyObject, - KeyObject); - - KeQuerySystemTime (&ParentKeyObject->KeyCell->LastWriteTime); - HvMarkCellDirty(&ParentKeyObject->RegistryHive->Hive, - ParentKeyObject->KeyCellOffset); - - if (!IsNoFileHive (KeyObject->RegistryHive) || - !IsNoFileHive (ParentKeyObject->RegistryHive)) - { - CmiSyncHives (); - } - - Status = STATUS_SUCCESS; - } - - /* Release hive lock */ - ExReleaseResourceLite(&CmpRegistryLock); - KeLeaveCriticalRegion(); - - DPRINT("PointerCount %lu\n", ObGetObjectPointerCount((PVOID)KeyObject)); - - /* Remove the keep-alive reference */ - ObDereferenceObject(KeyObject); - - if (KeyObject->RegistryHive != KeyObject->ParentKey->RegistryHive) - ObDereferenceObject(KeyObject); - - PostOperationInfo.Status = Status; - CmiCallRegisteredCallbacks(RegNtPostDeleteKey, &PostOperationInfo); - - /* Dereference the object */ - ObDereferenceObject(KeyObject); - - DPRINT("PointerCount %lu\n", ObGetObjectPointerCount((PVOID)KeyObject)); - DPRINT("HandleCount %lu\n", ObGetObjectHandleCount((PVOID)KeyObject)); - - /* - * Note: - * Hive-Synchronization will not be triggered here. This is done in - * CmpDeleteKeyObject() (in regobj.c) after all key-related structures - * have been released. - */ - - return Status; -} - NTSTATUS STDCALL NtFlushKey(IN HANDLE KeyHandle) { @@ -812,6 +703,52 @@ NtInitializeRegistry (IN BOOLEAN SetUpBoot) return Status; } +NTSTATUS +NTAPI +NtDeleteKey(IN HANDLE KeyHandle) +{ + PKEY_OBJECT KeyObject; + NTSTATUS Status; + REG_DELETE_KEY_INFORMATION DeleteKeyInfo; + REG_POST_OPERATION_INFORMATION PostOperationInfo; + PAGED_CODE(); + + /* Verify that the handle is valid and is a registry key */ + Status = ObReferenceObjectByHandle(KeyHandle, + DELETE, + CmpKeyObjectType, + ExGetPreviousMode(), + (PVOID *)&KeyObject, + NULL); + if (!NT_SUCCESS(Status)) return Status; + + /* Setup the callback */ + PostOperationInfo.Object = (PVOID)KeyObject; + DeleteKeyInfo.Object = (PVOID)KeyObject; + Status = CmiCallRegisteredCallbacks(RegNtPreDeleteKey, &DeleteKeyInfo); + if (NT_SUCCESS(Status)) + { + /* Call the internal API */ + Status = CmDeleteKey(KeyObject); + + /* Remove the keep-alive reference */ + ObDereferenceObject(KeyObject); + if (KeyObject->RegistryHive != KeyObject->ParentKey->RegistryHive) + { + /* Dereference again */ + ObDereferenceObject(KeyObject); + } + + /* Do post callback */ + PostOperationInfo.Status = Status; + CmiCallRegisteredCallbacks(RegNtPostDeleteKey, &PostOperationInfo); + } + + /* Dereference the object */ + ObDereferenceObject(KeyObject); + return Status; +} + NTSTATUS NTAPI NtEnumerateKey(IN HANDLE KeyHandle, diff --git a/reactos/ntoskrnl/cm/regfile.c b/reactos/ntoskrnl/cm/regfile.c index 7532421df8d..ef4c21b3d61 100644 --- a/reactos/ntoskrnl/cm/regfile.c +++ b/reactos/ntoskrnl/cm/regfile.c @@ -66,7 +66,6 @@ CmCloseHiveFiles(PEREGISTRY_HIVE RegistryHive) ZwClose(RegistryHive->LogHandle); } - NTSTATUS CmiFlushRegistryHive(PEREGISTRY_HIVE RegistryHive) { @@ -103,26 +102,6 @@ CmiFlushRegistryHive(PEREGISTRY_HIVE RegistryHive) return Success ? STATUS_SUCCESS : STATUS_UNSUCCESSFUL; } - -ULONG -CmiGetNumberOfSubKeys(PKEY_OBJECT KeyObject) -{ - PCM_KEY_NODE KeyCell; - ULONG SubKeyCount; - - VERIFY_KEY_OBJECT(KeyObject); - - KeyCell = KeyObject->KeyCell; - VERIFY_KEY_CELL(KeyCell); - - SubKeyCount = (KeyCell == NULL) ? 0 : - KeyCell->SubKeyCounts[HvStable] + - KeyCell->SubKeyCounts[HvVolatile]; - - return SubKeyCount; -} - - ULONG CmiGetMaxNameLength(PHHIVE Hive, PCM_KEY_NODE KeyCell) @@ -160,7 +139,6 @@ CmiGetMaxNameLength(PHHIVE Hive, return MaxName; } - ULONG CmiGetMaxClassLength(PHHIVE Hive, PCM_KEY_NODE KeyCell) @@ -196,7 +174,6 @@ CmiGetMaxClassLength(PHHIVE Hive, return MaxClass; } - ULONG CmiGetMaxValueNameLength(PHHIVE Hive, PCM_KEY_NODE KeyCell) @@ -244,7 +221,6 @@ CmiGetMaxValueNameLength(PHHIVE Hive, return MaxValueName; } - ULONG CmiGetMaxValueDataLength(PHHIVE Hive, PCM_KEY_NODE KeyCell) @@ -517,109 +493,6 @@ CmiAddSubKey(PEREGISTRY_HIVE RegistryHive, return(Status); } -NTSTATUS -CmiRemoveSubKey(PEREGISTRY_HIVE RegistryHive, - PKEY_OBJECT ParentKey, - PKEY_OBJECT SubKey) -{ - PHASH_TABLE_CELL HashBlock; - PVALUE_LIST_CELL ValueList; - PCM_KEY_VALUE ValueCell; - HV_STORAGE_TYPE Storage; - ULONG i; - - DPRINT("CmiRemoveSubKey() called\n"); - - Storage = (SubKey->KeyCell->Flags & REG_KEY_VOLATILE_CELL) ? HvVolatile : HvStable; - - /* Remove all values */ - if (SubKey->KeyCell->ValueList.Count != 0) - { - /* Get pointer to the value list cell */ - ValueList = HvGetCell (&RegistryHive->Hive, SubKey->KeyCell->ValueList.List); - - /* Enumerate all values */ - for (i = 0; i < SubKey->KeyCell->ValueList.Count; i++) - { - /* Get pointer to value cell */ - ValueCell = HvGetCell(&RegistryHive->Hive, - ValueList->ValueOffset[i]); - - if (!(ValueCell->DataSize & REG_DATA_IN_OFFSET) - && ValueCell->DataSize > sizeof(HCELL_INDEX) - && ValueCell->DataOffset != HCELL_NULL) - { - /* Destroy data cell */ - HvFreeCell (&RegistryHive->Hive, ValueCell->DataOffset); - } - - /* Destroy value cell */ - HvFreeCell (&RegistryHive->Hive, ValueList->ValueOffset[i]); - } - - /* Destroy value list cell */ - HvFreeCell (&RegistryHive->Hive, SubKey->KeyCell->ValueList.List); - - SubKey->KeyCell->ValueList.Count = 0; - SubKey->KeyCell->ValueList.List = (HCELL_INDEX)-1; - - HvMarkCellDirty(&RegistryHive->Hive, SubKey->KeyCellOffset); - } - - /* Remove the key from the parent key's hash block */ - if (ParentKey->KeyCell->SubKeyLists[Storage] != HCELL_NULL) - { - DPRINT("ParentKey SubKeyLists %lx\n", ParentKey->KeyCell->SubKeyLists[Storage]); - HashBlock = HvGetCell (&ParentKey->RegistryHive->Hive, - ParentKey->KeyCell->SubKeyLists[Storage]); - ASSERT(HashBlock->Id == REG_HASH_TABLE_CELL_ID); - DPRINT("ParentKey HashBlock %p\n", HashBlock); - CmiRemoveKeyFromHashTable(ParentKey->RegistryHive, - HashBlock, - SubKey->KeyCellOffset); - HvMarkCellDirty(&ParentKey->RegistryHive->Hive, - ParentKey->KeyCell->SubKeyLists[Storage]); - } - - /* Remove the key's hash block */ - if (SubKey->KeyCell->SubKeyLists[Storage] != HCELL_NULL) - { - DPRINT("SubKey SubKeyLists %lx\n", SubKey->KeyCell->SubKeyLists[Storage]); - HvFreeCell (&RegistryHive->Hive, SubKey->KeyCell->SubKeyLists[Storage]); - SubKey->KeyCell->SubKeyLists[Storage] = HCELL_NULL; - } - - /* Decrement the number of the parent key's sub keys */ - if (ParentKey != NULL) - { - DPRINT("ParentKey %p\n", ParentKey); - ParentKey->KeyCell->SubKeyCounts[Storage]--; - - /* Remove the parent key's hash table */ - if (ParentKey->KeyCell->SubKeyCounts[Storage] == 0 && - ParentKey->KeyCell->SubKeyLists[Storage] != HCELL_NULL) - { - DPRINT("ParentKey SubKeyLists %lx\n", ParentKey->KeyCell->SubKeyLists); - HvFreeCell (&ParentKey->RegistryHive->Hive, - ParentKey->KeyCell->SubKeyLists[Storage]); - ParentKey->KeyCell->SubKeyLists[Storage] = HCELL_NULL; - } - - KeQuerySystemTime(&ParentKey->KeyCell->LastWriteTime); - HvMarkCellDirty(&ParentKey->RegistryHive->Hive, - ParentKey->KeyCellOffset); - } - - /* Destroy key cell */ - HvFreeCell (&RegistryHive->Hive, SubKey->KeyCellOffset); - SubKey->KeyCell = NULL; - SubKey->KeyCellOffset = (HCELL_INDEX)-1; - - DPRINT("CmiRemoveSubKey() done\n"); - - return STATUS_SUCCESS; -} - NTSTATUS CmiAllocateHashTableCell (IN PEREGISTRY_HIVE RegistryHive, OUT PHASH_TABLE_CELL *HashBlock, @@ -675,34 +548,4 @@ CmiAddKeyToHashTable(PEREGISTRY_HIVE RegistryHive, return STATUS_SUCCESS; } -NTSTATUS -CmiRemoveKeyFromHashTable(PEREGISTRY_HIVE RegistryHive, - PHASH_TABLE_CELL HashBlock, - HCELL_INDEX NKBOffset) -{ - ULONG i; - - for (i = 0; i < HashBlock->HashTableSize; i++) - { - if (HashBlock->Table[i].KeyOffset == NKBOffset) - { - RtlMoveMemory(HashBlock->Table + i, - HashBlock->Table + i + 1, - (HashBlock->HashTableSize - i - 1) * - sizeof(HashBlock->Table[0])); - return STATUS_SUCCESS; - } - } - - return STATUS_UNSUCCESSFUL; -} - -NTSTATUS -CmiSaveTempHive (PEREGISTRY_HIVE Hive, - HANDLE FileHandle) -{ - Hive->HiveHandle = FileHandle; - return HvWriteHive(&Hive->Hive) ? STATUS_SUCCESS : STATUS_UNSUCCESSFUL; -} - /* EOF */ diff --git a/reactos/ntoskrnl/cm/regobj.c b/reactos/ntoskrnl/cm/regobj.c index ea8871e5922..4b85ef8cc3a 100644 --- a/reactos/ntoskrnl/cm/regobj.c +++ b/reactos/ntoskrnl/cm/regobj.c @@ -633,21 +633,10 @@ CmpDeleteKeyObject(PVOID DeletedObject) RemoveEntryList(&KeyObject->ListEntry); RtlFreeUnicodeString(&KeyObject->Name); - if (!NT_SUCCESS(CmiRemoveKeyFromList(KeyObject))) - { - DPRINT1("Key not found in parent list ???\n"); - } - - - ASSERT((KeyObject->Flags & KO_MARKED_FOR_DELETE) == FALSE); + ASSERT((KeyObject->Flags & KO_MARKED_FOR_DELETE) == FALSE); ObDereferenceObject (ParentKeyObject); - if (KeyObject->SubKeyCounts) - { - KEBUGCHECK(REGISTRY_ERROR); - } - if (KeyObject->SizeOfSubKeys) { ExFreePool(KeyObject->SubKeys); @@ -768,36 +757,6 @@ CmiAddKeyToList(PKEY_OBJECT ParentKey, NewKey->ParentKey = ParentKey; } - -NTSTATUS -CmiRemoveKeyFromList(PKEY_OBJECT KeyToRemove) -{ - PKEY_OBJECT ParentKey; - ULONG Index; - - ParentKey = KeyToRemove->ParentKey; - /* FIXME: If list maintained in alphabetic order, use dichotomic search */ - for (Index = 0; Index < ParentKey->SubKeyCounts; Index++) - { - if (ParentKey->SubKeys[Index] == KeyToRemove) - { - if (Index < ParentKey->SubKeyCounts-1) - RtlMoveMemory(&ParentKey->SubKeys[Index], - &ParentKey->SubKeys[Index + 1], - (ParentKey->SubKeyCounts - Index - 1) * sizeof(PKEY_OBJECT)); - ParentKey->SubKeyCounts--; - - DPRINT("Dereference parent key: 0x%x\n", ParentKey); - - ObDereferenceObject(ParentKey); - return STATUS_SUCCESS; - } - } - - return STATUS_UNSUCCESSFUL; -} - - NTSTATUS CmiScanKeyList(PKEY_OBJECT Parent, PUNICODE_STRING KeyName, diff --git a/reactos/ntoskrnl/config/cm.h b/reactos/ntoskrnl/config/cm.h index fe5f17218e0..9f47dd04125 100644 --- a/reactos/ntoskrnl/config/cm.h +++ b/reactos/ntoskrnl/config/cm.h @@ -693,6 +693,7 @@ typedef struct _KEY_INFORMATION #define SYSTEM_LOG_FILE L"\\SystemRoot\\System32\\Config\\SYSTEM.log" #define REG_SYSTEM_KEY_NAME L"\\Registry\\Machine\\SYSTEM" #define REG_HARDWARE_KEY_NAME L"\\Registry\\Machine\\HARDWARE" +#define IsNoFileHive(Hive) ((Hive)->Flags & HIVE_NO_FILE) typedef struct _EREGISTRY_HIVE { HHIVE Hive; @@ -1032,6 +1033,14 @@ EnlistKeyBodyWithKCB( IN ULONG Flags ); +NTSTATUS +NTAPI +CmpFreeKeyByCell( + IN PHHIVE Hive, + IN HCELL_INDEX Cell, + IN BOOLEAN Unlink +); + // // Name Functions // @@ -1131,6 +1140,22 @@ CmpComputeHashKey( IN BOOLEAN AllowSeparators ); +BOOLEAN +NTAPI +CmpRemoveSubKey( + IN PHHIVE Hive, + IN HCELL_INDEX ParentKey, + IN HCELL_INDEX TargetKey +); + +BOOLEAN +NTAPI +CmpMarkIndexDirty( + IN PHHIVE Hive, + HCELL_INDEX ParentKey, + HCELL_INDEX TargetKey +); + // // Cell Value Routines // diff --git a/reactos/ntoskrnl/config/cmapi.c b/reactos/ntoskrnl/config/cmapi.c index fd1bf9c568d..a10e2715e6d 100644 --- a/reactos/ntoskrnl/config/cmapi.c +++ b/reactos/ntoskrnl/config/cmapi.c @@ -983,3 +983,87 @@ Quickie: KeLeaveCriticalRegion(); return Status; } + +NTSTATUS +NTAPI +CmDeleteKey(IN PKEY_OBJECT KeyObject) +{ + NTSTATUS Status; + PHHIVE Hive; + PCM_KEY_NODE Node, Parent; + HCELL_INDEX Cell, ParentCell; + + /* Acquire hive lock */ + KeEnterCriticalRegion(); + ExAcquireResourceExclusiveLite(&CmpRegistryLock, TRUE); + + /* Get the hive and node */ + Hive = &KeyObject->RegistryHive->Hive; + Cell = KeyObject->KeyCellOffset; + + /* Check if we have no parent */ + if (!KeyObject->ParentKey) + { + /* This is an attempt to delete \Registry itself! */ + Status = STATUS_CANNOT_DELETE; + goto Quickie; + } + + /* Get the key node */ + Node = (PCM_KEY_NODE)HvGetCell(Hive, Cell); + if (!Node) + { + /* Fail */ + Status = STATUS_INSUFFICIENT_RESOURCES; + goto Quickie; + } + + /* Check if we don't have any children */ + if (!(Node->SubKeyCounts[HvStable] + Node->SubKeyCounts[HvVolatile])) + { + /* Get the parent and free the cell */ + ParentCell = Node->Parent; + Status = CmpFreeKeyByCell(Hive, Cell, TRUE); + if (NT_SUCCESS(Status)) + { + /* Get the parent node */ + Parent = (PCM_KEY_NODE)HvGetCell(Hive, ParentCell); + if (Parent) + { + /* Make sure we're dirty */ + ASSERT(HvIsCellDirty(Hive, ParentCell)); + + /* Update the write time */ + KeQuerySystemTime(&Parent->LastWriteTime); + + /* Release the cell */ + HvReleaseCell(Hive, ParentCell); + } + + /* Clear the cell */ + KeyObject->KeyCellOffset = HCELL_NIL; + } + } + else + { + /* Fail */ + Status = STATUS_CANNOT_DELETE; + } + +Quickie: + /* Release the cell */ + HvReleaseCell(Hive, Cell); + + /* Make sure we're file-backed */ + if (!(IsNoFileHive(KeyObject->RegistryHive)) || + !(IsNoFileHive(KeyObject->ParentKey->RegistryHive))) + { + /* Sync up the hives */ + CmiSyncHives(); + } + + /* Release hive lock */ + ExReleaseResourceLite(&CmpRegistryLock); + KeLeaveCriticalRegion(); + return Status; +} diff --git a/reactos/ntoskrnl/config/cmindex.c b/reactos/ntoskrnl/config/cmindex.c index 306b30a3bfe..7dab40272aa 100644 --- a/reactos/ntoskrnl/config/cmindex.c +++ b/reactos/ntoskrnl/config/cmindex.c @@ -703,12 +703,6 @@ CmpFindSubKeyByName(IN PHHIVE Hive, { /* Get the Index */ IndexRoot = (PCM_KEY_INDEX)HvGetCell(Hive, Parent->SubKeyLists[i]); -#if 0 - /* Make sure we have one and that the cell is allocated */ - ASSERT((IndexRoot == NULL) || - HvIsCellAllocated(Hive, Parent->SubKeyLists[i])); -#endif - /* Fail if we don't actually have an index root */ if (!IndexRoot) return HCELL_NIL; /* Get the cell we'll need to release */ @@ -777,3 +771,343 @@ CmpFindSubKeyByName(IN PHHIVE Hive, /* If we got here, then we failed */ return HCELL_NIL; } + +BOOLEAN +NTAPI +CmpMarkIndexDirty(IN PHHIVE Hive, + IN HCELL_INDEX ParentKey, + IN HCELL_INDEX TargetKey) +{ + PCM_KEY_NODE Node; + UNICODE_STRING SearchName; + BOOLEAN IsCompressed; + ULONG i, Result; + PCM_KEY_INDEX Index; + HCELL_INDEX IndexCell, Child = HCELL_NIL, CellToRelease = HCELL_NIL; + + /* Get the target key node */ + Node = (PCM_KEY_NODE)HvGetCell(Hive, TargetKey); + if (!Node) return FALSE; + + /* Check if it's compressed */ + if (Node->Flags & KEY_COMP_NAME) + { + /* Remember this for later */ + IsCompressed = TRUE; + + /* Build the search name */ + SearchName.Length = CmpCompressedNameSize(Node->Name, + Node->NameLength); + SearchName.MaximumLength = SearchName.Length; + SearchName.Buffer = ExAllocatePoolWithTag(PagedPool, + SearchName.Length, + TAG_CM); + if (!SearchName.Buffer) + { + /* Fail */ + HvReleaseCell(Hive, TargetKey); + return FALSE; + } + + /* Copy it */ + CmpCopyCompressedName(SearchName.Buffer, + SearchName.MaximumLength, + Node->Name, + Node->NameLength); + } + else + { + /* Name isn't compressed, build it directly from the node */ + IsCompressed = FALSE; + SearchName.Length = Node->NameLength; + SearchName.MaximumLength = Node->NameLength; + SearchName.Buffer = Node->Name; + } + + /* We can release the target key now */ + HvReleaseCell(Hive, TargetKey); + + /* Now get the parent key node */ + Node = (PCM_KEY_NODE)HvGetCell(Hive, ParentKey); + if (!Node) goto Quickie; + + /* Loop all hive storage */ + for (i = 0; i < Hive->StorageTypeCount; i++) + { + /* Check if any subkeys are in this index */ + if (Node->SubKeyCounts[i]) + { + /* Get the cell index */ + //ASSERT(HvIsCellAllocated(Hive, Node->SubKeyLists[i])); + IndexCell = Node->SubKeyLists[i]; + + /* Check if we had anything to release from before */ + if (CellToRelease != HCELL_NIL) + { + /* Release it now */ + HvReleaseCell(Hive, CellToRelease); + CellToRelease = HCELL_NIL; + } + + /* Get the key index for the cell */ + Index = (PCM_KEY_INDEX)HvGetCell(Hive, IndexCell); + if (!Index) goto Quickie; + + /* Release it at the next iteration or below */ + CellToRelease = IndexCell; + + /* Check if this is a root */ + if (Index->Signature == CM_KEY_INDEX_ROOT) + { + /* Get the child inside the root */ + Result = CmpFindSubKeyInRoot(Hive, Index, &SearchName, &Child); + if (Result & 0x80000000) goto Quickie; + if (Child == HCELL_NIL) continue; + + /* We found it, mark the cell dirty */ + HvMarkCellDirty(Hive, IndexCell); + + /* Check if we had anything to release from before */ + if (CellToRelease != HCELL_NIL) + { + /* Release it now */ + HvReleaseCell(Hive, CellToRelease); + CellToRelease = HCELL_NIL; + } + + /* Now this child is the index, get the actual key index */ + IndexCell = Child; + Index = (PCM_KEY_INDEX)HvGetCell(Hive, Child); + if (!Index) goto Quickie; + + /* Release it later */ + CellToRelease = Child; + } + + /* Make sure this is a valid index */ + ASSERT((Index->Signature == CM_KEY_INDEX_LEAF) || + (Index->Signature == CM_KEY_FAST_LEAF) || + (Index->Signature == CM_KEY_HASH_LEAF)); + + /* Find the child in the leaf */ + Result = CmpFindSubKeyInLeaf(Hive, Index, &SearchName, &Child); + if (Result & 0x80000000) goto Quickie; + if (Child != HCELL_NIL) + { + /* We found it, free the name now */ + if (IsCompressed) ExFreePool(SearchName.Buffer); + + /* Release the parent key */ + HvReleaseCell(Hive, ParentKey); + + /* Check if we had a left over cell to release */ + if (CellToRelease != HCELL_NIL) + { + /* Release it */ + HvReleaseCell(Hive, CellToRelease); + } + + /* And mark the index cell dirty */ + HvMarkCellDirty(Hive, IndexCell); + return TRUE; + } + } + } + +Quickie: + /* Release any cells that we still hold */ + if (Node) HvReleaseCell(Hive, ParentKey); + if (CellToRelease != HCELL_NIL) HvReleaseCell(Hive, CellToRelease); + + /* Free the search name and return failure */ + if (IsCompressed) ExFreePool(SearchName.Buffer); + return FALSE; +} + +BOOLEAN +NTAPI +CmpRemoveSubKey(IN PHHIVE Hive, + IN HCELL_INDEX ParentKey, + IN HCELL_INDEX TargetKey) +{ + PCM_KEY_NODE Node; + UNICODE_STRING SearchName; + BOOLEAN IsCompressed; + WCHAR Buffer[50]; + HCELL_INDEX RootCell = HCELL_NIL, LeafCell, ChildCell; + PCM_KEY_INDEX Root = NULL, Leaf; + PCM_KEY_FAST_INDEX Child; + ULONG Storage, RootIndex = 0x80000000, LeafIndex; + BOOLEAN Result = FALSE; + HCELL_INDEX CellToRelease1 = HCELL_NIL, CellToRelease2 = HCELL_NIL; + + /* Get the target key node */ + Node = (PCM_KEY_NODE)HvGetCell(Hive, TargetKey); + if (!Node) return FALSE; + + /* Make sure it's dirty, then release it */ + ASSERT(HvIsCellDirty(Hive, TargetKey)); + HvReleaseCell(Hive, TargetKey); + + /* Check if the name is compressed */ + if (Node->Flags & KEY_COMP_NAME) + { + /* Remember for later */ + IsCompressed = TRUE; + + /* Build the search name */ + SearchName.Length = CmpCompressedNameSize(Node->Name, + Node->NameLength); + SearchName.MaximumLength = SearchName.Length; + + /* Do we need an extra bufer? */ + if (SearchName.MaximumLength > sizeof(Buffer)) + { + /* Allocate one */ + SearchName.Buffer = ExAllocatePoolWithTag(PagedPool, + SearchName.Length, + TAG_CM); + if (!SearchName.Buffer) return FALSE; + } + else + { + /* Otherwise, use our local stack buffer */ + SearchName.Buffer = Buffer; + } + + /* Copy the compressed name */ + CmpCopyCompressedName(SearchName.Buffer, + SearchName.MaximumLength, + Node->Name, + Node->NameLength); + } + else + { + /* It's not compressed, build the name directly from the node */ + IsCompressed = FALSE; + SearchName.Length = Node->NameLength; + SearchName.MaximumLength = Node->NameLength; + SearchName.Buffer = Node->Name; + } + + /* Now get the parent node */ + Node = (PCM_KEY_NODE)HvGetCell(Hive, ParentKey); + if (!Node) goto Exit; + + /* Make sure it's dirty, then release it */ + ASSERT(HvIsCellDirty(Hive, ParentKey)); + HvReleaseCell(Hive, ParentKey); + + /* Get the storage type and make sure it's not empty */ + Storage = HvGetCellType(TargetKey); + ASSERT(Node->SubKeyCounts[Storage] != 0); + //ASSERT(HvIsCellAllocated(Hive, Node->SubKeyLists[Storage])); + + /* Get the leaf cell now */ + LeafCell = Node->SubKeyLists[Storage]; + Leaf = (PCM_KEY_INDEX)HvGetCell(Hive, LeafCell); + if (!Leaf) goto Exit; + + /* Remember to release it later */ + CellToRelease1 = LeafCell; + + /* Check if the leaf is a root */ + if (Leaf->Signature == CM_KEY_INDEX_ROOT) + { + /* Find the child inside the root */ + RootIndex = CmpFindSubKeyInRoot(Hive, Leaf, &SearchName, &ChildCell); + if (RootIndex & 0x80000000) goto Exit; + ASSERT(ChildCell != FALSE); + + /* The root cell is now this leaf */ + Root = Leaf; + RootCell = LeafCell; + + /* And the new leaf is now this child */ + LeafCell = ChildCell; + Leaf = (PCM_KEY_INDEX)HvGetCell(Hive, LeafCell); + if (!Leaf) goto Exit; + + /* Remember to release it later */ + CellToRelease2 = LeafCell; + } + + /* Make sure the leaf is valid */ + ASSERT((Leaf->Signature == CM_KEY_INDEX_LEAF) || + (Leaf->Signature == CM_KEY_FAST_LEAF) || + (Leaf->Signature == CM_KEY_HASH_LEAF)); + + /* Now get the child in the leaf */ + LeafIndex = CmpFindSubKeyInLeaf(Hive, Leaf, &SearchName, &ChildCell); + if (LeafIndex & 0x80000000) goto Exit; + ASSERT(ChildCell != HCELL_NIL); + + /* Decrement key counts and check if this was the last leaf entry */ + Node->SubKeyCounts[Storage]--; + if (!(--Leaf->Count)) + { + /* Free the leaf */ + HvFreeCell(Hive, LeafCell); + + /* Check if we were inside a root */ + if (Root) + { + /* Decrease the root count too, since the leaf is going away */ + if (!(--Root->Count)) + { + /* The root is gone too,n ow */ + HvFreeCell(Hive, RootCell); + Node->SubKeyLists[Storage] = HCELL_NIL; + } + else if (RootIndex < Root->Count) + { + /* Bring everything up by one */ + RtlMoveMemory(&Root->List[RootIndex], + &Root->List[RootIndex + 1], + (Root->Count - RootIndex) * sizeof(HCELL_INDEX)); + } + } + else + { + /* Otherwise, just clear the cell */ + Node->SubKeyLists[Storage] = HCELL_NIL; + } + } + else if (LeafIndex < Leaf->Count) + { + /* Was the leaf a normal index? */ + if (Leaf->Signature == CM_KEY_INDEX_LEAF) + { + /* Bring everything up by one */ + RtlMoveMemory(&Leaf->List[LeafIndex], + &Leaf->List[LeafIndex + 1], + (Leaf->Count - LeafIndex) * sizeof(HCELL_INDEX)); + } + else + { + /* This is a fast index, bring everything up by one */ + Child = (PCM_KEY_FAST_INDEX)Leaf; + RtlMoveMemory(&Child->List[LeafIndex], + &Child->List[LeafIndex+1], + (Child->Count - LeafIndex) * sizeof(CM_INDEX)); + } + } + + /* If we got here, now we're done */ + Result = TRUE; + +Exit: + /* Release any cells we may have been holding */ + if (CellToRelease1 != HCELL_NIL) HvReleaseCell(Hive, CellToRelease1); + if (CellToRelease2 != HCELL_NIL) HvReleaseCell(Hive, CellToRelease2); + + /* Check if the name was compressed and not inside our local buffer */ + if ((IsCompressed) && (SearchName.MaximumLength > sizeof(Buffer))) + { + /* Free the buffer we allocated */ + ExFreePool(SearchName.Buffer); + } + + /* Return the result */ + return Result; +} diff --git a/reactos/ntoskrnl/config/cmkeydel.c b/reactos/ntoskrnl/config/cmkeydel.c new file mode 100644 index 00000000000..c73e5cc54bd --- /dev/null +++ b/reactos/ntoskrnl/config/cmkeydel.c @@ -0,0 +1,221 @@ +/* + * PROJECT: ReactOS Kernel + * LICENSE: GPL - See COPYING in the top level directory + * FILE: ntoskrnl/config/cmkeydel.c + * PURPOSE: Configuration Manager - Key Body Deletion + * PROGRAMMERS: Alex Ionescu (alex.ionescu@reactos.org) + */ + +/* INCLUDES ******************************************************************/ + +#include "ntoskrnl.h" +#include "cm.h" +#define NDEBUG +#include "debug.h" + +/* FUNCTIONS *****************************************************************/ + +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[HvStable] == 0); + ASSERT(CellData->u.KeyNode.SubKeyCounts[HvVolatile] == 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); + 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); + } + + /* Check if we have security */ + if (CellData->u.KeyNode.Security != HCELL_NIL) + { + /* Mark it dirty */ + HvMarkCellDirty(Hive, CellData->u.KeyNode.Security); + + /* 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); + HvMarkCellDirty(Hive, SecurityData->u.KeySecurity.Blink); + } + + /* Check if we have any values */ + if (CellData->u.KeyNode.ValueList.Count > 0) + { + /* Dirty the value list */ + HvMarkCellDirty(Hive, CellData->u.KeyNode.ValueList.List); + + /* 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]); + + /* Get the value data and release it */ + ValueData = HvGetCell(Hive, ListData->u.KeyList[i]); + if (ValueData) ASSERT(FALSE); + 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); + return TRUE; +} + +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; +} + +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[HvStable] + + CellData->u.KeyNode.SubKeyCounts[HvVolatile]) == 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[HvStable] + + ParentData->u.KeyNode.SubKeyCounts[HvVolatile])) + { + /* 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; +} diff --git a/reactos/ntoskrnl/ntoskrnl.rbuild b/reactos/ntoskrnl/ntoskrnl.rbuild index ba595fc6fa9..d31e7bf3932 100644 --- a/reactos/ntoskrnl/ntoskrnl.rbuild +++ b/reactos/ntoskrnl/ntoskrnl.rbuild @@ -99,6 +99,7 @@ cminit.c cmhook.c cmkcbncb.c + cmkeydel.c cmmapvw.c cmname.c cmparse.c