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