Continue of MSVC-compiling changes....
[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 < (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 RegistryHive,
2266 IN PKEY_CELL KeyCell,
2267 OUT PKEY_CELL *SubKeyCell,
2268 OUT BLOCK_OFFSET *BlockOffset,
2269 IN PUNICODE_STRING KeyName,
2270 IN ACCESS_MASK DesiredAccess,
2271 IN ULONG Attributes)
2272 {
2273 PHASH_TABLE_CELL HashBlock;
2274 PKEY_CELL CurSubKeyCell;
2275 ULONG i;
2276
2277 VERIFY_KEY_CELL(KeyCell);
2278
2279 DPRINT("Scanning for sub key %wZ\n", KeyName);
2280
2281 assert(RegistryHive);
2282
2283 *SubKeyCell = NULL;
2284
2285 /* The key does not have any subkeys */
2286 if (KeyCell->HashTableOffset == (BLOCK_OFFSET)-1)
2287 {
2288 return STATUS_SUCCESS;
2289 }
2290
2291 /* Get hash table */
2292 HashBlock = CmiGetCell (RegistryHive, KeyCell->HashTableOffset, NULL);
2293 if (HashBlock == NULL)
2294 {
2295 DPRINT("CmiGetBlock() failed\n");
2296 return STATUS_UNSUCCESSFUL;
2297 }
2298
2299 for (i = 0; (i < KeyCell->NumberOfSubKeys) && (i < HashBlock->HashTableSize); i++)
2300 {
2301 if (Attributes & OBJ_CASE_INSENSITIVE)
2302 {
2303 if (HashBlock->Table[i].KeyOffset != 0 &&
2304 HashBlock->Table[i].KeyOffset != (ULONG_PTR)-1 &&
2305 (HashBlock->Table[i].HashValue == 0 ||
2306 CmiCompareHashI(KeyName, (PCHAR)&HashBlock->Table[i].HashValue)))
2307 {
2308 CurSubKeyCell = CmiGetCell (RegistryHive,
2309 HashBlock->Table[i].KeyOffset,
2310 NULL);
2311 if (CurSubKeyCell == NULL)
2312 {
2313 DPRINT("CmiGetBlock() failed\n");
2314 return STATUS_UNSUCCESSFUL;
2315 }
2316
2317 if (CmiCompareKeyNamesI(KeyName, CurSubKeyCell))
2318 {
2319 *SubKeyCell = CurSubKeyCell;
2320 *BlockOffset = HashBlock->Table[i].KeyOffset;
2321 break;
2322 }
2323 }
2324 }
2325 else
2326 {
2327 if (HashBlock->Table[i].KeyOffset != 0 &&
2328 HashBlock->Table[i].KeyOffset != (ULONG_PTR) -1 &&
2329 (HashBlock->Table[i].HashValue == 0 ||
2330 CmiCompareHash(KeyName, (PCHAR)&HashBlock->Table[i].HashValue)))
2331 {
2332 CurSubKeyCell = CmiGetCell (RegistryHive,
2333 HashBlock->Table[i].KeyOffset,
2334 NULL);
2335 if (CurSubKeyCell == NULL)
2336 {
2337 DPRINT("CmiGetBlock() failed\n");
2338 return STATUS_UNSUCCESSFUL;
2339 }
2340
2341 if (CmiCompareKeyNames(KeyName, CurSubKeyCell))
2342 {
2343 *SubKeyCell = CurSubKeyCell;
2344 *BlockOffset = HashBlock->Table[i].KeyOffset;
2345 break;
2346 }
2347 }
2348 }
2349 }
2350
2351 return STATUS_SUCCESS;
2352 }
2353
2354
2355 NTSTATUS
2356 CmiAddSubKey(PREGISTRY_HIVE RegistryHive,
2357 PKEY_OBJECT ParentKey,
2358 PKEY_OBJECT SubKey,
2359 PUNICODE_STRING SubKeyName,
2360 ULONG TitleIndex,
2361 PUNICODE_STRING Class,
2362 ULONG CreateOptions)
2363 {
2364 PHASH_TABLE_CELL HashBlock;
2365 BLOCK_OFFSET NKBOffset;
2366 PKEY_CELL NewKeyCell;
2367 ULONG NewBlockSize;
2368 PKEY_CELL ParentKeyCell;
2369 PDATA_CELL ClassCell;
2370 NTSTATUS Status;
2371 USHORT NameSize;
2372 PWSTR NamePtr;
2373 BOOLEAN Packable;
2374 ULONG i;
2375
2376 ParentKeyCell = ParentKey->KeyCell;
2377
2378 VERIFY_KEY_CELL(ParentKeyCell);
2379
2380 /* Skip leading backslash */
2381 if (SubKeyName->Buffer[0] == L'\\')
2382 {
2383 NamePtr = &SubKeyName->Buffer[1];
2384 NameSize = SubKeyName->Length - sizeof(WCHAR);
2385 }
2386 else
2387 {
2388 NamePtr = SubKeyName->Buffer;
2389 NameSize = SubKeyName->Length;
2390 }
2391
2392 /* Check whether key name can be packed */
2393 Packable = TRUE;
2394 for (i = 0; i < NameSize / sizeof(WCHAR); i++)
2395 {
2396 if (NamePtr[i] & 0xFF00)
2397 {
2398 Packable = FALSE;
2399 break;
2400 }
2401 }
2402
2403 /* Adjust name size */
2404 if (Packable)
2405 {
2406 NameSize = NameSize / sizeof(WCHAR);
2407 }
2408
2409 DPRINT("Key %S Length %lu %s\n", NamePtr, NameSize, (Packable)?"True":"False");
2410
2411 Status = STATUS_SUCCESS;
2412
2413 NewBlockSize = sizeof(KEY_CELL) + NameSize;
2414 Status = CmiAllocateCell (RegistryHive,
2415 NewBlockSize,
2416 (PVOID) &NewKeyCell,
2417 &NKBOffset);
2418 if (NewKeyCell == NULL)
2419 {
2420 Status = STATUS_INSUFFICIENT_RESOURCES;
2421 }
2422 else
2423 {
2424 NewKeyCell->Id = REG_KEY_CELL_ID;
2425 NewKeyCell->Flags = 0;
2426 NtQuerySystemTime(&NewKeyCell->LastWriteTime);
2427 NewKeyCell->ParentKeyOffset = -1;
2428 NewKeyCell->NumberOfSubKeys = 0;
2429 NewKeyCell->HashTableOffset = -1;
2430 NewKeyCell->NumberOfValues = 0;
2431 NewKeyCell->ValueListOffset = -1;
2432 NewKeyCell->SecurityKeyOffset = -1;
2433 NewKeyCell->ClassNameOffset = -1;
2434
2435 /* Pack the key name */
2436 NewKeyCell->NameSize = NameSize;
2437 if (Packable)
2438 {
2439 NewKeyCell->Flags |= REG_KEY_NAME_PACKED;
2440 for (i = 0; i < NameSize; i++)
2441 {
2442 NewKeyCell->Name[i] = (CHAR)(NamePtr[i] & 0x00FF);
2443 }
2444 }
2445 else
2446 {
2447 RtlCopyMemory(NewKeyCell->Name,
2448 NamePtr,
2449 NameSize);
2450 }
2451
2452 VERIFY_KEY_CELL(NewKeyCell);
2453
2454 if (Class != NULL)
2455 {
2456 NewKeyCell->ClassSize = Class->Length;
2457 Status = CmiAllocateCell (RegistryHive,
2458 sizeof(CELL_HEADER) + NewKeyCell->ClassSize,
2459 (PVOID)&ClassCell,
2460 &NewKeyCell->ClassNameOffset);
2461 RtlCopyMemory (ClassCell->Data,
2462 Class->Buffer,
2463 Class->Length);
2464 }
2465 }
2466
2467 if (!NT_SUCCESS(Status))
2468 {
2469 return Status;
2470 }
2471
2472 SubKey->KeyCell = NewKeyCell;
2473 SubKey->KeyCellOffset = NKBOffset;
2474
2475 /* Don't modify hash table if key is located in a pointer-based hive and parent key is not */
2476 if (IsPointerHive(RegistryHive) && (!IsPointerHive(ParentKey->RegistryHive)))
2477 {
2478 return(Status);
2479 }
2480
2481 if (ParentKeyCell->HashTableOffset == (ULONG_PTR) -1)
2482 {
2483 Status = CmiAllocateHashTableCell (RegistryHive,
2484 &HashBlock,
2485 &ParentKeyCell->HashTableOffset,
2486 REG_INIT_HASH_TABLE_SIZE);
2487 if (!NT_SUCCESS(Status))
2488 {
2489 return(Status);
2490 }
2491 }
2492 else
2493 {
2494 HashBlock = CmiGetCell (RegistryHive,
2495 ParentKeyCell->HashTableOffset,
2496 NULL);
2497 if (HashBlock == NULL)
2498 {
2499 DPRINT("CmiGetCell() failed\n");
2500 return STATUS_UNSUCCESSFUL;
2501 }
2502
2503 if (((ParentKeyCell->NumberOfSubKeys + 1) >= HashBlock->HashTableSize))
2504 {
2505 PHASH_TABLE_CELL NewHashBlock;
2506 BLOCK_OFFSET HTOffset;
2507
2508 /* Reallocate the hash table cell */
2509 Status = CmiAllocateHashTableCell (RegistryHive,
2510 &NewHashBlock,
2511 &HTOffset,
2512 HashBlock->HashTableSize +
2513 REG_EXTEND_HASH_TABLE_SIZE);
2514 if (!NT_SUCCESS(Status))
2515 {
2516 return Status;
2517 }
2518
2519 RtlZeroMemory(&NewHashBlock->Table[0],
2520 sizeof(NewHashBlock->Table[0]) * NewHashBlock->HashTableSize);
2521 RtlCopyMemory(&NewHashBlock->Table[0],
2522 &HashBlock->Table[0],
2523 sizeof(NewHashBlock->Table[0]) * HashBlock->HashTableSize);
2524 CmiDestroyCell (RegistryHive,
2525 HashBlock,
2526 ParentKeyCell->HashTableOffset);
2527 ParentKeyCell->HashTableOffset = HTOffset;
2528 HashBlock = NewHashBlock;
2529 }
2530 }
2531
2532 Status = CmiAddKeyToHashTable(RegistryHive,
2533 HashBlock,
2534 ParentKeyCell->HashTableOffset,
2535 NewKeyCell,
2536 NKBOffset);
2537 if (NT_SUCCESS(Status))
2538 {
2539 ParentKeyCell->NumberOfSubKeys++;
2540 }
2541
2542 NtQuerySystemTime (&ParentKeyCell->LastWriteTime);
2543 CmiMarkBlockDirty (RegistryHive, ParentKey->KeyCellOffset);
2544
2545 return(Status);
2546 }
2547
2548
2549 NTSTATUS
2550 CmiRemoveSubKey(PREGISTRY_HIVE RegistryHive,
2551 PKEY_OBJECT ParentKey,
2552 PKEY_OBJECT SubKey)
2553 {
2554 PHASH_TABLE_CELL HashBlock;
2555 PVALUE_LIST_CELL ValueList;
2556 PVALUE_CELL ValueCell;
2557 PDATA_CELL DataCell;
2558 ULONG i;
2559
2560 DPRINT("CmiRemoveSubKey() called\n");
2561
2562 /* Remove all values */
2563 if (SubKey->KeyCell->NumberOfValues != 0)
2564 {
2565 /* Get pointer to the value list cell */
2566 ValueList = CmiGetCell (RegistryHive,
2567 SubKey->KeyCell->ValueListOffset,
2568 NULL);
2569 if (ValueList == NULL)
2570 {
2571 DPRINT("CmiGetCell() failed\n");
2572 return STATUS_UNSUCCESSFUL;
2573 }
2574
2575 if (ValueList != NULL)
2576 {
2577 /* Enumerate all values */
2578 for (i = 0; i < SubKey->KeyCell->NumberOfValues; i++)
2579 {
2580 /* Get pointer to value cell */
2581 ValueCell = CmiGetCell (RegistryHive,
2582 ValueList->ValueOffset[i],
2583 NULL);
2584 if (ValueCell != NULL)
2585 {
2586 if (ValueCell->DataSize > sizeof(BLOCK_OFFSET))
2587 {
2588 DataCell = CmiGetCell (RegistryHive,
2589 ValueCell->DataOffset,
2590 NULL);
2591 if (DataCell == NULL)
2592 {
2593 DPRINT("CmiGetCell() failed\n");
2594 return STATUS_UNSUCCESSFUL;
2595 }
2596
2597 if (DataCell != NULL)
2598 {
2599 /* Destroy data cell */
2600 CmiDestroyCell (RegistryHive,
2601 DataCell,
2602 ValueCell->DataOffset);
2603 }
2604 }
2605
2606 /* Destroy value cell */
2607 CmiDestroyCell (RegistryHive,
2608 ValueCell,
2609 ValueList->ValueOffset[i]);
2610 }
2611 }
2612 }
2613
2614 /* Destroy value list cell */
2615 CmiDestroyCell (RegistryHive,
2616 ValueList,
2617 SubKey->KeyCell->ValueListOffset);
2618
2619 SubKey->KeyCell->NumberOfValues = 0;
2620 SubKey->KeyCell->ValueListOffset = (BLOCK_OFFSET)-1;
2621 }
2622
2623 /* Remove the key from the parent key's hash block */
2624 if (ParentKey->KeyCell->HashTableOffset != (BLOCK_OFFSET) -1)
2625 {
2626 DPRINT("ParentKey HashTableOffset %lx\n", ParentKey->KeyCell->HashTableOffset);
2627 HashBlock = CmiGetCell (ParentKey->RegistryHive,
2628 ParentKey->KeyCell->HashTableOffset,
2629 NULL);
2630 if (HashBlock == NULL)
2631 {
2632 DPRINT("CmiGetCell() failed\n");
2633 return STATUS_UNSUCCESSFUL;
2634 }
2635 DPRINT("ParentKey HashBlock %p\n", HashBlock);
2636 if (HashBlock != NULL)
2637 {
2638 CmiRemoveKeyFromHashTable(ParentKey->RegistryHive,
2639 HashBlock,
2640 SubKey->KeyCellOffset);
2641 CmiMarkBlockDirty(ParentKey->RegistryHive,
2642 ParentKey->KeyCell->HashTableOffset);
2643 }
2644 }
2645
2646 /* Remove the key's hash block */
2647 if (SubKey->KeyCell->HashTableOffset != (BLOCK_OFFSET) -1)
2648 {
2649 DPRINT("SubKey HashTableOffset %lx\n", SubKey->KeyCell->HashTableOffset);
2650 HashBlock = CmiGetCell (RegistryHive,
2651 SubKey->KeyCell->HashTableOffset,
2652 NULL);
2653 if (HashBlock == NULL)
2654 {
2655 DPRINT("CmiGetCell() failed\n");
2656 return STATUS_UNSUCCESSFUL;
2657 }
2658 DPRINT("SubKey HashBlock %p\n", HashBlock);
2659 if (HashBlock != NULL)
2660 {
2661 CmiDestroyCell (RegistryHive,
2662 HashBlock,
2663 SubKey->KeyCell->HashTableOffset);
2664 SubKey->KeyCell->HashTableOffset = -1;
2665 }
2666 }
2667
2668 /* Decrement the number of the parent key's sub keys */
2669 if (ParentKey != NULL)
2670 {
2671 DPRINT("ParentKey %p\n", ParentKey);
2672 ParentKey->KeyCell->NumberOfSubKeys--;
2673
2674 /* Remove the parent key's hash table */
2675 if (ParentKey->KeyCell->NumberOfSubKeys == 0)
2676 {
2677 DPRINT("ParentKey HashTableOffset %lx\n", ParentKey->KeyCell->HashTableOffset);
2678 HashBlock = CmiGetCell (ParentKey->RegistryHive,
2679 ParentKey->KeyCell->HashTableOffset,
2680 NULL);
2681 if (HashBlock == NULL)
2682 {
2683 DPRINT("CmiGetCell() failed\n");
2684 return STATUS_UNSUCCESSFUL;
2685 }
2686 DPRINT("ParentKey HashBlock %p\n", HashBlock);
2687 if (HashBlock != NULL)
2688 {
2689 CmiDestroyCell (ParentKey->RegistryHive,
2690 HashBlock,
2691 ParentKey->KeyCell->HashTableOffset);
2692 ParentKey->KeyCell->HashTableOffset = (BLOCK_OFFSET)-1;
2693 }
2694 }
2695
2696 NtQuerySystemTime(&ParentKey->KeyCell->LastWriteTime);
2697 CmiMarkBlockDirty(ParentKey->RegistryHive,
2698 ParentKey->KeyCellOffset);
2699 }
2700
2701 /* Destroy key cell */
2702 CmiDestroyCell (RegistryHive,
2703 SubKey->KeyCell,
2704 SubKey->KeyCellOffset);
2705 SubKey->KeyCell = NULL;
2706 SubKey->KeyCellOffset = (BLOCK_OFFSET)-1;
2707
2708 return(STATUS_SUCCESS);
2709 }
2710
2711
2712 NTSTATUS
2713 CmiScanKeyForValue(IN PREGISTRY_HIVE RegistryHive,
2714 IN PKEY_CELL KeyCell,
2715 IN PUNICODE_STRING ValueName,
2716 OUT PVALUE_CELL *ValueCell,
2717 OUT BLOCK_OFFSET *VBOffset)
2718 {
2719 PVALUE_LIST_CELL ValueListCell;
2720 PVALUE_CELL CurValueCell;
2721 ULONG i;
2722
2723 *ValueCell = NULL;
2724
2725 /* The key does not have any values */
2726 if (KeyCell->ValueListOffset == (BLOCK_OFFSET)-1)
2727 {
2728 return STATUS_SUCCESS;
2729 }
2730
2731 ValueListCell = CmiGetCell (RegistryHive, KeyCell->ValueListOffset, NULL);
2732 if (ValueListCell == NULL)
2733 {
2734 DPRINT("ValueListCell is NULL\n");
2735 return STATUS_UNSUCCESSFUL;
2736 }
2737
2738 VERIFY_VALUE_LIST_CELL(ValueListCell);
2739
2740 for (i = 0; i < KeyCell->NumberOfValues; i++)
2741 {
2742 CurValueCell = CmiGetCell (RegistryHive,
2743 ValueListCell->ValueOffset[i],
2744 NULL);
2745 if (CurValueCell == NULL)
2746 {
2747 DPRINT("CmiGetBlock() failed\n");
2748 return STATUS_UNSUCCESSFUL;
2749 }
2750
2751 if ((CurValueCell != NULL) &&
2752 CmiComparePackedNames(ValueName,
2753 CurValueCell->Name,
2754 CurValueCell->NameSize,
2755 CurValueCell->Flags & REG_VALUE_NAME_PACKED))
2756 {
2757 *ValueCell = CurValueCell;
2758 if (VBOffset)
2759 *VBOffset = ValueListCell->ValueOffset[i];
2760 //DPRINT("Found value %s\n", ValueName);
2761 break;
2762 }
2763 }
2764
2765 return STATUS_SUCCESS;
2766 }
2767
2768
2769 NTSTATUS
2770 CmiGetValueFromKeyByIndex(IN PREGISTRY_HIVE RegistryHive,
2771 IN PKEY_CELL KeyCell,
2772 IN ULONG Index,
2773 OUT PVALUE_CELL *ValueCell)
2774 {
2775 PVALUE_LIST_CELL ValueListCell;
2776 PVALUE_CELL CurValueCell;
2777
2778 *ValueCell = NULL;
2779
2780 if (KeyCell->ValueListOffset == (BLOCK_OFFSET)-1)
2781 {
2782 return STATUS_NO_MORE_ENTRIES;
2783 }
2784
2785 if (Index >= KeyCell->NumberOfValues)
2786 {
2787 return STATUS_NO_MORE_ENTRIES;
2788 }
2789
2790
2791 ValueListCell = CmiGetCell (RegistryHive, KeyCell->ValueListOffset, NULL);
2792 if (ValueListCell == NULL)
2793 {
2794 DPRINT("CmiGetBlock() failed\n");
2795 return STATUS_UNSUCCESSFUL;
2796 }
2797
2798 VERIFY_VALUE_LIST_CELL(ValueListCell);
2799
2800
2801 CurValueCell = CmiGetCell (RegistryHive,
2802 ValueListCell->ValueOffset[Index],
2803 NULL);
2804 if (CurValueCell == NULL)
2805 {
2806 DPRINT("CmiGetBlock() failed\n");
2807 return STATUS_UNSUCCESSFUL;
2808 }
2809
2810 *ValueCell = CurValueCell;
2811
2812 return STATUS_SUCCESS;
2813 }
2814
2815
2816 NTSTATUS
2817 CmiAddValueToKey(IN PREGISTRY_HIVE RegistryHive,
2818 IN PKEY_CELL KeyCell,
2819 IN PUNICODE_STRING ValueName,
2820 OUT PVALUE_CELL *pValueCell,
2821 OUT BLOCK_OFFSET *pVBOffset)
2822 {
2823 PVALUE_LIST_CELL NewValueListCell;
2824 PVALUE_LIST_CELL ValueListCell;
2825 PVALUE_CELL NewValueCell;
2826 BLOCK_OFFSET VLBOffset;
2827 BLOCK_OFFSET VBOffset;
2828 ULONG CellSize;
2829 NTSTATUS Status;
2830
2831 Status = CmiAllocateValueCell(RegistryHive,
2832 &NewValueCell,
2833 &VBOffset,
2834 ValueName);
2835 if (!NT_SUCCESS(Status))
2836 {
2837 return Status;
2838 }
2839
2840 DPRINT("KeyCell->ValuesOffset %lu\n", (ULONG)KeyCell->ValueListOffset);
2841
2842 ValueListCell = CmiGetCell (RegistryHive, KeyCell->ValueListOffset, NULL);
2843
2844 if (ValueListCell == NULL)
2845 {
2846 CellSize = sizeof(VALUE_LIST_CELL) +
2847 (3 * sizeof(BLOCK_OFFSET));
2848 Status = CmiAllocateCell (RegistryHive,
2849 CellSize,
2850 (PVOID) &ValueListCell,
2851 &VLBOffset);
2852
2853 if (!NT_SUCCESS(Status))
2854 {
2855 CmiDestroyValueCell(RegistryHive, NewValueCell, VBOffset);
2856 return Status;
2857 }
2858 KeyCell->ValueListOffset = VLBOffset;
2859 }
2860 else if (KeyCell->NumberOfValues >=
2861 (((ULONG)ABS_VALUE(ValueListCell->CellSize) - sizeof(VALUE_LIST_CELL)) / sizeof(BLOCK_OFFSET)))
2862 {
2863 CellSize = sizeof(VALUE_LIST_CELL) +
2864 ((KeyCell->NumberOfValues + REG_VALUE_LIST_CELL_MULTIPLE) * sizeof(BLOCK_OFFSET));
2865 Status = CmiAllocateCell (RegistryHive,
2866 CellSize,
2867 (PVOID) &NewValueListCell,
2868 &VLBOffset);
2869 if (!NT_SUCCESS(Status))
2870 {
2871 CmiDestroyValueCell(RegistryHive, NewValueCell, VBOffset);
2872 return Status;
2873 }
2874
2875 RtlCopyMemory(&NewValueListCell->ValueOffset[0],
2876 &ValueListCell->ValueOffset[0],
2877 sizeof(BLOCK_OFFSET) * KeyCell->NumberOfValues);
2878 CmiDestroyCell (RegistryHive, ValueListCell, KeyCell->ValueListOffset);
2879 KeyCell->ValueListOffset = VLBOffset;
2880 ValueListCell = NewValueListCell;
2881 }
2882
2883 DPRINT("KeyCell->NumberOfValues %lu, ValueListCell->CellSize %lu (%lu %lx)\n",
2884 KeyCell->NumberOfValues,
2885 (ULONG)ABS_VALUE(ValueListCell->CellSize),
2886 ((ULONG)ABS_VALUE(ValueListCell->CellSize) - sizeof(VALUE_LIST_CELL)) / sizeof(BLOCK_OFFSET),
2887 ((ULONG)ABS_VALUE(ValueListCell->CellSize) - sizeof(VALUE_LIST_CELL)) / sizeof(BLOCK_OFFSET));
2888
2889 ValueListCell->ValueOffset[KeyCell->NumberOfValues] = VBOffset;
2890 KeyCell->NumberOfValues++;
2891
2892 *pValueCell = NewValueCell;
2893 *pVBOffset = VBOffset;
2894
2895 return STATUS_SUCCESS;
2896 }
2897
2898
2899 NTSTATUS
2900 CmiDeleteValueFromKey(IN PREGISTRY_HIVE RegistryHive,
2901 IN PKEY_CELL KeyCell,
2902 IN BLOCK_OFFSET KeyCellOffset,
2903 IN PUNICODE_STRING ValueName)
2904 {
2905 PVALUE_LIST_CELL ValueListCell;
2906 PVALUE_CELL CurValueCell;
2907 ULONG i;
2908
2909 ValueListCell = CmiGetCell (RegistryHive, KeyCell->ValueListOffset, NULL);
2910
2911 if (ValueListCell == NULL)
2912 {
2913 DPRINT("CmiGetBlock() failed\n");
2914 return STATUS_SUCCESS;
2915 }
2916
2917 VERIFY_VALUE_LIST_CELL(ValueListCell);
2918
2919 for (i = 0; i < KeyCell->NumberOfValues; i++)
2920 {
2921 CurValueCell = CmiGetCell (RegistryHive, ValueListCell->ValueOffset[i], NULL);
2922 if (CurValueCell == NULL)
2923 {
2924 DPRINT("CmiGetBlock() failed\n");
2925 return STATUS_UNSUCCESSFUL;
2926 }
2927
2928 if ((CurValueCell != NULL) &&
2929 CmiComparePackedNames(ValueName,
2930 CurValueCell->Name,
2931 CurValueCell->NameSize,
2932 CurValueCell->Flags & REG_VALUE_NAME_PACKED))
2933 {
2934 CmiDestroyValueCell(RegistryHive, CurValueCell, ValueListCell->ValueOffset[i]);
2935
2936 if ((KeyCell->NumberOfValues - 1) < i)
2937 {
2938 RtlCopyMemory(&ValueListCell->ValueOffset[i],
2939 &ValueListCell->ValueOffset[i + 1],
2940 sizeof(BLOCK_OFFSET) * (KeyCell->NumberOfValues - 1 - i));
2941 }
2942 else
2943 {
2944 RtlZeroMemory(&ValueListCell->ValueOffset[i], sizeof(BLOCK_OFFSET));
2945 }
2946
2947 KeyCell->NumberOfValues -= 1;
2948 break;
2949 }
2950 }
2951
2952 if (KeyCell->NumberOfValues == 0)
2953 {
2954 CmiDestroyCell (RegistryHive,
2955 ValueListCell,
2956 KeyCell->ValueListOffset);
2957 }
2958 else
2959 {
2960 CmiMarkBlockDirty(RegistryHive,
2961 KeyCell->ValueListOffset);
2962 }
2963
2964 CmiMarkBlockDirty(RegistryHive,
2965 KeyCellOffset);
2966
2967 return STATUS_SUCCESS;
2968 }
2969
2970
2971 NTSTATUS
2972 CmiAllocateHashTableCell (IN PREGISTRY_HIVE RegistryHive,
2973 OUT PHASH_TABLE_CELL *HashBlock,
2974 OUT BLOCK_OFFSET *HBOffset,
2975 IN ULONG SubKeyCount)
2976 {
2977 PHASH_TABLE_CELL NewHashBlock;
2978 ULONG NewHashSize;
2979 NTSTATUS Status;
2980
2981 Status = STATUS_SUCCESS;
2982 *HashBlock = NULL;
2983 NewHashSize = sizeof(HASH_TABLE_CELL) +
2984 (SubKeyCount * sizeof(HASH_RECORD));
2985 Status = CmiAllocateCell (RegistryHive,
2986 NewHashSize,
2987 (PVOID*) &NewHashBlock,
2988 HBOffset);
2989
2990 if ((NewHashBlock == NULL) || (!NT_SUCCESS(Status)))
2991 {
2992 Status = STATUS_INSUFFICIENT_RESOURCES;
2993 }
2994 else
2995 {
2996 NewHashBlock->Id = REG_HASH_TABLE_CELL_ID;
2997 NewHashBlock->HashTableSize = SubKeyCount;
2998 *HashBlock = NewHashBlock;
2999 }
3000
3001 return Status;
3002 }
3003
3004
3005 PKEY_CELL
3006 CmiGetKeyFromHashByIndex(PREGISTRY_HIVE RegistryHive,
3007 PHASH_TABLE_CELL HashBlock,
3008 ULONG Index)
3009 {
3010 BLOCK_OFFSET KeyOffset;
3011 PKEY_CELL KeyCell;
3012
3013 if (HashBlock == NULL)
3014 return NULL;
3015
3016 if (IsPointerHive(RegistryHive))
3017 {
3018 KeyCell = (PKEY_CELL) HashBlock->Table[Index].KeyOffset;
3019 }
3020 else
3021 {
3022 KeyOffset = HashBlock->Table[Index].KeyOffset;
3023 KeyCell = CmiGetCell (RegistryHive, KeyOffset, NULL);
3024 }
3025
3026 return KeyCell;
3027 }
3028
3029
3030 NTSTATUS
3031 CmiAddKeyToHashTable(PREGISTRY_HIVE RegistryHive,
3032 PHASH_TABLE_CELL HashCell,
3033 BLOCK_OFFSET HashCellOffset,
3034 PKEY_CELL NewKeyCell,
3035 BLOCK_OFFSET NKBOffset)
3036 {
3037 ULONG i;
3038
3039 for (i = 0; i < HashCell->HashTableSize; i++)
3040 {
3041 if (HashCell->Table[i].KeyOffset == 0)
3042 {
3043 HashCell->Table[i].KeyOffset = NKBOffset;
3044 HashCell->Table[i].HashValue = 0;
3045 if (NewKeyCell->Flags & REG_KEY_NAME_PACKED)
3046 {
3047 RtlCopyMemory(&HashCell->Table[i].HashValue,
3048 NewKeyCell->Name,
3049 min(NewKeyCell->NameSize, sizeof(ULONG)));
3050 }
3051 CmiMarkBlockDirty(RegistryHive, HashCellOffset);
3052 return STATUS_SUCCESS;
3053 }
3054 }
3055
3056 return STATUS_UNSUCCESSFUL;
3057 }
3058
3059
3060 NTSTATUS
3061 CmiRemoveKeyFromHashTable(PREGISTRY_HIVE RegistryHive,
3062 PHASH_TABLE_CELL HashBlock,
3063 BLOCK_OFFSET NKBOffset)
3064 {
3065 ULONG i;
3066
3067 for (i = 0; i < HashBlock->HashTableSize; i++)
3068 {
3069 if (HashBlock->Table[i].KeyOffset == NKBOffset)
3070 {
3071 HashBlock->Table[i].KeyOffset = 0;
3072 HashBlock->Table[i].HashValue = 0;
3073 return STATUS_SUCCESS;
3074 }
3075 }
3076
3077 return STATUS_UNSUCCESSFUL;
3078 }
3079
3080
3081 NTSTATUS
3082 CmiAllocateValueCell(PREGISTRY_HIVE RegistryHive,
3083 PVALUE_CELL *ValueCell,
3084 BLOCK_OFFSET *VBOffset,
3085 IN PUNICODE_STRING ValueName)
3086 {
3087 PVALUE_CELL NewValueCell;
3088 NTSTATUS Status;
3089 BOOLEAN Packable;
3090 ULONG NameSize;
3091 ULONG i;
3092
3093 Status = STATUS_SUCCESS;
3094
3095 NameSize = CmiGetPackedNameLength(ValueName,
3096 &Packable);
3097
3098 DPRINT("ValueName->Length %lu NameSize %lu\n", ValueName->Length, NameSize);
3099
3100 Status = CmiAllocateCell (RegistryHive,
3101 sizeof(VALUE_CELL) + NameSize,
3102 (PVOID*) &NewValueCell,
3103 VBOffset);
3104 if ((NewValueCell == NULL) || (!NT_SUCCESS(Status)))
3105 {
3106 Status = STATUS_INSUFFICIENT_RESOURCES;
3107 }
3108 else
3109 {
3110 NewValueCell->Id = REG_VALUE_CELL_ID;
3111 NewValueCell->NameSize = NameSize;
3112 if (Packable)
3113 {
3114 /* Pack the value name */
3115 for (i = 0; i < NameSize; i++)
3116 NewValueCell->Name[i] = (CHAR)ValueName->Buffer[i];
3117 NewValueCell->Flags |= REG_VALUE_NAME_PACKED;
3118 }
3119 else
3120 {
3121 /* Copy the value name */
3122 RtlCopyMemory(NewValueCell->Name,
3123 ValueName->Buffer,
3124 NameSize);
3125 NewValueCell->Flags = 0;
3126 }
3127 NewValueCell->DataType = 0;
3128 NewValueCell->DataSize = 0;
3129 NewValueCell->DataOffset = (BLOCK_OFFSET)-1;
3130 *ValueCell = NewValueCell;
3131 }
3132
3133 return Status;
3134 }
3135
3136
3137 NTSTATUS
3138 CmiDestroyValueCell(PREGISTRY_HIVE RegistryHive,
3139 PVALUE_CELL ValueCell,
3140 BLOCK_OFFSET VBOffset)
3141 {
3142 NTSTATUS Status;
3143 PVOID pBlock;
3144 PHBIN pBin;
3145
3146 DPRINT("CmiDestroyValueCell(Cell %p Offset %lx)\n", ValueCell, VBOffset);
3147
3148 VERIFY_VALUE_CELL(ValueCell);
3149
3150 /* Destroy the data cell */
3151 if (ValueCell->DataSize > sizeof(BLOCK_OFFSET))
3152 {
3153 pBlock = CmiGetCell (RegistryHive, ValueCell->DataOffset, &pBin);
3154 if (pBlock == NULL)
3155 {
3156 DPRINT("CmiGetBlock() failed\n");
3157 return STATUS_UNSUCCESSFUL;
3158 }
3159
3160 Status = CmiDestroyCell (RegistryHive, pBlock, ValueCell->DataOffset);
3161 if (!NT_SUCCESS(Status))
3162 {
3163 return Status;
3164 }
3165
3166 /* Update time of heap */
3167 if (!IsNoFileHive(RegistryHive))
3168 NtQuerySystemTime(&pBin->DateModified);
3169 }
3170
3171 /* Destroy the value cell */
3172 Status = CmiDestroyCell (RegistryHive, ValueCell, VBOffset);
3173
3174 /* Update time of heap */
3175 if (!IsNoFileHive(RegistryHive) && CmiGetCell (RegistryHive, VBOffset, &pBin))
3176 {
3177 NtQuerySystemTime(&pBin->DateModified);
3178 }
3179
3180 return Status;
3181 }
3182
3183
3184 NTSTATUS
3185 CmiAddBin(PREGISTRY_HIVE RegistryHive,
3186 PVOID *NewBlock,
3187 BLOCK_OFFSET *NewBlockOffset)
3188 {
3189 PCELL_HEADER tmpBlock;
3190 PHBIN * tmpBlockList;
3191 PHBIN tmpBin;
3192
3193 tmpBin = ExAllocatePool(PagedPool, REG_BLOCK_SIZE);
3194 if (tmpBin == NULL)
3195 {
3196 return STATUS_INSUFFICIENT_RESOURCES;
3197 }
3198
3199 tmpBin->BlockId = REG_BIN_ID;
3200 tmpBin->BlockOffset = RegistryHive->FileSize - REG_BLOCK_SIZE;
3201 RegistryHive->FileSize += REG_BLOCK_SIZE;
3202 tmpBin->BlockSize = REG_BLOCK_SIZE;
3203 tmpBin->Unused1 = 0;
3204 ZwQuerySystemTime(&tmpBin->DateModified);
3205 tmpBin->Unused2 = 0;
3206
3207 /* Increase size of list of blocks */
3208 tmpBlockList = ExAllocatePool(NonPagedPool,
3209 sizeof(PHBIN *) * (RegistryHive->BlockListSize + 1));
3210 if (tmpBlockList == NULL)
3211 {
3212 ExFreePool(tmpBin);
3213 return STATUS_INSUFFICIENT_RESOURCES;
3214 }
3215
3216 if (RegistryHive->BlockListSize > 0)
3217 {
3218 RtlCopyMemory (tmpBlockList,
3219 RegistryHive->BlockList,
3220 sizeof(PHBIN *)*(RegistryHive->BlockListSize));
3221 ExFreePool(RegistryHive->BlockList);
3222 }
3223
3224 RegistryHive->BlockList = tmpBlockList;
3225 RegistryHive->BlockList[RegistryHive->BlockListSize] = tmpBin;
3226 RegistryHive->BlockListSize++;
3227
3228 /* Initialize a free block in this heap : */
3229 tmpBlock = (PCELL_HEADER)((ULONG_PTR) tmpBin + REG_HBIN_DATA_OFFSET);
3230 tmpBlock->CellSize = (REG_BLOCK_SIZE - REG_HBIN_DATA_OFFSET);
3231
3232 /* Grow bitmap if necessary */
3233 if (IsNoFileHive(RegistryHive) &&
3234 (RegistryHive->BlockListSize % (sizeof(ULONG) * 8) == 0))
3235 {
3236 PULONG BitmapBuffer;
3237 ULONG BitmapSize;
3238
3239 DPRINT("Grow hive bitmap\n");
3240
3241 /* Calculate bitmap size in bytes (always a multiple of 32 bits) */
3242 BitmapSize = ROUND_UP(RegistryHive->BlockListSize, sizeof(ULONG) * 8) / 8;
3243 DPRINT("RegistryHive->BlockListSize: %lu\n", RegistryHive->BlockListSize);
3244 DPRINT("BitmapSize: %lu Bytes %lu Bits\n", BitmapSize, BitmapSize * 8);
3245 BitmapBuffer = (PULONG)ExAllocatePool(PagedPool,
3246 BitmapSize);
3247 RtlZeroMemory(BitmapBuffer, BitmapSize);
3248 RtlCopyMemory(BitmapBuffer,
3249 RegistryHive->DirtyBitMap.Buffer,
3250 RegistryHive->DirtyBitMap.SizeOfBitMap);
3251 ExFreePool(RegistryHive->BitmapBuffer);
3252 RegistryHive->BitmapBuffer = BitmapBuffer;
3253 RtlInitializeBitMap(&RegistryHive->DirtyBitMap,
3254 RegistryHive->BitmapBuffer,
3255 BitmapSize * 8);
3256 }
3257
3258 *NewBlock = (PVOID) tmpBlock;
3259
3260 if (NewBlockOffset)
3261 *NewBlockOffset = tmpBin->BlockOffset + REG_HBIN_DATA_OFFSET;
3262
3263 /* Mark new bin dirty */
3264 CmiMarkBinDirty(RegistryHive,
3265 tmpBin->BlockOffset);
3266
3267 return STATUS_SUCCESS;
3268 }
3269
3270
3271 NTSTATUS
3272 CmiAllocateCell (PREGISTRY_HIVE RegistryHive,
3273 LONG CellSize,
3274 PVOID *Cell,
3275 BLOCK_OFFSET *CellOffset)
3276 {
3277 PCELL_HEADER NewCell;
3278 NTSTATUS Status;
3279 PHBIN pBin;
3280 ULONG i;
3281 PVOID Temp;
3282
3283 Status = STATUS_SUCCESS;
3284
3285 /* Round to 16 bytes multiple */
3286 CellSize = ROUND_UP(CellSize, 16);
3287
3288 /* Handle volatile hives first */
3289 if (IsPointerHive(RegistryHive))
3290 {
3291 NewCell = ExAllocatePool(NonPagedPool, CellSize);
3292
3293 if (NewCell == NULL)
3294 {
3295 Status = STATUS_INSUFFICIENT_RESOURCES;
3296 }
3297 else
3298 {
3299 RtlZeroMemory(NewCell, CellSize);
3300 NewCell->CellSize = -CellSize;
3301
3302 *Cell = NewCell;
3303 if (CellOffset != NULL)
3304 *CellOffset = (BLOCK_OFFSET) NewCell;
3305 }
3306 }
3307 else
3308 {
3309 /* first search in free blocks */
3310 NewCell = NULL;
3311 for (i = 0; i < RegistryHive->FreeListSize; i++)
3312 {
3313 if (RegistryHive->FreeList[i]->CellSize >= CellSize)
3314 {
3315 NewCell = RegistryHive->FreeList[i];
3316 if (CellOffset != NULL)
3317 *CellOffset = RegistryHive->FreeListOffset[i];
3318
3319 /* Update time of heap */
3320 Temp = CmiGetCell (RegistryHive, RegistryHive->FreeListOffset[i], &pBin);
3321 if (Temp == NULL)
3322 {
3323 DPRINT("CmiGetBlock() failed\n");
3324 return STATUS_UNSUCCESSFUL;
3325 }
3326
3327 if (Temp)
3328 {
3329 NtQuerySystemTime(&pBin->DateModified);
3330 CmiMarkBlockDirty(RegistryHive, RegistryHive->FreeListOffset[i]);
3331 }
3332
3333 if ((i + 1) < RegistryHive->FreeListSize)
3334 {
3335 RtlMoveMemory(&RegistryHive->FreeList[i],
3336 &RegistryHive->FreeList[i + 1],
3337 sizeof(RegistryHive->FreeList[0])
3338 * (RegistryHive->FreeListSize - i - 1));
3339 RtlMoveMemory(&RegistryHive->FreeListOffset[i],
3340 &RegistryHive->FreeListOffset[i + 1],
3341 sizeof(RegistryHive->FreeListOffset[0])
3342 * (RegistryHive->FreeListSize - i - 1));
3343 }
3344 RegistryHive->FreeListSize--;
3345 break;
3346 }
3347 }
3348
3349 /* Need to extend hive file : */
3350 if (NewCell == NULL)
3351 {
3352 /* Add a new bin */
3353 Status = CmiAddBin(RegistryHive, (PVOID *) &NewCell , CellOffset);
3354 }
3355
3356 if (NT_SUCCESS(Status))
3357 {
3358 *Cell = NewCell;
3359
3360 /* Split the block in two parts */
3361 if (NewCell->CellSize > CellSize)
3362 {
3363 NewCell = (PCELL_HEADER) ((ULONG_PTR) NewCell + CellSize);
3364 NewCell->CellSize = ((PCELL_HEADER) (*Cell))->CellSize - CellSize;
3365 CmiAddFree(RegistryHive,
3366 NewCell,
3367 *CellOffset + CellSize,
3368 TRUE);
3369 CmiMarkBlockDirty(RegistryHive,
3370 *CellOffset + CellSize);
3371 }
3372 else if (NewCell->CellSize < CellSize)
3373 {
3374 return(STATUS_UNSUCCESSFUL);
3375 }
3376
3377 RtlZeroMemory(*Cell, CellSize);
3378 ((PCELL_HEADER) (*Cell))->CellSize = -CellSize;
3379 }
3380 }
3381
3382 return(Status);
3383 }
3384
3385
3386 NTSTATUS
3387 CmiDestroyCell (PREGISTRY_HIVE RegistryHive,
3388 PVOID Cell,
3389 BLOCK_OFFSET CellOffset)
3390 {
3391 NTSTATUS Status;
3392 PHBIN pBin;
3393
3394 Status = STATUS_SUCCESS;
3395
3396 if (IsPointerHive(RegistryHive))
3397 {
3398 ExFreePool(Cell);
3399 }
3400 else
3401 {
3402 PCELL_HEADER pFree = Cell;
3403
3404 if (pFree->CellSize < 0)
3405 pFree->CellSize = -pFree->CellSize;
3406
3407 /* Clear block (except the block size) */
3408 RtlZeroMemory(((char*)pFree) + sizeof(ULONG),
3409 pFree->CellSize - sizeof(ULONG));
3410
3411 /* Add block to the list of free blocks */
3412 CmiAddFree(RegistryHive, Cell, CellOffset, TRUE);
3413
3414 /* Update time of heap */
3415 if (!IsNoFileHive(RegistryHive) && CmiGetCell (RegistryHive, CellOffset,&pBin))
3416 NtQuerySystemTime(&pBin->DateModified);
3417
3418 CmiMarkBlockDirty(RegistryHive, CellOffset);
3419 }
3420
3421 return Status;
3422 }
3423
3424
3425 PVOID
3426 CmiGetCell (PREGISTRY_HIVE RegistryHive,
3427 BLOCK_OFFSET CellOffset,
3428 PHBIN * ppBin)
3429 {
3430 PHBIN pBin;
3431
3432 if (ppBin)
3433 {
3434 *ppBin = NULL;
3435 }
3436
3437 if (CellOffset == (BLOCK_OFFSET)-1)
3438 {
3439 return NULL;
3440 }
3441
3442 if (IsPointerHive (RegistryHive))
3443 {
3444 return (PVOID)CellOffset;
3445 }
3446
3447 if (CellOffset > RegistryHive->BlockListSize * 4096)
3448 {
3449 DPRINT1("CellOffset exceeds valid range (%lu > %lu)\n",
3450 CellOffset, RegistryHive->BlockListSize * 4096);
3451 return NULL;
3452 }
3453
3454 pBin = RegistryHive->BlockList[CellOffset / 4096];
3455 if (pBin == NULL)
3456 {
3457 return NULL;
3458 }
3459
3460 if (ppBin)
3461 {
3462 *ppBin = pBin;
3463 }
3464
3465 return((PVOID)((ULONG_PTR)pBin + (CellOffset - pBin->BlockOffset)));
3466 }
3467
3468
3469 static BOOLEAN
3470 CmiMergeFree(PREGISTRY_HIVE RegistryHive,
3471 PCELL_HEADER FreeBlock,
3472 BLOCK_OFFSET FreeOffset)
3473 {
3474 BLOCK_OFFSET BlockOffset;
3475 BLOCK_OFFSET BinOffset;
3476 ULONG BlockSize;
3477 ULONG BinSize;
3478 PHBIN Bin;
3479 ULONG i;
3480
3481 DPRINT("CmiMergeFree(Block %lx Offset %lx Size %lx) called\n",
3482 FreeBlock, FreeOffset, FreeBlock->CellSize);
3483
3484 CmiGetCell (RegistryHive,
3485 FreeOffset,
3486 &Bin);
3487 DPRINT("Bin %p\n", Bin);
3488 if (Bin == NULL)
3489 return(FALSE);
3490
3491 BinOffset = Bin->BlockOffset;
3492 BinSize = Bin->BlockSize;
3493 DPRINT("Bin %p Offset %lx Size %lx\n", Bin, BinOffset, BinSize);
3494
3495 for (i = 0; i < RegistryHive->FreeListSize; i++)
3496 {
3497 BlockOffset = RegistryHive->FreeListOffset[i];
3498 BlockSize = RegistryHive->FreeList[i]->CellSize;
3499 if (BlockOffset > BinOffset &&
3500 BlockOffset < BinOffset + BinSize)
3501 {
3502 DPRINT("Free block: Offset %lx Size %lx\n",
3503 BlockOffset, BlockSize);
3504
3505 if ((i < (RegistryHive->FreeListSize - 1)) &&
3506 (BlockOffset + BlockSize == FreeOffset) &&
3507 (FreeOffset + FreeBlock->CellSize == RegistryHive->FreeListOffset[i + 1]))
3508 {
3509 DPRINT("Merge current block with previous and next block\n");
3510
3511 RegistryHive->FreeList[i]->CellSize +=
3512 (FreeBlock->CellSize + RegistryHive->FreeList[i + 1]->CellSize);
3513
3514 FreeBlock->CellSize = 0;
3515 RegistryHive->FreeList[i + 1]->CellSize = 0;
3516
3517
3518 if ((i + 2) < RegistryHive->FreeListSize)
3519 {
3520 RtlMoveMemory(&RegistryHive->FreeList[i + 1],
3521 &RegistryHive->FreeList[i + 2],
3522 sizeof(RegistryHive->FreeList[0])
3523 * (RegistryHive->FreeListSize - i - 2));
3524 RtlMoveMemory(&RegistryHive->FreeListOffset[i + 1],
3525 &RegistryHive->FreeListOffset[i + 2],
3526 sizeof(RegistryHive->FreeListOffset[0])
3527 * (RegistryHive->FreeListSize - i - 2));
3528 }
3529 RegistryHive->FreeListSize--;
3530
3531 CmiMarkBlockDirty(RegistryHive, BlockOffset);
3532
3533 return(TRUE);
3534 }
3535 else if (BlockOffset + BlockSize == FreeOffset)
3536 {
3537 DPRINT("Merge current block with previous block\n");
3538
3539 RegistryHive->FreeList[i]->CellSize += FreeBlock->CellSize;
3540 FreeBlock->CellSize = 0;
3541
3542 CmiMarkBlockDirty(RegistryHive, BlockOffset);
3543
3544 return(TRUE);
3545 }
3546 else if (FreeOffset + FreeBlock->CellSize == BlockOffset)
3547 {
3548 DPRINT("Merge current block with next block\n");
3549
3550 FreeBlock->CellSize += RegistryHive->FreeList[i]->CellSize;
3551 RegistryHive->FreeList[i]->CellSize = 0;
3552 RegistryHive->FreeList[i] = FreeBlock;
3553 RegistryHive->FreeListOffset[i] = FreeOffset;
3554
3555 CmiMarkBlockDirty(RegistryHive, FreeOffset);
3556
3557 return(TRUE);
3558 }
3559 }
3560 }
3561
3562 return(FALSE);
3563 }
3564
3565
3566 NTSTATUS
3567 CmiAddFree(PREGISTRY_HIVE RegistryHive,
3568 PCELL_HEADER FreeBlock,
3569 BLOCK_OFFSET FreeOffset,
3570 BOOLEAN MergeFreeBlocks)
3571 {
3572 PCELL_HEADER *tmpList;
3573 BLOCK_OFFSET *tmpListOffset;
3574 LONG minInd;
3575 LONG maxInd;
3576 LONG medInd;
3577
3578 assert(RegistryHive);
3579 assert(FreeBlock);
3580
3581 DPRINT("FreeBlock %.08lx FreeOffset %.08lx\n",
3582 FreeBlock, FreeOffset);
3583
3584 /* Merge free blocks */
3585 if (MergeFreeBlocks == TRUE)
3586 {
3587 if (CmiMergeFree(RegistryHive, FreeBlock, FreeOffset))
3588 return(STATUS_SUCCESS);
3589 }
3590
3591 if ((RegistryHive->FreeListSize + 1) > RegistryHive->FreeListMax)
3592 {
3593 tmpList = ExAllocatePool(PagedPool,
3594 sizeof(PCELL_HEADER) * (RegistryHive->FreeListMax + 32));
3595 if (tmpList == NULL)
3596 return STATUS_INSUFFICIENT_RESOURCES;
3597
3598 tmpListOffset = ExAllocatePool(PagedPool,
3599 sizeof(BLOCK_OFFSET) * (RegistryHive->FreeListMax + 32));
3600
3601 if (tmpListOffset == NULL)
3602 {
3603 ExFreePool(tmpList);
3604 return STATUS_INSUFFICIENT_RESOURCES;
3605 }
3606
3607 if (RegistryHive->FreeListMax)
3608 {
3609 RtlMoveMemory(tmpList,
3610 RegistryHive->FreeList,
3611 sizeof(PCELL_HEADER) * (RegistryHive->FreeListMax));
3612 RtlMoveMemory(tmpListOffset,
3613 RegistryHive->FreeListOffset,
3614 sizeof(BLOCK_OFFSET) * (RegistryHive->FreeListMax));
3615 ExFreePool(RegistryHive->FreeList);
3616 ExFreePool(RegistryHive->FreeListOffset);
3617 }
3618 RegistryHive->FreeList = tmpList;
3619 RegistryHive->FreeListOffset = tmpListOffset;
3620 RegistryHive->FreeListMax += 32;
3621 }
3622
3623 /* Add new offset to free list, maintaining list in ascending order */
3624 if ((RegistryHive->FreeListSize == 0)
3625 || (RegistryHive->FreeListOffset[RegistryHive->FreeListSize-1] < FreeOffset))
3626 {
3627 /* Add to end of list */
3628 RegistryHive->FreeList[RegistryHive->FreeListSize] = FreeBlock;
3629 RegistryHive->FreeListOffset[RegistryHive->FreeListSize++] = FreeOffset;
3630 }
3631 else if (RegistryHive->FreeListOffset[0] > FreeOffset)
3632 {
3633 /* Add to begin of list */
3634 RtlMoveMemory(&RegistryHive->FreeList[1],
3635 &RegistryHive->FreeList[0],
3636 sizeof(RegistryHive->FreeList[0]) * RegistryHive->FreeListSize);
3637 RtlMoveMemory(&RegistryHive->FreeListOffset[1],
3638 &RegistryHive->FreeListOffset[0],
3639 sizeof(RegistryHive->FreeListOffset[0]) * RegistryHive->FreeListSize);
3640 RegistryHive->FreeList[0] = FreeBlock;
3641 RegistryHive->FreeListOffset[0] = FreeOffset;
3642 RegistryHive->FreeListSize++;
3643 }
3644 else
3645 {
3646 /* Search where to insert */
3647 minInd = 0;
3648 maxInd = RegistryHive->FreeListSize - 1;
3649 while ((maxInd - minInd) > 1)
3650 {
3651 medInd = (minInd + maxInd) / 2;
3652 if (RegistryHive->FreeListOffset[medInd] > FreeOffset)
3653 maxInd = medInd;
3654 else
3655 minInd = medInd;
3656 }
3657
3658 /* Insert before maxInd */
3659 RtlMoveMemory(&RegistryHive->FreeList[maxInd+1],
3660 &RegistryHive->FreeList[maxInd],
3661 sizeof(RegistryHive->FreeList[0]) * (RegistryHive->FreeListSize - minInd));
3662 RtlMoveMemory(&RegistryHive->FreeListOffset[maxInd + 1],
3663 &RegistryHive->FreeListOffset[maxInd],
3664 sizeof(RegistryHive->FreeListOffset[0]) * (RegistryHive->FreeListSize-minInd));
3665 RegistryHive->FreeList[maxInd] = FreeBlock;
3666 RegistryHive->FreeListOffset[maxInd] = FreeOffset;
3667 RegistryHive->FreeListSize++;
3668 }
3669
3670 return STATUS_SUCCESS;
3671 }
3672
3673
3674 VOID
3675 CmiMarkBlockDirty(PREGISTRY_HIVE RegistryHive,
3676 BLOCK_OFFSET BlockOffset)
3677 {
3678 PDATA_CELL Cell;
3679 LONG CellSize;
3680 ULONG BlockNumber;
3681 ULONG BlockCount;
3682
3683 if (IsNoFileHive(RegistryHive))
3684 return;
3685
3686 DPRINT("CmiMarkBlockDirty(Offset 0x%lx)\n", (ULONG)BlockOffset);
3687
3688 BlockNumber = (ULONG)BlockOffset / 4096;
3689
3690 Cell = CmiGetCell (RegistryHive,
3691 BlockOffset,
3692 NULL);
3693
3694 CellSize = Cell->CellSize;
3695 if (CellSize < 0)
3696 CellSize = -CellSize;
3697
3698 BlockCount = (ROUND_UP(BlockOffset + CellSize, 4096) - ROUND_DOWN(BlockOffset, 4096)) / 4096;
3699
3700 DPRINT(" BlockNumber %lu Size %lu (%s) BlockCount %lu\n",
3701 BlockNumber,
3702 CellSize,
3703 (Cell->CellSize < 0) ? "used" : "free",
3704 BlockCount);
3705
3706 RegistryHive->HiveDirty = TRUE;
3707 RtlSetBits(&RegistryHive->DirtyBitMap,
3708 BlockNumber,
3709 BlockCount);
3710 }
3711
3712
3713 VOID
3714 CmiMarkBinDirty(PREGISTRY_HIVE RegistryHive,
3715 BLOCK_OFFSET BinOffset)
3716 {
3717 ULONG BlockNumber;
3718 ULONG BlockCount;
3719 PHBIN Bin;
3720
3721 if (IsNoFileHive(RegistryHive))
3722 return;
3723
3724 DPRINT("CmiMarkBinDirty(Offset 0x%lx)\n", (ULONG)BinOffset);
3725
3726 BlockNumber = (ULONG)BinOffset / 4096;
3727
3728 Bin = RegistryHive->BlockList[BlockNumber];
3729
3730 BlockCount = Bin->BlockSize / 4096;
3731
3732 DPRINT(" BlockNumber %lu Size %lu BlockCount %lu\n",
3733 BlockNumber,
3734 Bin->BlockSize,
3735 BlockCount);
3736
3737 RegistryHive->HiveDirty = TRUE;
3738 RtlSetBits(&RegistryHive->DirtyBitMap,
3739 BlockNumber,
3740 BlockCount);
3741 }
3742
3743
3744 ULONG
3745 CmiGetPackedNameLength(IN PUNICODE_STRING Name,
3746 OUT PBOOLEAN Packable)
3747 {
3748 ULONG i;
3749
3750 if (Packable != NULL)
3751 *Packable = TRUE;
3752
3753 for (i = 0; i < Name->Length / sizeof(WCHAR); i++)
3754 {
3755 if (Name->Buffer[i] & 0xFF00)
3756 {
3757 if (Packable != NULL)
3758 *Packable = FALSE;
3759 return Name->Length;
3760 }
3761 }
3762
3763 return (Name->Length / sizeof(WCHAR));
3764 }
3765
3766
3767 BOOLEAN
3768 CmiComparePackedNames(IN PUNICODE_STRING Name,
3769 IN PCHAR NameBuffer,
3770 IN USHORT NameBufferSize,
3771 IN BOOLEAN NamePacked)
3772 {
3773 PWCHAR UNameBuffer;
3774 ULONG i;
3775
3776 if (NamePacked == TRUE)
3777 {
3778 if (Name->Length != NameBufferSize * sizeof(WCHAR))
3779 return(FALSE);
3780
3781 for (i = 0; i < Name->Length / sizeof(WCHAR); i++)
3782 {
3783 if (RtlUpcaseUnicodeChar(Name->Buffer[i]) != RtlUpcaseUnicodeChar((WCHAR)NameBuffer[i]))
3784 return(FALSE);
3785 }
3786 }
3787 else
3788 {
3789 if (Name->Length != NameBufferSize)
3790 return(FALSE);
3791
3792 UNameBuffer = (PWCHAR)NameBuffer;
3793
3794 for (i = 0; i < Name->Length / sizeof(WCHAR); i++)
3795 {
3796 if (RtlUpcaseUnicodeChar(Name->Buffer[i]) != RtlUpcaseUnicodeChar(UNameBuffer[i]))
3797 return(FALSE);
3798 }
3799 }
3800
3801 return(TRUE);
3802 }
3803
3804
3805 VOID
3806 CmiCopyPackedName(PWCHAR NameBuffer,
3807 PCHAR PackedNameBuffer,
3808 ULONG PackedNameSize)
3809 {
3810 ULONG i;
3811
3812 for (i = 0; i < PackedNameSize; i++)
3813 NameBuffer[i] = (WCHAR)PackedNameBuffer[i];
3814 }
3815
3816
3817 BOOLEAN
3818 CmiCompareHash(PUNICODE_STRING KeyName,
3819 PCHAR HashString)
3820 {
3821 CHAR Buffer[4];
3822
3823 Buffer[0] = (KeyName->Length >= 2) ? (CHAR)KeyName->Buffer[0] : 0;
3824 Buffer[1] = (KeyName->Length >= 4) ? (CHAR)KeyName->Buffer[1] : 0;
3825 Buffer[2] = (KeyName->Length >= 6) ? (CHAR)KeyName->Buffer[2] : 0;
3826 Buffer[3] = (KeyName->Length >= 8) ? (CHAR)KeyName->Buffer[3] : 0;
3827
3828 return (strncmp(Buffer, HashString, 4) == 0);
3829 }
3830
3831
3832 BOOLEAN
3833 CmiCompareHashI(PUNICODE_STRING KeyName,
3834 PCHAR HashString)
3835 {
3836 CHAR Buffer[4];
3837
3838 Buffer[0] = (KeyName->Length >= 2) ? (CHAR)KeyName->Buffer[0] : 0;
3839 Buffer[1] = (KeyName->Length >= 4) ? (CHAR)KeyName->Buffer[1] : 0;
3840 Buffer[2] = (KeyName->Length >= 6) ? (CHAR)KeyName->Buffer[2] : 0;
3841 Buffer[3] = (KeyName->Length >= 8) ? (CHAR)KeyName->Buffer[3] : 0;
3842
3843 return (_strnicmp(Buffer, HashString, 4) == 0);
3844 }
3845
3846
3847 BOOLEAN
3848 CmiCompareKeyNames(PUNICODE_STRING KeyName,
3849 PKEY_CELL KeyCell)
3850 {
3851 PWCHAR UnicodeName;
3852 USHORT i;
3853
3854 DPRINT("Flags: %hx\n", KeyCell->Flags);
3855
3856 if (KeyCell->Flags & REG_KEY_NAME_PACKED)
3857 {
3858 if (KeyName->Length != KeyCell->NameSize * sizeof(WCHAR))
3859 return FALSE;
3860
3861 for (i = 0; i < KeyCell->NameSize; i++)
3862 {
3863 if (KeyName->Buffer[i] != (WCHAR)KeyCell->Name[i])
3864 return FALSE;
3865 }
3866 }
3867 else
3868 {
3869 if (KeyName->Length != KeyCell->NameSize)
3870 return FALSE;
3871
3872 UnicodeName = (PWCHAR)KeyCell->Name;
3873 for (i = 0; i < KeyCell->NameSize / sizeof(WCHAR); i++)
3874 {
3875 if (KeyName->Buffer[i] != UnicodeName[i])
3876 return FALSE;
3877 }
3878 }
3879
3880 return TRUE;
3881 }
3882
3883
3884 BOOLEAN
3885 CmiCompareKeyNamesI(PUNICODE_STRING KeyName,
3886 PKEY_CELL KeyCell)
3887 {
3888 PWCHAR UnicodeName;
3889 USHORT i;
3890
3891 DPRINT("Flags: %hx\n", KeyCell->Flags);
3892
3893 if (KeyCell->Flags & REG_KEY_NAME_PACKED)
3894 {
3895 if (KeyName->Length != KeyCell->NameSize * sizeof(WCHAR))
3896 return FALSE;
3897
3898 for (i = 0; i < KeyCell->NameSize; i++)
3899 {
3900 if (RtlUpcaseUnicodeChar(KeyName->Buffer[i]) !=
3901 RtlUpcaseUnicodeChar((WCHAR)KeyCell->Name[i]))
3902 return FALSE;
3903 }
3904 }
3905 else
3906 {
3907 if (KeyName->Length != KeyCell->NameSize)
3908 return FALSE;
3909
3910 UnicodeName = (PWCHAR)KeyCell->Name;
3911 for (i = 0; i < KeyCell->NameSize / sizeof(WCHAR); i++)
3912 {
3913 if (RtlUpcaseUnicodeChar(KeyName->Buffer[i]) !=
3914 RtlUpcaseUnicodeChar(UnicodeName[i]))
3915 return FALSE;
3916 }
3917 }
3918
3919 return TRUE;
3920 }
3921
3922
3923 NTSTATUS
3924 CmiCopyKey (PREGISTRY_HIVE DstHive,
3925 PKEY_CELL DstKeyCell,
3926 PREGISTRY_HIVE SrcHive,
3927 PKEY_CELL SrcKeyCell)
3928 {
3929 PKEY_CELL NewKeyCell;
3930 ULONG NewKeyCellSize;
3931 BLOCK_OFFSET NewKeyCellOffset;
3932 PHASH_TABLE_CELL NewHashTableCell;
3933 ULONG NewHashTableSize;
3934 BLOCK_OFFSET NewHashTableOffset;
3935 ULONG i;
3936 NTSTATUS Status;
3937
3938 DPRINT ("CmiCopyKey() called\n");
3939
3940 if (DstKeyCell == NULL)
3941 {
3942 /* Allocate and copy key cell */
3943 NewKeyCellSize = sizeof(KEY_CELL) + SrcKeyCell->NameSize;
3944 Status = CmiAllocateCell (DstHive,
3945 NewKeyCellSize,
3946 (PVOID) &NewKeyCell,
3947 &NewKeyCellOffset);
3948 if (!NT_SUCCESS(Status))
3949 {
3950 DPRINT1 ("CmiAllocateBlock() failed (Status %lx)\n", Status);
3951 return Status;
3952 }
3953 if (NewKeyCell == NULL)
3954 {
3955 DPRINT1 ("Failed to allocate a key cell\n");
3956 return STATUS_INSUFFICIENT_RESOURCES;
3957 }
3958
3959 RtlCopyMemory (NewKeyCell,
3960 SrcKeyCell,
3961 NewKeyCellSize);
3962
3963 DstHive->HiveHeader->RootKeyOffset = NewKeyCellOffset;
3964
3965 /* Copy class name */
3966 if (SrcKeyCell->ClassNameOffset != (BLOCK_OFFSET) -1)
3967 {
3968 PDATA_CELL SrcClassNameCell;
3969 PDATA_CELL NewClassNameCell;
3970 BLOCK_OFFSET NewClassNameOffset;
3971
3972 SrcClassNameCell = CmiGetCell (SrcHive, SrcKeyCell->ClassNameOffset, NULL),
3973
3974 NewKeyCell->ClassSize = SrcKeyCell->ClassSize;
3975 Status = CmiAllocateCell (DstHive,
3976 sizeof(CELL_HEADER) + NewKeyCell->ClassSize,
3977 (PVOID)&NewClassNameCell,
3978 &NewClassNameOffset);
3979 if (!NT_SUCCESS(Status))
3980 {
3981 DPRINT1 ("CmiAllocateBlock() failed (Status %lx)\n", Status);
3982 return Status;
3983 }
3984
3985 RtlCopyMemory (NewClassNameCell,
3986 SrcClassNameCell,
3987 NewKeyCell->ClassSize);
3988 NewKeyCell->ClassNameOffset = NewClassNameOffset;
3989 }
3990 }
3991 else
3992 {
3993 NewKeyCell = DstKeyCell;
3994 }
3995
3996 /* Allocate hash table */
3997 if (SrcKeyCell->NumberOfSubKeys > 0)
3998 {
3999 NewHashTableSize = ROUND_UP(SrcKeyCell->NumberOfSubKeys + 1, 4) - 1;
4000 Status = CmiAllocateHashTableCell (DstHive,
4001 &NewHashTableCell,
4002 &NewHashTableOffset,
4003 NewHashTableSize);
4004 if (!NT_SUCCESS(Status))
4005 {
4006 DPRINT1 ("CmiAllocateHashTableBlock() failed (Status %lx)\n", Status);
4007 return Status;
4008 }
4009 NewKeyCell->HashTableOffset = NewHashTableOffset;
4010 }
4011
4012 /* Allocate and copy value list and values */
4013 if (SrcKeyCell->NumberOfValues != 0)
4014 {
4015 PVALUE_LIST_CELL NewValueListCell;
4016 PVALUE_LIST_CELL SrcValueListCell;
4017 PVALUE_CELL NewValueCell;
4018 PVALUE_CELL SrcValueCell;
4019 PDATA_CELL SrcValueDataCell;
4020 PDATA_CELL NewValueDataCell;
4021 BLOCK_OFFSET ValueCellOffset;
4022 BLOCK_OFFSET ValueDataCellOffset;
4023 ULONG NewValueListCellSize;
4024 ULONG NewValueCellSize;
4025
4026
4027 NewValueListCellSize =
4028 ROUND_UP(SrcKeyCell->NumberOfValues, 4) * sizeof(BLOCK_OFFSET);
4029 Status = CmiAllocateCell (DstHive,
4030 NewValueListCellSize,
4031 (PVOID)&NewValueListCell,
4032 &NewKeyCell->ValueListOffset);
4033 if (!NT_SUCCESS(Status))
4034 {
4035 DPRINT1 ("CmiAllocateBlock() failed (Status %lx)\n", Status);
4036 return Status;
4037 }
4038
4039 RtlZeroMemory (NewValueListCell,
4040 NewValueListCellSize);
4041
4042 /* Copy values */
4043 SrcValueListCell = CmiGetCell (SrcHive, SrcKeyCell->ValueListOffset, NULL);
4044 for (i = 0; i < SrcKeyCell->NumberOfValues; i++)
4045 {
4046 /* Copy value cell */
4047 SrcValueCell = CmiGetCell (SrcHive, SrcValueListCell->ValueOffset[i], NULL);
4048
4049 NewValueCellSize = sizeof(VALUE_CELL) + SrcValueCell->NameSize;
4050 Status = CmiAllocateCell (DstHive,
4051 NewValueCellSize,
4052 (PVOID*) &NewValueCell,
4053 &ValueCellOffset);
4054 if (!NT_SUCCESS(Status))
4055 {
4056 DPRINT1 ("CmiAllocateBlock() failed (Status %lx)\n", Status);
4057 return Status;
4058 }
4059
4060 NewValueListCell->ValueOffset[i] = ValueCellOffset;
4061 RtlCopyMemory (NewValueCell,
4062 SrcValueCell,
4063 NewValueCellSize);
4064
4065 /* Copy value data cell */
4066 if (SrcValueCell->DataSize > (LONG) sizeof(PVOID))
4067 {
4068 SrcValueDataCell = CmiGetCell (SrcHive, SrcValueCell->DataOffset, NULL);
4069
4070 Status = CmiAllocateCell (DstHive,
4071 sizeof(CELL_HEADER) + SrcValueCell->DataSize,
4072 (PVOID*) &NewValueDataCell,
4073 &ValueDataCellOffset);
4074 if (!NT_SUCCESS(Status))
4075 {
4076 DPRINT1 ("CmiAllocateBlock() failed (Status %lx)\n", Status);
4077 return Status;
4078 }
4079 RtlCopyMemory (NewValueDataCell,
4080 SrcValueDataCell,
4081 SrcValueCell->DataSize);
4082 NewValueCell->DataOffset = ValueDataCellOffset;
4083 }
4084 }
4085 }
4086
4087 /* Copy subkeys */
4088 if (SrcKeyCell->NumberOfSubKeys > 0)
4089 {
4090 PHASH_TABLE_CELL SrcHashTableCell;
4091 PKEY_CELL SrcSubKeyCell;
4092 PKEY_CELL NewSubKeyCell;
4093 ULONG NewSubKeyCellSize;
4094 BLOCK_OFFSET NewSubKeyCellOffset;
4095 PHASH_RECORD SrcHashRecord;
4096
4097 SrcHashTableCell = CmiGetCell (SrcHive,
4098 SrcKeyCell->HashTableOffset,
4099 NULL);
4100
4101 for (i = 0; i < SrcKeyCell->NumberOfSubKeys; i++)
4102 {
4103 SrcHashRecord = &SrcHashTableCell->Table[i];
4104 SrcSubKeyCell = CmiGetCell (SrcHive, SrcHashRecord->KeyOffset, NULL);
4105
4106 /* Allocate and copy key cell */
4107 NewSubKeyCellSize = sizeof(KEY_CELL) + SrcSubKeyCell->NameSize;
4108 Status = CmiAllocateCell (DstHive,
4109 NewSubKeyCellSize,
4110 (PVOID)&NewSubKeyCell,
4111 &NewSubKeyCellOffset);
4112 if (!NT_SUCCESS(Status))
4113 {
4114 DPRINT1 ("CmiAllocateBlock() failed (Status %lx)\n", Status);
4115 return Status;
4116 }
4117 if (NewKeyCell == NULL)
4118 {
4119 DPRINT1 ("Failed to allocate a sub key cell\n");
4120 return STATUS_INSUFFICIENT_RESOURCES;
4121 }
4122
4123 NewHashTableCell->Table[i].KeyOffset = NewSubKeyCellOffset;
4124 NewHashTableCell->Table[i].HashValue = SrcHashRecord->HashValue;
4125
4126 RtlCopyMemory (NewSubKeyCell,
4127 SrcSubKeyCell,
4128 NewSubKeyCellSize);
4129
4130 /* Copy class name */
4131 if (SrcSubKeyCell->ClassNameOffset != (BLOCK_OFFSET) -1)
4132 {
4133 PDATA_CELL SrcClassNameCell;
4134 PDATA_CELL NewClassNameCell;
4135 BLOCK_OFFSET NewClassNameOffset;
4136
4137 SrcClassNameCell = CmiGetCell (SrcHive,
4138 SrcSubKeyCell->ClassNameOffset,
4139 NULL),
4140
4141 NewSubKeyCell->ClassSize = SrcSubKeyCell->ClassSize;
4142 Status = CmiAllocateCell (DstHive,
4143 sizeof(CELL_HEADER) + NewSubKeyCell->ClassSize,
4144 (PVOID)&NewClassNameCell,
4145 &NewClassNameOffset);
4146 if (!NT_SUCCESS(Status))
4147 {
4148 DPRINT1 ("CmiAllocateBlock() failed (Status %lx)\n", Status);
4149 return Status;
4150 }
4151
4152 NewSubKeyCell->ClassNameOffset = NewClassNameOffset;
4153 RtlCopyMemory (NewClassNameCell,
4154 SrcClassNameCell,
4155 NewSubKeyCell->ClassSize);
4156 }
4157
4158 /* Copy subkey data and subkeys */
4159 Status = CmiCopyKey (DstHive,
4160 NewSubKeyCell,
4161 SrcHive,
4162 SrcSubKeyCell);
4163 if (!NT_SUCCESS(Status))
4164 {
4165 DPRINT1 ("CmiAllocateBlock() failed (Status %lx)\n", Status);
4166 return Status;
4167 }
4168 }
4169 }
4170
4171 return STATUS_SUCCESS;
4172 }
4173
4174
4175 NTSTATUS
4176 CmiSaveTempHive (PREGISTRY_HIVE Hive,
4177 HANDLE FileHandle)
4178 {
4179 IO_STATUS_BLOCK IoStatusBlock;
4180 LARGE_INTEGER FileOffset;
4181 ULONG BlockIndex;
4182 PVOID BlockPtr;
4183 NTSTATUS Status;
4184
4185 DPRINT ("CmiSaveTempHive() called\n");
4186
4187 Hive->HiveHeader->Checksum = CmiCalcChecksum ((PULONG)Hive->HiveHeader);
4188
4189 /* Write hive block */
4190 #if defined(__GNUC__)
4191 FileOffset.QuadPart = 0ULL;
4192 #else
4193 FileOffset.QuadPart = 0;
4194 #endif
4195 Status = NtWriteFile (FileHandle,
4196 NULL,
4197 NULL,
4198 NULL,
4199 &IoStatusBlock,
4200 Hive->HiveHeader,
4201 sizeof(HIVE_HEADER),
4202 &FileOffset,
4203 NULL);
4204 if (!NT_SUCCESS(Status))
4205 {
4206 DPRINT1 ("NtWriteFile() failed (Status %lx)\n", Status);
4207 return Status;
4208 }
4209
4210 DPRINT ("Saving %lu blocks\n", Hive->BlockListSize);
4211 for (BlockIndex = 0; BlockIndex < Hive->BlockListSize; BlockIndex++)
4212 {
4213 BlockPtr = Hive->BlockList[BlockIndex];
4214 DPRINT ("BlockPtr %p\n", BlockPtr);
4215
4216 #if defined(__GNUC__)
4217 FileOffset.QuadPart = (ULONGLONG)(BlockIndex + 1) * 4096ULL;
4218 #else
4219 FileOffset.QuadPart = (ULONGLONG)(BlockIndex + 1) * 4096;
4220 #endif
4221 DPRINT ("File offset %I64x\n", FileOffset.QuadPart);
4222
4223 /* Write hive block */
4224 Status = NtWriteFile (FileHandle,
4225 NULL,
4226 NULL,
4227 NULL,
4228 &IoStatusBlock,
4229 BlockPtr,
4230 REG_BLOCK_SIZE,
4231 &FileOffset,
4232 NULL);
4233 if (!NT_SUCCESS(Status))
4234 {
4235 DPRINT1 ("NtWriteFile() failed (Status %lx)\n", Status);
4236 return Status;
4237 }
4238 }
4239
4240 Status = NtFlushBuffersFile (FileHandle,
4241 &IoStatusBlock);
4242 if (!NT_SUCCESS(Status))
4243 {
4244 DPRINT1 ("NtFlushBuffersFile() failed (Status %lx)\n", Status);
4245 }
4246
4247 DPRINT ("CmiSaveTempHive() done\n");
4248
4249 return Status;
4250 }
4251
4252 /* EOF */