1c2c66affSColin Finck /*
2cc63d8f4SGeorge Bișoc * PROJECT: ReactOS Kernel
3cc63d8f4SGeorge Bișoc * LICENSE: GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later)
4f3141fb2SGeorge Bișoc * PURPOSE: Configuration Manager Library - Registry Syncing & Hive/Log/Alternate Writing
5cc63d8f4SGeorge Bișoc * COPYRIGHT: Copyright 2001 - 2005 Eric Kohl
6cc63d8f4SGeorge Bișoc * Copyright 2005 Filip Navara <navaraf@reactos.org>
7cc63d8f4SGeorge Bișoc * Copyright 2021 Max Korostil
8cc63d8f4SGeorge Bișoc * Copyright 2022 George Bișoc <george.bisoc@reactos.org>
9c2c66affSColin Finck */
10c2c66affSColin Finck
11c2c66affSColin Finck #include "cmlib.h"
12c2c66affSColin Finck #define NDEBUG
13c2c66affSColin Finck #include <debug.h>
14c2c66affSColin Finck
15cc63d8f4SGeorge Bișoc /* DECLARATIONS *************************************************************/
16cc63d8f4SGeorge Bișoc
17cc63d8f4SGeorge Bișoc #if !defined(CMLIB_HOST) && !defined(_BLDR_)
18cc63d8f4SGeorge Bișoc BOOLEAN
19cc63d8f4SGeorge Bișoc NTAPI
20cc63d8f4SGeorge Bișoc IoSetThreadHardErrorMode(
21cc63d8f4SGeorge Bișoc _In_ BOOLEAN HardErrorEnabled);
22cc63d8f4SGeorge Bișoc #endif
23cc63d8f4SGeorge Bișoc
24feb67576SHermès Bélusca-Maïto /* GLOBALS ******************************************************************/
25cc63d8f4SGeorge Bișoc
26cc63d8f4SGeorge Bișoc /* PRIVATE FUNCTIONS ********************************************************/
27cc63d8f4SGeorge Bișoc
28cc63d8f4SGeorge Bișoc /**
29cc63d8f4SGeorge Bișoc * @brief
30cc63d8f4SGeorge Bișoc * Validates the base block header of a primary
31cc63d8f4SGeorge Bișoc * hive for consistency.
32cc63d8f4SGeorge Bișoc *
33cc63d8f4SGeorge Bișoc * @param[in] RegistryHive
34cc63d8f4SGeorge Bișoc * A pointer to a hive descriptor to look
35cc63d8f4SGeorge Bișoc * for the header block.
36cc63d8f4SGeorge Bișoc */
37cc63d8f4SGeorge Bișoc static
38cc63d8f4SGeorge Bișoc VOID
HvpValidateBaseHeader(_In_ PHHIVE RegistryHive)39cc63d8f4SGeorge Bișoc HvpValidateBaseHeader(
40cc63d8f4SGeorge Bișoc _In_ PHHIVE RegistryHive)
41c2c66affSColin Finck {
42cc63d8f4SGeorge Bișoc PHBASE_BLOCK BaseBlock;
43cc63d8f4SGeorge Bișoc
44cc63d8f4SGeorge Bișoc /*
45cc63d8f4SGeorge Bișoc * Cache the base block and validate it.
46cc63d8f4SGeorge Bișoc * Especially...
47cc63d8f4SGeorge Bișoc *
48cc63d8f4SGeorge Bișoc * 1. It must must have a valid signature.
49cc63d8f4SGeorge Bișoc * 2. It must have a valid format.
50cc63d8f4SGeorge Bișoc * 3. It must be of an adequate major version,
51cc63d8f4SGeorge Bișoc * not anything else.
52cc63d8f4SGeorge Bișoc */
53cc63d8f4SGeorge Bișoc BaseBlock = RegistryHive->BaseBlock;
54cc63d8f4SGeorge Bișoc ASSERT(BaseBlock->Signature == HV_HBLOCK_SIGNATURE);
55cc63d8f4SGeorge Bișoc ASSERT(BaseBlock->Format == HBASE_FORMAT_MEMORY);
56cc63d8f4SGeorge Bișoc ASSERT(BaseBlock->Major == HSYS_MAJOR);
57cc63d8f4SGeorge Bișoc }
58cc63d8f4SGeorge Bișoc
59cc63d8f4SGeorge Bișoc /**
60cc63d8f4SGeorge Bișoc * @unimplemented
61cc63d8f4SGeorge Bișoc * @brief
62cc63d8f4SGeorge Bișoc * Writes dirty data in a transacted way to a hive
63cc63d8f4SGeorge Bișoc * log file during hive syncing operation. Log
64cc63d8f4SGeorge Bișoc * files are used by the kernel/bootloader to
65cc63d8f4SGeorge Bișoc * perform recovery operations against a
66cc63d8f4SGeorge Bișoc * damaged primary hive.
67cc63d8f4SGeorge Bișoc *
68cc63d8f4SGeorge Bișoc * @param[in] RegistryHive
69cc63d8f4SGeorge Bișoc * A pointer to a hive descriptor where the log
70cc63d8f4SGeorge Bișoc * belongs to and of which we write data into the
71cc63d8f4SGeorge Bișoc * said log.
72cc63d8f4SGeorge Bișoc *
73cc63d8f4SGeorge Bișoc * @return
74cc63d8f4SGeorge Bișoc * Returns TRUE if log transaction writing has succeeded,
75cc63d8f4SGeorge Bișoc * FALSE otherwise.
76cc63d8f4SGeorge Bișoc *
77cc63d8f4SGeorge Bișoc * @remarks
78cc63d8f4SGeorge Bișoc * The function is not completely implemented, that is,
79cc63d8f4SGeorge Bișoc * it lacks the implementation for growing the log file size.
80cc63d8f4SGeorge Bișoc * See the FIXME comment below for further details.
81cc63d8f4SGeorge Bișoc */
82cc63d8f4SGeorge Bișoc static
83cc63d8f4SGeorge Bișoc BOOLEAN
84cc63d8f4SGeorge Bișoc CMAPI
HvpWriteLog(_In_ PHHIVE RegistryHive)85cc63d8f4SGeorge Bișoc HvpWriteLog(
86cc63d8f4SGeorge Bișoc _In_ PHHIVE RegistryHive)
87cc63d8f4SGeorge Bișoc {
88cc63d8f4SGeorge Bișoc BOOLEAN Success;
89c2c66affSColin Finck ULONG FileOffset;
90c2c66affSColin Finck ULONG BlockIndex;
91c2c66affSColin Finck ULONG LastIndex;
92cc63d8f4SGeorge Bișoc PVOID Block;
93cc63d8f4SGeorge Bișoc UINT32 BitmapSize, BufferSize;
94cc63d8f4SGeorge Bișoc PUCHAR HeaderBuffer, Ptr;
957f80d5eeSJoachim Henze
96cc63d8f4SGeorge Bișoc /*
97cc63d8f4SGeorge Bișoc * The hive log we are going to write data into
98cc63d8f4SGeorge Bișoc * has to be writable and with a sane storage.
99cc63d8f4SGeorge Bișoc */
10076f1da56SHermès Bélusca-Maïto ASSERT(!RegistryHive->ReadOnly);
101c2c66affSColin Finck ASSERT(RegistryHive->BaseBlock->Length ==
102c2c66affSColin Finck RegistryHive->Storage[Stable].Length * HBLOCK_SIZE);
103c2c66affSColin Finck
104cc63d8f4SGeorge Bișoc /* Validate the base header before we go further */
105cc63d8f4SGeorge Bișoc HvpValidateBaseHeader(RegistryHive);
106c2c66affSColin Finck
107cc63d8f4SGeorge Bișoc /*
10876f1da56SHermès Bélusca-Maïto * The sequences can diverge during a forced system shutdown
10976f1da56SHermès Bélusca-Maïto * occurrence, such as during a power failure, a hardware
11076f1da56SHermès Bélusca-Maïto * failure or during a system crash, and when one of the
11176f1da56SHermès Bélusca-Maïto * sequences have been modified during writing into the log
11276f1da56SHermès Bélusca-Maïto * or hive. In such cases the hive needs a repair.
113cc63d8f4SGeorge Bișoc */
114c2c66affSColin Finck if (RegistryHive->BaseBlock->Sequence1 !=
115c2c66affSColin Finck RegistryHive->BaseBlock->Sequence2)
116c2c66affSColin Finck {
117cc63d8f4SGeorge Bișoc DPRINT1("The sequences DO NOT MATCH (Sequence1 == 0x%x, Sequence2 == 0x%x)\n",
118cc63d8f4SGeorge Bișoc RegistryHive->BaseBlock->Sequence1, RegistryHive->BaseBlock->Sequence2);
119c2c66affSColin Finck return FALSE;
120c2c66affSColin Finck }
121c2c66affSColin Finck
122cc63d8f4SGeorge Bișoc /*
123cc63d8f4SGeorge Bișoc * FIXME: We must set a new file size for this log
124cc63d8f4SGeorge Bișoc * here but ReactOS lacks the necessary code implementation
125cc63d8f4SGeorge Bișoc * that manages the growing and shrinking of a hive's log
126cc63d8f4SGeorge Bișoc * size. So for now don't set any new size for the log.
127cc63d8f4SGeorge Bișoc */
128c2c66affSColin Finck
129cc63d8f4SGeorge Bișoc /*
130cc63d8f4SGeorge Bișoc * Now calculate the bitmap and buffer sizes to hold up our
131cc63d8f4SGeorge Bișoc * contents in a buffer.
132cc63d8f4SGeorge Bișoc */
133*c5f93c50STimo Kreuzer BitmapSize = ROUND_UP(sizeof(ULONG) + RegistryHive->DirtyVector.SizeOfBitMap, HSECTOR_SIZE);
134cc63d8f4SGeorge Bișoc BufferSize = HV_LOG_HEADER_SIZE + BitmapSize;
135c2c66affSColin Finck
136cc63d8f4SGeorge Bișoc /* Now allocate the base header block buffer */
137cc63d8f4SGeorge Bișoc HeaderBuffer = RegistryHive->Allocate(BufferSize, TRUE, TAG_CM);
138cc63d8f4SGeorge Bișoc if (!HeaderBuffer)
139c2c66affSColin Finck {
140cc63d8f4SGeorge Bișoc DPRINT1("Couldn't allocate buffer for base header block\n");
141c2c66affSColin Finck return FALSE;
142c2c66affSColin Finck }
143c2c66affSColin Finck
144cc63d8f4SGeorge Bișoc /* Great, now zero out the buffer */
145cc63d8f4SGeorge Bișoc RtlZeroMemory(HeaderBuffer, BufferSize);
146cc63d8f4SGeorge Bișoc
147cc63d8f4SGeorge Bișoc /*
148cc63d8f4SGeorge Bișoc * Update the base block of this hive and
149cc63d8f4SGeorge Bișoc * increment the primary sequence number
150cc63d8f4SGeorge Bișoc * as we are at the half of the work.
151cc63d8f4SGeorge Bișoc */
152c2c66affSColin Finck RegistryHive->BaseBlock->Type = HFILE_TYPE_LOG;
153c2c66affSColin Finck RegistryHive->BaseBlock->Sequence1++;
154cc63d8f4SGeorge Bișoc RegistryHive->BaseBlock->CheckSum = HvpHiveHeaderChecksum(RegistryHive->BaseBlock);
155c2c66affSColin Finck
156cc63d8f4SGeorge Bișoc /* Copy the base block header */
157cc63d8f4SGeorge Bișoc RtlCopyMemory(HeaderBuffer, RegistryHive->BaseBlock, HV_LOG_HEADER_SIZE);
158cc63d8f4SGeorge Bișoc Ptr = HeaderBuffer + HV_LOG_HEADER_SIZE;
159c2c66affSColin Finck
160cc63d8f4SGeorge Bișoc /* Copy the dirty vector */
161cc63d8f4SGeorge Bișoc *((PULONG)Ptr) = HV_LOG_DIRTY_SIGNATURE;
162cc63d8f4SGeorge Bișoc Ptr += sizeof(HV_LOG_DIRTY_SIGNATURE);
163c2c66affSColin Finck
164cc63d8f4SGeorge Bișoc /*
165cc63d8f4SGeorge Bișoc * FIXME: In ReactOS a vector contains one bit per block
166cc63d8f4SGeorge Bișoc * whereas in Windows each bit within a vector is per
167cc63d8f4SGeorge Bișoc * sector. Furthermore, the dirty blocks within a respective
168cc63d8f4SGeorge Bișoc * hive has to be marked as such in an appropriate function
169cc63d8f4SGeorge Bișoc * for this purpose (probably HvMarkDirty or similar).
170cc63d8f4SGeorge Bișoc *
171cc63d8f4SGeorge Bișoc * For the moment being, mark the relevant dirty blocks
172cc63d8f4SGeorge Bișoc * here.
173cc63d8f4SGeorge Bișoc */
174c2c66affSColin Finck BlockIndex = 0;
175c2c66affSColin Finck while (BlockIndex < RegistryHive->Storage[Stable].Length)
176c2c66affSColin Finck {
177cc63d8f4SGeorge Bișoc /* Check if the block is clean or we're past the last block */
178c2c66affSColin Finck LastIndex = BlockIndex;
179c2c66affSColin Finck BlockIndex = RtlFindSetBits(&RegistryHive->DirtyVector, 1, BlockIndex);
180cc63d8f4SGeorge Bișoc if (BlockIndex == ~HV_CLEAN_BLOCK || BlockIndex < LastIndex)
181c2c66affSColin Finck {
182c2c66affSColin Finck break;
183c2c66affSColin Finck }
184c2c66affSColin Finck
185cc63d8f4SGeorge Bișoc /*
186cc63d8f4SGeorge Bișoc * Mark this block as dirty and go to the next one.
187cc63d8f4SGeorge Bișoc *
188cc63d8f4SGeorge Bișoc * FIXME: We should rather use RtlSetBits but that crashes
189cc63d8f4SGeorge Bișoc * the system with a bugckeck. So for now mark blocks manually
190cc63d8f4SGeorge Bișoc * by hand.
191cc63d8f4SGeorge Bișoc */
192cc63d8f4SGeorge Bișoc Ptr[BlockIndex] = HV_LOG_DIRTY_BLOCK;
193cc63d8f4SGeorge Bișoc BlockIndex++;
194cc63d8f4SGeorge Bișoc }
195c2c66affSColin Finck
196cc63d8f4SGeorge Bișoc /* Now write the hive header and block bitmap into the log */
197cc63d8f4SGeorge Bișoc FileOffset = 0;
198c2c66affSColin Finck Success = RegistryHive->FileWrite(RegistryHive, HFILE_TYPE_LOG,
199cc63d8f4SGeorge Bișoc &FileOffset, HeaderBuffer, BufferSize);
200cc63d8f4SGeorge Bișoc RegistryHive->Free(HeaderBuffer, 0);
201c2c66affSColin Finck if (!Success)
202c2c66affSColin Finck {
203cc63d8f4SGeorge Bișoc DPRINT1("Failed to write the hive header block to log (primary sequence)\n");
204c2c66affSColin Finck return FALSE;
205c2c66affSColin Finck }
206c2c66affSColin Finck
207cc63d8f4SGeorge Bișoc /* Now write the actual dirty data to log */
208cc63d8f4SGeorge Bișoc FileOffset = BufferSize;
209cc63d8f4SGeorge Bișoc BlockIndex = 0;
210cc63d8f4SGeorge Bișoc while (BlockIndex < RegistryHive->Storage[Stable].Length)
211cc63d8f4SGeorge Bișoc {
212cc63d8f4SGeorge Bișoc /* Check if the block is clean or we're past the last block */
213cc63d8f4SGeorge Bișoc LastIndex = BlockIndex;
214cc63d8f4SGeorge Bișoc BlockIndex = RtlFindSetBits(&RegistryHive->DirtyVector, 1, BlockIndex);
215cc63d8f4SGeorge Bișoc if (BlockIndex == ~HV_CLEAN_BLOCK || BlockIndex < LastIndex)
216cc63d8f4SGeorge Bișoc {
217cc63d8f4SGeorge Bișoc break;
218cc63d8f4SGeorge Bișoc }
219cc63d8f4SGeorge Bișoc
220cc63d8f4SGeorge Bișoc /* Get the block */
221cc63d8f4SGeorge Bișoc Block = (PVOID)RegistryHive->Storage[Stable].BlockList[BlockIndex].BlockAddress;
222cc63d8f4SGeorge Bișoc
223cc63d8f4SGeorge Bișoc /* Write it to log */
224cc63d8f4SGeorge Bișoc Success = RegistryHive->FileWrite(RegistryHive, HFILE_TYPE_LOG,
225cc63d8f4SGeorge Bișoc &FileOffset, Block, HBLOCK_SIZE);
226cc63d8f4SGeorge Bișoc if (!Success)
227cc63d8f4SGeorge Bișoc {
228cc63d8f4SGeorge Bișoc DPRINT1("Failed to write dirty block to log (block 0x%p, block index 0x%x)\n", Block, BlockIndex);
229cc63d8f4SGeorge Bișoc return FALSE;
230cc63d8f4SGeorge Bișoc }
231cc63d8f4SGeorge Bișoc
232cc63d8f4SGeorge Bișoc /* Grow up the file offset as we go to the next block */
233c2c66affSColin Finck BlockIndex++;
234c2c66affSColin Finck FileOffset += HBLOCK_SIZE;
235c2c66affSColin Finck }
236c2c66affSColin Finck
237cc63d8f4SGeorge Bișoc /*
238cc63d8f4SGeorge Bișoc * We wrote the header and body of log with dirty,
239cc63d8f4SGeorge Bișoc * data do a flush immediately.
240cc63d8f4SGeorge Bișoc */
241c2c66affSColin Finck Success = RegistryHive->FileFlush(RegistryHive, HFILE_TYPE_LOG, NULL, 0);
242c2c66affSColin Finck if (!Success)
243c2c66affSColin Finck {
244cc63d8f4SGeorge Bișoc DPRINT1("Failed to flush the log\n");
245cc63d8f4SGeorge Bișoc return FALSE;
246c2c66affSColin Finck }
247c2c66affSColin Finck
248cc63d8f4SGeorge Bișoc /*
249cc63d8f4SGeorge Bișoc * OK, we're now at 80% of the work done.
250cc63d8f4SGeorge Bișoc * Increment the secondary sequence and flush
251cc63d8f4SGeorge Bișoc * the log again. We can have a fully successful
252cc63d8f4SGeorge Bișoc * transacted write of a log if the sequences
253cc63d8f4SGeorge Bișoc * are synced up properly.
254cc63d8f4SGeorge Bișoc */
255c2c66affSColin Finck RegistryHive->BaseBlock->Sequence2++;
256cc63d8f4SGeorge Bișoc RegistryHive->BaseBlock->CheckSum = HvpHiveHeaderChecksum(RegistryHive->BaseBlock);
257c2c66affSColin Finck
258cc63d8f4SGeorge Bișoc /* Write new stuff into log first */
259c2c66affSColin Finck FileOffset = 0;
260c2c66affSColin Finck Success = RegistryHive->FileWrite(RegistryHive, HFILE_TYPE_LOG,
261c2c66affSColin Finck &FileOffset, RegistryHive->BaseBlock,
262c2c66affSColin Finck HV_LOG_HEADER_SIZE);
263c2c66affSColin Finck if (!Success)
264c2c66affSColin Finck {
265cc63d8f4SGeorge Bișoc DPRINT1("Failed to write the log file (secondary sequence)\n");
266c2c66affSColin Finck return FALSE;
267c2c66affSColin Finck }
268c2c66affSColin Finck
269cc63d8f4SGeorge Bișoc /* Flush it finally */
270c2c66affSColin Finck Success = RegistryHive->FileFlush(RegistryHive, HFILE_TYPE_LOG, NULL, 0);
271c2c66affSColin Finck if (!Success)
272c2c66affSColin Finck {
273cc63d8f4SGeorge Bișoc DPRINT1("Failed to flush the log\n");
274cc63d8f4SGeorge Bișoc return FALSE;
275c2c66affSColin Finck }
2767f80d5eeSJoachim Henze
277c2c66affSColin Finck return TRUE;
278c2c66affSColin Finck }
279c2c66affSColin Finck
280cc63d8f4SGeorge Bișoc /**
281cc63d8f4SGeorge Bișoc * @brief
282cc63d8f4SGeorge Bișoc * Writes data (dirty or non) to a primary hive during
283cc63d8f4SGeorge Bișoc * syncing operation. Hive writing is also performed
284cc63d8f4SGeorge Bișoc * during a flush occurrence on request by the system.
285cc63d8f4SGeorge Bișoc *
286cc63d8f4SGeorge Bișoc * @param[in] RegistryHive
287cc63d8f4SGeorge Bișoc * A pointer to a hive descriptor where the data is
288cc63d8f4SGeorge Bișoc * to be written to that hive.
289cc63d8f4SGeorge Bișoc *
290cc63d8f4SGeorge Bișoc * @param[in] OnlyDirty
291cc63d8f4SGeorge Bișoc * If set to TRUE, the function only looks for dirty
292cc63d8f4SGeorge Bișoc * data to be written to the primary hive, otherwise if
293cc63d8f4SGeorge Bișoc * it's set to FALSE then the function writes all the data.
294cc63d8f4SGeorge Bișoc *
295f3141fb2SGeorge Bișoc * @param[in] FileType
296f3141fb2SGeorge Bișoc * The file type of a registry hive. This can be HFILE_TYPE_PRIMARY
297f3141fb2SGeorge Bișoc * or HFILE_TYPE_ALTERNATE.
298f3141fb2SGeorge Bișoc *
299cc63d8f4SGeorge Bișoc * @return
300cc63d8f4SGeorge Bișoc * Returns TRUE if writing to hive has succeeded,
301cc63d8f4SGeorge Bișoc * FALSE otherwise.
302f3141fb2SGeorge Bișoc *
303f3141fb2SGeorge Bișoc * @remarks
304f3141fb2SGeorge Bișoc * The on-disk header metadata of a hive is already written with type
305f3141fb2SGeorge Bișoc * of HFILE_TYPE_PRIMARY, regardless of what file type the caller submits,
306f3141fb2SGeorge Bișoc * as an alternate hive is basically a mirror of the primary hive.
307cc63d8f4SGeorge Bișoc */
308cc63d8f4SGeorge Bișoc static
309cc63d8f4SGeorge Bișoc BOOLEAN
310cc63d8f4SGeorge Bișoc CMAPI
HvpWriteHive(_In_ PHHIVE RegistryHive,_In_ BOOLEAN OnlyDirty,_In_ ULONG FileType)311c2c66affSColin Finck HvpWriteHive(
312cc63d8f4SGeorge Bișoc _In_ PHHIVE RegistryHive,
313f3141fb2SGeorge Bișoc _In_ BOOLEAN OnlyDirty,
314f3141fb2SGeorge Bișoc _In_ ULONG FileType)
315c2c66affSColin Finck {
316cc63d8f4SGeorge Bișoc BOOLEAN Success;
317c2c66affSColin Finck ULONG FileOffset;
318c2c66affSColin Finck ULONG BlockIndex;
319c2c66affSColin Finck ULONG LastIndex;
320cc63d8f4SGeorge Bișoc PVOID Block;
321c2c66affSColin Finck
32276f1da56SHermès Bélusca-Maïto ASSERT(!RegistryHive->ReadOnly);
323c2c66affSColin Finck ASSERT(RegistryHive->BaseBlock->Length ==
324c2c66affSColin Finck RegistryHive->Storage[Stable].Length * HBLOCK_SIZE);
325cc63d8f4SGeorge Bișoc ASSERT(RegistryHive->BaseBlock->RootCell != HCELL_NIL);
326c2c66affSColin Finck
327cc63d8f4SGeorge Bișoc /* Validate the base header before we go further */
328cc63d8f4SGeorge Bișoc HvpValidateBaseHeader(RegistryHive);
329c2c66affSColin Finck
330cc63d8f4SGeorge Bișoc /*
33176f1da56SHermès Bélusca-Maïto * The sequences can diverge during a forced system shutdown
33276f1da56SHermès Bélusca-Maïto * occurrence, such as during a power failure, a hardware
33376f1da56SHermès Bélusca-Maïto * failure or during a system crash, and when one of the
33476f1da56SHermès Bélusca-Maïto * sequences have been modified during writing into the log
33576f1da56SHermès Bélusca-Maïto * or hive. In such cases the hive needs a repair.
336cc63d8f4SGeorge Bișoc */
337c2c66affSColin Finck if (RegistryHive->BaseBlock->Sequence1 !=
338c2c66affSColin Finck RegistryHive->BaseBlock->Sequence2)
339c2c66affSColin Finck {
340cc63d8f4SGeorge Bișoc DPRINT1("The sequences DO NOT MATCH (Sequence1 == 0x%x, Sequence2 == 0x%x)\n",
341cc63d8f4SGeorge Bișoc RegistryHive->BaseBlock->Sequence1, RegistryHive->BaseBlock->Sequence2);
342c2c66affSColin Finck return FALSE;
343c2c66affSColin Finck }
344c2c66affSColin Finck
345cc63d8f4SGeorge Bișoc /*
346cc63d8f4SGeorge Bișoc * Update the primary sequence number and write
347cc63d8f4SGeorge Bișoc * the base block to hive.
348cc63d8f4SGeorge Bișoc */
349c2c66affSColin Finck RegistryHive->BaseBlock->Type = HFILE_TYPE_PRIMARY;
350c2c66affSColin Finck RegistryHive->BaseBlock->Sequence1++;
351cc63d8f4SGeorge Bișoc RegistryHive->BaseBlock->CheckSum = HvpHiveHeaderChecksum(RegistryHive->BaseBlock);
352c2c66affSColin Finck
353c2c66affSColin Finck /* Write hive block */
354c2c66affSColin Finck FileOffset = 0;
355f3141fb2SGeorge Bișoc Success = RegistryHive->FileWrite(RegistryHive, FileType,
356c2c66affSColin Finck &FileOffset, RegistryHive->BaseBlock,
357c2c66affSColin Finck sizeof(HBASE_BLOCK));
358c2c66affSColin Finck if (!Success)
359c2c66affSColin Finck {
360cc63d8f4SGeorge Bișoc DPRINT1("Failed to write the base block header to primary hive (primary sequence)\n");
361c2c66affSColin Finck return FALSE;
362c2c66affSColin Finck }
363c2c66affSColin Finck
364cc63d8f4SGeorge Bișoc /* Write the whole primary hive, block by block */
365c2c66affSColin Finck BlockIndex = 0;
366c2c66affSColin Finck while (BlockIndex < RegistryHive->Storage[Stable].Length)
367c2c66affSColin Finck {
368cc63d8f4SGeorge Bișoc /*
36976f1da56SHermès Bélusca-Maïto * If we have to synchronize the registry hive we
370cc63d8f4SGeorge Bișoc * want to look for dirty blocks to reflect the new
371cc63d8f4SGeorge Bișoc * updates done to the hive. Otherwise just write
372cc63d8f4SGeorge Bișoc * all the blocks as if we were doing a regular
37376f1da56SHermès Bélusca-Maïto * hive write.
374cc63d8f4SGeorge Bișoc */
375c2c66affSColin Finck if (OnlyDirty)
376c2c66affSColin Finck {
377cc63d8f4SGeorge Bișoc /* Check if the block is clean or we're past the last block */
378c2c66affSColin Finck LastIndex = BlockIndex;
379c2c66affSColin Finck BlockIndex = RtlFindSetBits(&RegistryHive->DirtyVector, 1, BlockIndex);
380cc63d8f4SGeorge Bișoc if (BlockIndex == ~HV_CLEAN_BLOCK || BlockIndex < LastIndex)
381c2c66affSColin Finck {
382c2c66affSColin Finck break;
383c2c66affSColin Finck }
384c2c66affSColin Finck }
385c2c66affSColin Finck
386cc63d8f4SGeorge Bișoc /* Get the block and offset position */
387cc63d8f4SGeorge Bișoc Block = (PVOID)RegistryHive->Storage[Stable].BlockList[BlockIndex].BlockAddress;
388c2c66affSColin Finck FileOffset = (BlockIndex + 1) * HBLOCK_SIZE;
389c2c66affSColin Finck
390cc63d8f4SGeorge Bișoc /* Now write this block to primary hive file */
391f3141fb2SGeorge Bișoc Success = RegistryHive->FileWrite(RegistryHive, FileType,
392cc63d8f4SGeorge Bișoc &FileOffset, Block, HBLOCK_SIZE);
393c2c66affSColin Finck if (!Success)
394c2c66affSColin Finck {
395cc63d8f4SGeorge Bișoc DPRINT1("Failed to write hive block to primary hive file (block 0x%p, block index 0x%x)\n",
396cc63d8f4SGeorge Bișoc Block, BlockIndex);
397c2c66affSColin Finck return FALSE;
398c2c66affSColin Finck }
399c2c66affSColin Finck
400cc63d8f4SGeorge Bișoc /* Go to the next block */
401c2c66affSColin Finck BlockIndex++;
402c2c66affSColin Finck }
403c2c66affSColin Finck
404cc63d8f4SGeorge Bișoc /*
405cc63d8f4SGeorge Bișoc * We wrote all the hive contents to the file, we
406cc63d8f4SGeorge Bișoc * must flush the changes to disk now.
407cc63d8f4SGeorge Bișoc */
408f3141fb2SGeorge Bișoc Success = RegistryHive->FileFlush(RegistryHive, FileType, NULL, 0);
409c2c66affSColin Finck if (!Success)
410c2c66affSColin Finck {
411cc63d8f4SGeorge Bișoc DPRINT1("Failed to flush the primary hive\n");
412cc63d8f4SGeorge Bișoc return FALSE;
413c2c66affSColin Finck }
414c2c66affSColin Finck
415cc63d8f4SGeorge Bișoc /*
416cc63d8f4SGeorge Bișoc * Increment the secondary sequence number and
41776f1da56SHermès Bélusca-Maïto * update the checksum. A successful hive write
41876f1da56SHermès Bélusca-Maïto * transaction is when both of sequences are the
41976f1da56SHermès Bélusca-Maïto * same, indicating the write operation didn't
420cc63d8f4SGeorge Bișoc * fail.
421cc63d8f4SGeorge Bișoc */
422c2c66affSColin Finck RegistryHive->BaseBlock->Sequence2++;
423cc63d8f4SGeorge Bișoc RegistryHive->BaseBlock->CheckSum = HvpHiveHeaderChecksum(RegistryHive->BaseBlock);
424c2c66affSColin Finck
425c2c66affSColin Finck /* Write hive block */
426c2c66affSColin Finck FileOffset = 0;
427f3141fb2SGeorge Bișoc Success = RegistryHive->FileWrite(RegistryHive, FileType,
428c2c66affSColin Finck &FileOffset, RegistryHive->BaseBlock,
429c2c66affSColin Finck sizeof(HBASE_BLOCK));
430c2c66affSColin Finck if (!Success)
431c2c66affSColin Finck {
432cc63d8f4SGeorge Bișoc DPRINT1("Failed to write the base block header to primary hive (secondary sequence)\n");
433c2c66affSColin Finck return FALSE;
434c2c66affSColin Finck }
435c2c66affSColin Finck
436cc63d8f4SGeorge Bișoc /* Flush the hive immediately */
437f3141fb2SGeorge Bișoc Success = RegistryHive->FileFlush(RegistryHive, FileType, NULL, 0);
438c2c66affSColin Finck if (!Success)
439c2c66affSColin Finck {
440cc63d8f4SGeorge Bișoc DPRINT1("Failed to flush the primary hive\n");
441c2c66affSColin Finck return FALSE;
442c2c66affSColin Finck }
443c2c66affSColin Finck
444cc63d8f4SGeorge Bișoc return TRUE;
445cc63d8f4SGeorge Bișoc }
446cc63d8f4SGeorge Bișoc
447cc63d8f4SGeorge Bișoc /* PUBLIC FUNCTIONS ***********************************************************/
448cc63d8f4SGeorge Bișoc
449cc63d8f4SGeorge Bișoc /**
450cc63d8f4SGeorge Bișoc * @brief
451cc63d8f4SGeorge Bișoc * Synchronizes a registry hive with latest updates
452cc63d8f4SGeorge Bișoc * from dirty data present in volatile memory, aka RAM.
453cc63d8f4SGeorge Bișoc * It writes both to hive log and corresponding primary
454cc63d8f4SGeorge Bișoc * hive. Syncing is done on request by the system during
455cc63d8f4SGeorge Bișoc * a flush occurrence.
456cc63d8f4SGeorge Bișoc *
457cc63d8f4SGeorge Bișoc * @param[in] RegistryHive
458cc63d8f4SGeorge Bișoc * A pointer to a hive descriptor where syncing is
459cc63d8f4SGeorge Bișoc * to be performed.
460cc63d8f4SGeorge Bișoc *
461cc63d8f4SGeorge Bișoc * @return
462cc63d8f4SGeorge Bișoc * Returns TRUE if syncing has succeeded, FALSE otherwise.
463cc63d8f4SGeorge Bișoc */
464cc63d8f4SGeorge Bișoc BOOLEAN
465cc63d8f4SGeorge Bișoc CMAPI
HvSyncHive(_In_ PHHIVE RegistryHive)466cc63d8f4SGeorge Bișoc HvSyncHive(
467cc63d8f4SGeorge Bișoc _In_ PHHIVE RegistryHive)
468cc63d8f4SGeorge Bișoc {
469cc63d8f4SGeorge Bișoc #if !defined(CMLIB_HOST) && !defined(_BLDR_)
470cc63d8f4SGeorge Bișoc BOOLEAN HardErrors;
471cc63d8f4SGeorge Bișoc #endif
472cc63d8f4SGeorge Bișoc
47376f1da56SHermès Bélusca-Maïto ASSERT(!RegistryHive->ReadOnly);
474cc63d8f4SGeorge Bișoc ASSERT(RegistryHive->Signature == HV_HHIVE_SIGNATURE);
475cc63d8f4SGeorge Bișoc
476feb67576SHermès Bélusca-Maïto /* Avoid any write operations on volatile hives */
477feb67576SHermès Bélusca-Maïto if (RegistryHive->HiveFlags & HIVE_VOLATILE)
478feb67576SHermès Bélusca-Maïto {
479feb67576SHermès Bélusca-Maïto DPRINT("Hive 0x%p is volatile\n", RegistryHive);
480feb67576SHermès Bélusca-Maïto return TRUE;
481feb67576SHermès Bélusca-Maïto }
482feb67576SHermès Bélusca-Maïto
483cc63d8f4SGeorge Bișoc /*
484cc63d8f4SGeorge Bișoc * Check if there's any dirty data in the vector.
485cc63d8f4SGeorge Bișoc * A space with clean blocks would be pointless for
486cc63d8f4SGeorge Bișoc * a log because we want to write dirty data in and
487cc63d8f4SGeorge Bișoc * sync up, not clean data. So just consider our
488cc63d8f4SGeorge Bișoc * job as done as there's literally nothing to do.
489cc63d8f4SGeorge Bișoc */
490cc63d8f4SGeorge Bișoc if (RtlFindSetBits(&RegistryHive->DirtyVector, 1, 0) == ~HV_CLEAN_BLOCK)
491cc63d8f4SGeorge Bișoc {
492cc63d8f4SGeorge Bișoc DPRINT("The dirty vector has clean data, nothing to do\n");
493cc63d8f4SGeorge Bișoc return TRUE;
494cc63d8f4SGeorge Bișoc }
495cc63d8f4SGeorge Bișoc
496cc63d8f4SGeorge Bișoc #if !defined(CMLIB_HOST) && !defined(_BLDR_)
497cc63d8f4SGeorge Bișoc /* Disable hard errors before syncing the hive */
498cc63d8f4SGeorge Bișoc HardErrors = IoSetThreadHardErrorMode(FALSE);
499cc63d8f4SGeorge Bișoc #endif
500cc63d8f4SGeorge Bișoc
501cc63d8f4SGeorge Bișoc #if !defined(_BLDR_)
502cc63d8f4SGeorge Bișoc /* Update hive header modification time */
503cc63d8f4SGeorge Bișoc KeQuerySystemTime(&RegistryHive->BaseBlock->TimeStamp);
504cc63d8f4SGeorge Bișoc #endif
505cc63d8f4SGeorge Bișoc
50676f1da56SHermès Bélusca-Maïto /* Update the hive log file if present */
50776f1da56SHermès Bélusca-Maïto if (RegistryHive->Log)
508cc63d8f4SGeorge Bișoc {
509cc63d8f4SGeorge Bișoc if (!HvpWriteLog(RegistryHive))
510cc63d8f4SGeorge Bișoc {
511cc63d8f4SGeorge Bișoc DPRINT1("Failed to write a log whilst syncing the hive\n");
512cc63d8f4SGeorge Bișoc #if !defined(CMLIB_HOST) && !defined(_BLDR_)
513cc63d8f4SGeorge Bișoc IoSetThreadHardErrorMode(HardErrors);
514cc63d8f4SGeorge Bișoc #endif
515cc63d8f4SGeorge Bișoc return FALSE;
516cc63d8f4SGeorge Bișoc }
517cc63d8f4SGeorge Bișoc }
518cc63d8f4SGeorge Bișoc
519cc63d8f4SGeorge Bișoc /* Update the primary hive file */
520f3141fb2SGeorge Bișoc if (!HvpWriteHive(RegistryHive, TRUE, HFILE_TYPE_PRIMARY))
521c2c66affSColin Finck {
522cc63d8f4SGeorge Bișoc DPRINT1("Failed to write the primary hive\n");
523cc63d8f4SGeorge Bișoc #if !defined(CMLIB_HOST) && !defined(_BLDR_)
524cc63d8f4SGeorge Bișoc IoSetThreadHardErrorMode(HardErrors);
525cc63d8f4SGeorge Bișoc #endif
526c2c66affSColin Finck return FALSE;
527c2c66affSColin Finck }
528c2c66affSColin Finck
529f3141fb2SGeorge Bișoc /* Update the alternate hive file if present */
53076f1da56SHermès Bélusca-Maïto if (RegistryHive->Alternate)
531f3141fb2SGeorge Bișoc {
532f3141fb2SGeorge Bișoc if (!HvpWriteHive(RegistryHive, TRUE, HFILE_TYPE_ALTERNATE))
533f3141fb2SGeorge Bișoc {
534f3141fb2SGeorge Bișoc DPRINT1("Failed to write the alternate hive\n");
535f3141fb2SGeorge Bișoc #if !defined(CMLIB_HOST) && !defined(_BLDR_)
536f3141fb2SGeorge Bișoc IoSetThreadHardErrorMode(HardErrors);
537f3141fb2SGeorge Bișoc #endif
538f3141fb2SGeorge Bișoc return FALSE;
539f3141fb2SGeorge Bișoc }
540f3141fb2SGeorge Bișoc }
541f3141fb2SGeorge Bișoc
542c2c66affSColin Finck /* Clear dirty bitmap. */
543c2c66affSColin Finck RtlClearAllBits(&RegistryHive->DirtyVector);
544c2c66affSColin Finck RegistryHive->DirtyCount = 0;
545c2c66affSColin Finck
546cc63d8f4SGeorge Bișoc #if !defined(CMLIB_HOST) && !defined(_BLDR_)
547cc63d8f4SGeorge Bișoc IoSetThreadHardErrorMode(HardErrors);
548cc63d8f4SGeorge Bișoc #endif
549c2c66affSColin Finck return TRUE;
550c2c66affSColin Finck }
551c2c66affSColin Finck
552cc63d8f4SGeorge Bișoc /**
553cc63d8f4SGeorge Bișoc * @unimplemented
554cc63d8f4SGeorge Bișoc * @brief
555cc63d8f4SGeorge Bișoc * Determines whether a registry hive needs
556cc63d8f4SGeorge Bișoc * to be shrinked or not based on its overall
557cc63d8f4SGeorge Bișoc * size of the hive space to avoid unnecessary
558cc63d8f4SGeorge Bișoc * bloat.
559cc63d8f4SGeorge Bișoc *
560cc63d8f4SGeorge Bișoc * @param[in] RegistryHive
561cc63d8f4SGeorge Bișoc * A pointer to a hive descriptor where hive
562cc63d8f4SGeorge Bișoc * shrinking is to be determined.
563cc63d8f4SGeorge Bișoc *
564cc63d8f4SGeorge Bișoc * @return
565cc63d8f4SGeorge Bișoc * Returns TRUE if hive shrinking needs to be
566cc63d8f4SGeorge Bișoc * done, FALSE otherwise.
567cc63d8f4SGeorge Bișoc */
568c2c66affSColin Finck BOOLEAN
569c2c66affSColin Finck CMAPI
HvHiveWillShrink(_In_ PHHIVE RegistryHive)570cc63d8f4SGeorge Bișoc HvHiveWillShrink(
571cc63d8f4SGeorge Bișoc _In_ PHHIVE RegistryHive)
572c2c66affSColin Finck {
573c2c66affSColin Finck /* No shrinking yet */
574db55933bSMark Jansen UNIMPLEMENTED_ONCE;
575c2c66affSColin Finck return FALSE;
576c2c66affSColin Finck }
577c2c66affSColin Finck
578cc63d8f4SGeorge Bișoc /**
579cc63d8f4SGeorge Bișoc * @brief
580cc63d8f4SGeorge Bișoc * Writes data to a registry hive. Unlike
581cc63d8f4SGeorge Bișoc * HvSyncHive, this function just writes
582cc63d8f4SGeorge Bișoc * the wholy registry data to a primary hive,
583cc63d8f4SGeorge Bișoc * ignoring if a certain data block is dirty
584cc63d8f4SGeorge Bișoc * or not.
585cc63d8f4SGeorge Bișoc *
586cc63d8f4SGeorge Bișoc * @param[in] RegistryHive
587cc63d8f4SGeorge Bișoc * A pointer to a hive descriptor where data
588cc63d8f4SGeorge Bișoc * is be written into.
589cc63d8f4SGeorge Bișoc *
590cc63d8f4SGeorge Bișoc * @return
591cc63d8f4SGeorge Bișoc * Returns TRUE if hive writing has succeeded,
592cc63d8f4SGeorge Bișoc * FALSE otherwise.
593cc63d8f4SGeorge Bișoc */
594cc63d8f4SGeorge Bișoc BOOLEAN
595cc63d8f4SGeorge Bișoc CMAPI
HvWriteHive(_In_ PHHIVE RegistryHive)596c2c66affSColin Finck HvWriteHive(
597cc63d8f4SGeorge Bișoc _In_ PHHIVE RegistryHive)
598c2c66affSColin Finck {
59976f1da56SHermès Bélusca-Maïto ASSERT(!RegistryHive->ReadOnly);
600cc63d8f4SGeorge Bișoc ASSERT(RegistryHive->Signature == HV_HHIVE_SIGNATURE);
601c2c66affSColin Finck
602cc63d8f4SGeorge Bișoc #if !defined(_BLDR_)
603c2c66affSColin Finck /* Update hive header modification time */
604c2c66affSColin Finck KeQuerySystemTime(&RegistryHive->BaseBlock->TimeStamp);
605cc63d8f4SGeorge Bișoc #endif
606c2c66affSColin Finck
607c2c66affSColin Finck /* Update hive file */
608f3141fb2SGeorge Bișoc if (!HvpWriteHive(RegistryHive, FALSE, HFILE_TYPE_PRIMARY))
609c2c66affSColin Finck {
610cc63d8f4SGeorge Bișoc DPRINT1("Failed to write the hive\n");
611c2c66affSColin Finck return FALSE;
612c2c66affSColin Finck }
613c2c66affSColin Finck
614c2c66affSColin Finck return TRUE;
615c2c66affSColin Finck }
616cc63d8f4SGeorge Bișoc
617f3141fb2SGeorge Bișoc /**
618f3141fb2SGeorge Bișoc * @brief
619f3141fb2SGeorge Bișoc * Writes data to an alternate registry hive.
620f3141fb2SGeorge Bișoc * An alternate hive is usually backed up by a primary
621f3141fb2SGeorge Bișoc * hive. This function is tipically used to force write
622f3141fb2SGeorge Bișoc * data into the alternate hive if both hives no longer match.
623f3141fb2SGeorge Bișoc *
624f3141fb2SGeorge Bișoc * @param[in] RegistryHive
625f3141fb2SGeorge Bișoc * A pointer to a hive descriptor where data
626f3141fb2SGeorge Bișoc * is to be written into.
627f3141fb2SGeorge Bișoc *
628f3141fb2SGeorge Bișoc * @return
629f3141fb2SGeorge Bișoc * Returns TRUE if hive writing has succeeded,
630f3141fb2SGeorge Bișoc * FALSE otherwise.
631f3141fb2SGeorge Bișoc */
632f3141fb2SGeorge Bișoc BOOLEAN
633f3141fb2SGeorge Bișoc CMAPI
HvWriteAlternateHive(_In_ PHHIVE RegistryHive)634f3141fb2SGeorge Bișoc HvWriteAlternateHive(
635f3141fb2SGeorge Bișoc _In_ PHHIVE RegistryHive)
636f3141fb2SGeorge Bișoc {
63776f1da56SHermès Bélusca-Maïto ASSERT(!RegistryHive->ReadOnly);
638f3141fb2SGeorge Bișoc ASSERT(RegistryHive->Signature == HV_HHIVE_SIGNATURE);
63976f1da56SHermès Bélusca-Maïto ASSERT(RegistryHive->Alternate);
640f3141fb2SGeorge Bișoc
641f3141fb2SGeorge Bișoc #if !defined(_BLDR_)
642f3141fb2SGeorge Bișoc /* Update hive header modification time */
643f3141fb2SGeorge Bișoc KeQuerySystemTime(&RegistryHive->BaseBlock->TimeStamp);
644f3141fb2SGeorge Bișoc #endif
645f3141fb2SGeorge Bișoc
646f3141fb2SGeorge Bișoc /* Update hive file */
647f3141fb2SGeorge Bișoc if (!HvpWriteHive(RegistryHive, FALSE, HFILE_TYPE_ALTERNATE))
648f3141fb2SGeorge Bișoc {
649f3141fb2SGeorge Bișoc DPRINT1("Failed to write the alternate hive\n");
650f3141fb2SGeorge Bișoc return FALSE;
651f3141fb2SGeorge Bișoc }
652f3141fb2SGeorge Bișoc
653f3141fb2SGeorge Bișoc return TRUE;
654f3141fb2SGeorge Bișoc }
655cc63d8f4SGeorge Bișoc
656cc63d8f4SGeorge Bișoc /**
657cc63d8f4SGeorge Bișoc * @brief
658cc63d8f4SGeorge Bișoc * Synchronizes a hive with recovered
659cc63d8f4SGeorge Bișoc * data during a healing/resuscitation
660cc63d8f4SGeorge Bișoc * operation of the registry.
661cc63d8f4SGeorge Bișoc *
662cc63d8f4SGeorge Bișoc * @param[in] RegistryHive
663cc63d8f4SGeorge Bișoc * A pointer to a hive descriptor where data
664cc63d8f4SGeorge Bișoc * syncing is to be done.
665cc63d8f4SGeorge Bișoc *
666cc63d8f4SGeorge Bișoc * @return
667cc63d8f4SGeorge Bișoc * Returns TRUE if hive syncing during recovery
668cc63d8f4SGeorge Bișoc * succeeded, FALSE otherwise.
669cc63d8f4SGeorge Bișoc */
670cc63d8f4SGeorge Bișoc BOOLEAN
671cc63d8f4SGeorge Bișoc CMAPI
HvSyncHiveFromRecover(_In_ PHHIVE RegistryHive)672cc63d8f4SGeorge Bișoc HvSyncHiveFromRecover(
673cc63d8f4SGeorge Bișoc _In_ PHHIVE RegistryHive)
674cc63d8f4SGeorge Bișoc {
67576f1da56SHermès Bélusca-Maïto ASSERT(!RegistryHive->ReadOnly);
676cc63d8f4SGeorge Bișoc ASSERT(RegistryHive->Signature == HV_HHIVE_SIGNATURE);
677cc63d8f4SGeorge Bișoc
678cc63d8f4SGeorge Bișoc /* Call the private API call to do the deed for us */
679f3141fb2SGeorge Bișoc return HvpWriteHive(RegistryHive, TRUE, HFILE_TYPE_PRIMARY);
680cc63d8f4SGeorge Bișoc }
681cc63d8f4SGeorge Bișoc
682cc63d8f4SGeorge Bișoc /* EOF */
683