xref: /reactos/sdk/lib/cmlib/hivewrt.c (revision 50cf16b3)
1 /*
2  * PROJECT:   Registry manipulation library
3  * LICENSE:   GPL - See COPYING in the top level directory
4  * COPYRIGHT: Copyright 2005 Filip Navara <navaraf@reactos.org>
5  *            Copyright 2001 - 2005 Eric Kohl
6  */
7 
8 #include "cmlib.h"
9 #define NDEBUG
10 #include <debug.h>
11 
12 static BOOLEAN CMAPI
13 HvpWriteLog(
14     PHHIVE RegistryHive)
15 {
16     ULONG FileOffset;
17     UINT32 BufferSize;
18     UINT32 BitmapSize;
19     PUCHAR Buffer;
20     PUCHAR Ptr;
21     ULONG BlockIndex;
22     ULONG LastIndex;
23     PVOID BlockPtr;
24     BOOLEAN Success;
25     static ULONG PrintCount = 0;
26 
27     if (PrintCount++ == 0)
28     {
29         UNIMPLEMENTED;
30     }
31     return TRUE;
32 
33     ASSERT(RegistryHive->ReadOnly == FALSE);
34     ASSERT(RegistryHive->BaseBlock->Length ==
35            RegistryHive->Storage[Stable].Length * HBLOCK_SIZE);
36 
37     DPRINT("HvpWriteLog called\n");
38 
39     if (RegistryHive->BaseBlock->Sequence1 !=
40         RegistryHive->BaseBlock->Sequence2)
41     {
42         return FALSE;
43     }
44 
45     BitmapSize = RegistryHive->DirtyVector.SizeOfBitMap;
46     BufferSize = HV_LOG_HEADER_SIZE + sizeof(ULONG) + BitmapSize;
47     BufferSize = ROUND_UP(BufferSize, HBLOCK_SIZE);
48 
49     DPRINT("Bitmap size %u  buffer size: %u\n", BitmapSize, BufferSize);
50 
51     Buffer = RegistryHive->Allocate(BufferSize, TRUE, TAG_CM);
52     if (Buffer == NULL)
53     {
54         return FALSE;
55     }
56 
57     /* Update first update counter and CheckSum */
58     RegistryHive->BaseBlock->Type = HFILE_TYPE_LOG;
59     RegistryHive->BaseBlock->Sequence1++;
60     RegistryHive->BaseBlock->CheckSum =
61         HvpHiveHeaderChecksum(RegistryHive->BaseBlock);
62 
63     /* Copy hive header */
64     RtlCopyMemory(Buffer, RegistryHive->BaseBlock, HV_LOG_HEADER_SIZE);
65     Ptr = Buffer + HV_LOG_HEADER_SIZE;
66     RtlCopyMemory(Ptr, "DIRT", 4);
67     Ptr += 4;
68     RtlCopyMemory(Ptr, RegistryHive->DirtyVector.Buffer, BitmapSize);
69 
70     /* Write hive block and block bitmap */
71     FileOffset = 0;
72     Success = RegistryHive->FileWrite(RegistryHive, HFILE_TYPE_LOG,
73                                       &FileOffset, Buffer, BufferSize);
74     RegistryHive->Free(Buffer, 0);
75 
76     if (!Success)
77     {
78         return FALSE;
79     }
80 
81     /* Write dirty blocks */
82     FileOffset = BufferSize;
83     BlockIndex = 0;
84     while (BlockIndex < RegistryHive->Storage[Stable].Length)
85     {
86         LastIndex = BlockIndex;
87         BlockIndex = RtlFindSetBits(&RegistryHive->DirtyVector, 1, BlockIndex);
88         if (BlockIndex == ~0U || BlockIndex < LastIndex)
89         {
90             break;
91         }
92 
93         BlockPtr = (PVOID)RegistryHive->Storage[Stable].BlockList[BlockIndex].BlockAddress;
94 
95         /* Write hive block */
96         Success = RegistryHive->FileWrite(RegistryHive, HFILE_TYPE_LOG,
97                                          &FileOffset, BlockPtr, HBLOCK_SIZE);
98         if (!Success)
99         {
100             return FALSE;
101         }
102 
103         BlockIndex++;
104         FileOffset += HBLOCK_SIZE;
105     }
106 
107     Success = RegistryHive->FileSetSize(RegistryHive, HFILE_TYPE_LOG, FileOffset, FileOffset);
108     if (!Success)
109     {
110         DPRINT("FileSetSize failed\n");
111         return FALSE;
112     }
113 
114     /* Flush the log file */
115     Success = RegistryHive->FileFlush(RegistryHive, HFILE_TYPE_LOG, NULL, 0);
116     if (!Success)
117     {
118         DPRINT("FileFlush failed\n");
119     }
120 
121     /* Update second update counter and CheckSum */
122     RegistryHive->BaseBlock->Sequence2++;
123     RegistryHive->BaseBlock->CheckSum =
124         HvpHiveHeaderChecksum(RegistryHive->BaseBlock);
125 
126     /* Write hive header again with updated sequence counter. */
127     FileOffset = 0;
128     Success = RegistryHive->FileWrite(RegistryHive, HFILE_TYPE_LOG,
129                                       &FileOffset, RegistryHive->BaseBlock,
130                                       HV_LOG_HEADER_SIZE);
131     if (!Success)
132     {
133         return FALSE;
134     }
135 
136     /* Flush the log file */
137     Success = RegistryHive->FileFlush(RegistryHive, HFILE_TYPE_LOG, NULL, 0);
138     if (!Success)
139     {
140         DPRINT("FileFlush failed\n");
141     }
142 
143     return TRUE;
144 }
145 
146 static BOOLEAN CMAPI
147 HvpWriteHive(
148     PHHIVE RegistryHive,
149     BOOLEAN OnlyDirty)
150 {
151     ULONG FileOffset;
152     ULONG BlockIndex;
153     ULONG LastIndex;
154     PVOID BlockPtr;
155     BOOLEAN Success;
156 
157     ASSERT(RegistryHive->ReadOnly == FALSE);
158     ASSERT(RegistryHive->BaseBlock->Length ==
159            RegistryHive->Storage[Stable].Length * HBLOCK_SIZE);
160 
161     DPRINT("HvpWriteHive called\n");
162 
163     if (RegistryHive->BaseBlock->Sequence1 !=
164         RegistryHive->BaseBlock->Sequence2)
165     {
166         return FALSE;
167     }
168 
169     /* Update first update counter and CheckSum */
170     RegistryHive->BaseBlock->Type = HFILE_TYPE_PRIMARY;
171     RegistryHive->BaseBlock->Sequence1++;
172     RegistryHive->BaseBlock->CheckSum =
173         HvpHiveHeaderChecksum(RegistryHive->BaseBlock);
174 
175     /* Write hive block */
176     FileOffset = 0;
177     Success = RegistryHive->FileWrite(RegistryHive, HFILE_TYPE_PRIMARY,
178                                       &FileOffset, RegistryHive->BaseBlock,
179                                       sizeof(HBASE_BLOCK));
180     if (!Success)
181     {
182         return FALSE;
183     }
184 
185     BlockIndex = 0;
186     while (BlockIndex < RegistryHive->Storage[Stable].Length)
187     {
188         if (OnlyDirty)
189         {
190             LastIndex = BlockIndex;
191             BlockIndex = RtlFindSetBits(&RegistryHive->DirtyVector, 1, BlockIndex);
192             if (BlockIndex == ~0U || BlockIndex < LastIndex)
193             {
194                 break;
195             }
196         }
197 
198         BlockPtr = (PVOID)RegistryHive->Storage[Stable].BlockList[BlockIndex].BlockAddress;
199         FileOffset = (BlockIndex + 1) * HBLOCK_SIZE;
200 
201         /* Write hive block */
202         Success = RegistryHive->FileWrite(RegistryHive, HFILE_TYPE_PRIMARY,
203                                           &FileOffset, BlockPtr, HBLOCK_SIZE);
204         if (!Success)
205         {
206             return FALSE;
207         }
208 
209         BlockIndex++;
210     }
211 
212     Success = RegistryHive->FileFlush(RegistryHive, HFILE_TYPE_PRIMARY, NULL, 0);
213     if (!Success)
214     {
215         DPRINT("FileFlush failed\n");
216     }
217 
218     /* Update second update counter and CheckSum */
219     RegistryHive->BaseBlock->Sequence2++;
220     RegistryHive->BaseBlock->CheckSum =
221         HvpHiveHeaderChecksum(RegistryHive->BaseBlock);
222 
223     /* Write hive block */
224     FileOffset = 0;
225     Success = RegistryHive->FileWrite(RegistryHive, HFILE_TYPE_PRIMARY,
226                                       &FileOffset, RegistryHive->BaseBlock,
227                                       sizeof(HBASE_BLOCK));
228     if (!Success)
229     {
230         return FALSE;
231     }
232 
233     Success = RegistryHive->FileFlush(RegistryHive, HFILE_TYPE_PRIMARY, NULL, 0);
234     if (!Success)
235     {
236         DPRINT("FileFlush failed\n");
237     }
238 
239     return TRUE;
240 }
241 
242 BOOLEAN CMAPI
243 HvSyncHive(
244     PHHIVE RegistryHive)
245 {
246     ASSERT(RegistryHive->ReadOnly == FALSE);
247 
248     if (RtlFindSetBits(&RegistryHive->DirtyVector, 1, 0) == ~0U)
249     {
250         return TRUE;
251     }
252 
253     /* Update hive header modification time */
254     KeQuerySystemTime(&RegistryHive->BaseBlock->TimeStamp);
255 
256     /* Update log file */
257     if (!HvpWriteLog(RegistryHive))
258     {
259         return FALSE;
260     }
261 
262     /* Update hive file */
263     if (!HvpWriteHive(RegistryHive, TRUE))
264     {
265         return FALSE;
266     }
267 
268     /* Clear dirty bitmap. */
269     RtlClearAllBits(&RegistryHive->DirtyVector);
270     RegistryHive->DirtyCount = 0;
271 
272     return TRUE;
273 }
274 
275 BOOLEAN
276 CMAPI
277 HvHiveWillShrink(IN PHHIVE RegistryHive)
278 {
279     /* No shrinking yet */
280     UNIMPLEMENTED;
281     return FALSE;
282 }
283 
284 BOOLEAN CMAPI
285 HvWriteHive(
286     PHHIVE RegistryHive)
287 {
288     ASSERT(RegistryHive->ReadOnly == FALSE);
289 
290     /* Update hive header modification time */
291     KeQuerySystemTime(&RegistryHive->BaseBlock->TimeStamp);
292 
293     /* Update hive file */
294     if (!HvpWriteHive(RegistryHive, FALSE))
295     {
296         return FALSE;
297     }
298 
299     return TRUE;
300 }
301