forget update de.rc
[reactos.git] / reactos / ntoskrnl / cm / registry.c
index e727569..c2cc4a2 100644 (file)
 
 #include "cm.h"
 
+#if defined (ALLOC_PRAGMA)
+#pragma alloc_text(INIT, CmInitHives)
+#pragma alloc_text(INIT, CmInitializeRegistry)
+#pragma alloc_text(INIT, CmInit2)
+#endif
+
+
 /* GLOBALS ******************************************************************/
 
 POBJECT_TYPE  CmiKeyType = NULL;
 PREGISTRY_HIVE  CmiVolatileHive = NULL;
-KSPIN_LOCK  CmiKeyListLock;
 
 LIST_ENTRY CmiHiveListHead;
 
 ERESOURCE CmiRegistryLock;
 
+KTIMER CmiWorkerTimer;
+LIST_ENTRY CmiKeyObjectListHead;
+ULONG CmiTimer = 0;
+
 volatile BOOLEAN CmiHiveSyncEnabled = FALSE;
 volatile BOOLEAN CmiHiveSyncPending = FALSE;
 KDPC CmiHiveSyncDpc;
@@ -241,33 +251,95 @@ CmiCheckRegistry(BOOLEAN Verbose)
   CmiCheckByName(Verbose, L"User");
 }
 
+VOID STDCALL
+CmiWorkerThread(PVOID Param)
+{
+  NTSTATUS Status;
+  PLIST_ENTRY CurrentEntry;
+  PKEY_OBJECT CurrentKey;
+  ULONG Count;
+
+
+  while (1)
+  {
+    Status = KeWaitForSingleObject(&CmiWorkerTimer,
+                                  Executive,
+                                  KernelMode,
+                                  FALSE,
+                                  NULL);
+    if (Status == STATUS_SUCCESS)
+    {
+      DPRINT("CmiWorkerThread\n");
+
+      /* Acquire hive lock */
+      KeEnterCriticalRegion();
+      ExAcquireResourceExclusiveLite(&CmiRegistryLock, TRUE);
+
+      CmiTimer++;
+
+      Count = 0;
+      CurrentEntry = CmiKeyObjectListHead.Blink;
+      while (CurrentEntry != &CmiKeyObjectListHead)
+      {
+         CurrentKey = CONTAINING_RECORD(CurrentEntry, KEY_OBJECT, ListEntry);
+        if (CurrentKey->TimeStamp + 120 > CmiTimer)
+        {
+           /* The object was accessed in the last 10min */
+           break;
+        }
+        if (1 == ObGetObjectPointerCount(CurrentKey) &&
+            !(CurrentKey->Flags & KO_MARKED_FOR_DELETE))
+        {
+           ObDereferenceObject(CurrentKey);
+            CurrentEntry = CmiKeyObjectListHead.Blink;
+           Count++;
+        }
+        else
+        {
+           CurrentEntry = CurrentEntry->Blink;
+        }
+      }
+      ExReleaseResourceLite(&CmiRegistryLock);
+      KeLeaveCriticalRegion();
+
+      DPRINT("Removed %d key objects\n", Count);
+
+    }
+    else
+    {
+      KEBUGCHECK(0);
+    }
+  }
+}
+
 VOID
 INIT_FUNCTION
 STDCALL
 CmInitHives(BOOLEAN SetupBoot)
 {
     PCHAR BaseAddress;
-    
+
     /* Load Registry Hives. This one can be missing. */
     if (CachedModules[SystemRegistry]) {
         BaseAddress = (PCHAR)CachedModules[SystemRegistry]->ModStart;
         CmImportSystemHive(BaseAddress,
                            CachedModules[SystemRegistry]->ModEnd - (ULONG_PTR)BaseAddress);
     }
-    
+
     BaseAddress = (PCHAR)CachedModules[HardwareRegistry]->ModStart;
     CmImportHardwareHive(BaseAddress,
                          CachedModules[HardwareRegistry]->ModEnd - (ULONG_PTR)BaseAddress);
-    
+
 
     /* Create dummy keys if no hardware hive was found */
     CmImportHardwareHive (NULL, 0);
 
     /* Initialize volatile registry settings */
     if (SetupBoot == FALSE) CmInit2((PCHAR)KeLoaderBlock.CommandLine);
-}   
+}
 
-VOID INIT_FUNCTION
+VOID 
+INIT_FUNCTION
 CmInitializeRegistry(VOID)
 {
   OBJECT_ATTRIBUTES ObjectAttributes;
@@ -279,31 +351,29 @@ CmInitializeRegistry(VOID)
   HANDLE RootKeyHandle;
   HANDLE KeyHandle;
   NTSTATUS Status;
+  LARGE_INTEGER DueTime;
+  HANDLE ThreadHandle;
+  CLIENT_ID ThreadId;
+  OBJECT_TYPE_INITIALIZER ObjectTypeInitializer;
+  UNICODE_STRING Name;
 
+  DPRINT("Creating Registry Object Type\n");
+  
   /*  Initialize the Key object type  */
-  CmiKeyType = ExAllocatePool(NonPagedPool, sizeof(OBJECT_TYPE));
-  ASSERT(CmiKeyType);
-  CmiKeyType->Tag = TAG('R', 'e', 'g', 'K');
-  CmiKeyType->TotalObjects = 0;
-  CmiKeyType->TotalHandles = 0;
-  CmiKeyType->PeakObjects = 0;
-  CmiKeyType->PeakHandles = 0;
-  CmiKeyType->PagedPoolCharge = 0;
-  CmiKeyType->NonpagedPoolCharge = sizeof(KEY_OBJECT);
-  CmiKeyType->Mapping = &CmiKeyMapping;
-  CmiKeyType->Dump = NULL;
-  CmiKeyType->Open = NULL;
-  CmiKeyType->Close = NULL;
-  CmiKeyType->Delete = CmiObjectDelete;
-  CmiKeyType->Parse = CmiObjectParse;
-  CmiKeyType->Security = CmiObjectSecurity;
-  CmiKeyType->QueryName = CmiObjectQueryName;
-  CmiKeyType->OkayToClose = NULL;
-  CmiKeyType->Create = CmiObjectCreate;
-  CmiKeyType->DuplicationNotify = NULL;
-  RtlInitUnicodeString(&CmiKeyType->TypeName, L"Key");
-
-  ObpCreateTypeObject (CmiKeyType);
+  RtlZeroMemory(&ObjectTypeInitializer, sizeof(ObjectTypeInitializer));
+  RtlInitUnicodeString(&Name, L"Key");
+  ObjectTypeInitializer.Length = sizeof(ObjectTypeInitializer);
+  ObjectTypeInitializer.DefaultPagedPoolCharge = sizeof(KEY_OBJECT);
+  ObjectTypeInitializer.GenericMapping = CmiKeyMapping;
+  ObjectTypeInitializer.PoolType = PagedPool;
+  ObjectTypeInitializer.ValidAccessMask = KEY_ALL_ACCESS;
+  ObjectTypeInitializer.UseDefaultObject = TRUE;
+  ObjectTypeInitializer.DeleteProcedure = CmiObjectDelete;
+  ObjectTypeInitializer.ParseProcedure = CmiObjectParse;
+  ObjectTypeInitializer.SecurityProcedure = CmiObjectSecurity;
+  ObjectTypeInitializer.QueryNameProcedure = CmiObjectQueryName;
+
+  ObpCreateTypeObject(&ObjectTypeInitializer, &Name, &CmiKeyType);
 
   /* Initialize the hive list */
   InitializeListHead(&CmiHiveListHead);
@@ -311,10 +381,33 @@ CmInitializeRegistry(VOID)
   /* Initialize registry lock */
   ExInitializeResourceLite(&CmiRegistryLock);
 
+  /* Initialize the key object list */
+  InitializeListHead(&CmiKeyObjectListHead);
+
+  /* Initialize the worker timer */
+  KeInitializeTimerEx(&CmiWorkerTimer, SynchronizationTimer);
+
+  /* Initialize the worker thread */
+  Status = PsCreateSystemThread(&ThreadHandle,
+                               THREAD_ALL_ACCESS,
+                               NULL,
+                               NULL,
+                               &ThreadId,
+                               CmiWorkerThread,
+                               NULL);
+  if (!NT_SUCCESS(Status))
+  {
+    KEBUGCHECK(0);
+  }
+
+  /* Start the timer */
+  DueTime.QuadPart = -1;
+  KeSetTimerEx(&CmiWorkerTimer, DueTime, 5000, NULL); /* 5sec */
+
   /*  Build volatile registry store  */
   Status = CmiCreateVolatileHive (&CmiVolatileHive);
   ASSERT(NT_SUCCESS(Status));
-  
+
   InitializeListHead(&CmiCallbackHead);
   ExInitializeFastMutex(&CmiCallbackLock);
 
@@ -333,7 +426,7 @@ CmInitializeRegistry(VOID)
   ASSERT(NT_SUCCESS(Status));
   Status = ObInsertObject(RootKey,
                          NULL,
-                         STANDARD_RIGHTS_REQUIRED,
+                         KEY_ALL_ACCESS,
                          0,
                          NULL,
                          &RootKeyHandle);
@@ -346,6 +439,7 @@ CmInitializeRegistry(VOID)
   RootKey->NumberOfSubKeys = 0;
   RootKey->SubKeys = NULL;
   RootKey->SizeOfSubKeys = 0;
+  InsertTailList(&CmiKeyObjectListHead, &RootKey->ListEntry);
   Status = RtlpCreateUnicodeString(&RootKey->Name, L"Registry", NonPagedPool);
   ASSERT(NT_SUCCESS(Status));
 
@@ -371,7 +465,7 @@ CmInitializeRegistry(VOID)
                             RootKeyHandle,
                             NULL);
   Status = ZwCreateKey(&KeyHandle,
-                      STANDARD_RIGHTS_REQUIRED,
+                      KEY_ALL_ACCESS,
                       &ObjectAttributes,
                       0,
                       NULL,
@@ -388,7 +482,7 @@ CmInitializeRegistry(VOID)
                             RootKeyHandle,
                             NULL);
   Status = ZwCreateKey(&KeyHandle,
-                      STANDARD_RIGHTS_REQUIRED,
+                      KEY_ALL_ACCESS,
                       &ObjectAttributes,
                       0,
                       NULL,
@@ -457,7 +551,7 @@ CmInit2(PCHAR CommandLine)
         MiniNT = TRUE;
       else if (!_strnicmp(CommandLine, "DEBUGPORT=PICE", 14))
         PiceStart = 1;
-      
+
       /* Add a space between the options */
       if (Position != 0)
         SystemStartOptions[Position++] = L' ';
@@ -514,8 +608,9 @@ CmiCreateCurrentControlSetLink(VOID)
   RTL_QUERY_REGISTRY_TABLE QueryTable[5];
   WCHAR TargetNameBuffer[80];
   ULONG TargetNameLength;
-  UNICODE_STRING LinkName;
-  UNICODE_STRING LinkValue;
+  UNICODE_STRING LinkName = RTL_CONSTANT_STRING(
+                            L"\\Registry\\Machine\\SYSTEM\\CurrentControlSet");
+  UNICODE_STRING LinkValue = RTL_CONSTANT_STRING(L"SymbolicLinkValue");
   ULONG CurrentSet;
   ULONG DefaultSet;
   ULONG Failed;
@@ -563,8 +658,6 @@ CmiCreateCurrentControlSetLink(VOID)
 
   DPRINT("Link target '%S'\n", TargetNameBuffer);
 
-  RtlRosInitUnicodeStringFromLiteral(&LinkName,
-                                 L"\\Registry\\Machine\\SYSTEM\\CurrentControlSet");
   InitializeObjectAttributes(&ObjectAttributes,
                             &LinkName,
                             OBJ_CASE_INSENSITIVE | OBJ_OPENIF | OBJ_OPENLINK,
@@ -583,8 +676,6 @@ CmiCreateCurrentControlSetLink(VOID)
       return(Status);
     }
 
-  RtlRosInitUnicodeStringFromLiteral(&LinkValue,
-                                 L"SymbolicLinkValue");
   Status = ZwSetValueKey(KeyHandle,
                         &LinkValue,
                         0,
@@ -611,14 +702,32 @@ CmiConnectHive(IN POBJECT_ATTRIBUTES KeyObjectAttributes,
   PKEY_OBJECT NewKey;
   NTSTATUS Status;
   PWSTR SubName;
+  UNICODE_STRING ObjectName;
+  OBJECT_CREATE_INFORMATION ObjectCreateInfo;
 
   DPRINT("CmiConnectHive(%p, %p) called.\n",
         KeyObjectAttributes, RegistryHive);
-
-  Status = ObFindObject(KeyObjectAttributes,
-                       (PVOID*)&ParentKey,
-                       &RemainingPath,
-                       CmiKeyType);
+     
+   /* Capture all the info */
+   DPRINT("Capturing Create Info\n");
+   Status = ObpCaptureObjectAttributes(KeyObjectAttributes,
+                                       KernelMode,
+                                       CmiKeyType,
+                                       &ObjectCreateInfo,
+                                       &ObjectName);
+   if (!NT_SUCCESS(Status))
+     {
+       DPRINT("ObpCaptureObjectAttributes() failed (Status %lx)\n", Status);
+       return Status;
+     }
+
+  Status = ObFindObject(&ObjectCreateInfo,
+                        &ObjectName,
+                                   (PVOID*)&ParentKey,
+                        &RemainingPath,
+                        CmiKeyType);
+     ObpReleaseCapturedAttributes(&ObjectCreateInfo);
+   if (ObjectName.Buffer) ExFreePool(ObjectName.Buffer);
   if (!NT_SUCCESS(Status))
     {
       return Status;
@@ -659,6 +768,7 @@ CmiConnectHive(IN POBJECT_ATTRIBUTES KeyObjectAttributes,
                          0,
                          0,
                          (PVOID*)&NewKey);
+                            
   if (!NT_SUCCESS(Status))
     {
       DPRINT1 ("ObCreateObject() failed (Status %lx)\n", Status);
@@ -666,12 +776,20 @@ CmiConnectHive(IN POBJECT_ATTRIBUTES KeyObjectAttributes,
       RtlFreeUnicodeString(&RemainingPath);
       return Status;
     }
-
+    DPRINT("Inserting Key into Object Tree\n");
+    Status =  ObInsertObject((PVOID)NewKey,
+                             NULL,
+                             KEY_ALL_ACCESS,
+                             0,
+                             NULL,
+                             NULL);
+DPRINT("Status %x\n", Status);
   NewKey->RegistryHive = RegistryHive;
   NewKey->KeyCellOffset = RegistryHive->HiveHeader->RootKeyOffset;
   NewKey->KeyCell = CmiGetCell (RegistryHive, NewKey->KeyCellOffset, NULL);
   NewKey->Flags = 0;
   NewKey->NumberOfSubKeys = 0;
+  InsertTailList(&CmiKeyObjectListHead, &NewKey->ListEntry);
   if (NewKey->KeyCell->NumberOfSubKeys != 0)
     {
       NewKey->SubKeys = ExAllocatePool(NonPagedPool,
@@ -726,6 +844,8 @@ CmiDisconnectHive (IN POBJECT_ATTRIBUTES KeyObjectAttributes,
   PREGISTRY_HIVE Hive;
   HANDLE KeyHandle;
   NTSTATUS Status;
+  PLIST_ENTRY CurrentEntry;
+  PKEY_OBJECT CurrentKey;
 
   DPRINT("CmiDisconnectHive() called\n");
 
@@ -765,11 +885,36 @@ CmiDisconnectHive (IN POBJECT_ATTRIBUTES KeyObjectAttributes,
       return STATUS_INVALID_PARAMETER;
     }
 
+  /* Acquire registry lock exclusively */
+  KeEnterCriticalRegion();
+  ExAcquireResourceExclusiveLite(&CmiRegistryLock, TRUE);
+
+  CurrentEntry = CmiKeyObjectListHead.Flink;
+  while (CurrentEntry != &CmiKeyObjectListHead)
+  {
+     CurrentKey = CONTAINING_RECORD(CurrentEntry, KEY_OBJECT, ListEntry);
+     if (1 == ObGetObjectPointerCount(CurrentKey) &&
+        !(CurrentKey->Flags & KO_MARKED_FOR_DELETE))
+     {
+        ObDereferenceObject(CurrentKey);
+        CurrentEntry = CmiKeyObjectListHead.Flink;
+     }
+     else
+     {
+        CurrentEntry = CurrentEntry->Flink;
+     }
+  }
+
   if (ObGetObjectHandleCount (KeyObject) != 0 ||
       ObGetObjectPointerCount (KeyObject) != 2)
     {
-      DPRINT1 ("Hive is still in use\n");
+      DPRINT1 ("Hive is still in use (hc %d, rc %d)\n", ObGetObjectHandleCount (KeyObject), ObGetObjectPointerCount (KeyObject));
       ObDereferenceObject (KeyObject);
+
+      /* Release registry lock */
+      ExReleaseResourceLite (&CmiRegistryLock);
+      KeLeaveCriticalRegion();
+
       return STATUS_UNSUCCESSFUL;
     }
 
@@ -781,6 +926,10 @@ CmiDisconnectHive (IN POBJECT_ATTRIBUTES KeyObjectAttributes,
 
   *RegistryHive = Hive;
 
+  /* Release registry lock */
+  ExReleaseResourceLite (&CmiRegistryLock);
+  KeLeaveCriticalRegion();
+
   DPRINT ("CmiDisconnectHive() done\n");
 
   return STATUS_SUCCESS;
@@ -791,15 +940,15 @@ static NTSTATUS
 CmiInitControlSetLink (VOID)
 {
   OBJECT_ATTRIBUTES ObjectAttributes;
-  UNICODE_STRING ControlSetKeyName;
-  UNICODE_STRING ControlSetLinkName;
-  UNICODE_STRING ControlSetValueName;
+  UNICODE_STRING ControlSetKeyName = RTL_CONSTANT_STRING(
+                                L"\\Registry\\Machine\\SYSTEM\\ControlSet001");
+  UNICODE_STRING ControlSetLinkName =  RTL_CONSTANT_STRING(
+                            L"\\Registry\\Machine\\SYSTEM\\CurrentControlSet");
+  UNICODE_STRING ControlSetValueName = RTL_CONSTANT_STRING(L"SymbolicLinkValue");
   HANDLE KeyHandle;
   NTSTATUS Status;
 
   /* Create 'ControlSet001' key */
-  RtlRosInitUnicodeStringFromLiteral (&ControlSetKeyName,
-                                  L"\\Registry\\Machine\\SYSTEM\\ControlSet001");
   InitializeObjectAttributes (&ObjectAttributes,
                              &ControlSetKeyName,
                              OBJ_CASE_INSENSITIVE,
@@ -820,8 +969,6 @@ CmiInitControlSetLink (VOID)
   ZwClose (KeyHandle);
 
   /* Link 'CurrentControlSet' to 'ControlSet001' key */
-  RtlRosInitUnicodeStringFromLiteral (&ControlSetLinkName,
-                                  L"\\Registry\\Machine\\SYSTEM\\CurrentControlSet");
   InitializeObjectAttributes (&ObjectAttributes,
                              &ControlSetLinkName,
                              OBJ_CASE_INSENSITIVE | OBJ_OPENIF | OBJ_OPENLINK,
@@ -840,8 +987,6 @@ CmiInitControlSetLink (VOID)
       return Status;
     }
 
-  RtlRosInitUnicodeStringFromLiteral (&ControlSetValueName,
-                                  L"SymbolicLinkValue");
   Status = ZwSetValueKey (KeyHandle,
                          &ControlSetValueName,
                          0,
@@ -864,8 +1009,8 @@ CmiInitHives(BOOLEAN SetupBoot)
   PKEY_VALUE_PARTIAL_INFORMATION ValueInfo;
   OBJECT_ATTRIBUTES ObjectAttributes;
   UNICODE_STRING FileName;
-  UNICODE_STRING KeyName;
-  UNICODE_STRING ValueName;
+  UNICODE_STRING KeyName = RTL_CONSTANT_STRING(L"\\Registry\\Machine\\HARDWARE");
+  UNICODE_STRING ValueName = RTL_CONSTANT_STRING(L"InstallPath");
   HANDLE KeyHandle;
 
   NTSTATUS Status;
@@ -881,8 +1026,6 @@ CmiInitHives(BOOLEAN SetupBoot)
 
   if (SetupBoot == TRUE)
     {
-      RtlRosInitUnicodeStringFromLiteral(&KeyName,
-                                     L"\\Registry\\Machine\\HARDWARE");
       InitializeObjectAttributes(&ObjectAttributes,
                                 &KeyName,
                                 OBJ_CASE_INSENSITIVE,
@@ -897,9 +1040,6 @@ CmiInitHives(BOOLEAN SetupBoot)
          return(Status);
        }
 
-      RtlRosInitUnicodeStringFromLiteral(&ValueName,
-                                     L"InstallPath");
-
       BufferSize = sizeof(KEY_VALUE_PARTIAL_INFORMATION) + 4096;
       ValueInfo = ExAllocatePool(PagedPool,
                                 BufferSize);
@@ -1155,7 +1295,7 @@ CmiHiveSyncRoutine(PVOID DeferredContext)
   ExReleaseResourceLite(&CmiRegistryLock);
   KeLeaveCriticalRegion();
 
-  DPRINT("DeferredContext %x\n", DeferredContext);
+  DPRINT("DeferredContext 0x%p\n", DeferredContext);
   ExFreePool(DeferredContext);
 
   DPRINT("CmiHiveSyncRoutine() done\n");
@@ -1182,7 +1322,7 @@ CmiHiveSyncDpcRoutine(PKDPC Dpc,
                       CmiHiveSyncRoutine,
                       WorkQueueItem);
 
-  DPRINT("DeferredContext %x\n", WorkQueueItem);
+  DPRINT("DeferredContext 0x%p\n", WorkQueueItem);
   ExQueueWorkItem(WorkQueueItem,
                  CriticalWorkQueue);
 }