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