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