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