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