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