Use upper-case ASSERT macros.
[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 ULONG LastIndex;
1401 PVOID BlockPtr;
1402 NTSTATUS Status;
1403
1404 DPRINT("CmiStartLogUpdate() called\n");
1405
1406 BitmapSize = ROUND_UP(RegistryHive->BlockListSize, sizeof(ULONG) * 8) / 8;
1407 BufferSize = sizeof(HIVE_HEADER) +
1408 sizeof(ULONG) +
1409 BitmapSize;
1410 BufferSize = ROUND_UP(BufferSize, REG_BLOCK_SIZE);
1411
1412 DPRINT("Bitmap size %lu buffer size: %lu\n", BitmapSize, BufferSize);
1413
1414 Buffer = (PUCHAR)ExAllocatePool(NonPagedPool,
1415 BufferSize);
1416 if (Buffer == NULL)
1417 {
1418 DPRINT("ExAllocatePool() failed\n");
1419 return(STATUS_INSUFFICIENT_RESOURCES);
1420 }
1421 RtlZeroMemory (Buffer,
1422 BufferSize);
1423
1424 /* Open log file for writing */
1425 InitializeObjectAttributes(&ObjectAttributes,
1426 &RegistryHive->LogFileName,
1427 OBJ_CASE_INSENSITIVE,
1428 NULL,
1429 NULL);
1430
1431 Status = NtCreateFile(&FileHandle,
1432 FILE_ALL_ACCESS,
1433 &ObjectAttributes,
1434 &IoStatusBlock,
1435 NULL,
1436 FILE_ATTRIBUTE_NORMAL,
1437 0,
1438 FILE_SUPERSEDE,
1439 FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT,
1440 NULL,
1441 0);
1442 if (!NT_SUCCESS(Status))
1443 {
1444 DPRINT("NtCreateFile() failed (Status %lx)\n", Status);
1445 ExFreePool(Buffer);
1446 return(Status);
1447 }
1448
1449 /* Update firt update counter and checksum */
1450 RegistryHive->HiveHeader->UpdateCounter1 = RegistryHive->UpdateCounter + 1;
1451 RegistryHive->HiveHeader->Checksum = CmiCalcChecksum((PULONG)RegistryHive->HiveHeader);
1452
1453 /* Copy hive header */
1454 RtlCopyMemory(Buffer,
1455 RegistryHive->HiveHeader,
1456 sizeof(HIVE_HEADER));
1457 Ptr = Buffer + sizeof(HIVE_HEADER);
1458
1459 RtlCopyMemory(Ptr,
1460 "DIRT",
1461 4);
1462 Ptr += 4;
1463 RtlCopyMemory(Ptr,
1464 RegistryHive->DirtyBitMap.Buffer,
1465 BitmapSize);
1466
1467 /* Write hive block and block bitmap */
1468 FileOffset.QuadPart = (ULONGLONG)0;
1469 Status = NtWriteFile(FileHandle,
1470 NULL,
1471 NULL,
1472 NULL,
1473 &IoStatusBlock,
1474 Buffer,
1475 BufferSize,
1476 &FileOffset,
1477 NULL);
1478 if (!NT_SUCCESS(Status))
1479 {
1480 DPRINT("NtWriteFile() failed (Status %lx)\n", Status);
1481 NtClose(FileHandle);
1482 ExFreePool(Buffer);
1483 return(Status);
1484 }
1485 ExFreePool(Buffer);
1486
1487 /* Write dirty blocks */
1488 FileOffset.QuadPart = (ULONGLONG)BufferSize;
1489 BlockIndex = 0;
1490 while (BlockIndex < RegistryHive->BlockListSize)
1491 {
1492 LastIndex = BlockIndex;
1493 BlockIndex = RtlFindSetBits(&RegistryHive->DirtyBitMap,
1494 1,
1495 BlockIndex);
1496 if (BlockIndex == (ULONG)-1 || BlockIndex < LastIndex)
1497 {
1498 DPRINT("No more set bits\n");
1499 Status = STATUS_SUCCESS;
1500 break;
1501 }
1502
1503 DPRINT("Block %lu is dirty\n", BlockIndex);
1504
1505 BlockPtr = RegistryHive->BlockList[BlockIndex].Block;
1506 DPRINT("BlockPtr %p\n", BlockPtr);
1507 DPRINT("File offset %I64x\n", FileOffset.QuadPart);
1508
1509 /* Write hive block */
1510 Status = NtWriteFile(FileHandle,
1511 NULL,
1512 NULL,
1513 NULL,
1514 &IoStatusBlock,
1515 BlockPtr,
1516 REG_BLOCK_SIZE,
1517 &FileOffset,
1518 NULL);
1519 if (!NT_SUCCESS(Status))
1520 {
1521 DPRINT1("NtWriteFile() failed (Status %lx)\n", Status);
1522 NtClose(FileHandle);
1523 return(Status);
1524 }
1525
1526 BlockIndex++;
1527 FileOffset.QuadPart += (ULONGLONG)REG_BLOCK_SIZE;
1528 }
1529
1530 /* Truncate log file */
1531 EndOfFileInfo.EndOfFile.QuadPart = FileOffset.QuadPart;
1532 Status = NtSetInformationFile(FileHandle,
1533 &IoStatusBlock,
1534 &EndOfFileInfo,
1535 sizeof(FILE_END_OF_FILE_INFORMATION),
1536 FileEndOfFileInformation);
1537 if (!NT_SUCCESS(Status))
1538 {
1539 DPRINT("NtSetInformationFile() failed (Status %lx)\n", Status);
1540 NtClose(FileHandle);
1541 return(Status);
1542 }
1543
1544 FileAllocationInfo.AllocationSize.QuadPart = FileOffset.QuadPart;
1545 Status = NtSetInformationFile(FileHandle,
1546 &IoStatusBlock,
1547 &FileAllocationInfo,
1548 sizeof(FILE_ALLOCATION_INFORMATION),
1549 FileAllocationInformation);
1550 if (!NT_SUCCESS(Status))
1551 {
1552 DPRINT("NtSetInformationFile() failed (Status %lx)\n", Status);
1553 NtClose(FileHandle);
1554 return(Status);
1555 }
1556
1557 /* Flush the log file */
1558 Status = NtFlushBuffersFile(FileHandle,
1559 &IoStatusBlock);
1560 if (!NT_SUCCESS(Status))
1561 {
1562 DPRINT("NtFlushBuffersFile() failed (Status %lx)\n", Status);
1563 }
1564
1565 NtClose(FileHandle);
1566
1567 return(Status);
1568 }
1569
1570
1571 static NTSTATUS
1572 CmiFinishLogUpdate(PREGISTRY_HIVE RegistryHive)
1573 {
1574 OBJECT_ATTRIBUTES ObjectAttributes;
1575 IO_STATUS_BLOCK IoStatusBlock;
1576 HANDLE FileHandle;
1577 LARGE_INTEGER FileOffset;
1578 ULONG BufferSize;
1579 ULONG BitmapSize;
1580 PUCHAR Buffer;
1581 PUCHAR Ptr;
1582 NTSTATUS Status;
1583
1584 DPRINT("CmiFinishLogUpdate() called\n");
1585
1586 BitmapSize = ROUND_UP(RegistryHive->BlockListSize, sizeof(ULONG) * 8) / 8;
1587 BufferSize = sizeof(HIVE_HEADER) +
1588 sizeof(ULONG) +
1589 BitmapSize;
1590 BufferSize = ROUND_UP(BufferSize, REG_BLOCK_SIZE);
1591
1592 DPRINT("Bitmap size %lu buffer size: %lu\n", BitmapSize, BufferSize);
1593
1594 Buffer = (PUCHAR)ExAllocatePool(NonPagedPool, BufferSize);
1595 if (Buffer == NULL)
1596 {
1597 DPRINT("ExAllocatePool() failed\n");
1598 return(STATUS_INSUFFICIENT_RESOURCES);
1599 }
1600
1601 /* Open log file for writing */
1602 InitializeObjectAttributes(&ObjectAttributes,
1603 &RegistryHive->LogFileName,
1604 OBJ_CASE_INSENSITIVE,
1605 NULL,
1606 NULL);
1607
1608 Status = NtCreateFile(&FileHandle,
1609 FILE_ALL_ACCESS,
1610 &ObjectAttributes,
1611 &IoStatusBlock,
1612 NULL,
1613 FILE_ATTRIBUTE_NORMAL,
1614 0,
1615 FILE_OPEN,
1616 FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT,
1617 NULL,
1618 0);
1619 if (!NT_SUCCESS(Status))
1620 {
1621 DPRINT("NtCreateFile() failed (Status %lx)\n", Status);
1622 ExFreePool(Buffer);
1623 return(Status);
1624 }
1625
1626 /* Update first and second update counter and checksum */
1627 RegistryHive->HiveHeader->UpdateCounter1 = RegistryHive->UpdateCounter + 1;
1628 RegistryHive->HiveHeader->UpdateCounter2 = RegistryHive->UpdateCounter + 1;
1629 RegistryHive->HiveHeader->Checksum = CmiCalcChecksum((PULONG)RegistryHive->HiveHeader);
1630
1631 /* Copy hive header */
1632 RtlCopyMemory(Buffer,
1633 RegistryHive->HiveHeader,
1634 sizeof(HIVE_HEADER));
1635 Ptr = Buffer + sizeof(HIVE_HEADER);
1636
1637 /* Write empty block bitmap */
1638 RtlCopyMemory(Ptr,
1639 "DIRT",
1640 4);
1641 Ptr += 4;
1642 RtlZeroMemory(Ptr,
1643 BitmapSize);
1644
1645 /* Write hive block and block bitmap */
1646 FileOffset.QuadPart = (ULONGLONG)0;
1647 Status = NtWriteFile(FileHandle,
1648 NULL,
1649 NULL,
1650 NULL,
1651 &IoStatusBlock,
1652 Buffer,
1653 BufferSize,
1654 &FileOffset,
1655 NULL);
1656 if (!NT_SUCCESS(Status))
1657 {
1658 DPRINT("NtWriteFile() failed (Status %lx)\n", Status);
1659 NtClose(FileHandle);
1660 ExFreePool(Buffer);
1661 return(Status);
1662 }
1663
1664 ExFreePool(Buffer);
1665
1666 /* Flush the log file */
1667 Status = NtFlushBuffersFile(FileHandle,
1668 &IoStatusBlock);
1669 if (!NT_SUCCESS(Status))
1670 {
1671 DPRINT("NtFlushBuffersFile() failed (Status %lx)\n", Status);
1672 }
1673
1674 NtClose(FileHandle);
1675
1676 return(Status);
1677 }
1678
1679
1680 static NTSTATUS
1681 CmiCleanupLogUpdate(PREGISTRY_HIVE RegistryHive)
1682 {
1683 FILE_END_OF_FILE_INFORMATION EndOfFileInfo;
1684 FILE_ALLOCATION_INFORMATION FileAllocationInfo;
1685 OBJECT_ATTRIBUTES ObjectAttributes;
1686 IO_STATUS_BLOCK IoStatusBlock;
1687 HANDLE FileHandle;
1688 ULONG BufferSize;
1689 ULONG BitmapSize;
1690 NTSTATUS Status;
1691
1692 DPRINT("CmiCleanupLogUpdate() called\n");
1693
1694 BitmapSize = ROUND_UP(RegistryHive->BlockListSize, sizeof(ULONG) * 8) / 8;
1695 BufferSize = sizeof(HIVE_HEADER) +
1696 sizeof(ULONG) +
1697 BitmapSize;
1698 BufferSize = ROUND_UP(BufferSize, REG_BLOCK_SIZE);
1699
1700 DPRINT("Bitmap size %lu buffer size: %lu\n", BitmapSize, BufferSize);
1701
1702 /* Open log file for writing */
1703 InitializeObjectAttributes(&ObjectAttributes,
1704 &RegistryHive->LogFileName,
1705 OBJ_CASE_INSENSITIVE,
1706 NULL,
1707 NULL);
1708
1709 Status = NtCreateFile(&FileHandle,
1710 FILE_ALL_ACCESS,
1711 &ObjectAttributes,
1712 &IoStatusBlock,
1713 NULL,
1714 FILE_ATTRIBUTE_NORMAL,
1715 0,
1716 FILE_OPEN,
1717 FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT,
1718 NULL,
1719 0);
1720 if (!NT_SUCCESS(Status))
1721 {
1722 DPRINT("NtCreateFile() failed (Status %lx)\n", Status);
1723 return(Status);
1724 }
1725
1726 /* Truncate log file */
1727 EndOfFileInfo.EndOfFile.QuadPart = (ULONGLONG)BufferSize;
1728 Status = NtSetInformationFile(FileHandle,
1729 &IoStatusBlock,
1730 &EndOfFileInfo,
1731 sizeof(FILE_END_OF_FILE_INFORMATION),
1732 FileEndOfFileInformation);
1733 if (!NT_SUCCESS(Status))
1734 {
1735 DPRINT("NtSetInformationFile() failed (Status %lx)\n", Status);
1736 NtClose(FileHandle);
1737 return(Status);
1738 }
1739
1740 FileAllocationInfo.AllocationSize.QuadPart = (ULONGLONG)BufferSize;
1741 Status = NtSetInformationFile(FileHandle,
1742 &IoStatusBlock,
1743 &FileAllocationInfo,
1744 sizeof(FILE_ALLOCATION_INFORMATION),
1745 FileAllocationInformation);
1746 if (!NT_SUCCESS(Status))
1747 {
1748 DPRINT("NtSetInformationFile() failed (Status %lx)\n", Status);
1749 NtClose(FileHandle);
1750 return(Status);
1751 }
1752
1753 /* Flush the log file */
1754 Status = NtFlushBuffersFile(FileHandle,
1755 &IoStatusBlock);
1756 if (!NT_SUCCESS(Status))
1757 {
1758 DPRINT("NtFlushBuffersFile() failed (Status %lx)\n", Status);
1759 }
1760
1761 NtClose(FileHandle);
1762
1763 return(Status);
1764 }
1765
1766
1767 static NTSTATUS
1768 CmiStartHiveUpdate(PREGISTRY_HIVE RegistryHive)
1769 {
1770 OBJECT_ATTRIBUTES ObjectAttributes;
1771 IO_STATUS_BLOCK IoStatusBlock;
1772 HANDLE FileHandle;
1773 LARGE_INTEGER FileOffset;
1774 ULONG BlockIndex;
1775 ULONG LastIndex;
1776 PVOID BlockPtr;
1777 NTSTATUS Status;
1778
1779 DPRINT("CmiStartHiveUpdate() called\n");
1780
1781 /* Open hive for writing */
1782 InitializeObjectAttributes(&ObjectAttributes,
1783 &RegistryHive->HiveFileName,
1784 OBJ_CASE_INSENSITIVE,
1785 NULL,
1786 NULL);
1787
1788 Status = NtCreateFile(&FileHandle,
1789 FILE_ALL_ACCESS,
1790 &ObjectAttributes,
1791 &IoStatusBlock,
1792 NULL,
1793 FILE_ATTRIBUTE_NORMAL,
1794 0,
1795 FILE_OPEN,
1796 FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT,
1797 NULL,
1798 0);
1799 if (!NT_SUCCESS(Status))
1800 {
1801 DPRINT("NtCreateFile() failed (Status %lx)\n", Status);
1802 return(Status);
1803 }
1804
1805 /* Update firt update counter and checksum */
1806 RegistryHive->HiveHeader->UpdateCounter1 = RegistryHive->UpdateCounter + 1;
1807 RegistryHive->HiveHeader->Checksum = CmiCalcChecksum((PULONG)RegistryHive->HiveHeader);
1808
1809 /* Write hive block */
1810 FileOffset.QuadPart = (ULONGLONG)0;
1811 Status = NtWriteFile(FileHandle,
1812 NULL,
1813 NULL,
1814 NULL,
1815 &IoStatusBlock,
1816 RegistryHive->HiveHeader,
1817 sizeof(HIVE_HEADER),
1818 &FileOffset,
1819 NULL);
1820 if (!NT_SUCCESS(Status))
1821 {
1822 DPRINT("NtWriteFile() failed (Status %lx)\n", Status);
1823 NtClose(FileHandle);
1824 return(Status);
1825 }
1826
1827 BlockIndex = 0;
1828 while (BlockIndex < RegistryHive->BlockListSize)
1829 {
1830 LastIndex = BlockIndex;
1831 BlockIndex = RtlFindSetBits(&RegistryHive->DirtyBitMap,
1832 1,
1833 BlockIndex);
1834 if (BlockIndex == (ULONG)-1 || BlockIndex < LastIndex)
1835 {
1836 DPRINT("No more set bits\n");
1837 Status = STATUS_SUCCESS;
1838 break;
1839 }
1840
1841 DPRINT("Block %lu is dirty\n", BlockIndex);
1842
1843 BlockPtr = RegistryHive->BlockList[BlockIndex].Block;
1844 DPRINT(" BlockPtr %p\n", BlockPtr);
1845
1846 FileOffset.QuadPart = (ULONGLONG)(BlockIndex + 1) * (ULONGLONG)REG_BLOCK_SIZE;
1847 DPRINT(" File offset %I64x\n", FileOffset.QuadPart);
1848
1849 /* Write hive block */
1850 Status = NtWriteFile(FileHandle,
1851 NULL,
1852 NULL,
1853 NULL,
1854 &IoStatusBlock,
1855 BlockPtr,
1856 REG_BLOCK_SIZE,
1857 &FileOffset,
1858 NULL);
1859 if (!NT_SUCCESS(Status))
1860 {
1861 DPRINT("NtWriteFile() failed (Status %lx)\n", Status);
1862 NtClose(FileHandle);
1863 return(Status);
1864 }
1865
1866 BlockIndex++;
1867 }
1868
1869 Status = NtFlushBuffersFile(FileHandle,
1870 &IoStatusBlock);
1871 if (!NT_SUCCESS(Status))
1872 {
1873 DPRINT("NtFlushBuffersFile() failed (Status %lx)\n", Status);
1874 }
1875
1876 NtClose(FileHandle);
1877
1878 return(Status);
1879 }
1880
1881
1882 static NTSTATUS
1883 CmiFinishHiveUpdate(PREGISTRY_HIVE RegistryHive)
1884 {
1885 OBJECT_ATTRIBUTES ObjectAttributes;
1886 IO_STATUS_BLOCK IoStatusBlock;
1887 LARGE_INTEGER FileOffset;
1888 HANDLE FileHandle;
1889 NTSTATUS Status;
1890
1891 DPRINT("CmiFinishHiveUpdate() called\n");
1892
1893 InitializeObjectAttributes(&ObjectAttributes,
1894 &RegistryHive->HiveFileName,
1895 OBJ_CASE_INSENSITIVE,
1896 NULL,
1897 NULL);
1898
1899 Status = NtCreateFile(&FileHandle,
1900 FILE_ALL_ACCESS,
1901 &ObjectAttributes,
1902 &IoStatusBlock,
1903 NULL,
1904 FILE_ATTRIBUTE_NORMAL,
1905 0,
1906 FILE_OPEN,
1907 FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT,
1908 NULL,
1909 0);
1910 if (!NT_SUCCESS(Status))
1911 {
1912 DPRINT("NtCreateFile() failed (Status %lx)\n", Status);
1913 return(Status);
1914 }
1915
1916 /* Update second update counter and checksum */
1917 RegistryHive->HiveHeader->UpdateCounter1 = RegistryHive->UpdateCounter + 1;
1918 RegistryHive->HiveHeader->UpdateCounter2 = RegistryHive->UpdateCounter + 1;
1919 RegistryHive->HiveHeader->Checksum = CmiCalcChecksum((PULONG)RegistryHive->HiveHeader);
1920
1921 /* Write hive block */
1922 FileOffset.QuadPart = (ULONGLONG)0;
1923 Status = NtWriteFile(FileHandle,
1924 NULL,
1925 NULL,
1926 NULL,
1927 &IoStatusBlock,
1928 RegistryHive->HiveHeader,
1929 sizeof(HIVE_HEADER),
1930 &FileOffset,
1931 NULL);
1932 if (!NT_SUCCESS(Status))
1933 {
1934 DPRINT("NtWriteFile() failed (Status %lx)\n", Status);
1935 NtClose(FileHandle);
1936 return(Status);
1937 }
1938
1939 Status = NtFlushBuffersFile(FileHandle,
1940 &IoStatusBlock);
1941 if (!NT_SUCCESS(Status))
1942 {
1943 DPRINT("NtFlushBuffersFile() failed (Status %lx)\n", Status);
1944 }
1945
1946 NtClose(FileHandle);
1947
1948 return(Status);
1949 }
1950
1951
1952 NTSTATUS
1953 CmiFlushRegistryHive(PREGISTRY_HIVE RegistryHive)
1954 {
1955 NTSTATUS Status;
1956
1957 DPRINT("CmiFlushRegistryHive() called\n");
1958
1959 if (RegistryHive->HiveDirty == FALSE)
1960 {
1961 return(STATUS_SUCCESS);
1962 }
1963
1964 DPRINT("Hive '%wZ' is dirty\n",
1965 &RegistryHive->HiveFileName);
1966 DPRINT("Log file: '%wZ'\n",
1967 &RegistryHive->LogFileName);
1968
1969 /* Update hive header modification time */
1970 NtQuerySystemTime(&RegistryHive->HiveHeader->DateModified);
1971
1972 /* Start log update */
1973 Status = CmiStartLogUpdate(RegistryHive);
1974 if (!NT_SUCCESS(Status))
1975 {
1976 DPRINT("CmiStartLogUpdate() failed (Status %lx)\n", Status);
1977 return(Status);
1978 }
1979
1980 /* Finish log update */
1981 Status = CmiFinishLogUpdate(RegistryHive);
1982 if (!NT_SUCCESS(Status))
1983 {
1984 DPRINT("CmiFinishLogUpdate() failed (Status %lx)\n", Status);
1985 return(Status);
1986 }
1987
1988 /* Start hive update */
1989 Status = CmiStartHiveUpdate(RegistryHive);
1990 if (!NT_SUCCESS(Status))
1991 {
1992 DPRINT("CmiStartHiveUpdate() failed (Status %lx)\n", Status);
1993 return(Status);
1994 }
1995
1996 /* Finish the hive update */
1997 Status = CmiFinishHiveUpdate(RegistryHive);
1998 if (!NT_SUCCESS(Status))
1999 {
2000 DPRINT("CmiFinishHiveUpdate() failed (Status %lx)\n", Status);
2001 return(Status);
2002 }
2003
2004 /* Cleanup log update */
2005 Status = CmiCleanupLogUpdate(RegistryHive);
2006 if (!NT_SUCCESS(Status))
2007 {
2008 DPRINT("CmiFinishLogUpdate() failed (Status %lx)\n", Status);
2009 return(Status);
2010 }
2011
2012 /* Increment hive update counter */
2013 RegistryHive->UpdateCounter++;
2014
2015 /* Clear dirty bitmap and dirty flag */
2016 RtlClearAllBits(&RegistryHive->DirtyBitMap);
2017 RegistryHive->HiveDirty = FALSE;
2018
2019 DPRINT("CmiFlushRegistryHive() done\n");
2020
2021 return(STATUS_SUCCESS);
2022 }
2023
2024
2025 ULONG
2026 CmiGetNumberOfSubKeys(PKEY_OBJECT KeyObject)
2027 {
2028 PKEY_OBJECT CurKey;
2029 PKEY_CELL KeyCell;
2030 ULONG SubKeyCount;
2031 ULONG i;
2032
2033 VERIFY_KEY_OBJECT(KeyObject);
2034
2035 KeyCell = KeyObject->KeyCell;
2036 VERIFY_KEY_CELL(KeyCell);
2037
2038 SubKeyCount = (KeyCell == NULL) ? 0 : KeyCell->NumberOfSubKeys;
2039
2040 /* Search for volatile or 'foreign' keys */
2041 for (i = 0; i < KeyObject->NumberOfSubKeys; i++)
2042 {
2043 CurKey = KeyObject->SubKeys[i];
2044 if (CurKey->RegistryHive == CmiVolatileHive ||
2045 CurKey->RegistryHive != KeyObject->RegistryHive)
2046 {
2047 SubKeyCount++;
2048 }
2049 }
2050
2051 return SubKeyCount;
2052 }
2053
2054
2055 ULONG
2056 CmiGetMaxNameLength(PKEY_OBJECT KeyObject)
2057 {
2058 PHASH_TABLE_CELL HashBlock;
2059 PKEY_OBJECT CurKey;
2060 PKEY_CELL CurSubKeyCell;
2061 PKEY_CELL KeyCell;
2062 ULONG MaxName;
2063 ULONG NameSize;
2064 ULONG i;
2065
2066 VERIFY_KEY_OBJECT(KeyObject);
2067
2068 KeyCell = KeyObject->KeyCell;
2069 VERIFY_KEY_CELL(KeyCell);
2070
2071 MaxName = 0;
2072 HashBlock = CmiGetCell (KeyObject->RegistryHive,
2073 KeyCell->HashTableOffset,
2074 NULL);
2075 if (HashBlock == NULL)
2076 {
2077 DPRINT("CmiGetBlock() failed\n");
2078 }
2079 else
2080 {
2081 for (i = 0; i < HashBlock->HashTableSize; i++)
2082 {
2083 if (HashBlock->Table[i].KeyOffset != 0)
2084 {
2085 CurSubKeyCell = CmiGetCell (KeyObject->RegistryHive,
2086 HashBlock->Table[i].KeyOffset,
2087 NULL);
2088 if (CurSubKeyCell == NULL)
2089 {
2090 DPRINT("CmiGetBlock() failed\n");
2091 continue;
2092 }
2093
2094 NameSize = CurSubKeyCell->NameSize;
2095 if (CurSubKeyCell->Flags & REG_KEY_NAME_PACKED)
2096 {
2097 NameSize *= sizeof(WCHAR);
2098 }
2099
2100 if (NameSize > MaxName)
2101 {
2102 MaxName = NameSize;
2103 }
2104 }
2105 }
2106 }
2107
2108 DPRINT ("KeyObject->NumberOfSubKeys %d\n", KeyObject->NumberOfSubKeys);
2109 for (i = 0; i < KeyObject->NumberOfSubKeys; i++)
2110 {
2111 CurKey = KeyObject->SubKeys[i];
2112 if (CurKey->RegistryHive == CmiVolatileHive ||
2113 CurKey->RegistryHive != KeyObject->RegistryHive)
2114 {
2115 CurSubKeyCell = CurKey->KeyCell;
2116 if (CurSubKeyCell == NULL)
2117 {
2118 DPRINT("CmiGetBlock() failed\n");
2119 continue;
2120 }
2121
2122 if ((CurSubKeyCell->Flags & REG_KEY_ROOT_CELL) == REG_KEY_ROOT_CELL)
2123 {
2124 /* Use name of the key object */
2125 NameSize = CurKey->Name.Length;
2126 }
2127 else
2128 {
2129 /* Use name of the key cell */
2130 NameSize = CurSubKeyCell->NameSize;
2131 if (CurSubKeyCell->Flags & REG_KEY_NAME_PACKED)
2132 {
2133 NameSize *= sizeof(WCHAR);
2134 }
2135 }
2136 DPRINT ("NameSize %lu\n", NameSize);
2137
2138 if (NameSize > MaxName)
2139 {
2140 MaxName = NameSize;
2141 }
2142 }
2143 }
2144
2145 DPRINT ("MaxName %lu\n", MaxName);
2146
2147 return MaxName;
2148 }
2149
2150
2151 ULONG
2152 CmiGetMaxClassLength(PKEY_OBJECT KeyObject)
2153 {
2154 PHASH_TABLE_CELL HashBlock;
2155 PKEY_OBJECT CurKey;
2156 PKEY_CELL CurSubKeyCell;
2157 PKEY_CELL KeyCell;
2158 ULONG MaxClass;
2159 ULONG i;
2160
2161 VERIFY_KEY_OBJECT(KeyObject);
2162
2163 KeyCell = KeyObject->KeyCell;
2164 VERIFY_KEY_CELL(KeyCell);
2165
2166 MaxClass = 0;
2167 HashBlock = CmiGetCell (KeyObject->RegistryHive,
2168 KeyCell->HashTableOffset,
2169 NULL);
2170 if (HashBlock == NULL)
2171 {
2172 DPRINT("CmiGetBlock() failed\n");
2173 }
2174 else
2175 {
2176 for (i = 0; i < HashBlock->HashTableSize; i++)
2177 {
2178 if (HashBlock->Table[i].KeyOffset != 0)
2179 {
2180 CurSubKeyCell = CmiGetCell (KeyObject->RegistryHive,
2181 HashBlock->Table[i].KeyOffset,
2182 NULL);
2183 if (CurSubKeyCell == NULL)
2184 {
2185 DPRINT("CmiGetBlock() failed\n");
2186 continue;
2187 }
2188
2189 if (MaxClass < CurSubKeyCell->ClassSize)
2190 {
2191 MaxClass = CurSubKeyCell->ClassSize;
2192 }
2193 }
2194 }
2195 }
2196
2197 DPRINT("KeyObject->NumberOfSubKeys %d\n", KeyObject->NumberOfSubKeys);
2198 for (i = 0; i < KeyObject->NumberOfSubKeys; i++)
2199 {
2200 CurKey = KeyObject->SubKeys[i];
2201 if (CurKey->RegistryHive == CmiVolatileHive ||
2202 CurKey->RegistryHive != KeyObject->RegistryHive)
2203 {
2204 CurSubKeyCell = CurKey->KeyCell;
2205 if (CurSubKeyCell == NULL)
2206 {
2207 DPRINT("CmiGetBlock() failed\n");
2208 continue;
2209 }
2210
2211 if (MaxClass < CurSubKeyCell->ClassSize)
2212 {
2213 MaxClass = CurSubKeyCell->ClassSize;
2214 }
2215 }
2216 }
2217
2218 return MaxClass;
2219 }
2220
2221
2222 ULONG
2223 CmiGetMaxValueNameLength(PREGISTRY_HIVE RegistryHive,
2224 PKEY_CELL KeyCell)
2225 {
2226 PVALUE_LIST_CELL ValueListCell;
2227 PVALUE_CELL CurValueCell;
2228 ULONG MaxValueName;
2229 ULONG Size;
2230 ULONG i;
2231
2232 VERIFY_KEY_CELL(KeyCell);
2233
2234 MaxValueName = 0;
2235 ValueListCell = CmiGetCell (RegistryHive,
2236 KeyCell->ValueListOffset,
2237 NULL);
2238 if (ValueListCell == NULL)
2239 {
2240 DPRINT("CmiGetBlock() failed\n");
2241 return 0;
2242 }
2243
2244 for (i = 0; i < KeyCell->NumberOfValues; i++)
2245 {
2246 CurValueCell = CmiGetCell (RegistryHive,
2247 ValueListCell->ValueOffset[i],
2248 NULL);
2249 if (CurValueCell == NULL)
2250 {
2251 DPRINT("CmiGetBlock() failed\n");
2252 }
2253
2254 if (CurValueCell != NULL)
2255 {
2256 Size = CurValueCell->NameSize;
2257 if (CurValueCell->Flags & REG_VALUE_NAME_PACKED)
2258 {
2259 Size *= sizeof(WCHAR);
2260 }
2261 if (MaxValueName < Size)
2262 {
2263 MaxValueName = Size;
2264 }
2265 }
2266 }
2267
2268 return MaxValueName;
2269 }
2270
2271
2272 ULONG
2273 CmiGetMaxValueDataLength(PREGISTRY_HIVE RegistryHive,
2274 PKEY_CELL KeyCell)
2275 {
2276 PVALUE_LIST_CELL ValueListCell;
2277 PVALUE_CELL CurValueCell;
2278 LONG MaxValueData;
2279 ULONG i;
2280
2281 VERIFY_KEY_CELL(KeyCell);
2282
2283 MaxValueData = 0;
2284 ValueListCell = CmiGetCell (RegistryHive, KeyCell->ValueListOffset, NULL);
2285 if (ValueListCell == NULL)
2286 {
2287 return 0;
2288 }
2289
2290 for (i = 0; i < KeyCell->NumberOfValues; i++)
2291 {
2292 CurValueCell = CmiGetCell (RegistryHive,
2293 ValueListCell->ValueOffset[i],NULL);
2294 if ((CurValueCell != NULL) &&
2295 (MaxValueData < (LONG)(CurValueCell->DataSize & REG_DATA_SIZE_MASK)))
2296 {
2297 MaxValueData = CurValueCell->DataSize & REG_DATA_SIZE_MASK;
2298 }
2299 }
2300
2301 return MaxValueData;
2302 }
2303
2304
2305 NTSTATUS
2306 CmiScanForSubKey(IN PREGISTRY_HIVE RegistryHive,
2307 IN PKEY_CELL KeyCell,
2308 OUT PKEY_CELL *SubKeyCell,
2309 OUT BLOCK_OFFSET *BlockOffset,
2310 IN PUNICODE_STRING KeyName,
2311 IN ACCESS_MASK DesiredAccess,
2312 IN ULONG Attributes)
2313 {
2314 PHASH_TABLE_CELL HashBlock;
2315 PKEY_CELL CurSubKeyCell;
2316 ULONG i;
2317
2318 VERIFY_KEY_CELL(KeyCell);
2319
2320 DPRINT("Scanning for sub key %wZ\n", KeyName);
2321
2322 ASSERT(RegistryHive);
2323
2324 *SubKeyCell = NULL;
2325
2326 /* The key does not have any subkeys */
2327 if (KeyCell->HashTableOffset == (BLOCK_OFFSET)-1)
2328 {
2329 return STATUS_SUCCESS;
2330 }
2331
2332 /* Get hash table */
2333 HashBlock = CmiGetCell (RegistryHive, KeyCell->HashTableOffset, NULL);
2334 if (HashBlock == NULL)
2335 {
2336 DPRINT("CmiGetBlock() failed\n");
2337 return STATUS_UNSUCCESSFUL;
2338 }
2339
2340 for (i = 0; (i < KeyCell->NumberOfSubKeys) && (i < HashBlock->HashTableSize); i++)
2341 {
2342 if (Attributes & OBJ_CASE_INSENSITIVE)
2343 {
2344 if (HashBlock->Table[i].KeyOffset != 0 &&
2345 HashBlock->Table[i].KeyOffset != (ULONG_PTR)-1 &&
2346 (HashBlock->Table[i].HashValue == 0 ||
2347 CmiCompareHashI(KeyName, (PCHAR)&HashBlock->Table[i].HashValue)))
2348 {
2349 CurSubKeyCell = CmiGetCell (RegistryHive,
2350 HashBlock->Table[i].KeyOffset,
2351 NULL);
2352 if (CurSubKeyCell == NULL)
2353 {
2354 DPRINT("CmiGetBlock() failed\n");
2355 return STATUS_UNSUCCESSFUL;
2356 }
2357
2358 if (CmiCompareKeyNamesI(KeyName, CurSubKeyCell))
2359 {
2360 *SubKeyCell = CurSubKeyCell;
2361 *BlockOffset = HashBlock->Table[i].KeyOffset;
2362 break;
2363 }
2364 }
2365 }
2366 else
2367 {
2368 if (HashBlock->Table[i].KeyOffset != 0 &&
2369 HashBlock->Table[i].KeyOffset != (ULONG_PTR) -1 &&
2370 (HashBlock->Table[i].HashValue == 0 ||
2371 CmiCompareHash(KeyName, (PCHAR)&HashBlock->Table[i].HashValue)))
2372 {
2373 CurSubKeyCell = CmiGetCell (RegistryHive,
2374 HashBlock->Table[i].KeyOffset,
2375 NULL);
2376 if (CurSubKeyCell == NULL)
2377 {
2378 DPRINT("CmiGetBlock() failed\n");
2379 return STATUS_UNSUCCESSFUL;
2380 }
2381
2382 if (CmiCompareKeyNames(KeyName, CurSubKeyCell))
2383 {
2384 *SubKeyCell = CurSubKeyCell;
2385 *BlockOffset = HashBlock->Table[i].KeyOffset;
2386 break;
2387 }
2388 }
2389 }
2390 }
2391
2392 return STATUS_SUCCESS;
2393 }
2394
2395
2396 NTSTATUS
2397 CmiAddSubKey(PREGISTRY_HIVE RegistryHive,
2398 PKEY_OBJECT ParentKey,
2399 PKEY_OBJECT SubKey,
2400 PUNICODE_STRING SubKeyName,
2401 ULONG TitleIndex,
2402 PUNICODE_STRING Class,
2403 ULONG CreateOptions)
2404 {
2405 PHASH_TABLE_CELL HashBlock;
2406 BLOCK_OFFSET NKBOffset;
2407 PKEY_CELL NewKeyCell;
2408 ULONG NewBlockSize;
2409 PKEY_CELL ParentKeyCell;
2410 PDATA_CELL ClassCell;
2411 NTSTATUS Status;
2412 USHORT NameSize;
2413 PWSTR NamePtr;
2414 BOOLEAN Packable;
2415 ULONG i;
2416
2417 ParentKeyCell = ParentKey->KeyCell;
2418
2419 VERIFY_KEY_CELL(ParentKeyCell);
2420
2421 /* Skip leading backslash */
2422 if (SubKeyName->Buffer[0] == L'\\')
2423 {
2424 NamePtr = &SubKeyName->Buffer[1];
2425 NameSize = SubKeyName->Length - sizeof(WCHAR);
2426 }
2427 else
2428 {
2429 NamePtr = SubKeyName->Buffer;
2430 NameSize = SubKeyName->Length;
2431 }
2432
2433 /* Check whether key name can be packed */
2434 Packable = TRUE;
2435 for (i = 0; i < NameSize / sizeof(WCHAR); i++)
2436 {
2437 if (NamePtr[i] & 0xFF00)
2438 {
2439 Packable = FALSE;
2440 break;
2441 }
2442 }
2443
2444 /* Adjust name size */
2445 if (Packable)
2446 {
2447 NameSize = NameSize / sizeof(WCHAR);
2448 }
2449
2450 DPRINT("Key %S Length %lu %s\n", NamePtr, NameSize, (Packable)?"True":"False");
2451
2452 Status = STATUS_SUCCESS;
2453
2454 NewBlockSize = sizeof(KEY_CELL) + NameSize;
2455 Status = CmiAllocateCell (RegistryHive,
2456 NewBlockSize,
2457 (PVOID) &NewKeyCell,
2458 &NKBOffset);
2459 if (NewKeyCell == NULL)
2460 {
2461 Status = STATUS_INSUFFICIENT_RESOURCES;
2462 }
2463 else
2464 {
2465 NewKeyCell->Id = REG_KEY_CELL_ID;
2466 NewKeyCell->Flags = 0;
2467 NtQuerySystemTime(&NewKeyCell->LastWriteTime);
2468 NewKeyCell->ParentKeyOffset = -1;
2469 NewKeyCell->NumberOfSubKeys = 0;
2470 NewKeyCell->HashTableOffset = -1;
2471 NewKeyCell->NumberOfValues = 0;
2472 NewKeyCell->ValueListOffset = -1;
2473 NewKeyCell->SecurityKeyOffset = -1;
2474 NewKeyCell->ClassNameOffset = -1;
2475
2476 /* Pack the key name */
2477 NewKeyCell->NameSize = NameSize;
2478 if (Packable)
2479 {
2480 NewKeyCell->Flags |= REG_KEY_NAME_PACKED;
2481 for (i = 0; i < NameSize; i++)
2482 {
2483 NewKeyCell->Name[i] = (CHAR)(NamePtr[i] & 0x00FF);
2484 }
2485 }
2486 else
2487 {
2488 RtlCopyMemory(NewKeyCell->Name,
2489 NamePtr,
2490 NameSize);
2491 }
2492
2493 VERIFY_KEY_CELL(NewKeyCell);
2494
2495 if (Class != NULL)
2496 {
2497 NewKeyCell->ClassSize = Class->Length;
2498 Status = CmiAllocateCell (RegistryHive,
2499 sizeof(CELL_HEADER) + NewKeyCell->ClassSize,
2500 (PVOID)&ClassCell,
2501 &NewKeyCell->ClassNameOffset);
2502 RtlCopyMemory (ClassCell->Data,
2503 Class->Buffer,
2504 Class->Length);
2505 }
2506 }
2507
2508 if (!NT_SUCCESS(Status))
2509 {
2510 return Status;
2511 }
2512
2513 SubKey->KeyCell = NewKeyCell;
2514 SubKey->KeyCellOffset = NKBOffset;
2515
2516 /* Don't modify hash table if key is located in a pointer-based hive and parent key is not */
2517 if (IsPointerHive(RegistryHive) && (!IsPointerHive(ParentKey->RegistryHive)))
2518 {
2519 return(Status);
2520 }
2521
2522 if (ParentKeyCell->HashTableOffset == (ULONG_PTR) -1)
2523 {
2524 Status = CmiAllocateHashTableCell (RegistryHive,
2525 &HashBlock,
2526 &ParentKeyCell->HashTableOffset,
2527 REG_INIT_HASH_TABLE_SIZE);
2528 if (!NT_SUCCESS(Status))
2529 {
2530 return(Status);
2531 }
2532 }
2533 else
2534 {
2535 HashBlock = CmiGetCell (RegistryHive,
2536 ParentKeyCell->HashTableOffset,
2537 NULL);
2538 if (HashBlock == NULL)
2539 {
2540 DPRINT("CmiGetCell() failed\n");
2541 return STATUS_UNSUCCESSFUL;
2542 }
2543
2544 if (((ParentKeyCell->NumberOfSubKeys + 1) >= HashBlock->HashTableSize))
2545 {
2546 PHASH_TABLE_CELL NewHashBlock;
2547 BLOCK_OFFSET HTOffset;
2548
2549 /* Reallocate the hash table cell */
2550 Status = CmiAllocateHashTableCell (RegistryHive,
2551 &NewHashBlock,
2552 &HTOffset,
2553 HashBlock->HashTableSize +
2554 REG_EXTEND_HASH_TABLE_SIZE);
2555 if (!NT_SUCCESS(Status))
2556 {
2557 return Status;
2558 }
2559
2560 RtlZeroMemory(&NewHashBlock->Table[0],
2561 sizeof(NewHashBlock->Table[0]) * NewHashBlock->HashTableSize);
2562 RtlCopyMemory(&NewHashBlock->Table[0],
2563 &HashBlock->Table[0],
2564 sizeof(NewHashBlock->Table[0]) * HashBlock->HashTableSize);
2565 CmiDestroyCell (RegistryHive,
2566 HashBlock,
2567 ParentKeyCell->HashTableOffset);
2568 ParentKeyCell->HashTableOffset = HTOffset;
2569 HashBlock = NewHashBlock;
2570 }
2571 }
2572
2573 Status = CmiAddKeyToHashTable(RegistryHive,
2574 HashBlock,
2575 ParentKeyCell->HashTableOffset,
2576 NewKeyCell,
2577 NKBOffset);
2578 if (NT_SUCCESS(Status))
2579 {
2580 ParentKeyCell->NumberOfSubKeys++;
2581 }
2582
2583 NtQuerySystemTime (&ParentKeyCell->LastWriteTime);
2584 CmiMarkBlockDirty (RegistryHive, ParentKey->KeyCellOffset);
2585
2586 return(Status);
2587 }
2588
2589
2590 NTSTATUS
2591 CmiRemoveSubKey(PREGISTRY_HIVE RegistryHive,
2592 PKEY_OBJECT ParentKey,
2593 PKEY_OBJECT SubKey)
2594 {
2595 PHASH_TABLE_CELL HashBlock;
2596 PVALUE_LIST_CELL ValueList;
2597 PVALUE_CELL ValueCell;
2598 PDATA_CELL DataCell;
2599 ULONG i;
2600
2601 DPRINT("CmiRemoveSubKey() called\n");
2602
2603 /* Remove all values */
2604 if (SubKey->KeyCell->NumberOfValues != 0)
2605 {
2606 /* Get pointer to the value list cell */
2607 ValueList = CmiGetCell (RegistryHive,
2608 SubKey->KeyCell->ValueListOffset,
2609 NULL);
2610 if (ValueList == NULL)
2611 {
2612 DPRINT("CmiGetCell() failed\n");
2613 return STATUS_UNSUCCESSFUL;
2614 }
2615
2616 /* Enumerate all values */
2617 for (i = 0; i < SubKey->KeyCell->NumberOfValues; i++)
2618 {
2619 /* Get pointer to value cell */
2620 ValueCell = CmiGetCell(RegistryHive,
2621 ValueList->ValueOffset[i],
2622 NULL);
2623 if (ValueCell == NULL)
2624 {
2625 DPRINT("CmiGetCell() failed\n");
2626 return STATUS_UNSUCCESSFUL;
2627 }
2628
2629 if (!(ValueCell->DataSize & REG_DATA_IN_OFFSET)
2630 && ValueCell->DataSize > sizeof(BLOCK_OFFSET))
2631 {
2632 DataCell = CmiGetCell (RegistryHive,
2633 ValueCell->DataOffset,
2634 NULL);
2635 if (DataCell == NULL)
2636 {
2637 DPRINT("CmiGetCell() failed\n");
2638 return STATUS_UNSUCCESSFUL;
2639 }
2640
2641 if (DataCell != NULL)
2642 {
2643 /* Destroy data cell */
2644 CmiDestroyCell (RegistryHive,
2645 DataCell,
2646 ValueCell->DataOffset);
2647 }
2648 }
2649
2650 /* Destroy value cell */
2651 CmiDestroyCell (RegistryHive,
2652 ValueCell,
2653 ValueList->ValueOffset[i]);
2654 }
2655
2656 /* Destroy value list cell */
2657 CmiDestroyCell (RegistryHive,
2658 ValueList,
2659 SubKey->KeyCell->ValueListOffset);
2660
2661 SubKey->KeyCell->NumberOfValues = 0;
2662 SubKey->KeyCell->ValueListOffset = (BLOCK_OFFSET)-1;
2663
2664 CmiMarkBlockDirty(RegistryHive,
2665 SubKey->KeyCellOffset);
2666 }
2667
2668 /* Remove the key from the parent key's hash block */
2669 if (ParentKey->KeyCell->HashTableOffset != (BLOCK_OFFSET) -1)
2670 {
2671 DPRINT("ParentKey HashTableOffset %lx\n", ParentKey->KeyCell->HashTableOffset);
2672 HashBlock = CmiGetCell (ParentKey->RegistryHive,
2673 ParentKey->KeyCell->HashTableOffset,
2674 NULL);
2675 if (HashBlock == NULL)
2676 {
2677 DPRINT("CmiGetCell() failed\n");
2678 return STATUS_UNSUCCESSFUL;
2679 }
2680 DPRINT("ParentKey HashBlock %p\n", HashBlock);
2681 if (HashBlock != NULL)
2682 {
2683 CmiRemoveKeyFromHashTable(ParentKey->RegistryHive,
2684 HashBlock,
2685 SubKey->KeyCellOffset);
2686 CmiMarkBlockDirty(ParentKey->RegistryHive,
2687 ParentKey->KeyCell->HashTableOffset);
2688 }
2689 }
2690
2691 /* Remove the key's hash block */
2692 if (SubKey->KeyCell->HashTableOffset != (BLOCK_OFFSET) -1)
2693 {
2694 DPRINT("SubKey HashTableOffset %lx\n", SubKey->KeyCell->HashTableOffset);
2695 HashBlock = CmiGetCell (RegistryHive,
2696 SubKey->KeyCell->HashTableOffset,
2697 NULL);
2698 if (HashBlock == NULL)
2699 {
2700 DPRINT("CmiGetCell() failed\n");
2701 return STATUS_UNSUCCESSFUL;
2702 }
2703 DPRINT("SubKey HashBlock %p\n", HashBlock);
2704 if (HashBlock != NULL)
2705 {
2706 CmiDestroyCell (RegistryHive,
2707 HashBlock,
2708 SubKey->KeyCell->HashTableOffset);
2709 SubKey->KeyCell->HashTableOffset = -1;
2710 }
2711 }
2712
2713 /* Decrement the number of the parent key's sub keys */
2714 if (ParentKey != NULL)
2715 {
2716 DPRINT("ParentKey %p\n", ParentKey);
2717 ParentKey->KeyCell->NumberOfSubKeys--;
2718
2719 /* Remove the parent key's hash table */
2720 if (ParentKey->KeyCell->NumberOfSubKeys == 0)
2721 {
2722 DPRINT("ParentKey HashTableOffset %lx\n", ParentKey->KeyCell->HashTableOffset);
2723 HashBlock = CmiGetCell (ParentKey->RegistryHive,
2724 ParentKey->KeyCell->HashTableOffset,
2725 NULL);
2726 if (HashBlock == NULL)
2727 {
2728 DPRINT("CmiGetCell() failed\n");
2729 return STATUS_UNSUCCESSFUL;
2730 }
2731 DPRINT("ParentKey HashBlock %p\n", HashBlock);
2732 if (HashBlock != NULL)
2733 {
2734 CmiDestroyCell (ParentKey->RegistryHive,
2735 HashBlock,
2736 ParentKey->KeyCell->HashTableOffset);
2737 ParentKey->KeyCell->HashTableOffset = (BLOCK_OFFSET)-1;
2738 }
2739 }
2740
2741 NtQuerySystemTime(&ParentKey->KeyCell->LastWriteTime);
2742 CmiMarkBlockDirty(ParentKey->RegistryHive,
2743 ParentKey->KeyCellOffset);
2744 }
2745
2746 /* Destroy key cell */
2747 CmiDestroyCell (RegistryHive,
2748 SubKey->KeyCell,
2749 SubKey->KeyCellOffset);
2750 SubKey->KeyCell = NULL;
2751 SubKey->KeyCellOffset = (BLOCK_OFFSET)-1;
2752
2753 DPRINT("CmiRemoveSubKey() done\n");
2754
2755 return STATUS_SUCCESS;
2756 }
2757
2758
2759 NTSTATUS
2760 CmiScanKeyForValue(IN PREGISTRY_HIVE RegistryHive,
2761 IN PKEY_CELL KeyCell,
2762 IN PUNICODE_STRING ValueName,
2763 OUT PVALUE_CELL *ValueCell,
2764 OUT BLOCK_OFFSET *ValueCellOffset)
2765 {
2766 PVALUE_LIST_CELL ValueListCell;
2767 PVALUE_CELL CurValueCell;
2768 ULONG i;
2769
2770 *ValueCell = NULL;
2771 if (ValueCellOffset != NULL)
2772 *ValueCellOffset = (BLOCK_OFFSET)-1;
2773
2774 /* The key does not have any values */
2775 if (KeyCell->ValueListOffset == (BLOCK_OFFSET)-1)
2776 {
2777 return STATUS_OBJECT_NAME_NOT_FOUND;
2778 }
2779
2780 ValueListCell = CmiGetCell (RegistryHive, KeyCell->ValueListOffset, NULL);
2781 if (ValueListCell == NULL)
2782 {
2783 DPRINT("ValueListCell is NULL\n");
2784 return STATUS_UNSUCCESSFUL;
2785 }
2786
2787 VERIFY_VALUE_LIST_CELL(ValueListCell);
2788
2789 for (i = 0; i < KeyCell->NumberOfValues; i++)
2790 {
2791 CurValueCell = CmiGetCell (RegistryHive,
2792 ValueListCell->ValueOffset[i],
2793 NULL);
2794 if (CurValueCell == NULL)
2795 {
2796 DPRINT("CmiGetBlock() failed\n");
2797 return STATUS_UNSUCCESSFUL;
2798 }
2799
2800 if ((CurValueCell != NULL) &&
2801 CmiComparePackedNames(ValueName,
2802 CurValueCell->Name,
2803 CurValueCell->NameSize,
2804 (BOOLEAN)((CurValueCell->Flags & REG_VALUE_NAME_PACKED) ? TRUE : FALSE)))
2805 {
2806 *ValueCell = CurValueCell;
2807 if (ValueCellOffset != NULL)
2808 *ValueCellOffset = ValueListCell->ValueOffset[i];
2809 //DPRINT("Found value %s\n", ValueName);
2810 return STATUS_SUCCESS;
2811 }
2812 }
2813
2814 return STATUS_OBJECT_NAME_NOT_FOUND;
2815 }
2816
2817
2818 NTSTATUS
2819 CmiGetValueFromKeyByIndex(IN PREGISTRY_HIVE RegistryHive,
2820 IN PKEY_CELL KeyCell,
2821 IN ULONG Index,
2822 OUT PVALUE_CELL *ValueCell)
2823 {
2824 PVALUE_LIST_CELL ValueListCell;
2825 PVALUE_CELL CurValueCell;
2826
2827 *ValueCell = NULL;
2828
2829 if (KeyCell->ValueListOffset == (BLOCK_OFFSET)-1)
2830 {
2831 return STATUS_NO_MORE_ENTRIES;
2832 }
2833
2834 if (Index >= KeyCell->NumberOfValues)
2835 {
2836 return STATUS_NO_MORE_ENTRIES;
2837 }
2838
2839
2840 ValueListCell = CmiGetCell (RegistryHive, KeyCell->ValueListOffset, NULL);
2841 if (ValueListCell == NULL)
2842 {
2843 DPRINT("CmiGetBlock() failed\n");
2844 return STATUS_UNSUCCESSFUL;
2845 }
2846
2847 VERIFY_VALUE_LIST_CELL(ValueListCell);
2848
2849
2850 CurValueCell = CmiGetCell (RegistryHive,
2851 ValueListCell->ValueOffset[Index],
2852 NULL);
2853 if (CurValueCell == NULL)
2854 {
2855 DPRINT("CmiGetBlock() failed\n");
2856 return STATUS_UNSUCCESSFUL;
2857 }
2858
2859 *ValueCell = CurValueCell;
2860
2861 return STATUS_SUCCESS;
2862 }
2863
2864
2865 NTSTATUS
2866 CmiAddValueToKey(IN PREGISTRY_HIVE RegistryHive,
2867 IN PKEY_CELL KeyCell,
2868 IN BLOCK_OFFSET KeyCellOffset,
2869 IN PUNICODE_STRING ValueName,
2870 OUT PVALUE_CELL *pValueCell,
2871 OUT BLOCK_OFFSET *pValueCellOffset)
2872 {
2873 PVALUE_LIST_CELL NewValueListCell;
2874 PVALUE_LIST_CELL ValueListCell;
2875 PVALUE_CELL NewValueCell;
2876 BLOCK_OFFSET NewValueListCellOffset;
2877 BLOCK_OFFSET ValueListCellOffset;
2878 BLOCK_OFFSET NewValueCellOffset;
2879 ULONG CellSize;
2880 NTSTATUS Status;
2881
2882 DPRINT("KeyCell->ValuesOffset %lu\n", (ULONG)KeyCell->ValueListOffset);
2883
2884 ValueListCell = CmiGetCell (RegistryHive, KeyCell->ValueListOffset, NULL);
2885 if (ValueListCell == NULL)
2886 {
2887 CellSize = sizeof(VALUE_LIST_CELL) +
2888 (3 * sizeof(BLOCK_OFFSET));
2889 Status = CmiAllocateCell (RegistryHive,
2890 CellSize,
2891 (PVOID) &ValueListCell,
2892 &ValueListCellOffset);
2893 if (!NT_SUCCESS(Status))
2894 {
2895 return Status;
2896 }
2897
2898 KeyCell->ValueListOffset = ValueListCellOffset;
2899 CmiMarkBlockDirty(RegistryHive, KeyCellOffset);
2900 CmiMarkBlockDirty(RegistryHive, ValueListCellOffset);
2901 }
2902 else if (KeyCell->NumberOfValues >=
2903 (((ULONG)ABS_VALUE(ValueListCell->CellSize) - sizeof(VALUE_LIST_CELL)) / sizeof(BLOCK_OFFSET)))
2904 {
2905 #if 0
2906 CellSize = sizeof(VALUE_LIST_CELL) +
2907 ((KeyCell->NumberOfValues + REG_VALUE_LIST_CELL_MULTIPLE) * sizeof(BLOCK_OFFSET));
2908 #endif
2909 CellSize = 2 * (ULONG)ABS_VALUE(ValueListCell->CellSize);
2910 Status = CmiAllocateCell (RegistryHive,
2911 CellSize,
2912 (PVOID) &NewValueListCell,
2913 &NewValueListCellOffset);
2914 if (!NT_SUCCESS(Status))
2915 {
2916 return Status;
2917 }
2918
2919 RtlCopyMemory(&NewValueListCell->ValueOffset[0],
2920 &ValueListCell->ValueOffset[0],
2921 sizeof(BLOCK_OFFSET) * KeyCell->NumberOfValues);
2922 CmiDestroyCell (RegistryHive, ValueListCell, KeyCell->ValueListOffset);
2923 CmiMarkBlockDirty (RegistryHive, KeyCell->ValueListOffset);
2924
2925 KeyCell->ValueListOffset = NewValueListCellOffset;
2926 ValueListCell = NewValueListCell;
2927 CmiMarkBlockDirty (RegistryHive, KeyCellOffset);
2928 CmiMarkBlockDirty (RegistryHive, NewValueListCellOffset);
2929 }
2930
2931 DPRINT("KeyCell->NumberOfValues %lu, ValueListCell->CellSize %lu (%lu %lx)\n",
2932 KeyCell->NumberOfValues,
2933 (ULONG)ABS_VALUE(ValueListCell->CellSize),
2934 ((ULONG)ABS_VALUE(ValueListCell->CellSize) - sizeof(VALUE_LIST_CELL)) / sizeof(BLOCK_OFFSET),
2935 ((ULONG)ABS_VALUE(ValueListCell->CellSize) - sizeof(VALUE_LIST_CELL)) / sizeof(BLOCK_OFFSET));
2936
2937 Status = CmiAllocateValueCell(RegistryHive,
2938 &NewValueCell,
2939 &NewValueCellOffset,
2940 ValueName);
2941 if (!NT_SUCCESS(Status))
2942 {
2943 return Status;
2944 }
2945
2946 ValueListCell->ValueOffset[KeyCell->NumberOfValues] = NewValueCellOffset;
2947 KeyCell->NumberOfValues++;
2948
2949 CmiMarkBlockDirty(RegistryHive, KeyCellOffset);
2950 CmiMarkBlockDirty(RegistryHive, KeyCell->ValueListOffset);
2951 CmiMarkBlockDirty(RegistryHive, NewValueCellOffset);
2952
2953 *pValueCell = NewValueCell;
2954 *pValueCellOffset = NewValueCellOffset;
2955
2956 return STATUS_SUCCESS;
2957 }
2958
2959
2960 NTSTATUS
2961 CmiDeleteValueFromKey(IN PREGISTRY_HIVE RegistryHive,
2962 IN PKEY_CELL KeyCell,
2963 IN BLOCK_OFFSET KeyCellOffset,
2964 IN PUNICODE_STRING ValueName)
2965 {
2966 PVALUE_LIST_CELL ValueListCell;
2967 PVALUE_CELL CurValueCell;
2968 ULONG i;
2969 NTSTATUS Status;
2970
2971 ValueListCell = CmiGetCell (RegistryHive, KeyCell->ValueListOffset, NULL);
2972 if (ValueListCell == NULL)
2973 {
2974 DPRINT1("CmiGetBlock() failed\n");
2975 return STATUS_SUCCESS;
2976 }
2977
2978 VERIFY_VALUE_LIST_CELL(ValueListCell);
2979
2980 for (i = 0; i < KeyCell->NumberOfValues; i++)
2981 {
2982 CurValueCell = CmiGetCell (RegistryHive, ValueListCell->ValueOffset[i], NULL);
2983 if (CurValueCell == NULL)
2984 {
2985 DPRINT1("CmiGetBlock() failed\n");
2986 return STATUS_UNSUCCESSFUL;
2987 }
2988
2989 if (CmiComparePackedNames(ValueName,
2990 CurValueCell->Name,
2991 CurValueCell->NameSize,
2992 (BOOLEAN)((CurValueCell->Flags & REG_VALUE_NAME_PACKED) ? TRUE : FALSE)))
2993 {
2994 Status = CmiDestroyValueCell(RegistryHive,
2995 CurValueCell,
2996 ValueListCell->ValueOffset[i]);
2997 if (CurValueCell == NULL)
2998 {
2999 DPRINT1("CmiDestroyValueCell() failed\n");
3000 return Status;
3001 }
3002
3003 if (i < (KeyCell->NumberOfValues - 1))
3004 {
3005 RtlMoveMemory(&ValueListCell->ValueOffset[i],
3006 &ValueListCell->ValueOffset[i + 1],
3007 sizeof(BLOCK_OFFSET) * (KeyCell->NumberOfValues - 1 - i));
3008 }
3009 ValueListCell->ValueOffset[KeyCell->NumberOfValues - 1] = 0;
3010
3011
3012 KeyCell->NumberOfValues--;
3013
3014 if (KeyCell->NumberOfValues == 0)
3015 {
3016 CmiDestroyCell(RegistryHive,
3017 ValueListCell,
3018 KeyCell->ValueListOffset);
3019 KeyCell->ValueListOffset = -1;
3020 }
3021 else
3022 {
3023 CmiMarkBlockDirty(RegistryHive,
3024 KeyCell->ValueListOffset);
3025 }
3026
3027 CmiMarkBlockDirty(RegistryHive,
3028 KeyCellOffset);
3029
3030 return STATUS_SUCCESS;
3031 }
3032 }
3033
3034 DPRINT("Couldn't find the desired value\n");
3035
3036 return STATUS_OBJECT_NAME_NOT_FOUND;
3037 }
3038
3039
3040 NTSTATUS
3041 CmiAllocateHashTableCell (IN PREGISTRY_HIVE RegistryHive,
3042 OUT PHASH_TABLE_CELL *HashBlock,
3043 OUT BLOCK_OFFSET *HBOffset,
3044 IN ULONG SubKeyCount)
3045 {
3046 PHASH_TABLE_CELL NewHashBlock;
3047 ULONG NewHashSize;
3048 NTSTATUS Status;
3049
3050 Status = STATUS_SUCCESS;
3051 *HashBlock = NULL;
3052 NewHashSize = sizeof(HASH_TABLE_CELL) +
3053 (SubKeyCount * sizeof(HASH_RECORD));
3054 Status = CmiAllocateCell (RegistryHive,
3055 NewHashSize,
3056 (PVOID*) &NewHashBlock,
3057 HBOffset);
3058
3059 if ((NewHashBlock == NULL) || (!NT_SUCCESS(Status)))
3060 {
3061 Status = STATUS_INSUFFICIENT_RESOURCES;
3062 }
3063 else
3064 {
3065 ASSERT(SubKeyCount <= 0xffff); /* should really be USHORT_MAX or similar */
3066 NewHashBlock->Id = REG_HASH_TABLE_CELL_ID;
3067 NewHashBlock->HashTableSize = (USHORT)SubKeyCount;
3068 *HashBlock = NewHashBlock;
3069 }
3070
3071 return Status;
3072 }
3073
3074
3075 PKEY_CELL
3076 CmiGetKeyFromHashByIndex(PREGISTRY_HIVE RegistryHive,
3077 PHASH_TABLE_CELL HashBlock,
3078 ULONG Index)
3079 {
3080 BLOCK_OFFSET KeyOffset;
3081 PKEY_CELL KeyCell;
3082
3083 if (HashBlock == NULL)
3084 return NULL;
3085
3086 if (IsPointerHive(RegistryHive))
3087 {
3088 KeyCell = (PKEY_CELL) HashBlock->Table[Index].KeyOffset;
3089 }
3090 else
3091 {
3092 KeyOffset = HashBlock->Table[Index].KeyOffset;
3093 KeyCell = CmiGetCell (RegistryHive, KeyOffset, NULL);
3094 }
3095
3096 return KeyCell;
3097 }
3098
3099
3100 NTSTATUS
3101 CmiAddKeyToHashTable(PREGISTRY_HIVE RegistryHive,
3102 PHASH_TABLE_CELL HashCell,
3103 BLOCK_OFFSET HashCellOffset,
3104 PKEY_CELL NewKeyCell,
3105 BLOCK_OFFSET NKBOffset)
3106 {
3107 ULONG i;
3108
3109 for (i = 0; i < HashCell->HashTableSize; i++)
3110 {
3111 if (HashCell->Table[i].KeyOffset == 0)
3112 {
3113 HashCell->Table[i].KeyOffset = NKBOffset;
3114 HashCell->Table[i].HashValue = 0;
3115 if (NewKeyCell->Flags & REG_KEY_NAME_PACKED)
3116 {
3117 RtlCopyMemory(&HashCell->Table[i].HashValue,
3118 NewKeyCell->Name,
3119 min(NewKeyCell->NameSize, sizeof(ULONG)));
3120 }
3121 CmiMarkBlockDirty(RegistryHive, HashCellOffset);
3122 return STATUS_SUCCESS;
3123 }
3124 }
3125
3126 return STATUS_UNSUCCESSFUL;
3127 }
3128
3129
3130 NTSTATUS
3131 CmiRemoveKeyFromHashTable(PREGISTRY_HIVE RegistryHive,
3132 PHASH_TABLE_CELL HashBlock,
3133 BLOCK_OFFSET NKBOffset)
3134 {
3135 ULONG i;
3136
3137 for (i = 0; i < HashBlock->HashTableSize; i++)
3138 {
3139 if (HashBlock->Table[i].KeyOffset == NKBOffset)
3140 {
3141 HashBlock->Table[i].KeyOffset = 0;
3142 HashBlock->Table[i].HashValue = 0;
3143 return STATUS_SUCCESS;
3144 }
3145 }
3146
3147 return STATUS_UNSUCCESSFUL;
3148 }
3149
3150
3151 NTSTATUS
3152 CmiAllocateValueCell(PREGISTRY_HIVE RegistryHive,
3153 PVALUE_CELL *ValueCell,
3154 BLOCK_OFFSET *VBOffset,
3155 IN PUNICODE_STRING ValueName)
3156 {
3157 PVALUE_CELL NewValueCell;
3158 NTSTATUS Status;
3159 BOOLEAN Packable;
3160 ULONG NameSize;
3161 ULONG i;
3162
3163 Status = STATUS_SUCCESS;
3164
3165 NameSize = CmiGetPackedNameLength(ValueName,
3166 &Packable);
3167
3168 DPRINT("ValueName->Length %lu NameSize %lu\n", ValueName->Length, NameSize);
3169
3170 Status = CmiAllocateCell (RegistryHive,
3171 sizeof(VALUE_CELL) + NameSize,
3172 (PVOID*) &NewValueCell,
3173 VBOffset);
3174 if ((NewValueCell == NULL) || (!NT_SUCCESS(Status)))
3175 {
3176 Status = STATUS_INSUFFICIENT_RESOURCES;
3177 }
3178 else
3179 {
3180 ASSERT(NameSize <= 0xffff); /* should really be USHORT_MAX or similar */
3181 NewValueCell->Id = REG_VALUE_CELL_ID;
3182 NewValueCell->NameSize = (USHORT)NameSize;
3183 if (Packable)
3184 {
3185 /* Pack the value name */
3186 for (i = 0; i < NameSize; i++)
3187 NewValueCell->Name[i] = (CHAR)ValueName->Buffer[i];
3188 NewValueCell->Flags |= REG_VALUE_NAME_PACKED;
3189 }
3190 else
3191 {
3192 /* Copy the value name */
3193 RtlCopyMemory(NewValueCell->Name,
3194 ValueName->Buffer,
3195 NameSize);
3196 NewValueCell->Flags = 0;
3197 }
3198 NewValueCell->DataType = 0;
3199 NewValueCell->DataSize = 0;
3200 NewValueCell->DataOffset = (BLOCK_OFFSET)-1;
3201 *ValueCell = NewValueCell;
3202 }
3203
3204 return Status;
3205 }
3206
3207
3208 NTSTATUS
3209 CmiDestroyValueCell(PREGISTRY_HIVE RegistryHive,
3210 PVALUE_CELL ValueCell,
3211 BLOCK_OFFSET ValueCellOffset)
3212 {
3213 NTSTATUS Status;
3214 PVOID DataCell;
3215 PHBIN Bin;
3216
3217 DPRINT("CmiDestroyValueCell(Cell %p Offset %lx)\n",
3218 ValueCell, ValueCellOffset);
3219
3220 VERIFY_VALUE_CELL(ValueCell);
3221
3222 /* Destroy the data cell */
3223 if (!(ValueCell->DataSize & REG_DATA_IN_OFFSET)
3224 && ValueCell->DataSize > sizeof(BLOCK_OFFSET))
3225 {
3226 DataCell = CmiGetCell (RegistryHive, ValueCell->DataOffset, &Bin);
3227 if (DataCell == NULL)
3228 {
3229 DPRINT("CmiGetCell() failed\n");
3230 return STATUS_UNSUCCESSFUL;
3231 }
3232
3233 Status = CmiDestroyCell (RegistryHive, DataCell, ValueCell->DataOffset);
3234 if (!NT_SUCCESS(Status))
3235 {
3236 return Status;
3237 }
3238
3239 /* Update time of heap */
3240 if (!IsNoFileHive(RegistryHive))
3241 NtQuerySystemTime(&Bin->DateModified);
3242 }
3243
3244 /* Destroy the value cell */
3245 Status = CmiDestroyCell (RegistryHive, ValueCell, ValueCellOffset);
3246
3247 /* Update time of heap */
3248 if (!IsNoFileHive(RegistryHive) && CmiGetCell (RegistryHive, ValueCellOffset, &Bin))
3249 {
3250 NtQuerySystemTime(&Bin->DateModified);
3251 }
3252
3253 return Status;
3254 }
3255
3256
3257 NTSTATUS
3258 CmiAddBin(PREGISTRY_HIVE RegistryHive,
3259 ULONG BlockCount,
3260 PVOID *NewBlock,
3261 BLOCK_OFFSET *NewBlockOffset)
3262 {
3263 PBLOCK_LIST_ENTRY BlockList;
3264 PCELL_HEADER tmpBlock;
3265 PHBIN tmpBin;
3266 ULONG BinSize;
3267 ULONG i;
3268
3269 DPRINT ("CmiAddBin (BlockCount %lu)\n", BlockCount);
3270
3271 BinSize = BlockCount * REG_BLOCK_SIZE;
3272 tmpBin = ExAllocatePool(PagedPool, BinSize);
3273 if (tmpBin == NULL)
3274 {
3275 return STATUS_INSUFFICIENT_RESOURCES;
3276 }
3277 RtlZeroMemory (tmpBin,
3278 BinSize);
3279
3280 tmpBin->HeaderId = REG_BIN_ID;
3281 tmpBin->BinOffset = RegistryHive->FileSize - REG_BLOCK_SIZE;
3282 RegistryHive->FileSize += BinSize;
3283 tmpBin->BinSize = BinSize;
3284 tmpBin->Unused1 = 0;
3285 NtQuerySystemTime(&tmpBin->DateModified);
3286 tmpBin->Unused2 = 0;
3287
3288 DPRINT (" BinOffset %lx BinSize %lx\n", tmpBin->BinOffset,tmpBin->BinSize);
3289
3290 /* Allocate new block list */
3291 BlockList = ExAllocatePool(NonPagedPool,
3292 sizeof(BLOCK_LIST_ENTRY) * (RegistryHive->BlockListSize + BlockCount));
3293 if (BlockList == NULL)
3294 {
3295 ExFreePool(tmpBin);
3296 return STATUS_INSUFFICIENT_RESOURCES;
3297 }
3298
3299 if (RegistryHive->BlockListSize > 0)
3300 {
3301 RtlCopyMemory (BlockList,
3302 RegistryHive->BlockList,
3303 sizeof(BLOCK_LIST_ENTRY) * RegistryHive->BlockListSize);
3304 ExFreePool(RegistryHive->BlockList);
3305 }
3306
3307 RegistryHive->BlockList = BlockList;
3308 for (i = 0; i < BlockCount; i++)
3309 {
3310 RegistryHive->BlockList[RegistryHive->BlockListSize + i].Block =
3311 (PVOID)((ULONG_PTR)tmpBin + (i * REG_BLOCK_SIZE));
3312 RegistryHive->BlockList[RegistryHive->BlockListSize + i].Bin = tmpBin;
3313 }
3314 RegistryHive->BlockListSize += BlockCount;
3315
3316 /* Initialize a free block in this heap : */
3317 tmpBlock = (PCELL_HEADER)((ULONG_PTR) tmpBin + REG_HBIN_DATA_OFFSET);
3318 tmpBlock->CellSize = (BinSize - REG_HBIN_DATA_OFFSET);
3319
3320 /* Grow bitmap if necessary */
3321 if (IsNoFileHive(RegistryHive) &&
3322 (RegistryHive->BlockListSize % (sizeof(ULONG) * 8) == 0))
3323 {
3324 PULONG BitmapBuffer;
3325 ULONG BitmapSize;
3326
3327 DPRINT("Grow hive bitmap\n");
3328
3329 /* Calculate bitmap size in bytes (always a multiple of 32 bits) */
3330 BitmapSize = ROUND_UP(RegistryHive->BlockListSize, sizeof(ULONG) * 8) / 8;
3331 DPRINT("RegistryHive->BlockListSize: %lu\n", RegistryHive->BlockListSize);
3332 DPRINT("BitmapSize: %lu Bytes %lu Bits\n", BitmapSize, BitmapSize * 8);
3333 BitmapBuffer = (PULONG)ExAllocatePool(PagedPool,
3334 BitmapSize);
3335 RtlZeroMemory(BitmapBuffer, BitmapSize);
3336 RtlCopyMemory(BitmapBuffer,
3337 RegistryHive->DirtyBitMap.Buffer,
3338 RegistryHive->DirtyBitMap.SizeOfBitMap);
3339 ExFreePool(RegistryHive->BitmapBuffer);
3340 RegistryHive->BitmapBuffer = BitmapBuffer;
3341 RtlInitializeBitMap(&RegistryHive->DirtyBitMap,
3342 RegistryHive->BitmapBuffer,
3343 BitmapSize * 8);
3344 }
3345
3346 *NewBlock = (PVOID) tmpBlock;
3347
3348 if (NewBlockOffset)
3349 *NewBlockOffset = tmpBin->BinOffset + REG_HBIN_DATA_OFFSET;
3350
3351 /* Mark new bin dirty */
3352 CmiMarkBinDirty(RegistryHive,
3353 tmpBin->BinOffset);
3354
3355 return STATUS_SUCCESS;
3356 }
3357
3358
3359 NTSTATUS
3360 CmiAllocateCell (PREGISTRY_HIVE RegistryHive,
3361 LONG CellSize,
3362 PVOID *Cell,
3363 BLOCK_OFFSET *CellOffset)
3364 {
3365 PCELL_HEADER NewCell;
3366 PHBIN Bin;
3367 ULONG i;
3368 PVOID Temp;
3369 NTSTATUS Status;
3370
3371 /* Round to 16 bytes multiple */
3372 CellSize = ROUND_UP(CellSize, 16);
3373
3374 /* Handle volatile hives first */
3375 if (IsPointerHive(RegistryHive))
3376 {
3377 NewCell = ExAllocatePool(NonPagedPool, CellSize);
3378 if (NewCell == NULL)
3379 {
3380 return STATUS_INSUFFICIENT_RESOURCES;
3381 }
3382
3383 RtlZeroMemory (NewCell,
3384 CellSize);
3385 NewCell->CellSize = -CellSize;
3386
3387 *Cell = NewCell;
3388 if (CellOffset != NULL)
3389 *CellOffset = (BLOCK_OFFSET) NewCell;
3390 }
3391 else
3392 {
3393 /* first search in free blocks */
3394 NewCell = NULL;
3395 for (i = 0; i < RegistryHive->FreeListSize; i++)
3396 {
3397 if (RegistryHive->FreeList[i]->CellSize >= CellSize)
3398 {
3399 NewCell = RegistryHive->FreeList[i];
3400 if (CellOffset != NULL)
3401 *CellOffset = RegistryHive->FreeListOffset[i];
3402
3403 /* Update time of heap */
3404 Temp = CmiGetCell (RegistryHive,
3405 RegistryHive->FreeListOffset[i],
3406 &Bin);
3407 if (Temp == NULL)
3408 {
3409 DPRINT("CmiGetBlock() failed\n");
3410 return STATUS_UNSUCCESSFUL;
3411 }
3412
3413 NtQuerySystemTime(&Bin->DateModified);
3414 CmiMarkBlockDirty(RegistryHive, RegistryHive->FreeListOffset[i]);
3415
3416 if ((i + 1) < RegistryHive->FreeListSize)
3417 {
3418 RtlMoveMemory(&RegistryHive->FreeList[i],
3419 &RegistryHive->FreeList[i + 1],
3420 sizeof(RegistryHive->FreeList[0])
3421 * (RegistryHive->FreeListSize - i - 1));
3422 RtlMoveMemory(&RegistryHive->FreeListOffset[i],
3423 &RegistryHive->FreeListOffset[i + 1],
3424 sizeof(RegistryHive->FreeListOffset[0])
3425 * (RegistryHive->FreeListSize - i - 1));
3426 }
3427 RegistryHive->FreeListSize--;
3428 break;
3429 }
3430 }
3431
3432 /* Need to extend hive file : */
3433 if (NewCell == NULL)
3434 {
3435 /* Add a new bin */
3436 Status = CmiAddBin(RegistryHive,
3437 ((CellSize + sizeof(HBIN) - 1) / REG_BLOCK_SIZE) + 1,
3438 (PVOID *)&NewCell,
3439 CellOffset);
3440 if (!NT_SUCCESS(Status))
3441 return Status;
3442 }
3443
3444 *Cell = NewCell;
3445
3446 /* Split the block in two parts */
3447 if (NewCell->CellSize > CellSize)
3448 {
3449 NewCell = (PCELL_HEADER) ((ULONG_PTR) NewCell + CellSize);
3450 NewCell->CellSize = ((PCELL_HEADER) (*Cell))->CellSize - CellSize;
3451 CmiAddFree(RegistryHive,
3452 NewCell,
3453 *CellOffset + CellSize,
3454 TRUE);
3455 CmiMarkBlockDirty(RegistryHive,
3456 *CellOffset + CellSize);
3457 }
3458 else if (NewCell->CellSize < CellSize)
3459 {
3460 return STATUS_UNSUCCESSFUL;
3461 }
3462
3463 RtlZeroMemory(*Cell,
3464 CellSize);
3465 ((PCELL_HEADER) (*Cell))->CellSize = -CellSize;
3466 }
3467
3468 return STATUS_SUCCESS;
3469 }
3470
3471
3472 NTSTATUS
3473 CmiDestroyCell (PREGISTRY_HIVE RegistryHive,
3474 PVOID Cell,
3475 BLOCK_OFFSET CellOffset)
3476 {
3477 NTSTATUS Status;
3478 PHBIN pBin;
3479
3480 Status = STATUS_SUCCESS;
3481
3482 if (IsPointerHive(RegistryHive))
3483 {
3484 ExFreePool(Cell);
3485 }
3486 else
3487 {
3488 PCELL_HEADER pFree = Cell;
3489
3490 if (pFree->CellSize < 0)
3491 pFree->CellSize = -pFree->CellSize;
3492
3493 /* Clear block (except the block size) */
3494 RtlZeroMemory(((char*)pFree) + sizeof(ULONG),
3495 pFree->CellSize - sizeof(ULONG));
3496
3497 /* Add block to the list of free blocks */
3498 CmiAddFree(RegistryHive, Cell, CellOffset, TRUE);
3499
3500 /* Update time of heap */
3501 if (!IsNoFileHive(RegistryHive) && CmiGetCell (RegistryHive, CellOffset,&pBin))
3502 NtQuerySystemTime(&pBin->DateModified);
3503
3504 CmiMarkBlockDirty(RegistryHive, CellOffset);
3505 }
3506
3507 return Status;
3508 }
3509
3510
3511 PVOID
3512 CmiGetCell (PREGISTRY_HIVE RegistryHive,
3513 BLOCK_OFFSET CellOffset,
3514 PHBIN *Bin)
3515 {
3516 PHBIN pBin;
3517
3518 if (Bin != NULL)
3519 {
3520 *Bin = NULL;
3521 }
3522
3523 if (CellOffset == (BLOCK_OFFSET)-1)
3524 {
3525 return NULL;
3526 }
3527
3528 if (IsPointerHive (RegistryHive))
3529 {
3530 return (PVOID)CellOffset;
3531 }
3532
3533 if (CellOffset > RegistryHive->BlockListSize * REG_BLOCK_SIZE)
3534 {
3535 DPRINT1("CellOffset exceeds valid range (%lu > %lu)\n",
3536 CellOffset, RegistryHive->BlockListSize * REG_BLOCK_SIZE);
3537 return NULL;
3538 }
3539
3540 pBin = RegistryHive->BlockList[CellOffset / REG_BLOCK_SIZE].Bin;
3541 if (pBin == NULL)
3542 {
3543 return NULL;
3544 }
3545
3546 if (Bin != NULL)
3547 {
3548 *Bin = pBin;
3549 }
3550
3551 return((PVOID)((ULONG_PTR)pBin + (CellOffset - pBin->BinOffset)));
3552 }
3553
3554
3555 static BOOLEAN
3556 CmiMergeFree(PREGISTRY_HIVE RegistryHive,
3557 PCELL_HEADER FreeBlock,
3558 BLOCK_OFFSET FreeOffset)
3559 {
3560 BLOCK_OFFSET BlockOffset;
3561 BLOCK_OFFSET BinOffset;
3562 ULONG BlockSize;
3563 ULONG BinSize;
3564 PHBIN Bin;
3565 ULONG i;
3566
3567 DPRINT("CmiMergeFree(Block %lx Offset %lx Size %lx) called\n",
3568 FreeBlock, FreeOffset, FreeBlock->CellSize);
3569
3570 CmiGetCell (RegistryHive,
3571 FreeOffset,
3572 &Bin);
3573 DPRINT("Bin %p\n", Bin);
3574 if (Bin == NULL)
3575 return(FALSE);
3576
3577 BinOffset = Bin->BinOffset;
3578 BinSize = Bin->BinSize;
3579 DPRINT("Bin %p Offset %lx Size %lx\n", Bin, BinOffset, BinSize);
3580
3581 for (i = 0; i < RegistryHive->FreeListSize; i++)
3582 {
3583 BlockOffset = RegistryHive->FreeListOffset[i];
3584 BlockSize = RegistryHive->FreeList[i]->CellSize;
3585 if (BlockOffset > BinOffset &&
3586 BlockOffset < BinOffset + BinSize)
3587 {
3588 DPRINT("Free block: Offset %lx Size %lx\n",
3589 BlockOffset, BlockSize);
3590
3591 if ((i < (RegistryHive->FreeListSize - 1)) &&
3592 (BlockOffset + BlockSize == FreeOffset) &&
3593 (FreeOffset + FreeBlock->CellSize == RegistryHive->FreeListOffset[i + 1]))
3594 {
3595 DPRINT("Merge current block with previous and next block\n");
3596
3597 RegistryHive->FreeList[i]->CellSize +=
3598 (FreeBlock->CellSize + RegistryHive->FreeList[i + 1]->CellSize);
3599
3600 FreeBlock->CellSize = 0;
3601 RegistryHive->FreeList[i + 1]->CellSize = 0;
3602
3603
3604 if ((i + 2) < RegistryHive->FreeListSize)
3605 {
3606 RtlMoveMemory(&RegistryHive->FreeList[i + 1],
3607 &RegistryHive->FreeList[i + 2],
3608 sizeof(RegistryHive->FreeList[0])
3609 * (RegistryHive->FreeListSize - i - 2));
3610 RtlMoveMemory(&RegistryHive->FreeListOffset[i + 1],
3611 &RegistryHive->FreeListOffset[i + 2],
3612 sizeof(RegistryHive->FreeListOffset[0])
3613 * (RegistryHive->FreeListSize - i - 2));
3614 }
3615 RegistryHive->FreeListSize--;
3616
3617 CmiMarkBlockDirty(RegistryHive, BlockOffset);
3618
3619 return(TRUE);
3620 }
3621 else if (BlockOffset + BlockSize == FreeOffset)
3622 {
3623 DPRINT("Merge current block with previous block\n");
3624
3625 RegistryHive->FreeList[i]->CellSize += FreeBlock->CellSize;
3626 FreeBlock->CellSize = 0;
3627
3628 CmiMarkBlockDirty(RegistryHive, BlockOffset);
3629
3630 return(TRUE);
3631 }
3632 else if (FreeOffset + FreeBlock->CellSize == BlockOffset)
3633 {
3634 DPRINT("Merge current block with next block\n");
3635
3636 FreeBlock->CellSize += RegistryHive->FreeList[i]->CellSize;
3637 RegistryHive->FreeList[i]->CellSize = 0;
3638 RegistryHive->FreeList[i] = FreeBlock;
3639 RegistryHive->FreeListOffset[i] = FreeOffset;
3640
3641 CmiMarkBlockDirty(RegistryHive, FreeOffset);
3642
3643 return(TRUE);
3644 }
3645 }
3646 }
3647
3648 return(FALSE);
3649 }
3650
3651
3652 NTSTATUS
3653 CmiAddFree(PREGISTRY_HIVE RegistryHive,
3654 PCELL_HEADER FreeBlock,
3655 BLOCK_OFFSET FreeOffset,
3656 BOOLEAN MergeFreeBlocks)
3657 {
3658 PCELL_HEADER *tmpList;
3659 BLOCK_OFFSET *tmpListOffset;
3660 LONG minInd;
3661 LONG maxInd;
3662 LONG medInd;
3663
3664 ASSERT(RegistryHive);
3665 ASSERT(FreeBlock);
3666
3667 DPRINT("FreeBlock %.08lx FreeOffset %.08lx\n",
3668 FreeBlock, FreeOffset);
3669
3670 /* Merge free blocks */
3671 if (MergeFreeBlocks == TRUE)
3672 {
3673 if (CmiMergeFree(RegistryHive, FreeBlock, FreeOffset))
3674 return(STATUS_SUCCESS);
3675 }
3676
3677 if ((RegistryHive->FreeListSize + 1) > RegistryHive->FreeListMax)
3678 {
3679 tmpList = ExAllocatePool(PagedPool,
3680 sizeof(PCELL_HEADER) * (RegistryHive->FreeListMax + 32));
3681 if (tmpList == NULL)
3682 return STATUS_INSUFFICIENT_RESOURCES;
3683
3684 tmpListOffset = ExAllocatePool(PagedPool,
3685 sizeof(BLOCK_OFFSET) * (RegistryHive->FreeListMax + 32));
3686
3687 if (tmpListOffset == NULL)
3688 {
3689 ExFreePool(tmpList);
3690 return STATUS_INSUFFICIENT_RESOURCES;
3691 }
3692
3693 if (RegistryHive->FreeListMax)
3694 {
3695 RtlMoveMemory(tmpList,
3696 RegistryHive->FreeList,
3697 sizeof(PCELL_HEADER) * (RegistryHive->FreeListMax));
3698 RtlMoveMemory(tmpListOffset,
3699 RegistryHive->FreeListOffset,
3700 sizeof(BLOCK_OFFSET) * (RegistryHive->FreeListMax));
3701 ExFreePool(RegistryHive->FreeList);
3702 ExFreePool(RegistryHive->FreeListOffset);
3703 }
3704 RegistryHive->FreeList = tmpList;
3705 RegistryHive->FreeListOffset = tmpListOffset;
3706 RegistryHive->FreeListMax += 32;
3707 }
3708
3709 /* Add new offset to free list, maintaining list in ascending order */
3710 if ((RegistryHive->FreeListSize == 0)
3711 || (RegistryHive->FreeListOffset[RegistryHive->FreeListSize-1] < FreeOffset))
3712 {
3713 /* Add to end of list */
3714 RegistryHive->FreeList[RegistryHive->FreeListSize] = FreeBlock;
3715 RegistryHive->FreeListOffset[RegistryHive->FreeListSize++] = FreeOffset;
3716 }
3717 else if (RegistryHive->FreeListOffset[0] > FreeOffset)
3718 {
3719 /* Add to begin of list */
3720 RtlMoveMemory(&RegistryHive->FreeList[1],
3721 &RegistryHive->FreeList[0],
3722 sizeof(RegistryHive->FreeList[0]) * RegistryHive->FreeListSize);
3723 RtlMoveMemory(&RegistryHive->FreeListOffset[1],
3724 &RegistryHive->FreeListOffset[0],
3725 sizeof(RegistryHive->FreeListOffset[0]) * RegistryHive->FreeListSize);
3726 RegistryHive->FreeList[0] = FreeBlock;
3727 RegistryHive->FreeListOffset[0] = FreeOffset;
3728 RegistryHive->FreeListSize++;
3729 }
3730 else
3731 {
3732 /* Search where to insert */
3733 minInd = 0;
3734 maxInd = RegistryHive->FreeListSize - 1;
3735 while ((maxInd - minInd) > 1)
3736 {
3737 medInd = (minInd + maxInd) / 2;
3738 if (RegistryHive->FreeListOffset[medInd] > FreeOffset)
3739 maxInd = medInd;
3740 else
3741 minInd = medInd;
3742 }
3743
3744 /* Insert before maxInd */
3745 RtlMoveMemory(&RegistryHive->FreeList[maxInd+1],
3746 &RegistryHive->FreeList[maxInd],
3747 sizeof(RegistryHive->FreeList[0]) * (RegistryHive->FreeListSize - minInd));
3748 RtlMoveMemory(&RegistryHive->FreeListOffset[maxInd + 1],
3749 &RegistryHive->FreeListOffset[maxInd],
3750 sizeof(RegistryHive->FreeListOffset[0]) * (RegistryHive->FreeListSize-minInd));
3751 RegistryHive->FreeList[maxInd] = FreeBlock;
3752 RegistryHive->FreeListOffset[maxInd] = FreeOffset;
3753 RegistryHive->FreeListSize++;
3754 }
3755
3756 return STATUS_SUCCESS;
3757 }
3758
3759
3760 VOID
3761 CmiMarkBlockDirty(PREGISTRY_HIVE RegistryHive,
3762 BLOCK_OFFSET BlockOffset)
3763 {
3764 PDATA_CELL Cell;
3765 LONG CellSize;
3766 ULONG BlockNumber;
3767 ULONG BlockCount;
3768
3769 if (IsNoFileHive(RegistryHive))
3770 return;
3771
3772 DPRINT("CmiMarkBlockDirty(Offset 0x%lx)\n", (ULONG)BlockOffset);
3773
3774 BlockNumber = (ULONG)BlockOffset / REG_BLOCK_SIZE;
3775
3776 Cell = CmiGetCell (RegistryHive,
3777 BlockOffset,
3778 NULL);
3779
3780 CellSize = Cell->CellSize;
3781 if (CellSize < 0)
3782 CellSize = -CellSize;
3783
3784 BlockCount = (ROUND_UP(BlockOffset + CellSize, REG_BLOCK_SIZE) -
3785 ROUND_DOWN(BlockOffset, REG_BLOCK_SIZE)) / REG_BLOCK_SIZE;
3786
3787 DPRINT(" BlockNumber %lu Size %lu (%s) BlockCount %lu\n",
3788 BlockNumber,
3789 CellSize,
3790 (Cell->CellSize < 0) ? "used" : "free",
3791 BlockCount);
3792
3793 RegistryHive->HiveDirty = TRUE;
3794 RtlSetBits(&RegistryHive->DirtyBitMap,
3795 BlockNumber,
3796 BlockCount);
3797 }
3798
3799
3800 VOID
3801 CmiMarkBinDirty(PREGISTRY_HIVE RegistryHive,
3802 BLOCK_OFFSET BinOffset)
3803 {
3804 ULONG BlockNumber;
3805 ULONG BlockCount;
3806 PHBIN Bin;
3807
3808 if (IsNoFileHive(RegistryHive))
3809 return;
3810
3811 DPRINT("CmiMarkBinDirty(Offset 0x%lx)\n", (ULONG)BinOffset);
3812
3813 BlockNumber = (ULONG)BinOffset / REG_BLOCK_SIZE;
3814
3815 Bin = RegistryHive->BlockList[BlockNumber].Bin;
3816
3817 BlockCount = Bin->BinSize / REG_BLOCK_SIZE;
3818
3819 DPRINT(" BlockNumber %lu BinSize %lu BlockCount %lu\n",
3820 BlockNumber,
3821 Bin->BinSize,
3822 BlockCount);
3823
3824 RegistryHive->HiveDirty = TRUE;
3825 RtlSetBits(&RegistryHive->DirtyBitMap,
3826 BlockNumber,
3827 BlockCount);
3828 }
3829
3830
3831 ULONG
3832 CmiGetPackedNameLength(IN PUNICODE_STRING Name,
3833 OUT PBOOLEAN Packable)
3834 {
3835 ULONG i;
3836
3837 if (Packable != NULL)
3838 *Packable = TRUE;
3839
3840 for (i = 0; i < Name->Length / sizeof(WCHAR); i++)
3841 {
3842 if (Name->Buffer[i] & 0xFF00)
3843 {
3844 if (Packable != NULL)
3845 *Packable = FALSE;
3846 return Name->Length;
3847 }
3848 }
3849
3850 return (Name->Length / sizeof(WCHAR));
3851 }
3852
3853
3854 BOOLEAN
3855 CmiComparePackedNames(IN PUNICODE_STRING Name,
3856 IN PCHAR NameBuffer,
3857 IN USHORT NameBufferSize,
3858 IN BOOLEAN NamePacked)
3859 {
3860 PWCHAR UNameBuffer;
3861 ULONG i;
3862
3863 if (NamePacked == TRUE)
3864 {
3865 if (Name->Length != NameBufferSize * sizeof(WCHAR))
3866 return(FALSE);
3867
3868 for (i = 0; i < Name->Length / sizeof(WCHAR); i++)
3869 {
3870 if (RtlUpcaseUnicodeChar(Name->Buffer[i]) != RtlUpcaseUnicodeChar((WCHAR)NameBuffer[i]))
3871 return(FALSE);
3872 }
3873 }
3874 else
3875 {
3876 if (Name->Length != NameBufferSize)
3877 return(FALSE);
3878
3879 UNameBuffer = (PWCHAR)NameBuffer;
3880
3881 for (i = 0; i < Name->Length / sizeof(WCHAR); i++)
3882 {
3883 if (RtlUpcaseUnicodeChar(Name->Buffer[i]) != RtlUpcaseUnicodeChar(UNameBuffer[i]))
3884 return(FALSE);
3885 }
3886 }
3887
3888 return(TRUE);
3889 }
3890
3891
3892 VOID
3893 CmiCopyPackedName(PWCHAR NameBuffer,
3894 PCHAR PackedNameBuffer,
3895 ULONG PackedNameSize)
3896 {
3897 ULONG i;
3898
3899 for (i = 0; i < PackedNameSize; i++)
3900 NameBuffer[i] = (WCHAR)PackedNameBuffer[i];
3901 }
3902
3903
3904 BOOLEAN
3905 CmiCompareHash(PUNICODE_STRING KeyName,
3906 PCHAR HashString)
3907 {
3908 CHAR Buffer[4];
3909
3910 Buffer[0] = (KeyName->Length >= 2) ? (CHAR)KeyName->Buffer[0] : 0;
3911 Buffer[1] = (KeyName->Length >= 4) ? (CHAR)KeyName->Buffer[1] : 0;
3912 Buffer[2] = (KeyName->Length >= 6) ? (CHAR)KeyName->Buffer[2] : 0;
3913 Buffer[3] = (KeyName->Length >= 8) ? (CHAR)KeyName->Buffer[3] : 0;
3914
3915 return (strncmp(Buffer, HashString, 4) == 0);
3916 }
3917
3918
3919 BOOLEAN
3920 CmiCompareHashI(PUNICODE_STRING KeyName,
3921 PCHAR HashString)
3922 {
3923 CHAR Buffer[4];
3924
3925 Buffer[0] = (KeyName->Length >= 2) ? (CHAR)KeyName->Buffer[0] : 0;
3926 Buffer[1] = (KeyName->Length >= 4) ? (CHAR)KeyName->Buffer[1] : 0;
3927 Buffer[2] = (KeyName->Length >= 6) ? (CHAR)KeyName->Buffer[2] : 0;
3928 Buffer[3] = (KeyName->Length >= 8) ? (CHAR)KeyName->Buffer[3] : 0;
3929
3930 return (_strnicmp(Buffer, HashString, 4) == 0);
3931 }
3932
3933
3934 BOOLEAN
3935 CmiCompareKeyNames(PUNICODE_STRING KeyName,
3936 PKEY_CELL KeyCell)
3937 {
3938 PWCHAR UnicodeName;
3939 USHORT i;
3940
3941 DPRINT("Flags: %hx\n", KeyCell->Flags);
3942
3943 if (KeyCell->Flags & REG_KEY_NAME_PACKED)
3944 {
3945 if (KeyName->Length != KeyCell->NameSize * sizeof(WCHAR))
3946 return FALSE;
3947
3948 for (i = 0; i < KeyCell->NameSize; i++)
3949 {
3950 if (KeyName->Buffer[i] != (WCHAR)KeyCell->Name[i])
3951 return FALSE;
3952 }
3953 }
3954 else
3955 {
3956 if (KeyName->Length != KeyCell->NameSize)
3957 return FALSE;
3958
3959 UnicodeName = (PWCHAR)KeyCell->Name;
3960 for (i = 0; i < KeyCell->NameSize / sizeof(WCHAR); i++)
3961 {
3962 if (KeyName->Buffer[i] != UnicodeName[i])
3963 return FALSE;
3964 }
3965 }
3966
3967 return TRUE;
3968 }
3969
3970
3971 BOOLEAN
3972 CmiCompareKeyNamesI(PUNICODE_STRING KeyName,
3973 PKEY_CELL KeyCell)
3974 {
3975 PWCHAR UnicodeName;
3976 USHORT i;
3977
3978 DPRINT("Flags: %hx\n", KeyCell->Flags);
3979
3980 if (KeyCell->Flags & REG_KEY_NAME_PACKED)
3981 {
3982 if (KeyName->Length != KeyCell->NameSize * sizeof(WCHAR))
3983 return FALSE;
3984
3985 for (i = 0; i < KeyCell->NameSize; i++)
3986 {
3987 if (RtlUpcaseUnicodeChar(KeyName->Buffer[i]) !=
3988 RtlUpcaseUnicodeChar((WCHAR)KeyCell->Name[i]))
3989 return FALSE;
3990 }
3991 }
3992 else
3993 {
3994 if (KeyName->Length != KeyCell->NameSize)
3995 return FALSE;
3996
3997 UnicodeName = (PWCHAR)KeyCell->Name;
3998 for (i = 0; i < KeyCell->NameSize / sizeof(WCHAR); i++)
3999 {
4000 if (RtlUpcaseUnicodeChar(KeyName->Buffer[i]) !=
4001 RtlUpcaseUnicodeChar(UnicodeName[i]))
4002 return FALSE;
4003 }
4004 }
4005
4006 return TRUE;
4007 }
4008
4009
4010 NTSTATUS
4011 CmiCopyKey (PREGISTRY_HIVE DstHive,
4012 PKEY_CELL DstKeyCell,
4013 PREGISTRY_HIVE SrcHive,
4014 PKEY_CELL SrcKeyCell)
4015 {
4016 PKEY_CELL NewKeyCell;
4017 ULONG NewKeyCellSize;
4018 BLOCK_OFFSET NewKeyCellOffset;
4019 PHASH_TABLE_CELL NewHashTableCell;
4020 ULONG NewHashTableSize;
4021 BLOCK_OFFSET NewHashTableOffset;
4022 ULONG i;
4023 NTSTATUS Status;
4024
4025 DPRINT ("CmiCopyKey() called\n");
4026
4027 if (DstKeyCell == NULL)
4028 {
4029 /* Allocate and copy key cell */
4030 NewKeyCellSize = sizeof(KEY_CELL) + SrcKeyCell->NameSize;
4031 Status = CmiAllocateCell (DstHive,
4032 NewKeyCellSize,
4033 (PVOID) &NewKeyCell,
4034 &NewKeyCellOffset);
4035 if (!NT_SUCCESS(Status))
4036 {
4037 DPRINT1 ("CmiAllocateBlock() failed (Status %lx)\n", Status);
4038 return Status;
4039 }
4040 if (NewKeyCell == NULL)
4041 {
4042 DPRINT1 ("Failed to allocate a key cell\n");
4043 return STATUS_INSUFFICIENT_RESOURCES;
4044 }
4045
4046 RtlCopyMemory (NewKeyCell,
4047 SrcKeyCell,
4048 NewKeyCellSize);
4049
4050 DstHive->HiveHeader->RootKeyOffset = NewKeyCellOffset;
4051
4052 /* Copy class name */
4053 if (SrcKeyCell->ClassNameOffset != (BLOCK_OFFSET) -1)
4054 {
4055 PDATA_CELL SrcClassNameCell;
4056 PDATA_CELL NewClassNameCell;
4057 BLOCK_OFFSET NewClassNameOffset;
4058
4059 SrcClassNameCell = CmiGetCell (SrcHive, SrcKeyCell->ClassNameOffset, NULL),
4060
4061 NewKeyCell->ClassSize = SrcKeyCell->ClassSize;
4062 Status = CmiAllocateCell (DstHive,
4063 sizeof(CELL_HEADER) + NewKeyCell->ClassSize,
4064 (PVOID)&NewClassNameCell,
4065 &NewClassNameOffset);
4066 if (!NT_SUCCESS(Status))
4067 {
4068 DPRINT1 ("CmiAllocateBlock() failed (Status %lx)\n", Status);
4069 return Status;
4070 }
4071
4072 RtlCopyMemory (NewClassNameCell,
4073 SrcClassNameCell,
4074 NewKeyCell->ClassSize);
4075 NewKeyCell->ClassNameOffset = NewClassNameOffset;
4076 }
4077 }
4078 else
4079 {
4080 NewKeyCell = DstKeyCell;
4081 }
4082
4083 /* Allocate hash table */
4084 if (SrcKeyCell->NumberOfSubKeys > 0)
4085 {
4086 NewHashTableSize = ROUND_UP(SrcKeyCell->NumberOfSubKeys + 1, 4) - 1;
4087 Status = CmiAllocateHashTableCell (DstHive,
4088 &NewHashTableCell,
4089 &NewHashTableOffset,
4090 NewHashTableSize);
4091 if (!NT_SUCCESS(Status))
4092 {
4093 DPRINT1 ("CmiAllocateHashTableBlock() failed (Status %lx)\n", Status);
4094 return Status;
4095 }
4096 NewKeyCell->HashTableOffset = NewHashTableOffset;
4097 }
4098
4099 /* Allocate and copy value list and values */
4100 if (SrcKeyCell->NumberOfValues != 0)
4101 {
4102 PVALUE_LIST_CELL NewValueListCell;
4103 PVALUE_LIST_CELL SrcValueListCell;
4104 PVALUE_CELL NewValueCell;
4105 PVALUE_CELL SrcValueCell;
4106 PDATA_CELL SrcValueDataCell;
4107 PDATA_CELL NewValueDataCell;
4108 BLOCK_OFFSET ValueCellOffset;
4109 BLOCK_OFFSET ValueDataCellOffset;
4110 ULONG NewValueListCellSize;
4111 ULONG NewValueCellSize;
4112
4113
4114 NewValueListCellSize =
4115 ROUND_UP(SrcKeyCell->NumberOfValues, 4) * sizeof(BLOCK_OFFSET);
4116 Status = CmiAllocateCell (DstHive,
4117 NewValueListCellSize,
4118 (PVOID)&NewValueListCell,
4119 &NewKeyCell->ValueListOffset);
4120 if (!NT_SUCCESS(Status))
4121 {
4122 DPRINT1 ("CmiAllocateBlock() failed (Status %lx)\n", Status);
4123 return Status;
4124 }
4125
4126 RtlZeroMemory (NewValueListCell,
4127 NewValueListCellSize);
4128
4129 /* Copy values */
4130 SrcValueListCell = CmiGetCell (SrcHive, SrcKeyCell->ValueListOffset, NULL);
4131 for (i = 0; i < SrcKeyCell->NumberOfValues; i++)
4132 {
4133 /* Copy value cell */
4134 SrcValueCell = CmiGetCell (SrcHive, SrcValueListCell->ValueOffset[i], NULL);
4135
4136 NewValueCellSize = sizeof(VALUE_CELL) + SrcValueCell->NameSize;
4137 Status = CmiAllocateCell (DstHive,
4138 NewValueCellSize,
4139 (PVOID*) &NewValueCell,
4140 &ValueCellOffset);
4141 if (!NT_SUCCESS(Status))
4142 {
4143 DPRINT1 ("CmiAllocateBlock() failed (Status %lx)\n", Status);
4144 return Status;
4145 }
4146
4147 NewValueListCell->ValueOffset[i] = ValueCellOffset;
4148 RtlCopyMemory (NewValueCell,
4149 SrcValueCell,
4150 NewValueCellSize);
4151
4152 /* Copy value data cell */
4153 if (SrcValueCell->DataSize > (LONG) sizeof(PVOID))
4154 {
4155 SrcValueDataCell = CmiGetCell (SrcHive, SrcValueCell->DataOffset, NULL);
4156
4157 Status = CmiAllocateCell (DstHive,
4158 sizeof(CELL_HEADER) + SrcValueCell->DataSize,
4159 (PVOID*) &NewValueDataCell,
4160 &ValueDataCellOffset);
4161 if (!NT_SUCCESS(Status))
4162 {
4163 DPRINT1 ("CmiAllocateBlock() failed (Status %lx)\n", Status);
4164 return Status;
4165 }
4166 RtlCopyMemory (NewValueDataCell,
4167 SrcValueDataCell,
4168 SrcValueCell->DataSize);
4169 NewValueCell->DataOffset = ValueDataCellOffset;
4170 }
4171 }
4172 }
4173
4174 /* Copy subkeys */
4175 if (SrcKeyCell->NumberOfSubKeys > 0)
4176 {
4177 PHASH_TABLE_CELL SrcHashTableCell;
4178 PKEY_CELL SrcSubKeyCell;
4179 PKEY_CELL NewSubKeyCell;
4180 ULONG NewSubKeyCellSize;
4181 BLOCK_OFFSET NewSubKeyCellOffset;
4182 PHASH_RECORD SrcHashRecord;
4183
4184 SrcHashTableCell = CmiGetCell (SrcHive,
4185 SrcKeyCell->HashTableOffset,
4186 NULL);
4187
4188 for (i = 0; i < SrcKeyCell->NumberOfSubKeys; i++)
4189 {
4190 SrcHashRecord = &SrcHashTableCell->Table[i];
4191 SrcSubKeyCell = CmiGetCell (SrcHive, SrcHashRecord->KeyOffset, NULL);
4192
4193 /* Allocate and copy key cell */
4194 NewSubKeyCellSize = sizeof(KEY_CELL) + SrcSubKeyCell->NameSize;
4195 Status = CmiAllocateCell (DstHive,
4196 NewSubKeyCellSize,
4197 (PVOID)&NewSubKeyCell,
4198 &NewSubKeyCellOffset);
4199 if (!NT_SUCCESS(Status))
4200 {
4201 DPRINT1 ("CmiAllocateBlock() failed (Status %lx)\n", Status);
4202 return Status;
4203 }
4204 if (NewKeyCell == NULL)
4205 {
4206 DPRINT1 ("Failed to allocate a sub key cell\n");
4207 return STATUS_INSUFFICIENT_RESOURCES;
4208 }
4209
4210 NewHashTableCell->Table[i].KeyOffset = NewSubKeyCellOffset;
4211 NewHashTableCell->Table[i].HashValue = SrcHashRecord->HashValue;
4212
4213 RtlCopyMemory (NewSubKeyCell,
4214 SrcSubKeyCell,
4215 NewSubKeyCellSize);
4216
4217 /* Copy class name */
4218 if (SrcSubKeyCell->ClassNameOffset != (BLOCK_OFFSET) -1)
4219 {
4220 PDATA_CELL SrcClassNameCell;
4221 PDATA_CELL NewClassNameCell;
4222 BLOCK_OFFSET NewClassNameOffset;
4223
4224 SrcClassNameCell = CmiGetCell (SrcHive,
4225 SrcSubKeyCell->ClassNameOffset,
4226 NULL),
4227
4228 NewSubKeyCell->ClassSize = SrcSubKeyCell->ClassSize;
4229 Status = CmiAllocateCell (DstHive,
4230 sizeof(CELL_HEADER) + NewSubKeyCell->ClassSize,
4231 (PVOID)&NewClassNameCell,
4232 &NewClassNameOffset);
4233 if (!NT_SUCCESS(Status))
4234 {
4235 DPRINT1 ("CmiAllocateBlock() failed (Status %lx)\n", Status);
4236 return Status;
4237 }
4238
4239 NewSubKeyCell->ClassNameOffset = NewClassNameOffset;
4240 RtlCopyMemory (NewClassNameCell,
4241 SrcClassNameCell,
4242 NewSubKeyCell->ClassSize);
4243 }
4244
4245 /* Copy subkey data and subkeys */
4246 Status = CmiCopyKey (DstHive,
4247 NewSubKeyCell,
4248 SrcHive,
4249 SrcSubKeyCell);
4250 if (!NT_SUCCESS(Status))
4251 {
4252 DPRINT1 ("CmiAllocateBlock() failed (Status %lx)\n", Status);
4253 return Status;
4254 }
4255 }
4256 }
4257
4258 return STATUS_SUCCESS;
4259 }
4260
4261
4262 NTSTATUS
4263 CmiSaveTempHive (PREGISTRY_HIVE Hive,
4264 HANDLE FileHandle)
4265 {
4266 IO_STATUS_BLOCK IoStatusBlock;
4267 LARGE_INTEGER FileOffset;
4268 ULONG BlockIndex;
4269 PVOID BlockPtr;
4270 NTSTATUS Status;
4271
4272 DPRINT ("CmiSaveTempHive() called\n");
4273
4274 Hive->HiveHeader->Checksum = CmiCalcChecksum ((PULONG)Hive->HiveHeader);
4275
4276 /* Write hive block */
4277 FileOffset.QuadPart = (ULONGLONG)0;
4278 Status = NtWriteFile (FileHandle,
4279 NULL,
4280 NULL,
4281 NULL,
4282 &IoStatusBlock,
4283 Hive->HiveHeader,
4284 sizeof(HIVE_HEADER),
4285 &FileOffset,
4286 NULL);
4287 if (!NT_SUCCESS(Status))
4288 {
4289 DPRINT1 ("NtWriteFile() failed (Status %lx)\n", Status);
4290 return Status;
4291 }
4292
4293 DPRINT ("Saving %lu blocks\n", Hive->BlockListSize);
4294 for (BlockIndex = 0; BlockIndex < Hive->BlockListSize; BlockIndex++)
4295 {
4296 BlockPtr = Hive->BlockList[BlockIndex].Block;
4297 DPRINT ("BlockPtr %p\n", BlockPtr);
4298
4299 FileOffset.QuadPart = (ULONGLONG)(BlockIndex + 1) * (ULONGLONG)REG_BLOCK_SIZE;
4300 DPRINT ("File offset %I64x\n", FileOffset.QuadPart);
4301
4302 /* Write hive block */
4303 Status = NtWriteFile (FileHandle,
4304 NULL,
4305 NULL,
4306 NULL,
4307 &IoStatusBlock,
4308 BlockPtr,
4309 REG_BLOCK_SIZE,
4310 &FileOffset,
4311 NULL);
4312 if (!NT_SUCCESS(Status))
4313 {
4314 DPRINT1 ("NtWriteFile() failed (Status %lx)\n", Status);
4315 return Status;
4316 }
4317 }
4318
4319 Status = NtFlushBuffersFile (FileHandle,
4320 &IoStatusBlock);
4321 if (!NT_SUCCESS(Status))
4322 {
4323 DPRINT1 ("NtFlushBuffersFile() failed (Status %lx)\n", Status);
4324 }
4325
4326 DPRINT ("CmiSaveTempHive() done\n");
4327
4328 return Status;
4329 }
4330
4331 /* EOF */