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