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