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