https://git.reactos.org/?p=reactos.git;a=commitdiff;h=f3141fb29ebc26bcf1771…
commit f3141fb29ebc26bcf177163edd48ae0408bb381b
Author: George Bișoc <george.bisoc(a)reactos.org>
AuthorDate: Mon Oct 30 18:07:21 2023 +0100
Commit: George Bișoc <george.bisoc(a)reactos.org>
CommitDate: Sun Nov 19 20:44:29 2023 +0100
[NTOS:CM] Implement support for alternate registry hives
Sometimes repairing a broken hive with a hive log does not always guarantee the hive
in question has fully recovered. In worst cases it could happen the LOG itself is
even
corrupt too and that would certainly lead to a total unbootable system. This is most
likely
if the victim hive is the SYSTEM hive.
This can be anyhow solved by the help of a mirror hive, or also called an
"alternate hive".
Alternate hives serve the purpose as backup hives for primary hives of which there is
still
a risk that is not worth taking. For now only the SYSTEM hive is granted the right to
have
a backup alternate hive.
=== NOTE ===
Currently the SYSTEM hive can only base upon the alternate SYSTEM.ALT hive, which
means the
corresponding LOG file never gets updated. When time comes the existing code must be
adapted
to allow the possibility to use .ALT and .LOG hives simultaneously.
---
ntoskrnl/config/cmapi.c | 2 +
ntoskrnl/config/cminit.c | 29 ++++++----
ntoskrnl/config/cmsysini.c | 119 ++++++++++++++++++++++++++++++++++++++---
ntoskrnl/include/internal/cm.h | 21 ++++----
sdk/lib/cmlib/cmlib.h | 9 ++++
sdk/lib/cmlib/hivedata.h | 4 +-
sdk/lib/cmlib/hiveinit.c | 13 +++++
sdk/lib/cmlib/hivewrt.c | 81 ++++++++++++++++++++++++----
8 files changed, 239 insertions(+), 39 deletions(-)
diff --git a/ntoskrnl/config/cmapi.c b/ntoskrnl/config/cmapi.c
index 287caecf245..8e3e3edd69a 100644
--- a/ntoskrnl/config/cmapi.c
+++ b/ntoskrnl/config/cmapi.c
@@ -2703,6 +2703,7 @@ CmSaveKey(IN PCM_KEY_CONTROL_BLOCK Kcb,
NULL,
NULL,
NULL,
+ NULL,
CM_CHECK_REGISTRY_DONT_PURGE_VOLATILES);
if (!NT_SUCCESS(Status)) goto Cleanup;
@@ -2795,6 +2796,7 @@ CmSaveMergedKeys(IN PCM_KEY_CONTROL_BLOCK HighKcb,
NULL,
NULL,
NULL,
+ NULL,
CM_CHECK_REGISTRY_DONT_PURGE_VOLATILES);
if (!NT_SUCCESS(Status))
goto done;
diff --git a/ntoskrnl/config/cminit.c b/ntoskrnl/config/cminit.c
index 3406bfea302..15dc4f0d77c 100644
--- a/ntoskrnl/config/cminit.c
+++ b/ntoskrnl/config/cminit.c
@@ -16,16 +16,18 @@
NTSTATUS
NTAPI
-CmpInitializeHive(OUT PCMHIVE *CmHive,
- IN ULONG OperationType,
- IN ULONG HiveFlags,
- IN ULONG FileType,
- IN PVOID HiveData OPTIONAL,
- IN HANDLE Primary,
- IN HANDLE Log,
- IN HANDLE External,
- IN PCUNICODE_STRING FileName OPTIONAL,
- IN ULONG CheckFlags)
+CmpInitializeHive(
+ _Out_ PCMHIVE *CmHive,
+ _In_ ULONG OperationType,
+ _In_ ULONG HiveFlags,
+ _In_ ULONG FileType,
+ _In_opt_ PVOID HiveData,
+ _In_ HANDLE Primary,
+ _In_ HANDLE Log,
+ _In_ HANDLE External,
+ _In_ HANDLE Alternate,
+ _In_opt_ PCUNICODE_STRING FileName,
+ _In_ ULONG CheckFlags)
{
PCMHIVE Hive;
IO_STATUS_BLOCK IoStatusBlock;
@@ -44,13 +46,17 @@ CmpInitializeHive(OUT PCMHIVE *CmHive,
* unless this hive is a shared system hive.
* - An in-memory initialization without hive data.
* - A log hive that is not linked to a correct file type.
+ * - An alternate hive that is not linked to a correct file type.
+ * - A lonely alternate hive not backed up with its corresponding primary hive.
*/
if (((External) && ((Primary) || (Log))) ||
((Log) && !(Primary)) ||
(!(CmpShareSystemHives) && (HiveFlags & HIVE_VOLATILE) &&
((Primary) || (External) || (Log))) ||
((OperationType == HINIT_MEMORY) && (!HiveData)) ||
- ((Log) && (FileType != HFILE_TYPE_LOG)))
+ ((Log) && (FileType != HFILE_TYPE_LOG)) ||
+ ((Alternate) && (FileType != HFILE_TYPE_ALTERNATE)) ||
+ ((Alternate) && !(Primary)))
{
/* Fail the request */
return STATUS_INVALID_PARAMETER;
@@ -140,6 +146,7 @@ CmpInitializeHive(OUT PCMHIVE *CmHive,
Hive->FileHandles[HFILE_TYPE_PRIMARY] = Primary;
Hive->FileHandles[HFILE_TYPE_LOG] = Log;
Hive->FileHandles[HFILE_TYPE_EXTERNAL] = External;
+ Hive->FileHandles[HFILE_TYPE_ALTERNATE] = Alternate;
/* Initailize the guarded mutex */
KeInitializeGuardedMutex(Hive->ViewLock);
diff --git a/ntoskrnl/config/cmsysini.c b/ntoskrnl/config/cmsysini.c
index d74fffe07da..d28a5b5d20d 100644
--- a/ntoskrnl/config/cmsysini.c
+++ b/ntoskrnl/config/cmsysini.c
@@ -359,6 +359,7 @@ CmpInitHiveFromFile(IN PCUNICODE_STRING HiveName,
FileHandle,
LogHandle,
NULL,
+ NULL,
HiveName,
CheckFlags);
if (!NT_SUCCESS(Status))
@@ -906,11 +907,12 @@ CmpInitializeSystemHive(IN PLOADER_PARAMETER_BLOCK LoaderBlock)
Status = CmpInitializeHive(&SystemHive,
HiveBase ? HINIT_MEMORY : HINIT_CREATE,
HIVE_NOLAZYFLUSH,
- HFILE_TYPE_LOG,
+ HFILE_TYPE_ALTERNATE,
HiveBase,
NULL,
NULL,
NULL,
+ NULL,
&HiveName,
HiveBase ? CM_CHECK_REGISTRY_PURGE_VOLATILES :
CM_CHECK_REGISTRY_DONT_PURGE_VOLATILES);
if (!NT_SUCCESS(Status))
@@ -1181,6 +1183,76 @@ CmpGetRegistryPath(VOID)
return ConfigPath;
}
+/**
+ * @brief
+ * Checks if the primary and alternate backing hive are
+ * the same, by determining the time stamp of both hives.
+ *
+ * @param[in] FileName
+ * A pointer to a string containing the file name of the
+ * primary hive.
+ *
+ * @param[in] CmMainmHive
+ * A pointer to a CM hive descriptor associated with the
+ * primary hive.
+ *
+ * @param[in] AlternateHandle
+ * A handle to a file that represents the alternate hive.
+ *
+ * @param[in] Diverged
+ * A pointer to a boolean value, if both hives are the same
+ * it returns TRUE. Otherwise it returns FALSE.
+ */
+static
+VOID
+CmpHasAlternateHiveDiverged(
+ _In_ PCUNICODE_STRING FileName,
+ _In_ PCMHIVE CmMainmHive,
+ _In_ HANDLE AlternateHandle,
+ _Out_ PBOOLEAN Diverged)
+{
+ PHHIVE Hive, AlternateHive;
+ NTSTATUS Status;
+ PCMHIVE CmiAlternateHive;
+
+ /* Assume it has not diverged */
+ *Diverged = FALSE;
+
+ /* Initialize the SYSTEM alternate hive */
+ Status = CmpInitializeHive(&CmiAlternateHive,
+ HINIT_FILE,
+ 0,
+ HFILE_TYPE_PRIMARY,
+ NULL,
+ AlternateHandle,
+ NULL,
+ NULL,
+ NULL,
+ FileName,
+ CM_CHECK_REGISTRY_DONT_PURGE_VOLATILES);
+ if (!NT_SUCCESS(Status))
+ {
+ /* Assume it has diverged... */
+ DPRINT1("Failed to initialize the alternate hive to check for diversion
(Status 0x%lx)\n", Status);
+ *Diverged = TRUE;
+ return;
+ }
+
+ /*
+ * Check the timestamp of both hives. If they do not match they
+ * have diverged, the kernel has to synchronize the both hives.
+ */
+ Hive = &CmMainmHive->Hive;
+ AlternateHive = &CmiAlternateHive->Hive;
+ if (AlternateHive->BaseBlock->TimeStamp.QuadPart !=
+ Hive->BaseBlock->TimeStamp.QuadPart)
+ {
+ *Diverged = TRUE;
+ }
+
+ CmpDestroyHive(CmiAlternateHive);
+}
+
_Function_class_(KSTART_ROUTINE)
VOID
NTAPI
@@ -1193,9 +1265,10 @@ CmpLoadHiveThread(IN PVOID StartContext)
USHORT FileStart;
ULONG PrimaryDisposition, SecondaryDisposition, ClusterSize;
PCMHIVE CmHive;
- HANDLE PrimaryHandle = NULL, LogHandle = NULL;
+ HANDLE PrimaryHandle = NULL, AlternateHandle = NULL;
NTSTATUS Status = STATUS_SUCCESS;
PVOID ErrorParameters;
+ BOOLEAN HasDiverged;
PAGED_CODE();
/* Get the hive index, make sure it makes sense */
@@ -1274,18 +1347,18 @@ CmpLoadHiveThread(IN PVOID StartContext)
{
/* It's now, open the hive file and log */
Status = CmpOpenHiveFiles(&FileName,
- L".LOG",
+ L".ALT",
&PrimaryHandle,
- &LogHandle,
+ &AlternateHandle,
&PrimaryDisposition,
&SecondaryDisposition,
TRUE,
TRUE,
FALSE,
&ClusterSize);
- if (!(NT_SUCCESS(Status)) || !(LogHandle))
+ if (!(NT_SUCCESS(Status)) || !(AlternateHandle))
{
- /* Couldn't open the hive or its log file, raise a hard error */
+ /* Couldn't open the hive or its alternate file, raise a hard error
*/
ErrorParameters = &FileName;
NtRaiseHardError(STATUS_CANNOT_LOAD_REGISTRY_FILE,
1,
@@ -1299,7 +1372,14 @@ CmpLoadHiveThread(IN PVOID StartContext)
}
/* Save the file handles. This should remove our sync hacks */
- CmHive->FileHandles[HFILE_TYPE_LOG] = LogHandle;
+ /*
+ * FIXME: Any hive that relies on the alternate hive for recovery purposes
+ * will only get an alternate hive. As a result, the LOG file would never
+ * get synced each time a write is done to the hive. In the future it would
+ * be best to adapt the code so that a primary hive can use a LOG and ALT
+ * hives at the same time.
+ */
+ CmHive->FileHandles[HFILE_TYPE_ALTERNATE] = AlternateHandle;
CmHive->FileHandles[HFILE_TYPE_PRIMARY] = PrimaryHandle;
/* Allow lazy flushing since the handles are there -- remove sync hacks */
@@ -1332,6 +1412,28 @@ CmpLoadHiveThread(IN PVOID StartContext)
CmHive->Hive.DirtyCount = CmHive->Hive.DirtyVector.SizeOfBitMap;
HvSyncHive((PHHIVE)CmHive);
}
+ else
+ {
+ /*
+ * Check whether the both primary and alternate hives are the same,
+ * or that the primary or alternate were created for the first time.
+ * Do a write against the alternate hive in these cases.
+ */
+ CmpHasAlternateHiveDiverged(&FileName,
+ CmHive,
+ AlternateHandle,
+ &HasDiverged);
+ if (HasDiverged ||
+ PrimaryDisposition == FILE_CREATED ||
+ SecondaryDisposition == FILE_CREATED)
+ {
+ if (!HvWriteAlternateHive((PHHIVE)CmHive))
+ {
+ DPRINT1("Failed to write to alternate hive\n");
+ goto Exit;
+ }
+ }
+ }
/* Finally, set our allocated hive to the same hive we've had */
CmpMachineHiveList[i].CmHive2 = CmHive;
@@ -1339,6 +1441,7 @@ CmpLoadHiveThread(IN PVOID StartContext)
}
}
+Exit:
/* We're done */
CmpMachineHiveList[i].ThreadFinished = TRUE;
@@ -1571,6 +1674,7 @@ CmInitSystem1(VOID)
NULL,
NULL,
NULL,
+ NULL,
CM_CHECK_REGISTRY_DONT_PURGE_VOLATILES);
if (!NT_SUCCESS(Status))
{
@@ -1662,6 +1766,7 @@ CmInitSystem1(VOID)
NULL,
NULL,
NULL,
+ NULL,
CM_CHECK_REGISTRY_DONT_PURGE_VOLATILES);
if (!NT_SUCCESS(Status))
{
diff --git a/ntoskrnl/include/internal/cm.h b/ntoskrnl/include/internal/cm.h
index 04869a812bc..7657fc77fb9 100644
--- a/ntoskrnl/include/internal/cm.h
+++ b/ntoskrnl/include/internal/cm.h
@@ -747,16 +747,17 @@ CmpQueryKeyName(
NTSTATUS
NTAPI
CmpInitializeHive(
- OUT PCMHIVE *CmHive,
- IN ULONG OperationType,
- IN ULONG HiveFlags,
- IN ULONG FileType,
- IN PVOID HiveData OPTIONAL,
- IN HANDLE Primary,
- IN HANDLE Log,
- IN HANDLE External,
- IN PCUNICODE_STRING FileName OPTIONAL,
- IN ULONG CheckFlags
+ _Out_ PCMHIVE *CmHive,
+ _In_ ULONG OperationType,
+ _In_ ULONG HiveFlags,
+ _In_ ULONG FileType,
+ _In_opt_ PVOID HiveData,
+ _In_ HANDLE Primary,
+ _In_ HANDLE Log,
+ _In_ HANDLE External,
+ _In_ HANDLE Alternate,
+ _In_opt_ PCUNICODE_STRING FileName,
+ _In_ ULONG CheckFlags
);
NTSTATUS
diff --git a/sdk/lib/cmlib/cmlib.h b/sdk/lib/cmlib/cmlib.h
index fc73e5a58ac..aee69f58460 100644
--- a/sdk/lib/cmlib/cmlib.h
+++ b/sdk/lib/cmlib/cmlib.h
@@ -120,6 +120,10 @@
IN ULONG StartingIndex,
IN ULONG NumberToSet);
+ VOID NTAPI
+ RtlSetAllBits(
+ IN PRTL_BITMAP BitMapHeader);
+
VOID NTAPI
RtlClearAllBits(
IN PRTL_BITMAP BitMapHeader);
@@ -509,6 +513,11 @@ BOOLEAN CMAPI
HvWriteHive(
PHHIVE RegistryHive);
+BOOLEAN
+CMAPI
+HvWriteAlternateHive(
+ _In_ PHHIVE RegistryHive);
+
BOOLEAN
CMAPI
HvSyncHiveFromRecover(
diff --git a/sdk/lib/cmlib/hivedata.h b/sdk/lib/cmlib/hivedata.h
index 16f96de6b4f..83c9d53a5cd 100644
--- a/sdk/lib/cmlib/hivedata.h
+++ b/sdk/lib/cmlib/hivedata.h
@@ -33,7 +33,8 @@
#define HFILE_TYPE_PRIMARY 0
#define HFILE_TYPE_LOG 1
#define HFILE_TYPE_EXTERNAL 2
-#define HFILE_TYPE_MAX 3
+#define HFILE_TYPE_ALTERNATE 3 // Technically a HFILE_TYPE_PRIMARY but for
mirror backup hives. ONLY USED for the SYSTEM hive!
+#define HFILE_TYPE_MAX 4
//
// Hive sizes
@@ -334,6 +335,7 @@ typedef struct _HHIVE
BOOLEAN ReadOnly;
#if (NTDDI_VERSION < NTDDI_VISTA) // NTDDI_LONGHORN
BOOLEAN Log;
+ BOOLEAN Alternate;
#endif
BOOLEAN DirtyFlag;
#if (NTDDI_VERSION >= NTDDI_VISTA) // NTDDI_LONGHORN
diff --git a/sdk/lib/cmlib/hiveinit.c b/sdk/lib/cmlib/hiveinit.c
index a89a5050c21..d79c9dadad3 100644
--- a/sdk/lib/cmlib/hiveinit.c
+++ b/sdk/lib/cmlib/hiveinit.c
@@ -441,6 +441,18 @@ HvpInitializeMemoryHive(
RtlInitializeBitMap(&Hive->DirtyVector, BitmapBuffer, BitmapSize * 8);
RtlClearAllBits(&Hive->DirtyVector);
+ /*
+ * Mark the entire hive as dirty. Indeed we understand if we charged up
+ * the alternate variant of the primary hive (e.g. SYSTEM.ALT) because
+ * FreeLdr could not load the main SYSTEM hive, due to corruptions, and
+ * repairing it with a LOG did not help at all.
+ */
+ if (ChunkBase->BootRecover == HBOOT_BOOT_RECOVERED_BY_ALTERNATE_HIVE)
+ {
+ RtlSetAllBits(&Hive->DirtyVector);
+ Hive->DirtyCount = Hive->DirtyVector.SizeOfBitMap;
+ }
+
HvpInitFileName(Hive->BaseBlock, FileName);
return STATUS_SUCCESS;
@@ -1377,6 +1389,7 @@ HvInitialize(
Hive->Version = HSYS_MINOR;
#if (NTDDI_VERSION < NTDDI_VISTA)
Hive->Log = (FileType == HFILE_TYPE_LOG);
+ Hive->Alternate = (FileType == HFILE_TYPE_ALTERNATE);
#endif
Hive->HiveFlags = HiveFlags & ~HIVE_NOLAZYFLUSH;
diff --git a/sdk/lib/cmlib/hivewrt.c b/sdk/lib/cmlib/hivewrt.c
index 4fea5fa70e6..d95e8559196 100644
--- a/sdk/lib/cmlib/hivewrt.c
+++ b/sdk/lib/cmlib/hivewrt.c
@@ -1,7 +1,7 @@
/*
* PROJECT: ReactOS Kernel
* LICENSE: GPL-2.0-or-later (
https://spdx.org/licenses/GPL-2.0-or-later)
- * PURPOSE: Configuration Manager Library - Registry Syncing & Hive/Log Writing
+ * PURPOSE: Configuration Manager Library - Registry Syncing & Hive/Log/Alternate
Writing
* COPYRIGHT: Copyright 2001 - 2005 Eric Kohl
* Copyright 2005 Filip Navara <navaraf(a)reactos.org>
* Copyright 2021 Max Korostil
@@ -297,16 +297,26 @@ HvpWriteLog(
* data to be written to the primary hive, otherwise if
* it's set to FALSE then the function writes all the data.
*
+ * @param[in] FileType
+ * The file type of a registry hive. This can be HFILE_TYPE_PRIMARY
+ * or HFILE_TYPE_ALTERNATE.
+ *
* @return
* Returns TRUE if writing to hive has succeeded,
* FALSE otherwise.
+ *
+ * @remarks
+ * The on-disk header metadata of a hive is already written with type
+ * of HFILE_TYPE_PRIMARY, regardless of what file type the caller submits,
+ * as an alternate hive is basically a mirror of the primary hive.
*/
static
BOOLEAN
CMAPI
HvpWriteHive(
_In_ PHHIVE RegistryHive,
- _In_ BOOLEAN OnlyDirty)
+ _In_ BOOLEAN OnlyDirty,
+ _In_ ULONG FileType)
{
BOOLEAN Success;
ULONG FileOffset;
@@ -348,7 +358,7 @@ HvpWriteHive(
/* Write hive block */
FileOffset = 0;
- Success = RegistryHive->FileWrite(RegistryHive, HFILE_TYPE_PRIMARY,
+ Success = RegistryHive->FileWrite(RegistryHive, FileType,
&FileOffset, RegistryHive->BaseBlock,
sizeof(HBASE_BLOCK));
if (!Success)
@@ -384,7 +394,7 @@ HvpWriteHive(
FileOffset = (BlockIndex + 1) * HBLOCK_SIZE;
/* Now write this block to primary hive file */
- Success = RegistryHive->FileWrite(RegistryHive, HFILE_TYPE_PRIMARY,
+ Success = RegistryHive->FileWrite(RegistryHive, FileType,
&FileOffset, Block, HBLOCK_SIZE);
if (!Success)
{
@@ -401,7 +411,7 @@ HvpWriteHive(
* We wrote all the hive contents to the file, we
* must flush the changes to disk now.
*/
- Success = RegistryHive->FileFlush(RegistryHive, HFILE_TYPE_PRIMARY, NULL, 0);
+ Success = RegistryHive->FileFlush(RegistryHive, FileType, NULL, 0);
if (!Success)
{
DPRINT1("Failed to flush the primary hive\n");
@@ -420,7 +430,7 @@ HvpWriteHive(
/* Write hive block */
FileOffset = 0;
- Success = RegistryHive->FileWrite(RegistryHive, HFILE_TYPE_PRIMARY,
+ Success = RegistryHive->FileWrite(RegistryHive, FileType,
&FileOffset, RegistryHive->BaseBlock,
sizeof(HBASE_BLOCK));
if (!Success)
@@ -430,7 +440,7 @@ HvpWriteHive(
}
/* Flush the hive immediately */
- Success = RegistryHive->FileFlush(RegistryHive, HFILE_TYPE_PRIMARY, NULL, 0);
+ Success = RegistryHive->FileFlush(RegistryHive, FileType, NULL, 0);
if (!Success)
{
DPRINT1("Failed to flush the primary hive\n");
@@ -526,7 +536,7 @@ HvSyncHive(
}
/* Update the primary hive file */
- if (!HvpWriteHive(RegistryHive, TRUE))
+ if (!HvpWriteHive(RegistryHive, TRUE, HFILE_TYPE_PRIMARY))
{
DPRINT1("Failed to write the primary hive\n");
#if !defined(CMLIB_HOST) && !defined(_BLDR_)
@@ -535,6 +545,19 @@ HvSyncHive(
return FALSE;
}
+ /* Update the alternate hive file if present */
+ if (RegistryHive->Alternate == TRUE)
+ {
+ if (!HvpWriteHive(RegistryHive, TRUE, HFILE_TYPE_ALTERNATE))
+ {
+ DPRINT1("Failed to write the alternate hive\n");
+#if !defined(CMLIB_HOST) && !defined(_BLDR_)
+ IoSetThreadHardErrorMode(HardErrors);
+#endif
+ return FALSE;
+ }
+ }
+
/* Clear dirty bitmap. */
RtlClearAllBits(&RegistryHive->DirtyVector);
RegistryHive->DirtyCount = 0;
@@ -601,7 +624,7 @@ HvWriteHive(
#endif
/* Update hive file */
- if (!HvpWriteHive(RegistryHive, FALSE))
+ if (!HvpWriteHive(RegistryHive, FALSE, HFILE_TYPE_PRIMARY))
{
DPRINT1("Failed to write the hive\n");
return FALSE;
@@ -610,6 +633,44 @@ HvWriteHive(
return TRUE;
}
+/**
+ * @brief
+ * Writes data to an alternate registry hive.
+ * An alternate hive is usually backed up by a primary
+ * hive. This function is tipically used to force write
+ * data into the alternate hive if both hives no longer match.
+ *
+ * @param[in] RegistryHive
+ * A pointer to a hive descriptor where data
+ * is to be written into.
+ *
+ * @return
+ * Returns TRUE if hive writing has succeeded,
+ * FALSE otherwise.
+ */
+BOOLEAN
+CMAPI
+HvWriteAlternateHive(
+ _In_ PHHIVE RegistryHive)
+{
+ ASSERT(RegistryHive->ReadOnly == FALSE);
+ ASSERT(RegistryHive->Signature == HV_HHIVE_SIGNATURE);
+ ASSERT(RegistryHive->Alternate == TRUE);
+
+#if !defined(_BLDR_)
+ /* Update hive header modification time */
+ KeQuerySystemTime(&RegistryHive->BaseBlock->TimeStamp);
+#endif
+
+ /* Update hive file */
+ if (!HvpWriteHive(RegistryHive, FALSE, HFILE_TYPE_ALTERNATE))
+ {
+ DPRINT1("Failed to write the alternate hive\n");
+ return FALSE;
+ }
+
+ return TRUE;
+}
/**
* @brief
@@ -634,7 +695,7 @@ HvSyncHiveFromRecover(
ASSERT(RegistryHive->Signature == HV_HHIVE_SIGNATURE);
/* Call the private API call to do the deed for us */
- return HvpWriteHive(RegistryHive, TRUE);
+ return HvpWriteHive(RegistryHive, TRUE, HFILE_TYPE_PRIMARY);
}
/* EOF */