c73b659283bf5d8af367131918c4e2d3937299ec
[reactos.git] / reactos / ntoskrnl / cm / regfile.c
1 /* $Id$
2 *
3 * COPYRIGHT: See COPYING in the top level directory
4 * PROJECT: ReactOS kernel
5 * FILE: ntoskrnl/cm/regfile.c
6 * PURPOSE: Registry file manipulation routines
7 *
8 * PROGRAMMERS: No programmer listed.
9 */
10
11 #include <ntoskrnl.h>
12 #define NDEBUG
13 #include <internal/debug.h>
14
15 #include "cm.h"
16
17
18 /* uncomment to enable hive checks (incomplete and probably buggy) */
19 // #define HIVE_CHECK
20
21 /* LOCAL MACROS *************************************************************/
22
23 #define ABS_VALUE(V) (((V) < 0) ? -(V) : (V))
24
25 BOOLEAN CmiDoVerify = FALSE;
26
27 static ULONG
28 CmiCalcChecksum(PULONG Buffer);
29
30 /* FUNCTIONS ****************************************************************/
31
32 VOID
33 CmiCreateDefaultHiveHeader(PHIVE_HEADER Header)
34 {
35 ASSERT(Header);
36 RtlZeroMemory(Header, sizeof(HIVE_HEADER));
37 Header->BlockId = REG_HIVE_ID;
38 Header->UpdateCounter1 = 0;
39 Header->UpdateCounter2 = 0;
40 Header->DateModified.u.LowPart = 0;
41 Header->DateModified.u.HighPart = 0;
42 Header->Unused3 = 1;
43 Header->Unused4 = 3;
44 Header->Unused5 = 0;
45 Header->Unused6 = 1;
46 Header->Unused7 = 1;
47 Header->RootKeyOffset = (BLOCK_OFFSET)-1;
48 Header->BlockSize = REG_BLOCK_SIZE;
49 Header->Unused6 = 1;
50 Header->Checksum = 0;
51 }
52
53
54 VOID
55 CmiCreateDefaultBinHeader(PHBIN BinHeader)
56 {
57 ASSERT(BinHeader);
58 RtlZeroMemory(BinHeader, sizeof(HBIN));
59 BinHeader->HeaderId = REG_BIN_ID;
60 BinHeader->DateModified.u.LowPart = 0;
61 BinHeader->DateModified.u.HighPart = 0;
62 BinHeader->BinSize = REG_BLOCK_SIZE;
63 }
64
65
66 VOID
67 CmiCreateDefaultRootKeyCell(PKEY_CELL RootKeyCell)
68 {
69 ASSERT(RootKeyCell);
70 RtlZeroMemory(RootKeyCell, sizeof(KEY_CELL));
71 RootKeyCell->CellSize = -sizeof(KEY_CELL);
72 RootKeyCell->Id = REG_KEY_CELL_ID;
73 RootKeyCell->Flags = REG_KEY_ROOT_CELL | REG_KEY_NAME_PACKED;
74 KeQuerySystemTime(&RootKeyCell->LastWriteTime);
75 RootKeyCell->ParentKeyOffset = 0;
76 RootKeyCell->NumberOfSubKeys = 0;
77 RootKeyCell->HashTableOffset = -1;
78 RootKeyCell->NumberOfValues = 0;
79 RootKeyCell->ValueListOffset = -1;
80 RootKeyCell->SecurityKeyOffset = 0;
81 RootKeyCell->ClassNameOffset = -1;
82 RootKeyCell->NameSize = 0;
83 RootKeyCell->ClassSize = 0;
84 }
85
86
87 VOID
88 CmiVerifyBinHeader(PHBIN BinHeader)
89 {
90 if (CmiDoVerify)
91 {
92
93 ASSERT(BinHeader);
94
95 if (BinHeader->HeaderId != REG_BIN_ID)
96 {
97 DbgPrint("Bin header ID is %.08x (should be %.08x)\n",
98 BinHeader->HeaderId, REG_BIN_ID);
99 ASSERT(BinHeader->HeaderId == REG_BIN_ID);
100 }
101
102 //BinHeader->DateModified.dwLowDateTime
103
104 //BinHeader->DateModified.dwHighDateTime
105
106
107 if (BinHeader->BinSize != REG_BLOCK_SIZE)
108 {
109 DbgPrint("BinSize is %.08x (should be a multiple of %.08x)\n",
110 BinHeader->BinSize, REG_BLOCK_SIZE);
111 ASSERT(BinHeader->BinSize % REG_BLOCK_SIZE == 0);
112 }
113
114 }
115 }
116
117
118 VOID
119 CmiVerifyKeyCell(PKEY_CELL KeyCell)
120 {
121 if (CmiDoVerify)
122 {
123
124 ASSERT(KeyCell);
125
126 if (KeyCell->CellSize == 0)
127 {
128 DbgPrint("CellSize is %d (must not be 0)\n",
129 KeyCell->CellSize);
130 ASSERT(KeyCell->CellSize != 0);
131 }
132
133 if (KeyCell->Id != REG_KEY_CELL_ID)
134 {
135 DbgPrint("Id is %.08x (should be %.08x)\n",
136 KeyCell->Id, REG_KEY_CELL_ID);
137 ASSERT(KeyCell->Id == REG_KEY_CELL_ID);
138 }
139
140 //KeyCell->Flags;
141
142 //KeyCell->LastWriteTime;
143
144 if (KeyCell->ParentKeyOffset < 0)
145 {
146 DbgPrint("ParentKeyOffset is %d (must not be < 0)\n",
147 KeyCell->ParentKeyOffset);
148 ASSERT(KeyCell->ParentKeyOffset >= 0);
149 }
150
151 if (KeyCell->NumberOfSubKeys < 0)
152 {
153 DbgPrint("NumberOfSubKeys is %d (must not be < 0)\n",
154 KeyCell->NumberOfSubKeys);
155 ASSERT(KeyCell->NumberOfSubKeys >= 0);
156 }
157
158 //KeyCell->HashTableOffset;
159
160 if (KeyCell->NumberOfValues < 0)
161 {
162 DbgPrint("NumberOfValues is %d (must not be < 0)\n",
163 KeyCell->NumberOfValues);
164 ASSERT(KeyCell->NumberOfValues >= 0);
165 }
166
167 //KeyCell->ValuesOffset = -1;
168
169 if (KeyCell->SecurityKeyOffset < 0)
170 {
171 DbgPrint("SecurityKeyOffset is %d (must not be < 0)\n",
172 KeyCell->SecurityKeyOffset);
173 ASSERT(KeyCell->SecurityKeyOffset >= 0);
174 }
175
176 //KeyCell->ClassNameOffset = -1;
177
178 //KeyCell->NameSize
179
180 //KeyCell->ClassSize
181
182 }
183 }
184
185
186 VOID
187 CmiVerifyRootKeyCell(PKEY_CELL RootKeyCell)
188 {
189 if (CmiDoVerify)
190 {
191
192 CmiVerifyKeyCell(RootKeyCell);
193
194 if (!(RootKeyCell->Flags & REG_KEY_ROOT_CELL))
195 {
196 DbgPrint("Flags is %.08x (should be %.08x)\n",
197 RootKeyCell->Flags, REG_KEY_ROOT_CELL | REG_KEY_NAME_PACKED);
198 ASSERT(!(RootKeyCell->Flags & (REG_KEY_ROOT_CELL | REG_KEY_NAME_PACKED)));
199 }
200
201 }
202 }
203
204
205 VOID
206 CmiVerifyValueCell(PVALUE_CELL ValueCell)
207 {
208 if (CmiDoVerify)
209 {
210
211 ASSERT(ValueCell);
212
213 if (ValueCell->CellSize == 0)
214 {
215 DbgPrint("CellSize is %d (must not be 0)\n",
216 ValueCell->CellSize);
217 ASSERT(ValueCell->CellSize != 0);
218 }
219
220 if (ValueCell->Id != REG_VALUE_CELL_ID)
221 {
222 DbgPrint("Id is %.08x (should be %.08x)\n",
223 ValueCell->Id, REG_VALUE_CELL_ID);
224 ASSERT(ValueCell->Id == REG_VALUE_CELL_ID);
225 }
226
227 //ValueCell->NameSize;
228 //ValueCell->LONG DataSize;
229 //ValueCell->DataOffset;
230 //ValueCell->ULONG DataType;
231 //ValueCell->USHORT Flags;
232 //ValueCell->USHORT Unused1;
233 //ValueCell->UCHAR Name[0];
234 }
235 }
236
237
238 VOID
239 CmiVerifyValueListCell(PVALUE_LIST_CELL ValueListCell)
240 {
241 if (CmiDoVerify)
242 {
243
244 if (ValueListCell->CellSize == 0)
245 {
246 DbgPrint("CellSize is %d (must not be 0)\n",
247 ValueListCell->CellSize);
248 ASSERT(ValueListCell->CellSize != 0);
249 }
250
251 }
252 }
253
254
255 VOID
256 CmiVerifyKeyObject(PKEY_OBJECT KeyObject)
257 {
258 if (CmiDoVerify)
259 {
260
261 if (KeyObject->RegistryHive == NULL)
262 {
263 DbgPrint("RegistryHive is NULL (must not be NULL)\n",
264 KeyObject->RegistryHive);
265 ASSERT(KeyObject->RegistryHive != NULL);
266 }
267
268 if (KeyObject->KeyCell == NULL)
269 {
270 DbgPrint("KeyCell is NULL (must not be NULL)\n",
271 KeyObject->KeyCell);
272 ASSERT(KeyObject->KeyCell != NULL);
273 }
274
275 if (KeyObject->ParentKey == NULL)
276 {
277 DbgPrint("ParentKey is NULL (must not be NULL)\n",
278 KeyObject->ParentKey);
279 ASSERT(KeyObject->ParentKey != NULL);
280 }
281
282 }
283 }
284
285
286 VOID
287 CmiVerifyHiveHeader(PHIVE_HEADER Header)
288 {
289 if (CmiDoVerify)
290 {
291
292 if (Header->BlockId != REG_HIVE_ID)
293 {
294 DbgPrint("BlockId is %.08x (must be %.08x)\n",
295 Header->BlockId,
296 REG_HIVE_ID);
297 ASSERT(Header->BlockId == REG_HIVE_ID);
298 }
299
300 if (Header->Unused3 != 1)
301 {
302 DbgPrint("Unused3 is %.08x (must be 1)\n",
303 Header->Unused3);
304 ASSERT(Header->Unused3 == 1);
305 }
306
307 if (Header->Unused4 != 3)
308 {
309 DbgPrint("Unused4 is %.08x (must be 3)\n",
310 Header->Unused4);
311 ASSERT(Header->Unused4 == 3);
312 }
313
314 if (Header->Unused5 != 0)
315 {
316 DbgPrint("Unused5 is %.08x (must be 0)\n",
317 Header->Unused5);
318 ASSERT(Header->Unused5 == 0);
319 }
320
321 if (Header->Unused6 != 1)
322 {
323 DbgPrint("Unused6 is %.08x (must be 1)\n",
324 Header->Unused6);
325 ASSERT(Header->Unused6 == 1);
326 }
327
328 if (Header->Unused7 != 1)
329 {
330 DbgPrint("Unused7 is %.08x (must be 1)\n",
331 Header->Unused7);
332 ASSERT(Header->Unused7 == 1);
333 }
334
335 }
336 }
337
338
339 VOID
340 CmiVerifyRegistryHive(PREGISTRY_HIVE RegistryHive)
341 {
342 if (CmiDoVerify)
343 {
344
345 CmiVerifyHiveHeader(RegistryHive->HiveHeader);
346
347 }
348 }
349
350
351 static NTSTATUS
352 CmiCreateNewRegFile(HANDLE FileHandle)
353 {
354 IO_STATUS_BLOCK IoStatusBlock;
355 PCELL_HEADER FreeCell;
356 PHIVE_HEADER HiveHeader;
357 PKEY_CELL RootKeyCell;
358 NTSTATUS Status;
359 PHBIN BinHeader;
360 PCHAR Buffer;
361
362 Buffer = (PCHAR) ExAllocatePool(NonPagedPool, 2 * REG_BLOCK_SIZE);
363 if (Buffer == NULL)
364 return STATUS_INSUFFICIENT_RESOURCES;
365
366 RtlZeroMemory (Buffer,
367 2 * REG_BLOCK_SIZE);
368
369 HiveHeader = (PHIVE_HEADER)Buffer;
370 BinHeader = (PHBIN)((ULONG_PTR)Buffer + REG_BLOCK_SIZE);
371 RootKeyCell = (PKEY_CELL)((ULONG_PTR)Buffer + REG_BLOCK_SIZE + REG_HBIN_DATA_OFFSET);
372 FreeCell = (PCELL_HEADER)((ULONG_PTR)Buffer + REG_BLOCK_SIZE + REG_HBIN_DATA_OFFSET + sizeof(KEY_CELL));
373
374 CmiCreateDefaultHiveHeader(HiveHeader);
375 CmiCreateDefaultBinHeader(BinHeader);
376 CmiCreateDefaultRootKeyCell(RootKeyCell);
377
378 /* First block */
379 BinHeader->BinOffset = 0;
380
381 /* Offset to root key block */
382 HiveHeader->RootKeyOffset = REG_HBIN_DATA_OFFSET;
383
384 /* The rest of the block is free */
385 FreeCell->CellSize = REG_BLOCK_SIZE - (REG_HBIN_DATA_OFFSET + sizeof(KEY_CELL));
386
387 Status = ZwWriteFile(FileHandle,
388 NULL,
389 NULL,
390 NULL,
391 &IoStatusBlock,
392 Buffer,
393 2 * REG_BLOCK_SIZE,
394 0,
395 NULL);
396
397 ExFreePool(Buffer);
398
399 if (!NT_SUCCESS(Status))
400 {
401 return(Status);
402 }
403
404 Status = ZwFlushBuffersFile(FileHandle,
405 &IoStatusBlock);
406
407 return(Status);
408 }
409
410
411 #ifdef HIVE_CHECK
412 static NTSTATUS
413 CmiCheckAndFixHive(PREGISTRY_HIVE RegistryHive)
414 {
415 OBJECT_ATTRIBUTES ObjectAttributes;
416 FILE_STANDARD_INFORMATION fsi;
417 IO_STATUS_BLOCK IoStatusBlock;
418 HANDLE HiveHandle = INVALID_HANDLE_VALUE;
419 HANDLE LogHandle = INVALID_HANDLE_VALUE;
420 PHIVE_HEADER HiveHeader = NULL;
421 PHIVE_HEADER LogHeader = NULL;
422 LARGE_INTEGER FileOffset;
423 ULONG FileSize;
424 ULONG BufferSize;
425 ULONG BitmapSize;
426 RTL_BITMAP BlockBitMap;
427 NTSTATUS Status;
428
429 DPRINT("CmiCheckAndFixHive() called\n");
430
431 /* Try to open the hive file */
432 InitializeObjectAttributes(&ObjectAttributes,
433 &RegistryHive->HiveFileName,
434 OBJ_CASE_INSENSITIVE,
435 NULL,
436 NULL);
437
438 Status = ZwCreateFile(&HiveHandle,
439 FILE_READ_DATA | FILE_READ_ATTRIBUTES,
440 &ObjectAttributes,
441 &IoStatusBlock,
442 NULL,
443 FILE_ATTRIBUTE_NORMAL,
444 0,
445 FILE_OPEN,
446 FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT,
447 NULL,
448 0);
449 if (Status == STATUS_OBJECT_NAME_NOT_FOUND)
450 {
451 return(STATUS_SUCCESS);
452 }
453 if (!NT_SUCCESS(Status))
454 {
455 DPRINT("ZwCreateFile() failed (Status %lx)\n", Status);
456 return(Status);
457 }
458
459 /* Try to open the log file */
460 InitializeObjectAttributes(&ObjectAttributes,
461 &RegistryHive->LogFileName,
462 OBJ_CASE_INSENSITIVE,
463 NULL,
464 NULL);
465
466 Status = ZwCreateFile(&LogHandle,
467 FILE_READ_DATA | FILE_READ_ATTRIBUTES,
468 &ObjectAttributes,
469 &IoStatusBlock,
470 NULL,
471 FILE_ATTRIBUTE_NORMAL,
472 0,
473 FILE_OPEN,
474 FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT,
475 NULL,
476 0);
477 if (Status == STATUS_OBJECT_NAME_NOT_FOUND)
478 {
479 LogHandle = INVALID_HANDLE_VALUE;
480 }
481 else if (!NT_SUCCESS(Status))
482 {
483 DPRINT("ZwCreateFile() failed (Status %lx)\n", Status);
484 ZwClose(HiveHandle);
485 return(Status);
486 }
487
488 /* Allocate hive header */
489 HiveHeader = ExAllocatePool(PagedPool,
490 sizeof(HIVE_HEADER));
491 if (HiveHeader == NULL)
492 {
493 DPRINT("ExAllocatePool() failed\n");
494 Status = STATUS_INSUFFICIENT_RESOURCES;
495 goto ByeBye;
496 }
497
498 /* Read hive base block */
499 FileOffset.QuadPart = 0ULL;
500 Status = ZwReadFile(HiveHandle,
501 0,
502 0,
503 0,
504 &IoStatusBlock,
505 HiveHeader,
506 sizeof(HIVE_HEADER),
507 &FileOffset,
508 0);
509 if (!NT_SUCCESS(Status))
510 {
511 DPRINT("ZwReadFile() failed (Status %lx)\n", Status);
512 goto ByeBye;
513 }
514
515 if (LogHandle == INVALID_HANDLE_VALUE)
516 {
517 if (HiveHeader->Checksum != CmiCalcChecksum((PULONG)HiveHeader) ||
518 HiveHeader->UpdateCounter1 != HiveHeader->UpdateCounter2)
519 {
520 /* There is no way to fix the hive without log file - BSOD! */
521 DPRINT("Hive header inconsistent and no log file available!\n");
522 KEBUGCHECK(CONFIG_LIST_FAILED);
523 }
524
525 Status = STATUS_SUCCESS;
526 goto ByeBye;
527 }
528 else
529 {
530 /* Allocate hive header */
531 LogHeader = ExAllocatePool(PagedPool,
532 sizeof(HIVE_HEADER));
533 if (LogHeader == NULL)
534 {
535 DPRINT("ExAllocatePool() failed\n");
536 Status = STATUS_INSUFFICIENT_RESOURCES;
537 goto ByeBye;
538 }
539
540 /* Read log file header */
541 FileOffset.QuadPart = 0ULL;
542 Status = ZwReadFile(LogHandle,
543 0,
544 0,
545 0,
546 &IoStatusBlock,
547 LogHeader,
548 sizeof(HIVE_HEADER),
549 &FileOffset,
550 0);
551 if (!NT_SUCCESS(Status))
552 {
553 DPRINT("ZwReadFile() failed (Status %lx)\n", Status);
554 goto ByeBye;
555 }
556
557 /* Check log file header integrity */
558 if (LogHeader->Checksum != CmiCalcChecksum((PULONG)LogHeader) ||
559 LogHeader->UpdateCounter1 != LogHeader->UpdateCounter2)
560 {
561 if (HiveHeader->Checksum != CmiCalcChecksum((PULONG)HiveHeader) ||
562 HiveHeader->UpdateCounter1 != HiveHeader->UpdateCounter2)
563 {
564 DPRINT("Hive file and log file are inconsistent!\n");
565 KEBUGCHECK(CONFIG_LIST_FAILED);
566 }
567
568 /* Log file damaged but hive is okay */
569 Status = STATUS_SUCCESS;
570 goto ByeBye;
571 }
572
573 if (HiveHeader->UpdateCounter1 == HiveHeader->UpdateCounter2 &&
574 HiveHeader->UpdateCounter1 == LogHeader->UpdateCounter1)
575 {
576 /* Hive and log file are up-to-date */
577 Status = STATUS_SUCCESS;
578 goto ByeBye;
579 }
580
581 /*
582 * Hive needs an update!
583 */
584
585 /* Get file size */
586 Status = ZwQueryInformationFile(LogHandle,
587 &IoStatusBlock,
588 &fsi,
589 sizeof(fsi),
590 FileStandardInformation);
591 if (!NT_SUCCESS(Status))
592 {
593 DPRINT("ZwQueryInformationFile() failed (Status %lx)\n", Status);
594 goto ByeBye;
595 }
596 FileSize = fsi.EndOfFile.u.LowPart;
597
598 /* Calculate bitmap and block size */
599 BitmapSize = ROUND_UP((FileSize / REG_BLOCK_SIZE) - 1, sizeof(ULONG) * 8) / 8;
600 BufferSize = sizeof(HIVE_HEADER) +
601 sizeof(ULONG) +
602 BitmapSize;
603 BufferSize = ROUND_UP(BufferSize, REG_BLOCK_SIZE);
604
605 /* Reallocate log header block */
606 ExFreePool(LogHeader);
607 LogHeader = ExAllocatePool(PagedPool,
608 BufferSize);
609 if (LogHeader == NULL)
610 {
611 DPRINT("ExAllocatePool() failed\n");
612 Status = STATUS_INSUFFICIENT_RESOURCES;
613 goto ByeBye;
614 }
615
616 /* Read log file header */
617 FileOffset.QuadPart = 0ULL;
618 Status = ZwReadFile(LogHandle,
619 0,
620 0,
621 0,
622 &IoStatusBlock,
623 LogHeader,
624 BufferSize,
625 &FileOffset,
626 0);
627 if (!NT_SUCCESS(Status))
628 {
629 DPRINT("ZwReadFile() failed (Status %lx)\n", Status);
630 goto ByeBye;
631 }
632
633 /* Initialize bitmap */
634 RtlInitializeBitMap(&BlockBitMap,
635 (PVOID)((ULONG_PTR)LogHeader + REG_BLOCK_SIZE + sizeof(ULONG)),
636 BitmapSize * 8);
637
638 /* FIXME: Update dirty blocks */
639
640
641 /* FIXME: Update hive header */
642
643
644 Status = STATUS_SUCCESS;
645 }
646
647
648 /* Clean up the mess */
649 ByeBye:
650 if (HiveHeader != NULL)
651 ExFreePool(HiveHeader);
652
653 if (LogHeader != NULL)
654 ExFreePool(LogHeader);
655
656 if (LogHandle != INVALID_HANDLE_VALUE)
657 ZwClose(LogHandle);
658
659 ZwClose(HiveHandle);
660
661 return(Status);
662 }
663 #endif
664
665
666 NTSTATUS
667 CmiImportHiveBins(PREGISTRY_HIVE Hive,
668 PUCHAR ChunkPtr)
669 {
670 BLOCK_OFFSET BlockOffset;
671 ULONG BlockIndex;
672 PHBIN Bin;
673 ULONG j;
674
675 BlockIndex = 0;
676 BlockOffset = 0;
677 while (BlockIndex < Hive->BlockListSize)
678 {
679 Bin = (PHBIN)((ULONG_PTR)ChunkPtr + BlockOffset);
680
681 if (Bin->HeaderId != REG_BIN_ID)
682 {
683 DPRINT1 ("Bad bin header id %x, offset %x\n", Bin->HeaderId, BlockOffset);
684 return STATUS_REGISTRY_CORRUPT;
685 }
686
687 ASSERTMSG("Bin size must be multiple of 4K\n",
688 (Bin->BinSize % REG_BLOCK_SIZE) == 0);
689
690 /* Allocate the hive block */
691 Hive->BlockList[BlockIndex].Bin = ExAllocatePool (PagedPool,
692 Bin->BinSize);
693 if (Hive->BlockList[BlockIndex].Bin == NULL)
694 {
695 DPRINT1 ("ExAllocatePool() failed\n");
696 return STATUS_INSUFFICIENT_RESOURCES;
697 }
698 Hive->BlockList[BlockIndex].Block = (PVOID)Hive->BlockList[BlockIndex].Bin;
699
700 /* Import the Bin */
701 RtlCopyMemory (Hive->BlockList[BlockIndex].Bin,
702 Bin,
703 Bin->BinSize);
704
705 if (Bin->BinSize > REG_BLOCK_SIZE)
706 {
707 for (j = 1; j < Bin->BinSize / REG_BLOCK_SIZE; j++)
708 {
709 Hive->BlockList[BlockIndex + j].Bin = Hive->BlockList[BlockIndex].Bin;
710 Hive->BlockList[BlockIndex + j].Block =
711 (PVOID)((ULONG_PTR)Hive->BlockList[BlockIndex].Bin + (j * REG_BLOCK_SIZE));
712 }
713 }
714
715 BlockIndex += Bin->BinSize / REG_BLOCK_SIZE;
716 BlockOffset += Bin->BinSize;
717 }
718
719 return STATUS_SUCCESS;
720 }
721
722
723 VOID
724 CmiFreeHiveBins (PREGISTRY_HIVE Hive)
725 {
726 ULONG i;
727 PHBIN Bin;
728
729 Bin = NULL;
730 for (i = 0; i < Hive->BlockListSize; i++)
731 {
732 if (Hive->BlockList[i].Bin == NULL)
733 continue;
734
735 if (Hive->BlockList[i].Bin != Bin)
736 {
737 Bin = Hive->BlockList[i].Bin;
738 ExFreePool (Hive->BlockList[i].Bin);
739 }
740 Hive->BlockList[i].Bin = NULL;
741 Hive->BlockList[i].Block = NULL;
742 }
743 }
744
745
746 NTSTATUS
747 CmiCreateHiveFreeCellList(PREGISTRY_HIVE Hive)
748 {
749 BLOCK_OFFSET BlockOffset;
750 PCELL_HEADER FreeBlock;
751 ULONG BlockIndex;
752 ULONG FreeOffset;
753 PHBIN Bin;
754 NTSTATUS Status;
755
756 /* Initialize the free cell list */
757 Hive->FreeListSize = 0;
758 Hive->FreeListMax = 0;
759 Hive->FreeList = NULL;
760 Hive->FreeListOffset = NULL;
761
762 BlockOffset = 0;
763 BlockIndex = 0;
764 while (BlockIndex < Hive->BlockListSize)
765 {
766 Bin = Hive->BlockList[BlockIndex].Bin;
767
768 /* Search free blocks and add to list */
769 FreeOffset = REG_HBIN_DATA_OFFSET;
770 while (FreeOffset < Bin->BinSize)
771 {
772 FreeBlock = (PCELL_HEADER) ((ULONG_PTR) Bin + FreeOffset);
773 if (FreeBlock->CellSize > 0)
774 {
775 Status = CmiAddFree(Hive,
776 FreeBlock,
777 Bin->BinOffset + FreeOffset,
778 FALSE);
779
780 if (!NT_SUCCESS(Status))
781 {
782 return Status;
783 }
784
785 FreeOffset += FreeBlock->CellSize;
786 }
787 else
788 {
789 FreeOffset -= FreeBlock->CellSize;
790 }
791 }
792
793 BlockIndex += Bin->BinSize / REG_BLOCK_SIZE;
794 BlockOffset += Bin->BinSize;
795 }
796
797 return STATUS_SUCCESS;
798 }
799
800
801 VOID
802 CmiFreeHiveFreeCellList(PREGISTRY_HIVE Hive)
803 {
804 ExFreePool (Hive->FreeList);
805 ExFreePool (Hive->FreeListOffset);
806
807 Hive->FreeListSize = 0;
808 Hive->FreeListMax = 0;
809 Hive->FreeList = NULL;
810 Hive->FreeListOffset = NULL;
811 }
812
813
814 NTSTATUS
815 CmiCreateHiveBitmap(PREGISTRY_HIVE Hive)
816 {
817 ULONG BitmapSize;
818
819 /* Calculate bitmap size in bytes (always a multiple of 32 bits) */
820 BitmapSize = ROUND_UP(Hive->BlockListSize, sizeof(ULONG) * 8) / 8;
821 DPRINT("Hive->BlockListSize: %lu\n", Hive->BlockListSize);
822 DPRINT("BitmapSize: %lu Bytes %lu Bits\n", BitmapSize, BitmapSize * 8);
823
824 /* Allocate bitmap */
825 Hive->BitmapBuffer = (PULONG)ExAllocatePool(PagedPool,
826 BitmapSize);
827 if (Hive->BitmapBuffer == NULL)
828 {
829 return STATUS_INSUFFICIENT_RESOURCES;
830 }
831
832 RtlInitializeBitMap(&Hive->DirtyBitMap,
833 Hive->BitmapBuffer,
834 BitmapSize * 8);
835
836 /* Initialize bitmap */
837 RtlClearAllBits(&Hive->DirtyBitMap);
838 Hive->HiveDirty = FALSE;
839
840 return STATUS_SUCCESS;
841 }
842
843
844 static NTSTATUS
845 CmiInitNonVolatileRegistryHive (PREGISTRY_HIVE RegistryHive,
846 PWSTR Filename)
847 {
848 OBJECT_ATTRIBUTES ObjectAttributes;
849 ULONG CreateDisposition;
850 IO_STATUS_BLOCK IoSB;
851 HANDLE FileHandle;
852 PSECTION_OBJECT SectionObject;
853 PUCHAR ViewBase;
854 ULONG ViewSize;
855 NTSTATUS Status;
856
857 DPRINT("CmiInitNonVolatileRegistryHive(%p, %S) called\n",
858 RegistryHive, Filename);
859
860 /* Duplicate Filename */
861 Status = RtlCreateUnicodeString(&RegistryHive->HiveFileName,
862 Filename);
863 if (!NT_SUCCESS(Status))
864 {
865 DPRINT("RtlCreateUnicodeString() failed (Status %lx)\n", Status);
866 return(Status);
867 }
868
869 /* Create log file name */
870 RegistryHive->LogFileName.Length = (wcslen(Filename) + 4) * sizeof(WCHAR);
871 RegistryHive->LogFileName.MaximumLength = RegistryHive->LogFileName.Length + sizeof(WCHAR);
872 RegistryHive->LogFileName.Buffer = ExAllocatePoolWithTag(PagedPool,
873 RegistryHive->LogFileName.MaximumLength,
874 TAG('U', 'S', 'T', 'R'));
875 if (RegistryHive->LogFileName.Buffer == NULL)
876 {
877 RtlFreeUnicodeString(&RegistryHive->HiveFileName);
878 DPRINT("ExAllocatePool() failed\n");
879 return(STATUS_INSUFFICIENT_RESOURCES);
880 }
881 wcscpy(RegistryHive->LogFileName.Buffer,
882 Filename);
883 wcscat(RegistryHive->LogFileName.Buffer,
884 L".log");
885
886 #ifdef HIVE_CHECK
887 /* Check and eventually fix a hive */
888 Status = CmiCheckAndFixHive(RegistryHive);
889 if (!NT_SUCCESS(Status))
890 {
891 RtlFreeUnicodeString(&RegistryHive->HiveFileName);
892 RtlFreeUnicodeString(&RegistryHive->LogFileName);
893 DPRINT1("CmiCheckAndFixHive() failed (Status %lx)\n", Status);
894 return(Status);
895 }
896 #endif
897
898 InitializeObjectAttributes(&ObjectAttributes,
899 &RegistryHive->HiveFileName,
900 OBJ_CASE_INSENSITIVE,
901 NULL,
902 NULL);
903
904 CreateDisposition = FILE_OPEN_IF;
905 Status = ZwCreateFile(&FileHandle,
906 FILE_ALL_ACCESS,
907 &ObjectAttributes,
908 &IoSB,
909 NULL,
910 FILE_ATTRIBUTE_NORMAL,
911 0,
912 CreateDisposition,
913 FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT,
914 NULL,
915 0);
916 if (!NT_SUCCESS(Status))
917 {
918 RtlFreeUnicodeString(&RegistryHive->HiveFileName);
919 RtlFreeUnicodeString(&RegistryHive->LogFileName);
920 DPRINT("ZwCreateFile() failed (Status %lx)\n", Status);
921 return(Status);
922 }
923
924 if (IoSB.Information != FILE_OPENED)
925 {
926 Status = CmiCreateNewRegFile(FileHandle);
927 if (!NT_SUCCESS(Status))
928 {
929 DPRINT("CmiCreateNewRegFile() failed (Status %lx)\n", Status);
930 ZwClose(FileHandle);
931 RtlFreeUnicodeString(&RegistryHive->HiveFileName);
932 RtlFreeUnicodeString(&RegistryHive->LogFileName);
933 return(Status);
934 }
935 }
936
937 /* Create the hive section */
938 Status = MmCreateSection(&SectionObject,
939 SECTION_ALL_ACCESS,
940 NULL,
941 NULL,
942 PAGE_READWRITE,
943 SEC_COMMIT,
944 FileHandle,
945 NULL);
946 if (!NT_SUCCESS(Status))
947 {
948 DPRINT1("MmCreateSection() failed (Status %lx)\n", Status);
949 RtlFreeUnicodeString(&RegistryHive->HiveFileName);
950 RtlFreeUnicodeString(&RegistryHive->LogFileName);
951 return(Status);
952 }
953
954 /* Map the hive file */
955 ViewBase = NULL;
956 ViewSize = 0;
957 Status = MmMapViewOfSection(SectionObject,
958 PsGetCurrentProcess(),
959 (PVOID*)&ViewBase,
960 0,
961 ViewSize,
962 NULL,
963 &ViewSize,
964 0,
965 MEM_COMMIT,
966 PAGE_READWRITE);
967 if (!NT_SUCCESS(Status))
968 {
969 DPRINT1("MmMapViewOfSection() failed (Status %lx)\n", Status);
970 ObDereferenceObject(SectionObject);
971 RtlFreeUnicodeString(&RegistryHive->HiveFileName);
972 RtlFreeUnicodeString(&RegistryHive->LogFileName);
973 ZwClose(FileHandle);
974 return(Status);
975 }
976 DPRINT("ViewBase %p ViewSize %lx\n", ViewBase, ViewSize);
977
978 /* Copy hive header and initalize hive */
979 RtlCopyMemory (RegistryHive->HiveHeader,
980 ViewBase,
981 sizeof(HIVE_HEADER));
982 RegistryHive->FileSize = ViewSize;
983 RegistryHive->BlockListSize = (RegistryHive->FileSize / REG_BLOCK_SIZE) - 1;
984 RegistryHive->UpdateCounter = RegistryHive->HiveHeader->UpdateCounter1;
985
986 /* Allocate hive block list */
987 RegistryHive->BlockList = ExAllocatePool(NonPagedPool,
988 RegistryHive->BlockListSize * sizeof(BLOCK_LIST_ENTRY));
989 if (RegistryHive->BlockList == NULL)
990 {
991 DPRINT1("Failed to allocate the hive block list\n");
992 MmUnmapViewOfSection(PsGetCurrentProcess(),
993 ViewBase);
994 ObDereferenceObject(SectionObject);
995 RtlFreeUnicodeString(&RegistryHive->HiveFileName);
996 RtlFreeUnicodeString(&RegistryHive->LogFileName);
997 ZwClose(FileHandle);
998 return STATUS_INSUFFICIENT_RESOURCES;
999 }
1000 RtlZeroMemory (RegistryHive->BlockList,
1001 RegistryHive->BlockListSize * sizeof(BLOCK_LIST_ENTRY));
1002
1003 /* Import the hive bins */
1004 Status = CmiImportHiveBins (RegistryHive,
1005 ViewBase + REG_BLOCK_SIZE);
1006 if (!NT_SUCCESS(Status))
1007 {
1008 ExFreePool(RegistryHive->BlockList);
1009 MmUnmapViewOfSection(PsGetCurrentProcess(),
1010 ViewBase);
1011 ObDereferenceObject(SectionObject);
1012 RtlFreeUnicodeString(&RegistryHive->HiveFileName);
1013 RtlFreeUnicodeString(&RegistryHive->LogFileName);
1014 ZwClose(FileHandle);
1015 return Status;
1016 }
1017
1018 /* Unmap and dereference the hive section */
1019 MmUnmapViewOfSection(PsGetCurrentProcess(),
1020 ViewBase);
1021 ObDereferenceObject(SectionObject);
1022
1023 /* Close the hive file */
1024 ZwClose(FileHandle);
1025
1026 /* Initialize the free cell list */
1027 Status = CmiCreateHiveFreeCellList (RegistryHive);
1028 if (!NT_SUCCESS(Status))
1029 {
1030 CmiFreeHiveBins(RegistryHive);
1031 ExFreePool(RegistryHive->BlockList);
1032 RtlFreeUnicodeString(&RegistryHive->HiveFileName);
1033 RtlFreeUnicodeString(&RegistryHive->LogFileName);
1034 return Status;
1035 }
1036
1037 /* Create the block bitmap */
1038 Status = CmiCreateHiveBitmap (RegistryHive);
1039 if (!NT_SUCCESS(Status))
1040 {
1041 CmiFreeHiveFreeCellList(RegistryHive);
1042 CmiFreeHiveBins(RegistryHive);
1043 ExFreePool(RegistryHive->BlockList);
1044 RtlFreeUnicodeString(&RegistryHive->HiveFileName);
1045 RtlFreeUnicodeString(&RegistryHive->LogFileName);
1046 return Status;
1047 }
1048
1049 DPRINT("CmiInitNonVolatileRegistryHive(%p, %S) - Finished.\n",
1050 RegistryHive, Filename);
1051
1052 return STATUS_SUCCESS;
1053 }
1054
1055
1056 NTSTATUS
1057 CmiCreateVolatileHive(PREGISTRY_HIVE *RegistryHive)
1058 {
1059 PKEY_CELL RootKeyCell;
1060 PREGISTRY_HIVE Hive;
1061
1062 *RegistryHive = NULL;
1063
1064 Hive = ExAllocatePool (NonPagedPool,
1065 sizeof(REGISTRY_HIVE));
1066 if (Hive == NULL)
1067 return STATUS_INSUFFICIENT_RESOURCES;
1068
1069 RtlZeroMemory (Hive,
1070 sizeof(REGISTRY_HIVE));
1071
1072 DPRINT("Hive 0x%p\n", Hive);
1073
1074 Hive->HiveHeader = (PHIVE_HEADER)ExAllocatePool (NonPagedPool,
1075 sizeof(HIVE_HEADER));
1076 if (Hive->HiveHeader == NULL)
1077 {
1078 ExFreePool (Hive);
1079 return STATUS_INSUFFICIENT_RESOURCES;
1080 }
1081 RtlZeroMemory (Hive->HiveHeader,
1082 sizeof(HIVE_HEADER));
1083
1084 Hive->Flags = (HIVE_NO_FILE | HIVE_POINTER);
1085
1086 CmiCreateDefaultHiveHeader (Hive->HiveHeader);
1087
1088 RootKeyCell = (PKEY_CELL)ExAllocatePool (NonPagedPool,
1089 sizeof(KEY_CELL));
1090 if (RootKeyCell == NULL)
1091 {
1092 ExFreePool(Hive->HiveHeader);
1093 ExFreePool(Hive);
1094 return STATUS_INSUFFICIENT_RESOURCES;
1095 }
1096
1097 CmiCreateDefaultRootKeyCell (RootKeyCell);
1098 Hive->HiveHeader->RootKeyOffset = (BLOCK_OFFSET)RootKeyCell;
1099
1100 /* Acquire hive list lock exclusively */
1101 KeEnterCriticalRegion();
1102 ExAcquireResourceExclusiveLite (&CmiRegistryLock, TRUE);
1103
1104 /* Add the new hive to the hive list */
1105 InsertTailList (&CmiHiveListHead,
1106 &Hive->HiveList);
1107
1108 /* Release hive list lock */
1109 ExReleaseResourceLite (&CmiRegistryLock);
1110 KeLeaveCriticalRegion();
1111
1112 VERIFY_REGISTRY_HIVE (Hive);
1113
1114 *RegistryHive = Hive;
1115
1116 return STATUS_SUCCESS;
1117 }
1118
1119
1120 NTSTATUS
1121 CmiCreateTempHive(PREGISTRY_HIVE *RegistryHive)
1122 {
1123 PHBIN BinHeader;
1124 PCELL_HEADER FreeCell;
1125 PREGISTRY_HIVE Hive;
1126 NTSTATUS Status;
1127
1128 DPRINT ("CmiCreateTempHive() called\n");
1129
1130 *RegistryHive = NULL;
1131
1132 Hive = ExAllocatePool (NonPagedPool,
1133 sizeof(REGISTRY_HIVE));
1134 if (Hive == NULL)
1135 {
1136 DPRINT1 ("Failed to allocate registry hive block\n");
1137 return STATUS_INSUFFICIENT_RESOURCES;
1138 }
1139 RtlZeroMemory (Hive,
1140 sizeof(REGISTRY_HIVE));
1141
1142 DPRINT ("Hive 0x%p\n", Hive);
1143
1144 Hive->HiveHeader = (PHIVE_HEADER)ExAllocatePool (NonPagedPool,
1145 REG_BLOCK_SIZE);
1146 if (Hive->HiveHeader == NULL)
1147 {
1148 DPRINT1 ("Failed to allocate hive header block\n");
1149 ExFreePool (Hive);
1150 return STATUS_INSUFFICIENT_RESOURCES;
1151 }
1152 RtlZeroMemory (Hive->HiveHeader,
1153 REG_BLOCK_SIZE);
1154
1155 DPRINT ("HiveHeader 0x%p\n", Hive->HiveHeader);
1156
1157 Hive->Flags = HIVE_NO_FILE;
1158
1159 RtlInitUnicodeString (&Hive->HiveFileName,
1160 NULL);
1161 RtlInitUnicodeString (&Hive->LogFileName,
1162 NULL);
1163
1164 CmiCreateDefaultHiveHeader (Hive->HiveHeader);
1165
1166 /* Allocate hive block list */
1167 Hive->BlockList = ExAllocatePool (NonPagedPool,
1168 sizeof(PBLOCK_LIST_ENTRY));
1169 if (Hive->BlockList == NULL)
1170 {
1171 DPRINT1 ("Failed to allocate hive block list\n");
1172 ExFreePool(Hive->HiveHeader);
1173 ExFreePool(Hive);
1174 return STATUS_INSUFFICIENT_RESOURCES;
1175 }
1176
1177 /* Allocate first Bin */
1178 Hive->BlockList[0].Bin = ExAllocatePool (NonPagedPool,
1179 REG_BLOCK_SIZE);
1180 if (Hive->BlockList[0].Bin == NULL)
1181 {
1182 DPRINT1 ("Failed to allocate first bin\n");
1183 ExFreePool(Hive->BlockList);
1184 ExFreePool(Hive->HiveHeader);
1185 ExFreePool(Hive);
1186 return STATUS_INSUFFICIENT_RESOURCES;
1187 }
1188 Hive->BlockList[0].Block = (PVOID)Hive->BlockList[0].Bin;
1189
1190 Hive->FileSize = 2* REG_BLOCK_SIZE;
1191 Hive->BlockListSize = 1;
1192 Hive->UpdateCounter = Hive->HiveHeader->UpdateCounter1;
1193
1194
1195 BinHeader = Hive->BlockList[0].Bin;
1196 FreeCell = (PCELL_HEADER)((ULONG_PTR)BinHeader + REG_HBIN_DATA_OFFSET);
1197
1198 CmiCreateDefaultBinHeader (BinHeader);
1199
1200 /* First block */
1201 BinHeader->BinOffset = 0;
1202
1203 /* Offset to root key block */
1204 Hive->HiveHeader->RootKeyOffset = (BLOCK_OFFSET)-1;
1205
1206 /* The rest of the block is free */
1207 FreeCell->CellSize = REG_BLOCK_SIZE - REG_HBIN_DATA_OFFSET;
1208
1209 /* Create the free cell list */
1210 Status = CmiCreateHiveFreeCellList (Hive);
1211 if (Hive->BlockList[0].Bin == NULL)
1212 {
1213 DPRINT1 ("CmiCreateHiveFreeCellList() failed (Status %lx)\n", Status);
1214 ExFreePool(Hive->BlockList[0].Bin);
1215 ExFreePool(Hive->BlockList);
1216 ExFreePool(Hive->HiveHeader);
1217 ExFreePool(Hive);
1218 return Status;
1219 }
1220
1221 /* Acquire hive list lock exclusively */
1222 KeEnterCriticalRegion();
1223 ExAcquireResourceExclusiveLite(&CmiRegistryLock, TRUE);
1224
1225 /* Add the new hive to the hive list */
1226 InsertTailList (&CmiHiveListHead,
1227 &Hive->HiveList);
1228
1229 /* Release hive list lock */
1230 ExReleaseResourceLite(&CmiRegistryLock);
1231 KeLeaveCriticalRegion();
1232
1233 VERIFY_REGISTRY_HIVE (Hive);
1234
1235 *RegistryHive = Hive;
1236
1237 return STATUS_SUCCESS;
1238 }
1239
1240
1241 NTSTATUS
1242 CmiLoadHive(IN POBJECT_ATTRIBUTES KeyObjectAttributes,
1243 IN PUNICODE_STRING FileName,
1244 IN ULONG Flags)
1245 {
1246 PREGISTRY_HIVE Hive;
1247 NTSTATUS Status;
1248
1249 DPRINT ("CmiLoadHive(Filename %wZ)\n", FileName);
1250
1251 if (Flags & ~REG_NO_LAZY_FLUSH)
1252 return STATUS_INVALID_PARAMETER;
1253
1254 Hive = ExAllocatePool (NonPagedPool,
1255 sizeof(REGISTRY_HIVE));
1256 if (Hive == NULL)
1257 {
1258 DPRINT1 ("Failed to allocate hive header.\n");
1259 return STATUS_INSUFFICIENT_RESOURCES;
1260 }
1261 RtlZeroMemory (Hive,
1262 sizeof(REGISTRY_HIVE));
1263
1264 DPRINT ("Hive 0x%p\n", Hive);
1265 Hive->Flags = (Flags & REG_NO_LAZY_FLUSH) ? HIVE_NO_SYNCH : 0;
1266
1267 Hive->HiveHeader = (PHIVE_HEADER)ExAllocatePool(NonPagedPool,
1268 sizeof(HIVE_HEADER));
1269 if (Hive->HiveHeader == NULL)
1270 {
1271 DPRINT1 ("Failed to allocate hive header.\n");
1272 ExFreePool (Hive);
1273 return STATUS_INSUFFICIENT_RESOURCES;
1274 }
1275
1276 RtlZeroMemory (Hive->HiveHeader,
1277 sizeof(HIVE_HEADER));
1278
1279 Status = CmiInitNonVolatileRegistryHive (Hive,
1280 FileName->Buffer);
1281 if (!NT_SUCCESS (Status))
1282 {
1283 DPRINT1 ("CmiInitNonVolatileRegistryHive() failed (Status %lx)\n", Status);
1284 ExFreePool (Hive->HiveHeader);
1285 ExFreePool (Hive);
1286 return Status;
1287 }
1288
1289 /* Add the new hive to the hive list */
1290 InsertTailList (&CmiHiveListHead,
1291 &Hive->HiveList);
1292
1293 VERIFY_REGISTRY_HIVE(Hive);
1294
1295 Status = CmiConnectHive (KeyObjectAttributes,
1296 Hive);
1297 if (!NT_SUCCESS(Status))
1298 {
1299 DPRINT1 ("CmiConnectHive() failed (Status %lx)\n", Status);
1300 // CmiRemoveRegistryHive (Hive);
1301 }
1302
1303 DPRINT ("CmiLoadHive() done\n");
1304
1305 return Status;
1306 }
1307
1308
1309 NTSTATUS
1310 CmiRemoveRegistryHive(PREGISTRY_HIVE RegistryHive)
1311 {
1312 if (RegistryHive->Flags & HIVE_POINTER)
1313 return STATUS_UNSUCCESSFUL;
1314
1315 /* Remove hive from hive list */
1316 RemoveEntryList (&RegistryHive->HiveList);
1317
1318 /* Release file names */
1319 RtlFreeUnicodeString (&RegistryHive->HiveFileName);
1320 RtlFreeUnicodeString (&RegistryHive->LogFileName);
1321
1322 /* Release hive bitmap */
1323 ExFreePool (RegistryHive->BitmapBuffer);
1324
1325 /* Release free cell list */
1326 ExFreePool (RegistryHive->FreeList);
1327 ExFreePool (RegistryHive->FreeListOffset);
1328
1329 /* Release bins and bin list */
1330 CmiFreeHiveBins (RegistryHive);
1331 ExFreePool (RegistryHive->BlockList);
1332
1333 /* Release hive header */
1334 ExFreePool (RegistryHive->HiveHeader);
1335
1336 /* Release hive */
1337 ExFreePool (RegistryHive);
1338
1339 return STATUS_SUCCESS;
1340 }
1341
1342
1343 static ULONG
1344 CmiCalcChecksum(PULONG Buffer)
1345 {
1346 ULONG Sum = 0;
1347 ULONG i;
1348
1349 for (i = 0; i < 127; i++)
1350 Sum += Buffer[i];
1351
1352 return(Sum);
1353 }
1354
1355
1356 static NTSTATUS
1357 CmiStartLogUpdate(PREGISTRY_HIVE RegistryHive)
1358 {
1359 FILE_END_OF_FILE_INFORMATION EndOfFileInfo;
1360 FILE_ALLOCATION_INFORMATION FileAllocationInfo;
1361 OBJECT_ATTRIBUTES ObjectAttributes;
1362 IO_STATUS_BLOCK IoStatusBlock;
1363 HANDLE FileHandle;
1364 LARGE_INTEGER FileOffset;
1365 ULONG BufferSize;
1366 ULONG BitmapSize;
1367 PUCHAR Buffer;
1368 PUCHAR Ptr;
1369 ULONG BlockIndex;
1370 ULONG LastIndex;
1371 PVOID BlockPtr;
1372 NTSTATUS Status;
1373
1374 DPRINT("CmiStartLogUpdate() called\n");
1375
1376 BitmapSize = ROUND_UP(RegistryHive->BlockListSize, sizeof(ULONG) * 8) / 8;
1377 BufferSize = sizeof(HIVE_HEADER) +
1378 sizeof(ULONG) +
1379 BitmapSize;
1380 BufferSize = ROUND_UP(BufferSize, REG_BLOCK_SIZE);
1381
1382 DPRINT("Bitmap size %lu buffer size: %lu\n", BitmapSize, BufferSize);
1383
1384 Buffer = (PUCHAR)ExAllocatePool(NonPagedPool,
1385 BufferSize);
1386 if (Buffer == NULL)
1387 {
1388 DPRINT("ExAllocatePool() failed\n");
1389 return(STATUS_INSUFFICIENT_RESOURCES);
1390 }
1391 RtlZeroMemory (Buffer,
1392 BufferSize);
1393
1394 /* Open log file for writing */
1395 InitializeObjectAttributes(&ObjectAttributes,
1396 &RegistryHive->LogFileName,
1397 OBJ_CASE_INSENSITIVE,
1398 NULL,
1399 NULL);
1400
1401 Status = ZwCreateFile(&FileHandle,
1402 FILE_ALL_ACCESS,
1403 &ObjectAttributes,
1404 &IoStatusBlock,
1405 NULL,
1406 FILE_ATTRIBUTE_NORMAL,
1407 0,
1408 FILE_SUPERSEDE,
1409 FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT,
1410 NULL,
1411 0);
1412 if (!NT_SUCCESS(Status))
1413 {
1414 DPRINT("ZwCreateFile() failed (Status %lx)\n", Status);
1415 ExFreePool(Buffer);
1416 return(Status);
1417 }
1418
1419 /* Update firt update counter and checksum */
1420 RegistryHive->HiveHeader->UpdateCounter1 = RegistryHive->UpdateCounter + 1;
1421 RegistryHive->HiveHeader->Checksum = CmiCalcChecksum((PULONG)RegistryHive->HiveHeader);
1422
1423 /* Copy hive header */
1424 RtlCopyMemory(Buffer,
1425 RegistryHive->HiveHeader,
1426 sizeof(HIVE_HEADER));
1427 Ptr = Buffer + sizeof(HIVE_HEADER);
1428
1429 RtlCopyMemory(Ptr,
1430 "DIRT",
1431 4);
1432 Ptr += 4;
1433 RtlCopyMemory(Ptr,
1434 RegistryHive->DirtyBitMap.Buffer,
1435 BitmapSize);
1436
1437 /* Write hive block and block bitmap */
1438 FileOffset.QuadPart = (ULONGLONG)0;
1439 Status = ZwWriteFile(FileHandle,
1440 NULL,
1441 NULL,
1442 NULL,
1443 &IoStatusBlock,
1444 Buffer,
1445 BufferSize,
1446 &FileOffset,
1447 NULL);
1448 if (!NT_SUCCESS(Status))
1449 {
1450 DPRINT("ZwWriteFile() failed (Status %lx)\n", Status);
1451 ZwClose(FileHandle);
1452 ExFreePool(Buffer);
1453 return(Status);
1454 }
1455 ExFreePool(Buffer);
1456
1457 /* Write dirty blocks */
1458 FileOffset.QuadPart = (ULONGLONG)BufferSize;
1459 BlockIndex = 0;
1460 while (BlockIndex < RegistryHive->BlockListSize)
1461 {
1462 LastIndex = BlockIndex;
1463 BlockIndex = RtlFindSetBits(&RegistryHive->DirtyBitMap,
1464 1,
1465 BlockIndex);
1466 if (BlockIndex == (ULONG)-1 || BlockIndex < LastIndex)
1467 {
1468 DPRINT("No more set bits\n");
1469 Status = STATUS_SUCCESS;
1470 break;
1471 }
1472
1473 DPRINT("Block %lu is dirty\n", BlockIndex);
1474
1475 BlockPtr = RegistryHive->BlockList[BlockIndex].Block;
1476 DPRINT("BlockPtr %p\n", BlockPtr);
1477 DPRINT("File offset %I64x\n", FileOffset.QuadPart);
1478
1479 /* Write hive block */
1480 Status = ZwWriteFile(FileHandle,
1481 NULL,
1482 NULL,
1483 NULL,
1484 &IoStatusBlock,
1485 BlockPtr,
1486 REG_BLOCK_SIZE,
1487 &FileOffset,
1488 NULL);
1489 if (!NT_SUCCESS(Status))
1490 {
1491 DPRINT1("ZwWriteFile() failed (Status %lx)\n", Status);
1492 ZwClose(FileHandle);
1493 return(Status);
1494 }
1495
1496 BlockIndex++;
1497 FileOffset.QuadPart += (ULONGLONG)REG_BLOCK_SIZE;
1498 }
1499
1500 /* Truncate log file */
1501 EndOfFileInfo.EndOfFile.QuadPart = FileOffset.QuadPart;
1502 Status = ZwSetInformationFile(FileHandle,
1503 &IoStatusBlock,
1504 &EndOfFileInfo,
1505 sizeof(FILE_END_OF_FILE_INFORMATION),
1506 FileEndOfFileInformation);
1507 if (!NT_SUCCESS(Status))
1508 {
1509 DPRINT("ZwSetInformationFile() failed (Status %lx)\n", Status);
1510 ZwClose(FileHandle);
1511 return(Status);
1512 }
1513
1514 FileAllocationInfo.AllocationSize.QuadPart = FileOffset.QuadPart;
1515 Status = ZwSetInformationFile(FileHandle,
1516 &IoStatusBlock,
1517 &FileAllocationInfo,
1518 sizeof(FILE_ALLOCATION_INFORMATION),
1519 FileAllocationInformation);
1520 if (!NT_SUCCESS(Status))
1521 {
1522 DPRINT("ZwSetInformationFile() failed (Status %lx)\n", Status);
1523 ZwClose(FileHandle);
1524 return(Status);
1525 }
1526
1527 /* Flush the log file */
1528 Status = ZwFlushBuffersFile(FileHandle,
1529 &IoStatusBlock);
1530 if (!NT_SUCCESS(Status))
1531 {
1532 DPRINT("ZwFlushBuffersFile() failed (Status %lx)\n", Status);
1533 }
1534
1535 ZwClose(FileHandle);
1536
1537 return(Status);
1538 }
1539
1540
1541 static NTSTATUS
1542 CmiFinishLogUpdate(PREGISTRY_HIVE RegistryHive)
1543 {
1544 OBJECT_ATTRIBUTES ObjectAttributes;
1545 IO_STATUS_BLOCK IoStatusBlock;
1546 HANDLE FileHandle;
1547 LARGE_INTEGER FileOffset;
1548 ULONG BufferSize;
1549 ULONG BitmapSize;
1550 PUCHAR Buffer;
1551 PUCHAR Ptr;
1552 NTSTATUS Status;
1553
1554 DPRINT("CmiFinishLogUpdate() called\n");
1555
1556 BitmapSize = ROUND_UP(RegistryHive->BlockListSize, sizeof(ULONG) * 8) / 8;
1557 BufferSize = sizeof(HIVE_HEADER) +
1558 sizeof(ULONG) +
1559 BitmapSize;
1560 BufferSize = ROUND_UP(BufferSize, REG_BLOCK_SIZE);
1561
1562 DPRINT("Bitmap size %lu buffer size: %lu\n", BitmapSize, BufferSize);
1563
1564 Buffer = (PUCHAR)ExAllocatePool(NonPagedPool, BufferSize);
1565 if (Buffer == NULL)
1566 {
1567 DPRINT("ExAllocatePool() failed\n");
1568 return(STATUS_INSUFFICIENT_RESOURCES);
1569 }
1570
1571 /* Open log file for writing */
1572 InitializeObjectAttributes(&ObjectAttributes,
1573 &RegistryHive->LogFileName,
1574 OBJ_CASE_INSENSITIVE,
1575 NULL,
1576 NULL);
1577
1578 Status = ZwCreateFile(&FileHandle,
1579 FILE_ALL_ACCESS,
1580 &ObjectAttributes,
1581 &IoStatusBlock,
1582 NULL,
1583 FILE_ATTRIBUTE_NORMAL,
1584 0,
1585 FILE_OPEN,
1586 FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT,
1587 NULL,
1588 0);
1589 if (!NT_SUCCESS(Status))
1590 {
1591 DPRINT("ZwCreateFile() failed (Status %lx)\n", Status);
1592 ExFreePool(Buffer);
1593 return(Status);
1594 }
1595
1596 /* Update first and second update counter and checksum */
1597 RegistryHive->HiveHeader->UpdateCounter1 = RegistryHive->UpdateCounter + 1;
1598 RegistryHive->HiveHeader->UpdateCounter2 = RegistryHive->UpdateCounter + 1;
1599 RegistryHive->HiveHeader->Checksum = CmiCalcChecksum((PULONG)RegistryHive->HiveHeader);
1600
1601 /* Copy hive header */
1602 RtlCopyMemory(Buffer,
1603 RegistryHive->HiveHeader,
1604 sizeof(HIVE_HEADER));
1605 Ptr = Buffer + sizeof(HIVE_HEADER);
1606
1607 /* Write empty block bitmap */
1608 RtlCopyMemory(Ptr,
1609 "DIRT",
1610 4);
1611 Ptr += 4;
1612 RtlZeroMemory(Ptr,
1613 BitmapSize);
1614
1615 /* Write hive block and block bitmap */
1616 FileOffset.QuadPart = (ULONGLONG)0;
1617 Status = ZwWriteFile(FileHandle,
1618 NULL,
1619 NULL,
1620 NULL,
1621 &IoStatusBlock,
1622 Buffer,
1623 BufferSize,
1624 &FileOffset,
1625 NULL);
1626 if (!NT_SUCCESS(Status))
1627 {
1628 DPRINT("ZwWriteFile() failed (Status %lx)\n", Status);
1629 ZwClose(FileHandle);
1630 ExFreePool(Buffer);
1631 return(Status);
1632 }
1633
1634 ExFreePool(Buffer);
1635
1636 /* Flush the log file */
1637 Status = ZwFlushBuffersFile(FileHandle,
1638 &IoStatusBlock);
1639 if (!NT_SUCCESS(Status))
1640 {
1641 DPRINT("ZwFlushBuffersFile() failed (Status %lx)\n", Status);
1642 }
1643
1644 ZwClose(FileHandle);
1645
1646 return(Status);
1647 }
1648
1649
1650 static NTSTATUS
1651 CmiCleanupLogUpdate(PREGISTRY_HIVE RegistryHive)
1652 {
1653 FILE_END_OF_FILE_INFORMATION EndOfFileInfo;
1654 FILE_ALLOCATION_INFORMATION FileAllocationInfo;
1655 OBJECT_ATTRIBUTES ObjectAttributes;
1656 IO_STATUS_BLOCK IoStatusBlock;
1657 HANDLE FileHandle;
1658 ULONG BufferSize;
1659 ULONG BitmapSize;
1660 NTSTATUS Status;
1661
1662 DPRINT("CmiCleanupLogUpdate() called\n");
1663
1664 BitmapSize = ROUND_UP(RegistryHive->BlockListSize, sizeof(ULONG) * 8) / 8;
1665 BufferSize = sizeof(HIVE_HEADER) +
1666 sizeof(ULONG) +
1667 BitmapSize;
1668 BufferSize = ROUND_UP(BufferSize, REG_BLOCK_SIZE);
1669
1670 DPRINT("Bitmap size %lu buffer size: %lu\n", BitmapSize, BufferSize);
1671
1672 /* Open log file for writing */
1673 InitializeObjectAttributes(&ObjectAttributes,
1674 &RegistryHive->LogFileName,
1675 OBJ_CASE_INSENSITIVE,
1676 NULL,
1677 NULL);
1678
1679 Status = ZwCreateFile(&FileHandle,
1680 FILE_ALL_ACCESS,
1681 &ObjectAttributes,
1682 &IoStatusBlock,
1683 NULL,
1684 FILE_ATTRIBUTE_NORMAL,
1685 0,
1686 FILE_OPEN,
1687 FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT,
1688 NULL,
1689 0);
1690 if (!NT_SUCCESS(Status))
1691 {
1692 DPRINT("ZwCreateFile() failed (Status %lx)\n", Status);
1693 return(Status);
1694 }
1695
1696 /* Truncate log file */
1697 EndOfFileInfo.EndOfFile.QuadPart = (ULONGLONG)BufferSize;
1698 Status = ZwSetInformationFile(FileHandle,
1699 &IoStatusBlock,
1700 &EndOfFileInfo,
1701 sizeof(FILE_END_OF_FILE_INFORMATION),
1702 FileEndOfFileInformation);
1703 if (!NT_SUCCESS(Status))
1704 {
1705 DPRINT("ZwSetInformationFile() failed (Status %lx)\n", Status);
1706 ZwClose(FileHandle);
1707 return(Status);
1708 }
1709
1710 FileAllocationInfo.AllocationSize.QuadPart = (ULONGLONG)BufferSize;
1711 Status = ZwSetInformationFile(FileHandle,
1712 &IoStatusBlock,
1713 &FileAllocationInfo,
1714 sizeof(FILE_ALLOCATION_INFORMATION),
1715 FileAllocationInformation);
1716 if (!NT_SUCCESS(Status))
1717 {
1718 DPRINT("NtSetInformationFile() failed (Status %lx)\n", Status);
1719 ZwClose(FileHandle);
1720 return(Status);
1721 }
1722
1723 /* Flush the log file */
1724 Status = ZwFlushBuffersFile(FileHandle,
1725 &IoStatusBlock);
1726 if (!NT_SUCCESS(Status))
1727 {
1728 DPRINT("ZwFlushBuffersFile() failed (Status %lx)\n", Status);
1729 }
1730
1731 ZwClose(FileHandle);
1732
1733 return(Status);
1734 }
1735
1736
1737 static NTSTATUS
1738 CmiStartHiveUpdate(PREGISTRY_HIVE RegistryHive)
1739 {
1740 OBJECT_ATTRIBUTES ObjectAttributes;
1741 IO_STATUS_BLOCK IoStatusBlock;
1742 HANDLE FileHandle;
1743 LARGE_INTEGER FileOffset;
1744 ULONG BlockIndex;
1745 ULONG LastIndex;
1746 PVOID BlockPtr;
1747 NTSTATUS Status;
1748
1749 DPRINT("CmiStartHiveUpdate() called\n");
1750
1751 /* Open hive for writing */
1752 InitializeObjectAttributes(&ObjectAttributes,
1753 &RegistryHive->HiveFileName,
1754 OBJ_CASE_INSENSITIVE,
1755 NULL,
1756 NULL);
1757
1758 Status = ZwCreateFile(&FileHandle,
1759 FILE_ALL_ACCESS,
1760 &ObjectAttributes,
1761 &IoStatusBlock,
1762 NULL,
1763 FILE_ATTRIBUTE_NORMAL,
1764 0,
1765 FILE_OPEN,
1766 FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT,
1767 NULL,
1768 0);
1769 if (!NT_SUCCESS(Status))
1770 {
1771 DPRINT("ZwCreateFile() failed (Status %lx)\n", Status);
1772 return(Status);
1773 }
1774
1775 /* Update firt update counter and checksum */
1776 RegistryHive->HiveHeader->UpdateCounter1 = RegistryHive->UpdateCounter + 1;
1777 RegistryHive->HiveHeader->Checksum = CmiCalcChecksum((PULONG)RegistryHive->HiveHeader);
1778
1779 /* Write hive block */
1780 FileOffset.QuadPart = (ULONGLONG)0;
1781 Status = ZwWriteFile(FileHandle,
1782 NULL,
1783 NULL,
1784 NULL,
1785 &IoStatusBlock,
1786 RegistryHive->HiveHeader,
1787 sizeof(HIVE_HEADER),
1788 &FileOffset,
1789 NULL);
1790 if (!NT_SUCCESS(Status))
1791 {
1792 DPRINT("ZwWriteFile() failed (Status %lx)\n", Status);
1793 ZwClose(FileHandle);
1794 return(Status);
1795 }
1796
1797 BlockIndex = 0;
1798 while (BlockIndex < RegistryHive->BlockListSize)
1799 {
1800 LastIndex = BlockIndex;
1801 BlockIndex = RtlFindSetBits(&RegistryHive->DirtyBitMap,
1802 1,
1803 BlockIndex);
1804 if (BlockIndex == (ULONG)-1 || BlockIndex < LastIndex)
1805 {
1806 DPRINT("No more set bits\n");
1807 Status = STATUS_SUCCESS;
1808 break;
1809 }
1810
1811 DPRINT("Block %lu is dirty\n", BlockIndex);
1812
1813 BlockPtr = RegistryHive->BlockList[BlockIndex].Block;
1814 DPRINT(" BlockPtr %p\n", BlockPtr);
1815
1816 FileOffset.QuadPart = (ULONGLONG)(BlockIndex + 1) * (ULONGLONG)REG_BLOCK_SIZE;
1817 DPRINT(" File offset %I64x\n", FileOffset.QuadPart);
1818
1819 /* Write hive block */
1820 Status = ZwWriteFile(FileHandle,
1821 NULL,
1822 NULL,
1823 NULL,
1824 &IoStatusBlock,
1825 BlockPtr,
1826 REG_BLOCK_SIZE,
1827 &FileOffset,
1828 NULL);
1829 if (!NT_SUCCESS(Status))
1830 {
1831 DPRINT("ZwWriteFile() failed (Status %lx)\n", Status);
1832 ZwClose(FileHandle);
1833 return(Status);
1834 }
1835
1836 BlockIndex++;
1837 }
1838
1839 Status = ZwFlushBuffersFile(FileHandle,
1840 &IoStatusBlock);
1841 if (!NT_SUCCESS(Status))
1842 {
1843 DPRINT("ZwFlushBuffersFile() failed (Status %lx)\n", Status);
1844 }
1845
1846 ZwClose(FileHandle);
1847
1848 return(Status);
1849 }
1850
1851
1852 static NTSTATUS
1853 CmiFinishHiveUpdate(PREGISTRY_HIVE RegistryHive)
1854 {
1855 OBJECT_ATTRIBUTES ObjectAttributes;
1856 IO_STATUS_BLOCK IoStatusBlock;
1857 LARGE_INTEGER FileOffset;
1858 HANDLE FileHandle;
1859 NTSTATUS Status;
1860
1861 DPRINT("CmiFinishHiveUpdate() called\n");
1862
1863 InitializeObjectAttributes(&ObjectAttributes,
1864 &RegistryHive->HiveFileName,
1865 OBJ_CASE_INSENSITIVE,
1866 NULL,
1867 NULL);
1868
1869 Status = ZwCreateFile(&FileHandle,
1870 FILE_ALL_ACCESS,
1871 &ObjectAttributes,
1872 &IoStatusBlock,
1873 NULL,
1874 FILE_ATTRIBUTE_NORMAL,
1875 0,
1876 FILE_OPEN,
1877 FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT,
1878 NULL,
1879 0);
1880 if (!NT_SUCCESS(Status))
1881 {
1882 DPRINT("ZwCreateFile() failed (Status %lx)\n", Status);
1883 return(Status);
1884 }
1885
1886 /* Update second update counter and checksum */
1887 RegistryHive->HiveHeader->UpdateCounter1 = RegistryHive->UpdateCounter + 1;
1888 RegistryHive->HiveHeader->UpdateCounter2 = RegistryHive->UpdateCounter + 1;
1889 RegistryHive->HiveHeader->Checksum = CmiCalcChecksum((PULONG)RegistryHive->HiveHeader);
1890
1891 /* Write hive block */
1892 FileOffset.QuadPart = (ULONGLONG)0;
1893 Status = ZwWriteFile(FileHandle,
1894 NULL,
1895 NULL,
1896 NULL,
1897 &IoStatusBlock,
1898 RegistryHive->HiveHeader,
1899 sizeof(HIVE_HEADER),
1900 &FileOffset,
1901 NULL);
1902 if (!NT_SUCCESS(Status))
1903 {
1904 DPRINT("ZwWriteFile() failed (Status %lx)\n", Status);
1905 ZwClose(FileHandle);
1906 return(Status);
1907 }
1908
1909 Status = ZwFlushBuffersFile(FileHandle,
1910 &IoStatusBlock);
1911 if (!NT_SUCCESS(Status))
1912 {
1913 DPRINT("ZwFlushBuffersFile() failed (Status %lx)\n", Status);
1914 }
1915
1916 ZwClose(FileHandle);
1917
1918 return(Status);
1919 }
1920
1921
1922 NTSTATUS
1923 CmiFlushRegistryHive(PREGISTRY_HIVE RegistryHive)
1924 {
1925 NTSTATUS Status;
1926
1927 DPRINT("CmiFlushRegistryHive() called\n");
1928
1929 if (RegistryHive->HiveDirty == FALSE)
1930 {
1931 return(STATUS_SUCCESS);
1932 }
1933
1934 DPRINT("Hive '%wZ' is dirty\n",
1935 &RegistryHive->HiveFileName);
1936 DPRINT("Log file: '%wZ'\n",
1937 &RegistryHive->LogFileName);
1938
1939 /* Update hive header modification time */
1940 KeQuerySystemTime(&RegistryHive->HiveHeader->DateModified);
1941
1942 /* Start log update */
1943 Status = CmiStartLogUpdate(RegistryHive);
1944 if (!NT_SUCCESS(Status))
1945 {
1946 DPRINT("CmiStartLogUpdate() failed (Status %lx)\n", Status);
1947 return(Status);
1948 }
1949
1950 /* Finish log update */
1951 Status = CmiFinishLogUpdate(RegistryHive);
1952 if (!NT_SUCCESS(Status))
1953 {
1954 DPRINT("CmiFinishLogUpdate() failed (Status %lx)\n", Status);
1955 return(Status);
1956 }
1957
1958 /* Start hive update */
1959 Status = CmiStartHiveUpdate(RegistryHive);
1960 if (!NT_SUCCESS(Status))
1961 {
1962 DPRINT("CmiStartHiveUpdate() failed (Status %lx)\n", Status);
1963 return(Status);
1964 }
1965
1966 /* Finish the hive update */
1967 Status = CmiFinishHiveUpdate(RegistryHive);
1968 if (!NT_SUCCESS(Status))
1969 {
1970 DPRINT("CmiFinishHiveUpdate() failed (Status %lx)\n", Status);
1971 return(Status);
1972 }
1973
1974 /* Cleanup log update */
1975 Status = CmiCleanupLogUpdate(RegistryHive);
1976 if (!NT_SUCCESS(Status))
1977 {
1978 DPRINT("CmiFinishLogUpdate() failed (Status %lx)\n", Status);
1979 return(Status);
1980 }
1981
1982 /* Increment hive update counter */
1983 RegistryHive->UpdateCounter++;
1984
1985 /* Clear dirty bitmap and dirty flag */
1986 RtlClearAllBits(&RegistryHive->DirtyBitMap);
1987 RegistryHive->HiveDirty = FALSE;
1988
1989 DPRINT("CmiFlushRegistryHive() done\n");
1990
1991 return(STATUS_SUCCESS);
1992 }
1993
1994
1995 ULONG
1996 CmiGetNumberOfSubKeys(PKEY_OBJECT KeyObject)
1997 {
1998 PKEY_OBJECT CurKey;
1999 PKEY_CELL KeyCell;
2000 ULONG SubKeyCount;
2001 ULONG i;
2002
2003 VERIFY_KEY_OBJECT(KeyObject);
2004
2005 KeyCell = KeyObject->KeyCell;
2006 VERIFY_KEY_CELL(KeyCell);
2007
2008 SubKeyCount = (KeyCell == NULL) ? 0 : KeyCell->NumberOfSubKeys;
2009
2010 /* Search for volatile or 'foreign' keys */
2011 for (i = 0; i < KeyObject->NumberOfSubKeys; i++)
2012 {
2013 CurKey = KeyObject->SubKeys[i];
2014 if (CurKey->RegistryHive == CmiVolatileHive ||
2015 CurKey->RegistryHive != KeyObject->RegistryHive)
2016 {
2017 SubKeyCount++;
2018 }
2019 }
2020
2021 return SubKeyCount;
2022 }
2023
2024
2025 ULONG
2026 CmiGetMaxNameLength(PKEY_OBJECT KeyObject)
2027 {
2028 PHASH_TABLE_CELL HashBlock;
2029 PKEY_OBJECT CurKey;
2030 PKEY_CELL CurSubKeyCell;
2031 PKEY_CELL KeyCell;
2032 ULONG MaxName;
2033 ULONG NameSize;
2034 ULONG i;
2035
2036 VERIFY_KEY_OBJECT(KeyObject);
2037
2038 KeyCell = KeyObject->KeyCell;
2039 VERIFY_KEY_CELL(KeyCell);
2040
2041 MaxName = 0;
2042 HashBlock = CmiGetCell (KeyObject->RegistryHive,
2043 KeyCell->HashTableOffset,
2044 NULL);
2045 if (HashBlock == NULL)
2046 {
2047 DPRINT("CmiGetBlock() failed\n");
2048 }
2049 else
2050 {
2051 for (i = 0; i < HashBlock->HashTableSize; i++)
2052 {
2053 if (HashBlock->Table[i].KeyOffset != 0)
2054 {
2055 CurSubKeyCell = CmiGetCell (KeyObject->RegistryHive,
2056 HashBlock->Table[i].KeyOffset,
2057 NULL);
2058 if (CurSubKeyCell == NULL)
2059 {
2060 DPRINT("CmiGetBlock() failed\n");
2061 continue;
2062 }
2063
2064 NameSize = CurSubKeyCell->NameSize;
2065 if (CurSubKeyCell->Flags & REG_KEY_NAME_PACKED)
2066 {
2067 NameSize *= sizeof(WCHAR);
2068 }
2069
2070 if (NameSize > MaxName)
2071 {
2072 MaxName = NameSize;
2073 }
2074 }
2075 }
2076 }
2077
2078 DPRINT ("KeyObject->NumberOfSubKeys %d\n", KeyObject->NumberOfSubKeys);
2079 for (i = 0; i < KeyObject->NumberOfSubKeys; i++)
2080 {
2081 CurKey = KeyObject->SubKeys[i];
2082 if (CurKey->RegistryHive == CmiVolatileHive ||
2083 CurKey->RegistryHive != KeyObject->RegistryHive)
2084 {
2085 CurSubKeyCell = CurKey->KeyCell;
2086 if (CurSubKeyCell == NULL)
2087 {
2088 DPRINT("CmiGetBlock() failed\n");
2089 continue;
2090 }
2091
2092 if ((CurSubKeyCell->Flags & REG_KEY_ROOT_CELL) == REG_KEY_ROOT_CELL)
2093 {
2094 /* Use name of the key object */
2095 NameSize = CurKey->Name.Length;
2096 }
2097 else
2098 {
2099 /* Use name of the key cell */
2100 NameSize = CurSubKeyCell->NameSize;
2101 if (CurSubKeyCell->Flags & REG_KEY_NAME_PACKED)
2102 {
2103 NameSize *= sizeof(WCHAR);
2104 }
2105 }
2106 DPRINT ("NameSize %lu\n", NameSize);
2107
2108 if (NameSize > MaxName)
2109 {
2110 MaxName = NameSize;
2111 }
2112 }
2113 }
2114
2115 DPRINT ("MaxName %lu\n", MaxName);
2116
2117 return MaxName;
2118 }
2119
2120
2121 ULONG
2122 CmiGetMaxClassLength(PKEY_OBJECT KeyObject)
2123 {
2124 PHASH_TABLE_CELL HashBlock;
2125 PKEY_OBJECT CurKey;
2126 PKEY_CELL CurSubKeyCell;
2127 PKEY_CELL KeyCell;
2128 ULONG MaxClass;
2129 ULONG i;
2130
2131 VERIFY_KEY_OBJECT(KeyObject);
2132
2133 KeyCell = KeyObject->KeyCell;
2134 VERIFY_KEY_CELL(KeyCell);
2135
2136 MaxClass = 0;
2137 HashBlock = CmiGetCell (KeyObject->RegistryHive,
2138 KeyCell->HashTableOffset,
2139 NULL);
2140 if (HashBlock == NULL)
2141 {
2142 DPRINT("CmiGetBlock() failed\n");
2143 }
2144 else
2145 {
2146 for (i = 0; i < HashBlock->HashTableSize; i++)
2147 {
2148 if (HashBlock->Table[i].KeyOffset != 0)
2149 {
2150 CurSubKeyCell = CmiGetCell (KeyObject->RegistryHive,
2151 HashBlock->Table[i].KeyOffset,
2152 NULL);
2153 if (CurSubKeyCell == NULL)
2154 {
2155 DPRINT("CmiGetBlock() failed\n");
2156 continue;
2157 }
2158
2159 if (MaxClass < CurSubKeyCell->ClassSize)
2160 {
2161 MaxClass = CurSubKeyCell->ClassSize;
2162 }
2163 }
2164 }
2165 }
2166
2167 DPRINT("KeyObject->NumberOfSubKeys %d\n", KeyObject->NumberOfSubKeys);
2168 for (i = 0; i < KeyObject->NumberOfSubKeys; i++)
2169 {
2170 CurKey = KeyObject->SubKeys[i];
2171 if (CurKey->RegistryHive == CmiVolatileHive ||
2172 CurKey->RegistryHive != KeyObject->RegistryHive)
2173 {
2174 CurSubKeyCell = CurKey->KeyCell;
2175 if (CurSubKeyCell == NULL)
2176 {
2177 DPRINT("CmiGetBlock() failed\n");
2178 continue;
2179 }
2180
2181 if (MaxClass < CurSubKeyCell->ClassSize)
2182 {
2183 MaxClass = CurSubKeyCell->ClassSize;
2184 }
2185 }
2186 }
2187
2188 return MaxClass;
2189 }
2190
2191
2192 ULONG
2193 CmiGetMaxValueNameLength(PREGISTRY_HIVE RegistryHive,
2194 PKEY_CELL KeyCell)
2195 {
2196 PVALUE_LIST_CELL ValueListCell;
2197 PVALUE_CELL CurValueCell;
2198 ULONG MaxValueName;
2199 ULONG Size;
2200 ULONG i;
2201
2202 VERIFY_KEY_CELL(KeyCell);
2203
2204 MaxValueName = 0;
2205 ValueListCell = CmiGetCell (RegistryHive,
2206 KeyCell->ValueListOffset,
2207 NULL);
2208 if (ValueListCell == NULL)
2209 {
2210 DPRINT("CmiGetBlock() failed\n");
2211 return 0;
2212 }
2213
2214 for (i = 0; i < KeyCell->NumberOfValues; i++)
2215 {
2216 CurValueCell = CmiGetCell (RegistryHive,
2217 ValueListCell->ValueOffset[i],
2218 NULL);
2219 if (CurValueCell == NULL)
2220 {
2221 DPRINT("CmiGetBlock() failed\n");
2222 }
2223
2224 if (CurValueCell != NULL)
2225 {
2226 Size = CurValueCell->NameSize;
2227 if (CurValueCell->Flags & REG_VALUE_NAME_PACKED)
2228 {
2229 Size *= sizeof(WCHAR);
2230 }
2231 if (MaxValueName < Size)
2232 {
2233 MaxValueName = Size;
2234 }
2235 }
2236 }
2237
2238 return MaxValueName;
2239 }
2240
2241
2242 ULONG
2243 CmiGetMaxValueDataLength(PREGISTRY_HIVE RegistryHive,
2244 PKEY_CELL KeyCell)
2245 {
2246 PVALUE_LIST_CELL ValueListCell;
2247 PVALUE_CELL CurValueCell;
2248 LONG MaxValueData;
2249 ULONG i;
2250
2251 VERIFY_KEY_CELL(KeyCell);
2252
2253 MaxValueData = 0;
2254 ValueListCell = CmiGetCell (RegistryHive, KeyCell->ValueListOffset, NULL);
2255 if (ValueListCell == NULL)
2256 {
2257 return 0;
2258 }
2259
2260 for (i = 0; i < KeyCell->NumberOfValues; i++)
2261 {
2262 CurValueCell = CmiGetCell (RegistryHive,
2263 ValueListCell->ValueOffset[i],NULL);
2264 if ((CurValueCell != NULL) &&
2265 (MaxValueData < (LONG)(CurValueCell->DataSize & REG_DATA_SIZE_MASK)))
2266 {
2267 MaxValueData = CurValueCell->DataSize & REG_DATA_SIZE_MASK;
2268 }
2269 }
2270
2271 return MaxValueData;
2272 }
2273
2274
2275 NTSTATUS
2276 CmiScanForSubKey(IN PREGISTRY_HIVE RegistryHive,
2277 IN PKEY_CELL KeyCell,
2278 OUT PKEY_CELL *SubKeyCell,
2279 OUT BLOCK_OFFSET *BlockOffset,
2280 IN PUNICODE_STRING KeyName,
2281 IN ACCESS_MASK DesiredAccess,
2282 IN ULONG Attributes)
2283 {
2284 PHASH_TABLE_CELL HashBlock;
2285 PKEY_CELL CurSubKeyCell;
2286 ULONG i;
2287
2288 VERIFY_KEY_CELL(KeyCell);
2289
2290 DPRINT("Scanning for sub key %wZ\n", KeyName);
2291
2292 ASSERT(RegistryHive);
2293
2294 *SubKeyCell = NULL;
2295
2296 /* The key does not have any subkeys */
2297 if (KeyCell->HashTableOffset == (BLOCK_OFFSET)-1)
2298 {
2299 return STATUS_SUCCESS;
2300 }
2301
2302 /* Get hash table */
2303 HashBlock = CmiGetCell (RegistryHive, KeyCell->HashTableOffset, NULL);
2304 if (HashBlock == NULL)
2305 {
2306 DPRINT("CmiGetBlock() failed\n");
2307 return STATUS_UNSUCCESSFUL;
2308 }
2309
2310 for (i = 0; (i < KeyCell->NumberOfSubKeys) && (i < HashBlock->HashTableSize); i++)
2311 {
2312 if (Attributes & OBJ_CASE_INSENSITIVE)
2313 {
2314 if (HashBlock->Table[i].KeyOffset != 0 &&
2315 HashBlock->Table[i].KeyOffset != (ULONG_PTR)-1 &&
2316 (HashBlock->Table[i].HashValue == 0 ||
2317 CmiCompareHashI(KeyName, (PCHAR)&HashBlock->Table[i].HashValue)))
2318 {
2319 CurSubKeyCell = CmiGetCell (RegistryHive,
2320 HashBlock->Table[i].KeyOffset,
2321 NULL);
2322 if (CurSubKeyCell == NULL)
2323 {
2324 DPRINT("CmiGetBlock() failed\n");
2325 return STATUS_UNSUCCESSFUL;
2326 }
2327
2328 if (CmiCompareKeyNamesI(KeyName, CurSubKeyCell))
2329 {
2330 *SubKeyCell = CurSubKeyCell;
2331 *BlockOffset = HashBlock->Table[i].KeyOffset;
2332 break;
2333 }
2334 }
2335 }
2336 else
2337 {
2338 if (HashBlock->Table[i].KeyOffset != 0 &&
2339 HashBlock->Table[i].KeyOffset != (ULONG_PTR) -1 &&
2340 (HashBlock->Table[i].HashValue == 0 ||
2341 CmiCompareHash(KeyName, (PCHAR)&HashBlock->Table[i].HashValue)))
2342 {
2343 CurSubKeyCell = CmiGetCell (RegistryHive,
2344 HashBlock->Table[i].KeyOffset,
2345 NULL);
2346 if (CurSubKeyCell == NULL)
2347 {
2348 DPRINT("CmiGetBlock() failed\n");
2349 return STATUS_UNSUCCESSFUL;
2350 }
2351
2352 if (CmiCompareKeyNames(KeyName, CurSubKeyCell))
2353 {
2354 *SubKeyCell = CurSubKeyCell;
2355 *BlockOffset = HashBlock->Table[i].KeyOffset;
2356 break;
2357 }
2358 }
2359 }
2360 }
2361
2362 return STATUS_SUCCESS;
2363 }
2364
2365
2366 NTSTATUS
2367 CmiAddSubKey(PREGISTRY_HIVE RegistryHive,
2368 PKEY_OBJECT ParentKey,
2369 PKEY_OBJECT SubKey,
2370 PUNICODE_STRING SubKeyName,
2371 ULONG TitleIndex,
2372 PUNICODE_STRING Class,
2373 ULONG CreateOptions)
2374 {
2375 PHASH_TABLE_CELL HashBlock;
2376 BLOCK_OFFSET NKBOffset;
2377 PKEY_CELL NewKeyCell;
2378 ULONG NewBlockSize;
2379 PKEY_CELL ParentKeyCell;
2380 PDATA_CELL ClassCell;
2381 NTSTATUS Status;
2382 USHORT NameSize;
2383 PWSTR NamePtr;
2384 BOOLEAN Packable;
2385 ULONG i;
2386
2387 ParentKeyCell = ParentKey->KeyCell;
2388
2389 VERIFY_KEY_CELL(ParentKeyCell);
2390
2391 /* Skip leading backslash */
2392 if (SubKeyName->Buffer[0] == L'\\')
2393 {
2394 NamePtr = &SubKeyName->Buffer[1];
2395 NameSize = SubKeyName->Length - sizeof(WCHAR);
2396 }
2397 else
2398 {
2399 NamePtr = SubKeyName->Buffer;
2400 NameSize = SubKeyName->Length;
2401 }
2402
2403 /* Check whether key name can be packed */
2404 Packable = TRUE;
2405 for (i = 0; i < NameSize / sizeof(WCHAR); i++)
2406 {
2407 if (NamePtr[i] & 0xFF00)
2408 {
2409 Packable = FALSE;
2410 break;
2411 }
2412 }
2413
2414 /* Adjust name size */
2415 if (Packable)
2416 {
2417 NameSize = NameSize / sizeof(WCHAR);
2418 }
2419
2420 DPRINT("Key %S Length %lu %s\n", NamePtr, NameSize, (Packable)?"True":"False");
2421
2422 Status = STATUS_SUCCESS;
2423
2424 NewBlockSize = sizeof(KEY_CELL) + NameSize;
2425 Status = CmiAllocateCell (RegistryHive,
2426 NewBlockSize,
2427 (PVOID) &NewKeyCell,
2428 &NKBOffset);
2429 if (NewKeyCell == NULL)
2430 {
2431 Status = STATUS_INSUFFICIENT_RESOURCES;
2432 }
2433 else
2434 {
2435 NewKeyCell->Id = REG_KEY_CELL_ID;
2436 NewKeyCell->Flags = 0;
2437 KeQuerySystemTime(&NewKeyCell->LastWriteTime);
2438 NewKeyCell->ParentKeyOffset = -1;
2439 NewKeyCell->NumberOfSubKeys = 0;
2440 NewKeyCell->HashTableOffset = -1;
2441 NewKeyCell->NumberOfValues = 0;
2442 NewKeyCell->ValueListOffset = -1;
2443 NewKeyCell->SecurityKeyOffset = -1;
2444 NewKeyCell->ClassNameOffset = -1;
2445
2446 /* Pack the key name */
2447 NewKeyCell->NameSize = NameSize;
2448 if (Packable)
2449 {
2450 NewKeyCell->Flags |= REG_KEY_NAME_PACKED;
2451 for (i = 0; i < NameSize; i++)
2452 {
2453 NewKeyCell->Name[i] = (CHAR)(NamePtr[i] & 0x00FF);
2454 }
2455 }
2456 else
2457 {
2458 RtlCopyMemory(NewKeyCell->Name,
2459 NamePtr,
2460 NameSize);
2461 }
2462
2463 VERIFY_KEY_CELL(NewKeyCell);
2464
2465 if (Class != NULL)
2466 {
2467 NewKeyCell->ClassSize = Class->Length;
2468 Status = CmiAllocateCell (RegistryHive,
2469 sizeof(CELL_HEADER) + NewKeyCell->ClassSize,
2470 (PVOID)&ClassCell,
2471 &NewKeyCell->ClassNameOffset);
2472 RtlCopyMemory (ClassCell->Data,
2473 Class->Buffer,
2474 Class->Length);
2475 }
2476 }
2477
2478 if (!NT_SUCCESS(Status))
2479 {
2480 return Status;
2481 }
2482
2483 SubKey->KeyCell = NewKeyCell;
2484 SubKey->KeyCellOffset = NKBOffset;
2485
2486 /* Don't modify hash table if key is located in a pointer-based hive and parent key is not */
2487 if (IsPointerHive(RegistryHive) && (!IsPointerHive(ParentKey->RegistryHive)))
2488 {
2489 return(Status);
2490 }
2491
2492 if (ParentKeyCell->HashTableOffset == (ULONG_PTR) -1)
2493 {
2494 Status = CmiAllocateHashTableCell (RegistryHive,
2495 &HashBlock,
2496 &ParentKeyCell->HashTableOffset,
2497 REG_INIT_HASH_TABLE_SIZE);
2498 if (!NT_SUCCESS(Status))
2499 {
2500 return(Status);
2501 }
2502 }
2503 else
2504 {
2505 HashBlock = CmiGetCell (RegistryHive,
2506 ParentKeyCell->HashTableOffset,
2507 NULL);
2508 if (HashBlock == NULL)
2509 {
2510 DPRINT("CmiGetCell() failed\n");
2511 return STATUS_UNSUCCESSFUL;
2512 }
2513
2514 if (((ParentKeyCell->NumberOfSubKeys + 1) >= HashBlock->HashTableSize))
2515 {
2516 PHASH_TABLE_CELL NewHashBlock;
2517 BLOCK_OFFSET HTOffset;
2518
2519 /* Reallocate the hash table cell */
2520 Status = CmiAllocateHashTableCell (RegistryHive,
2521 &NewHashBlock,
2522 &HTOffset,
2523 HashBlock->HashTableSize +
2524 REG_EXTEND_HASH_TABLE_SIZE);
2525 if (!NT_SUCCESS(Status))
2526 {
2527 return Status;
2528 }
2529
2530 RtlZeroMemory(&NewHashBlock->Table[0],
2531 sizeof(NewHashBlock->Table[0]) * NewHashBlock->HashTableSize);
2532 RtlCopyMemory(&NewHashBlock->Table[0],
2533 &HashBlock->Table[0],
2534 sizeof(NewHashBlock->Table[0]) * HashBlock->HashTableSize);
2535 CmiDestroyCell (RegistryHive,
2536 HashBlock,
2537 ParentKeyCell->HashTableOffset);
2538 ParentKeyCell->HashTableOffset = HTOffset;
2539 HashBlock = NewHashBlock;
2540 }
2541 }
2542
2543 Status = CmiAddKeyToHashTable(RegistryHive,
2544 HashBlock,
2545 ParentKeyCell->HashTableOffset,
2546 NewKeyCell,
2547 NKBOffset);
2548 if (NT_SUCCESS(Status))
2549 {
2550 ParentKeyCell->NumberOfSubKeys++;
2551 }
2552
2553 KeQuerySystemTime (&ParentKeyCell->LastWriteTime);
2554 CmiMarkBlockDirty (RegistryHive, ParentKey->KeyCellOffset);
2555
2556 return(Status);
2557 }
2558
2559
2560 NTSTATUS
2561 CmiRemoveSubKey(PREGISTRY_HIVE RegistryHive,
2562 PKEY_OBJECT ParentKey,
2563 PKEY_OBJECT SubKey)
2564 {
2565 PHASH_TABLE_CELL HashBlock;
2566 PVALUE_LIST_CELL ValueList;
2567 PVALUE_CELL ValueCell;
2568 PDATA_CELL DataCell;
2569 ULONG i;
2570
2571 DPRINT("CmiRemoveSubKey() called\n");
2572
2573 /* Remove all values */
2574 if (SubKey->KeyCell->NumberOfValues != 0)
2575 {
2576 /* Get pointer to the value list cell */
2577 ValueList = CmiGetCell (RegistryHive,
2578 SubKey->KeyCell->ValueListOffset,
2579 NULL);
2580 if (ValueList == NULL)
2581 {
2582 DPRINT("CmiGetCell() failed\n");
2583 return STATUS_UNSUCCESSFUL;
2584 }
2585
2586 /* Enumerate all values */
2587 for (i = 0; i < SubKey->KeyCell->NumberOfValues; i++)
2588 {
2589 /* Get pointer to value cell */
2590 ValueCell = CmiGetCell(RegistryHive,
2591 ValueList->ValueOffset[i],
2592 NULL);
2593 if (ValueCell == NULL)
2594 {
2595 DPRINT("CmiGetCell() failed\n");
2596 return STATUS_UNSUCCESSFUL;
2597 }
2598
2599 if (!(ValueCell->DataSize & REG_DATA_IN_OFFSET)
2600 && ValueCell->DataSize > sizeof(BLOCK_OFFSET))
2601 {
2602 DataCell = CmiGetCell (RegistryHive,
2603 ValueCell->DataOffset,
2604 NULL);
2605 if (DataCell == NULL)
2606 {
2607 DPRINT("CmiGetCell() failed\n");
2608 return STATUS_UNSUCCESSFUL;
2609 }
2610
2611 if (DataCell != NULL)
2612 {
2613 /* Destroy data cell */
2614 CmiDestroyCell (RegistryHive,
2615 DataCell,
2616 ValueCell->DataOffset);
2617 }
2618 }
2619
2620 /* Destroy value cell */
2621 CmiDestroyCell (RegistryHive,
2622 ValueCell,
2623 ValueList->ValueOffset[i]);
2624 }
2625
2626 /* Destroy value list cell */
2627 CmiDestroyCell (RegistryHive,
2628 ValueList,
2629 SubKey->KeyCell->ValueListOffset);
2630
2631 SubKey->KeyCell->NumberOfValues = 0;
2632 SubKey->KeyCell->ValueListOffset = (BLOCK_OFFSET)-1;
2633
2634 CmiMarkBlockDirty(RegistryHive,
2635 SubKey->KeyCellOffset);
2636 }
2637
2638 /* Remove the key from the parent key's hash block */
2639 if (ParentKey->KeyCell->HashTableOffset != (BLOCK_OFFSET) -1)
2640 {
2641 DPRINT("ParentKey HashTableOffset %lx\n", ParentKey->KeyCell->HashTableOffset);
2642 HashBlock = CmiGetCell (ParentKey->RegistryHive,
2643 ParentKey->KeyCell->HashTableOffset,
2644 NULL);
2645 if (HashBlock == NULL)
2646 {
2647 DPRINT("CmiGetCell() failed\n");
2648 return STATUS_UNSUCCESSFUL;
2649 }
2650 DPRINT("ParentKey HashBlock %p\n", HashBlock);
2651 if (HashBlock != NULL)
2652 {
2653 CmiRemoveKeyFromHashTable(ParentKey->RegistryHive,
2654 HashBlock,
2655 SubKey->KeyCellOffset);
2656 CmiMarkBlockDirty(ParentKey->RegistryHive,
2657 ParentKey->KeyCell->HashTableOffset);
2658 }
2659 }
2660
2661 /* Remove the key's hash block */
2662 if (SubKey->KeyCell->HashTableOffset != (BLOCK_OFFSET) -1)
2663 {
2664 DPRINT("SubKey HashTableOffset %lx\n", SubKey->KeyCell->HashTableOffset);
2665 HashBlock = CmiGetCell (RegistryHive,
2666 SubKey->KeyCell->HashTableOffset,
2667 NULL);
2668 if (HashBlock == NULL)
2669 {
2670 DPRINT("CmiGetCell() failed\n");
2671 return STATUS_UNSUCCESSFUL;
2672 }
2673 DPRINT("SubKey HashBlock %p\n", HashBlock);
2674 if (HashBlock != NULL)
2675 {
2676 CmiDestroyCell (RegistryHive,
2677 HashBlock,
2678 SubKey->KeyCell->HashTableOffset);
2679 SubKey->KeyCell->HashTableOffset = -1;
2680 }
2681 }
2682
2683 /* Decrement the number of the parent key's sub keys */
2684 if (ParentKey != NULL)
2685 {
2686 DPRINT("ParentKey %p\n", ParentKey);
2687 ParentKey->KeyCell->NumberOfSubKeys--;
2688
2689 /* Remove the parent key's hash table */
2690 if (ParentKey->KeyCell->NumberOfSubKeys == 0)
2691 {
2692 DPRINT("ParentKey HashTableOffset %lx\n", ParentKey->KeyCell->HashTableOffset);
2693 HashBlock = CmiGetCell (ParentKey->RegistryHive,
2694 ParentKey->KeyCell->HashTableOffset,
2695 NULL);
2696 if (HashBlock == NULL)
2697 {
2698 DPRINT("CmiGetCell() failed\n");
2699 return STATUS_UNSUCCESSFUL;
2700 }
2701 DPRINT("ParentKey HashBlock %p\n", HashBlock);
2702 if (HashBlock != NULL)
2703 {
2704 CmiDestroyCell (ParentKey->RegistryHive,
2705 HashBlock,
2706 ParentKey->KeyCell->HashTableOffset);
2707 ParentKey->KeyCell->HashTableOffset = (BLOCK_OFFSET)-1;
2708 }
2709 }
2710
2711 KeQuerySystemTime(&ParentKey->KeyCell->LastWriteTime);
2712 CmiMarkBlockDirty(ParentKey->RegistryHive,
2713 ParentKey->KeyCellOffset);
2714 }
2715
2716 /* Destroy key cell */
2717 CmiDestroyCell (RegistryHive,
2718 SubKey->KeyCell,
2719 SubKey->KeyCellOffset);
2720 SubKey->KeyCell = NULL;
2721 SubKey->KeyCellOffset = (BLOCK_OFFSET)-1;
2722
2723 DPRINT("CmiRemoveSubKey() done\n");
2724
2725 return STATUS_SUCCESS;
2726 }
2727
2728
2729 NTSTATUS
2730 CmiScanKeyForValue(IN PREGISTRY_HIVE RegistryHive,
2731 IN PKEY_CELL KeyCell,
2732 IN PUNICODE_STRING ValueName,
2733 OUT PVALUE_CELL *ValueCell,
2734 OUT BLOCK_OFFSET *ValueCellOffset)
2735 {
2736 PVALUE_LIST_CELL ValueListCell;
2737 PVALUE_CELL CurValueCell;
2738 ULONG i;
2739
2740 *ValueCell = NULL;
2741 if (ValueCellOffset != NULL)
2742 *ValueCellOffset = (BLOCK_OFFSET)-1;
2743
2744 /* The key does not have any values */
2745 if (KeyCell->ValueListOffset == (BLOCK_OFFSET)-1)
2746 {
2747 return STATUS_OBJECT_NAME_NOT_FOUND;
2748 }
2749
2750 ValueListCell = CmiGetCell (RegistryHive, KeyCell->ValueListOffset, NULL);
2751 if (ValueListCell == NULL)
2752 {
2753 DPRINT("ValueListCell is NULL\n");
2754 return STATUS_UNSUCCESSFUL;
2755 }
2756
2757 VERIFY_VALUE_LIST_CELL(ValueListCell);
2758
2759 for (i = 0; i < KeyCell->NumberOfValues; i++)
2760 {
2761 CurValueCell = CmiGetCell (RegistryHive,
2762 ValueListCell->ValueOffset[i],
2763 NULL);
2764 if (CurValueCell == NULL)
2765 {
2766 DPRINT("CmiGetBlock() failed\n");
2767 return STATUS_UNSUCCESSFUL;
2768 }
2769
2770 if ((CurValueCell != NULL) &&
2771 CmiComparePackedNames(ValueName,
2772 CurValueCell->Name,
2773 CurValueCell->NameSize,
2774 (BOOLEAN)((CurValueCell->Flags & REG_VALUE_NAME_PACKED) ? TRUE : FALSE)))
2775 {
2776 *ValueCell = CurValueCell;
2777 if (ValueCellOffset != NULL)
2778 *ValueCellOffset = ValueListCell->ValueOffset[i];
2779 //DPRINT("Found value %s\n", ValueName);
2780 return STATUS_SUCCESS;
2781 }
2782 }
2783
2784 return STATUS_OBJECT_NAME_NOT_FOUND;
2785 }
2786
2787
2788 NTSTATUS
2789 CmiGetValueFromKeyByIndex(IN PREGISTRY_HIVE RegistryHive,
2790 IN PKEY_CELL KeyCell,
2791 IN ULONG Index,
2792 OUT PVALUE_CELL *ValueCell)
2793 {
2794 PVALUE_LIST_CELL ValueListCell;
2795 PVALUE_CELL CurValueCell;
2796
2797 *ValueCell = NULL;
2798
2799 if (KeyCell->ValueListOffset == (BLOCK_OFFSET)-1)
2800 {
2801 return STATUS_NO_MORE_ENTRIES;
2802 }
2803
2804 if (Index >= KeyCell->NumberOfValues)
2805 {
2806 return STATUS_NO_MORE_ENTRIES;
2807 }
2808
2809
2810 ValueListCell = CmiGetCell (RegistryHive, KeyCell->ValueListOffset, NULL);
2811 if (ValueListCell == NULL)
2812 {
2813 DPRINT("CmiGetBlock() failed\n");
2814 return STATUS_UNSUCCESSFUL;
2815 }
2816
2817 VERIFY_VALUE_LIST_CELL(ValueListCell);
2818
2819
2820 CurValueCell = CmiGetCell (RegistryHive,
2821 ValueListCell->ValueOffset[Index],
2822 NULL);
2823 if (CurValueCell == NULL)
2824 {
2825 DPRINT("CmiGetBlock() failed\n");
2826 return STATUS_UNSUCCESSFUL;
2827 }
2828
2829 *ValueCell = CurValueCell;
2830
2831 return STATUS_SUCCESS;
2832 }
2833
2834
2835 NTSTATUS
2836 CmiAddValueToKey(IN PREGISTRY_HIVE RegistryHive,
2837 IN PKEY_CELL KeyCell,
2838 IN BLOCK_OFFSET KeyCellOffset,
2839 IN PUNICODE_STRING ValueName,
2840 OUT PVALUE_CELL *pValueCell,
2841 OUT BLOCK_OFFSET *pValueCellOffset)
2842 {
2843 PVALUE_LIST_CELL NewValueListCell;
2844 PVALUE_LIST_CELL ValueListCell;
2845 PVALUE_CELL NewValueCell;
2846 BLOCK_OFFSET NewValueListCellOffset;
2847 BLOCK_OFFSET ValueListCellOffset;
2848 BLOCK_OFFSET NewValueCellOffset;
2849 ULONG CellSize;
2850 NTSTATUS Status;
2851
2852 DPRINT("KeyCell->ValuesOffset %lu\n", (ULONG)KeyCell->ValueListOffset);
2853
2854 ValueListCell = CmiGetCell (RegistryHive, KeyCell->ValueListOffset, NULL);
2855 if (ValueListCell == NULL)
2856 {
2857 CellSize = sizeof(VALUE_LIST_CELL) +
2858 (3 * sizeof(BLOCK_OFFSET));
2859 Status = CmiAllocateCell (RegistryHive,
2860 CellSize,
2861 (PVOID) &ValueListCell,
2862 &ValueListCellOffset);
2863 if (!NT_SUCCESS(Status))
2864 {
2865 return Status;
2866 }
2867
2868 KeyCell->ValueListOffset = ValueListCellOffset;
2869 CmiMarkBlockDirty(RegistryHive, KeyCellOffset);
2870 CmiMarkBlockDirty(RegistryHive, ValueListCellOffset);
2871 }
2872 else if (KeyCell->NumberOfValues >=
2873 (((ULONG)ABS_VALUE(ValueListCell->CellSize) - sizeof(VALUE_LIST_CELL)) / sizeof(BLOCK_OFFSET)))
2874 {
2875 #if 0
2876 CellSize = sizeof(VALUE_LIST_CELL) +
2877 ((KeyCell->NumberOfValues + REG_VALUE_LIST_CELL_MULTIPLE) * sizeof(BLOCK_OFFSET));
2878 #endif
2879 CellSize = 2 * (ULONG)ABS_VALUE(ValueListCell->CellSize);
2880 Status = CmiAllocateCell (RegistryHive,
2881 CellSize,
2882 (PVOID) &NewValueListCell,
2883 &NewValueListCellOffset);
2884 if (!NT_SUCCESS(Status))
2885 {
2886 return Status;
2887 }
2888
2889 RtlCopyMemory(&NewValueListCell->ValueOffset[0],
2890 &ValueListCell->ValueOffset[0],
2891 sizeof(BLOCK_OFFSET) * KeyCell->NumberOfValues);
2892 CmiDestroyCell (RegistryHive, ValueListCell, KeyCell->ValueListOffset);
2893 CmiMarkBlockDirty (RegistryHive, KeyCell->ValueListOffset);
2894
2895 KeyCell->ValueListOffset = NewValueListCellOffset;
2896 ValueListCell = NewValueListCell;
2897 CmiMarkBlockDirty (RegistryHive, KeyCellOffset);
2898 CmiMarkBlockDirty (RegistryHive, NewValueListCellOffset);
2899 }
2900
2901 DPRINT("KeyCell->NumberOfValues %lu, ValueListCell->CellSize %lu (%lu %lx)\n",
2902 KeyCell->NumberOfValues,
2903 (ULONG)ABS_VALUE(ValueListCell->CellSize),
2904 ((ULONG)ABS_VALUE(ValueListCell->CellSize) - sizeof(VALUE_LIST_CELL)) / sizeof(BLOCK_OFFSET),
2905 ((ULONG)ABS_VALUE(ValueListCell->CellSize) - sizeof(VALUE_LIST_CELL)) / sizeof(BLOCK_OFFSET));
2906
2907 Status = CmiAllocateValueCell(RegistryHive,
2908 &NewValueCell,
2909 &NewValueCellOffset,
2910 ValueName);
2911 if (!NT_SUCCESS(Status))
2912 {
2913 return Status;
2914 }
2915
2916 ValueListCell->ValueOffset[KeyCell->NumberOfValues] = NewValueCellOffset;
2917 KeyCell->NumberOfValues++;
2918
2919 CmiMarkBlockDirty(RegistryHive, KeyCellOffset);
2920 CmiMarkBlockDirty(RegistryHive, KeyCell->ValueListOffset);
2921 CmiMarkBlockDirty(RegistryHive, NewValueCellOffset);
2922
2923 *pValueCell = NewValueCell;
2924 *pValueCellOffset = NewValueCellOffset;
2925
2926 return STATUS_SUCCESS;
2927 }
2928
2929
2930 NTSTATUS
2931 CmiDeleteValueFromKey(IN PREGISTRY_HIVE RegistryHive,
2932 IN PKEY_CELL KeyCell,
2933 IN BLOCK_OFFSET KeyCellOffset,
2934 IN PUNICODE_STRING ValueName)
2935 {
2936 PVALUE_LIST_CELL ValueListCell;
2937 PVALUE_CELL CurValueCell;
2938 ULONG i;
2939 NTSTATUS Status;
2940
2941 ValueListCell = CmiGetCell (RegistryHive, KeyCell->ValueListOffset, NULL);
2942 if (ValueListCell == NULL)
2943 {
2944 DPRINT1("CmiGetBlock() failed\n");
2945 return STATUS_SUCCESS;
2946 }
2947
2948 VERIFY_VALUE_LIST_CELL(ValueListCell);
2949
2950 for (i = 0; i < KeyCell->NumberOfValues; i++)
2951 {
2952 CurValueCell = CmiGetCell (RegistryHive, ValueListCell->ValueOffset[i], NULL);
2953 if (CurValueCell == NULL)
2954 {
2955 DPRINT1("CmiGetBlock() failed\n");
2956 return STATUS_UNSUCCESSFUL;
2957 }
2958
2959 if (CmiComparePackedNames(ValueName,
2960 CurValueCell->Name,
2961 CurValueCell->NameSize,
2962 (BOOLEAN)((CurValueCell->Flags & REG_VALUE_NAME_PACKED) ? TRUE : FALSE)))
2963 {
2964 Status = CmiDestroyValueCell(RegistryHive,
2965 CurValueCell,
2966 ValueListCell->ValueOffset[i]);
2967 if (CurValueCell == NULL)
2968 {
2969 DPRINT1("CmiDestroyValueCell() failed\n");
2970 return Status;
2971 }
2972
2973 if (i < (KeyCell->NumberOfValues - 1))
2974 {
2975 RtlMoveMemory(&ValueListCell->ValueOffset[i],
2976 &ValueListCell->ValueOffset[i + 1],
2977 sizeof(BLOCK_OFFSET) * (KeyCell->NumberOfValues - 1 - i));
2978 }
2979 ValueListCell->ValueOffset[KeyCell->NumberOfValues - 1] = 0;
2980
2981
2982 KeyCell->NumberOfValues--;
2983
2984 if (KeyCell->NumberOfValues == 0)
2985 {
2986 CmiDestroyCell(RegistryHive,
2987 ValueListCell,
2988 KeyCell->ValueListOffset);
2989 KeyCell->ValueListOffset = -1;
2990 }
2991 else
2992 {
2993 CmiMarkBlockDirty(RegistryHive,
2994 KeyCell->ValueListOffset);
2995 }
2996
2997 CmiMarkBlockDirty(RegistryHive,
2998 KeyCellOffset);
2999
3000 return STATUS_SUCCESS;
3001 }
3002 }
3003
3004 DPRINT("Couldn't find the desired value\n");
3005
3006 return STATUS_OBJECT_NAME_NOT_FOUND;
3007 }
3008
3009
3010 NTSTATUS
3011 CmiAllocateHashTableCell (IN PREGISTRY_HIVE RegistryHive,
3012 OUT PHASH_TABLE_CELL *HashBlock,
3013 OUT BLOCK_OFFSET *HBOffset,
3014 IN ULONG SubKeyCount)
3015 {
3016 PHASH_TABLE_CELL NewHashBlock;
3017 ULONG NewHashSize;
3018 NTSTATUS Status;
3019
3020 Status = STATUS_SUCCESS;
3021 *HashBlock = NULL;
3022 NewHashSize = sizeof(HASH_TABLE_CELL) +
3023 (SubKeyCount * sizeof(HASH_RECORD));
3024 Status = CmiAllocateCell (RegistryHive,
3025 NewHashSize,
3026 (PVOID*) &NewHashBlock,
3027 HBOffset);
3028
3029 if ((NewHashBlock == NULL) || (!NT_SUCCESS(Status)))
3030 {
3031 Status = STATUS_INSUFFICIENT_RESOURCES;
3032 }
3033 else
3034 {
3035 ASSERT(SubKeyCount <= 0xffff); /* should really be USHORT_MAX or similar */
3036 NewHashBlock->Id = REG_HASH_TABLE_CELL_ID;
3037 NewHashBlock->HashTableSize = (USHORT)SubKeyCount;
3038 *HashBlock = NewHashBlock;
3039 }
3040
3041 return Status;
3042 }
3043
3044
3045 PKEY_CELL
3046 CmiGetKeyFromHashByIndex(PREGISTRY_HIVE RegistryHive,
3047 PHASH_TABLE_CELL HashBlock,
3048 ULONG Index)
3049 {
3050 BLOCK_OFFSET KeyOffset;
3051 PKEY_CELL KeyCell;
3052
3053 if (HashBlock == NULL)
3054 return NULL;
3055
3056 if (IsPointerHive(RegistryHive))
3057 {
3058 KeyCell = (PKEY_CELL) HashBlock->Table[Index].KeyOffset;
3059 }
3060 else
3061 {
3062 KeyOffset = HashBlock->Table[Index].KeyOffset;
3063 KeyCell = CmiGetCell (RegistryHive, KeyOffset, NULL);
3064 }
3065
3066 return KeyCell;
3067 }
3068
3069
3070 NTSTATUS
3071 CmiAddKeyToHashTable(PREGISTRY_HIVE RegistryHive,
3072 PHASH_TABLE_CELL HashCell,
3073 BLOCK_OFFSET HashCellOffset,
3074 PKEY_CELL NewKeyCell,
3075 BLOCK_OFFSET NKBOffset)
3076 {
3077 ULONG i;
3078
3079 for (i = 0; i < HashCell->HashTableSize; i++)
3080 {
3081 if (HashCell->Table[i].KeyOffset == 0)
3082 {
3083 HashCell->Table[i].KeyOffset = NKBOffset;
3084 HashCell->Table[i].HashValue = 0;
3085 if (NewKeyCell->Flags & REG_KEY_NAME_PACKED)
3086 {
3087 RtlCopyMemory(&HashCell->Table[i].HashValue,
3088 NewKeyCell->Name,
3089 min(NewKeyCell->NameSize, sizeof(ULONG)));
3090 }
3091 CmiMarkBlockDirty(RegistryHive, HashCellOffset);
3092 return STATUS_SUCCESS;
3093 }
3094 }
3095
3096 return STATUS_UNSUCCESSFUL;
3097 }
3098
3099
3100 NTSTATUS
3101 CmiRemoveKeyFromHashTable(PREGISTRY_HIVE RegistryHive,
3102 PHASH_TABLE_CELL HashBlock,
3103 BLOCK_OFFSET NKBOffset)
3104 {
3105 ULONG i;
3106
3107 for (i = 0; i < HashBlock->HashTableSize; i++)
3108 {
3109 if (HashBlock->Table[i].KeyOffset == NKBOffset)
3110 {
3111 HashBlock->Table[i].KeyOffset = 0;
3112 HashBlock->Table[i].HashValue = 0;
3113 return STATUS_SUCCESS;
3114 }
3115 }
3116
3117 return STATUS_UNSUCCESSFUL;
3118 }
3119
3120
3121 NTSTATUS
3122 CmiAllocateValueCell(PREGISTRY_HIVE RegistryHive,
3123 PVALUE_CELL *ValueCell,
3124 BLOCK_OFFSET *VBOffset,
3125 IN PUNICODE_STRING ValueName)
3126 {
3127 PVALUE_CELL NewValueCell;
3128 NTSTATUS Status;
3129 BOOLEAN Packable;
3130 ULONG NameSize;
3131 ULONG i;
3132
3133 Status = STATUS_SUCCESS;
3134
3135 NameSize = CmiGetPackedNameLength(ValueName,
3136 &Packable);
3137
3138 DPRINT("ValueName->Length %lu NameSize %lu\n", ValueName->Length, NameSize);
3139
3140 Status = CmiAllocateCell (RegistryHive,
3141 sizeof(VALUE_CELL) + NameSize,
3142 (PVOID*) &NewValueCell,
3143 VBOffset);
3144 if ((NewValueCell == NULL) || (!NT_SUCCESS(Status)))
3145 {
3146 Status = STATUS_INSUFFICIENT_RESOURCES;
3147 }
3148 else
3149 {
3150 ASSERT(NameSize <= 0xffff); /* should really be USHORT_MAX or similar */
3151 NewValueCell->Id = REG_VALUE_CELL_ID;
3152 NewValueCell->NameSize = (USHORT)NameSize;
3153 if (Packable)
3154 {
3155 /* Pack the value name */
3156 for (i = 0; i < NameSize; i++)
3157 NewValueCell->Name[i] = (CHAR)ValueName->Buffer[i];
3158 NewValueCell->Flags |= REG_VALUE_NAME_PACKED;
3159 }
3160 else
3161 {
3162 /* Copy the value name */
3163 RtlCopyMemory(NewValueCell->Name,
3164 ValueName->Buffer,
3165 NameSize);
3166 NewValueCell->Flags = 0;
3167 }
3168 NewValueCell->DataType = 0;
3169 NewValueCell->DataSize = 0;
3170 NewValueCell->DataOffset = (BLOCK_OFFSET)-1;
3171 *ValueCell = NewValueCell;
3172 }
3173
3174 return Status;
3175 }
3176
3177
3178 NTSTATUS
3179 CmiDestroyValueCell(PREGISTRY_HIVE RegistryHive,
3180 PVALUE_CELL ValueCell,
3181 BLOCK_OFFSET ValueCellOffset)
3182 {
3183 NTSTATUS Status;
3184 PVOID DataCell;
3185 PHBIN Bin;
3186
3187 DPRINT("CmiDestroyValueCell(Cell %p Offset %lx)\n",
3188 ValueCell, ValueCellOffset);
3189
3190 VERIFY_VALUE_CELL(ValueCell);
3191
3192 /* Destroy the data cell */
3193 if (!(ValueCell->DataSize & REG_DATA_IN_OFFSET)
3194 && ValueCell->DataSize > sizeof(BLOCK_OFFSET))
3195 {
3196 DataCell = CmiGetCell (RegistryHive, ValueCell->DataOffset, &Bin);
3197 if (DataCell == NULL)
3198 {
3199 DPRINT("CmiGetCell() failed\n");
3200 return STATUS_UNSUCCESSFUL;
3201 }
3202
3203 Status = CmiDestroyCell (RegistryHive, DataCell, ValueCell->DataOffset);
3204 if (!NT_SUCCESS(Status))
3205 {
3206 return Status;
3207 }
3208
3209 /* Update time of heap */
3210 if (!IsNoFileHive(RegistryHive))
3211 KeQuerySystemTime(&Bin->DateModified);
3212 }
3213
3214 /* Destroy the value cell */
3215 Status = CmiDestroyCell (RegistryHive, ValueCell, ValueCellOffset);
3216
3217 /* Update time of heap */
3218 if (!IsNoFileHive(RegistryHive) && CmiGetCell (RegistryHive, ValueCellOffset, &Bin))
3219 {
3220 KeQuerySystemTime(&Bin->DateModified);
3221 }
3222
3223 return Status;
3224 }
3225
3226
3227 NTSTATUS
3228 CmiAddBin(PREGISTRY_HIVE RegistryHive,
3229 ULONG BlockCount,
3230 PVOID *NewBlock,
3231 BLOCK_OFFSET *NewBlockOffset)
3232 {
3233 PBLOCK_LIST_ENTRY BlockList;
3234 PCELL_HEADER tmpBlock;
3235 PHBIN tmpBin;
3236 ULONG BinSize;
3237 ULONG i;
3238 ULONG BitmapSize;
3239
3240 DPRINT ("CmiAddBin (BlockCount %lu)\n", BlockCount);
3241
3242 BinSize = BlockCount * REG_BLOCK_SIZE;
3243 tmpBin = ExAllocatePool(PagedPool, BinSize);
3244 if (tmpBin == NULL)
3245 {
3246 return STATUS_INSUFFICIENT_RESOURCES;
3247 }
3248 RtlZeroMemory (tmpBin,
3249 BinSize);
3250
3251 tmpBin->HeaderId = REG_BIN_ID;
3252 tmpBin->BinOffset = RegistryHive->FileSize - REG_BLOCK_SIZE;
3253 RegistryHive->FileSize += BinSize;
3254 tmpBin->BinSize = BinSize;
3255 tmpBin->Unused1 = 0;
3256 KeQuerySystemTime(&tmpBin->DateModified);
3257 tmpBin->Unused2 = 0;
3258
3259 DPRINT (" BinOffset %lx BinSize %lx\n", tmpBin->BinOffset,tmpBin->BinSize);
3260
3261 /* Allocate new block list */
3262 BlockList = ExAllocatePool(NonPagedPool,
3263 sizeof(BLOCK_LIST_ENTRY) * (RegistryHive->BlockListSize + BlockCount));
3264 if (BlockList == NULL)
3265 {
3266 ExFreePool(tmpBin);
3267 return STATUS_INSUFFICIENT_RESOURCES;
3268 }
3269
3270 if (RegistryHive->BlockListSize > 0)
3271 {
3272 RtlCopyMemory (BlockList,
3273 RegistryHive->BlockList,
3274 sizeof(BLOCK_LIST_ENTRY) * RegistryHive->BlockListSize);
3275 ExFreePool(RegistryHive->BlockList);
3276 }
3277
3278 RegistryHive->BlockList = BlockList;
3279 for (i = 0; i < BlockCount; i++)
3280 {
3281 RegistryHive->BlockList[RegistryHive->BlockListSize + i].Block =
3282 (PVOID)((ULONG_PTR)tmpBin + (i * REG_BLOCK_SIZE));
3283 RegistryHive->BlockList[RegistryHive->BlockListSize + i].Bin = tmpBin;
3284 }
3285 RegistryHive->BlockListSize += BlockCount;
3286
3287 /* Initialize a free block in this heap : */
3288 tmpBlock = (PCELL_HEADER)((ULONG_PTR) tmpBin + REG_HBIN_DATA_OFFSET);
3289 tmpBlock->CellSize = (BinSize - REG_HBIN_DATA_OFFSET);
3290
3291 /* Calculate bitmap size in bytes (always a multiple of 32 bits) */
3292 BitmapSize = ROUND_UP(RegistryHive->BlockListSize, sizeof(ULONG) * 8) / 8;
3293
3294 /* Grow bitmap if necessary */
3295 if (!IsNoFileHive(RegistryHive) &&
3296 BitmapSize > RegistryHive->DirtyBitMap.SizeOfBitMap / 8)
3297 {
3298 PULONG BitmapBuffer;
3299
3300 DPRINT("Grow hive bitmap\n");
3301
3302 DPRINT("RegistryHive->BlockListSize: %lu\n", RegistryHive->BlockListSize);
3303 DPRINT("BitmapSize: %lu Bytes %lu Bits\n", BitmapSize, BitmapSize * 8);
3304 BitmapBuffer = (PULONG)ExAllocatePool(PagedPool,
3305 BitmapSize);
3306 RtlZeroMemory(BitmapBuffer, BitmapSize);
3307 RtlCopyMemory(BitmapBuffer,
3308 RegistryHive->DirtyBitMap.Buffer,
3309 RegistryHive->DirtyBitMap.SizeOfBitMap / 8);
3310 ExFreePool(RegistryHive->BitmapBuffer);
3311 RegistryHive->BitmapBuffer = BitmapBuffer;
3312 RtlInitializeBitMap(&RegistryHive->DirtyBitMap,
3313 RegistryHive->BitmapBuffer,
3314 BitmapSize * 8);
3315 }
3316
3317 *NewBlock = (PVOID) tmpBlock;
3318
3319 if (NewBlockOffset)
3320 *NewBlockOffset = tmpBin->BinOffset + REG_HBIN_DATA_OFFSET;
3321
3322 /* Mark new bin dirty */
3323 CmiMarkBinDirty(RegistryHive,
3324 tmpBin->BinOffset);
3325
3326 return STATUS_SUCCESS;
3327 }
3328
3329
3330 NTSTATUS
3331 CmiAllocateCell (PREGISTRY_HIVE RegistryHive,
3332 LONG CellSize,
3333 PVOID *Cell,
3334 BLOCK_OFFSET *CellOffset)
3335 {
3336 PCELL_HEADER NewCell;
3337 PHBIN Bin;
3338 ULONG i;
3339 PVOID Temp;
3340 NTSTATUS Status;
3341
3342 /* Round to 16 bytes multiple */
3343 CellSize = ROUND_UP(CellSize, 16);
3344
3345 /* Handle volatile hives first */
3346 if (IsPointerHive(RegistryHive))
3347 {
3348 NewCell = ExAllocatePool(NonPagedPool, CellSize);
3349 if (NewCell == NULL)
3350 {
3351 return STATUS_INSUFFICIENT_RESOURCES;
3352 }
3353
3354 RtlZeroMemory (NewCell,
3355 CellSize);
3356 NewCell->CellSize = -CellSize;
3357
3358 *Cell = NewCell;
3359 if (CellOffset != NULL)
3360 *CellOffset = (BLOCK_OFFSET) NewCell;
3361 }
3362 else
3363 {
3364 /* first search in free blocks */
3365 NewCell = NULL;
3366 for (i = 0; i < RegistryHive->FreeListSize; i++)
3367 {
3368 if (RegistryHive->FreeList[i]->CellSize >= CellSize)
3369 {
3370 NewCell = RegistryHive->FreeList[i];
3371 if (CellOffset != NULL)
3372 *CellOffset = RegistryHive->FreeListOffset[i];
3373
3374 /* Update time of heap */
3375 Temp = CmiGetCell (RegistryHive,
3376 RegistryHive->FreeListOffset[i],
3377 &Bin);
3378 if (</