https://git.reactos.org/?p=reactos.git;a=commitdiff;h=ea6dac3438a7ec3b333f4…
commit ea6dac3438a7ec3b333f4cb3fb738177e9e62c0a
Author: Eric Kohl <eric.kohl(a)reactos.org>
AuthorDate: Fri Sep 28 16:24:07 2018 +0200
Commit: Eric Kohl <eric.kohl(a)reactos.org>
CommitDate: Fri Sep 28 16:24:07 2018 +0200
[SERVICES] Create a new control set on a non-setup boot.
---
base/system/services/controlset.c | 381 ++++++++++++++++++++++++++++++++++++++
base/system/services/services.c | 6 +-
base/system/services/services.h | 3 +-
3 files changed, 386 insertions(+), 4 deletions(-)
diff --git a/base/system/services/controlset.c b/base/system/services/controlset.c
index 19bbb53877..948f3ddc79 100644
--- a/base/system/services/controlset.c
+++ b/base/system/services/controlset.c
@@ -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 */
diff --git a/base/system/services/services.c b/base/system/services/services.c
index bd7f24ccc0..591c5a7062 100644
--- a/base/system/services/services.c
+++ b/base/system/services/services.c
@@ -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;
}
diff --git a/base/system/services/services.h b/base/system/services/services.h
index ce1b46eafa..cbbf6eb008 100644
--- a/base/system/services/services.h
+++ b/base/system/services/services.h
@@ -159,7 +159,8 @@ ScmDecryptPassword(
/* controlset.c */
-BOOL ScmGetControlSetValues(VOID);
+BOOL
+ScmUpdateControlSets(VOID)
/* database.c */