From db53bf24cb12563914a90278fdd48f8138e97597 Mon Sep 17 00:00:00 2001 From: Eric Kohl Date: Sun, 26 Sep 2010 11:37:40 +0000 Subject: [PATCH] [NTOSKRNL] Implement NtQueryOpenSubKeys. svn path=/trunk/; revision=48902 --- reactos/ntoskrnl/config/cmapi.c | 84 ++++++++++++++++++++++++ reactos/ntoskrnl/config/ntapi.c | 88 +++++++++++++++++++++++++- reactos/ntoskrnl/include/internal/cm.h | 7 ++ 3 files changed, 177 insertions(+), 2 deletions(-) diff --git a/reactos/ntoskrnl/config/cmapi.c b/reactos/ntoskrnl/config/cmapi.c index 538c3e5b560..4db60d7a676 100644 --- a/reactos/ntoskrnl/config/cmapi.c +++ b/reactos/ntoskrnl/config/cmapi.c @@ -4,6 +4,7 @@ * FILE: ntoskrnl/config/cmapi.c * PURPOSE: Configuration Manager - Internal Registry APIs * PROGRAMMERS: Alex Ionescu (alex.ionescu@reactos.org) + * Eric Kohl */ /* INCLUDES ******************************************************************/ @@ -1814,3 +1815,86 @@ CmUnloadKey(IN PCM_KEY_CONTROL_BLOCK Kcb, UNIMPLEMENTED; return STATUS_NOT_IMPLEMENTED; } + +ULONG +NTAPI +CmCountOpenSubKeys(IN PCM_KEY_CONTROL_BLOCK RootKcb, + IN BOOLEAN RemoveEmptyCacheEntries) +{ + PCM_KEY_HASH Entry; + PCM_KEY_CONTROL_BLOCK CachedKcb; + PCM_KEY_CONTROL_BLOCK ParentKcb; + USHORT ParentKeyCount; + USHORT j; + ULONG i; + ULONG SubKeys = 0; + + DPRINT("CmCountOpenSubKeys() called\n"); + + /* The root key is the only referenced key. There are no refereced sub keys. */ + if (RootKcb->RefCount == 1) + { + DPRINT("open sub keys: 0\n"); + return 0; + } + + /* Enumerate all hash lists */ + for (i = 0; i < CmpHashTableSize; i++) + { + /* Get the first cache entry */ + Entry = CmpCacheTable[i].Entry; + + /* Enumerate all cache entries */ + while (Entry) + { + /* Get the KCB of the current cache entry */ + CachedKcb = CONTAINING_RECORD(Entry, CM_KEY_CONTROL_BLOCK, KeyHash); + + /* Check keys only that are subkeys to our root key */ + if (CachedKcb->TotalLevels > RootKcb->TotalLevels) + { + /* Calculate the number of parent keys to the root key */ + ParentKeyCount = CachedKcb->TotalLevels - RootKcb->TotalLevels; + + /* Find a parent key that could be the root key */ + ParentKcb = CachedKcb; + for (j = 0; j < ParentKeyCount; j++) + { + ParentKcb = ParentKcb->ParentKcb; + } + + /* Check whether the parent is the root key */ + if (ParentKcb == RootKcb) + { + DPRINT("Found a sub key \n"); + DPRINT("RefCount = %u\n", CachedKcb->RefCount); + + if (CachedKcb->RefCount > 0) + { + /* Count the current hash entry if it is in use */ + SubKeys++; + } + else if ((CachedKcb->RefCount == 0) && (RemoveEmptyCacheEntries == TRUE)) + { + /* Remove the current key from the delayed close list */ + CmpRemoveFromDelayedClose(CachedKcb); + + /* Remove the current cache entry */ + CmpCleanUpKcbCacheWithLock(CachedKcb, TRUE); + + /* Restart, because the hash list has changed */ + Entry = CmpCacheTable[i].Entry; + continue; + } + } + } + + /* Get the next cache entry */ + Entry = Entry->NextHash; + } + } + + DPRINT("open sub keys: %u\n", SubKeys); + + return SubKeys; +} diff --git a/reactos/ntoskrnl/config/ntapi.c b/reactos/ntoskrnl/config/ntapi.c index 4d4123d90be..0e76f7cd743 100644 --- a/reactos/ntoskrnl/config/ntapi.c +++ b/reactos/ntoskrnl/config/ntapi.c @@ -4,6 +4,7 @@ * FILE: ntoskrnl/config/cmapi.c * PURPOSE: Configuration Manager - Internal Registry APIs * PROGRAMMERS: Alex Ionescu (alex.ionescu@reactos.org) + * Eric Kohl */ /* INCLUDES ******************************************************************/ @@ -1015,8 +1016,91 @@ NTAPI NtQueryOpenSubKeys(IN POBJECT_ATTRIBUTES TargetKey, OUT PULONG HandleCount) { - UNIMPLEMENTED; - return STATUS_NOT_IMPLEMENTED; + KPROCESSOR_MODE PreviousMode; + PCM_KEY_BODY KeyBody = NULL; + HANDLE KeyHandle; + NTSTATUS Status; + + DPRINT("NtQueryOpenSubKeys()\n"); + + PAGED_CODE(); + + /* Get the processor mode */ + PreviousMode = KeGetPreviousMode(); + + if (PreviousMode != KernelMode) + { + /* Prepare to probe parameters */ + _SEH2_TRY + { + /* Probe target key */ + ProbeForRead(TargetKey, + sizeof(OBJECT_ATTRIBUTES), + sizeof(ULONG)); + + /* Probe handle count */ + ProbeForWriteUlong(HandleCount); + } + _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) + { + /* Return the exception code */ + _SEH2_YIELD(return _SEH2_GetExceptionCode()); + } + _SEH2_END; + } + + /* Open a handle to the key */ + Status = ObOpenObjectByName(TargetKey, + CmpKeyObjectType, + PreviousMode, + NULL, + KEY_READ, + NULL, + &KeyHandle); + if (NT_SUCCESS(Status)) + { + /* Reference the key object */ + Status = ObReferenceObjectByHandle(KeyHandle, + KEY_READ, + CmpKeyObjectType, + PreviousMode, + (PVOID *)&KeyBody, + NULL); + + /* Close the handle */ + NtClose(KeyHandle); + } + + /* Fail, if the key object could not be referenced */ + if (!NT_SUCCESS(Status)) + return Status; + + /* Lock the registry exclusively */ + CmpLockRegistryExclusive(); + + /* Fail, if we did not open a hive root key */ + if (KeyBody->KeyControlBlock->KeyCell != + KeyBody->KeyControlBlock->KeyHive->BaseBlock->RootCell) + { + DPRINT("Error: Key is not a hive root key!\n"); + CmpUnlockRegistry(); + ObDereferenceObject(KeyBody); + return STATUS_INVALID_PARAMETER; + } + + /* Call the internal API */ + *HandleCount = CmCountOpenSubKeys(KeyBody->KeyControlBlock, + FALSE); + + /* Unlock the registry */ + CmpUnlockRegistry(); + + /* Dereference the key object */ + ObDereferenceObject(KeyBody); + + DPRINT("Done.\n"); + + return Status; } NTSTATUS diff --git a/reactos/ntoskrnl/include/internal/cm.h b/reactos/ntoskrnl/include/internal/cm.h index 62f4010f20b..30fa3669f4a 100644 --- a/reactos/ntoskrnl/include/internal/cm.h +++ b/reactos/ntoskrnl/include/internal/cm.h @@ -1501,6 +1501,13 @@ CmUnloadKey( IN ULONG Flags ); +ULONG +NTAPI +CmCountOpenSubKeys( + IN PCM_KEY_CONTROL_BLOCK RootKcb, + IN BOOLEAN RemoveEmptyCacheEntries +); + // // Startup and Shutdown // -- 2.17.1