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 (Temp == NULL)
3379 {
3380 DPRINT("CmiGetBlock() failed\n");
3381 return STATUS_UNSUCCESSFUL;
3382 }
3383
3384 KeQuerySystemTime(&Bin->DateModified);
3385 CmiMarkBlockDirty(RegistryHive, RegistryHive->FreeListOffset[i]);
3386
3387 if ((i + 1) < RegistryHive->FreeListSize)
3388 {
3389 RtlMoveMemory(&RegistryHive->FreeList[i],
3390 &RegistryHive->FreeList[i + 1],
3391 sizeof(RegistryHive->FreeList[0])
3392 * (RegistryHive->FreeListSize - i - 1));
3393 RtlMoveMemory(&RegistryHive->FreeListOffset[i],
3394 &RegistryHive->FreeListOffset[i + 1],
3395 sizeof(RegistryHive->FreeListOffset[0])
3396 * (RegistryHive->FreeListSize - i - 1));
3397 }
3398 RegistryHive->FreeListSize--;
3399 break;
3400 }
3401 }
3402
3403 /* Need to extend hive file : */
3404 if (NewCell == NULL)
3405 {
3406 /* Add a new bin */
3407 Status = CmiAddBin(RegistryHive,
3408 ((CellSize + sizeof(HBIN) - 1) / REG_BLOCK_SIZE) + 1,
3409 (PVOID *)&NewCell,
3410 CellOffset);
3411 if (!NT_SUCCESS(Status))
3412 return Status;
3413 }
3414
3415 *Cell = NewCell;
3416
3417 /* Split the block in two parts */
3418 if (NewCell->CellSize > CellSize)
3419 {
3420 NewCell = (PCELL_HEADER) ((ULONG_PTR) NewCell + CellSize);
3421 NewCell->CellSize = ((PCELL_HEADER) (*Cell))->CellSize - CellSize;
3422 CmiAddFree(RegistryHive,
3423 NewCell,
3424 *CellOffset + CellSize,
3425 TRUE);
3426 CmiMarkBlockDirty(RegistryHive,
3427 *CellOffset + CellSize);
3428 }
3429 else if (NewCell->CellSize < CellSize)
3430 {
3431 return STATUS_UNSUCCESSFUL;
3432 }
3433
3434 RtlZeroMemory(*Cell,
3435 CellSize);
3436 ((PCELL_HEADER) (*Cell))->CellSize = -CellSize;
3437 }
3438
3439 return STATUS_SUCCESS;
3440 }
3441
3442
3443 NTSTATUS
3444 CmiDestroyCell (PREGISTRY_HIVE RegistryHive,
3445 PVOID Cell,
3446 BLOCK_OFFSET CellOffset)
3447 {
3448 NTSTATUS Status;
3449 PHBIN pBin;
3450
3451 Status = STATUS_SUCCESS;
3452
3453 if (IsPointerHive(RegistryHive))
3454 {
3455 ExFreePool(Cell);
3456 }
3457 else
3458 {
3459 PCELL_HEADER pFree = Cell;
3460
3461 if (pFree->CellSize < 0)
3462 pFree->CellSize = -pFree->CellSize;
3463
3464 /* Clear block (except the block size) */
3465 RtlZeroMemory(((char*)pFree) + sizeof(ULONG),
3466 pFree->CellSize - sizeof(ULONG));
3467
3468 /* Add block to the list of free blocks */
3469 CmiAddFree(RegistryHive, Cell, CellOffset, TRUE);
3470
3471 /* Update time of heap */
3472 if (!IsNoFileHive(RegistryHive) && CmiGetCell (RegistryHive, CellOffset,&pBin))
3473 KeQuerySystemTime(&pBin->DateModified);
3474
3475 CmiMarkBlockDirty(RegistryHive, CellOffset);
3476 }
3477
3478 return Status;
3479 }
3480
3481
3482 PVOID
3483 CmiGetCell (PREGISTRY_HIVE RegistryHive,
3484 BLOCK_OFFSET CellOffset,
3485 PHBIN *Bin)
3486 {
3487 PHBIN pBin;
3488
3489 if (Bin != NULL)
3490 {
3491 *Bin = NULL;
3492 }
3493
3494 if (CellOffset == (BLOCK_OFFSET)-1)
3495 {
3496 return NULL;
3497 }
3498
3499 if (IsPointerHive (RegistryHive))
3500 {
3501 return (PVOID)CellOffset;
3502 }
3503
3504 if (CellOffset > RegistryHive->BlockListSize * REG_BLOCK_SIZE)
3505 {
3506 DPRINT1("CellOffset exceeds valid range (%lu > %lu)\n",
3507 CellOffset, RegistryHive->BlockListSize * REG_BLOCK_SIZE);
3508 return NULL;
3509 }
3510
3511 pBin = RegistryHive->BlockList[CellOffset / REG_BLOCK_SIZE].Bin;
3512 if (pBin == NULL)
3513 {
3514 return NULL;
3515 }
3516
3517 if (Bin != NULL)
3518 {
3519 *Bin = pBin;
3520 }
3521
3522 return((PVOID)((ULONG_PTR)pBin + (CellOffset - pBin->BinOffset)));
3523 }
3524
3525
3526 static BOOLEAN
3527 CmiMergeFree(PREGISTRY_HIVE RegistryHive,
3528 PCELL_HEADER FreeBlock,
3529 BLOCK_OFFSET FreeOffset)
3530 {
3531 BLOCK_OFFSET BlockOffset;
3532 BLOCK_OFFSET BinOffset;
3533 ULONG BlockSize;
3534 ULONG BinSize;
3535 PHBIN Bin;
3536 ULONG i;
3537
3538 DPRINT("CmiMergeFree(Block %lx Offset %lx Size %lx) called\n",
3539 FreeBlock, FreeOffset, FreeBlock->CellSize);
3540
3541 CmiGetCell (RegistryHive,
3542 FreeOffset,
3543 &Bin);
3544 DPRINT("Bin %p\n", Bin);
3545 if (Bin == NULL)
3546 return(FALSE);
3547
3548 BinOffset = Bin->BinOffset;
3549 BinSize = Bin->BinSize;
3550 DPRINT("Bin %p Offset %lx Size %lx\n", Bin, BinOffset, BinSize);
3551
3552 for (i = 0; i < RegistryHive->FreeListSize; i++)
3553 {
3554 BlockOffset = RegistryHive->FreeListOffset[i];
3555 BlockSize = RegistryHive->FreeList[i]->CellSize;
3556 if (BlockOffset > BinOffset &&
3557 BlockOffset < BinOffset + BinSize)
3558 {
3559 DPRINT("Free block: Offset %lx Size %lx\n",
3560 BlockOffset, BlockSize);
3561
3562 if ((i < (RegistryHive->FreeListSize - 1)) &&
3563 (BlockOffset + BlockSize == FreeOffset) &&
3564 (FreeOffset + FreeBlock->CellSize == RegistryHive->FreeListOffset[i + 1]))
3565 {
3566 DPRINT("Merge current block with previous and next block\n");
3567
3568 RegistryHive->FreeList[i]->CellSize +=
3569 (FreeBlock->CellSize + RegistryHive->FreeList[i + 1]->CellSize);
3570
3571 FreeBlock->CellSize = 0;
3572 RegistryHive->FreeList[i + 1]->CellSize = 0;
3573
3574
3575 if ((i + 2) < RegistryHive->FreeListSize)
3576 {
3577 RtlMoveMemory(&RegistryHive->FreeList[i + 1],
3578 &RegistryHive->FreeList[i + 2],
3579 sizeof(RegistryHive->FreeList[0])
3580 * (RegistryHive->FreeListSize - i - 2));
3581 RtlMoveMemory(&RegistryHive->FreeListOffset[i + 1],
3582 &RegistryHive->FreeListOffset[i + 2],
3583 sizeof(RegistryHive->FreeListOffset[0])
3584 * (RegistryHive->FreeListSize - i - 2));
3585 }
3586 RegistryHive->FreeListSize--;
3587
3588 CmiMarkBlockDirty(RegistryHive, BlockOffset);
3589
3590 return(TRUE);
3591 }
3592 else if (BlockOffset + BlockSize == FreeOffset)
3593 {
3594 DPRINT("Merge current block with previous block\n");
3595
3596 RegistryHive->FreeList[i]->CellSize += FreeBlock->CellSize;
3597 FreeBlock->CellSize = 0;
3598
3599 CmiMarkBlockDirty(RegistryHive, BlockOffset);
3600
3601 return(TRUE);
3602 }
3603 else if (FreeOffset + FreeBlock->CellSize == BlockOffset)
3604 {
3605 DPRINT("Merge current block with next block\n");
3606
3607 FreeBlock->CellSize += RegistryHive->FreeList[i]->CellSize;
3608 RegistryHive->FreeList[i]->CellSize = 0;
3609 RegistryHive->FreeList[i] = FreeBlock;
3610 RegistryHive->FreeListOffset[i] = FreeOffset;
3611
3612 CmiMarkBlockDirty(RegistryHive, FreeOffset);
3613
3614 return(TRUE);
3615 }
3616 }
3617 }
3618
3619 return(FALSE);
3620 }
3621
3622
3623 NTSTATUS
3624 CmiAddFree(PREGISTRY_HIVE RegistryHive,
3625 PCELL_HEADER FreeBlock,
3626 BLOCK_OFFSET FreeOffset,
3627 BOOLEAN MergeFreeBlocks)
3628 {
3629 PCELL_HEADER *tmpList;
3630 BLOCK_OFFSET *tmpListOffset;
3631 LONG minInd;
3632 LONG maxInd;
3633 LONG medInd;
3634
3635 ASSERT(RegistryHive);
3636 ASSERT(FreeBlock);
3637
3638 DPRINT("FreeBlock %.08lx FreeOffset %.08lx\n",
3639 FreeBlock, FreeOffset);
3640
3641 /* Merge free blocks */
3642 if (MergeFreeBlocks == TRUE)
3643 {
3644 if (CmiMergeFree(RegistryHive, FreeBlock, FreeOffset))
3645 return(STATUS_SUCCESS);
3646 }
3647
3648 if ((RegistryHive->FreeListSize + 1) > RegistryHive->FreeListMax)
3649 {
3650 tmpList = ExAllocatePool(PagedPool,
3651 sizeof(PCELL_HEADER) * (RegistryHive->FreeListMax + 32));
3652 if (tmpList == NULL)
3653 return STATUS_INSUFFICIENT_RESOURCES;
3654
3655 tmpListOffset = ExAllocatePool(PagedPool,
3656 sizeof(BLOCK_OFFSET) * (RegistryHive->FreeListMax + 32));
3657
3658 if (tmpListOffset == NULL)
3659 {
3660 ExFreePool(tmpList);
3661 return STATUS_INSUFFICIENT_RESOURCES;
3662 }
3663
3664 if (RegistryHive->FreeListMax)
3665 {
3666 RtlMoveMemory(tmpList,
3667 RegistryHive->FreeList,
3668 sizeof(PCELL_HEADER) * (RegistryHive->FreeListMax));
3669 RtlMoveMemory(tmpListOffset,
3670 RegistryHive->FreeListOffset,
3671 sizeof(BLOCK_OFFSET) * (RegistryHive->FreeListMax));
3672 ExFreePool(RegistryHive->FreeList);
3673 ExFreePool(RegistryHive->FreeListOffset);
3674 }
3675 RegistryHive->FreeList = tmpList;
3676 RegistryHive->FreeListOffset = tmpListOffset;
3677 RegistryHive->FreeListMax += 32;
3678 }
3679
3680 /* Add new offset to free list, maintaining list in ascending order */
3681 if ((RegistryHive->FreeListSize == 0)
3682 || (RegistryHive->FreeListOffset[RegistryHive->FreeListSize-1] < FreeOffset))
3683 {
3684 /* Add to end of list */
3685 RegistryHive->FreeList[RegistryHive->FreeListSize] = FreeBlock;
3686 RegistryHive->FreeListOffset[RegistryHive->FreeListSize++] = FreeOffset;
3687 }
3688 else if (RegistryHive->FreeListOffset[0] > FreeOffset)
3689 {
3690 /* Add to begin of list */
3691 RtlMoveMemory(&RegistryHive->FreeList[1],
3692 &RegistryHive->FreeList[0],
3693 sizeof(RegistryHive->FreeList[0]) * RegistryHive->FreeListSize);
3694 RtlMoveMemory(&RegistryHive->FreeListOffset[1],
3695 &RegistryHive->FreeListOffset[0],
3696 sizeof(RegistryHive->FreeListOffset[0]) * RegistryHive->FreeListSize);
3697 RegistryHive->FreeList[0] = FreeBlock;
3698 RegistryHive->FreeListOffset[0] = FreeOffset;
3699 RegistryHive->FreeListSize++;
3700 }
3701 else
3702 {
3703 /* Search where to insert */
3704 minInd = 0;
3705 maxInd = RegistryHive->FreeListSize - 1;
3706 while ((maxInd - minInd) > 1)
3707 {
3708 medInd = (minInd + maxInd) / 2;
3709 if (RegistryHive->FreeListOffset[medInd] > FreeOffset)
3710 maxInd = medInd;
3711 else
3712 minInd = medInd;
3713 }
3714
3715 /* Insert before maxInd */
3716 RtlMoveMemory(&RegistryHive->FreeList[maxInd+1],
3717 &RegistryHive->FreeList[maxInd],
3718 sizeof(RegistryHive->FreeList[0]) * (RegistryHive->FreeListSize - minInd));
3719 RtlMoveMemory(&RegistryHive->FreeListOffset[maxInd + 1],
3720 &RegistryHive->FreeListOffset[maxInd],
3721 sizeof(RegistryHive->FreeListOffset[0]) * (RegistryHive->FreeListSize-minInd));
3722 RegistryHive->FreeList[maxInd] = FreeBlock;
3723 RegistryHive->FreeListOffset[maxInd] = FreeOffset;
3724 RegistryHive->FreeListSize++;
3725 }
3726
3727 return STATUS_SUCCESS;
3728 }
3729
3730
3731 VOID
3732 CmiMarkBlockDirty(PREGISTRY_HIVE RegistryHive,
3733 BLOCK_OFFSET BlockOffset)
3734 {
3735 PDATA_CELL Cell;
3736 LONG CellSize;
3737 ULONG BlockNumber;
3738 ULONG BlockCount;
3739
3740 if (IsNoFileHive(RegistryHive))
3741 return;
3742
3743 DPRINT("CmiMarkBlockDirty(Offset 0x%lx)\n", (ULONG)BlockOffset);
3744
3745 BlockNumber = (ULONG)BlockOffset / REG_BLOCK_SIZE;
3746
3747 Cell = CmiGetCell (RegistryHive,
3748 BlockOffset,
3749 NULL);
3750
3751 CellSize = Cell->CellSize;
3752 if (CellSize < 0)
3753 CellSize = -CellSize;
3754
3755 BlockCount = (ROUND_UP(BlockOffset + CellSize, REG_BLOCK_SIZE) -
3756 ROUND_DOWN(BlockOffset, REG_BLOCK_SIZE)) / REG_BLOCK_SIZE;
3757
3758 DPRINT(" BlockNumber %lu Size %lu (%s) BlockCount %lu\n",
3759 BlockNumber,
3760 CellSize,
3761 (Cell->CellSize < 0) ? "used" : "free",
3762 BlockCount);
3763
3764 RegistryHive->HiveDirty = TRUE;
3765 RtlSetBits(&RegistryHive->DirtyBitMap,
3766 BlockNumber,
3767 BlockCount);
3768 }
3769
3770
3771 VOID
3772 CmiMarkBinDirty(PREGISTRY_HIVE RegistryHive,
3773 BLOCK_OFFSET BinOffset)
3774 {
3775 ULONG BlockNumber;
3776 ULONG BlockCount;
3777 PHBIN Bin;
3778
3779 if (IsNoFileHive(RegistryHive))
3780 return;
3781
3782 DPRINT("CmiMarkBinDirty(Offset 0x%lx)\n", (ULONG)BinOffset);
3783
3784 BlockNumber = (ULONG)BinOffset / REG_BLOCK_SIZE;
3785
3786 Bin = RegistryHive->BlockList[BlockNumber].Bin;
3787
3788 BlockCount = Bin->BinSize / REG_BLOCK_SIZE;
3789
3790 DPRINT(" BlockNumber %lu BinSize %lu BlockCount %lu\n",
3791 BlockNumber,
3792 Bin->BinSize,
3793 BlockCount);
3794
3795 RegistryHive->HiveDirty = TRUE;
3796 RtlSetBits(&RegistryHive->DirtyBitMap,
3797 BlockNumber,
3798 BlockCount);
3799 }
3800
3801
3802 ULONG
3803 CmiGetPackedNameLength(IN PUNICODE_STRING Name,
3804 OUT PBOOLEAN Packable)
3805 {
3806 ULONG i;
3807
3808 if (Packable != NULL)
3809 *Packable = TRUE;
3810
3811 for (i = 0; i < Name->Length / sizeof(WCHAR); i++)
3812 {
3813 if (Name->Buffer[i] & 0xFF00)
3814 {
3815 if (Packable != NULL)
3816 *Packable = FALSE;
3817 return Name->Length;
3818 }
3819 }
3820
3821 return (Name->Length / sizeof(WCHAR));
3822 }
3823
3824
3825 BOOLEAN
3826 CmiComparePackedNames(IN PUNICODE_STRING Name,
3827 IN PUCHAR NameBuffer,
3828 IN USHORT NameBufferSize,
3829 IN BOOLEAN NamePacked)
3830 {
3831 PWCHAR UNameBuffer;
3832 ULONG i;
3833
3834 if (NamePacked == TRUE)
3835 {
3836 if (Name->Length != NameBufferSize * sizeof(WCHAR))
3837 return(FALSE);
3838
3839 for (i = 0; i < Name->Length / sizeof(WCHAR); i++)
3840 {
3841 if (RtlUpcaseUnicodeChar(Name->Buffer[i]) != RtlUpcaseUnicodeChar((WCHAR)NameBuffer[i]))
3842 return(FALSE);
3843 }
3844 }
3845 else
3846 {
3847 if (Name->Length != NameBufferSize)
3848 return(FALSE);
3849
3850 UNameBuffer = (PWCHAR)NameBuffer;
3851
3852 for (i = 0; i < Name->Length / sizeof(WCHAR); i++)
3853 {
3854 if (RtlUpcaseUnicodeChar(Name->Buffer[i]) != RtlUpcaseUnicodeChar(UNameBuffer[i]))
3855 return(FALSE);
3856 }
3857 }
3858
3859 return(TRUE);
3860 }
3861
3862
3863 VOID
3864 CmiCopyPackedName(PWCHAR NameBuffer,
3865 PUCHAR PackedNameBuffer,
3866 ULONG PackedNameSize)
3867 {
3868 ULONG i;
3869
3870 for (i = 0; i < PackedNameSize; i++)
3871 NameBuffer[i] = (WCHAR)PackedNameBuffer[i];
3872 }
3873
3874
3875 BOOLEAN
3876 CmiCompareHash(PUNICODE_STRING KeyName,
3877 PCHAR HashString)
3878 {
3879 CHAR Buffer[4];
3880
3881 Buffer[0] = (KeyName->Length >= 2) ? (CHAR)KeyName->Buffer[0] : 0;
3882 Buffer[1] = (KeyName->Length >= 4) ? (CHAR)KeyName->Buffer[1] : 0;
3883 Buffer[2] = (KeyName->Length >= 6) ? (CHAR)KeyName->Buffer[2] : 0;
3884 Buffer[3] = (KeyName->Length >= 8) ? (CHAR)KeyName->Buffer[3] : 0;
3885
3886 return (strncmp(Buffer, HashString, 4) == 0);
3887 }
3888
3889
3890 BOOLEAN
3891 CmiCompareHashI(PUNICODE_STRING KeyName,
3892 PCHAR HashString)
3893 {
3894 CHAR Buffer[4];
3895
3896 Buffer[0] = (KeyName->Length >= 2) ? (CHAR)KeyName->Buffer[0] : 0;
3897 Buffer[1] = (KeyName->Length >= 4) ? (CHAR)KeyName->Buffer[1] : 0;
3898 Buffer[2] = (KeyName->Length >= 6) ? (CHAR)KeyName->Buffer[2] : 0;
3899 Buffer[3] = (KeyName->Length >= 8) ? (CHAR)KeyName->Buffer[3] : 0;
3900
3901 return (_strnicmp(Buffer, HashString, 4) == 0);
3902 }
3903
3904
3905 BOOLEAN
3906 CmiCompareKeyNames(PUNICODE_STRING KeyName,
3907 PKEY_CELL KeyCell)
3908 {
3909 PWCHAR UnicodeName;
3910 USHORT i;
3911
3912 DPRINT("Flags: %hx\n", KeyCell->Flags);
3913
3914 if (KeyCell->Flags & REG_KEY_NAME_PACKED)
3915 {
3916 if (KeyName->Length != KeyCell->NameSize * sizeof(WCHAR))
3917 return FALSE;
3918
3919 for (i = 0; i < KeyCell->NameSize; i++)
3920 {
3921 if (KeyName->Buffer[i] != (WCHAR)KeyCell->Name[i])
3922 return FALSE;
3923 }
3924 }
3925 else
3926 {
3927 if (KeyName->Length != KeyCell->NameSize)
3928 return FALSE;
3929
3930 UnicodeName = (PWCHAR)KeyCell->Name;
3931 for (i = 0; i < KeyCell->NameSize / sizeof(WCHAR); i++)
3932 {
3933 if (KeyName->Buffer[i] != UnicodeName[i])
3934 return FALSE;
3935 }
3936 }
3937
3938 return TRUE;
3939 }
3940
3941
3942 BOOLEAN
3943 CmiCompareKeyNamesI(PUNICODE_STRING KeyName,
3944 PKEY_CELL KeyCell)
3945 {
3946 PWCHAR UnicodeName;
3947 USHORT i;
3948
3949 DPRINT("Flags: %hx\n", KeyCell->Flags);
3950
3951 if (KeyCell->Flags & REG_KEY_NAME_PACKED)
3952 {
3953 if (KeyName->Length != KeyCell->NameSize * sizeof(WCHAR))
3954 return FALSE;
3955
3956 for (i = 0; i < KeyCell->NameSize; i++)
3957 {
3958 if (RtlUpcaseUnicodeChar(KeyName->Buffer[i]) !=
3959 RtlUpcaseUnicodeChar((WCHAR)KeyCell->Name[i]))
3960 return FALSE;
3961 }
3962 }
3963 else
3964 {
3965 if (KeyName->Length != KeyCell->NameSize)
3966 return FALSE;
3967
3968 UnicodeName = (PWCHAR)KeyCell->Name;
3969 for (i = 0; i < KeyCell->NameSize / sizeof(WCHAR); i++)
3970 {
3971 if (RtlUpcaseUnicodeChar(KeyName->Buffer[i]) !=
3972 RtlUpcaseUnicodeChar(UnicodeName[i]))
3973 return FALSE;
3974 }
3975 }
3976
3977 return TRUE;
3978 }
3979
3980
3981 NTSTATUS
3982 CmiCopyKey (PREGISTRY_HIVE DstHive,
3983 PKEY_CELL DstKeyCell,
3984 PREGISTRY_HIVE SrcHive,
3985 PKEY_CELL SrcKeyCell)
3986 {
3987 PKEY_CELL NewKeyCell;
3988 ULONG NewKeyCellSize;
3989 BLOCK_OFFSET NewKeyCellOffset;
3990 PHASH_TABLE_CELL NewHashTableCell;
3991 ULONG NewHashTableSize;
3992 BLOCK_OFFSET NewHashTableOffset;
3993 ULONG i;
3994 NTSTATUS Status;
3995
3996 DPRINT ("CmiCopyKey() called\n");
3997
3998 if (DstKeyCell == NULL)
3999 {
4000 /* Allocate and copy key cell */
4001 NewKeyCellSize = sizeof(KEY_CELL) + SrcKeyCell->NameSize;
4002 Status = CmiAllocateCell (DstHive,
4003 NewKeyCellSize,
4004 (PVOID) &NewKeyCell,
4005 &NewKeyCellOffset);
4006 if (!NT_SUCCESS(Status))
4007 {
4008 DPRINT1 ("CmiAllocateBlock() failed (Status %lx)\n", Status);
4009 return Status;
4010 }
4011 if (NewKeyCell == NULL)
4012 {
4013 DPRINT1 ("Failed to allocate a key cell\n");
4014 return STATUS_INSUFFICIENT_RESOURCES;
4015 }
4016
4017 RtlCopyMemory (NewKeyCell,
4018 SrcKeyCell,
4019 NewKeyCellSize);
4020
4021 DstHive->HiveHeader->RootKeyOffset = NewKeyCellOffset;
4022
4023 /* Copy class name */
4024 if (SrcKeyCell->ClassNameOffset != (BLOCK_OFFSET) -1)
4025 {
4026 PDATA_CELL SrcClassNameCell;
4027 PDATA_CELL NewClassNameCell;
4028 BLOCK_OFFSET NewClassNameOffset;
4029
4030 SrcClassNameCell = CmiGetCell (SrcHive, SrcKeyCell->ClassNameOffset, NULL),
4031
4032 NewKeyCell->ClassSize = SrcKeyCell->ClassSize;
4033 Status = CmiAllocateCell (DstHive,
4034 sizeof(CELL_HEADER) + NewKeyCell->ClassSize,
4035 (PVOID)&NewClassNameCell,
4036 &NewClassNameOffset);
4037 if (!NT_SUCCESS(Status))
4038 {
4039 DPRINT1 ("CmiAllocateBlock() failed (Status %lx)\n", Status);
4040 return Status;
4041 }
4042
4043 RtlCopyMemory (NewClassNameCell,
4044 SrcClassNameCell,
4045 NewKeyCell->ClassSize);
4046 NewKeyCell->ClassNameOffset = NewClassNameOffset;
4047 }
4048 }
4049 else
4050 {
4051 NewKeyCell = DstKeyCell;
4052 }
4053
4054 /* Allocate hash table */
4055 if (SrcKeyCell->NumberOfSubKeys > 0)
4056 {
4057 NewHashTableSize = ROUND_UP(SrcKeyCell->NumberOfSubKeys + 1, 4) - 1;
4058 Status = CmiAllocateHashTableCell (DstHive,
4059 &NewHashTableCell,
4060 &NewHashTableOffset,
4061 NewHashTableSize);
4062 if (!NT_SUCCESS(Status))
4063 {
4064 DPRINT1 ("CmiAllocateHashTableBlock() failed (Status %lx)\n", Status);
4065 return Status;
4066 }
4067 NewKeyCell->HashTableOffset = NewHashTableOffset;
4068 }
4069 else
4070 {
4071 NewHashTableCell = NULL;
4072 }
4073
4074 /* Allocate and copy value list and values */
4075 if (SrcKeyCell->NumberOfValues != 0)
4076 {
4077 PVALUE_LIST_CELL NewValueListCell;
4078 PVALUE_LIST_CELL SrcValueListCell;
4079 PVALUE_CELL NewValueCell;
4080 PVALUE_CELL SrcValueCell;
4081 PDATA_CELL SrcValueDataCell;
4082 PDATA_CELL NewValueDataCell;
4083 BLOCK_OFFSET ValueCellOffset;
4084 BLOCK_OFFSET ValueDataCellOffset;
4085 ULONG NewValueListCellSize;
4086 ULONG NewValueCellSize;
4087
4088
4089 NewValueListCellSize =
4090 ROUND_UP(SrcKeyCell->NumberOfValues, 4) * sizeof(BLOCK_OFFSET);
4091 Status = CmiAllocateCell (DstHive,
4092 NewValueListCellSize,
4093 (PVOID)&NewValueListCell,
4094 &NewKeyCell->ValueListOffset);
4095 if (!NT_SUCCESS(Status))
4096 {
4097 DPRINT1 ("CmiAllocateBlock() failed (Status %lx)\n", Status);
4098 return Status;
4099 }
4100
4101 RtlZeroMemory (NewValueListCell,
4102 NewValueListCellSize);
4103
4104 /* Copy values */
4105 SrcValueListCell = CmiGetCell (SrcHive, SrcKeyCell->ValueListOffset, NULL);
4106 for (i = 0; i < SrcKeyCell->NumberOfValues; i++)
4107 {
4108 /* Copy value cell */
4109 SrcValueCell = CmiGetCell (SrcHive, SrcValueListCell->ValueOffset[i], NULL);
4110
4111 NewValueCellSize = sizeof(VALUE_CELL) + SrcValueCell->NameSize;
4112 Status = CmiAllocateCell (DstHive,
4113 NewValueCellSize,
4114 (PVOID*) &NewValueCell,
4115 &ValueCellOffset);
4116 if (!NT_SUCCESS(Status))
4117 {
4118 DPRINT1 ("CmiAllocateBlock() failed (Status %lx)\n", Status);
4119 return Status;
4120 }
4121
4122 NewValueListCell->ValueOffset[i] = ValueCellOffset;
4123 RtlCopyMemory (NewValueCell,
4124 SrcValueCell,
4125 NewValueCellSize);
4126
4127 /* Copy value data cell */
4128 if (SrcValueCell->DataSize > (LONG) sizeof(PVOID))
4129 {
4130 SrcValueDataCell = CmiGetCell (SrcHive, SrcValueCell->DataOffset, NULL);
4131
4132 Status = CmiAllocateCell (DstHive,
4133 sizeof(CELL_HEADER) + SrcValueCell->DataSize,
4134 (PVOID*) &NewValueDataCell,
4135 &ValueDataCellOffset);
4136 if (!NT_SUCCESS(Status))
4137 {
4138 DPRINT1 ("CmiAllocateBlock() failed (Status %lx)\n", Status);
4139 return Status;
4140 }
4141 RtlCopyMemory (NewValueDataCell,
4142 SrcValueDataCell,
4143 SrcValueCell->DataSize);
4144 NewValueCell->DataOffset = ValueDataCellOffset;
4145 }
4146 }
4147 }
4148
4149 /* Copy subkeys */
4150 if (SrcKeyCell->NumberOfSubKeys > 0)
4151 {
4152 PHASH_TABLE_CELL SrcHashTableCell;
4153 PKEY_CELL SrcSubKeyCell;
4154 PKEY_CELL NewSubKeyCell;
4155 ULONG NewSubKeyCellSize;
4156 BLOCK_OFFSET NewSubKeyCellOffset;
4157 PHASH_RECORD SrcHashRecord;
4158
4159 SrcHashTableCell = CmiGetCell (SrcHive,
4160 SrcKeyCell->HashTableOffset,
4161 NULL);
4162
4163 for (i = 0; i < SrcKeyCell->NumberOfSubKeys; i++)
4164 {
4165 SrcHashRecord = &SrcHashTableCell->Table[i];
4166 SrcSubKeyCell = CmiGetCell (SrcHive, SrcHashRecord->KeyOffset, NULL);
4167
4168 /* Allocate and copy key cell */
4169 NewSubKeyCellSize = sizeof(KEY_CELL) + SrcSubKeyCell->NameSize;
4170 Status = CmiAllocateCell (DstHive,
4171 NewSubKeyCellSize,
4172 (PVOID)&NewSubKeyCell,
4173 &NewSubKeyCellOffset);
4174 if (!NT_SUCCESS(Status))
4175 {
4176 DPRINT1 ("CmiAllocateBlock() failed (Status %lx)\n", Status);
4177 return Status;
4178 }
4179 if (NewKeyCell == NULL)
4180 {
4181 DPRINT1 ("Failed to allocate a sub key cell\n");
4182 return STATUS_INSUFFICIENT_RESOURCES;
4183 }
4184
4185 NewHashTableCell->Table[i].KeyOffset = NewSubKeyCellOffset;
4186 NewHashTableCell->Table[i].HashValue = SrcHashRecord->HashValue;
4187
4188 RtlCopyMemory (NewSubKeyCell,
4189 SrcSubKeyCell,
4190 NewSubKeyCellSize);
4191
4192 /* Copy class name */
4193 if (SrcSubKeyCell->ClassNameOffset != (BLOCK_OFFSET) -1)
4194 {
4195 PDATA_CELL SrcClassNameCell;
4196 PDATA_CELL NewClassNameCell;
4197 BLOCK_OFFSET NewClassNameOffset;
4198
4199 SrcClassNameCell = CmiGetCell (SrcHive,
4200 SrcSubKeyCell->ClassNameOffset,
4201 NULL),
4202
4203 NewSubKeyCell->ClassSize = SrcSubKeyCell->ClassSize;
4204 Status = CmiAllocateCell (DstHive,
4205 sizeof(CELL_HEADER) + NewSubKeyCell->ClassSize,
4206 (PVOID)&NewClassNameCell,
4207 &NewClassNameOffset);
4208 if (!NT_SUCCESS(Status))
4209 {
4210 DPRINT1 ("CmiAllocateBlock() failed (Status %lx)\n", Status);
4211 return Status;
4212 }
4213
4214 NewSubKeyCell->ClassNameOffset = NewClassNameOffset;
4215 RtlCopyMemory (NewClassNameCell,
4216 SrcClassNameCell,
4217 NewSubKeyCell->ClassSize);
4218 }
4219
4220 /* Copy subkey data and subkeys */
4221 Status = CmiCopyKey (DstHive,
4222 NewSubKeyCell,
4223 SrcHive,
4224 SrcSubKeyCell);
4225 if (!NT_SUCCESS(Status))
4226 {
4227 DPRINT1 ("CmiAllocateBlock() failed (Status %lx)\n", Status);
4228 return Status;
4229 }
4230 }
4231 }
4232
4233 return STATUS_SUCCESS;
4234 }
4235
4236
4237 NTSTATUS
4238 CmiSaveTempHive (PREGISTRY_HIVE Hive,
4239 HANDLE FileHandle)
4240 {
4241 IO_STATUS_BLOCK IoStatusBlock;
4242 LARGE_INTEGER FileOffset;
4243 ULONG BlockIndex;
4244 PVOID BlockPtr;
4245 NTSTATUS Status;
4246
4247 DPRINT ("CmiSaveTempHive() called\n");
4248
4249 Hive->HiveHeader->Checksum = CmiCalcChecksum ((PULONG)Hive->HiveHeader);
4250
4251 /* Write hive block */
4252 FileOffset.QuadPart = (ULONGLONG)0;
4253 Status = ZwWriteFile (FileHandle,
4254 NULL,
4255 NULL,
4256 NULL,
4257 &IoStatusBlock,
4258 Hive->HiveHeader,
4259 sizeof(HIVE_HEADER),
4260 &FileOffset,
4261 NULL);
4262 if (!NT_SUCCESS(Status))
4263 {
4264 DPRINT1 ("ZwWriteFile() failed (Status %lx)\n", Status);
4265 return Status;
4266 }
4267
4268 DPRINT ("Saving %lu blocks\n", Hive->BlockListSize);
4269 for (BlockIndex = 0; BlockIndex < Hive->BlockListSize; BlockIndex++)
4270 {
4271 BlockPtr = Hive->BlockList[BlockIndex].Block;
4272 DPRINT ("BlockPtr %p\n", BlockPtr);
4273
4274 FileOffset.QuadPart = (ULONGLONG)(BlockIndex + 1) * (ULONGLONG)REG_BLOCK_SIZE;
4275 DPRINT ("File offset %I64x\n", FileOffset.QuadPart);
4276
4277 /* Write hive block */
4278 Status = ZwWriteFile (FileHandle,
4279 NULL,
4280 NULL,
4281 NULL,
4282 &IoStatusBlock,
4283 BlockPtr,
4284 REG_BLOCK_SIZE,
4285 &FileOffset,
4286 NULL);
4287 if (!NT_SUCCESS(Status))
4288 {
4289 DPRINT1 ("ZwWriteFile() failed (Status %lx)\n", Status);
4290 return Status;
4291 }
4292 }
4293
4294 Status = ZwFlushBuffersFile (FileHandle,
4295 &IoStatusBlock);
4296 if (!NT_SUCCESS(Status))
4297 {
4298 DPRINT1 ("ZwFlushBuffersFile() failed (Status %lx)\n", Status);
4299 }
4300
4301 DPRINT ("CmiSaveTempHive() done\n");
4302
4303 return Status;
4304 }
4305
4306 /* EOF */