[MKHIVE] Minor improvements.
[reactos.git] / sdk / tools / mkhive / registry.c
index 91f93d4..a3cc712 100644 (file)
@@ -21,7 +21,8 @@
  * PROJECT:         ReactOS hive maker
  * FILE:            tools/mkhive/registry.c
  * PURPOSE:         Registry code
- * PROGRAMMER:      Hervé Poussineau
+ * PROGRAMMERS:     Hervé Poussineau
+ *                  Hermès Bélusca-Maïto
  */
 
 /*
  *   - Implement RegDeleteKeyW() and RegDeleteValueW()
  */
 
-#include <stdlib.h>
-#include <string.h>
-#include <stdio.h>
-
 #define NDEBUG
 #include "mkhive.h"
 
 static CMHIVE RootHive;
 static PMEMKEY RootKey;
-CMHIVE DefaultHive;  /* \Registry\User\.DEFAULT */
-CMHIVE SamHive;      /* \Registry\Machine\SAM */
-CMHIVE SecurityHive; /* \Registry\Machine\SECURITY */
-CMHIVE SoftwareHive; /* \Registry\Machine\SOFTWARE */
-CMHIVE SystemHive;   /* \Registry\Machine\SYSTEM */
-CMHIVE BcdHive;      /* \Registry\Machine\BCD00000000 */
+
+static CMHIVE SystemHive;   /* \Registry\Machine\SYSTEM */
+static CMHIVE SoftwareHive; /* \Registry\Machine\SOFTWARE */
+static CMHIVE DefaultHive;  /* \Registry\User\.DEFAULT */
+static CMHIVE SamHive;      /* \Registry\Machine\SAM */
+static CMHIVE SecurityHive; /* \Registry\Machine\SECURITY */
+static CMHIVE BcdHive;      /* \Registry\Machine\BCD00000000 */
 
 //
 // TODO: Write these values in a more human-readable form.
@@ -56,7 +54,7 @@ CMHIVE BcdHive;      /* \Registry\Machine\BCD00000000 */
 // A cross-check was subsequently done with the system hives to verify that
 // the security descriptors were the same.
 //
-UCHAR BcdSecurity[] =
+static UCHAR BcdSecurity[] =
 {
     // SECURITY_DESCRIPTOR_RELATIVE
     0x01,                   // Revision
@@ -118,7 +116,7 @@ UCHAR BcdSecurity[] =
     0x01, 0x02, 0x00, 0x00
 };
 
-UCHAR SoftwareSecurity[] =
+static UCHAR SoftwareSecurity[] =
 {
     // SECURITY_DESCRIPTOR_RELATIVE
     0x01,                   // Revision
@@ -234,7 +232,7 @@ UCHAR SoftwareSecurity[] =
 };
 
 // Same security for SYSTEM, SAM and .DEFAULT
-UCHAR SystemSecurity[] =
+static UCHAR SystemSecurity[] =
 {
     // SECURITY_DESCRIPTOR_RELATIVE
     0x01,                   // Revision
@@ -330,6 +328,24 @@ UCHAR SystemSecurity[] =
     0x01, 0x02, 0x00, 0x00
 };
 
+
+HIVE_LIST_ENTRY RegistryHives[/*MAX_NUMBER_OF_REGISTRY_HIVES*/] =
+{
+    /* Special Setup system registry hive */
+    // WARNING: Please *keep* it in first position!
+    { "SETUPREG", L"Registry\\Machine\\SYSTEM"     , &SystemHive  , SystemSecurity  , sizeof(SystemSecurity)   },
+
+    /* Regular registry hives */
+    { "SYSTEM"  , L"Registry\\Machine\\SYSTEM"     , &SystemHive  , SystemSecurity  , sizeof(SystemSecurity)   },
+    { "SOFTWARE", L"Registry\\Machine\\SOFTWARE"   , &SoftwareHive, SoftwareSecurity, sizeof(SoftwareSecurity) },
+    { "DEFAULT" , L"Registry\\User\\.DEFAULT"      , &DefaultHive , SystemSecurity  , sizeof(SystemSecurity)   },
+    { "SAM"     , L"Registry\\Machine\\SAM"        , &SamHive     , SystemSecurity  , sizeof(SystemSecurity)   },
+    { "SECURITY", L"Registry\\Machine\\SECURITY"   , &SecurityHive, NULL            , 0                        },
+    { "BCD"     , L"Registry\\Machine\\BCD00000000", &BcdHive     , BcdSecurity     , sizeof(BcdSecurity)      },
+};
+C_ASSERT(_countof(RegistryHives) == MAX_NUMBER_OF_REGISTRY_HIVES);
+
+
 static PMEMKEY
 CreateInMemoryStructure(
     IN PCMHIVE RegistryHive,
@@ -346,10 +362,11 @@ CreateInMemoryStructure(
     return Key;
 }
 
+LIST_ENTRY CmiHiveListHead;
 LIST_ENTRY CmiReparsePointsHead;
 
 static LONG
-RegpOpenOrCreateKey(
+RegpCreateOrOpenKey(
     IN HKEY hParentKey,
     IN PCWSTR KeyName,
     IN BOOL AllowCreation,
@@ -369,7 +386,7 @@ RegpOpenOrCreateKey(
     PCM_KEY_NODE SubKeyCell;
     HCELL_INDEX BlockOffset;
 
-    DPRINT("RegpCreateOpenKey('%S')\n", KeyName);
+    DPRINT("RegpCreateOrOpenKey('%S')\n", KeyName);
 
     if (*KeyName == OBJ_NAME_PATH_SEPARATOR)
     {
@@ -442,11 +459,18 @@ RegpOpenOrCreateKey(
                                   Volatile,
                                   &BlockOffset);
         }
+        else // if (BlockOffset == HCELL_NIL)
+        {
+            Status = STATUS_OBJECT_NAME_NOT_FOUND; // ERROR_PATH_NOT_FOUND;
+        }
 
         HvReleaseCell(&ParentRegistryHive->Hive, ParentCellOffset);
 
         if (!NT_SUCCESS(Status))
+        {
+            DPRINT("RegpCreateOrOpenKey('%S'): Could not create or open subkey '%wZ'\n", KeyName, &KeyString);
             return ERROR_UNSUCCESSFUL;
+        }
 
         ParentCellOffset = BlockOffset;
         if (End)
@@ -465,31 +489,24 @@ RegpOpenOrCreateKey(
 }
 
 LONG WINAPI
-RegCreateKeyW(
-    IN HKEY hKey,
-    IN LPCWSTR lpSubKey,
-    OUT PHKEY phkResult)
+RegCloseKey(
+    IN HKEY hKey)
 {
-    return RegpOpenOrCreateKey(hKey, lpSubKey, TRUE, FALSE, phkResult);
-}
+    PMEMKEY Key = HKEY_TO_MEMKEY(hKey); // ParentKey
+
+    /* Free the object */
+    free(Key);
 
-LONG WINAPI
-RegDeleteKeyW(
-    IN HKEY hKey,
-    IN LPCWSTR lpSubKey)
-{
-    DPRINT1("RegDeleteKeyW(0x%p, '%S') is UNIMPLEMENTED!\n",
-            hKey, (lpSubKey ? lpSubKey : L""));
     return ERROR_SUCCESS;
 }
 
 LONG WINAPI
-RegOpenKeyW(
+RegCreateKeyW(
     IN HKEY hKey,
     IN LPCWSTR lpSubKey,
     OUT PHKEY phkResult)
 {
-    return RegpOpenOrCreateKey(hKey, lpSubKey, FALSE, FALSE, phkResult);
+    return RegpCreateOrOpenKey(hKey, lpSubKey, TRUE, FALSE, phkResult);
 }
 
 LONG WINAPI
@@ -504,13 +521,32 @@ RegCreateKeyExW(
     OUT PHKEY phkResult,
     OUT LPDWORD lpdwDisposition OPTIONAL)
 {
-    return RegpOpenOrCreateKey(hKey,
+    return RegpCreateOrOpenKey(hKey,
                                lpSubKey,
                                TRUE,
                                (dwOptions & REG_OPTION_VOLATILE) != 0,
                                phkResult);
 }
 
+LONG WINAPI
+RegDeleteKeyW(
+    IN HKEY hKey,
+    IN LPCWSTR lpSubKey)
+{
+    DPRINT1("RegDeleteKeyW(0x%p, '%S') is UNIMPLEMENTED!\n",
+            hKey, (lpSubKey ? lpSubKey : L""));
+    return ERROR_SUCCESS;
+}
+
+LONG WINAPI
+RegOpenKeyW(
+    IN HKEY hKey,
+    IN LPCWSTR lpSubKey,
+    OUT PHKEY phkResult)
+{
+    return RegpCreateOrOpenKey(hKey, lpSubKey, FALSE, FALSE, phkResult);
+}
+
 LONG WINAPI
 RegSetValueExW(
     IN HKEY hKey,
@@ -524,6 +560,7 @@ RegSetValueExW(
     PHHIVE Hive;
     PCM_KEY_NODE KeyNode; // ParentNode
     PCM_KEY_VALUE ValueCell;
+    ULONG ChildIndex;
     HCELL_INDEX CellIndex;
     UNICODE_STRING ValueNameString;
 
@@ -567,12 +604,24 @@ RegSetValueExW(
 
     /* Initialize value name string */
     RtlInitUnicodeString(&ValueNameString, lpValueName);
-    CellIndex = CmpFindValueByName(Hive, KeyNode, &ValueNameString);
+    if (!CmpFindNameInList(Hive,
+                           &KeyNode->ValueList,
+                           &ValueNameString,
+                           &ChildIndex,
+                           &CellIndex))
+    {
+        /* Sanity check */
+        ASSERT(CellIndex == HCELL_NIL);
+        /* Fail */
+        // Status = STATUS_INSUFFICIENT_RESOURCES;
+        return ERROR_UNSUCCESSFUL;
+    }
     if (CellIndex == HCELL_NIL)
     {
         /* The value doesn't exist, create a new one */
         Status = CmiAddValueKey(Key->RegistryHive,
                                 KeyNode,
+                                ChildIndex,
                                 &ValueNameString,
                                 &ValueCell,
                                 &CellIndex);
@@ -582,6 +631,7 @@ RegSetValueExW(
         /* The value already exists, use it. Get the value cell. */
         ValueCell = HvGetCell(&Key->RegistryHive->Hive, CellIndex);
         ASSERT(ValueCell != NULL);
+        Status = STATUS_SUCCESS;
     }
 
     // /**/HvReleaseCell(Hive, CellIndex);/**/
@@ -629,7 +679,7 @@ RegSetValueExW(
             NewOffset = HvAllocateCell(Hive, cbData, Stable, HCELL_NIL);
             if (NewOffset == HCELL_NIL)
             {
-                DPRINT("HvAllocateCell() failed with status 0x%08x\n", Status);
+                DPRINT("HvAllocateCell() has failed!\n");
                 return ERROR_UNSUCCESSFUL;
             }
 
@@ -660,20 +710,19 @@ RegSetValueExW(
     /* Save the write time */
     KeQuerySystemTime(&KeyNode->LastWriteTime);
 
-    DPRINT("Return status 0x%08x\n", Status);
-    return Status;
+    return ERROR_SUCCESS;
 }
 
 
-// Synced with freeldr/windows/registry.c
+// Synced with freeldr/ntldr/registry.c
 static
 VOID
 RepGetValueData(
     IN PHHIVE Hive,
     IN PCM_KEY_VALUE ValueCell,
-    OUT ULONG* Type OPTIONAL,
+    OUT PULONG Type OPTIONAL,
     OUT PUCHAR Data OPTIONAL,
-    IN OUT ULONG* DataSize OPTIONAL)
+    IN OUT PULONG DataSize OPTIONAL)
 {
     ULONG DataLength;
     PVOID DataCell;
@@ -704,7 +753,7 @@ RepGetValueData(
     }
 }
 
-// Similar to RegQueryValue in freeldr/windows/registry.c
+// Similar to RegQueryValue in freeldr/ntldr/registry.c
 LONG WINAPI
 RegQueryValueExW(
     IN HKEY hKey,
@@ -759,16 +808,16 @@ static BOOL
 ConnectRegistry(
     IN HKEY RootKey,
     IN PCMHIVE HiveToConnect,
-    IN PUCHAR Descriptor,
-    IN ULONG DescriptorLength,
-    IN LPCWSTR Path)
+    IN PUCHAR SecurityDescriptor,
+    IN ULONG SecurityDescriptorLength,
+    IN PCWSTR Path)
 {
     NTSTATUS Status;
+    LONG rc;
     PREPARSE_POINT ReparsePoint;
     PMEMKEY NewKey;
-    LONG rc;
 
-    ReparsePoint = (PREPARSE_POINT)malloc(sizeof(REPARSE_POINT));
+    ReparsePoint = (PREPARSE_POINT)malloc(sizeof(*ReparsePoint));
     if (!ReparsePoint)
         return FALSE;
 
@@ -794,11 +843,11 @@ ConnectRegistry(
      */
     Status = CmiCreateSecurityKey(&HiveToConnect->Hive,
                                   HiveToConnect->Hive.BaseBlock->RootCell,
-                                  Descriptor, DescriptorLength);
+                                  SecurityDescriptor, SecurityDescriptorLength);
     if (!NT_SUCCESS(Status))
         DPRINT1("Failed to add security for root key '%S'\n", Path);
 
-    /* Create key */
+    /* Create the key */
     rc = RegCreateKeyExW(RootKey,
                          Path,
                          0,
@@ -821,18 +870,70 @@ ConnectRegistry(
     ReparsePoint->DestinationHive = NewKey->RegistryHive;
     ReparsePoint->DestinationKeyCellOffset = NewKey->KeyCellOffset;
     InsertTailList(&CmiReparsePointsHead, &ReparsePoint->ListEntry);
+
     return TRUE;
 }
 
-LIST_ENTRY CmiHiveListHead;
+static BOOL
+CreateSymLink(
+    IN PCWSTR LinkKeyPath OPTIONAL,
+    IN OUT PHKEY LinkKeyHandle OPTIONAL,
+    // IN PCWSTR TargetKeyPath OPTIONAL,
+    IN HKEY TargetKeyHandle)
+{
+    LONG rc;
+    PMEMKEY LinkKey, TargetKey;
+    PREPARSE_POINT ReparsePoint;
+
+    ReparsePoint = (PREPARSE_POINT)malloc(sizeof(*ReparsePoint));
+    if (!ReparsePoint)
+        return FALSE;
+
+    if (LinkKeyPath && !(LinkKeyHandle && *LinkKeyHandle))
+    {
+        /* Create the link key */
+        rc = RegCreateKeyExW(NULL,
+                             LinkKeyPath,
+                             0,
+                             NULL,
+                             REG_OPTION_VOLATILE,
+                             0,
+                             NULL,
+                             (PHKEY)&LinkKey,
+                             NULL);
+        if (rc != ERROR_SUCCESS)
+        {
+            free(ReparsePoint);
+            return FALSE;
+        }
+    }
+    else if (LinkKeyHandle)
+    {
+        /* Use the user-provided link key handle */
+        LinkKey = HKEY_TO_MEMKEY(*LinkKeyHandle);
+    }
+
+    if (LinkKeyHandle)
+        *LinkKeyHandle = MEMKEY_TO_HKEY(LinkKey);
+
+    TargetKey = HKEY_TO_MEMKEY(TargetKeyHandle);
+
+    ReparsePoint->SourceHive = LinkKey->RegistryHive;
+    ReparsePoint->SourceKeyCellOffset = LinkKey->KeyCellOffset;
+    ReparsePoint->DestinationHive = TargetKey->RegistryHive;
+    ReparsePoint->DestinationKeyCellOffset = TargetKey->KeyCellOffset;
+    InsertTailList(&CmiReparsePointsHead, &ReparsePoint->ListEntry);
+
+    return TRUE;
+}
 
 VOID
-RegInitializeRegistry(VOID)
+RegInitializeRegistry(
+    IN PCSTR HiveList)
 {
-    UNICODE_STRING RootKeyName = RTL_CONSTANT_STRING(L"\\");
     NTSTATUS Status;
-    PMEMKEY ControlSetKey, CurrentControlSetKey;
-    PREPARSE_POINT ReparsePoint;
+    UINT i;
+    HKEY ControlSetKey;
 
     InitializeListHead(&CmiHiveListHead);
     InitializeListHead(&CmiReparsePointsHead);
@@ -847,70 +948,58 @@ RegInitializeRegistry(VOID)
     RootKey = CreateInMemoryStructure(&RootHive,
                                       RootHive.Hive.BaseBlock->RootCell);
 
-    /* Create DEFAULT key */
-    ConnectRegistry(NULL,
-                    &DefaultHive,
-                    SystemSecurity, sizeof(SystemSecurity),
-                    L"Registry\\User\\.DEFAULT");
-
-    /* Create SAM key */
-    ConnectRegistry(NULL,
-                    &SamHive,
-                    SystemSecurity, sizeof(SystemSecurity),
-                    L"Registry\\Machine\\SAM");
-
-    /* Create SECURITY key */
-    ConnectRegistry(NULL,
-                    &SecurityHive,
-                    NULL, 0,
-                    L"Registry\\Machine\\SECURITY");
-
-    /* Create SOFTWARE key */
-    ConnectRegistry(NULL,
-                    &SoftwareHive,
-                    SoftwareSecurity, sizeof(SoftwareSecurity),
-                    L"Registry\\Machine\\SOFTWARE");
-
-    /* Create BCD key */
-    ConnectRegistry(NULL,
-                    &BcdHive,
-                    BcdSecurity, sizeof(BcdSecurity),
-                    L"Registry\\Machine\\BCD00000000");
-
-    /* Create SYSTEM key */
-    ConnectRegistry(NULL,
-                    &SystemHive,
-                    SystemSecurity, sizeof(SystemSecurity),
-                    L"Registry\\Machine\\SYSTEM");
-
-    /* Create 'ControlSet001' key */
+    for (i = 0; i < _countof(RegistryHives); ++i)
+    {
+        /* Skip this registry hive if it's not in the list */
+        if (!strstr(HiveList, RegistryHives[i].HiveName))
+            continue;
+
+        /* Create the registry key */
+        ConnectRegistry(NULL,
+                        RegistryHives[i].CmHive,
+                        RegistryHives[i].SecurityDescriptor,
+                        RegistryHives[i].SecurityDescriptorLength,
+                        RegistryHives[i].HiveRegistryPath);
+
+        /* If we happen to deal with the special setup registry hive, stop there */
+        // if (strcmp(RegistryHives[i].HiveName, "SETUPREG") == 0)
+        if (i == 0)
+            break;
+    }
+
+    /* Create the 'ControlSet001' key */
     RegCreateKeyW(NULL,
                   L"Registry\\Machine\\SYSTEM\\ControlSet001",
-                  (HKEY*)&ControlSetKey);
-
-    /* Create 'CurrentControlSet' key */
-    RegCreateKeyExW(NULL,
-                    L"Registry\\Machine\\SYSTEM\\CurrentControlSet",
-                    0,
-                    NULL,
-                    REG_OPTION_VOLATILE,
-                    0,
-                    NULL,
-                    (HKEY*)&CurrentControlSetKey,
-                    NULL);
-
-    /* Connect 'CurrentControlSet' to 'ControlSet001' */
-    ReparsePoint = (PREPARSE_POINT)malloc(sizeof(REPARSE_POINT));
-    ReparsePoint->SourceHive = CurrentControlSetKey->RegistryHive;
-    ReparsePoint->SourceKeyCellOffset = CurrentControlSetKey->KeyCellOffset;
-    ReparsePoint->DestinationHive = ControlSetKey->RegistryHive;
-    ReparsePoint->DestinationKeyCellOffset = ControlSetKey->KeyCellOffset;
-    InsertTailList(&CmiReparsePointsHead, &ReparsePoint->ListEntry);
+                  &ControlSetKey);
+
+    /* Create the 'CurrentControlSet' key as a symlink to 'ControlSet001' */
+    CreateSymLink(L"Registry\\Machine\\SYSTEM\\CurrentControlSet",
+                  NULL, ControlSetKey);
+
+    RegCloseKey(ControlSetKey);
+
+#if 0
+    /* Link SECURITY to SAM */
+    CmpLinkKeyToHive(L"\\Registry\\Machine\\Security\\SAM", L"\\Registry\\Machine\\SAM\\SAM");
+    /* Link S-1-5-18 to .Default */
+    CmpLinkKeyToHive(L"\\Registry\\User\\S-1-5-18", L"\\Registry\\User\\.Default");
+#endif
 }
 
 VOID
 RegShutdownRegistry(VOID)
 {
+    PLIST_ENTRY Entry;
+    PREPARSE_POINT ReparsePoint;
+
+    /* Clean up the reparse points list */
+    while (!IsListEmpty(&CmiReparsePointsHead))
+    {
+        Entry = RemoveHeadList(&CmiReparsePointsHead);
+        ReparsePoint = CONTAINING_RECORD(Entry, REPARSE_POINT, ListEntry);
+        free(ReparsePoint);
+    }
+
     /* FIXME: clean up the complete hive */
 
     free(RootKey);