[SERVICES] Create a new control set on a non-setup boot.
authorEric Kohl <eric.kohl@reactos.org>
Fri, 28 Sep 2018 14:24:07 +0000 (16:24 +0200)
committerEric Kohl <eric.kohl@reactos.org>
Fri, 28 Sep 2018 14:24:07 +0000 (16:24 +0200)
base/system/services/controlset.c
base/system/services/services.c
base/system/services/services.h

index 19bbb53..948f3dd 100644 (file)
@@ -25,6 +25,234 @@ static DWORD dwLastKnownGoodControlSet;
 
 /* FUNCTIONS *****************************************************************/
 
+static
+DWORD
+ScmCopyKey(HKEY hDstKey,
+           HKEY hSrcKey)
+{
+#if (_WIN32_WINNT >= 0x0600)
+    return RegCopyTreeW(hSrcKey,
+                        NULL,
+                        hDstKey);
+#else
+    FILETIME LastWrite;
+    DWORD dwSubKeys;
+    DWORD dwValues;
+    DWORD dwType;
+    DWORD dwMaxSubKeyNameLength;
+    DWORD dwSubKeyNameLength;
+    DWORD dwMaxValueNameLength;
+    DWORD dwValueNameLength;
+    DWORD dwMaxValueLength;
+    DWORD dwValueLength;
+    DWORD dwDisposition;
+    DWORD i;
+    LPWSTR lpNameBuffer;
+    LPBYTE lpDataBuffer;
+    HKEY hDstSubKey;
+    HKEY hSrcSubKey;
+    DWORD dwError;
+
+    DPRINT("ScmCopyKey()\n");
+
+    dwError = RegQueryInfoKey(hSrcKey,
+                              NULL,
+                              NULL,
+                              NULL,
+                              &dwSubKeys,
+                              &dwMaxSubKeyNameLength,
+                              NULL,
+                              &dwValues,
+                              &dwMaxValueNameLength,
+                              &dwMaxValueLength,
+                              NULL,
+                              NULL);
+    if (dwError != ERROR_SUCCESS)
+    {
+        DPRINT1("RegQueryInfoKey() failed (Error %lu)\n", dwError);
+        return dwError;
+    }
+
+    dwMaxSubKeyNameLength++;
+    dwMaxValueNameLength++;
+
+    DPRINT("dwSubKeys %lu\n", dwSubKeys);
+    DPRINT("dwMaxSubKeyNameLength %lu\n", dwMaxSubKeyNameLength);
+    DPRINT("dwValues %lu\n", dwValues);
+    DPRINT("dwMaxValueNameLength %lu\n", dwMaxValueNameLength);
+    DPRINT("dwMaxValueLength %lu\n", dwMaxValueLength);
+
+    /* Copy subkeys */
+    if (dwSubKeys != 0)
+    {
+        lpNameBuffer = HeapAlloc(GetProcessHeap(),
+                                 0,
+                                 dwMaxSubKeyNameLength * sizeof(WCHAR));
+        if (lpNameBuffer == NULL)
+        {
+            DPRINT1("Buffer allocation failed\n");
+            return ERROR_NOT_ENOUGH_MEMORY;
+        }
+
+        for (i = 0; i < dwSubKeys; i++)
+        {
+            dwSubKeyNameLength = dwMaxSubKeyNameLength;
+            dwError = RegEnumKeyExW(hSrcKey,
+                                   i,
+                                   lpNameBuffer,
+                                   &dwSubKeyNameLength,
+                                   NULL,
+                                   NULL,
+                                   NULL,
+                                   &LastWrite);
+            if (dwError != ERROR_SUCCESS)
+            {
+                DPRINT1("Subkey enumeration failed (Error %lu)\n", dwError);
+                HeapFree(GetProcessHeap(),
+                         0,
+                         lpNameBuffer);
+                return dwError;
+            }
+
+            dwError = RegCreateKeyExW(hDstKey,
+                                     lpNameBuffer,
+                                     0,
+                                     NULL,
+                                     REG_OPTION_NON_VOLATILE,
+                                     KEY_WRITE,
+                                     NULL,
+                                     &hDstSubKey,
+                                     &dwDisposition);
+            if (dwError != ERROR_SUCCESS)
+            {
+                DPRINT1("Subkey creation failed (Error %lu)\n", dwError);
+                HeapFree(GetProcessHeap(),
+                         0,
+                         lpNameBuffer);
+                return dwError;
+            }
+
+            dwError = RegOpenKeyExW(hSrcKey,
+                                   lpNameBuffer,
+                                   0,
+                                   KEY_READ,
+                                   &hSrcSubKey);
+            if (dwError != ERROR_SUCCESS)
+            {
+                DPRINT1("Error: %lu\n", dwError);
+                RegCloseKey(hDstSubKey);
+                HeapFree(GetProcessHeap(),
+                         0,
+                         lpNameBuffer);
+                return dwError;
+            }
+
+            dwError = ScmCopyKey(hDstSubKey,
+                                hSrcSubKey);
+            if (dwError != ERROR_SUCCESS)
+            {
+                DPRINT1("Error: %lu\n", dwError);
+                RegCloseKey (hSrcSubKey);
+                RegCloseKey (hDstSubKey);
+                HeapFree(GetProcessHeap(),
+                         0,
+                         lpNameBuffer);
+                return dwError;
+            }
+
+            RegCloseKey(hSrcSubKey);
+            RegCloseKey(hDstSubKey);
+        }
+
+        HeapFree(GetProcessHeap(),
+                 0,
+                 lpNameBuffer);
+    }
+
+    /* Copy values */
+    if (dwValues != 0)
+    {
+        lpNameBuffer = HeapAlloc(GetProcessHeap(),
+                                 0,
+                                 dwMaxValueNameLength * sizeof(WCHAR));
+        if (lpNameBuffer == NULL)
+        {
+            DPRINT1("Buffer allocation failed\n");
+            return ERROR_NOT_ENOUGH_MEMORY;
+        }
+
+        lpDataBuffer = HeapAlloc(GetProcessHeap(),
+                                 0,
+                                 dwMaxValueLength);
+        if (lpDataBuffer == NULL)
+        {
+            DPRINT1("Buffer allocation failed\n");
+            HeapFree(GetProcessHeap(),
+                     0,
+                     lpNameBuffer);
+            return ERROR_NOT_ENOUGH_MEMORY;
+        }
+
+        for (i = 0; i < dwValues; i++)
+        {
+            dwValueNameLength = dwMaxValueNameLength;
+            dwValueLength = dwMaxValueLength;
+            dwError = RegEnumValueW(hSrcKey,
+                                   i,
+                                   lpNameBuffer,
+                                   &dwValueNameLength,
+                                   NULL,
+                                   &dwType,
+                                   lpDataBuffer,
+                                   &dwValueLength);
+            if (dwError != ERROR_SUCCESS)
+            {
+                DPRINT1("Error: %lu\n", dwError);
+                HeapFree(GetProcessHeap(),
+                         0,
+                         lpDataBuffer);
+                HeapFree(GetProcessHeap(),
+                         0,
+                         lpNameBuffer);
+                return dwError;
+            }
+
+            dwError = RegSetValueExW(hDstKey,
+                                    lpNameBuffer,
+                                    0,
+                                    dwType,
+                                    lpDataBuffer,
+                                    dwValueLength);
+            if (dwError != ERROR_SUCCESS)
+            {
+                DPRINT1("Error: %lu\n", dwError);
+                HeapFree(GetProcessHeap(),
+                         0,
+                         lpDataBuffer);
+                HeapFree(GetProcessHeap(),
+                         0,
+                         lpNameBuffer);
+                return dwError;
+            }
+        }
+
+        HeapFree(GetProcessHeap(),
+                 0,
+                 lpDataBuffer);
+
+        HeapFree(GetProcessHeap(),
+                 0,
+                 lpNameBuffer);
+    }
+
+    DPRINT("ScmCopyKey() done \n");
+
+    return ERROR_SUCCESS;
+#endif
+}
+
+
+static
 BOOL
 ScmGetControlSetValues(VOID)
 {
@@ -102,4 +330,157 @@ ScmGetControlSetValues(VOID)
     return TRUE;
 }
 
+
+static
+DWORD
+ScmSetLastKnownGoodControlSet(
+    DWORD dwControlSet)
+{
+    HKEY hSelectKey;
+    DWORD dwError;
+
+    dwError = RegOpenKeyExW(HKEY_LOCAL_MACHINE,
+                            L"System\\Select",
+                            0,
+                            KEY_WRITE,
+                            &hSelectKey);
+    if (dwError != ERROR_SUCCESS)
+        return dwError;
+
+    dwError = RegSetValueExW(hSelectKey,
+                             L"LastKnownGood",
+                             0,
+                             REG_DWORD,
+                             (LPBYTE)&dwControlSet,
+                             sizeof(dwControlSet));
+
+    RegCloseKey(hSelectKey);
+
+    return dwError;
+}
+
+
+static
+DWORD
+ScmGetSetupInProgress(VOID)
+{
+    DWORD dwError;
+    HKEY hKey;
+    DWORD dwType;
+    DWORD dwSize;
+    DWORD dwSetupInProgress = (DWORD)-1;
+
+    DPRINT("ScmGetSetupInProgress()\n");
+
+    /* Open key */
+    dwError = RegOpenKeyExW(HKEY_LOCAL_MACHINE,
+                            L"SYSTEM\\Setup",
+                            0,
+                            KEY_QUERY_VALUE,
+                            &hKey);
+    if (dwError == ERROR_SUCCESS)
+    {
+        /* Read key */
+        dwSize = sizeof(DWORD);
+        RegQueryValueExW(hKey,
+                         L"SystemSetupInProgress",
+                         NULL,
+                         &dwType,
+                         (LPBYTE)&dwSetupInProgress,
+                         &dwSize);
+        RegCloseKey(hKey);
+    }
+
+    DPRINT("SetupInProgress: %lu\n", dwSetupInProgress);
+    return dwSetupInProgress;
+}
+
+
+BOOL
+ScmUpdateControlSets(VOID)
+{
+    WCHAR szCurrentControlSetName[32];
+    WCHAR szNewControlSetName[32];
+    HKEY hCurrentControlSetKey = NULL;
+    HKEY hNewControlSetKey = NULL;
+    DWORD dwNewControlSet, dwDisposition;
+    DWORD dwError;
+
+    /* Do not create a new control set when the system setup is running */
+    if (ScmGetSetupInProgress() != 0)
+    {
+        DPRINT1("No new control set because we are in setup mode!\n");
+        return TRUE;
+    }
+
+    /* Get the control set values */
+    if (!ScmGetControlSetValues())
+        return FALSE;
+
+    /* Search for a new control set number */
+    for (dwNewControlSet = 1; dwNewControlSet < 1000; dwNewControlSet++)
+    {
+         if ((dwNewControlSet != dwCurrentControlSet) &&
+             (dwNewControlSet != dwDefaultControlSet) &&
+             (dwNewControlSet != dwFailedControlSet) &&
+             (dwNewControlSet != dwLastKnownGoodControlSet))
+            break;
+    }
+
+    /* Fail if we did not find an unused control set!*/
+    if (dwNewControlSet >= 1000)
+    {
+        DPRINT1("Too many control sets!\n");
+        return FALSE;
+    }
+
+    /* Create the current control set name */
+    swprintf(szCurrentControlSetName, L"SYSTEM\\ControlSet%03lu", dwCurrentControlSet);
+    DPRINT("Current control set: %S\n", szCurrentControlSetName);
+
+    /* Create the new control set name */
+    swprintf(szNewControlSetName, L"SYSTEM\\ControlSet%03lu", dwNewControlSet);
+    DPRINT("New control set: %S\n", szNewControlSetName);
+
+    /* Open the current control set key */
+    dwError = RegOpenKeyExW(HKEY_LOCAL_MACHINE,
+                            szCurrentControlSetName,
+                            0,
+                            KEY_READ,
+                            &hCurrentControlSetKey);
+    if (dwError != ERROR_SUCCESS)
+        goto done;
+
+    /* Create the new control set key */
+    dwError = RegCreateKeyExW(HKEY_LOCAL_MACHINE,
+                              szNewControlSetName,
+                              0,
+                              NULL,
+                              REG_OPTION_NON_VOLATILE,
+                              KEY_WRITE,
+                              NULL,
+                              &hNewControlSetKey,
+                              &dwDisposition);
+    if (dwError != ERROR_SUCCESS)
+        goto done;
+
+    /* Copy the current control set to the new control set */
+    dwError = ScmCopyKey(hNewControlSetKey,
+                         hCurrentControlSetKey);
+    if (dwError != ERROR_SUCCESS)
+        goto done;
+
+    /* Set the new 'LastKnownGood' control set */
+    dwError = ScmSetLastKnownGoodControlSet(dwNewControlSet);
+
+done:
+    if (hNewControlSetKey != NULL)
+        RegCloseKey(hNewControlSetKey);
+
+    if (hCurrentControlSetKey != NULL)
+        RegCloseKey(hCurrentControlSetKey);
+
+    return (dwError == ERROR_SUCCESS);
+}
+
 /* EOF */
index bd7f24c..591c5a7 100644 (file)
@@ -178,10 +178,10 @@ wWinMain(HINSTANCE hInstance,
 
     /* FIXME: more initialization */
 
-    /* Read the control set values */
-    if (!ScmGetControlSetValues())
+    /* Update the control sets */
+    if (!ScmUpdateControlSets())
     {
-        DPRINT1("SERVICES: Failed to read the control set values\n");
+        DPRINT1("SERVICES: Failed to update the control sets\n");
         goto done;
     }
 
index ce1b46e..cbbf6eb 100644 (file)
@@ -159,7 +159,8 @@ ScmDecryptPassword(
 
 /* controlset.c */
 
-BOOL ScmGetControlSetValues(VOID);
+BOOL
+ScmUpdateControlSets(VOID)
 
 
 /* database.c */