bebaf3bbefc5ae6a9b263b8b189b356ce707ea91
[reactos.git] / reactos / ntoskrnl / cm / regfile.c
1 /*
2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS kernel
4 * FILE: ntoskrnl/cm/regfile.c
5 * PURPOSE: Registry file manipulation routines
6 * UPDATE HISTORY:
7 */
8
9 #include <ntoskrnl.h>
10 #define NDEBUG
11 #include <internal/debug.h>
12
13 #include "cm.h"
14
15
16 /* uncomment to enable hive checks (incomplete and probably buggy) */
17 // #define HIVE_CHECK
18
19 /* LOCAL MACROS *************************************************************/
20
21 #define ROUND_DOWN(N, S) ((N) - ((N) % (S)))
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 NtQuerySystemTime(&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 = NtWriteFile(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 assertmsg(NT_SUCCESS(Status), ("Status: 0x%X\n", Status));
400
401 if (!NT_SUCCESS(Status))
402 {
403 return(Status);
404 }
405
406 Status = NtFlushBuffersFile(FileHandle,
407 &IoStatusBlock);
408
409 return(Status);
410 }
411
412
413 #ifdef HIVE_CHECK
414 static NTSTATUS
415 CmiCheckAndFixHive(PREGISTRY_HIVE RegistryHive)
416 {
417 OBJECT_ATTRIBUTES ObjectAttributes;
418 FILE_STANDARD_INFORMATION fsi;
419 IO_STATUS_BLOCK IoStatusBlock;
420 HANDLE HiveHandle = INVALID_HANDLE_VALUE;
421 HANDLE LogHandle = INVALID_HANDLE_VALUE;
422 PHIVE_HEADER HiveHeader = NULL;
423 PHIVE_HEADER LogHeader = NULL;
424 LARGE_INTEGER FileOffset;
425 ULONG FileSize;
426 ULONG BufferSize;
427 ULONG BitmapSize;
428 RTL_BITMAP BlockBitMap;
429 NTSTATUS Status;
430
431 DPRINT("CmiCheckAndFixHive() called\n");
432
433 /* Try to open the hive file */
434 InitializeObjectAttributes(&ObjectAttributes,
435 &RegistryHive->HiveFileName,
436 OBJ_CASE_INSENSITIVE,
437 NULL,
438 NULL);
439
440 Status = NtCreateFile(&HiveHandle,
441 FILE_READ_DATA | FILE_READ_ATTRIBUTES,
442 &ObjectAttributes,
443 &IoStatusBlock,
444 NULL,
445 FILE_ATTRIBUTE_NORMAL,
446 0,
447 FILE_OPEN,
448 FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT,
449 NULL,
450 0);
451 if (Status == STATUS_OBJECT_NAME_NOT_FOUND)
452 {
453 return(STATUS_SUCCESS);
454 }
455 if (!NT_SUCCESS(Status))
456 {
457 DPRINT("NtCreateFile() failed (Status %lx)\n", Status);
458 return(Status);
459 }
460
461 /* Try to open the log file */
462 InitializeObjectAttributes(&ObjectAttributes,
463 &RegistryHive->LogFileName,
464 OBJ_CASE_INSENSITIVE,
465 NULL,
466 NULL);
467
468 Status = NtCreateFile(&LogHandle,
469 FILE_READ_DATA | FILE_READ_ATTRIBUTES,
470 &ObjectAttributes,
471 &IoStatusBlock,
472 NULL,
473 FILE_ATTRIBUTE_NORMAL,
474 0,
475 FILE_OPEN,
476 FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT,
477 NULL,
478 0);
479 if (Status == STATUS_OBJECT_NAME_NOT_FOUND)
480 {
481 LogHandle = INVALID_HANDLE_VALUE;
482 }
483 else if (!NT_SUCCESS(Status))
484 {
485 DPRINT("NtCreateFile() failed (Status %lx)\n", Status);
486 NtClose(HiveHandle);
487 return(Status);
488 }
489
490 /* Allocate hive header */
491 HiveHeader = ExAllocatePool(PagedPool,
492 sizeof(HIVE_HEADER));
493 if (HiveHeader == NULL)
494 {
495 DPRINT("ExAllocatePool() failed\n");
496 Status = STATUS_INSUFFICIENT_RESOURCES;
497 goto ByeBye;
498 }
499
500 /* Read hive base block */
501 FileOffset.QuadPart = 0ULL;
502 Status = NtReadFile(HiveHandle,
503 0,
504 0,
505 0,
506 &IoStatusBlock,
507 HiveHeader,
508 sizeof(HIVE_HEADER),
509 &FileOffset,
510 0);
511 if (!NT_SUCCESS(Status))
512 {
513 DPRINT("NtReadFile() failed (Status %lx)\n", Status);
514 goto ByeBye;
515 }
516
517 if (LogHandle == INVALID_HANDLE_VALUE)
518 {
519 if (HiveHeader->Checksum != CmiCalcChecksum((PULONG)HiveHeader) ||
520 HiveHeader->UpdateCounter1 != HiveHeader->UpdateCounter2)
521 {
522 /* There is no way to fix the hive without log file - BSOD! */
523 DPRINT("Hive header inconsistent and no log file available!\n");
524 KEBUGCHECK(CONFIG_LIST_FAILED);
525 }
526
527 Status = STATUS_SUCCESS;
528 goto ByeBye;
529 }
530 else
531 {
532 /* Allocate hive header */
533 LogHeader = ExAllocatePool(PagedPool,
534 sizeof(HIVE_HEADER));
535 if (LogHeader == NULL)
536 {
537 DPRINT("ExAllocatePool() failed\n");
538 Status = STATUS_INSUFFICIENT_RESOURCES;
539 goto ByeBye;
540 }
541
542 /* Read log file header */
543 FileOffset.QuadPart = 0ULL;
544 Status = NtReadFile(LogHandle,
545 0,
546 0,
547 0,
548 &IoStatusBlock,
549 LogHeader,
550 sizeof(HIVE_HEADER),
551 &FileOffset,
552 0);
553 if (!NT_SUCCESS(Status))
554 {
555 DPRINT("NtReadFile() failed (Status %lx)\n", Status);
556 goto ByeBye;
557 }
558
559 /* Check log file header integrity */
560 if (LogHeader->Checksum != CmiCalcChecksum((PULONG)LogHeader) ||
561 LogHeader->UpdateCounter1 != LogHeader->UpdateCounter2)
562 {
563 if (HiveHeader->Checksum != CmiCalcChecksum((PULONG)HiveHeader) ||
564 HiveHeader->UpdateCounter1 != HiveHeader->UpdateCounter2)
565 {
566 DPRINT("Hive file and log file are inconsistent!\n");
567 KEBUGCHECK(CONFIG_LIST_FAILED);
568 }
569
570 /* Log file damaged but hive is okay */
571 Status = STATUS_SUCCESS;
572 goto ByeBye;
573 }
574
575 if (HiveHeader->UpdateCounter1 == HiveHeader->UpdateCounter2 &&
576 HiveHeader->UpdateCounter1 == LogHeader->UpdateCounter1)
577 {
578 /* Hive and log file are up-to-date */
579 Status = STATUS_SUCCESS;
580 goto ByeBye;
581 }
582
583 /*
584 * Hive needs an update!
585 */
586
587 /* Get file size */
588 Status = NtQueryInformationFile(LogHandle,
589 &IoStatusBlock,
590 &fsi,
591 sizeof(fsi),
592 FileStandardInformation);
593 if (!NT_SUCCESS(Status))
594 {
595 DPRINT("NtQueryInformationFile() failed (Status %lx)\n", Status);
596 goto ByeBye;
597 }
598 FileSize = fsi.EndOfFile.u.LowPart;
599
600 /* Calculate bitmap and block size */
601 BitmapSize = ROUND_UP((FileSize / REG_BLOCK_SIZE) - 1, sizeof(ULONG) * 8) / 8;
602 BufferSize = sizeof(HIVE_HEADER) +
603 sizeof(ULONG) +
604 BitmapSize;
605 BufferSize = ROUND_UP(BufferSize, REG_BLOCK_SIZE);
606
607 /* Reallocate log header block */
608 ExFreePool(LogHeader);
609 LogHeader = ExAllocatePool(PagedPool,
610 BufferSize);
611 if (LogHeader == NULL)
612 {
613 DPRINT("ExAllocatePool() failed\n");
614 Status = STATUS_INSUFFICIENT_RESOURCES;
615 goto ByeBye;
616 }
617
618 /* Read log file header */
619 FileOffset.QuadPart = 0ULL;
620 Status = NtReadFile(LogHandle,
621 0,
622 0,
623 0,
624 &IoStatusBlock,
625 LogHeader,
626 BufferSize,
627 &FileOffset,
628 0);
629 if (!NT_SUCCESS(Status))
630 {
631 DPRINT("NtReadFile() failed (Status %lx)\n", Status);
632 goto ByeBye;
633 }
634
635 /* Initialize bitmap */
636 RtlInitializeBitMap(&BlockBitMap,
637 (PVOID)((ULONG_PTR)LogHeader + REG_BLOCK_SIZE + sizeof(ULONG)),
638 BitmapSize * 8);
639
640 /* FIXME: Update dirty blocks */
641
642
643 /* FIXME: Update hive header */
644
645
646 Status = STATUS_SUCCESS;
647 }
648
649
650 /* Clean up the mess */
651 ByeBye:
652 if (HiveHeader != NULL)
653 ExFreePool(HiveHeader);
654
655 if (LogHeader != NULL)
656 ExFreePool(LogHeader);
657
658 if (LogHandle != INVALID_HANDLE_VALUE)
659 NtClose(LogHandle);
660
661 NtClose(HiveHandle);
662
663 return(Status);
664 }
665 #endif
666
667
668 NTSTATUS
669 CmiImportHiveBins(PREGISTRY_HIVE Hive,
670 PUCHAR ChunkPtr)
671 {
672 BLOCK_OFFSET BlockOffset;
673 ULONG BlockIndex;
674 PHBIN Bin;
675 ULONG j;
676
677 BlockIndex = 0;
678 BlockOffset = 0;
679 while (BlockIndex < Hive->BlockListSize)
680 {
681 Bin = (PHBIN)((ULONG_PTR)ChunkPtr + BlockOffset);
682
683 if (Bin->HeaderId != REG_BIN_ID)
684 {
685 DPRINT1 ("Bad bin header id %x, offset %x\n", Bin->HeaderId, BlockOffset);
686 return STATUS_REGISTRY_CORRUPT;
687 }
688
689 assertmsg((Bin->BinSize % REG_BLOCK_SIZE) == 0,
690 ("Bin size (0x%.08x) must be multiple of 4K\n",
691 Bin->BinSize));
692
693 /* Allocate the hive block */
694 Hive->BlockList[BlockIndex].Bin = ExAllocatePool (PagedPool,
695 Bin->BinSize);
696 if (Hive->BlockList[BlockIndex].Bin == NULL)
697 {
698 DPRINT1 ("ExAllocatePool() failed\n");
699 return STATUS_INSUFFICIENT_RESOURCES;
700 }
701 Hive->BlockList[BlockIndex].Block = (PVOID)Hive->BlockList[BlockIndex].Bin;
702
703 /* Import the Bin */
704 RtlCopyMemory (Hive->BlockList[BlockIndex].Bin,
705 Bin,
706 Bin->BinSize);
707
708 if (Bin->BinSize > REG_BLOCK_SIZE)
709 {
710 for (j = 1; j < Bin->BinSize / REG_BLOCK_SIZE; j++)
711 {
712 Hive->BlockList[BlockIndex + j].Bin = Hive->BlockList[BlockIndex].Bin;
713 Hive->BlockList[BlockIndex + j].Block =
714 (PVOID)((ULONG_PTR)Hive->BlockList[BlockIndex].Bin + (j * REG_BLOCK_SIZE));
715 }
716 }
717
718 BlockIndex += Bin->BinSize / REG_BLOCK_SIZE;
719 BlockOffset += Bin->BinSize;
720 }
721
722 return STATUS_SUCCESS;
723 }
724
725
726 VOID
727 CmiFreeHiveBins (PREGISTRY_HIVE Hive)
728 {
729 ULONG i;
730 PHBIN Bin;
731
732 Bin = NULL;
733 for (i = 0; i < Hive->BlockListSize; i++)
734 {
735 if (Hive->BlockList[i].Bin == NULL)
736 continue;
737
738 if (Hive->BlockList[i].Bin != Bin)
739 {
740 Bin = Hive->BlockList[i].Bin;
741 ExFreePool (Hive->BlockList[i].Bin);
742 }
743 Hive->BlockList[i].Bin = NULL;
744 Hive->BlockList[i].Block = NULL;
745 }
746 }
747
748
749 NTSTATUS
750 CmiCreateHiveFreeCellList(PREGISTRY_HIVE Hive)
751 {
752 BLOCK_OFFSET BlockOffset;
753 PCELL_HEADER FreeBlock;
754 ULONG BlockIndex;
755 ULONG FreeOffset;
756 PHBIN Bin;
757 NTSTATUS Status;
758
759 /* Initialize the free cell list */
760 Hive->FreeListSize = 0;
761 Hive->FreeListMax = 0;
762 Hive->FreeList = NULL;
763 Hive->FreeListOffset = NULL;
764
765 BlockOffset = 0;
766 BlockIndex = 0;
767 while (BlockIndex < Hive->BlockListSize)
768 {
769 Bin = Hive->BlockList[BlockIndex].Bin;
770
771 /* Search free blocks and add to list */
772 FreeOffset = REG_HBIN_DATA_OFFSET;
773 while (FreeOffset < Bin->BinSize)
774 {
775 FreeBlock = (PCELL_HEADER) ((ULONG_PTR) Bin + FreeOffset);
776 if (FreeBlock->CellSize > 0)
777 {
778 Status = CmiAddFree(Hive,
779 FreeBlock,
780 Bin->BinOffset + FreeOffset,
781 FALSE);
782
783 if (!NT_SUCCESS(Status))
784 {
785 return Status;
786 }
787
788 FreeOffset += FreeBlock->CellSize;
789 }
790 else
791 {
792 FreeOffset -= FreeBlock->CellSize;
793 }
794 }
795
796 BlockIndex += Bin->BinSize / REG_BLOCK_SIZE;
797 BlockOffset += Bin->BinSize;
798 }
799
800 return STATUS_SUCCESS;
801 }
802
803
804 VOID
805 CmiFreeHiveFreeCellList(PREGISTRY_HIVE Hive)
806 {
807 ExFreePool (Hive->FreeList);
808 ExFreePool (Hive->FreeListOffset);
809
810 Hive->FreeListSize = 0;
811 Hive->FreeListMax = 0;
812 Hive->FreeList = NULL;
813 Hive->FreeListOffset = NULL;
814 }
815
816
817 NTSTATUS
818 CmiCreateHiveBitmap(PREGISTRY_HIVE Hive)
819 {
820 ULONG BitmapSize;
821
822 /* Calculate bitmap size in bytes (always a multiple of 32 bits) */
823 BitmapSize = ROUND_UP(Hive->BlockListSize, sizeof(ULONG) * 8) / 8;
824 DPRINT("Hive->BlockListSize: %lu\n", Hive->BlockListSize);
825 DPRINT("BitmapSize: %lu Bytes %lu Bits\n", BitmapSize, BitmapSize * 8);
826
827 /* Allocate bitmap */
828 Hive->BitmapBuffer = (PULONG)ExAllocatePool(PagedPool,
829 BitmapSize);
830 if (Hive->BitmapBuffer == NULL)
831 {
832 return STATUS_INSUFFICIENT_RESOURCES;
833 }
834
835 RtlInitializeBitMap(&Hive->DirtyBitMap,
836 Hive->BitmapBuffer,
837 BitmapSize * 8);
838
839 /* Initialize bitmap */
840 RtlClearAllBits(&Hive->DirtyBitMap);
841 Hive->HiveDirty = FALSE;
842
843 return STATUS_SUCCESS;
844 }
845
846
847 static NTSTATUS
848 CmiInitNonVolatileRegistryHive (PREGISTRY_HIVE RegistryHive,
849 PWSTR Filename)
850 {
851 OBJECT_ATTRIBUTES ObjectAttributes;
852 ULONG CreateDisposition;
853 IO_STATUS_BLOCK IoSB;
854 HANDLE FileHandle;
855 PSECTION_OBJECT SectionObject;
856 PUCHAR ViewBase;
857 ULONG ViewSize;
858 NTSTATUS Status;
859
860 DPRINT("CmiInitNonVolatileRegistryHive(%p, %S) called\n",
861 RegistryHive, Filename);
862
863 /* Duplicate Filename */
864 Status = RtlCreateUnicodeString(&RegistryHive->HiveFileName,
865 Filename);
866 if (!NT_SUCCESS(Status))
867 {
868 DPRINT("RtlCreateUnicodeString() failed (Status %lx)\n", Status);
869 return(Status);
870 }
871
872 /* Create log file name */
873 RegistryHive->LogFileName.Length = (wcslen(Filename) + 4) * sizeof(WCHAR);
874 RegistryHive->LogFileName.MaximumLength = RegistryHive->LogFileName.Length + sizeof(WCHAR);
875 RegistryHive->LogFileName.Buffer = ExAllocatePool(NonPagedPool,
876 RegistryHive->LogFileName.MaximumLength);
877 if (RegistryHive->LogFileName.Buffer == NULL)
878 {
879 RtlFreeUnicodeString(&RegistryHive->HiveFileName);
880 DPRINT("ExAllocatePool() failed\n");
881 return(STATUS_INSUFFICIENT_RESOURCES);
882 }
883 wcscpy(RegistryHive->LogFileName.Buffer,
884 Filename);
885 wcscat(RegistryHive->LogFileName.Buffer,
886 L".log");
887
888 #ifdef HIVE_CHECK
889 /* Check and eventually fix a hive */
890 Status = CmiCheckAndFixHive(RegistryHive);
891 if (!NT_SUCCESS(Status))
892 {
893 RtlFreeUnicodeString(&RegistryHive->HiveFileName);
894 RtlFreeUnicodeString(&RegistryHive->LogFileName);
895 DPRINT1("CmiCheckAndFixHive() failed (Status %lx)\n", Status);
896 return(Status);
897 }
898 #endif
899
900 InitializeObjectAttributes(&ObjectAttributes,
901 &RegistryHive->HiveFileName,
902 OBJ_CASE_INSENSITIVE,
903 NULL,
904 NULL);
905
906 CreateDisposition = FILE_OPEN_IF;
907 Status = NtCreateFile(&FileHandle,
908 FILE_ALL_ACCESS,
909 &ObjectAttributes,
910 &IoSB,
911 NULL,
912 FILE_ATTRIBUTE_NORMAL,
913 0,
914 CreateDisposition,
915 FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT,
916 NULL,
917 0);
918 if (!NT_SUCCESS(Status))
919 {
920 RtlFreeUnicodeString(&RegistryHive->HiveFileName);
921 RtlFreeUnicodeString(&RegistryHive->LogFileName);
922 DPRINT("NtCreateFile() failed (Status %lx)\n", Status);
923 return(Status);
924 }
925
926 if (IoSB.Information != FILE_OPENED)
927 {
928 Status = CmiCreateNewRegFile(FileHandle);
929 if (!NT_SUCCESS(Status))
930 {
931 DPRINT("CmiCreateNewRegFile() failed (Status %lx)\n", Status);
932 NtClose(FileHandle);
933 RtlFreeUnicodeString(&RegistryHive->HiveFileName);
934 RtlFreeUnicodeString(&RegistryHive->LogFileName);
935 return(Status);
936 }
937 }
938
939 /* Create the hive section */
940 Status = MmCreateSection(&SectionObject,
941 SECTION_ALL_ACCESS,
942 NULL,
943 NULL,
944 PAGE_READWRITE,
945 SEC_COMMIT,
946 FileHandle,
947 NULL);
948 if (!NT_SUCCESS(Status))
949 {
950 DPRINT1("MmCreateSection() failed (Status %lx)\n", Status);
951 RtlFreeUnicodeString(&RegistryHive->HiveFileName);
952 RtlFreeUnicodeString(&RegistryHive->LogFileName);
953 return(Status);
954 }
955
956 /* Map the hive file */
957 ViewBase = NULL;
958 ViewSize = 0;
959 Status = MmMapViewOfSection(SectionObject,
960 PsGetCurrentProcess(),
961 (PVOID*)&ViewBase,
962 0,
963 ViewSize,
964 NULL,
965 &ViewSize,
966 0,
967 MEM_COMMIT,
968 PAGE_READWRITE);
969 if (!NT_SUCCESS(Status))
970 {
971 DPRINT1("MmMapViewOfSection() failed (Status %lx)\n", Status);
972 ObDereferenceObject(SectionObject);
973 RtlFreeUnicodeString(&RegistryHive->HiveFileName);
974 RtlFreeUnicodeString(&RegistryHive->LogFileName);
975 NtClose(FileHandle);
976 return(Status);
977 }
978 DPRINT("ViewBase %p ViewSize %lx\n", ViewBase, ViewSize);
979
980 /* Copy hive header and initalize hive */
981 RtlCopyMemory (RegistryHive->HiveHeader,
982 ViewBase,
983 sizeof(HIVE_HEADER));
984 RegistryHive->FileSize = ViewSize;
985 RegistryHive->BlockListSize = (RegistryHive->FileSize / REG_BLOCK_SIZE) - 1;
986 RegistryHive->UpdateCounter = RegistryHive->HiveHeader->UpdateCounter1;
987
988 /* Allocate hive block list */
989 RegistryHive->BlockList = ExAllocatePool(NonPagedPool,
990 RegistryHive->BlockListSize * sizeof(BLOCK_LIST_ENTRY));
991 if (RegistryHive->BlockList == NULL)
992 {
993 DPRINT1("Failed to allocate the hive block list\n");
994 MmUnmapViewOfSection(PsGetCurrentProcess(),
995 ViewBase);
996 ObDereferenceObject(SectionObject);
997 RtlFreeUnicodeString(&RegistryHive->HiveFileName);
998 RtlFreeUnicodeString(&RegistryHive->LogFileName);
999 NtClose(FileHandle);
1000 return STATUS_INSUFFICIENT_RESOURCES;
1001 }
1002 RtlZeroMemory (RegistryHive->BlockList,
1003 RegistryHive->BlockListSize * sizeof(BLOCK_LIST_ENTRY));
1004
1005 /* Import the hive bins */
1006 Status = CmiImportHiveBins (RegistryHive,
1007 ViewBase + REG_BLOCK_SIZE);
1008 if (!NT_SUCCESS(Status))
1009 {
1010 ExFreePool(RegistryHive->BlockList);
1011 MmUnmapViewOfSection(PsGetCurrentProcess(),
1012 ViewBase);
1013 ObDereferenceObject(SectionObject);
1014 RtlFreeUnicodeString(&RegistryHive->HiveFileName);
1015 RtlFreeUnicodeString(&RegistryHive->LogFileName);
1016 NtClose(FileHandle);
1017 return Status;
1018 }
1019
1020 /* Unmap and dereference the hive section */
1021 MmUnmapViewOfSection(PsGetCurrentProcess(),
1022 ViewBase);
1023 ObDereferenceObject(SectionObject);
1024
1025 /* Close the hive file */
1026 NtClose(FileHandle);
1027
1028 /* Initialize the free cell list */
1029 Status = CmiCreateHiveFreeCellList (RegistryHive);
1030 if (!NT_SUCCESS(Status))
1031 {
1032 CmiFreeHiveBins(RegistryHive);
1033 ExFreePool(RegistryHive->BlockList);
1034 RtlFreeUnicodeString(&RegistryHive->HiveFileName);
1035 RtlFreeUnicodeString(&RegistryHive->LogFileName);
1036 return Status;
1037 }
1038
1039 /* Create the block bitmap */
1040 Status = CmiCreateHiveBitmap (RegistryHive);
1041 if (!NT_SUCCESS(Status))
1042 {
1043 CmiFreeHiveFreeCellList(RegistryHive);
1044 CmiFreeHiveBins(RegistryHive);
1045 ExFreePool(RegistryHive->BlockList);
1046 RtlFreeUnicodeString(&RegistryHive->HiveFileName);
1047 RtlFreeUnicodeString(&RegistryHive->LogFileName);
1048 return Status;
1049 }
1050
1051 DPRINT("CmiInitNonVolatileRegistryHive(%p, %S) - Finished.\n",
1052 RegistryHive, Filename);
1053
1054 return STATUS_SUCCESS;
1055 }
1056
1057
1058 NTSTATUS
1059 CmiCreateVolatileHive(PREGISTRY_HIVE *RegistryHive)
1060 {
1061 PKEY_CELL RootKeyCell;
1062 PREGISTRY_HIVE Hive;
1063
1064 *RegistryHive = NULL;
1065
1066 Hive = ExAllocatePool (NonPagedPool,
1067 sizeof(REGISTRY_HIVE));
1068 if (Hive == NULL)
1069 return STATUS_INSUFFICIENT_RESOURCES;
1070
1071 RtlZeroMemory (Hive,
1072 sizeof(REGISTRY_HIVE));
1073
1074 DPRINT("Hive %x\n", Hive);
1075
1076 Hive->HiveHeader = (PHIVE_HEADER)ExAllocatePool (NonPagedPool,
1077 sizeof(HIVE_HEADER));
1078 if (Hive->HiveHeader == NULL)
1079 {
1080 ExFreePool (Hive);
1081 return STATUS_INSUFFICIENT_RESOURCES;
1082 }
1083 RtlZeroMemory (Hive->HiveHeader,
1084 sizeof(HIVE_HEADER));
1085
1086 Hive->Flags = (HIVE_NO_FILE | HIVE_POINTER);
1087
1088 CmiCreateDefaultHiveHeader (Hive->HiveHeader);
1089
1090 RootKeyCell = (PKEY_CELL)ExAllocatePool (NonPagedPool,
1091 sizeof(KEY_CELL));
1092 if (RootKeyCell == NULL)
1093 {
1094 ExFreePool(Hive->HiveHeader);
1095 ExFreePool(Hive);
1096 return STATUS_INSUFFICIENT_RESOURCES;
1097 }
1098
1099 CmiCreateDefaultRootKeyCell (RootKeyCell);
1100 Hive->HiveHeader->RootKeyOffset = (BLOCK_OFFSET)RootKeyCell;
1101
1102 ExInitializeResourceLite (&Hive->HiveResource);
1103
1104 /* Acquire hive list lock exclusively */
1105 KeEnterCriticalRegion();
1106 ExAcquireResourceExclusiveLite (&CmiHiveListLock,
1107 TRUE);
1108
1109 /* Add the new hive to the hive list */
1110 InsertTailList (&CmiHiveListHead,
1111 &Hive->HiveList);
1112
1113 /* Release hive list lock */
1114 ExReleaseResourceLite (&CmiHiveListLock);
1115 KeLeaveCriticalRegion();
1116
1117 VERIFY_REGISTRY_HIVE (Hive);
1118
1119 *RegistryHive = Hive;
1120
1121 return STATUS_SUCCESS;
1122 }
1123
1124
1125 NTSTATUS
1126 CmiCreateTempHive(PREGISTRY_HIVE *RegistryHive)
1127 {
1128 PHBIN BinHeader;
1129 PCELL_HEADER FreeCell;
1130 PREGISTRY_HIVE Hive;
1131 NTSTATUS Status;
1132
1133 DPRINT ("CmiCreateTempHive() called\n");
1134
1135 *RegistryHive = NULL;
1136
1137 Hive = ExAllocatePool (NonPagedPool,
1138 sizeof(REGISTRY_HIVE));
1139 if (Hive == NULL)
1140 {
1141 DPRINT1 ("Failed to allocate registry hive block\n");
1142 return STATUS_INSUFFICIENT_RESOURCES;
1143 }
1144 RtlZeroMemory (Hive,
1145 sizeof(REGISTRY_HIVE));
1146
1147 DPRINT ("Hive %x\n", Hive);
1148
1149 Hive->HiveHeader = (PHIVE_HEADER)ExAllocatePool (NonPagedPool,
1150 REG_BLOCK_SIZE);
1151 if (Hive->HiveHeader == NULL)
1152 {
1153 DPRINT1 ("Failed to allocate hive header block\n");
1154 ExFreePool (Hive);
1155 return STATUS_INSUFFICIENT_RESOURCES;
1156 }
1157 RtlZeroMemory (Hive->HiveHeader,
1158 REG_BLOCK_SIZE);
1159
1160 DPRINT ("HiveHeader %x\n", Hive->HiveHeader);
1161
1162 Hive->Flags = HIVE_NO_FILE;
1163
1164 RtlInitUnicodeString (&Hive->HiveFileName,
1165 NULL);
1166 RtlInitUnicodeString (&Hive->LogFileName,
1167 NULL);
1168
1169 CmiCreateDefaultHiveHeader (Hive->HiveHeader);
1170
1171 /* Allocate hive block list */
1172 Hive->BlockList = ExAllocatePool (NonPagedPool,
1173 sizeof(PBLOCK_LIST_ENTRY));
1174 if (Hive->BlockList == NULL)
1175 {
1176 DPRINT1 ("Failed to allocate hive block list\n");
1177 ExFreePool(Hive->HiveHeader);
1178 ExFreePool(Hive);
1179 return STATUS_INSUFFICIENT_RESOURCES;
1180 }
1181
1182 /* Allocate first Bin */
1183 Hive->BlockList[0].Bin = ExAllocatePool (NonPagedPool,
1184 REG_BLOCK_SIZE);
1185 if (Hive->BlockList[0].Bin == NULL)
1186 {
1187 DPRINT1 ("Failed to allocate first bin\n");
1188 ExFreePool(Hive->BlockList);
1189 ExFreePool(Hive->HiveHeader);
1190 ExFreePool(Hive);
1191 return STATUS_INSUFFICIENT_RESOURCES;
1192 }
1193 Hive->BlockList[0].Block = (PVOID)Hive->BlockList[0].Bin;
1194
1195 Hive->FileSize = 2* REG_BLOCK_SIZE;
1196 Hive->BlockListSize = 1;
1197 Hive->UpdateCounter = Hive->HiveHeader->UpdateCounter1;
1198
1199
1200 BinHeader = Hive->BlockList[0].Bin;
1201 FreeCell = (PCELL_HEADER)((ULONG_PTR)BinHeader + REG_HBIN_DATA_OFFSET);
1202
1203 CmiCreateDefaultBinHeader (BinHeader);
1204
1205 /* First block */
1206 BinHeader->BinOffset = 0;
1207
1208 /* Offset to root key block */
1209 Hive->HiveHeader->RootKeyOffset = (BLOCK_OFFSET)-1;
1210
1211 /* The rest of the block is free */
1212 FreeCell->CellSize = REG_BLOCK_SIZE - REG_HBIN_DATA_OFFSET;
1213
1214 /* Create the free cell list */
1215 Status = CmiCreateHiveFreeCellList (Hive);
1216 if (Hive->BlockList[0].Bin == NULL)
1217 {
1218 DPRINT1 ("CmiCreateHiveFreeCellList() failed (Status %lx)\n", Status);
1219 ExFreePool(Hive->BlockList[0].Bin);
1220 ExFreePool(Hive->BlockList);
1221 ExFreePool(Hive->HiveHeader);
1222 ExFreePool(Hive);
1223 return Status;
1224 }
1225
1226
1227 ExInitializeResourceLite (&Hive->HiveResource);
1228
1229 /* Acquire hive list lock exclusively */
1230 KeEnterCriticalRegion();
1231 ExAcquireResourceExclusiveLite (&CmiHiveListLock,
1232 TRUE);
1233
1234 /* Add the new hive to the hive list */
1235 InsertTailList (&CmiHiveListHead,
1236 &Hive->HiveList);
1237
1238 /* Release hive list lock */
1239 ExReleaseResourceLite (&CmiHiveListLock);
1240 KeLeaveCriticalRegion();
1241
1242 VERIFY_REGISTRY_HIVE (Hive);
1243
1244 *RegistryHive = Hive;
1245
1246 return STATUS_SUCCESS;
1247 }
1248
1249
1250 NTSTATUS
1251 CmiLoadHive(IN POBJECT_ATTRIBUTES KeyObjectAttributes,
1252 IN PUNICODE_STRING FileName,
1253 IN ULONG Flags)
1254 {
1255 PREGISTRY_HIVE Hive;
1256 NTSTATUS Status;
1257
1258 DPRINT ("CmiLoadHive(Filename %wZ)\n", FileName);
1259
1260 if (Flags & ~REG_NO_LAZY_FLUSH)
1261 return STATUS_INVALID_PARAMETER;
1262
1263 Hive = ExAllocatePool (NonPagedPool,
1264 sizeof(REGISTRY_HIVE));
1265 if (Hive == NULL)
1266 {
1267 DPRINT1 ("Failed to allocate hive header.\n");
1268 return STATUS_INSUFFICIENT_RESOURCES;
1269 }
1270 RtlZeroMemory (Hive,
1271 sizeof(REGISTRY_HIVE));
1272
1273 DPRINT ("Hive %x\n", Hive);
1274 Hive->Flags = (Flags & REG_NO_LAZY_FLUSH) ? HIVE_NO_SYNCH : 0;
1275
1276 Hive->HiveHeader = (PHIVE_HEADER)ExAllocatePool(NonPagedPool,
1277 sizeof(HIVE_HEADER));
1278 if (Hive->HiveHeader == NULL)
1279 {
1280 DPRINT1 ("Failed to allocate hive header.\n");
1281 ExFreePool (Hive);
1282 return STATUS_INSUFFICIENT_RESOURCES;
1283 }
1284
1285 RtlZeroMemory (Hive->HiveHeader,
1286 sizeof(HIVE_HEADER));
1287
1288 Status = CmiInitNonVolatileRegistryHive (Hive,
1289 FileName->Buffer);
1290 if (!NT_SUCCESS (Status))
1291 {
1292 DPRINT1 ("CmiInitNonVolatileRegistryHive() failed (Status %lx)\n", Status);
1293 ExFreePool (Hive->HiveHeader);
1294 ExFreePool (Hive);
1295 return Status;
1296 }
1297
1298 ExInitializeResourceLite (&Hive->HiveResource);
1299
1300 /* Add the new hive to the hive list */
1301 KeEnterCriticalRegion();
1302 ExAcquireResourceExclusiveLite (&CmiHiveListLock,
1303 TRUE);
1304 InsertTailList (&CmiHiveListHead,
1305 &Hive->HiveList);
1306 ExReleaseResourceLite (&CmiHiveListLock);
1307 KeLeaveCriticalRegion();
1308
1309
1310 VERIFY_REGISTRY_HIVE(Hive);
1311
1312
1313 Status = CmiConnectHive (KeyObjectAttributes,
1314 Hive);
1315 if (!NT_SUCCESS(Status))
1316 {
1317 DPRINT1 ("CmiConnectHive() failed (Status %lx)\n", Status);
1318 // CmiRemoveRegistryHive (Hive);
1319 }
1320
1321 DPRINT ("CmiLoadHive() done\n");
1322
1323 return Status;
1324 }
1325
1326
1327 NTSTATUS
1328 CmiRemoveRegistryHive(PREGISTRY_HIVE RegistryHive)
1329 {
1330 if (RegistryHive->Flags & HIVE_POINTER)
1331 return STATUS_UNSUCCESSFUL;
1332
1333 /* Acquire hive list lock exclusively */
1334 KeEnterCriticalRegion();
1335 ExAcquireResourceExclusiveLite (&CmiHiveListLock,
1336 TRUE);
1337
1338 /* Remove hive from hive list */
1339 RemoveEntryList (&RegistryHive->HiveList);
1340
1341 /* Release hive list lock */
1342 ExReleaseResourceLite (&CmiHiveListLock);
1343 KeLeaveCriticalRegion();
1344
1345 /* Release file names */
1346 RtlFreeUnicodeString (&RegistryHive->HiveFileName);
1347 RtlFreeUnicodeString (&RegistryHive->LogFileName);
1348
1349 /* Release hive bitmap */
1350 ExFreePool (RegistryHive->BitmapBuffer);
1351
1352 /* Release free cell list */
1353 ExFreePool (RegistryHive->FreeList);
1354 ExFreePool (RegistryHive->FreeListOffset);
1355
1356 /* Release hive resource */
1357 ExDeleteResource (&RegistryHive->HiveResource);
1358
1359 /* Release bins and bin list */
1360 CmiFreeHiveBins (RegistryHive);
1361 ExFreePool (RegistryHive->BlockList);
1362
1363 /* Release hive header */
1364 ExFreePool (RegistryHive->HiveHeader);
1365
1366 /* Release hive */
1367 ExFreePool (RegistryHive);
1368
1369 return STATUS_SUCCESS;
1370 }
1371
1372
1373 static ULONG
1374 CmiCalcChecksum(PULONG Buffer)
1375 {
1376 ULONG Sum = 0;
1377 ULONG i;
1378
1379 for (i = 0; i < 127; i++)
1380 Sum += Buffer[i];
1381
1382 return(Sum);
1383 }
1384
1385
1386 static NTSTATUS
1387 CmiStartLogUpdate(PREGISTRY_HIVE RegistryHive)
1388 {
1389 FILE_END_OF_FILE_INFORMATION EndOfFileInfo;
1390 FILE_ALLOCATION_INFORMATION FileAllocationInfo;
1391 OBJECT_ATTRIBUTES ObjectAttributes;
1392 IO_STATUS_BLOCK IoStatusBlock;
1393 HANDLE FileHandle;
1394 LARGE_INTEGER FileOffset;
1395 ULONG BufferSize;
1396 ULONG BitmapSize;
1397 PUCHAR Buffer;
1398 PUCHAR Ptr;
1399 ULONG BlockIndex;
1400 PVOID BlockPtr;
1401 NTSTATUS Status;
1402
1403 DPRINT("CmiStartLogUpdate() called\n");
1404
1405 BitmapSize = ROUND_UP(RegistryHive->BlockListSize, sizeof(ULONG) * 8) / 8;
1406 BufferSize = sizeof(HIVE_HEADER) +
1407 sizeof(ULONG) +
1408 BitmapSize;
1409 BufferSize = ROUND_UP(BufferSize, REG_BLOCK_SIZE);
1410
1411 DPRINT("Bitmap size %lu buffer size: %lu\n", BitmapSize, BufferSize);
1412
1413 Buffer = (PUCHAR)ExAllocatePool(NonPagedPool,
1414 BufferSize);
1415 if (Buffer == NULL)
1416 {
1417 DPRINT("ExAllocatePool() failed\n");
1418 return(STATUS_INSUFFICIENT_RESOURCES);
1419 }
1420 RtlZeroMemory (Buffer,
1421 BufferSize);
1422
1423 /* Open log file for writing */
1424 InitializeObjectAttributes(&ObjectAttributes,
1425 &RegistryHive->LogFileName,
1426 OBJ_CASE_INSENSITIVE,
1427 NULL,
1428 NULL);
1429
1430 Status = NtCreateFile(&FileHandle,
1431 FILE_ALL_ACCESS,
1432 &ObjectAttributes,
1433 &IoStatusBlock,
1434 NULL,
1435 FILE_ATTRIBUTE_NORMAL,
1436 0,
1437 FILE_SUPERSEDE,
1438 FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT,
1439 NULL,
1440 0);
1441 if (!NT_SUCCESS(Status))
1442 {
1443 DPRINT("NtCreateFile() failed (Status %lx)\n", Status);
1444 ExFreePool(Buffer);
1445 return(Status);
1446 }
1447
1448 /* Update firt update counter and checksum */
1449 RegistryHive->HiveHeader->UpdateCounter1 = RegistryHive->UpdateCounter + 1;
1450 RegistryHive->HiveHeader->Checksum = CmiCalcChecksum((PULONG)RegistryHive->HiveHeader);
1451
1452 /* Copy hive header */
1453 RtlCopyMemory(Buffer,
1454 RegistryHive->HiveHeader,
1455 sizeof(HIVE_HEADER));
1456 Ptr = Buffer + sizeof(HIVE_HEADER);
1457
1458 RtlCopyMemory(Ptr,
1459 "DIRT",
1460 4);
1461 Ptr += 4;
1462 RtlCopyMemory(Ptr,
1463 RegistryHive->DirtyBitMap.Buffer,
1464 BitmapSize);
1465
1466 /* Write hive block and block bitmap */
1467 FileOffset.QuadPart = (ULONGLONG)0;
1468 Status = NtWriteFile(FileHandle,
1469 NULL,
1470 NULL,
1471 NULL,
1472 &IoStatusBlock,
1473 Buffer,
1474 BufferSize,
1475 &FileOffset,
1476 NULL);
1477 if (!NT_SUCCESS(Status))
1478 {
1479 DPRINT("NtWriteFile() failed (Status %lx)\n", Status);
1480 NtClose(FileHandle);
1481 ExFreePool(Buffer);
1482 return(Status);
1483 }
1484 ExFreePool(Buffer);
1485
1486 /* Write dirty blocks */
1487 FileOffset.QuadPart = (ULONGLONG)BufferSize;
1488 BlockIndex = 0;
1489 while (TRUE)
1490 {
1491 BlockIndex = RtlFindSetBits(&RegistryHive->DirtyBitMap,
1492 1,
1493 BlockIndex);
1494 if ((BlockIndex == (ULONG)-1) ||
1495 (BlockIndex >= RegistryHive->BlockListSize))
1496 {
1497 DPRINT("No more set bits\n");
1498 Status = STATUS_SUCCESS;
1499 break;
1500 }
1501
1502 DPRINT("Block %lu is dirty\n", BlockIndex);
1503
1504 BlockPtr = RegistryHive->BlockList[BlockIndex].Block;
1505 DPRINT("BlockPtr %p\n", BlockPtr);
1506 DPRINT("File offset %I64x\n", FileOffset.QuadPart);
1507
1508 /* Write hive block */
1509 Status = NtWriteFile(FileHandle,
1510 NULL,
1511 NULL,
1512 NULL,
1513 &IoStatusBlock,
1514 BlockPtr,
1515 REG_BLOCK_SIZE,
1516 &FileOffset,
1517 NULL);
1518 if (!NT_SUCCESS(Status))
1519 {
1520 DPRINT1("NtWriteFile() failed (Status %lx)\n", Status);
1521 NtClose(FileHandle);
1522 return(Status);
1523 }
1524
1525 BlockIndex++;
1526 FileOffset.QuadPart += (ULONGLONG)REG_BLOCK_SIZE;
1527 }
1528
1529 /* Truncate log file */
1530 EndOfFileInfo.EndOfFile.QuadPart = FileOffset.QuadPart;
1531 Status = NtSetInformationFile(FileHandle,
1532 &IoStatusBlock,
1533 &EndOfFileInfo,
1534 sizeof(FILE_END_OF_FILE_INFORMATION),
1535 FileEndOfFileInformation);
1536 if (!NT_SUCCESS(Status))
1537 {
1538 DPRINT("NtSetInformationFile() failed (Status %lx)\n", Status);
1539 NtClose(FileHandle);
1540 return(Status);
1541 }
1542
1543 FileAllocationInfo.AllocationSize.QuadPart = FileOffset.QuadPart;
1544 Status = NtSetInformationFile(FileHandle,
1545 &IoStatusBlock,
1546 &FileAllocationInfo,
1547 sizeof(FILE_ALLOCATION_INFORMATION),
1548 FileAllocationInformation);
1549 if (!NT_SUCCESS(Status))
1550 {
1551 DPRINT("NtSetInformationFile() failed (Status %lx)\n", Status);
1552 NtClose(FileHandle);
1553 return(Status);
1554 }
1555
1556 /* Flush the log file */
1557 Status = NtFlushBuffersFile(FileHandle,
1558 &IoStatusBlock);
1559 if (!NT_SUCCESS(Status))
1560 {
1561 DPRINT("NtFlushBuffersFile() failed (Status %lx)\n", Status);
1562 }
1563
1564 NtClose(FileHandle);
1565
1566 return(Status);
1567 }
1568
1569
1570 static NTSTATUS
1571 CmiFinishLogUpdate(PREGISTRY_HIVE RegistryHive)
1572 {
1573 OBJECT_ATTRIBUTES ObjectAttributes;
1574 IO_STATUS_BLOCK IoStatusBlock;
1575 HANDLE FileHandle;
1576 LARGE_INTEGER FileOffset;
1577 ULONG BufferSize;
1578 ULONG BitmapSize;
1579 PUCHAR Buffer;
1580 PUCHAR Ptr;
1581 NTSTATUS Status;
1582
1583 DPRINT("CmiFinishLogUpdate() called\n");
1584
1585 BitmapSize = ROUND_UP(RegistryHive->BlockListSize, sizeof(ULONG) * 8) / 8;
1586 BufferSize = sizeof(HIVE_HEADER) +
1587 sizeof(ULONG) +
1588 BitmapSize;
1589 BufferSize = ROUND_UP(BufferSize, REG_BLOCK_SIZE);
1590
1591 DPRINT("Bitmap size %lu buffer size: %lu\n", BitmapSize, BufferSize);
1592
1593 Buffer = (PUCHAR)ExAllocatePool(NonPagedPool, BufferSize);
1594 if (Buffer == NULL)
1595 {
1596 DPRINT("ExAllocatePool() failed\n");
1597 return(STATUS_INSUFFICIENT_RESOURCES);
1598 }
1599
1600 /* Open log file for writing */
1601 InitializeObjectAttributes(&ObjectAttributes,
1602 &RegistryHive->LogFileName,
1603 OBJ_CASE_INSENSITIVE,
1604 NULL,
1605 NULL);
1606
1607 Status = NtCreateFile(&FileHandle,
1608 FILE_ALL_ACCESS,
1609 &ObjectAttributes,
1610 &IoStatusBlock,
1611 NULL,
1612 FILE_ATTRIBUTE_NORMAL,
1613 0,
1614 FILE_OPEN,
1615 FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT,
1616 NULL,
1617 0);
1618 if (!NT_SUCCESS(Status))
1619 {
1620 DPRINT("NtCreateFile() failed (Status %lx)\n", Status);
1621 ExFreePool(Buffer);
1622 return(Status);
1623 }
1624
1625 /* Update first and second update counter and checksum */
1626 RegistryHive->HiveHeader->UpdateCounter1 = RegistryHive->UpdateCounter + 1;
1627 RegistryHive->HiveHeader->UpdateCounter2 = RegistryHive->UpdateCounter + 1;
1628 RegistryHive->HiveHeader->Checksum = CmiCalcChecksum((PULONG)RegistryHive->HiveHeader);
1629
1630 /* Copy hive header */
1631 RtlCopyMemory(Buffer,
1632 RegistryHive->HiveHeader,
1633 sizeof(HIVE_HEADER));
1634 Ptr = Buffer + sizeof(HIVE_HEADER);
1635
1636 /* Write empty block bitmap */
1637 RtlCopyMemory(Ptr,
1638 "DIRT",
1639 4);
1640 Ptr += 4;
1641 RtlZeroMemory(Ptr,
1642 BitmapSize);
1643
1644 /* Write hive block and block bitmap */
1645 FileOffset.QuadPart = (ULONGLONG)0;
1646 Status = NtWriteFile(FileHandle,
1647 NULL,
1648 NULL,
1649 NULL,
1650 &IoStatusBlock,
1651 Buffer,
1652 BufferSize,
1653 &FileOffset,
1654 NULL);
1655 if (!NT_SUCCESS(Status))
1656 {
1657 DPRINT("NtWriteFile() failed (Status %lx)\n", Status);
1658 NtClose(FileHandle);
1659 ExFreePool(Buffer);
1660 return(Status);
1661 }
1662
1663 ExFreePool(Buffer);
1664
1665 /* Flush the log file */
1666 Status = NtFlushBuffersFile(FileHandle,
1667 &IoStatusBlock);
1668 if (!NT_SUCCESS(Status))
1669 {
1670 DPRINT("NtFlushBuffersFile() failed (Status %lx)\n", Status);
1671 }
1672
1673 NtClose(FileHandle);
1674
1675 return(Status);
1676 }
1677
1678
1679 static NTSTATUS
1680 CmiCleanupLogUpdate(PREGISTRY_HIVE RegistryHive)
1681 {
1682 FILE_END_OF_FILE_INFORMATION EndOfFileInfo;
1683 FILE_ALLOCATION_INFORMATION FileAllocationInfo;
1684 OBJECT_ATTRIBUTES ObjectAttributes;
1685 IO_STATUS_BLOCK IoStatusBlock;
1686 HANDLE FileHandle;
1687 ULONG BufferSize;
1688 ULONG BitmapSize;
1689 NTSTATUS Status;
1690
1691 DPRINT("CmiCleanupLogUpdate() called\n");
1692
1693 BitmapSize = ROUND_UP(RegistryHive->BlockListSize, sizeof(ULONG) * 8) / 8;
1694 BufferSize = sizeof(HIVE_HEADER) +
1695 sizeof(ULONG) +
1696 BitmapSize;
1697 BufferSize = ROUND_UP(BufferSize, REG_BLOCK_SIZE);
1698
1699 DPRINT("Bitmap size %lu buffer size: %lu\n", BitmapSize, BufferSize);
1700
1701 /* Open log file for writing */
1702 InitializeObjectAttributes(&ObjectAttributes,
1703 &RegistryHive->LogFileName,
1704 OBJ_CASE_INSENSITIVE,
1705 NULL,
1706 NULL);
1707
1708 Status = NtCreateFile(&FileHandle,
1709 FILE_ALL_ACCESS,
1710 &ObjectAttributes,
1711 &IoStatusBlock,
1712 NULL,
1713 FILE_ATTRIBUTE_NORMAL,
1714 0,
1715 FILE_OPEN,
1716 FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT,
1717 NULL,
1718 0);
1719 if (!NT_SUCCESS(Status))
1720 {
1721 DPRINT("NtCreateFile() failed (Status %lx)\n", Status);
1722 return(Status);
1723 }
1724
1725 /* Truncate log file */
1726 EndOfFileInfo.EndOfFile.QuadPart = (ULONGLONG)BufferSize;
1727 Status = NtSetInformationFile(FileHandle,
1728 &IoStatusBlock,
1729 &EndOfFileInfo,
1730 sizeof(FILE_END_OF_FILE_INFORMATION),
1731 FileEndOfFileInformation);
1732 if (!NT_SUCCESS(Status))
1733 {
1734 DPRINT("NtSetInformationFile() failed (Status %lx)\n", Status);
1735 NtClose(FileHandle);
1736 return(Status);
1737 }
1738
1739 FileAllocationInfo.AllocationSize.QuadPart = (ULONGLONG)BufferSize;
1740 Status = NtSetInformationFile(FileHandle,
1741 &IoStatusBlock,
1742 &FileAllocationInfo,
1743 sizeof(FILE_ALLOCATION_INFORMATION),
1744 FileAllocationInformation);
1745 if (!NT_SUCCESS(Status))
1746 {
1747 DPRINT("NtSetInformationFile() failed (Status %lx)\n", Status);
1748 NtClose(FileHandle);
1749 return(Status);
1750 }
1751
1752 /* Flush the log file */
1753 Status = NtFlushBuffersFile(FileHandle,
1754 &IoStatusBlock);
1755 if (!NT_SUCCESS(Status))
1756 {
1757 DPRINT("NtFlushBuffersFile() failed (Status %lx)\n", Status);
1758 }
1759
1760 NtClose(FileHandle);
1761
1762 return(Status);
1763 }
1764
1765
1766 static NTSTATUS
1767 CmiStartHiveUpdate(PREGISTRY_HIVE RegistryHive)
1768 {
1769 OBJECT_ATTRIBUTES ObjectAttributes;
1770 IO_STATUS_BLOCK IoStatusBlock;
1771 HANDLE FileHandle;
1772 LARGE_INTEGER FileOffset;
1773 ULONG BlockIndex;
1774 PVOID BlockPtr;
1775 NTSTATUS Status;
1776
1777 DPRINT("CmiStartHiveUpdate() called\n");
1778
1779 /* Open hive for writing */
1780 InitializeObjectAttributes(&ObjectAttributes,
1781 &RegistryHive->HiveFileName,
1782 OBJ_CASE_INSENSITIVE,
1783 NULL,
1784 NULL);
1785
1786 Status = NtCreateFile(&FileHandle,
1787 FILE_ALL_ACCESS,
1788 &ObjectAttributes,
1789 &IoStatusBlock,
1790 NULL,
1791 FILE_ATTRIBUTE_NORMAL,
1792 0,
1793 FILE_OPEN,
1794 FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT,
1795 NULL,
1796 0);
1797 if (!NT_SUCCESS(Status))
1798 {
1799 DPRINT("NtCreateFile() failed (Status %lx)\n", Status);
1800 return(Status);
1801 }
1802
1803 /* Update firt update counter and checksum */
1804 RegistryHive->HiveHeader->UpdateCounter1 = RegistryHive->UpdateCounter + 1;
1805 RegistryHive->HiveHeader->Checksum = CmiCalcChecksum((PULONG)RegistryHive->HiveHeader);
1806
1807 /* Write hive block */
1808 FileOffset.QuadPart = (ULONGLONG)0;
1809 Status = NtWriteFile(FileHandle,
1810 NULL,
1811 NULL,
1812 NULL,
1813 &IoStatusBlock,
1814 RegistryHive->HiveHeader,
1815 sizeof(HIVE_HEADER),
1816 &FileOffset,
1817 NULL);
1818 if (!NT_SUCCESS(Status))
1819 {
1820 DPRINT("NtWriteFile() failed (Status %lx)\n", Status);
1821 NtClose(FileHandle);
1822 return(Status);
1823 }
1824
1825 BlockIndex = 0;
1826 while (TRUE)
1827 {
1828 BlockIndex = RtlFindSetBits(&RegistryHive->DirtyBitMap,
1829 1,
1830 BlockIndex);
1831 if ((BlockIndex == (ULONG)-1) ||
1832 (BlockIndex >= RegistryHive->BlockListSize))
1833 {
1834 DPRINT("No more set bits\n");
1835 Status = STATUS_SUCCESS;
1836 break;
1837 }
1838
1839 DPRINT("Block %lu is dirty\n", BlockIndex);
1840
1841 BlockPtr = RegistryHive->BlockList[BlockIndex].Block;
1842 DPRINT(" BlockPtr %p\n", BlockPtr);
1843
1844 FileOffset.QuadPart = (ULONGLONG)(BlockIndex + 1) * (ULONGLONG)REG_BLOCK_SIZE;
1845 DPRINT(" File offset %I64x\n", FileOffset.QuadPart);
1846
1847 /* Write hive block */
1848 Status = NtWriteFile(FileHandle,
1849 NULL,
1850 NULL,
1851 NULL,
1852 &IoStatusBlock,
1853 BlockPtr,
1854 REG_BLOCK_SIZE,
1855 &FileOffset,
1856 NULL);
1857 if (!NT_SUCCESS(Status))
1858 {
1859 DPRINT("NtWriteFile() failed (Status %lx)\n", Status);
1860 NtClose(FileHandle);
1861 return(Status);
1862 }
1863
1864 BlockIndex++;
1865 }
1866
1867 Status = NtFlushBuffersFile(FileHandle,
1868 &IoStatusBlock);
1869 if (!NT_SUCCESS(Status))
1870 {
1871 DPRINT("NtFlushBuffersFile() failed (Status %lx)\n", Status);
1872 }
1873
1874 NtClose(FileHandle);
1875
1876 return(Status);
1877 }
1878
1879
1880 static NTSTATUS
1881 CmiFinishHiveUpdate(PREGISTRY_HIVE RegistryHive)
1882 {
1883 OBJECT_ATTRIBUTES ObjectAttributes;
1884 IO_STATUS_BLOCK IoStatusBlock;
1885 LARGE_INTEGER FileOffset;
1886 HANDLE FileHandle;
1887 NTSTATUS Status;
1888
1889 DPRINT("CmiFinishHiveUpdate() called\n");
1890
1891 InitializeObjectAttributes(&ObjectAttributes,
1892 &RegistryHive->HiveFileName,
1893 OBJ_CASE_INSENSITIVE,
1894 NULL,
1895 NULL);
1896
1897 Status = NtCreateFile(&FileHandle,
1898 FILE_ALL_ACCESS,
1899 &ObjectAttributes,
1900 &IoStatusBlock,
1901 NULL,
1902 FILE_ATTRIBUTE_NORMAL,
1903 0,
1904 FILE_OPEN,
1905 FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT,
1906 NULL,
1907 0);
1908 if (!NT_SUCCESS(Status))
1909 {
1910 DPRINT("NtCreateFile() failed (Status %lx)\n", Status);
1911 return(Status);
1912 }
1913
1914 /* Update second update counter and checksum */
1915 RegistryHive->HiveHeader->UpdateCounter1 = RegistryHive->UpdateCounter + 1;
1916 RegistryHive->HiveHeader->UpdateCounter2 = RegistryHive->UpdateCounter + 1;
1917 RegistryHive->HiveHeader->Checksum = CmiCalcChecksum((PULONG)RegistryHive->HiveHeader);
1918
1919 /* Write hive block */
1920 FileOffset.QuadPart = (ULONGLONG)0;
1921 Status = NtWriteFile(FileHandle,
1922 NULL,
1923 NULL,
1924 NULL,
1925 &IoStatusBlock,
1926 RegistryHive->HiveHeader,
1927 sizeof(HIVE_HEADER),
1928 &FileOffset,
1929 NULL);
1930 if (!NT_SUCCESS(Status))
1931 {
1932 DPRINT("NtWriteFile() failed (Status %lx)\n", Status);
1933 NtClose(FileHandle);
1934 return(Status);
1935 }
1936
1937 Status = NtFlushBuffersFile(FileHandle,
1938 &IoStatusBlock);
1939 if (!NT_SUCCESS(Status))
1940 {
1941 DPRINT("NtFlushBuffersFile() failed (Status %lx)\n", Status);
1942 }
1943
1944 NtClose(FileHandle);
1945
1946 return(Status);
1947 }
1948
1949
1950 NTSTATUS
1951 CmiFlushRegistryHive(PREGISTRY_HIVE RegistryHive)
1952 {
1953 NTSTATUS Status;
1954
1955 DPRINT("CmiFlushRegistryHive() called\n");
1956
1957 if (RegistryHive->HiveDirty == FALSE)
1958 {
1959 return(STATUS_SUCCESS);
1960 }
1961
1962 DPRINT("Hive '%wZ' is dirty\n",
1963 &RegistryHive->HiveFileName);
1964 DPRINT("Log file: '%wZ'\n",
1965 &RegistryHive->LogFileName);
1966
1967 /* Update hive header modification time */
1968 NtQuerySystemTime(&RegistryHive->HiveHeader->DateModified);
1969
1970 /* Start log update */
1971 Status = CmiStartLogUpdate(RegistryHive);
1972 if (!NT_SUCCESS(Status))
1973 {
1974 DPRINT("CmiStartLogUpdate() failed (Status %lx)\n", Status);
1975 return(Status);
1976 }
1977
1978 /* Finish log update */
1979 Status = CmiFinishLogUpdate(RegistryHive);
1980 if (!NT_SUCCESS(Status))
1981 {
1982 DPRINT("CmiFinishLogUpdate() failed (Status %lx)\n", Status);
1983 return(Status);
1984 }
1985
1986 /* Start hive update */
1987 Status = CmiStartHiveUpdate(RegistryHive);
1988 if (!NT_SUCCESS(Status))
1989 {
1990 DPRINT("CmiStartHiveUpdate() failed (Status %lx)\n", Status);
1991 return(Status);
1992 }
1993
1994 /* Finish the hive update */
1995 Status = CmiFinishHiveUpdate(RegistryHive);
1996 if (!NT_SUCCESS(Status))
1997 {
1998 DPRINT("CmiFinishHiveUpdate() failed (Status %lx)\n", Status);
1999 return(Status);
2000 }
2001
2002 /* Cleanup log update */
2003 Status = CmiCleanupLogUpdate(RegistryHive);
2004 if (!NT_SUCCESS(Status))
2005 {
2006 DPRINT("CmiFinishLogUpdate() failed (Status %lx)\n", Status);
2007 return(Status);
2008 }
2009
2010 /* Increment hive update counter */
2011 RegistryHive->UpdateCounter++;
2012
2013 /* Clear dirty bitmap and dirty flag */
2014 RtlClearAllBits(&RegistryHive->DirtyBitMap);
2015 RegistryHive->HiveDirty = FALSE;
2016
2017 DPRINT("CmiFlushRegistryHive() done\n");
2018
2019 return(STATUS_SUCCESS);
2020 }
2021
2022
2023 ULONG
2024 CmiGetNumberOfSubKeys(PKEY_OBJECT KeyObject)
2025 {
2026 PKEY_OBJECT CurKey;
2027 PKEY_CELL KeyCell;
2028 ULONG SubKeyCount;
2029 ULONG i;
2030
2031 VERIFY_KEY_OBJECT(KeyObject);
2032
2033 KeyCell = KeyObject->KeyCell;
2034 VERIFY_KEY_CELL(KeyCell);
2035
2036 SubKeyCount = (KeyCell == NULL) ? 0 : KeyCell->NumberOfSubKeys;
2037
2038 /* Search for volatile or 'foreign' keys */
2039 for (i = 0; i < KeyObject->NumberOfSubKeys; i++)
2040 {
2041 CurKey = KeyObject->SubKeys[i];
2042 if (CurKey->RegistryHive == CmiVolatileHive ||
2043 CurKey->RegistryHive != KeyObject->RegistryHive)
2044 {
2045 SubKeyCount++;
2046 }
2047 }
2048
2049 return SubKeyCount;
2050 }
2051
2052
2053 ULONG
2054 CmiGetMaxNameLength(PKEY_OBJECT KeyObject)
2055 {
2056 PHASH_TABLE_CELL HashBlock;
2057 PKEY_OBJECT CurKey;
2058 PKEY_CELL CurSubKeyCell;
2059 PKEY_CELL KeyCell;
2060 ULONG MaxName;
2061 ULONG NameSize;
2062 ULONG i;
2063
2064 VERIFY_KEY_OBJECT(KeyObject);
2065
2066 KeyCell = KeyObject->KeyCell;
2067 VERIFY_KEY_CELL(KeyCell);
2068
2069 MaxName = 0;
2070 HashBlock = CmiGetCell (KeyObject->RegistryHive,
2071 KeyCell->HashTableOffset,
2072 NULL);
2073 if (HashBlock == NULL)
2074 {
2075 DPRINT("CmiGetBlock() failed\n");
2076 }
2077 else
2078 {
2079 for (i = 0; i < HashBlock->HashTableSize; i++)
2080 {
2081 if (HashBlock->Table[i].KeyOffset != 0)
2082 {
2083 CurSubKeyCell = CmiGetCell (KeyObject->RegistryHive,
2084 HashBlock->Table[i].KeyOffset,
2085 NULL);
2086 if (CurSubKeyCell == NULL)
2087 {
2088 DPRINT("CmiGetBlock() failed\n");
2089 continue;
2090 }
2091
2092 NameSize = CurSubKeyCell->NameSize;
2093 if (CurSubKeyCell->Flags & REG_KEY_NAME_PACKED)
2094 {
2095 NameSize *= sizeof(WCHAR);
2096 }
2097
2098 if (NameSize > MaxName)
2099 {
2100 MaxName = NameSize;
2101 }
2102 }
2103 }
2104 }
2105
2106 DPRINT ("KeyObject->NumberOfSubKeys %d\n", KeyObject->NumberOfSubKeys);
2107 for (i = 0; i < KeyObject->NumberOfSubKeys; i++)
2108 {
2109 CurKey = KeyObject->SubKeys[i];
2110 if (CurKey->RegistryHive == CmiVolatileHive ||
2111 CurKey->RegistryHive != KeyObject->RegistryHive)
2112 {
2113 CurSubKeyCell = CurKey->KeyCell;
2114 if (CurSubKeyCell == NULL)
2115 {
2116 DPRINT("CmiGetBlock() failed\n");
2117 continue;
2118 }
2119
2120 if ((CurSubKeyCell->Flags & REG_KEY_ROOT_CELL) == REG_KEY_ROOT_CELL)
2121 {
2122 /* Use name of the key object */
2123 NameSize = CurKey->Name.Length;
2124 }
2125 else
2126 {
2127 /* Use name of the key cell */
2128 NameSize = CurSubKeyCell->NameSize;
2129 if (CurSubKeyCell->Flags & REG_KEY_NAME_PACKED)
2130 {
2131 NameSize *= sizeof(WCHAR);
2132 }
2133 }
2134 DPRINT ("NameSize %lu\n", NameSize);
2135
2136 if (NameSize > MaxName)
2137 {
2138 MaxName = NameSize;
2139 }
2140 }
2141 }
2142
2143 DPRINT ("MaxName %lu\n", MaxName);
2144
2145 return MaxName;
2146 }
2147
2148
2149 ULONG
2150 CmiGetMaxClassLength(PKEY_OBJECT KeyObject)
2151 {
2152 PHASH_TABLE_CELL HashBlock;
2153 PKEY_OBJECT CurKey;
2154 PKEY_CELL CurSubKeyCell;
2155 PKEY_CELL KeyCell;
2156 ULONG MaxClass;
2157 ULONG i;
2158
2159 VERIFY_KEY_OBJECT(KeyObject);
2160
2161 KeyCell = KeyObject->KeyCell;
2162 VERIFY_KEY_CELL(KeyCell);
2163
2164 MaxClass = 0;
2165 HashBlock = CmiGetCell (KeyObject->RegistryHive,
2166 KeyCell->HashTableOffset,
2167 NULL);
2168 if (HashBlock == NULL)
2169 {
2170 DPRINT("CmiGetBlock() failed\n");
2171 }
2172 else
2173 {
2174 for (i = 0; i < HashBlock->HashTableSize; i++)
2175 {
2176 if (HashBlock->Table[i].KeyOffset != 0)
2177 {
2178 CurSubKeyCell = CmiGetCell (KeyObject->RegistryHive,
2179 HashBlock->Table[i].KeyOffset,
2180 NULL);
2181 if (CurSubKeyCell == NULL)
2182 {
2183 DPRINT("CmiGetBlock() failed\n");
2184 continue;
2185 }
2186
2187 if (MaxClass < CurSubKeyCell->ClassSize)
2188 {
2189 MaxClass = CurSubKeyCell->ClassSize;
2190 }
2191 }
2192 }
2193 }
2194
2195 DPRINT("KeyObject->NumberOfSubKeys %d\n", KeyObject->NumberOfSubKeys);
2196 for (i = 0; i < KeyObject->NumberOfSubKeys; i++)
2197 {
2198 CurKey = KeyObject->SubKeys[i];
2199 if (CurKey->RegistryHive == CmiVolatileHive ||
2200 CurKey->RegistryHive != KeyObject->RegistryHive)
2201 {
2202 CurSubKeyCell = CurKey->KeyCell;
2203 if (CurSubKeyCell == NULL)
2204 {
2205 DPRINT("CmiGetBlock() failed\n");
2206 continue;
2207 }
2208
2209 if (MaxClass < CurSubKeyCell->ClassSize)
2210 {
2211 MaxClass = CurSubKeyCell->ClassSize;
2212 }
2213 }
2214 }
2215
2216 return MaxClass;
2217 }
2218
2219
2220 ULONG
2221 CmiGetMaxValueNameLength(PREGISTRY_HIVE RegistryHive,
2222 PKEY_CELL KeyCell)
2223 {
2224 PVALUE_LIST_CELL ValueListCell;
2225 PVALUE_CELL CurValueCell;
2226 ULONG MaxValueName;
2227 ULONG Size;
2228 ULONG i;
2229
2230 VERIFY_KEY_CELL(KeyCell);
2231
2232 MaxValueName = 0;
2233 ValueListCell = CmiGetCell (RegistryHive,
2234 KeyCell->ValueListOffset,
2235 NULL);
2236 if (ValueListCell == NULL)
2237 {
2238 DPRINT("CmiGetBlock() failed\n");
2239 return 0;
2240 }
2241
2242 for (i = 0; i < KeyCell->NumberOfValues; i++)
2243 {
2244 CurValueCell = CmiGetCell (RegistryHive,
2245 ValueListCell->ValueOffset[i],
2246 NULL);
2247 if (CurValueCell == NULL)
2248 {
2249 DPRINT("CmiGetBlock() failed\n");
2250 }
2251
2252 if (CurValueCell != NULL)
2253 {
2254 Size = CurValueCell->NameSize;
2255 if (CurValueCell->Flags & REG_VALUE_NAME_PACKED)
2256 {
2257 Size *= sizeof(WCHAR);
2258 }
2259 if (MaxValueName < Size)
2260 {
2261 MaxValueName = Size;
2262 }
2263 }
2264 }
2265
2266 return MaxValueName;
2267 }
2268
2269
2270 ULONG
2271 CmiGetMaxValueDataLength(PREGISTRY_HIVE RegistryHive,
2272 PKEY_CELL KeyCell)
2273 {
2274 PVALUE_LIST_CELL ValueListCell;
2275 PVALUE_CELL CurValueCell;
2276 LONG MaxValueData;
2277 ULONG i;
2278
2279 VERIFY_KEY_CELL(KeyCell);
2280
2281 MaxValueData = 0;
2282 ValueListCell = CmiGetCell (RegistryHive, KeyCell->ValueListOffset, NULL);
2283 if (ValueListCell == NULL)
2284 {
2285 return 0;
2286 }
2287
2288 for (i = 0; i < KeyCell->NumberOfValues; i++)
2289 {
2290 CurValueCell = CmiGetCell (RegistryHive,
2291 ValueListCell->ValueOffset[i],NULL);
2292 if ((CurValueCell != NULL) &&
2293 (MaxValueData < (LONG)(CurValueCell->DataSize & REG_DATA_SIZE_MASK)))
2294 {
2295 MaxValueData = CurValueCell->DataSize & REG_DATA_SIZE_MASK;
2296 }
2297 }
2298
2299 return MaxValueData;
2300 }
2301
2302
2303 NTSTATUS
2304 CmiScanForSubKey(IN PREGISTRY_HIVE RegistryHive,
2305 IN PKEY_CELL KeyCell,
2306 OUT PKEY_CELL *SubKeyCell,
2307 OUT BLOCK_OFFSET *BlockOffset,
2308 IN PUNICODE_STRING KeyName,
2309 IN ACCESS_MASK DesiredAccess,
2310 IN ULONG Attributes)
2311 {
2312 PHASH_TABLE_CELL HashBlock;
2313 PKEY_CELL CurSubKeyCell;
2314 ULONG i;
2315
2316 VERIFY_KEY_CELL(KeyCell);
2317
2318 DPRINT("Scanning for sub key %wZ\n", KeyName);
2319
2320 assert(RegistryHive);
2321
2322 *SubKeyCell = NULL;
2323
2324 /* The key does not have any subkeys */
2325 if (KeyCell->HashTableOffset == (BLOCK_OFFSET)-1)
2326 {
2327 return STATUS_SUCCESS;
2328 }
2329
2330 /* Get hash table */
2331 HashBlock = CmiGetCell (RegistryHive, KeyCell->HashTableOffset, NULL);
2332 if (HashBlock == NULL)
2333 {
2334 DPRINT("CmiGetBlock() failed\n");
2335 return STATUS_UNSUCCESSFUL;
2336 }
2337
2338 for (i = 0; (i < KeyCell->NumberOfSubKeys) && (i < HashBlock->HashTableSize); i++)
2339 {
2340 if (Attributes & OBJ_CASE_INSENSITIVE)
2341 {
2342 if (HashBlock->Table[i].KeyOffset != 0 &&
2343 HashBlock->Table[i].KeyOffset != (ULONG_PTR)-1 &&
2344 (HashBlock->Table[i].HashValue == 0 ||
2345 CmiCompareHashI(KeyName, (PCHAR)&HashBlock->Table[i].HashValue)))
2346 {
2347 CurSubKeyCell = CmiGetCell (RegistryHive,
2348 HashBlock->Table[i].KeyOffset,
2349 NULL);
2350 if (CurSubKeyCell == NULL)
2351 {
2352 DPRINT("CmiGetBlock() failed\n");
2353 return STATUS_UNSUCCESSFUL;
2354 }
2355
2356 if (CmiCompareKeyNamesI(KeyName, CurSubKeyCell))
2357 {
2358 *SubKeyCell = CurSubKeyCell;
2359 *BlockOffset = HashBlock->Table[i].KeyOffset;
2360 break;
2361 }
2362 }
2363 }
2364 else
2365 {
2366 if (HashBlock->Table[i].KeyOffset != 0 &&
2367 HashBlock->Table[i].KeyOffset != (ULONG_PTR) -1 &&
2368 (HashBlock->Table[i].HashValue == 0 ||
2369 CmiCompareHash(KeyName, (PCHAR)&HashBlock->Table[i].HashValue)))
2370 {
2371 CurSubKeyCell = CmiGetCell (RegistryHive,
2372 HashBlock->Table[i].KeyOffset,
2373 NULL);
2374 if (CurSubKeyCell == NULL)
2375 {
2376 DPRINT("CmiGetBlock() failed\n");
2377 return STATUS_UNSUCCESSFUL;
2378 }
2379
2380 if (CmiCompareKeyNames(KeyName, CurSubKeyCell))
2381 {
2382 *SubKeyCell = CurSubKeyCell;
2383 *BlockOffset = HashBlock->Table[i].KeyOffset;
2384 break;
2385 }
2386 }
2387 }
2388 }
2389
2390 return STATUS_SUCCESS;
2391 }
2392
2393
2394 NTSTATUS
2395 CmiAddSubKey(PREGISTRY_HIVE RegistryHive,
2396 PKEY_OBJECT ParentKey,
2397 PKEY_OBJECT SubKey,
2398 PUNICODE_STRING SubKeyName,
2399 ULONG TitleIndex,
2400 PUNICODE_STRING Class,
2401 ULONG CreateOptions)
2402 {
2403 PHASH_TABLE_CELL HashBlock;
2404 BLOCK_OFFSET NKBOffset;
2405 PKEY_CELL NewKeyCell;
2406 ULONG NewBlockSize;
2407 PKEY_CELL ParentKeyCell;
2408 PDATA_CELL ClassCell;
2409 NTSTATUS Status;
2410 USHORT NameSize;
2411 PWSTR NamePtr;
2412 BOOLEAN Packable;
2413 ULONG i;
2414
2415 ParentKeyCell = ParentKey->KeyCell;
2416
2417 VERIFY_KEY_CELL(ParentKeyCell);
2418
2419 /* Skip leading backslash */
2420 if (SubKeyName->Buffer[0] == L'\\')
2421 {
2422 NamePtr = &SubKeyName->Buffer[1];
2423 NameSize = SubKeyName->Length - sizeof(WCHAR);
2424 }
2425 else
2426 {
2427 NamePtr = SubKeyName->Buffer;
2428 NameSize = SubKeyName->Length;
2429 }
2430
2431 /* Check whether key name can be packed */
2432 Packable = TRUE;
2433 for (i = 0; i < NameSize / sizeof(WCHAR); i++)
2434 {
2435 if (NamePtr[i] & 0xFF00)
2436 {
2437 Packable = FALSE;
2438 break;
2439 }
2440 }
2441
2442 /* Adjust name size */
2443 if (Packable)
2444 {
2445 NameSize = NameSize / sizeof(WCHAR);
2446 }
2447
2448 DPRINT("Key %S Length %lu %s\n", NamePtr, NameSize, (Packable)?"True":"False");
2449
2450 Status = STATUS_SUCCESS;
2451
2452 NewBlockSize = sizeof(KEY_CELL) + NameSize;
2453 Status = CmiAllocateCell (RegistryHive,
2454 NewBlockSize,
2455 (PVOID) &NewKeyCell,
2456 &NKBOffset);
2457 if (NewKeyCell == NULL)
2458 {
2459 Status = STATUS_INSUFFICIENT_RESOURCES;
2460 }
2461 else
2462 {
2463 NewKeyCell->Id = REG_KEY_CELL_ID;
2464 NewKeyCell->Flags = 0;
2465 NtQuerySystemTime(&NewKeyCell->LastWriteTime);
2466 NewKeyCell->ParentKeyOffset = -1;
2467 NewKeyCell->NumberOfSubKeys = 0;
2468 NewKeyCell->HashTableOffset = -1;
2469 NewKeyCell->NumberOfValues = 0;
2470 NewKeyCell->ValueListOffset = -1;
2471 NewKeyCell->SecurityKeyOffset = -1;
2472 NewKeyCell->ClassNameOffset = -1;
2473
2474 /* Pack the key name */
2475 NewKeyCell->NameSize = NameSize;
2476 if (Packable)
2477 {
2478 NewKeyCell->Flags |= REG_KEY_NAME_PACKED;
2479 for (i = 0; i < NameSize; i++)
2480 {
2481 NewKeyCell->Name[i] = (CHAR)(NamePtr[i] & 0x00FF);
2482 }
2483 }
2484 else
2485 {
2486 RtlCopyMemory(NewKeyCell->Name,
2487 NamePtr,
2488 NameSize);
2489 }
2490
2491 VERIFY_KEY_CELL(NewKeyCell);
2492
2493 if (Class != NULL)
2494 {
2495 NewKeyCell->ClassSize = Class->Length;
2496 Status = CmiAllocateCell (RegistryHive,
2497 sizeof(CELL_HEADER) + NewKeyCell->ClassSize,
2498 (PVOID)&ClassCell,
2499 &NewKeyCell->ClassNameOffset);
2500 RtlCopyMemory (ClassCell->Data,
2501 Class->Buffer,
2502 Class->Length);
2503 }
2504 }
2505
2506 if (!NT_SUCCESS(Status))
2507 {
2508 return Status;
2509 }
2510
2511 SubKey->KeyCell = NewKeyCell;
2512 SubKey->KeyCellOffset = NKBOffset;
2513
2514 /* Don't modify hash table if key is located in a pointer-based hive and parent key is not */
2515 if (IsPointerHive(RegistryHive) && (!IsPointerHive(ParentKey->RegistryHive)))
2516 {
2517 return(Status);
2518 }
2519
2520 if (ParentKeyCell->HashTableOffset == (ULONG_PTR) -1)
2521 {
2522 Status = CmiAllocateHashTableCell (RegistryHive,
2523 &HashBlock,
2524 &ParentKeyCell->HashTableOffset,
2525 REG_INIT_HASH_TABLE_SIZE);
2526 if (!NT_SUCCESS(Status))
2527 {
2528 return(Status);
2529 }
2530 }
2531 else
2532 {
2533 HashBlock = CmiGetCell (RegistryHive,
2534 ParentKeyCell->HashTableOffset,
2535 NULL);
2536 if (HashBlock == NULL)
2537 {
2538 DPRINT("CmiGetCell() failed\n");
2539 return STATUS_UNSUCCESSFUL;
2540 }
2541
2542 if (((ParentKeyCell->NumberOfSubKeys + 1) >= HashBlock->HashTableSize))
2543 {
2544 PHASH_TABLE_CELL NewHashBlock;
2545 BLOCK_OFFSET HTOffset;
2546
2547 /* Reallocate the hash table cell */
2548 Status = CmiAllocateHashTableCell (RegistryHive,
2549 &NewHashBlock,
2550 &HTOffset,
2551 HashBlock->HashTableSize +
2552 REG_EXTEND_HASH_TABLE_SIZE);
2553 if (!NT_SUCCESS(Status))
2554 {
2555 return Status;
2556 }
2557
2558 RtlZeroMemory(&NewHashBlock->Table[0],
2559 sizeof(NewHashBlock->Table[0]) * NewHashBlock->HashTableSize);
2560 RtlCopyMemory(&NewHashBlock->Table[0],
2561 &HashBlock->Table[0],
2562 sizeof(NewHashBlock->Table[0]) * HashBlock->HashTableSize);
2563 CmiDestroyCell (RegistryHive,
2564 HashBlock,
2565 ParentKeyCell->HashTableOffset);
2566 ParentKeyCell->HashTableOffset = HTOffset;
2567 HashBlock = NewHashBlock;
2568 }
2569 }
2570
2571 Status = CmiAddKeyToHashTable(RegistryHive,
2572 HashBlock,
2573 ParentKeyCell->HashTableOffset,
2574 NewKeyCell,
2575 NKBOffset);
2576 if (NT_SUCCESS(Status))
2577 {
2578 ParentKeyCell->NumberOfSubKeys++;
2579 }
2580
2581 NtQuerySystemTime (&ParentKeyCell->LastWriteTime);
2582 CmiMarkBlockDirty (RegistryHive, ParentKey->KeyCellOffset);
2583
2584 return(Status);
2585 }
2586
2587
2588 NTSTATUS
2589 CmiRemoveSubKey(PREGISTRY_HIVE RegistryHive,
2590 PKEY_OBJECT ParentKey,
2591 PKEY_OBJECT SubKey)
2592 {
2593 PHASH_TABLE_CELL HashBlock;
2594 PVALUE_LIST_CELL ValueList;
2595 PVALUE_CELL ValueCell;
2596 PDATA_CELL DataCell;
2597 ULONG i;
2598
2599 DPRINT("CmiRemoveSubKey() called\n");
2600
2601 /* Remove all values */
2602 if (SubKey->KeyCell->NumberOfValues != 0)
2603 {
2604 /* Get pointer to the value list cell */
2605 ValueList = CmiGetCell (RegistryHive,
2606 SubKey->KeyCell->ValueListOffset,
2607 NULL);
2608 if (ValueList == NULL)
2609 {
2610 DPRINT("CmiGetCell() failed\n");
2611 return STATUS_UNSUCCESSFUL;
2612 }
2613
2614 /* Enumerate all values */
2615 for (i = 0; i < SubKey->KeyCell->NumberOfValues; i++)
2616 {
2617 /* Get pointer to value cell */
2618 ValueCell = CmiGetCell(RegistryHive,
2619 ValueList->ValueOffset[i],
2620 NULL);
2621 if (ValueCell == NULL)
2622 {
2623 DPRINT("CmiGetCell() failed\n");
2624 return STATUS_UNSUCCESSFUL;
2625 }
2626
2627 if (ValueCell->DataSize > sizeof(BLOCK_OFFSET))
2628 {
2629 DataCell = CmiGetCell (RegistryHive,
2630 ValueCell->DataOffset,
2631 NULL);
2632 if (DataCell == NULL)
2633 {
2634 DPRINT("CmiGetCell() failed\n");
2635 return STATUS_UNSUCCESSFUL;
2636 }
2637
2638 if (DataCell != NULL)
2639 {
2640 /* Destroy data cell */
2641 CmiDestroyCell (RegistryHive,
2642 DataCell,
2643 ValueCell->DataOffset);
2644 }
2645 }
2646
2647 /* Destroy value cell */
2648 CmiDestroyCell (RegistryHive,
2649 ValueCell,
2650 ValueList->ValueOffset[i]);
2651 }
2652
2653 /* Destroy value list cell */
2654 CmiDestroyCell (RegistryHive,
2655 ValueList,
2656 SubKey->KeyCell->ValueListOffset);
2657
2658 SubKey->KeyCell->NumberOfValues = 0;
2659 SubKey->KeyCell->ValueListOffset = (BLOCK_OFFSET)-1;
2660
2661 CmiMarkBlockDirty(RegistryHive,
2662 SubKey->KeyCellOffset);
2663 }
2664
2665 /* Remove the key from the parent key's hash block */
2666 if (ParentKey->KeyCell->HashTableOffset != (BLOCK_OFFSET) -1)
2667 {
2668 DPRINT("ParentKey HashTableOffset %lx\n", ParentKey->KeyCell->HashTableOffset);
2669 HashBlock = CmiGetCell (ParentKey->RegistryHive,
2670 ParentKey->KeyCell->HashTableOffset,
2671 NULL);
2672 if (HashBlock == NULL)
2673 {
2674 DPRINT("CmiGetCell() failed\n");
2675 return STATUS_UNSUCCESSFUL;
2676 }
2677 DPRINT("ParentKey HashBlock %p\n", HashBlock);
2678 if (HashBlock != NULL)
2679 {
2680 CmiRemoveKeyFromHashTable(ParentKey->RegistryHive,
2681 HashBlock,
2682 SubKey->KeyCellOffset);
2683 CmiMarkBlockDirty(ParentKey->RegistryHive,
2684 ParentKey->KeyCell->HashTableOffset);
2685 }
2686 }
2687
2688 /* Remove the key's hash block */
2689 if (SubKey->KeyCell->HashTableOffset != (BLOCK_OFFSET) -1)
2690 {
2691 DPRINT("SubKey HashTableOffset %lx\n", SubKey->KeyCell->HashTableOffset);
2692 HashBlock = CmiGetCell (RegistryHive,
2693 SubKey->KeyCell->HashTableOffset,
2694 NULL);
2695 if (HashBlock == NULL)
2696 {
2697 DPRINT("CmiGetCell() failed\n");
2698 return STATUS_UNSUCCESSFUL;
2699 }
2700 DPRINT("SubKey HashBlock %p\n", HashBlock);
2701 if (HashBlock != NULL)
2702 {
2703 CmiDestroyCell (RegistryHive,
2704 HashBlock,
2705 SubKey->KeyCell->HashTableOffset);
2706 SubKey->KeyCell->HashTableOffset = -1;
2707 }
2708 }
2709
2710 /* Decrement the number of the parent key's sub keys */
2711 if (ParentKey != NULL)
2712 {
2713 DPRINT("ParentKey %p\n", ParentKey);
2714 ParentKey->KeyCell->NumberOfSubKeys--;
2715
2716 /* Remove the parent key's hash table */
2717 if (ParentKey->KeyCell->NumberOfSubKeys == 0)
2718 {
2719 DPRINT("ParentKey HashTableOffset %lx\n", ParentKey->KeyCell->HashTableOffset);
2720 HashBlock = CmiGetCell (ParentKey->RegistryHive,
2721 ParentKey->KeyCell->HashTableOffset,
2722 NULL);
2723 if (HashBlock == NULL)
2724 {
2725 DPRINT("CmiGetCell() failed\n");
2726 return STATUS_UNSUCCESSFUL;
2727 }
2728 DPRINT("ParentKey HashBlock %p\n", HashBlock);
2729 if (HashBlock != NULL)
2730 {
2731 CmiDestroyCell (ParentKey->RegistryHive,
2732 HashBlock,
2733 ParentKey->KeyCell->HashTableOffset);
2734 ParentKey->KeyCell->HashTableOffset = (BLOCK_OFFSET)-1;
2735 }
2736 }
2737
2738 NtQuerySystemTime(&ParentKey->KeyCell->LastWriteTime);
2739 CmiMarkBlockDirty(ParentKey->RegistryHive,
2740 ParentKey->KeyCellOffset);
2741 }
2742
2743 /* Destroy key cell */
2744 CmiDestroyCell (RegistryHive,
2745 SubKey->KeyCell,
2746 SubKey->KeyCellOffset);
2747 SubKey->KeyCell = NULL;
2748 SubKey->KeyCellOffset = (BLOCK_OFFSET)-1;
2749
2750 DPRINT("CmiRemoveSubKey() done\n");
2751
2752 return STATUS_SUCCESS;
2753 }
2754
2755
2756 NTSTATUS
2757 CmiScanKeyForValue(IN PREGISTRY_HIVE RegistryHive,
2758 IN PKEY_CELL KeyCell,
2759 IN PUNICODE_STRING ValueName,
2760 OUT PVALUE_CELL *ValueCell,
2761 OUT BLOCK_OFFSET *ValueCellOffset)
2762 {
2763 PVALUE_LIST_CELL ValueListCell;
2764 PVALUE_CELL CurValueCell;
2765 ULONG i;
2766
2767 *ValueCell = NULL;
2768 if (ValueCellOffset != NULL)
2769 *ValueCellOffset = (BLOCK_OFFSET)-1;
2770
2771 /* The key does not have any values */
2772 if (KeyCell->ValueListOffset == (BLOCK_OFFSET)-1)
2773 {
2774 return STATUS_OBJECT_NAME_NOT_FOUND;
2775 }
2776
2777 ValueListCell = CmiGetCell (RegistryHive, KeyCell->ValueListOffset, NULL);
2778 if (ValueListCell == NULL)
2779 {
2780 DPRINT("ValueListCell is NULL\n");
2781 return STATUS_UNSUCCESSFUL;
2782 }
2783
2784 VERIFY_VALUE_LIST_CELL(ValueListCell);
2785
2786 for (i = 0; i < KeyCell->NumberOfValues; i++)
2787 {
2788 CurValueCell = CmiGetCell (RegistryHive,
2789 ValueListCell->ValueOffset[i],
2790 NULL);
2791 if (CurValueCell == NULL)
2792 {
2793 DPRINT("CmiGetBlock() failed\n");
2794 return STATUS_UNSUCCESSFUL;
2795 }
2796
2797 if ((CurValueCell != NULL) &&
2798 CmiComparePackedNames(ValueName,
2799 CurValueCell->Name,
2800 CurValueCell->NameSize,
2801 (BOOLEAN)((CurValueCell->Flags & REG_VALUE_NAME_PACKED) ? TRUE : FALSE)))
2802 {
2803 *ValueCell = CurValueCell;
2804 if (ValueCellOffset != NULL)
2805 *ValueCellOffset = ValueListCell->ValueOffset[i];
2806 //DPRINT("Found value %s\n", ValueName);
2807 return STATUS_SUCCESS;
2808 }
2809 }
2810
2811 return STATUS_OBJECT_NAME_NOT_FOUND;
2812 }
2813
2814
2815 NTSTATUS
2816 CmiGetValueFromKeyByIndex(IN PREGISTRY_HIVE RegistryHive,
2817 IN PKEY_CELL KeyCell,
2818 IN ULONG Index,
2819 OUT PVALUE_CELL *ValueCell)
2820 {
2821 PVALUE_LIST_CELL ValueListCell;
2822 PVALUE_CELL CurValueCell;
2823
2824 *ValueCell = NULL;
2825
2826 if (KeyCell->ValueListOffset == (BLOCK_OFFSET)-1)
2827 {
2828 return STATUS_NO_MORE_ENTRIES;
2829 }
2830
2831 if (Index >= KeyCell->NumberOfValues)
2832 {
2833 return STATUS_NO_MORE_ENTRIES;
2834 }
2835
2836
2837 ValueListCell = CmiGetCell (RegistryHive, KeyCell->ValueListOffset, NULL);
2838 if (ValueListCell == NULL)
2839 {
2840 DPRINT("CmiGetBlock() failed\n");
2841 return STATUS_UNSUCCESSFUL;
2842 }
2843
2844 VERIFY_VALUE_LIST_CELL(ValueListCell);
2845
2846
2847 CurValueCell = CmiGetCell (RegistryHive,
2848 ValueListCell->ValueOffset[Index],
2849 NULL);
2850 if (CurValueCell == NULL)
2851 {
2852 DPRINT("CmiGetBlock() failed\n");
2853 return STATUS_UNSUCCESSFUL;
2854 }
2855
2856 *ValueCell = CurValueCell;
2857
2858 return STATUS_SUCCESS;
2859 }
2860
2861
2862 NTSTATUS
2863 CmiAddValueToKey(IN PREGISTRY_HIVE RegistryHive,
2864 IN PKEY_CELL KeyCell,
2865 IN BLOCK_OFFSET KeyCellOffset,
2866 IN PUNICODE_STRING ValueName,
2867 OUT PVALUE_CELL *pValueCell,
2868 OUT BLOCK_OFFSET *pValueCellOffset)
2869 {
2870 PVALUE_LIST_CELL NewValueListCell;
2871 PVALUE_LIST_CELL ValueListCell;
2872 PVALUE_CELL NewValueCell;
2873 BLOCK_OFFSET NewValueListCellOffset;
2874 BLOCK_OFFSET ValueListCellOffset;
2875 BLOCK_OFFSET NewValueCellOffset;
2876 ULONG CellSize;
2877 NTSTATUS Status;
2878
2879 DPRINT("KeyCell->ValuesOffset %lu\n", (ULONG)KeyCell->ValueListOffset);
2880
2881 ValueListCell = CmiGetCell (RegistryHive, KeyCell->ValueListOffset, NULL);
2882 if (ValueListCell == NULL)
2883 {
2884 CellSize = sizeof(VALUE_LIST_CELL) +
2885 (3 * sizeof(BLOCK_OFFSET));
2886 Status = CmiAllocateCell (RegistryHive,
2887 CellSize,
2888 (PVOID) &ValueListCell,
2889 &ValueListCellOffset);
2890 if (!NT_SUCCESS(Status))
2891 {
2892 return Status;
2893 }
2894
2895 KeyCell->ValueListOffset = ValueListCellOffset;
2896 CmiMarkBlockDirty(RegistryHive, KeyCellOffset);
2897 CmiMarkBlockDirty(RegistryHive, ValueListCellOffset);
2898 }
2899 else if (KeyCell->NumberOfValues >=
2900 (((ULONG)ABS_VALUE(ValueListCell->CellSize) - sizeof(VALUE_LIST_CELL)) / sizeof(BLOCK_OFFSET)))
2901 {
2902 #if 0
2903 CellSize = sizeof(VALUE_LIST_CELL) +
2904 ((KeyCell->NumberOfValues + REG_VALUE_LIST_CELL_MULTIPLE) * sizeof(BLOCK_OFFSET));
2905 #endif
2906 CellSize = 2 * (ULONG)ABS_VALUE(ValueListCell->CellSize);
2907 Status = CmiAllocateCell (RegistryHive,
2908 CellSize,
2909 (PVOID) &NewValueListCell,
2910 &NewValueListCellOffset);
2911 if (!NT_SUCCESS(Status))
2912 {
2913 return Status;
2914 }
2915
2916 RtlCopyMemory(&NewValueListCell->ValueOffset[0],
2917 &ValueListCell->ValueOffset[0],
2918 sizeof(BLOCK_OFFSET) * KeyCell->NumberOfValues);
2919 CmiDestroyCell (RegistryHive, ValueListCell, KeyCell->ValueListOffset);
2920 CmiMarkBlockDirty (RegistryHive, KeyCell->ValueListOffset);
2921
2922 KeyCell->ValueListOffset = NewValueListCellOffset;
2923 ValueListCell = NewValueListCell;
2924 CmiMarkBlockDirty (RegistryHive, KeyCellOffset);
2925 CmiMarkBlockDirty (RegistryHive, NewValueListCellOffset);
2926 }
2927
2928 DPRINT("KeyCell->NumberOfValues %lu, ValueListCell->CellSize %lu (%lu %lx)\n",
2929 KeyCell->NumberOfValues,
2930 (ULONG)ABS_VALUE(ValueListCell->CellSize),
2931 ((ULONG)ABS_VALUE(ValueListCell->CellSize) - sizeof(VALUE_LIST_CELL)) / sizeof(BLOCK_OFFSET),
2932 ((ULONG)ABS_VALUE(ValueListCell->CellSize) - sizeof(VALUE_LIST_CELL)) / sizeof(BLOCK_OFFSET));
2933
2934 Status = CmiAllocateValueCell(RegistryHive,
2935 &NewValueCell,
2936 &NewValueCellOffset,
2937 ValueName);
2938 if (!NT_SUCCESS(Status))
2939 {
2940 return Status;
2941 }
2942
2943 ValueListCell->ValueOffset[KeyCell->NumberOfValues] = NewValueCellOffset;
2944 KeyCell->NumberOfValues++;
2945
2946 CmiMarkBlockDirty(RegistryHive, KeyCellOffset);
2947 CmiMarkBlockDirty(RegistryHive, KeyCell->ValueListOffset);
2948 CmiMarkBlockDirty(RegistryHive, NewValueCellOffset);
2949
2950 *pValueCell = NewValueCell;
2951 *pValueCellOffset = NewValueCellOffset;
2952
2953 return STATUS_SUCCESS;
2954 }
2955
2956
2957 NTSTATUS
2958 CmiDeleteValueFromKey(IN PREGISTRY_HIVE RegistryHive,
2959 IN PKEY_CELL KeyCell,
2960 IN BLOCK_OFFSET KeyCellOffset,
2961 IN PUNICODE_STRING ValueName)
2962 {
2963 PVALUE_LIST_CELL ValueListCell;
2964 PVALUE_CELL CurValueCell;
2965 ULONG i;
2966 NTSTATUS Status;
2967
2968 ValueListCell = CmiGetCell (RegistryHive, KeyCell->ValueListOffset, NULL);
2969 if (ValueListCell == NULL)
2970 {
2971 DPRINT1("CmiGetBlock() failed\n");
2972 return STATUS_SUCCESS;
2973 }
2974
2975 VERIFY_VALUE_LIST_CELL(ValueListCell);
2976
2977 for (i = 0; i < KeyCell->NumberOfValues; i++)
2978 {
2979 CurValueCell = CmiGetCell (RegistryHive, ValueListCell->ValueOffset[i], NULL);
2980 if (CurValueCell == NULL)
2981 {
2982 DPRINT1("CmiGetBlock() failed\n");
2983 return STATUS_UNSUCCESSFUL;
2984 }
2985
2986 if (CmiComparePackedNames(ValueName,
2987 CurValueCell->Name,
2988 CurValueCell->NameSize,
2989 (BOOLEAN)((CurValueCell->Flags & REG_VALUE_NAME_PACKED) ? TRUE : FALSE)))
2990 {
2991 Status = CmiDestroyValueCell(RegistryHive,
2992 CurValueCell,
2993 ValueListCell->ValueOffset[i]);
2994 if (CurValueCell == NULL)
2995 {
2996 DPRINT1("CmiDestroyValueCell() failed\n");
2997 return Status;
2998 }
2999
3000 if (i < (KeyCell->NumberOfValues - 1))
3001 {
3002 RtlMoveMemory(&ValueListCell->ValueOffset[i],
3003 &ValueListCell->ValueOffset[i + 1],
3004 sizeof(BLOCK_OFFSET) * (KeyCell->NumberOfValues - 1 - i));
3005 }
3006 ValueListCell->ValueOffset[KeyCell->NumberOfValues - 1] = 0;
3007
3008
3009 KeyCell->NumberOfValues--;
3010
3011 if (KeyCell->NumberOfValues == 0)
3012 {
3013 CmiDestroyCell(RegistryHive,
3014 ValueListCell,
3015 KeyCell->ValueListOffset);
3016 KeyCell->ValueListOffset = -1;
3017 }
3018 else
3019 {
3020 CmiMarkBlockDirty(RegistryHive,
3021 KeyCell->ValueListOffset);
3022 }
3023
3024 CmiMarkBlockDirty(RegistryHive,
3025 KeyCellOffset);
3026
3027 return STATUS_SUCCESS;
3028 }
3029 }
3030
3031 DPRINT("Couldn't find the desired value\n");
3032
3033 return STATUS_OBJECT_NAME_NOT_FOUND;
3034 }
3035
3036
3037 NTSTATUS
3038 CmiAllocateHashTableCell (IN PREGISTRY_HIVE RegistryHive,
3039 OUT PHASH_TABLE_CELL *HashBlock,
3040 OUT BLOCK_OFFSET *HBOffset,
3041 IN ULONG SubKeyCount)
3042 {
3043 PHASH_TABLE_CELL NewHashBlock;
3044 ULONG NewHashSize;
3045 NTSTATUS Status;
3046
3047 Status = STATUS_SUCCESS;
3048 *HashBlock = NULL;
3049 NewHashSize = sizeof(HASH_TABLE_CELL) +
3050 (SubKeyCount * sizeof(HASH_RECORD));
3051 Status = CmiAllocateCell (RegistryHive,
3052 NewHashSize,
3053 (PVOID*) &NewHashBlock,
3054 HBOffset);
3055
3056 if ((NewHashBlock == NULL) || (!NT_SUCCESS(Status)))
3057 {
3058 Status = STATUS_INSUFFICIENT_RESOURCES;
3059 }
3060 else
3061 {
3062 assert(SubKeyCount <= 0xffff); /* should really be USHORT_MAX or similar */
3063 NewHashBlock->Id = REG_HASH_TABLE_CELL_ID;
3064 NewHashBlock->HashTableSize = (USHORT)SubKeyCount;
3065 *HashBlock = NewHashBlock;
3066 }
3067
3068 return Status;
3069 }
3070
3071
3072 PKEY_CELL
3073 CmiGetKeyFromHashByIndex(PREGISTRY_HIVE RegistryHive,
3074 PHASH_TABLE_CELL HashBlock,
3075 ULONG Index)
3076 {
3077 BLOCK_OFFSET KeyOffset;
3078 PKEY_CELL KeyCell;
3079
3080 if (HashBlock == NULL)
3081 return NULL;
3082
3083 if (IsPointerHive(RegistryHive))
3084 {
3085 KeyCell = (PKEY_CELL) HashBlock->Table[Index].KeyOffset;
3086 }
3087 else
3088 {
3089 KeyOffset = HashBlock->Table[Index].KeyOffset;
3090 KeyCell = CmiGetCell (RegistryHive, KeyOffset, NULL);
3091 }
3092
3093 return KeyCell;
3094 }
3095
3096
3097 NTSTATUS
3098 CmiAddKeyToHashTable(PREGISTRY_HIVE RegistryHive,
3099 PHASH_TABLE_CELL HashCell,
3100 BLOCK_OFFSET HashCellOffset,
3101 PKEY_CELL NewKeyCell,
3102 BLOCK_OFFSET NKBOffset)
3103 {
3104 ULONG i;
3105
3106 for (i = 0; i < HashCell->HashTableSize; i++)
3107 {
3108 if (HashCell->Table[i].KeyOffset == 0)
3109 {
3110 HashCell->Table[i].KeyOffset = NKBOffset;
3111 HashCell->Table[i].HashValue = 0;
3112 if (NewKeyCell->Flags & REG_KEY_NAME_PACKED)
3113 {
3114 RtlCopyMemory(&HashCell->Table[i].HashValue,
3115 NewKeyCell->Name,
3116 min(NewKeyCell->NameSize, sizeof(ULONG)));
3117 }
3118 CmiMarkBlockDirty(RegistryHive, HashCellOffset);
3119 return STATUS_SUCCESS;
3120 }
3121 }
3122
3123 return STATUS_UNSUCCESSFUL;
3124 }
3125
3126
3127 NTSTATUS
3128 CmiRemoveKeyFromHashTable(PREGISTRY_HIVE RegistryHive,
3129 PHASH_TABLE_CELL HashBlock,
3130 BLOCK_OFFSET NKBOffset)
3131 {
3132 ULONG i;
3133
3134 for (i = 0; i < HashBlock->HashTableSize; i++)
3135 {
3136 if (HashBlock->Table[i].KeyOffset == NKBOffset)
3137 {
3138 HashBlock->Table[i].KeyOffset = 0;
3139 HashBlock->Table[i].HashValue = 0;
3140 return STATUS_SUCCESS;
3141 }
3142 }
3143
3144 return STATUS_UNSUCCESSFUL;
3145 }
3146
3147
3148 NTSTATUS
3149 CmiAllocateValueCell(PREGISTRY_HIVE RegistryHive,
3150 PVALUE_CELL *ValueCell,
3151 BLOCK_OFFSET *VBOffset,
3152 IN PUNICODE_STRING ValueName)
3153 {
3154 PVALUE_CELL NewValueCell;
3155 NTSTATUS Status;
3156 BOOLEAN Packable;
3157 ULONG NameSize;
3158 ULONG i;
3159
3160 Status = STATUS_SUCCESS;
3161
3162 NameSize = CmiGetPackedNameLength(ValueName,
3163 &Packable);
3164
3165 DPRINT("ValueName->Length %lu NameSize %lu\n", ValueName->Length, NameSize);
3166
3167 Status = CmiAllocateCell (RegistryHive,
3168 sizeof(VALUE_CELL) + NameSize,
3169 (PVOID*) &NewValueCell,
3170 VBOffset);
3171 if ((NewValueCell == NULL) || (!NT_SUCCESS(Status)))
3172 {
3173 Status = STATUS_INSUFFICIENT_RESOURCES;
3174 }
3175 else
3176 {
3177 assert(NameSize <= 0xffff); /* should really be USHORT_MAX or similar */
3178 NewValueCell->Id = REG_VALUE_CELL_ID;
3179 NewValueCell->NameSize = (USHORT)NameSize;
3180 if (Packable)
3181 {
3182 /* Pack the value name */
3183 for (i = 0; i < NameSize; i++)
3184 NewValueCell->Name[i] = (CHAR)ValueName->Buffer[i];
3185 NewValueCell->Flags |= REG_VALUE_NAME_PACKED;
3186 }
3187 else
3188 {
3189 /* Copy the value name */
3190 RtlCopyMemory(NewValueCell->Name,
3191 ValueName->Buffer,
3192 NameSize);
3193 NewValueCell->Flags = 0;
3194 }
3195 NewValueCell->DataType = 0;
3196 NewValueCell->DataSize = 0;
3197 NewValueCell->DataOffset = (BLOCK_OFFSET)-1;
3198 *ValueCell = NewValueCell;
3199 }
3200
3201 return Status;
3202 }
3203
3204
3205 NTSTATUS
3206 CmiDestroyValueCell(PREGISTRY_HIVE RegistryHive,
3207 PVALUE_CELL ValueCell,
3208 BLOCK_OFFSET ValueCellOffset)
3209 {
3210 NTSTATUS Status;
3211 PVOID DataCell;
3212 PHBIN Bin;
3213
3214 DPRINT("CmiDestroyValueCell(Cell %p Offset %lx)\n",
3215 ValueCell, ValueCellOffset);
3216
3217 VERIFY_VALUE_CELL(ValueCell);
3218
3219 /* Destroy the data cell */
3220 if (ValueCell->DataSize > sizeof(BLOCK_OFFSET))
3221 {
3222 DataCell = CmiGetCell (RegistryHive, ValueCell->DataOffset, &Bin);
3223 if (DataCell == NULL)
3224 {
3225 DPRINT("CmiGetCell() failed\n");
3226 return STATUS_UNSUCCESSFUL;
3227 }
3228
3229 Status = CmiDestroyCell (RegistryHive, DataCell, ValueCell->DataOffset);
3230 if (!NT_SUCCESS(Status))
3231 {
3232 return Status;
3233 }
3234
3235 /* Update time of heap */
3236 if (!IsNoFileHive(RegistryHive))
3237 NtQuerySystemTime(&Bin->DateModified);
3238 }
3239
3240 /* Destroy the value cell */
3241 Status = CmiDestroyCell (RegistryHive, ValueCell, ValueCellOffset);
3242
3243 /* Update time of heap */
3244 if (!IsNoFileHive(RegistryHive) && CmiGetCell (RegistryHive, ValueCellOffset, &Bin))
3245 {
3246 NtQuerySystemTime(&Bin->DateModified);
3247 }
3248
3249 return Status;
3250 }
3251
3252
3253 NTSTATUS
3254 CmiAddBin(PREGISTRY_HIVE RegistryHive,
3255 ULONG BlockCount,
3256 PVOID *NewBlock,
3257 BLOCK_OFFSET *NewBlockOffset)
3258 {
3259 PBLOCK_LIST_ENTRY BlockList;
3260 PCELL_HEADER tmpBlock;
3261 PHBIN tmpBin;
3262 ULONG BinSize;
3263 ULONG i;
3264
3265 DPRINT ("CmiAddBin (BlockCount %lu)\n", BlockCount);
3266
3267 BinSize = BlockCount * REG_BLOCK_SIZE;
3268 tmpBin = ExAllocatePool(PagedPool, BinSize);
3269 if (tmpBin == NULL)
3270 {
3271 return STATUS_INSUFFICIENT_RESOURCES;
3272 }
3273 RtlZeroMemory (tmpBin,
3274 BinSize);
3275
3276 tmpBin->HeaderId = REG_BIN_ID;
3277 tmpBin->BinOffset = RegistryHive->FileSize - REG_BLOCK_SIZE;
3278 RegistryHive->FileSize += BinSize;
3279 tmpBin->BinSize = BinSize;
3280 tmpBin->Unused1 = 0;
3281 NtQuerySystemTime(&tmpBin->DateModified);
3282 tmpBin->Unused2 = 0;
3283
3284 DPRINT (" BinOffset %lx BinSize %lx\n", tmpBin->BinOffset,tmpBin->BinSize);
3285
3286 /* Allocate new block list */
3287 BlockList = ExAllocatePool(NonPagedPool,
3288 sizeof(BLOCK_LIST_ENTRY) * (RegistryHive->BlockListSize + BlockCount));
3289 if (BlockList == NULL)
3290 {
3291 ExFreePool(tmpBin);
3292 return STATUS_INSUFFICIENT_RESOURCES;
3293 }
3294
3295 if (RegistryHive->BlockListSize > 0)
3296 {
3297 RtlCopyMemory (BlockList,
3298 RegistryHive->BlockList,
3299 sizeof(BLOCK_LIST_ENTRY) * RegistryHive->BlockListSize);
3300 ExFreePool(RegistryHive->BlockList);
3301 }
3302
3303 RegistryHive->BlockList = BlockList;
3304 for (i = 0; i < BlockCount; i++)
3305 {
3306 RegistryHive->BlockList[RegistryHive->BlockListSize + i].Block =
3307 (PVOID)((ULONG_PTR)tmpBin + (i * REG_BLOCK_SIZE));
3308 RegistryHive->BlockList[RegistryHive->BlockListSize + i].Bin = tmpBin;
3309 }
3310 RegistryHive->BlockListSize += BlockCount;
3311
3312 /* Initialize a free block in this heap : */
3313 tmpBlock = (PCELL_HEADER)((ULONG_PTR) tmpBin + REG_HBIN_DATA_OFFSET);
3314 tmpBlock->CellSize = (BinSize - REG_HBIN_DATA_OFFSET);
3315
3316 /* Grow bitmap if necessary */
3317 if (IsNoFileHive(RegistryHive) &&
3318 (RegistryHive->BlockListSize % (sizeof(ULONG) * 8) == 0))
3319 {
3320 PULONG BitmapBuffer;
3321 ULONG BitmapSize;
3322
3323 DPRINT("Grow hive bitmap\n");
3324
3325 /* Calculate bitmap size in bytes (always a multiple of 32 bits) */
3326 BitmapSize = ROUND_UP(RegistryHive->BlockListSize, sizeof(ULONG) * 8) / 8;
3327 DPRINT("RegistryHive->BlockListSize: %lu\n", RegistryHive->BlockListSize);
3328 DPRINT("BitmapSize: %lu Bytes %lu Bits\n", BitmapSize, BitmapSize * 8);
3329 BitmapBuffer = (PULONG)ExAllocatePool(PagedPool,
3330 BitmapSize);
3331 RtlZeroMemory(BitmapBuffer, BitmapSize);
3332 RtlCopyMemory(BitmapBuffer,
3333 RegistryHive->DirtyBitMap.Buffer,
3334 RegistryHive->DirtyBitMap.SizeOfBitMap);
3335 ExFreePool(RegistryHive->BitmapBuffer);
3336 RegistryHive->BitmapBuffer = BitmapBuffer;
3337 RtlInitializeBitMap(&RegistryHive->DirtyBitMap,
3338 RegistryHive->BitmapBuffer,
3339 BitmapSize * 8);
3340 }
3341
3342 *NewBlock = (PVOID) tmpBlock;
3343
3344 if (NewBlockOffset)
3345 *NewBlockOffset = tmpBin->BinOffset + REG_HBIN_DATA_OFFSET;
3346
3347 /* Mark new bin dirty */
3348 CmiMarkBinDirty(RegistryHive,
3349 tmpBin->BinOffset);
3350
3351 return STATUS_SUCCESS;
3352 }
3353
3354
3355 NTSTATUS
3356 CmiAllocateCell (PREGISTRY_HIVE RegistryHive,
3357 LONG CellSize,
3358 PVOID *Cell,
3359 BLOCK_OFFSET *CellOffset)
3360 {
3361 PCELL_HEADER NewCell;
3362 PHBIN Bin;
3363 ULONG i;
3364 PVOID Temp;
3365 NTSTATUS Status;
3366
3367 /* Round to 16 bytes multiple */
3368 CellSize = ROUND_UP(CellSize, 16);
3369
3370 /* Handle volatile hives first */
3371 if (IsPointerHive(RegistryHive))
3372 {
3373 NewCell = ExAllocatePool(NonPagedPool, CellSize);
3374 if (NewCell == NULL)
3375 {
3376 return STATUS_INSUFFICIENT_RESOURCES;
3377 }
3378
3379 RtlZeroMemory (NewCell,
3380 CellSize);
3381 NewCell->CellSize = -CellSize;
3382
3383 *Cell = NewCell;
3384 if (CellOffset != NULL)
3385 *CellOffset = (BLOCK_OFFSET) NewCell;
3386 }
3387 else
3388 {
3389 /* first search in free blocks */
3390 NewCell = NULL;
3391 for (i = 0; i < RegistryHive->FreeListSize; i++)
3392 {
3393 if (RegistryHive->FreeList[i]->CellSize >= CellSize)
3394 {
3395 NewCell = RegistryHive->FreeList[i];
3396 if (CellOffset != NULL)
3397 *CellOffset = RegistryHive->FreeListOffset[i];
3398
3399 /* Update time of heap */
3400 Temp = CmiGetCell (RegistryHive,
3401 RegistryHive->FreeListOffset[i],
3402 &Bin);
3403 if (Temp == NULL)
3404 {
3405 DPRINT("CmiGetBlock() failed\n");
3406 return STATUS_UNSUCCESSFUL;
3407 }
3408
3409 NtQuerySystemTime(&Bin->DateModified);
3410 CmiMarkBlockDirty(RegistryHive, RegistryHive->FreeListOffset[i]);
3411
3412 if ((i + 1) < RegistryHive->FreeListSize)
3413 {
3414 RtlMoveMemory(&RegistryHive->FreeList[i],
3415 &RegistryHive->FreeList[i + 1],
3416 sizeof(RegistryHive->FreeList[0])
3417 * (RegistryHive->FreeListSize - i - 1));
3418 RtlMoveMemory(&RegistryHive->FreeListOffset[i],
3419 &RegistryHive->FreeListOffset[i + 1],
3420 sizeof(RegistryHive->FreeListOffset[0])
3421 * (RegistryHive->FreeListSize - i - 1));
3422 }
3423 RegistryHive->FreeListSize--;
3424 break;
3425 }
3426 }
3427
3428 /* Need to extend hive file : */
3429 if (NewCell == NULL)
3430 {
3431 /* Add a new bin */
3432 Status = CmiAddBin(RegistryHive,
3433 ((CellSize + sizeof(HBIN) - 1) / REG_BLOCK_SIZE) + 1,
3434 (PVOID *)&NewCell,
3435 CellOffset);
3436 if (!NT_SUCCESS(Status))
3437 return Status;
3438 }
3439
3440 *Cell = NewCell;
3441
3442 /* Split the block in two parts */
3443 if (NewCell->CellSize > CellSize)
3444 {
3445 NewCell = (PCELL_HEADER) ((ULONG_PTR) NewCell + CellSize);
3446 NewCell->CellSize = ((PCELL_HEADER) (*Cell))->CellSize - CellSize;
3447 CmiAddFree(RegistryHive,
3448 NewCell,
3449 *CellOffset + CellSize,
3450 TRUE);
3451 CmiMarkBlockDirty(RegistryHive,
3452 *CellOffset + CellSize);
3453 }
3454 else if (NewCell->CellSize < CellSize)
3455 {
3456 return STATUS_UNSUCCESSFUL;
3457 }
3458
3459 RtlZeroMemory(*Cell,
3460 CellSize);
3461 ((PCELL_HEADER) (*Cell))->CellSize = -CellSize;
3462 }
3463
3464 return STATUS_SUCCESS;
3465 }
3466
3467
3468 NTSTATUS
3469 CmiDestroyCell (PREGISTRY_HIVE RegistryHive,
3470 PVOID Cell,
3471 BLOCK_OFFSET CellOffset)
3472 {
3473 NTSTATUS Status;
3474 PHBIN pBin;
3475
3476 Status = STATUS_SUCCESS;
3477
3478 if (IsPointerHive(RegistryHive))
3479 {
3480 ExFreePool(Cell);
3481 }
3482 else
3483 {
3484 PCELL_HEADER pFree = Cell;
3485
3486 if (pFree->CellSize < 0)
3487 pFree->CellSize = -pFree->CellSize;
3488
3489 /* Clear block (except the block size) */
3490 RtlZeroMemory(((char*)pFree) + sizeof(ULONG),
3491 pFree->CellSize - sizeof(ULONG));
3492
3493 /* Add block to the list of free blocks */
3494 CmiAddFree(RegistryHive, Cell, CellOffset, TRUE);
3495
3496 /* Update time of heap */
3497 if (!IsNoFileHive(RegistryHive) && CmiGetCell (RegistryHive, CellOffset,&pBin))
3498 NtQuerySystemTime(&pBin->DateModified);
3499
3500 CmiMarkBlockDirty(RegistryHive, CellOffset);
3501 }
3502
3503 return Status;
3504 }
3505
3506
3507 PVOID
3508 CmiGetCell (PREGISTRY_HIVE RegistryHive,
3509 BLOCK_OFFSET CellOffset,
3510 PHBIN *Bin)
3511 {
3512 PHBIN pBin;
3513
3514 if (Bin != NULL)
3515 {
3516 *Bin = NULL;
3517 }
3518
3519 if (CellOffset == (BLOCK_OFFSET)-1)
3520 {
3521 return NULL;
3522 }
3523
3524 if (IsPointerHive (RegistryHive))
3525 {
3526 return (PVOID)CellOffset;
3527 }
3528
3529 if (CellOffset > RegistryHive->BlockListSize * REG_BLOCK_SIZE)
3530 {
3531 DPRINT1("CellOffset exceeds valid range (%lu > %lu)\n",
3532 CellOffset, RegistryHive->BlockListSize * REG_BLOCK_SIZE);
3533 return NULL;
3534 }
3535
3536 pBin = RegistryHive->BlockList[CellOffset / REG_BLOCK_SIZE].Bin;
3537 if (pBin == NULL)
3538 {
3539 return NULL;
3540 }
3541
3542 if (Bin != NULL)
3543 {
3544 *Bin = pBin;
3545 }
3546
3547 return((PVOID)((ULONG_PTR)pBin + (CellOffset - pBin->BinOffset)));
3548 }
3549
3550
3551 static BOOLEAN
3552 CmiMergeFree(PREGISTRY_HIVE RegistryHive,
3553 PCELL_HEADER FreeBlock,
3554 BLOCK_OFFSET FreeOffset)
3555 {
3556 BLOCK_OFFSET BlockOffset;
3557 BLOCK_OFFSET BinOffset;
3558 ULONG BlockSize;
3559 ULONG BinSize;
3560 PHBIN Bin;
3561 ULONG i;
3562
3563 DPRINT("CmiMergeFree(Block %lx Offset %lx Size %lx) called\n",
3564 FreeBlock, FreeOffset, FreeBlock->CellSize);
3565
3566 CmiGetCell (RegistryHive,
3567 FreeOffset,
3568 &Bin);
3569 DPRINT("Bin %p\n", Bin);
3570 if (Bin == NULL)
3571 return(FALSE);
3572
3573 BinOffset = Bin->BinOffset;
3574 BinSize = Bin->BinSize;
3575 DPRINT("Bin %p Offset %lx Size %lx\n", Bin, BinOffset, BinSize);
3576
3577 for (i = 0; i < RegistryHive->FreeListSize; i++)
3578 {
3579 BlockOffset = RegistryHive->FreeListOffset[i];
3580 BlockSize = RegistryHive->FreeList[i]->CellSize;
3581 if (BlockOffset > BinOffset &&
3582 BlockOffset < BinOffset + BinSize)
3583 {
3584 DPRINT("Free block: Offset %lx Size %lx\n",
3585 BlockOffset, BlockSize);
3586
3587 if ((i < (RegistryHive->FreeListSize - 1)) &&
3588 (BlockOffset + BlockSize == FreeOffset) &&
3589 (FreeOffset + FreeBlock->CellSize == RegistryHive->FreeListOffset[i + 1]))
3590 {
3591 DPRINT("Merge current block with previous and next block\n");
3592
3593 RegistryHive->FreeList[i]->CellSize +=
3594 (FreeBlock->CellSize + RegistryHive->FreeList[i + 1]->CellSize);
3595
3596 FreeBlock->CellSize = 0;
3597 RegistryHive->FreeList[i + 1]->CellSize = 0;
3598
3599
3600 if ((i + 2) < RegistryHive->FreeListSize)
3601 {
3602 RtlMoveMemory(&RegistryHive->FreeList[i + 1],
3603 &RegistryHive->FreeList[i + 2],
3604 sizeof(RegistryHive->FreeList[0])
3605 * (RegistryHive->FreeListSize - i - 2));
3606 RtlMoveMemory(&RegistryHive->FreeListOffset[i + 1],
3607 &RegistryHive->FreeListOffset[i + 2],
3608 sizeof(RegistryHive->FreeListOffset[0])
3609 * (RegistryHive->FreeListSize - i - 2));
3610 }
3611 RegistryHive->FreeListSize--;
3612
3613 CmiMarkBlockDirty(RegistryHive, BlockOffset);
3614
3615 return(TRUE);
3616 }
3617 else if (BlockOffset + BlockSize == FreeOffset)
3618 {
3619 DPRINT("Merge current block with previous block\n");
3620
3621 RegistryHive->FreeList[i]->CellSize += FreeBlock->CellSize;
3622 FreeBlock->CellSize = 0;
3623
3624 CmiMarkBlockDirty(RegistryHive, BlockOffset);
3625
3626 return(TRUE);
3627 }
3628 else if (FreeOffset + FreeBlock->CellSize == BlockOffset)
3629 {
3630 DPRINT("Merge current block with next block\n");
3631
3632 FreeBlock->CellSize += RegistryHive->FreeList[i]->CellSize;
3633 RegistryHive->FreeList[i]->CellSize = 0;
3634 RegistryHive->FreeList[i] = FreeBlock;
3635 RegistryHive->FreeListOffset[i] = FreeOffset;
3636
3637 CmiMarkBlockDirty(RegistryHive, FreeOffset);
3638
3639 return(TRUE);
3640 }
3641 }
3642 }
3643
3644 return(FALSE);
3645 }
3646
3647
3648 NTSTATUS
3649 CmiAddFree(PREGISTRY_HIVE RegistryHive,
3650 PCELL_HEADER FreeBlock,
3651 BLOCK_OFFSET FreeOffset,
3652 BOOLEAN MergeFreeBlocks)
3653 {
3654 PCELL_HEADER *tmpList;
3655 BLOCK_OFFSET *tmpListOffset;
3656 LONG minInd;
3657 LONG maxInd;
3658 LONG medInd;
3659
3660 assert(RegistryHive);
3661 assert(FreeBlock);
3662
3663 DPRINT("FreeBlock %.08lx FreeOffset %.08lx\n",
3664 FreeBlock, FreeOffset);
3665
3666 /* Merge free blocks */
3667 if (MergeFreeBlocks == TRUE)
3668 {
3669 if (CmiMergeFree(RegistryHive, FreeBlock, FreeOffset))
3670 return(STATUS_SUCCESS);
3671 }
3672
3673 if ((RegistryHive->FreeListSize + 1) > RegistryHive->FreeListMax)
3674 {
3675 tmpList = ExAllocatePool(PagedPool,
3676 sizeof(PCELL_HEADER) * (RegistryHive->FreeListMax + 32));
3677 if (tmpList == NULL)
3678 return STATUS_INSUFFICIENT_RESOURCES;
3679
3680 tmpListOffset = ExAllocatePool(PagedPool,
3681 sizeof(BLOCK_OFFSET) * (RegistryHive->FreeListMax + 32));
3682
3683 if (tmpListOffset == NULL)
3684 {
3685 ExFreePool(tmpList);
3686 return STATUS_INSUFFICIENT_RESOURCES;
3687 }
3688
3689 if (RegistryHive->FreeListMax)
3690 {
3691 RtlMoveMemory(tmpList,
3692 RegistryHive->FreeList,
3693 sizeof(PCELL_HEADER) * (RegistryHive->FreeListMax));
3694 RtlMoveMemory(tmpListOffset,
3695 RegistryHive->FreeListOffset,
3696 sizeof(BLOCK_OFFSET) * (RegistryHive->FreeListMax));
3697 ExFreePool(RegistryHive->FreeList);
3698 ExFreePool(RegistryHive->FreeListOffset);
3699 }
3700 RegistryHive->FreeList = tmpList;
3701 RegistryHive->FreeListOffset = tmpListOffset;
3702 RegistryHive->FreeListMax += 32;
3703 }
3704
3705 /* Add new offset to free list, maintaining list in ascending order */
3706 if ((RegistryHive->FreeListSize == 0)
3707 || (RegistryHive->FreeListOffset[RegistryHive->FreeListSize-1] < FreeOffset))
3708 {
3709 /* Add to end of list */
3710 RegistryHive->FreeList[RegistryHive->FreeListSize] = FreeBlock;
3711 RegistryHive->FreeListOffset[RegistryHive->FreeListSize++] = FreeOffset;
3712 }
3713 else if (RegistryHive->FreeListOffset[0] > FreeOffset)
3714 {
3715 /* Add to begin of list */
3716 RtlMoveMemory(&RegistryHive->FreeList[1],
3717 &RegistryHive->FreeList[0],
3718 sizeof(RegistryHive->FreeList[0]) * RegistryHive->FreeListSize);
3719 RtlMoveMemory(&RegistryHive->FreeListOffset[1],
3720 &RegistryHive->FreeListOffset[0],
3721 sizeof(RegistryHive->FreeListOffset[0]) * RegistryHive->FreeListSize);
3722 RegistryHive->FreeList[0] = FreeBlock;
3723 RegistryHive->FreeListOffset[0] = FreeOffset;
3724 RegistryHive->FreeListSize++;
3725 }
3726 else
3727 {
3728 /* Search where to insert */
3729 minInd = 0;
3730 maxInd = RegistryHive->FreeListSize - 1;
3731 while ((maxInd - minInd) > 1)
3732 {
3733 medInd = (minInd + maxInd) / 2;
3734 if (RegistryHive->FreeListOffset[medInd] > FreeOffset)
3735 maxInd = medInd;
3736 else
3737 minInd = medInd;
3738 }
3739
3740 /* Insert before maxInd */
3741 RtlMoveMemory(&RegistryHive->FreeList[maxInd+1],
3742 &RegistryHive->FreeList[maxInd],
3743 sizeof(RegistryHive->FreeList[0]) * (RegistryHive->FreeListSize - minInd));
3744 RtlMoveMemory(&RegistryHive->FreeListOffset[maxInd + 1],
3745 &RegistryHive->FreeListOffset[maxInd],
3746 sizeof(RegistryHive->FreeListOffset[0]) * (RegistryHive->FreeListSize-minInd));
3747 RegistryHive->FreeList[maxInd] = FreeBlock;
3748 RegistryHive->FreeListOffset[maxInd] = FreeOffset;
3749 RegistryHive->FreeListSize++;
3750 }
3751
3752 return STATUS_SUCCESS;
3753 }
3754
3755
3756 VOID
3757 CmiMarkBlockDirty(PREGISTRY_HIVE RegistryHive,
3758 BLOCK_OFFSET BlockOffset)
3759 {
3760 PDATA_CELL Cell;
3761 LONG CellSize;
3762 ULONG BlockNumber;
3763 ULONG BlockCount;
3764
3765 if (IsNoFileHive(RegistryHive))
3766 return;
3767
3768 DPRINT("CmiMarkBlockDirty(Offset 0x%lx)\n", (ULONG)BlockOffset);
3769
3770 BlockNumber = (ULONG)BlockOffset / REG_BLOCK_SIZE;
3771
3772 Cell = CmiGetCell (RegistryHive,
3773 BlockOffset,
3774 NULL);
3775
3776 CellSize = Cell->CellSize;
3777 if (CellSize < 0)
3778 CellSize = -CellSize;
3779
3780 BlockCount = (ROUND_UP(BlockOffset + CellSize, REG_BLOCK_SIZE) -
3781 ROUND_DOWN(BlockOffset, REG_BLOCK_SIZE)) / REG_BLOCK_SIZE;
3782
3783 DPRINT(" BlockNumber %lu Size %lu (%s) BlockCount %lu\n",
3784 BlockNumber,
3785 CellSize,
3786 (Cell->CellSize < 0) ? "used" : "free",
3787 BlockCount);
3788
3789 RegistryHive->HiveDirty = TRUE;
3790 RtlSetBits(&RegistryHive->DirtyBitMap,
3791 BlockNumber,
3792 BlockCount);
3793 }
3794
3795
3796 VOID
3797 CmiMarkBinDirty(PREGISTRY_HIVE RegistryHive,
3798 BLOCK_OFFSET BinOffset)
3799 {
3800 ULONG BlockNumber;
3801 ULONG BlockCount;
3802 PHBIN Bin;
3803
3804 if (IsNoFileHive(RegistryHive))
3805 return;
3806
3807 DPRINT("CmiMarkBinDirty(Offset 0x%lx)\n", (ULONG)BinOffset);
3808
3809 BlockNumber = (ULONG)BinOffset / REG_BLOCK_SIZE;
3810
3811 Bin = RegistryHive->BlockList[BlockNumber].Bin;
3812
3813 BlockCount = Bin->BinSize / REG_BLOCK_SIZE;
3814
3815 DPRINT(" BlockNumber %lu BinSize %lu BlockCount %lu\n",
3816 BlockNumber,
3817 Bin->BinSize,
3818 BlockCount);
3819
3820 RegistryHive->HiveDirty = TRUE;
3821 RtlSetBits(&RegistryHive->DirtyBitMap,
3822 BlockNumber,
3823 BlockCount);
3824 }
3825
3826
3827 ULONG
3828 CmiGetPackedNameLength(IN PUNICODE_STRING Name,
3829 OUT PBOOLEAN Packable)
3830 {
3831 ULONG i;
3832
3833 if (Packable != NULL)
3834 *Packable = TRUE;
3835
3836 for (i = 0; i < Name->Length / sizeof(WCHAR); i++)
3837 {
3838 if (Name->Buffer[i] & 0xFF00)
3839 {
3840 if (Packable != NULL)
3841 *Packable = FALSE;
3842 return Name->Length;
3843 }
3844 }
3845
3846 return (Name->Length / sizeof(WCHAR));
3847 }
3848
3849
3850 BOOLEAN
3851 CmiComparePackedNames(IN PUNICODE_STRING Name,
3852 IN PCHAR NameBuffer,
3853 IN USHORT NameBufferSize,
3854 IN BOOLEAN NamePacked)
3855 {
3856 PWCHAR UNameBuffer;
3857 ULONG i;
3858
3859 if (NamePacked == TRUE)
3860 {
3861 if (Name->Length != NameBufferSize * sizeof(WCHAR))
3862 return(FALSE);
3863
3864 for (i = 0; i < Name->Length / sizeof(WCHAR); i++)
3865 {
3866 if (RtlUpcaseUnicodeChar(Name->Buffer[i]) != RtlUpcaseUnicodeChar((WCHAR)NameBuffer[i]))
3867 return(FALSE);
3868 }
3869 }
3870 else
3871 {
3872 if (Name->Length != NameBufferSize)
3873 return(FALSE);
3874
3875 UNameBuffer = (PWCHAR)NameBuffer;
3876
3877 for (i = 0; i < Name->Length / sizeof(WCHAR); i++)
3878 {
3879 if (RtlUpcaseUnicodeChar(Name->Buffer[i]) != RtlUpcaseUnicodeChar(UNameBuffer[i]))
3880 return(FALSE);
3881 }
3882 }
3883
3884 return(TRUE);
3885 }
3886
3887
3888 VOID
3889 CmiCopyPackedName(PWCHAR NameBuffer,
3890 PCHAR PackedNameBuffer,
3891 ULONG PackedNameSize)
3892 {
3893 ULONG i;
3894
3895 for (i = 0; i < PackedNameSize; i++)
3896 NameBuffer[i] = (WCHAR)PackedNameBuffer[i];
3897 }
3898
3899
3900 BOOLEAN
3901 CmiCompareHash(PUNICODE_STRING KeyName,
3902 PCHAR HashString)
3903 {
3904 CHAR Buffer[4];
3905
3906 Buffer[0] = (KeyName->Length >= 2) ? (CHAR)KeyName->Buffer[0] : 0;
3907 Buffer[1] = (KeyName->Length >= 4) ? (CHAR)KeyName->Buffer[1] : 0;
3908 Buffer[2] = (KeyName->Length >= 6) ? (CHAR)KeyName->Buffer[2] : 0;
3909 Buffer[3] = (KeyName->Length >= 8) ? (CHAR)KeyName->Buffer[3] : 0;
3910
3911 return (strncmp(Buffer, HashString, 4) == 0);
3912 }
3913
3914
3915 BOOLEAN
3916 CmiCompareHashI(PUNICODE_STRING KeyName,
3917 PCHAR HashString)
3918 {
3919 CHAR Buffer[4];
3920
3921 Buffer[0] = (KeyName->Length >= 2) ? (CHAR)KeyName->Buffer[0] : 0;
3922 Buffer[1] = (KeyName->Length >= 4) ? (CHAR)KeyName->Buffer[1] : 0;
3923 Buffer[2] = (KeyName->Length >= 6) ? (CHAR)KeyName->Buffer[2] : 0;
3924 Buffer[3] = (KeyName->Length >= 8) ? (CHAR)KeyName->Buffer[3] : 0;
3925
3926 return (_strnicmp(Buffer, HashString, 4) == 0);
3927 }
3928
3929
3930 BOOLEAN
3931 CmiCompareKeyNames(PUNICODE_STRING KeyName,
3932 PKEY_CELL KeyCell)
3933 {
3934 PWCHAR UnicodeName;
3935 USHORT i;
3936
3937 DPRINT("Flags: %hx\n", KeyCell->Flags);
3938
3939 if (KeyCell->Flags & REG_KEY_NAME_PACKED)
3940 {
3941 if (KeyName->Length != KeyCell->NameSize * sizeof(WCHAR))
3942 return FALSE;
3943
3944 for (i = 0; i < KeyCell->NameSize; i++)
3945 {
3946 if (KeyName->Buffer[i] != (WCHAR)KeyCell->Name[i])
3947 return FALSE;
3948 }
3949 }
3950 else
3951 {
3952 if (KeyName->Length != KeyCell->NameSize)
3953 return FALSE;
3954
3955 UnicodeName = (PWCHAR)KeyCell->Name;
3956 for (i = 0; i < KeyCell->NameSize / sizeof(WCHAR); i++)
3957 {
3958 if (KeyName->Buffer[i] != UnicodeName[i])
3959 return FALSE;
3960 }
3961 }
3962
3963 return TRUE;
3964 }
3965
3966
3967 BOOLEAN
3968 CmiCompareKeyNamesI(PUNICODE_STRING KeyName,
3969 PKEY_CELL KeyCell)
3970 {
3971 PWCHAR UnicodeName;
3972 USHORT i;
3973
3974 DPRINT("Flags: %hx\n", KeyCell->Flags);
3975
3976 if (KeyCell->Flags & REG_KEY_NAME_PACKED)
3977 {
3978 if (KeyName->Length != KeyCell->NameSize * sizeof(WCHAR))
3979 return FALSE;
3980
3981 for (i = 0; i < KeyCell->NameSize; i++)
3982 {
3983 if (RtlUpcaseUnicodeChar(KeyName->Buffer[i]) !=
3984 RtlUpcaseUnicodeChar((WCHAR)KeyCell->Name[i]))
3985 return FALSE;
3986 }
3987 }
3988 else
3989 {
3990 if (KeyName->Length != KeyCell->NameSize)
3991 return FALSE;
3992
3993 UnicodeName = (PWCHAR)KeyCell->Name;
3994 for (i = 0; i < KeyCell->NameSize / sizeof(WCHAR); i++)
3995 {
3996 if (RtlUpcaseUnicodeChar(KeyName->Buffer[i]) !=
3997 RtlUpcaseUnicodeChar(UnicodeName[i]))
3998 return FALSE;
3999 }
4000 }
4001
4002 return TRUE;
4003 }
4004
4005
4006 NTSTATUS
4007 CmiCopyKey (PREGISTRY_HIVE DstHive,
4008 PKEY_CELL DstKeyCell,
4009 PREGISTRY_HIVE SrcHive,
4010 PKEY_CELL SrcKeyCell)
4011 {
4012 PKEY_CELL NewKeyCell;
4013 ULONG NewKeyCellSize;
4014 BLOCK_OFFSET NewKeyCellOffset;
4015 PHASH_TABLE_CELL NewHashTableCell;
4016 ULONG NewHashTableSize;
4017 BLOCK_OFFSET NewHashTableOffset;
4018 ULONG i;
4019 NTSTATUS Status;
4020
4021 DPRINT ("CmiCopyKey() called\n");
4022
4023 if (DstKeyCell == NULL)
4024 {
4025 /* Allocate and copy key cell */
4026 NewKeyCellSize = sizeof(KEY_CELL) + SrcKeyCell->NameSize;
4027 Status = CmiAllocateCell (DstHive,
4028 NewKeyCellSize,
4029 (PVOID) &NewKeyCell,
4030 &NewKeyCellOffset);
4031 if (!NT_SUCCESS(Status))
4032 {
4033 DPRINT1 ("CmiAllocateBlock() failed (Status %lx)\n", Status);
4034 return Status;
4035 }
4036 if (NewKeyCell == NULL)
4037 {
4038 DPRINT1 ("Failed to allocate a key cell\n");
4039 return STATUS_INSUFFICIENT_RESOURCES;
4040 }
4041
4042 RtlCopyMemory (NewKeyCell,
4043 SrcKeyCell,
4044 NewKeyCellSize);
4045
4046 DstHive->HiveHeader->RootKeyOffset = NewKeyCellOffset;
4047
4048 /* Copy class name */
4049 if (SrcKeyCell->ClassNameOffset != (BLOCK_OFFSET) -1)
4050 {
4051 PDATA_CELL SrcClassNameCell;
4052 PDATA_CELL NewClassNameCell;
4053 BLOCK_OFFSET NewClassNameOffset;
4054
4055 SrcClassNameCell = CmiGetCell (SrcHive, SrcKeyCell->ClassNameOffset, NULL),
4056
4057 NewKeyCell->ClassSize = SrcKeyCell->ClassSize;
4058 Status = CmiAllocateCell (DstHive,
4059 sizeof(CELL_HEADER) + NewKeyCell->ClassSize,
4060 (PVOID)&NewClassNameCell,
4061 &NewClassNameOffset);
4062 if (!NT_SUCCESS(Status))
4063 {
4064 DPRINT1 ("CmiAllocateBlock() failed (Status %lx)\n", Status);
4065 return Status;
4066 }
4067
4068 RtlCopyMemory (NewClassNameCell,
4069 SrcClassNameCell,
4070 NewKeyCell->ClassSize);
4071 NewKeyCell->ClassNameOffset = NewClassNameOffset;
4072 }
4073 }
4074 else
4075 {
4076 NewKeyCell = DstKeyCell;
4077 }
4078
4079 /* Allocate hash table */
4080 if (SrcKeyCell->NumberOfSubKeys > 0)
4081 {
4082 NewHashTableSize = ROUND_UP(SrcKeyCell->NumberOfSubKeys + 1, 4) - 1;
4083 Status = CmiAllocateHashTableCell (DstHive,
4084 &NewHashTableCell,
4085 &NewHashTableOffset,
4086 NewHashTableSize);
4087 if (!NT_SUCCESS(Status))
4088 {
4089 DPRINT1 ("CmiAllocateHashTableBlock() failed (Status %lx)\n", Status);
4090 return Status;
4091 }
4092 NewKeyCell->HashTableOffset = NewHashTableOffset;
4093 }
4094
4095 /* Allocate and copy value list and values */
4096 if (SrcKeyCell->NumberOfValues != 0)
4097 {
4098 PVALUE_LIST_CELL NewValueListCell;
4099 PVALUE_LIST_CELL SrcValueListCell;
4100 PVALUE_CELL NewValueCell;
4101 PVALUE_CELL SrcValueCell;
4102 PDATA_CELL SrcValueDataCell;
4103 PDATA_CELL NewValueDataCell;
4104 BLOCK_OFFSET ValueCellOffset;
4105 BLOCK_OFFSET ValueDataCellOffset;
4106 ULONG NewValueListCellSize;
4107 ULONG NewValueCellSize;
4108
4109
4110 NewValueListCellSize =
4111 ROUND_UP(SrcKeyCell->NumberOfValues, 4) * sizeof(BLOCK_OFFSET);
4112 Status = CmiAllocateCell (DstHive,
4113 NewValueListCellSize,
4114 (PVOID)&NewValueListCell,
4115 &NewKeyCell->ValueListOffset);
4116 if (!NT_SUCCESS(Status))
4117 {
4118 DPRINT1 ("CmiAllocateBlock() failed (Status %lx)\n", Status);
4119 return Status;
4120 }
4121
4122 RtlZeroMemory (NewValueListCell,
4123 NewValueListCellSize);
4124
4125 /* Copy values */
4126 SrcValueListCell = CmiGetCell (SrcHive, SrcKeyCell->ValueListOffset, NULL);
4127 for (i = 0; i < SrcKeyCell->NumberOfValues; i++)
4128 {
4129 /* Copy value cell */
4130 SrcValueCell = CmiGetCell (SrcHive, SrcValueListCell->ValueOffset[i], NULL);
4131
4132 NewValueCellSize = sizeof(VALUE_CELL) + SrcValueCell->NameSize;
4133 Status = CmiAllocateCell (DstHive,
4134 NewValueCellSize,
4135 (PVOID*) &NewValueCell,
4136 &ValueCellOffset);
4137 if (!NT_SUCCESS(Status))
4138 {
4139 DPRINT1 ("CmiAllocateBlock() failed (Status %lx)\n", Status);
4140 return Status;
4141 }
4142
4143 NewValueListCell->ValueOffset[i] = ValueCellOffset;
4144 RtlCopyMemory (NewValueCell,
4145 SrcValueCell,
4146 NewValueCellSize);
4147
4148 /* Copy value data cell */
4149 if (SrcValueCell->DataSize > (LONG) sizeof(PVOID))
4150 {
4151 SrcValueDataCell = CmiGetCell (SrcHive, SrcValueCell->DataOffset, NULL);
4152
4153 Status = CmiAllocateCell (DstHive,
4154 sizeof(CELL_HEADER) + SrcValueCell->DataSize,
4155 (PVOID*) &NewValueDataCell,
4156 &ValueDataCellOffset);
4157 if (!NT_SUCCESS(Status))
4158 {
4159 DPRINT1 ("CmiAllocateBlock() failed (Status %lx)\n", Status);
4160 return Status;
4161 }
4162 RtlCopyMemory (NewValueDataCell,
4163 SrcValueDataCell,
4164 SrcValueCell->DataSize);
4165 NewValueCell->DataOffset = ValueDataCellOffset;
4166 }
4167 }
4168 }
4169
4170 /* Copy subkeys */
4171 if (SrcKeyCell->NumberOfSubKeys > 0)
4172 {
4173 PHASH_TABLE_CELL SrcHashTableCell;
4174 PKEY_CELL SrcSubKeyCell;
4175 PKEY_CELL NewSubKeyCell;
4176 ULONG NewSubKeyCellSize;
4177 BLOCK_OFFSET NewSubKeyCellOffset;
4178 PHASH_RECORD SrcHashRecord;
4179
4180 SrcHashTableCell = CmiGetCell (SrcHive,
4181 SrcKeyCell->HashTableOffset,
4182 NULL);
4183
4184 for (i = 0; i < SrcKeyCell->NumberOfSubKeys; i++)
4185 {
4186 SrcHashRecord = &SrcHashTableCell->Table[i];
4187 SrcSubKeyCell = CmiGetCell (SrcHive, SrcHashRecord->KeyOffset, NULL);
4188
4189 /* Allocate and copy key cell */
4190 NewSubKeyCellSize = sizeof(KEY_CELL) + SrcSubKeyCell->NameSize;
4191 Status = CmiAllocateCell (DstHive,
4192 NewSubKeyCellSize,
4193 (PVOID)&NewSubKeyCell,
4194 &NewSubKeyCellOffset);
4195 if (!NT_SUCCESS(Status))
4196 {
4197 DPRINT1 ("CmiAllocateBlock() failed (Status %lx)\n", Status);
4198 return Status;
4199 }
4200 if (NewKeyCell == NULL)
4201 {
4202 DPRINT1 ("Failed to allocate a sub key cell\n");
4203 return STATUS_INSUFFICIENT_RESOURCES;
4204 }
4205
4206 NewHashTableCell->Table[i].KeyOffset = NewSubKeyCellOffset;
4207 NewHashTableCell->Table[i].HashValue = SrcHashRecord->HashValue;
4208
4209 RtlCopyMemory (NewSubKeyCell,
4210 SrcSubKeyCell,
4211 NewSubKeyCellSize);
4212
4213 /* Copy class name */
4214 if (SrcSubKeyCell->ClassNameOffset != (BLOCK_OFFSET) -1)
4215 {
4216 PDATA_CELL SrcClassNameCell;
4217 PDATA_CELL NewClassNameCell;
4218 BLOCK_OFFSET NewClassNameOffset;
4219
4220 SrcClassNameCell = CmiGetCell (SrcHive,
4221 SrcSubKeyCell->ClassNameOffset,
4222 NULL),
4223
4224 NewSubKeyCell->ClassSize = SrcSubKeyCell->ClassSize;
4225 Status = CmiAllocateCell (DstHive,
4226 sizeof(CELL_HEADER) + NewSubKeyCell->ClassSize,
4227 (PVOID)&NewClassNameCell,
4228 &NewClassNameOffset);
4229 if (!NT_SUCCESS(Status))
4230 {
4231 DPRINT1 ("CmiAllocateBlock() failed (Status %lx)\n", Status);
4232 return Status;
4233 }
4234
4235 NewSubKeyCell->ClassNameOffset = NewClassNameOffset;
4236 RtlCopyMemory (NewClassNameCell,
4237 SrcClassNameCell,
4238 NewSubKeyCell->ClassSize);
4239 }
4240
4241 /* Copy subkey data and subkeys */
4242 Status = CmiCopyKey (DstHive,
4243 NewSubKeyCell,
4244 SrcHive,
4245 SrcSubKeyCell);
4246 if (!NT_SUCCESS(Status))
4247 {
4248 DPRINT1 ("CmiAllocateBlock() failed (Status %lx)\n", Status);
4249 return Status;
4250 }
4251 }
4252 }
4253
4254 return STATUS_SUCCESS;
4255 }
4256
4257
4258 NTSTATUS
4259 CmiSaveTempHive (PREGISTRY_HIVE Hive,
4260 HANDLE FileHandle)
4261 {
4262 IO_STATUS_BLOCK IoStatusBlock;
4263 LARGE_INTEGER FileOffset;
4264 ULONG BlockIndex;
4265 PVOID BlockPtr;
4266 NTSTATUS Status;
4267
4268 DPRINT ("CmiSaveTempHive() called\n");
4269
4270 Hive->HiveHeader->Checksum = CmiCalcChecksum ((PULONG)Hive->HiveHeader);
4271
4272 /* Write hive block */
4273 FileOffset.QuadPart = (ULONGLONG)0;
4274 Status = NtWriteFile (FileHandle,
4275 NULL,
4276 NULL,
4277 NULL,
4278 &IoStatusBlock,
4279 Hive->HiveHeader,
4280 sizeof(HIVE_HEADER),
4281 &FileOffset,
4282 NULL);
4283 if (!NT_SUCCESS(Status))
4284 {
4285 DPRINT1 ("NtWriteFile() failed (Status %lx)\n", Status);
4286 return Status;
4287 }
4288
4289 DPRINT ("Saving %lu blocks\n", Hive->BlockListSize);
4290 for (BlockIndex = 0; BlockIndex < Hive->BlockListSize; BlockIndex++)
4291 {
4292 BlockPtr = Hive->BlockList[BlockIndex].Block;
4293 DPRINT ("BlockPtr %p\n", BlockPtr);
4294
4295 FileOffset.QuadPart = (ULONGLONG)(BlockIndex + 1) * (ULONGLONG)REG_BLOCK_SIZE;
4296 DPRINT ("File offset %I64x\n", FileOffset.QuadPart);
4297
4298 /* Write hive block */
4299 Status = NtWriteFile (FileHandle,
4300 NULL,
4301 NULL,
4302 NULL,
4303 &IoStatusBlock,
4304 BlockPtr,
4305 REG_BLOCK_SIZE,
4306 &FileOffset,
4307 NULL);
4308 if (!NT_SUCCESS(Status))
4309 {
4310 DPRINT1 ("NtWriteFile() failed (Status %lx)\n", Status);
4311 return Status;
4312 }
4313 }
4314
4315 Status = NtFlushBuffersFile (FileHandle,
4316 &IoStatusBlock);
4317 if (!NT_SUCCESS(Status))
4318 {
4319 DPRINT1 ("NtFlushBuffersFile() failed (Status %lx)\n", Status);
4320 }
4321
4322 DPRINT ("CmiSaveTempHive() done\n");
4323
4324 return Status;
4325 }
4326
4327 /* EOF */