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