[NTOSKRNL]
authorEric Kohl <eric.kohl@reactos.org>
Sun, 26 Sep 2010 11:37:40 +0000 (11:37 +0000)
committerEric Kohl <eric.kohl@reactos.org>
Sun, 26 Sep 2010 11:37:40 +0000 (11:37 +0000)
Implement NtQueryOpenSubKeys.

svn path=/trunk/; revision=48902

reactos/ntoskrnl/config/cmapi.c
reactos/ntoskrnl/config/ntapi.c
reactos/ntoskrnl/include/internal/cm.h

index 538c3e5..4db60d7 100644 (file)
@@ -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;
+}
index 4d4123d..0e76f7c 100644 (file)
@@ -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
index 62f4010..30fa366 100644 (file)
@@ -1501,6 +1501,13 @@ CmUnloadKey(
     IN ULONG Flags
 );
 
+ULONG
+NTAPI
+CmCountOpenSubKeys(
+    IN PCM_KEY_CONTROL_BLOCK RootKcb,
+    IN BOOLEAN RemoveEmptyCacheEntries
+);
+
 //
 // Startup and Shutdown
 //