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