Implemented import of binary system hive. (UNTESTED)
[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 <ddk/ntifs.h>
11 #include <roscfg.h>
12 #include <internal/ob.h>
13 #include <limits.h>
14 #include <string.h>
15 #include <internal/pool.h>
16 #include <internal/registry.h>
17 #include <reactos/bugcodes.h>
18
19 #define NDEBUG
20 #include <internal/debug.h>
21
22 #include "cm.h"
23
24
25 /* uncomment to enable hive checks (incomplete and probably buggy) */
26 // #define HIVE_CHECK
27
28 /* LOCAL MACROS *************************************************************/
29
30 #define ROUND_UP(N, S) ((((N) + (S) - 1) / (S)) * (S))
31 #define ROUND_DOWN(N, S) ((N) - ((N) % (S)))
32
33 #define ABS_VALUE(V) (((V) < 0) ? -(V) : (V))
34
35 BOOLEAN CmiDoVerify = FALSE;
36
37 static ULONG
38 CmiCalcChecksum(PULONG Buffer);
39
40 /* FUNCTIONS ****************************************************************/
41
42 VOID
43 CmiCreateDefaultHiveHeader(PHIVE_HEADER Header)
44 {
45 assert(Header);
46 RtlZeroMemory(Header, sizeof(HIVE_HEADER));
47 Header->BlockId = REG_HIVE_ID;
48 Header->UpdateCounter1 = 0;
49 Header->UpdateCounter2 = 0;
50 Header->DateModified.dwLowDateTime = 0;
51 Header->DateModified.dwHighDateTime = 0;
52 Header->Unused3 = 1;
53 Header->Unused4 = 3;
54 Header->Unused5 = 0;
55 Header->Unused6 = 1;
56 Header->Unused7 = 1;
57 Header->RootKeyCell = 0;
58 Header->BlockSize = REG_BLOCK_SIZE;
59 Header->Unused6 = 1;
60 Header->Checksum = 0;
61 }
62
63
64 VOID
65 CmiCreateDefaultBinCell(PHBIN BinCell)
66 {
67 assert(BinCell);
68 RtlZeroMemory(BinCell, sizeof(HBIN));
69 BinCell->BlockId = REG_BIN_ID;
70 BinCell->DateModified.dwLowDateTime = 0;
71 BinCell->DateModified.dwHighDateTime = 0;
72 BinCell->BlockSize = REG_BLOCK_SIZE;
73 }
74
75
76 VOID
77 CmiCreateDefaultRootKeyCell(PKEY_CELL RootKeyCell)
78 {
79 assert(RootKeyCell);
80 RtlZeroMemory(RootKeyCell, sizeof(KEY_CELL));
81 RootKeyCell->CellSize = -sizeof(KEY_CELL);
82 RootKeyCell->Id = REG_KEY_CELL_ID;
83 RootKeyCell->Type = REG_ROOT_KEY_CELL_TYPE;
84 NtQuerySystemTime((PTIME) &RootKeyCell->LastWriteTime);
85 RootKeyCell->ParentKeyOffset = 0;
86 RootKeyCell->NumberOfSubKeys = 0;
87 RootKeyCell->HashTableOffset = -1;
88 RootKeyCell->NumberOfValues = 0;
89 RootKeyCell->ValuesOffset = -1;
90 RootKeyCell->SecurityKeyOffset = 0;
91 RootKeyCell->ClassNameOffset = -1;
92 RootKeyCell->NameSize = 0;
93 RootKeyCell->ClassSize = 0;
94 }
95
96
97 VOID
98 CmiVerifyBinCell(PHBIN BinCell)
99 {
100 if (CmiDoVerify)
101 {
102
103 assert(BinCell);
104
105 if (BinCell->BlockId != REG_BIN_ID)
106 {
107 DbgPrint("BlockId is %.08x (should be %.08x)\n",
108 BinCell->BlockId, REG_BIN_ID);
109 assert(BinCell->BlockId == REG_BIN_ID);
110 }
111
112 //BinCell->DateModified.dwLowDateTime
113
114 //BinCell->DateModified.dwHighDateTime
115
116
117 if (BinCell->BlockSize != REG_BLOCK_SIZE)
118 {
119 DbgPrint("BlockSize is %.08x (should be %.08x)\n",
120 BinCell->BlockSize, REG_BLOCK_SIZE);
121 assert(BinCell->BlockSize == REG_BLOCK_SIZE);
122 }
123
124 }
125 }
126
127
128 VOID
129 CmiVerifyKeyCell(PKEY_CELL KeyCell)
130 {
131 if (CmiDoVerify)
132 {
133
134 assert(KeyCell);
135
136 if (KeyCell->CellSize == 0)
137 {
138 DbgPrint("CellSize is %d (must not be 0)\n",
139 KeyCell->CellSize);
140 assert(KeyCell->CellSize != 0);
141 }
142
143 if (KeyCell->Id != REG_KEY_CELL_ID)
144 {
145 DbgPrint("Id is %.08x (should be %.08x)\n",
146 KeyCell->Id, REG_KEY_CELL_ID);
147 assert(KeyCell->Id == REG_KEY_CELL_ID);
148 }
149
150 if ((KeyCell->Type != REG_KEY_CELL_TYPE)
151 && (KeyCell->Type != REG_ROOT_KEY_CELL_TYPE))
152 {
153 DbgPrint("Type is %.08x (should be %.08x or %.08x)\n",
154 KeyCell->Type, REG_KEY_CELL_TYPE, REG_ROOT_KEY_CELL_TYPE);
155 assert(FALSE);
156 }
157
158 //KeyCell->LastWriteTime;
159
160 if (KeyCell->ParentKeyOffset < 0)
161 {
162 DbgPrint("ParentKeyOffset is %d (must not be < 0)\n",
163 KeyCell->ParentKeyOffset);
164 assert(KeyCell->ParentKeyOffset >= 0);
165 }
166
167 if (KeyCell->NumberOfSubKeys < 0)
168 {
169 DbgPrint("NumberOfSubKeys is %d (must not be < 0)\n",
170 KeyCell->NumberOfSubKeys);
171 assert(KeyCell->NumberOfSubKeys >= 0);
172 }
173
174 //KeyCell->HashTableOffset;
175
176 if (KeyCell->NumberOfValues < 0)
177 {
178 DbgPrint("NumberOfValues is %d (must not be < 0)\n",
179 KeyCell->NumberOfValues);
180 assert(KeyCell->NumberOfValues >= 0);
181 }
182
183 //KeyCell->ValuesOffset = -1;
184
185 if (KeyCell->SecurityKeyOffset < 0)
186 {
187 DbgPrint("SecurityKeyOffset is %d (must not be < 0)\n",
188 KeyCell->SecurityKeyOffset);
189 assert(KeyCell->SecurityKeyOffset >= 0);
190 }
191
192 //KeyCell->ClassNameOffset = -1;
193
194 //KeyCell->NameSize
195
196 //KeyCell->ClassSize
197
198 }
199 }
200
201
202 VOID
203 CmiVerifyRootKeyCell(PKEY_CELL RootKeyCell)
204 {
205 if (CmiDoVerify)
206 {
207
208 CmiVerifyKeyCell(RootKeyCell);
209
210 if (RootKeyCell->Type != REG_ROOT_KEY_CELL_TYPE)
211 {
212 DbgPrint("Type is %.08x (should be %.08x)\n",
213 RootKeyCell->Type, REG_ROOT_KEY_CELL_TYPE);
214 assert(RootKeyCell->Type == REG_ROOT_KEY_CELL_TYPE);
215 }
216
217 }
218 }
219
220
221 VOID
222 CmiVerifyValueCell(PVALUE_CELL ValueCell)
223 {
224 if (CmiDoVerify)
225 {
226
227 assert(ValueCell);
228
229 if (ValueCell->CellSize == 0)
230 {
231 DbgPrint("CellSize is %d (must not be 0)\n",
232 ValueCell->CellSize);
233 assert(ValueCell->CellSize != 0);
234 }
235
236 if (ValueCell->Id != REG_VALUE_CELL_ID)
237 {
238 DbgPrint("Id is %.08x (should be %.08x)\n",
239 ValueCell->Id, REG_VALUE_CELL_ID);
240 assert(ValueCell->Id == REG_VALUE_CELL_ID);
241 }
242
243 //ValueCell->NameSize;
244 //ValueCell->LONG DataSize;
245 //ValueCell->DataOffset;
246 //ValueCell->ULONG DataType;
247 //ValueCell->USHORT Flags;
248 //ValueCell->USHORT Unused1;
249 //ValueCell->UCHAR Name[0];
250 }
251 }
252
253
254 VOID
255 CmiVerifyValueListCell(PVALUE_LIST_CELL ValueListCell)
256 {
257 if (CmiDoVerify)
258 {
259
260 if (ValueListCell->CellSize == 0)
261 {
262 DbgPrint("CellSize is %d (must not be 0)\n",
263 ValueListCell->CellSize);
264 assert(ValueListCell->CellSize != 0);
265 }
266
267 }
268 }
269
270
271 VOID
272 CmiVerifyKeyObject(PKEY_OBJECT KeyObject)
273 {
274 if (CmiDoVerify)
275 {
276
277 if (KeyObject->RegistryHive == NULL)
278 {
279 DbgPrint("RegistryHive is NULL (must not be NULL)\n",
280 KeyObject->RegistryHive);
281 assert(KeyObject->RegistryHive != NULL);
282 }
283
284 if (KeyObject->KeyCell == NULL)
285 {
286 DbgPrint("KeyCell is NULL (must not be NULL)\n",
287 KeyObject->KeyCell);
288 assert(KeyObject->KeyCell != NULL);
289 }
290
291 if (KeyObject->ParentKey == NULL)
292 {
293 DbgPrint("ParentKey is NULL (must not be NULL)\n",
294 KeyObject->ParentKey);
295 assert(KeyObject->ParentKey != NULL);
296 }
297
298 }
299 }
300
301
302 VOID
303 CmiVerifyHiveHeader(PHIVE_HEADER Header)
304 {
305 if (CmiDoVerify)
306 {
307
308 if (Header->BlockId != REG_HIVE_ID)
309 {
310 DbgPrint("BlockId is %.08x (must be %.08x)\n",
311 Header->BlockId,
312 REG_HIVE_ID);
313 assert(Header->BlockId == REG_HIVE_ID);
314 }
315
316 if (Header->Unused3 != 1)
317 {
318 DbgPrint("Unused3 is %.08x (must be 1)\n",
319 Header->Unused3);
320 assert(Header->Unused3 == 1);
321 }
322
323 if (Header->Unused4 != 3)
324 {
325 DbgPrint("Unused4 is %.08x (must be 3)\n",
326 Header->Unused4);
327 assert(Header->Unused4 == 3);
328 }
329
330 if (Header->Unused5 != 0)
331 {
332 DbgPrint("Unused5 is %.08x (must be 0)\n",
333 Header->Unused5);
334 assert(Header->Unused5 == 0);
335 }
336
337 if (Header->Unused6 != 1)
338 {
339 DbgPrint("Unused6 is %.08x (must be 1)\n",
340 Header->Unused6);
341 assert(Header->Unused6 == 1);
342 }
343
344 if (Header->Unused7 != 1)
345 {
346 DbgPrint("Unused7 is %.08x (must be 1)\n",
347 Header->Unused7);
348 assert(Header->Unused7 == 1);
349 }
350
351 }
352 }
353
354
355 VOID
356 CmiVerifyRegistryHive(PREGISTRY_HIVE RegistryHive)
357 {
358 if (CmiDoVerify)
359 {
360
361 CmiVerifyHiveHeader(RegistryHive->HiveHeader);
362
363 }
364 }
365
366
367 static NTSTATUS
368 CmiPopulateHive(HANDLE FileHandle)
369 {
370 IO_STATUS_BLOCK IoStatusBlock;
371 LARGE_INTEGER FileOffset;
372 PCELL_HEADER FreeCell;
373 NTSTATUS Status;
374 PHBIN BinCell;
375 PCHAR tBuf;
376 ULONG i;
377
378 tBuf = (PCHAR) ExAllocatePool(NonPagedPool, REG_BLOCK_SIZE);
379 if (tBuf == NULL)
380 return STATUS_INSUFFICIENT_RESOURCES;
381
382 BinCell = (PHBIN) tBuf;
383 FreeCell = (PCELL_HEADER) (tBuf + REG_HBIN_DATA_OFFSET);
384
385 CmiCreateDefaultBinCell(BinCell);
386
387 // The whole block is free
388 FreeCell->CellSize = REG_BLOCK_SIZE - REG_HBIN_DATA_OFFSET;
389
390 // Add free blocks so we don't need to expand
391 // the file for a while
392 for (i = 1; i < 50; i++)
393 {
394 // Block offset of this bin
395 BinCell->BlockOffset = i * REG_BLOCK_SIZE;
396
397 FileOffset.u.HighPart = 0;
398 FileOffset.u.LowPart = (i + 1) * REG_BLOCK_SIZE;
399
400 Status = NtWriteFile(FileHandle,
401 NULL,
402 NULL,
403 NULL,
404 &IoStatusBlock,
405 tBuf,
406 REG_BLOCK_SIZE,
407 &FileOffset,
408 NULL);
409 assertmsg(NT_SUCCESS(Status), ("Status: 0x%X\n", Status));
410 if (!NT_SUCCESS(Status))
411 {
412 ExFreePool(tBuf);
413 return Status;
414 }
415 }
416
417 ExFreePool(tBuf);
418
419 return Status;
420 }
421
422
423 static NTSTATUS
424 CmiCreateNewRegFile(HANDLE FileHandle)
425 {
426 IO_STATUS_BLOCK IoStatusBlock;
427 PCELL_HEADER FreeCell;
428 PHIVE_HEADER HiveHeader;
429 PKEY_CELL RootKeyCell;
430 NTSTATUS Status;
431 PHBIN BinCell;
432 PCHAR Buffer;
433
434 Buffer = (PCHAR) ExAllocatePool(NonPagedPool, 2 * REG_BLOCK_SIZE);
435 if (Buffer == NULL)
436 return STATUS_INSUFFICIENT_RESOURCES;
437
438 HiveHeader = (PHIVE_HEADER)Buffer;
439 BinCell = (PHBIN)((ULONG_PTR)Buffer + REG_BLOCK_SIZE);
440 RootKeyCell = (PKEY_CELL)((ULONG_PTR)Buffer + REG_BLOCK_SIZE + REG_HBIN_DATA_OFFSET);
441 FreeCell = (PCELL_HEADER)((ULONG_PTR)Buffer + REG_BLOCK_SIZE + REG_HBIN_DATA_OFFSET + sizeof(KEY_CELL));
442
443 CmiCreateDefaultHiveHeader(HiveHeader);
444 CmiCreateDefaultBinCell(BinCell);
445 CmiCreateDefaultRootKeyCell(RootKeyCell);
446
447 /* First block */
448 BinCell->BlockOffset = 0;
449
450 /* Offset to root key block */
451 HiveHeader->RootKeyCell = REG_HBIN_DATA_OFFSET;
452
453 /* The rest of the block is free */
454 FreeCell->CellSize = REG_BLOCK_SIZE - (REG_HBIN_DATA_OFFSET + sizeof(KEY_CELL));
455
456 Status = NtWriteFile(FileHandle,
457 NULL,
458 NULL,
459 NULL,
460 &IoStatusBlock,
461 Buffer,
462 2 * REG_BLOCK_SIZE,
463 0,
464 NULL);
465
466 ExFreePool(Buffer);
467
468 assertmsg(NT_SUCCESS(Status), ("Status: 0x%X\n", Status));
469
470 if (!NT_SUCCESS(Status))
471 {
472 return(Status);
473 }
474
475 #if 1
476 if (NT_SUCCESS(Status))
477 {
478 CmiPopulateHive(FileHandle);
479 }
480 #endif
481
482 Status = NtFlushBuffersFile(FileHandle,
483 &IoStatusBlock);
484
485 return(Status);
486 }
487
488
489 #ifdef HIVE_CHECK
490 static NTSTATUS
491 CmiCheckAndFixHive(PREGISTRY_HIVE RegistryHive)
492 {
493 OBJECT_ATTRIBUTES ObjectAttributes;
494 FILE_STANDARD_INFORMATION fsi;
495 IO_STATUS_BLOCK IoStatusBlock;
496 HANDLE HiveHandle = INVALID_HANDLE_VALUE;
497 HANDLE LogHandle = INVALID_HANDLE_VALUE;
498 PHIVE_HEADER HiveHeader = NULL;
499 PHIVE_HEADER LogHeader = NULL;
500 LARGE_INTEGER FileOffset;
501 ULONG FileSize;
502 ULONG BufferSize;
503 ULONG BitmapSize;
504 RTL_BITMAP BlockBitMap;
505 NTSTATUS Status;
506
507 DPRINT("CmiCheckAndFixHive() called\n");
508
509 /* Try to open the hive file */
510 InitializeObjectAttributes(&ObjectAttributes,
511 &RegistryHive->HiveFileName,
512 0,
513 NULL,
514 NULL);
515
516 Status = NtCreateFile(&HiveHandle,
517 FILE_READ_DATA | FILE_READ_ATTRIBUTES,
518 &ObjectAttributes,
519 &IoStatusBlock,
520 NULL,
521 FILE_ATTRIBUTE_NORMAL,
522 0,
523 FILE_OPEN,
524 FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT,
525 NULL,
526 0);
527 if (Status == STATUS_OBJECT_NAME_NOT_FOUND)
528 {
529 return(STATUS_SUCCESS);
530 }
531 if (!NT_SUCCESS(Status))
532 {
533 DPRINT("NtCreateFile() failed (Status %lx)\n", Status);
534 return(Status);
535 }
536
537 /* Try to open the log file */
538 InitializeObjectAttributes(&ObjectAttributes,
539 &RegistryHive->LogFileName,
540 0,
541 NULL,
542 NULL);
543
544 Status = NtCreateFile(&LogHandle,
545 FILE_READ_DATA | FILE_READ_ATTRIBUTES,
546 &ObjectAttributes,
547 &IoStatusBlock,
548 NULL,
549 FILE_ATTRIBUTE_NORMAL,
550 0,
551 FILE_OPEN,
552 FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT,
553 NULL,
554 0);
555 if (Status == STATUS_OBJECT_NAME_NOT_FOUND)
556 {
557 LogHandle = INVALID_HANDLE_VALUE;
558 }
559 else if (!NT_SUCCESS(Status))
560 {
561 DPRINT("NtCreateFile() failed (Status %lx)\n", Status);
562 NtClose(HiveHandle);
563 return(Status);
564 }
565
566 /* Allocate hive header */
567 HiveHeader = ExAllocatePool(PagedPool,
568 sizeof(HIVE_HEADER));
569 if (HiveHeader == NULL)
570 {
571 DPRINT("ExAllocatePool() failed\n");
572 Status = STATUS_INSUFFICIENT_RESOURCES;
573 goto ByeBye;
574 }
575
576 /* Read hive base block */
577 FileOffset.QuadPart = 0ULL;
578 Status = NtReadFile(HiveHandle,
579 0,
580 0,
581 0,
582 &IoStatusBlock,
583 HiveHeader,
584 sizeof(HIVE_HEADER),
585 &FileOffset,
586 0);
587 if (!NT_SUCCESS(Status))
588 {
589 DPRINT("NtReadFile() failed (Status %lx)\n", Status);
590 goto ByeBye;
591 }
592
593 if (LogHandle == INVALID_HANDLE_VALUE)
594 {
595 if (HiveHeader->Checksum != CmiCalcChecksum((PULONG)HiveHeader) ||
596 HiveHeader->UpdateCounter1 != HiveHeader->UpdateCounter2)
597 {
598 /* There is no way to fix the hive without log file - BSOD! */
599 DPRINT("Hive header inconsistent and no log file available!\n");
600 KeBugCheck(CONFIG_LIST_FAILED);
601 }
602
603 Status = STATUS_SUCCESS;
604 goto ByeBye;
605 }
606 else
607 {
608 /* Allocate hive header */
609 LogHeader = ExAllocatePool(PagedPool,
610 sizeof(HIVE_HEADER));
611 if (LogHeader == NULL)
612 {
613 DPRINT("ExAllocatePool() failed\n");
614 Status = STATUS_INSUFFICIENT_RESOURCES;
615 goto ByeBye;
616 }
617
618 /* Read log file header */
619 FileOffset.QuadPart = 0ULL;
620 Status = NtReadFile(LogHandle,
621 0,
622 0,
623 0,
624 &IoStatusBlock,
625 LogHeader,
626 sizeof(HIVE_HEADER),
627 &FileOffset,
628 0);
629 if (!NT_SUCCESS(Status))
630 {
631 DPRINT("NtReadFile() failed (Status %lx)\n", Status);
632 goto ByeBye;
633 }
634
635 /* Check log file header integrity */
636 if (LogHeader->Checksum != CmiCalcChecksum((PULONG)LogHeader) ||
637 LogHeader->UpdateCounter1 != LogHeader->UpdateCounter2)
638 {
639 if (HiveHeader->Checksum != CmiCalcChecksum((PULONG)HiveHeader) ||
640 HiveHeader->UpdateCounter1 != HiveHeader->UpdateCounter2)
641 {
642 DPRINT("Hive file and log file are inconsistent!\n");
643 KeBugCheck(CONFIG_LIST_FAILED);
644 }
645
646 /* Log file damaged but hive is okay */
647 Status = STATUS_SUCCESS;
648 goto ByeBye;
649 }
650
651 if (HiveHeader->UpdateCounter1 == HiveHeader->UpdateCounter2 &&
652 HiveHeader->UpdateCounter1 == LogHeader->UpdateCounter1)
653 {
654 /* Hive and log file are up-to-date */
655 Status = STATUS_SUCCESS;
656 goto ByeBye;
657 }
658
659 /*
660 * Hive needs an update!
661 */
662
663 /* Get file size */
664 Status = NtQueryInformationFile(LogHandle,
665 &IoStatusBlock,
666 &fsi,
667 sizeof(fsi),
668 FileStandardInformation);
669 if (!NT_SUCCESS(Status))
670 {
671 DPRINT("NtQueryInformationFile() failed (Status %lx)\n", Status);
672 goto ByeBye;
673 }
674 FileSize = fsi.EndOfFile.u.LowPart;
675
676 /* Calculate bitmap and block size */
677 BitmapSize = ROUND_UP((FileSize / 4096) - 1, sizeof(ULONG) * 8) / 8;
678 BufferSize = sizeof(HIVE_HEADER) +
679 sizeof(ULONG) +
680 BitmapSize;
681 BufferSize = ROUND_UP(BufferSize, 4096);
682
683 /* Reallocate log header block */
684 ExFreePool(LogHeader);
685 LogHeader = ExAllocatePool(PagedPool,
686 BufferSize);
687 if (LogHeader == NULL)
688 {
689 DPRINT("ExAllocatePool() failed\n");
690 Status = STATUS_INSUFFICIENT_RESOURCES;
691 goto ByeBye;
692 }
693
694 /* Read log file header */
695 FileOffset.QuadPart = 0ULL;
696 Status = NtReadFile(LogHandle,
697 0,
698 0,
699 0,
700 &IoStatusBlock,
701 LogHeader,
702 BufferSize,
703 &FileOffset,
704 0);
705 if (!NT_SUCCESS(Status))
706 {
707 DPRINT("NtReadFile() failed (Status %lx)\n", Status);
708 goto ByeBye;
709 }
710
711 /* Initialize bitmap */
712 RtlInitializeBitMap(&BlockBitMap,
713 (PVOID)((ULONG)LogHeader + 4096 + sizeof(ULONG)),
714 BitmapSize * 8);
715
716 /* FIXME: Update dirty blocks */
717
718
719 /* FIXME: Update hive header */
720
721
722 Status = STATUS_SUCCESS;
723 }
724
725
726 /* Clean up the mess */
727 ByeBye:
728 if (HiveHeader != NULL)
729 ExFreePool(HiveHeader);
730
731 if (LogHeader != NULL)
732 ExFreePool(LogHeader);
733
734 if (LogHandle != INVALID_HANDLE_VALUE)
735 NtClose(LogHandle);
736
737 NtClose(HiveHandle);
738
739 return(Status);
740 }
741 #endif
742
743
744 static NTSTATUS
745 CmiInitNonVolatileRegistryHive(PREGISTRY_HIVE RegistryHive,
746 PWSTR Filename,
747 BOOLEAN CreateNew)
748 {
749 OBJECT_ATTRIBUTES ObjectAttributes;
750 FILE_STANDARD_INFORMATION fsi;
751 PCELL_HEADER FreeBlock;
752 LARGE_INTEGER FileOffset;
753 BLOCK_OFFSET BlockOffset;
754 ULONG CreateDisposition;
755 IO_STATUS_BLOCK IoSB;
756 HANDLE FileHandle;
757 ULONG FreeOffset;
758 NTSTATUS Status;
759 PHBIN tmpBin;
760 ULONG i, j;
761 ULONG BitmapSize;
762
763 DPRINT("CmiInitNonVolatileRegistryHive(%p, %S, %d) called\n",
764 RegistryHive, Filename, CreateNew);
765
766 /* Duplicate Filename */
767 Status = RtlCreateUnicodeString(&RegistryHive->HiveFileName,
768 Filename);
769 if (!NT_SUCCESS(Status))
770 {
771 DPRINT("RtlCreateUnicodeString() failed (Status %lx)\n", Status);
772 return(Status);
773 }
774
775 /* Create log file name */
776 RegistryHive->LogFileName.Length = (wcslen(Filename) + 4) * sizeof(WCHAR);
777 RegistryHive->LogFileName.MaximumLength = RegistryHive->LogFileName.Length + sizeof(WCHAR);
778 RegistryHive->LogFileName.Buffer = ExAllocatePool(NonPagedPool,
779 RegistryHive->LogFileName.MaximumLength);
780 if (RegistryHive->LogFileName.Buffer == NULL)
781 {
782 RtlFreeUnicodeString(&RegistryHive->HiveFileName);
783 DPRINT("ExAllocatePool() failed\n");
784 return(STATUS_INSUFFICIENT_RESOURCES);
785 }
786 wcscpy(RegistryHive->LogFileName.Buffer,
787 Filename);
788 wcscat(RegistryHive->LogFileName.Buffer,
789 L".log");
790
791 #ifdef HIVE_CHECK
792 /* Check and eventually fix a hive */
793 Status = CmiCheckAndFixHive(RegistryHive);
794 if (!NT_SUCCESS(Status))
795 {
796 RtlFreeUnicodeString(&RegistryHive->HiveFileName);
797 RtlFreeUnicodeString(&RegistryHive->LogFileName);
798 DPRINT1("CmiCheckAndFixHive() failed (Status %lx)\n", Status);
799 return(Status);
800 }
801 #endif
802
803 InitializeObjectAttributes(&ObjectAttributes,
804 &RegistryHive->HiveFileName,
805 0,
806 NULL,
807 NULL);
808
809 /*
810 * Note:
811 * This is a workaround to prevent a BSOD because of missing registry hives.
812 * The workaround is only useful for developers. An implementation for the
813 * ordinary user must bail out on missing registry hives because they are
814 * essential to booting and configuring the OS.
815 */
816 #if 0
817 if (CreateNew == TRUE)
818 CreateDisposition = FILE_OPEN_IF;
819 else
820 CreateDisposition = FILE_OPEN;
821 #endif
822 CreateDisposition = FILE_OPEN_IF;
823
824 Status = NtCreateFile(&FileHandle,
825 FILE_ALL_ACCESS,
826 &ObjectAttributes,
827 &IoSB,
828 NULL,
829 FILE_ATTRIBUTE_NORMAL,
830 0,
831 CreateDisposition,
832 FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT,
833 NULL,
834 0);
835 if (!NT_SUCCESS(Status))
836 {
837 RtlFreeUnicodeString(&RegistryHive->HiveFileName);
838 RtlFreeUnicodeString(&RegistryHive->LogFileName);
839 DPRINT("NtCreateFile() failed (Status %lx)\n", Status);
840 return(Status);
841 }
842
843 /* Note: Another workaround! See the note above! */
844 #if 0
845 if ((CreateNew) && (IoSB.Information == FILE_CREATED))
846 #endif
847 if (IoSB.Information != FILE_OPENED)
848 {
849 Status = CmiCreateNewRegFile(FileHandle);
850 if (!NT_SUCCESS(Status))
851 {
852 DPRINT("CmiCreateNewRegFile() failed (Status %lx)\n", Status);
853 NtClose(FileHandle);
854 RtlFreeUnicodeString(&RegistryHive->HiveFileName);
855 RtlFreeUnicodeString(&RegistryHive->LogFileName);
856 return(Status);
857 }
858 }
859
860 /* Read hive header */
861 FileOffset.u.HighPart = 0;
862 FileOffset.u.LowPart = 0;
863 DPRINT(" Attempting to ZwReadFile(%d) for %d bytes into %p\n", FileHandle, sizeof(HIVE_HEADER), RegistryHive->HiveHeader);
864 Status = NtReadFile(FileHandle,
865 0,
866 0,
867 0,
868 &IoSB,
869 RegistryHive->HiveHeader,
870 sizeof(HIVE_HEADER),
871 &FileOffset,
872 0);
873 assertmsg(NT_SUCCESS(Status), ("Status: 0x%X\n", Status));
874 if (!NT_SUCCESS(Status))
875 {
876 DPRINT("NtReadFile() failed (Status %lx)\n", Status);
877 NtClose(FileHandle);
878 RtlFreeUnicodeString(&RegistryHive->HiveFileName);
879 RtlFreeUnicodeString(&RegistryHive->LogFileName);
880 return Status;
881 }
882
883 /* Read update counter */
884 RegistryHive->UpdateCounter = RegistryHive->HiveHeader->UpdateCounter1;
885
886 Status = NtQueryInformationFile(FileHandle,
887 &IoSB,
888 &fsi,
889 sizeof(fsi),
890 FileStandardInformation);
891 assertmsg(NT_SUCCESS(Status), ("Status: 0x%X\n", Status));
892 if (!NT_SUCCESS(Status) || fsi.EndOfFile.u.LowPart == 0)
893 {
894 DPRINT("NtQueryInformationFile() failed (Status %lx)\n", Status);
895 NtClose(FileHandle);
896 RtlFreeUnicodeString(&RegistryHive->HiveFileName);
897 RtlFreeUnicodeString(&RegistryHive->LogFileName);
898 return Status;
899 }
900
901 RegistryHive->FileSize = fsi.EndOfFile.u.LowPart;
902 RegistryHive->BlockListSize = (RegistryHive->FileSize / 4096) - 1;
903
904 DPRINT("Space needed for block list describing hive: 0x%x\n",
905 sizeof(PHBIN *) * RegistryHive->BlockListSize);
906
907 RegistryHive->BlockList = ExAllocatePool(NonPagedPool,
908 sizeof(PHBIN *) * RegistryHive->BlockListSize);
909
910 if (RegistryHive->BlockList == NULL)
911 {
912 ExFreePool(RegistryHive->BlockList);
913 NtClose(FileHandle);
914 RtlFreeUnicodeString(&RegistryHive->HiveFileName);
915 RtlFreeUnicodeString(&RegistryHive->LogFileName);
916 DPRINT("CmiInitNonVolatileRegistryHive() - Failed 6.\n");
917 return STATUS_INSUFFICIENT_RESOURCES;
918 }
919
920 RegistryHive->BlockList[0] = ExAllocatePool(PagedPool,
921 RegistryHive->FileSize - 4096);
922 if (RegistryHive->BlockList[0] == NULL)
923 {
924 ExFreePool(RegistryHive->BlockList);
925 NtClose(FileHandle);
926 RtlFreeUnicodeString(&RegistryHive->HiveFileName);
927 RtlFreeUnicodeString(&RegistryHive->LogFileName);
928 DPRINT("CmiInitNonVolatileRegistryHive() - Failed 8.\n");
929 return STATUS_INSUFFICIENT_RESOURCES;
930 }
931
932 FileOffset.u.HighPart = 0;
933 FileOffset.u.LowPart = 4096;
934
935 DPRINT(" Attempting to NtReadFile(%d) for %d bytes into %p\n",
936 FileHandle, RegistryHive->FileSize - 4096, (PVOID)RegistryHive->BlockList[0]);
937 Status = NtReadFile(FileHandle,
938 0,
939 0,
940 0,
941 &IoSB,
942 (PVOID) RegistryHive->BlockList[0],
943 RegistryHive->FileSize - 4096,
944 &FileOffset,
945 0);
946
947 assertmsg(NT_SUCCESS(Status), ("Status: 0x%X\n", Status));
948
949 NtClose(FileHandle);
950
951 RegistryHive->FreeListSize = 0;
952 RegistryHive->FreeListMax = 0;
953 RegistryHive->FreeList = NULL;
954
955 BlockOffset = 0;
956 for (i = 0; i < RegistryHive->BlockListSize; i++)
957 {
958 RegistryHive->BlockList[i] = (PHBIN) (((ULONG_PTR) RegistryHive->BlockList[0]) + BlockOffset);
959 tmpBin = (PHBIN) (((ULONG_PTR) RegistryHive->BlockList[i]));
960 if (tmpBin->BlockId != REG_BIN_ID)
961 {
962 DPRINT("Bad BlockId %x, offset %x\n", tmpBin->BlockId, BlockOffset);
963 //KeBugCheck(0);
964 return STATUS_INSUFFICIENT_RESOURCES;
965 }
966
967 assertmsg((tmpBin->BlockSize % 4096) == 0, ("BlockSize (0x%.08x) must be multiplum of 4K\n", tmpBin->BlockSize));
968
969 if (tmpBin->BlockSize > 4096)
970 {
971 for (j = 1; j < tmpBin->BlockSize / 4096; j++)
972 {
973 RegistryHive->BlockList[i + j] = RegistryHive->BlockList[i];
974 }
975 i = i + j - 1;
976 }
977
978 /* Search free blocks and add to list */
979 FreeOffset = REG_HBIN_DATA_OFFSET;
980 while (FreeOffset < tmpBin->BlockSize)
981 {
982 FreeBlock = (PCELL_HEADER) ((ULONG_PTR) RegistryHive->BlockList[i] + FreeOffset);
983 if (FreeBlock->CellSize > 0)
984 {
985 Status = CmiAddFree(RegistryHive,
986 FreeBlock,
987 RegistryHive->BlockList[i]->BlockOffset + FreeOffset,
988 FALSE);
989
990 if (!NT_SUCCESS(Status))
991 {
992 /* FIXME: */
993 assert(FALSE);
994 }
995
996 FreeOffset += FreeBlock->CellSize;
997 }
998 else
999 {
1000 FreeOffset -= FreeBlock->CellSize;
1001 }
1002 }
1003 BlockOffset += tmpBin->BlockSize;
1004 }
1005
1006 /*
1007 * Create block bitmap and clear all bits
1008 */
1009 /* Calculate bitmap size in bytes (always a multiple of 32 bits) */
1010 BitmapSize = ROUND_UP(RegistryHive->BlockListSize, sizeof(ULONG) * 8) / 8;
1011 DPRINT("RegistryHive->BlockListSize: %lu\n", RegistryHive->BlockListSize);
1012 DPRINT("BitmapSize: %lu Bytes %lu Bits\n", BitmapSize, BitmapSize * 8);
1013
1014 /* Allocate bitmap */
1015 RegistryHive->BitmapBuffer = (PULONG)ExAllocatePool(PagedPool,
1016 BitmapSize);
1017 RtlInitializeBitMap(&RegistryHive->DirtyBitMap,
1018 RegistryHive->BitmapBuffer,
1019 BitmapSize * 8);
1020
1021 /* Initialize bitmap */
1022 RtlClearAllBits(&RegistryHive->DirtyBitMap);
1023 RegistryHive->HiveDirty = FALSE;
1024
1025 DPRINT("CmiInitNonVolatileRegistryHive(%p, %S, %d) - Finished.\n",
1026 RegistryHive, Filename, CreateNew);
1027
1028 return(STATUS_SUCCESS);
1029 }
1030
1031
1032 static NTSTATUS
1033 CmiInitVolatileRegistryHive(PREGISTRY_HIVE RegistryHive)
1034 {
1035 PKEY_CELL RootKeyCell;
1036
1037 RegistryHive->Flags |= HIVE_VOLATILE;
1038
1039 CmiCreateDefaultHiveHeader(RegistryHive->HiveHeader);
1040
1041 RootKeyCell = (PKEY_CELL) ExAllocatePool(NonPagedPool, sizeof(KEY_CELL));
1042
1043 if (RootKeyCell == NULL)
1044 return STATUS_INSUFFICIENT_RESOURCES;
1045
1046 CmiCreateDefaultRootKeyCell(RootKeyCell);
1047
1048 RegistryHive->HiveHeader->RootKeyCell = (BLOCK_OFFSET) RootKeyCell;
1049
1050 return STATUS_SUCCESS;
1051 }
1052
1053
1054 NTSTATUS
1055 CmiCreateRegistryHive(PWSTR Filename,
1056 PREGISTRY_HIVE *RegistryHive,
1057 BOOLEAN CreateNew)
1058 {
1059 PREGISTRY_HIVE Hive;
1060 NTSTATUS Status;
1061
1062 DPRINT("CmiCreateRegistryHive(Filename %S)\n", Filename);
1063
1064 *RegistryHive = NULL;
1065
1066 Hive = ExAllocatePool(NonPagedPool, sizeof(REGISTRY_HIVE));
1067 if (Hive == NULL)
1068 return(STATUS_INSUFFICIENT_RESOURCES);
1069
1070 DPRINT("Hive %x\n", Hive);
1071
1072 RtlZeroMemory(Hive, sizeof(REGISTRY_HIVE));
1073
1074 Hive->HiveHeader = (PHIVE_HEADER)
1075 ExAllocatePool(NonPagedPool, sizeof(HIVE_HEADER));
1076
1077 if (Hive->HiveHeader == NULL)
1078 {
1079 ExFreePool(Hive);
1080 return(STATUS_INSUFFICIENT_RESOURCES);
1081 }
1082
1083 if (Filename != NULL)
1084 {
1085 Status = CmiInitNonVolatileRegistryHive(Hive, Filename, CreateNew);
1086 }
1087 else
1088 {
1089 Status = CmiInitVolatileRegistryHive(Hive);
1090 }
1091
1092 if (!NT_SUCCESS(Status))
1093 {
1094 ExFreePool(Hive->HiveHeader);
1095 ExFreePool(Hive);
1096 return(Status);
1097 }
1098
1099 ExInitializeResourceLite(&Hive->HiveResource);
1100
1101 /* Acquire hive list lock exclusively */
1102 ExAcquireResourceExclusiveLite(&CmiHiveListLock, TRUE);
1103
1104 /* Add the new hive to the hive list */
1105 InsertTailList(&CmiHiveListHead, &Hive->HiveList);
1106
1107 /* Release hive list lock */
1108 ExReleaseResourceLite(&CmiHiveListLock);
1109
1110 VERIFY_REGISTRY_HIVE(Hive);
1111
1112 *RegistryHive = Hive;
1113
1114 DPRINT("CmiCreateRegistryHive(Filename %S) - Finished.\n", Filename);
1115
1116 return(STATUS_SUCCESS);
1117 }
1118
1119
1120 NTSTATUS
1121 CmiRemoveRegistryHive(PREGISTRY_HIVE RegistryHive)
1122 {
1123 /* Acquire hive list lock exclusively */
1124 ExAcquireResourceExclusiveLite(&CmiHiveListLock, TRUE);
1125
1126 /* Remove hive from hive list */
1127 RemoveEntryList(&RegistryHive->HiveList);
1128
1129 /* Release hive list lock */
1130 ExReleaseResourceLite(&CmiHiveListLock);
1131
1132
1133 /* FIXME: Remove attached keys and values */
1134
1135
1136 /* Release hive header */
1137 ExFreePool(RegistryHive->HiveHeader);
1138
1139 /* Release hive */
1140 ExFreePool(RegistryHive);
1141
1142 return(STATUS_SUCCESS);
1143 }
1144
1145
1146 static ULONG
1147 CmiCalcChecksum(PULONG Buffer)
1148 {
1149 ULONG Sum = 0;
1150 ULONG i;
1151
1152 for (i = 0; i < 127; i++)
1153 Sum += Buffer[i];
1154
1155 return(Sum);
1156 }
1157
1158
1159 static NTSTATUS
1160 CmiStartLogUpdate(PREGISTRY_HIVE RegistryHive)
1161 {
1162 FILE_END_OF_FILE_INFORMATION EndOfFileInfo;
1163 FILE_ALLOCATION_INFORMATION FileAllocationInfo;
1164 OBJECT_ATTRIBUTES ObjectAttributes;
1165 IO_STATUS_BLOCK IoStatusBlock;
1166 HANDLE FileHandle;
1167 LARGE_INTEGER FileOffset;
1168 ULONG BufferSize;
1169 ULONG BitmapSize;
1170 PUCHAR Buffer;
1171 PUCHAR Ptr;
1172 ULONG BlockIndex;
1173 ULONG BlockOffset;
1174 PVOID BlockPtr;
1175 NTSTATUS Status;
1176
1177 DPRINT("CmiStartLogUpdate() called\n");
1178
1179 BitmapSize = ROUND_UP(RegistryHive->BlockListSize, sizeof(ULONG) * 8) / 8;
1180 BufferSize = sizeof(HIVE_HEADER) +
1181 sizeof(ULONG) +
1182 BitmapSize;
1183 BufferSize = ROUND_UP(BufferSize, 4096);
1184
1185 DPRINT("Bitmap size %lu buffer size: %lu\n", BitmapSize, BufferSize);
1186
1187 Buffer = (PUCHAR)ExAllocatePool(NonPagedPool, BufferSize);
1188 if (Buffer == NULL)
1189 {
1190 DPRINT("ExAllocatePool() failed\n");
1191 return(STATUS_INSUFFICIENT_RESOURCES);
1192 }
1193
1194 /* Open log file for writing */
1195 InitializeObjectAttributes(&ObjectAttributes,
1196 &RegistryHive->LogFileName,
1197 0,
1198 NULL,
1199 NULL);
1200
1201 Status = NtCreateFile(&FileHandle,
1202 FILE_ALL_ACCESS,
1203 &ObjectAttributes,
1204 &IoStatusBlock,
1205 NULL,
1206 FILE_ATTRIBUTE_NORMAL,
1207 0,
1208 FILE_SUPERSEDE,
1209 FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT,
1210 NULL,
1211 0);
1212 if (!NT_SUCCESS(Status))
1213 {
1214 DPRINT("NtCreateFile() failed (Status %lx)\n", Status);
1215 ExFreePool(Buffer);
1216 return(Status);
1217 }
1218
1219 /* Update firt update counter and checksum */
1220 RegistryHive->HiveHeader->UpdateCounter1 = RegistryHive->UpdateCounter + 1;
1221 RegistryHive->HiveHeader->Checksum = CmiCalcChecksum((PULONG)RegistryHive->HiveHeader);
1222
1223 /* Copy hive header */
1224 RtlCopyMemory(Buffer,
1225 RegistryHive->HiveHeader,
1226 sizeof(HIVE_HEADER));
1227 Ptr = Buffer + sizeof(HIVE_HEADER);
1228
1229 RtlCopyMemory(Ptr,
1230 "DIRT",
1231 4);
1232 Ptr += 4;
1233 RtlCopyMemory(Ptr,
1234 RegistryHive->DirtyBitMap.Buffer,
1235 BitmapSize);
1236
1237 /* Write hive block and block bitmap */
1238 FileOffset.QuadPart = 0ULL;
1239 Status = NtWriteFile(FileHandle,
1240 NULL,
1241 NULL,
1242 NULL,
1243 &IoStatusBlock,
1244 Buffer,
1245 BufferSize,
1246 &FileOffset,
1247 NULL);
1248 if (!NT_SUCCESS(Status))
1249 {
1250 DPRINT("NtWriteFile() failed (Status %lx)\n", Status);
1251 NtClose(FileHandle);
1252 ExFreePool(Buffer);
1253 return(Status);
1254 }
1255 ExFreePool(Buffer);
1256
1257 /* Write dirty blocks */
1258 FileOffset.QuadPart = (ULONGLONG)BufferSize;
1259 BlockIndex = 0;
1260 while (TRUE)
1261 {
1262 BlockIndex = RtlFindSetBits(&RegistryHive->DirtyBitMap,
1263 1,
1264 BlockIndex);
1265 if (BlockIndex == (ULONG)-1)
1266 {
1267 DPRINT("No more set bits\n");
1268 Status = STATUS_SUCCESS;
1269 break;
1270 }
1271
1272 DPRINT("Block %lu is dirty\n", BlockIndex);
1273
1274 BlockOffset = RegistryHive->BlockList[BlockIndex]->BlockOffset;
1275 DPRINT("Block offset %lx\n", BlockOffset);
1276
1277 BlockPtr = RegistryHive->BlockList[BlockIndex] + ((BlockIndex * 4096) - BlockOffset);
1278 DPRINT("BlockPtr %p\n", BlockPtr);
1279
1280 DPRINT("File offset %I64x\n", FileOffset.QuadPart);
1281
1282 /* Write hive block */
1283 Status = NtWriteFile(FileHandle,
1284 NULL,
1285 NULL,
1286 NULL,
1287 &IoStatusBlock,
1288 BlockPtr,
1289 REG_BLOCK_SIZE,
1290 &FileOffset,
1291 NULL);
1292 if (!NT_SUCCESS(Status))
1293 {
1294 DPRINT("NtWriteFile() failed (Status %lx)\n", Status);
1295 NtClose(FileHandle);
1296 return(Status);
1297 }
1298
1299 BlockIndex++;
1300 FileOffset.QuadPart += 4096ULL;
1301 }
1302
1303 /* Truncate log file */
1304 EndOfFileInfo.EndOfFile.QuadPart = FileOffset.QuadPart;
1305 Status = NtSetInformationFile(FileHandle,
1306 &IoStatusBlock,
1307 &EndOfFileInfo,
1308 sizeof(FILE_END_OF_FILE_INFORMATION),
1309 FileEndOfFileInformation);
1310 if (!NT_SUCCESS(Status))
1311 {
1312 DPRINT("NtSetInformationFile() failed (Status %lx)\n", Status);
1313 NtClose(FileHandle);
1314 return(Status);
1315 }
1316
1317 FileAllocationInfo.AllocationSize.QuadPart = FileOffset.QuadPart;
1318 Status = NtSetInformationFile(FileHandle,
1319 &IoStatusBlock,
1320 &FileAllocationInfo,
1321 sizeof(FILE_ALLOCATION_INFORMATION),
1322 FileAllocationInformation);
1323 if (!NT_SUCCESS(Status))
1324 {
1325 DPRINT("NtSetInformationFile() failed (Status %lx)\n", Status);
1326 NtClose(FileHandle);
1327 return(Status);
1328 }
1329
1330 /* Flush the log file */
1331 Status = NtFlushBuffersFile(FileHandle,
1332 &IoStatusBlock);
1333 if (!NT_SUCCESS(Status))
1334 {
1335 DPRINT("NtFlushBuffersFile() failed (Status %lx)\n", Status);
1336 }
1337
1338 NtClose(FileHandle);
1339
1340 return(Status);
1341 }
1342
1343
1344 static NTSTATUS
1345 CmiFinishLogUpdate(PREGISTRY_HIVE RegistryHive)
1346 {
1347 OBJECT_ATTRIBUTES ObjectAttributes;
1348 IO_STATUS_BLOCK IoStatusBlock;
1349 HANDLE FileHandle;
1350 LARGE_INTEGER FileOffset;
1351 ULONG BufferSize;
1352 ULONG BitmapSize;
1353 PUCHAR Buffer;
1354 PUCHAR Ptr;
1355 NTSTATUS Status;
1356
1357 DPRINT("CmiFinishLogUpdate() called\n");
1358
1359 BitmapSize = ROUND_UP(RegistryHive->BlockListSize, sizeof(ULONG) * 8) / 8;
1360 BufferSize = sizeof(HIVE_HEADER) +
1361 sizeof(ULONG) +
1362 BitmapSize;
1363 BufferSize = ROUND_UP(BufferSize, 4096);
1364
1365 DPRINT("Bitmap size %lu buffer size: %lu\n", BitmapSize, BufferSize);
1366
1367 Buffer = (PUCHAR)ExAllocatePool(NonPagedPool, BufferSize);
1368 if (Buffer == NULL)
1369 {
1370 DPRINT("ExAllocatePool() failed\n");
1371 return(STATUS_INSUFFICIENT_RESOURCES);
1372 }
1373
1374 /* Open log file for writing */
1375 InitializeObjectAttributes(&ObjectAttributes,
1376 &RegistryHive->LogFileName,
1377 0,
1378 NULL,
1379 NULL);
1380
1381 Status = NtCreateFile(&FileHandle,
1382 FILE_ALL_ACCESS,
1383 &ObjectAttributes,
1384 &IoStatusBlock,
1385 NULL,
1386 FILE_ATTRIBUTE_NORMAL,
1387 0,
1388 FILE_OPEN,
1389 FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT,
1390 NULL,
1391 0);
1392 if (!NT_SUCCESS(Status))
1393 {
1394 DPRINT("NtCreateFile() failed (Status %lx)\n", Status);
1395 ExFreePool(Buffer);
1396 return(Status);
1397 }
1398
1399 /* Update first and second update counter and checksum */
1400 RegistryHive->HiveHeader->UpdateCounter1 = RegistryHive->UpdateCounter + 1;
1401 RegistryHive->HiveHeader->UpdateCounter2 = RegistryHive->UpdateCounter + 1;
1402 RegistryHive->HiveHeader->Checksum = CmiCalcChecksum((PULONG)RegistryHive->HiveHeader);
1403
1404 /* Copy hive header */
1405 RtlCopyMemory(Buffer,
1406 RegistryHive->HiveHeader,
1407 sizeof(HIVE_HEADER));
1408 Ptr = Buffer + sizeof(HIVE_HEADER);
1409
1410 /* Write empty block bitmap */
1411 RtlCopyMemory(Ptr,
1412 "DIRT",
1413 4);
1414 Ptr += 4;
1415 RtlZeroMemory(Ptr,
1416 BitmapSize);
1417
1418 /* Write hive block and block bitmap */
1419 FileOffset.QuadPart = 0ULL;
1420 Status = NtWriteFile(FileHandle,
1421 NULL,
1422 NULL,
1423 NULL,
1424 &IoStatusBlock,
1425 Buffer,
1426 BufferSize,
1427 &FileOffset,
1428 NULL);
1429 if (!NT_SUCCESS(Status))
1430 {
1431 DPRINT("NtWriteFile() failed (Status %lx)\n", Status);
1432 NtClose(FileHandle);
1433 ExFreePool(Buffer);
1434 return(Status);
1435 }
1436
1437 ExFreePool(Buffer);
1438
1439 /* Flush the log file */
1440 Status = NtFlushBuffersFile(FileHandle,
1441 &IoStatusBlock);
1442 if (!NT_SUCCESS(Status))
1443 {
1444 DPRINT("NtFlushBuffersFile() failed (Status %lx)\n", Status);
1445 }
1446
1447 NtClose(FileHandle);
1448
1449 return(Status);
1450 }
1451
1452
1453 static NTSTATUS
1454 CmiCleanupLogUpdate(PREGISTRY_HIVE RegistryHive)
1455 {
1456 FILE_END_OF_FILE_INFORMATION EndOfFileInfo;
1457 FILE_ALLOCATION_INFORMATION FileAllocationInfo;
1458 OBJECT_ATTRIBUTES ObjectAttributes;
1459 IO_STATUS_BLOCK IoStatusBlock;
1460 HANDLE FileHandle;
1461 ULONG BufferSize;
1462 ULONG BitmapSize;
1463 NTSTATUS Status;
1464
1465 DPRINT("CmiFinishLogUpdate() called\n");
1466
1467 BitmapSize = ROUND_UP(RegistryHive->BlockListSize, sizeof(ULONG) * 8) / 8;
1468 BufferSize = sizeof(HIVE_HEADER) +
1469 sizeof(ULONG) +
1470 BitmapSize;
1471 BufferSize = ROUND_UP(BufferSize, 4096);
1472
1473 DPRINT("Bitmap size %lu buffer size: %lu\n", BitmapSize, BufferSize);
1474
1475 /* Open log file for writing */
1476 InitializeObjectAttributes(&ObjectAttributes,
1477 &RegistryHive->LogFileName,
1478 0,
1479 NULL,
1480 NULL);
1481
1482 Status = NtCreateFile(&FileHandle,
1483 FILE_ALL_ACCESS,
1484 &ObjectAttributes,
1485 &IoStatusBlock,
1486 NULL,
1487 FILE_ATTRIBUTE_NORMAL,
1488 0,
1489 FILE_OPEN,
1490 FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT,
1491 NULL,
1492 0);
1493 if (!NT_SUCCESS(Status))
1494 {
1495 DPRINT("NtCreateFile() failed (Status %lx)\n", Status);
1496 return(Status);
1497 }
1498
1499 /* Truncate log file */
1500 EndOfFileInfo.EndOfFile.QuadPart = (ULONGLONG)BufferSize;
1501 Status = NtSetInformationFile(FileHandle,
1502 &IoStatusBlock,
1503 &EndOfFileInfo,
1504 sizeof(FILE_END_OF_FILE_INFORMATION),
1505 FileEndOfFileInformation);
1506 if (!NT_SUCCESS(Status))
1507 {
1508 DPRINT("NtSetInformationFile() failed (Status %lx)\n", Status);
1509 NtClose(FileHandle);
1510 return(Status);
1511 }
1512
1513 FileAllocationInfo.AllocationSize.QuadPart = (ULONGLONG)BufferSize;
1514 Status = NtSetInformationFile(FileHandle,
1515 &IoStatusBlock,
1516 &FileAllocationInfo,
1517 sizeof(FILE_ALLOCATION_INFORMATION),
1518 FileAllocationInformation);
1519 if (!NT_SUCCESS(Status))
1520 {
1521 DPRINT("NtSetInformationFile() failed (Status %lx)\n", Status);
1522 NtClose(FileHandle);
1523 return(Status);
1524 }
1525
1526 /* Flush the log file */
1527 Status = NtFlushBuffersFile(FileHandle,
1528 &IoStatusBlock);
1529 if (!NT_SUCCESS(Status))
1530 {
1531 DPRINT("NtFlushBuffersFile() failed (Status %lx)\n", Status);
1532 }
1533
1534 NtClose(FileHandle);
1535
1536 return(Status);
1537 }
1538
1539
1540 static NTSTATUS
1541 CmiStartHiveUpdate(PREGISTRY_HIVE RegistryHive)
1542 {
1543 OBJECT_ATTRIBUTES ObjectAttributes;
1544 IO_STATUS_BLOCK IoStatusBlock;
1545 HANDLE FileHandle;
1546 LARGE_INTEGER FileOffset;
1547 ULONG BlockIndex;
1548 ULONG BlockOffset;
1549 PVOID BlockPtr;
1550 NTSTATUS Status;
1551
1552 DPRINT("CmiStartHiveUpdate() called\n");
1553
1554 /* Open hive for writing */
1555 InitializeObjectAttributes(&ObjectAttributes,
1556 &RegistryHive->HiveFileName,
1557 0,
1558 NULL,
1559 NULL);
1560
1561 Status = NtCreateFile(&FileHandle,
1562 FILE_ALL_ACCESS,
1563 &ObjectAttributes,
1564 &IoStatusBlock,
1565 NULL,
1566 FILE_ATTRIBUTE_NORMAL,
1567 0,
1568 FILE_OPEN,
1569 FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT,
1570 NULL,
1571 0);
1572 if (!NT_SUCCESS(Status))
1573 {
1574 DPRINT("NtCreateFile() failed (Status %lx)\n", Status);
1575 return(Status);
1576 }
1577
1578 /* Update firt update counter and checksum */
1579 RegistryHive->HiveHeader->UpdateCounter1 = RegistryHive->UpdateCounter + 1;
1580 RegistryHive->HiveHeader->Checksum = CmiCalcChecksum((PULONG)RegistryHive->HiveHeader);
1581
1582 /* Write hive block */
1583 FileOffset.QuadPart = 0ULL;
1584 Status = NtWriteFile(FileHandle,
1585 NULL,
1586 NULL,
1587 NULL,
1588 &IoStatusBlock,
1589 RegistryHive->HiveHeader,
1590 sizeof(HIVE_HEADER),
1591 &FileOffset,
1592 NULL);
1593 if (!NT_SUCCESS(Status))
1594 {
1595 DPRINT("NtWriteFile() failed (Status %lx)\n", Status);
1596 NtClose(FileHandle);
1597 return(Status);
1598 }
1599
1600 BlockIndex = 0;
1601 while (TRUE)
1602 {
1603 BlockIndex = RtlFindSetBits(&RegistryHive->DirtyBitMap,
1604 1,
1605 BlockIndex);
1606 if (BlockIndex == (ULONG)-1)
1607 {
1608 DPRINT("No more set bits\n");
1609 Status = STATUS_SUCCESS;
1610 break;
1611 }
1612
1613 DPRINT("Block %lu is dirty\n", BlockIndex);
1614
1615 BlockOffset = RegistryHive->BlockList[BlockIndex]->BlockOffset;
1616 DPRINT("Block offset %lx\n", BlockOffset);
1617
1618 BlockPtr = RegistryHive->BlockList[BlockIndex] + ((BlockIndex * 4096) - BlockOffset);
1619 DPRINT("BlockPtr %p\n", BlockPtr);
1620
1621 FileOffset.QuadPart = (ULONGLONG)(BlockIndex + 1) * 4096ULL;
1622 DPRINT("File offset %I64x\n", FileOffset.QuadPart);
1623
1624
1625 /* Write hive block */
1626 Status = NtWriteFile(FileHandle,
1627 NULL,
1628 NULL,
1629 NULL,
1630 &IoStatusBlock,
1631 BlockPtr,
1632 REG_BLOCK_SIZE,
1633 &FileOffset,
1634 NULL);
1635 if (!NT_SUCCESS(Status))
1636 {
1637 DPRINT("NtWriteFile() failed (Status %lx)\n", Status);
1638 NtClose(FileHandle);
1639 return(Status);
1640 }
1641
1642 BlockIndex++;
1643 }
1644
1645 Status = NtFlushBuffersFile(FileHandle,
1646 &IoStatusBlock);
1647 if (!NT_SUCCESS(Status))
1648 {
1649 DPRINT("NtFlushBuffersFile() failed (Status %lx)\n", Status);
1650 }
1651
1652 NtClose(FileHandle);
1653
1654 return(Status);
1655 }
1656
1657
1658 static NTSTATUS
1659 CmiFinishHiveUpdate(PREGISTRY_HIVE RegistryHive)
1660 {
1661 OBJECT_ATTRIBUTES ObjectAttributes;
1662 IO_STATUS_BLOCK IoStatusBlock;
1663 LARGE_INTEGER FileOffset;
1664 HANDLE FileHandle;
1665 NTSTATUS Status;
1666
1667 DPRINT("CmiFinishHiveUpdate() called\n");
1668
1669 InitializeObjectAttributes(&ObjectAttributes,
1670 &RegistryHive->HiveFileName,
1671 0,
1672 NULL,
1673 NULL);
1674
1675 Status = NtCreateFile(&FileHandle,
1676 FILE_ALL_ACCESS,
1677 &ObjectAttributes,
1678 &IoStatusBlock,
1679 NULL,
1680 FILE_ATTRIBUTE_NORMAL,
1681 0,
1682 FILE_OPEN,
1683 FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT,
1684 NULL,
1685 0);
1686 if (!NT_SUCCESS(Status))
1687 {
1688 DPRINT("NtCreateFile() failed (Status %lx)\n", Status);
1689 return(Status);
1690 }
1691
1692 /* Update second update counter and checksum */
1693 RegistryHive->HiveHeader->UpdateCounter1 = RegistryHive->UpdateCounter + 1;
1694 RegistryHive->HiveHeader->UpdateCounter2 = RegistryHive->UpdateCounter + 1;
1695 RegistryHive->HiveHeader->Checksum = CmiCalcChecksum((PULONG)RegistryHive->HiveHeader);
1696
1697 /* Write hive block */
1698 FileOffset.QuadPart = 0ULL;
1699 Status = NtWriteFile(FileHandle,
1700 NULL,
1701 NULL,
1702 NULL,
1703 &IoStatusBlock,
1704 RegistryHive->HiveHeader,
1705 sizeof(HIVE_HEADER),
1706 &FileOffset,
1707 NULL);
1708 if (!NT_SUCCESS(Status))
1709 {
1710 DPRINT("NtWriteFile() failed (Status %lx)\n", Status);
1711 NtClose(FileHandle);
1712 return(Status);
1713 }
1714
1715 Status = NtFlushBuffersFile(FileHandle,
1716 &IoStatusBlock);
1717 if (!NT_SUCCESS(Status))
1718 {
1719 DPRINT("NtFlushBuffersFile() failed (Status %lx)\n", Status);
1720 }
1721
1722 NtClose(FileHandle);
1723
1724 return(Status);
1725 }
1726
1727
1728 NTSTATUS
1729 CmiFlushRegistryHive(PREGISTRY_HIVE RegistryHive)
1730 {
1731 NTSTATUS Status;
1732
1733 DPRINT("CmiFlushRegistryHive() called\n");
1734
1735 if (RegistryHive->HiveDirty == FALSE)
1736 {
1737 return(STATUS_SUCCESS);
1738 }
1739
1740 DPRINT("Hive '%wZ' is dirty\n",
1741 &RegistryHive->HiveFileName);
1742 DPRINT("Log file: '%wZ'\n",
1743 &RegistryHive->LogFileName);
1744
1745 /* Update hive header modification time */
1746 NtQuerySystemTime((PTIME)&RegistryHive->HiveHeader->DateModified);
1747
1748 /* Start log update */
1749 Status = CmiStartLogUpdate(RegistryHive);
1750 if (!NT_SUCCESS(Status))
1751 {
1752 DPRINT("CmiStartLogUpdate() failed (Status %lx)\n", Status);
1753 return(Status);
1754 }
1755
1756 /* Finish log update */
1757 Status = CmiFinishLogUpdate(RegistryHive);
1758 if (!NT_SUCCESS(Status))
1759 {
1760 DPRINT("CmiFinishLogUpdate() failed (Status %lx)\n", Status);
1761 return(Status);
1762 }
1763
1764 /* Start hive update */
1765 Status = CmiStartHiveUpdate(RegistryHive);
1766 if (!NT_SUCCESS(Status))
1767 {
1768 DPRINT("CmiStartHiveUpdate() failed (Status %lx)\n", Status);
1769 return(Status);
1770 }
1771
1772 /* Finish the hive update */
1773 Status = CmiFinishHiveUpdate(RegistryHive);
1774 if (!NT_SUCCESS(Status))
1775 {
1776 DPRINT("CmiFinishHiveUpdate() failed (Status %lx)\n", Status);
1777 return(Status);
1778 }
1779
1780 /* Cleanup log update */
1781 Status = CmiCleanupLogUpdate(RegistryHive);
1782 if (!NT_SUCCESS(Status))
1783 {
1784 DPRINT("CmiFinishLogUpdate() failed (Status %lx)\n", Status);
1785 return(Status);
1786 }
1787
1788 /* Increment hive update counter */
1789 RegistryHive->UpdateCounter++;
1790
1791 /* Clear dirty bitmap and dirty flag */
1792 RtlClearAllBits(&RegistryHive->DirtyBitMap);
1793 RegistryHive->HiveDirty = FALSE;
1794
1795 DPRINT("CmiFlushRegistryHive() done\n");
1796
1797 return(STATUS_SUCCESS);
1798 }
1799
1800
1801 ULONG
1802 CmiGetMaxNameLength(PREGISTRY_HIVE RegistryHive,
1803 PKEY_CELL KeyCell)
1804 {
1805 PHASH_TABLE_CELL HashBlock;
1806 PKEY_CELL CurSubKeyCell;
1807 ULONG MaxName;
1808 ULONG i;
1809
1810 VERIFY_KEY_CELL(KeyCell);
1811
1812 MaxName = 0;
1813 HashBlock = CmiGetBlock(RegistryHive, KeyCell->HashTableOffset, NULL);
1814 if (HashBlock == NULL)
1815 {
1816 return 0;
1817 }
1818
1819 for (i = 0; i < HashBlock->HashTableSize; i++)
1820 {
1821 if (HashBlock->Table[i].KeyOffset != 0)
1822 {
1823 CurSubKeyCell = CmiGetBlock(RegistryHive,
1824 HashBlock->Table[i].KeyOffset,
1825 NULL);
1826 if (MaxName < CurSubKeyCell->NameSize)
1827 {
1828 MaxName = CurSubKeyCell->NameSize;
1829 }
1830 CmiReleaseBlock(RegistryHive, CurSubKeyCell);
1831 }
1832 }
1833
1834 CmiReleaseBlock(RegistryHive, HashBlock);
1835
1836 return MaxName;
1837 }
1838
1839
1840 ULONG
1841 CmiGetMaxClassLength(PREGISTRY_HIVE RegistryHive,
1842 PKEY_CELL KeyCell)
1843 {
1844 PHASH_TABLE_CELL HashBlock;
1845 PKEY_CELL CurSubKeyCell;
1846 ULONG MaxClass;
1847 ULONG i;
1848
1849 VERIFY_KEY_CELL(KeyCell);
1850
1851 MaxClass = 0;
1852 HashBlock = CmiGetBlock(RegistryHive, KeyCell->HashTableOffset, NULL);
1853 if (HashBlock == NULL)
1854 {
1855 return 0;
1856 }
1857
1858 for (i = 0; i < HashBlock->HashTableSize; i++)
1859 {
1860 if (HashBlock->Table[i].KeyOffset != 0)
1861 {
1862 CurSubKeyCell = CmiGetBlock(RegistryHive,
1863 HashBlock->Table[i].KeyOffset,
1864 NULL);
1865 if (MaxClass < CurSubKeyCell->ClassSize)
1866 {
1867 MaxClass = CurSubKeyCell->ClassSize;
1868 }
1869 CmiReleaseBlock(RegistryHive, CurSubKeyCell);
1870 }
1871 }
1872
1873 CmiReleaseBlock(RegistryHive, HashBlock);
1874
1875 return MaxClass;
1876 }
1877
1878
1879 ULONG
1880 CmiGetMaxValueNameLength(PREGISTRY_HIVE RegistryHive,
1881 PKEY_CELL KeyCell)
1882 {
1883 PVALUE_LIST_CELL ValueListCell;
1884 PVALUE_CELL CurValueCell;
1885 ULONG MaxValueName;
1886 ULONG i;
1887
1888 VERIFY_KEY_CELL(KeyCell);
1889
1890 ValueListCell = CmiGetBlock(RegistryHive,
1891 KeyCell->ValuesOffset,
1892 NULL);
1893 MaxValueName = 0;
1894 if (ValueListCell == NULL)
1895 {
1896 return 0;
1897 }
1898
1899 for (i = 0; i < KeyCell->NumberOfValues; i++)
1900 {
1901 CurValueCell = CmiGetBlock(RegistryHive,
1902 ValueListCell->Values[i],
1903 NULL);
1904 if (CurValueCell != NULL &&
1905 MaxValueName < CurValueCell->NameSize)
1906 {
1907 MaxValueName = CurValueCell->NameSize;
1908 }
1909 CmiReleaseBlock(RegistryHive, CurValueCell);
1910 }
1911
1912 CmiReleaseBlock(RegistryHive, ValueListCell);
1913
1914 return MaxValueName;
1915 }
1916
1917
1918 ULONG
1919 CmiGetMaxValueDataLength(PREGISTRY_HIVE RegistryHive,
1920 PKEY_CELL KeyCell)
1921 {
1922 PVALUE_LIST_CELL ValueListCell;
1923 PVALUE_CELL CurValueCell;
1924 LONG MaxValueData;
1925 ULONG i;
1926
1927 VERIFY_KEY_CELL(KeyCell);
1928
1929 ValueListCell = CmiGetBlock(RegistryHive, KeyCell->ValuesOffset, NULL);
1930 MaxValueData = 0;
1931 if (ValueListCell == NULL)
1932 {
1933 return 0;
1934 }
1935
1936 for (i = 0; i < KeyCell->NumberOfValues; i++)
1937 {
1938 CurValueCell = CmiGetBlock(RegistryHive,
1939 ValueListCell->Values[i],NULL);
1940 if ((CurValueCell != NULL) &&
1941 (MaxValueData < (CurValueCell->DataSize & LONG_MAX)))
1942 {
1943 MaxValueData = CurValueCell->DataSize & LONG_MAX;
1944 }
1945 CmiReleaseBlock(RegistryHive, CurValueCell);
1946 }
1947
1948 CmiReleaseBlock(RegistryHive, ValueListCell);
1949
1950 return MaxValueData;
1951 }
1952
1953
1954 NTSTATUS
1955 CmiScanForSubKey(IN PREGISTRY_HIVE RegistryHive,
1956 IN PKEY_CELL KeyCell,
1957 OUT PKEY_CELL *SubKeyCell,
1958 OUT BLOCK_OFFSET *BlockOffset,
1959 IN PCHAR KeyName,
1960 IN ACCESS_MASK DesiredAccess,
1961 IN ULONG Attributes)
1962 {
1963 PHASH_TABLE_CELL HashBlock;
1964 PKEY_CELL CurSubKeyCell;
1965 WORD KeyLength;
1966 ULONG i;
1967
1968 VERIFY_KEY_CELL(KeyCell);
1969
1970 //DPRINT("Scanning for sub key %s\n", KeyName);
1971
1972 assert(RegistryHive);
1973
1974 KeyLength = strlen(KeyName);
1975
1976 HashBlock = CmiGetBlock(RegistryHive, KeyCell->HashTableOffset, NULL);
1977 *SubKeyCell = NULL;
1978 if (HashBlock == NULL)
1979 {
1980 return STATUS_SUCCESS;
1981 }
1982
1983 for (i = 0; (i < KeyCell->NumberOfSubKeys)
1984 && (i < HashBlock->HashTableSize); i++)
1985 {
1986 if (Attributes & OBJ_CASE_INSENSITIVE)
1987 {
1988 if ((HashBlock->Table[i].KeyOffset != 0) &&
1989 (HashBlock->Table[i].KeyOffset != (ULONG_PTR)-1) &&
1990 (_strnicmp(KeyName, (PCHAR) &HashBlock->Table[i].HashValue, 4) == 0))
1991 {
1992 CurSubKeyCell = CmiGetBlock(RegistryHive,
1993 HashBlock->Table[i].KeyOffset,
1994 NULL);
1995 if ((CurSubKeyCell->NameSize == KeyLength)
1996 && (_strnicmp(KeyName, CurSubKeyCell->Name, KeyLength) == 0))
1997 {
1998 *SubKeyCell = CurSubKeyCell;
1999 *BlockOffset = HashBlock->Table[i].KeyOffset;
2000 break;
2001 }
2002 else
2003 {
2004 CmiReleaseBlock(RegistryHive, CurSubKeyCell);
2005 }
2006 }
2007 }
2008 else
2009 {
2010 if (HashBlock->Table[i].KeyOffset != 0 &&
2011 HashBlock->Table[i].KeyOffset != (ULONG_PTR) -1 &&
2012 !strncmp(KeyName, (PCHAR) &HashBlock->Table[i].HashValue, 4))
2013 {
2014 CurSubKeyCell = CmiGetBlock(RegistryHive,
2015 HashBlock->Table[i].KeyOffset,NULL);
2016 if (CurSubKeyCell->NameSize == KeyLength
2017 && !_strnicmp(KeyName, CurSubKeyCell->Name, KeyLength))
2018 {
2019 *SubKeyCell = CurSubKeyCell;
2020 *BlockOffset = HashBlock->Table[i].KeyOffset;
2021 break;
2022 }
2023 else
2024 {
2025 CmiReleaseBlock(RegistryHive, CurSubKeyCell);
2026 }
2027 }
2028 }
2029 }
2030
2031 CmiReleaseBlock(RegistryHive, HashBlock);
2032
2033 return STATUS_SUCCESS;
2034 }
2035
2036
2037 NTSTATUS
2038 CmiAddSubKey(PREGISTRY_HIVE RegistryHive,
2039 PKEY_OBJECT Parent,
2040 PKEY_OBJECT SubKey,
2041 PWSTR NewSubKeyName,
2042 USHORT NewSubKeyNameSize,
2043 ULONG TitleIndex,
2044 PUNICODE_STRING Class,
2045 ULONG CreateOptions)
2046 {
2047 PHASH_TABLE_CELL NewHashBlock;
2048 PHASH_TABLE_CELL HashBlock;
2049 BLOCK_OFFSET NKBOffset;
2050 PKEY_CELL NewKeyCell;
2051 ULONG NewBlockSize;
2052 PKEY_CELL KeyCell;
2053 NTSTATUS Status;
2054 USHORT NameSize;
2055
2056 KeyCell = Parent->KeyCell;
2057
2058 VERIFY_KEY_CELL(KeyCell);
2059
2060 if (NewSubKeyName[0] == L'\\')
2061 {
2062 NewSubKeyName++;
2063 NameSize = NewSubKeyNameSize / 2 - 1;
2064 }
2065 else
2066 {
2067 NameSize = NewSubKeyNameSize / 2;
2068 }
2069 Status = STATUS_SUCCESS;
2070
2071 NewBlockSize = sizeof(KEY_CELL) + NameSize;
2072 Status = CmiAllocateBlock(RegistryHive,
2073 (PVOID) &NewKeyCell,
2074 NewBlockSize,
2075 &NKBOffset);
2076
2077 if (NewKeyCell == NULL)
2078 {
2079 Status = STATUS_INSUFFICIENT_RESOURCES;
2080 }
2081 else
2082 {
2083 NewKeyCell->Id = REG_KEY_CELL_ID;
2084 NewKeyCell->Type = REG_KEY_CELL_TYPE;
2085 ZwQuerySystemTime((PTIME) &NewKeyCell->LastWriteTime);
2086 NewKeyCell->ParentKeyOffset = -1;
2087 NewKeyCell->NumberOfSubKeys = 0;
2088 NewKeyCell->HashTableOffset = -1;
2089 NewKeyCell->NumberOfValues = 0;
2090 NewKeyCell->ValuesOffset = -1;
2091 NewKeyCell->SecurityKeyOffset = -1;
2092 NewKeyCell->NameSize = NameSize;
2093 wcstombs(NewKeyCell->Name, NewSubKeyName, NameSize);
2094 NewKeyCell->ClassNameOffset = -1;
2095
2096 VERIFY_KEY_CELL(NewKeyCell);
2097
2098 if (Class)
2099 {
2100 PDATA_CELL pClass;
2101
2102 NewKeyCell->ClassSize = Class->Length + sizeof(WCHAR);
2103 Status = CmiAllocateBlock(RegistryHive,
2104 (PVOID) &pClass,
2105 NewKeyCell->ClassSize,
2106 &NewKeyCell->ClassNameOffset);
2107 wcsncpy((PWSTR) pClass->Data, Class->Buffer, Class->Length);
2108 ((PWSTR) (pClass->Data))[Class->Length] = 0;
2109 }
2110 }
2111
2112 if (!NT_SUCCESS(Status))
2113 {
2114 return Status;
2115 }
2116
2117 SubKey->KeyCell = NewKeyCell;
2118 SubKey->BlockOffset = NKBOffset;
2119
2120 /* Don't modify hash table if key is volatile and parent is not */
2121 if (IsVolatileHive(RegistryHive) && (!IsVolatileHive(Parent->RegistryHive)))
2122 {
2123 return(Status);
2124 }
2125
2126 if (KeyCell->HashTableOffset == (ULONG_PTR) -1)
2127 {
2128 Status = CmiAllocateHashTableBlock(RegistryHive,
2129 &HashBlock,
2130 &KeyCell->HashTableOffset,
2131 REG_INIT_HASH_TABLE_SIZE);
2132 if (!NT_SUCCESS(Status))
2133 {
2134 return(Status);
2135 }
2136 }
2137 else
2138 {
2139 HashBlock = CmiGetBlock(RegistryHive, KeyCell->HashTableOffset, NULL);
2140 if (((KeyCell->NumberOfSubKeys + 1) >= HashBlock->HashTableSize))
2141 {
2142 BLOCK_OFFSET HTOffset;
2143
2144 /* Reallocate the hash table block */
2145 Status = CmiAllocateHashTableBlock(RegistryHive,
2146 &NewHashBlock,
2147 &HTOffset,
2148 HashBlock->HashTableSize +
2149 REG_EXTEND_HASH_TABLE_SIZE);
2150 if (!NT_SUCCESS(Status))
2151 {
2152 return Status;
2153 }
2154
2155 RtlZeroMemory(&NewHashBlock->Table[0],
2156 sizeof(NewHashBlock->Table[0]) * NewHashBlock->HashTableSize);
2157 RtlCopyMemory(&NewHashBlock->Table[0],
2158 &HashBlock->Table[0],
2159 sizeof(NewHashBlock->Table[0]) * HashBlock->HashTableSize);
2160 CmiDestroyBlock(RegistryHive,
2161 HashBlock,
2162 KeyCell->HashTableOffset);
2163 KeyCell->HashTableOffset = HTOffset;
2164 HashBlock = NewHashBlock;
2165 }
2166 }
2167
2168 Status = CmiAddKeyToHashTable(RegistryHive,
2169 HashBlock,
2170 NewKeyCell,
2171 NKBOffset);
2172 if (NT_SUCCESS(Status))
2173 {
2174 KeyCell->NumberOfSubKeys++;
2175 }
2176
2177 return(Status);
2178 }
2179
2180
2181 NTSTATUS
2182 CmiRemoveSubKey(PREGISTRY_HIVE RegistryHive,
2183 PKEY_OBJECT ParentKey,
2184 PKEY_OBJECT SubKey)
2185 {
2186 PHASH_TABLE_CELL HashBlock;
2187 PVALUE_LIST_CELL ValueList;
2188 PVALUE_CELL ValueCell;
2189 PDATA_CELL DataCell;
2190 ULONG i;
2191
2192 DPRINT("CmiRemoveSubKey() called\n");
2193
2194 /* Remove all values */
2195 if (SubKey->KeyCell->NumberOfValues != 0)
2196 {
2197 /* Get pointer to the value list cell */
2198 ValueList = CmiGetBlock(RegistryHive,
2199 SubKey->KeyCell->ValuesOffset,
2200 NULL);
2201 if (ValueList != NULL)
2202 {
2203 /* Enumerate all values */
2204 for (i = 0; i < SubKey->KeyCell->NumberOfValues; i++)
2205 {
2206 /* Get pointer to value cell */
2207 ValueCell = CmiGetBlock(RegistryHive,
2208 ValueList->Values[i],
2209 NULL);
2210 if (ValueCell != NULL)
2211 {
2212 if (ValueCell->DataSize > 4)
2213 {
2214 DataCell = CmiGetBlock(RegistryHive,
2215 ValueCell->DataOffset,
2216 NULL);
2217 if (DataCell != NULL)
2218 {
2219 /* Destroy data cell */
2220 CmiDestroyBlock(RegistryHive,
2221 DataCell,
2222 ValueCell->DataOffset);
2223 }
2224 }
2225
2226 /* Destroy value cell */
2227 CmiDestroyBlock(RegistryHive,
2228 ValueCell,
2229 ValueList->Values[i]);
2230 }
2231 }
2232 }
2233
2234 /* Destroy value list cell */
2235 CmiDestroyBlock(RegistryHive,
2236 ValueList,
2237 SubKey->KeyCell->ValuesOffset);
2238
2239 SubKey->KeyCell->NumberOfValues = 0;
2240 SubKey->KeyCell->ValuesOffset = -1;
2241 }
2242
2243 /* Remove the key from the parent key's hash block */
2244 if (ParentKey->KeyCell->HashTableOffset != (BLOCK_OFFSET) -1)
2245 {
2246 DPRINT("ParentKey HashTableOffset %lx\n", ParentKey->KeyCell->HashTableOffset)
2247 HashBlock = CmiGetBlock(RegistryHive,
2248 ParentKey->KeyCell->HashTableOffset,
2249 NULL);
2250 DPRINT("ParentKey HashBlock %p\n", HashBlock)
2251 if (HashBlock != NULL)
2252 {
2253 CmiRemoveKeyFromHashTable(RegistryHive,
2254 HashBlock,
2255 SubKey->BlockOffset);
2256 CmiMarkBlockDirty(RegistryHive,
2257 ParentKey->KeyCell->HashTableOffset);
2258 }
2259 }
2260
2261 /* Remove the key's hash block */
2262 if (SubKey->KeyCell->HashTableOffset != (BLOCK_OFFSET) -1)
2263 {
2264 DPRINT("SubKey HashTableOffset %lx\n", SubKey->KeyCell->HashTableOffset)
2265 HashBlock = CmiGetBlock(RegistryHive,
2266 SubKey->KeyCell->HashTableOffset,
2267 NULL);
2268 DPRINT("SubKey HashBlock %p\n", HashBlock)
2269 if (HashBlock != NULL)
2270 {
2271 CmiDestroyBlock(RegistryHive,
2272 HashBlock,
2273 SubKey->KeyCell->HashTableOffset);
2274 SubKey->KeyCell->HashTableOffset = -1;
2275 }
2276 }
2277
2278 /* Decrement the number of the parent key's sub keys */
2279 if (ParentKey != NULL)
2280 {
2281 DPRINT("ParentKey %p\n", ParentKey)
2282 ParentKey->KeyCell->NumberOfSubKeys--;
2283
2284 /* Remove the parent key's hash table */
2285 if (ParentKey->KeyCell->NumberOfSubKeys == 0)
2286 {
2287 DPRINT("ParentKey HashTableOffset %lx\n", ParentKey->KeyCell->HashTableOffset)
2288 HashBlock = CmiGetBlock(RegistryHive,
2289 ParentKey->KeyCell->HashTableOffset,
2290 NULL);
2291 DPRINT("ParentKey HashBlock %p\n", HashBlock)
2292 if (HashBlock != NULL)
2293 {
2294 CmiDestroyBlock(RegistryHive,
2295 HashBlock,
2296 ParentKey->KeyCell->HashTableOffset);
2297 ParentKey->KeyCell->HashTableOffset = -1;
2298 }
2299 }
2300
2301 NtQuerySystemTime((PTIME)&ParentKey->KeyCell->LastWriteTime);
2302 CmiMarkBlockDirty(RegistryHive,
2303 ParentKey->BlockOffset);
2304 }
2305
2306 /* Destroy key cell */
2307 CmiDestroyBlock(RegistryHive,
2308 SubKey->KeyCell,
2309 SubKey->BlockOffset);
2310 SubKey->BlockOffset = -1;
2311 SubKey->KeyCell = NULL;
2312
2313 return(STATUS_SUCCESS);
2314 }
2315
2316
2317 NTSTATUS
2318 CmiScanKeyForValue(IN PREGISTRY_HIVE RegistryHive,
2319 IN PKEY_CELL KeyCell,
2320 IN PUNICODE_STRING ValueName,
2321 OUT PVALUE_CELL *ValueCell,
2322 OUT BLOCK_OFFSET *VBOffset)
2323 {
2324 PVALUE_LIST_CELL ValueListCell;
2325 PVALUE_CELL CurValueCell;
2326 ULONG i;
2327
2328 ValueListCell = CmiGetBlock(RegistryHive, KeyCell->ValuesOffset, NULL);
2329
2330 *ValueCell = NULL;
2331
2332 if (ValueListCell == NULL)
2333 {
2334 DPRINT("ValueListCell is NULL\n");
2335 return STATUS_SUCCESS;
2336 }
2337
2338 VERIFY_VALUE_LIST_CELL(ValueListCell);
2339
2340 for (i = 0; i < KeyCell->NumberOfValues; i++)
2341 {
2342 CurValueCell = CmiGetBlock(RegistryHive,
2343 ValueListCell->Values[i],
2344 NULL);
2345
2346 if ((CurValueCell != NULL) &&
2347 CmiComparePackedNames(ValueName,
2348 CurValueCell->Name,
2349 CurValueCell->NameSize,
2350 CurValueCell->Flags & REG_VALUE_NAME_PACKED))
2351 {
2352 *ValueCell = CurValueCell;
2353 if (VBOffset)
2354 *VBOffset = ValueListCell->Values[i];
2355 //DPRINT("Found value %s\n", ValueName);
2356 break;
2357 }
2358 CmiReleaseBlock(RegistryHive, CurValueCell);
2359 }
2360
2361 CmiReleaseBlock(RegistryHive, ValueListCell);
2362
2363 return STATUS_SUCCESS;
2364 }
2365
2366
2367 NTSTATUS
2368 CmiGetValueFromKeyByIndex(IN PREGISTRY_HIVE RegistryHive,
2369 IN PKEY_CELL KeyCell,
2370 IN ULONG Index,
2371 OUT PVALUE_CELL *ValueCell)
2372 {
2373 PVALUE_LIST_CELL ValueListCell;
2374 PVALUE_CELL CurValueCell;
2375
2376 ValueListCell = CmiGetBlock(RegistryHive, KeyCell->ValuesOffset, NULL);
2377
2378 *ValueCell = NULL;
2379
2380 if (ValueListCell == NULL)
2381 {
2382 return STATUS_NO_MORE_ENTRIES;
2383 }
2384
2385 VERIFY_VALUE_LIST_CELL(ValueListCell);
2386
2387 if (Index >= KeyCell->NumberOfValues)
2388 {
2389 return STATUS_NO_MORE_ENTRIES;
2390 }
2391
2392 CurValueCell = CmiGetBlock(RegistryHive,
2393 ValueListCell->Values[Index],
2394 NULL);
2395
2396 if (CurValueCell != NULL)
2397 {
2398 *ValueCell = CurValueCell;
2399 }
2400
2401 CmiReleaseBlock(RegistryHive, CurValueCell);
2402 CmiReleaseBlock(RegistryHive, ValueListCell);
2403
2404 return STATUS_SUCCESS;
2405 }
2406
2407
2408 NTSTATUS
2409 CmiAddValueToKey(IN PREGISTRY_HIVE RegistryHive,
2410 IN PKEY_CELL KeyCell,
2411 IN PUNICODE_STRING ValueName,
2412 OUT PVALUE_CELL *pValueCell,
2413 OUT BLOCK_OFFSET *pVBOffset)
2414 {
2415 PVALUE_LIST_CELL NewValueListCell;
2416 PVALUE_LIST_CELL ValueListCell;
2417 PVALUE_CELL NewValueCell;
2418 BLOCK_OFFSET VLBOffset;
2419 BLOCK_OFFSET VBOffset;
2420 NTSTATUS Status;
2421
2422 Status = CmiAllocateValueCell(RegistryHive,
2423 &NewValueCell,
2424 &VBOffset,
2425 ValueName);
2426 *pVBOffset = VBOffset;
2427
2428 if (!NT_SUCCESS(Status))
2429 {
2430 return Status;
2431 }
2432
2433 ValueListCell = CmiGetBlock(RegistryHive, KeyCell->ValuesOffset, NULL);
2434
2435 if (ValueListCell == NULL)
2436 {
2437 Status = CmiAllocateBlock(RegistryHive,
2438 (PVOID) &ValueListCell,
2439 sizeof(BLOCK_OFFSET) * 3,
2440 &VLBOffset);
2441
2442 if (!NT_SUCCESS(Status))
2443 {
2444 CmiDestroyValueCell(RegistryHive, NewValueCell, VBOffset);
2445 return Status;
2446 }
2447 KeyCell->ValuesOffset = VLBOffset;
2448 }
2449 else if (KeyCell->NumberOfValues >=
2450 (((ULONG)ABS_VALUE(ValueListCell->CellSize) - 4) / sizeof(BLOCK_OFFSET)))
2451 {
2452 Status = CmiAllocateBlock(RegistryHive,
2453 (PVOID) &NewValueListCell,
2454 (KeyCell->NumberOfValues + REG_VALUE_LIST_CELL_MULTIPLE) *
2455 sizeof(BLOCK_OFFSET),
2456 &VLBOffset);
2457 if (!NT_SUCCESS(Status))
2458 {
2459 CmiDestroyValueCell(RegistryHive, NewValueCell, VBOffset);
2460 return Status;
2461 }
2462
2463 RtlCopyMemory(&NewValueListCell->Values[0],
2464 &ValueListCell->Values[0],
2465 sizeof(BLOCK_OFFSET) * KeyCell->NumberOfValues);
2466 CmiDestroyBlock(RegistryHive, ValueListCell, KeyCell->ValuesOffset);
2467 KeyCell->ValuesOffset = VLBOffset;
2468 ValueListCell = NewValueListCell;
2469 }
2470
2471 DPRINT("KeyCell->NumberOfValues %lu, ValueListCell->CellSize %lu (%lu %lx)\n",
2472 KeyCell->NumberOfValues,
2473 (ULONG)ABS_VALUE(ValueListCell->CellSize),
2474 ((ULONG)ABS_VALUE(ValueListCell->CellSize) - 4) / sizeof(BLOCK_OFFSET),
2475 ((ULONG)ABS_VALUE(ValueListCell->CellSize) - 4) / sizeof(BLOCK_OFFSET));
2476
2477 ValueListCell->Values[KeyCell->NumberOfValues] = VBOffset;
2478 KeyCell->NumberOfValues++;
2479 CmiReleaseBlock(RegistryHive, ValueListCell);
2480 CmiReleaseBlock(RegistryHive, NewValueCell);
2481 *pValueCell = NewValueCell;
2482
2483 return STATUS_SUCCESS;
2484 }
2485
2486
2487 NTSTATUS
2488 CmiDeleteValueFromKey(IN PREGISTRY_HIVE RegistryHive,
2489 IN PKEY_CELL KeyCell,
2490 IN BLOCK_OFFSET KeyCellOffset,
2491 IN PUNICODE_STRING ValueName)
2492 {
2493 PVALUE_LIST_CELL ValueListCell;
2494 PVALUE_CELL CurValueCell;
2495 ULONG i;
2496
2497 ValueListCell = CmiGetBlock(RegistryHive, KeyCell->ValuesOffset, NULL);
2498
2499 if (ValueListCell == NULL)
2500 {
2501 return STATUS_SUCCESS;
2502 }
2503
2504 VERIFY_VALUE_LIST_CELL(ValueListCell);
2505
2506 for (i = 0; i < KeyCell->NumberOfValues; i++)
2507 {
2508 CurValueCell = CmiGetBlock(RegistryHive, ValueListCell->Values[i], NULL);
2509
2510 if ((CurValueCell != NULL) &&
2511 CmiComparePackedNames(ValueName,
2512 CurValueCell->Name,
2513 CurValueCell->NameSize,
2514 CurValueCell->Flags & REG_VALUE_NAME_PACKED))
2515 {
2516 CmiDestroyValueCell(RegistryHive, CurValueCell, ValueListCell->Values[i]);
2517
2518 if ((KeyCell->NumberOfValues - 1) < i)
2519 {
2520 RtlCopyMemory(&ValueListCell->Values[i],
2521 &ValueListCell->Values[i + 1],
2522 sizeof(BLOCK_OFFSET) * (KeyCell->NumberOfValues - 1 - i));
2523 }
2524 else
2525 {
2526 RtlZeroMemory(&ValueListCell->Values[i], sizeof(BLOCK_OFFSET));
2527 }
2528
2529 KeyCell->NumberOfValues -= 1;
2530 break;
2531 }
2532 CmiReleaseBlock(RegistryHive, CurValueCell);
2533 }
2534
2535 CmiReleaseBlock(RegistryHive, ValueListCell);
2536
2537 if (KeyCell->NumberOfValues == 0)
2538 {
2539 CmiDestroyBlock(RegistryHive,
2540 ValueListCell,
2541 KeyCell->ValuesOffset);
2542 }
2543 else
2544 {
2545 CmiMarkBlockDirty(RegistryHive,
2546 KeyCell->ValuesOffset);
2547 }
2548
2549 CmiMarkBlockDirty(RegistryHive,
2550 KeyCellOffset);
2551
2552 return STATUS_SUCCESS;
2553 }
2554
2555
2556 NTSTATUS
2557 CmiAllocateHashTableBlock(IN PREGISTRY_HIVE RegistryHive,
2558 OUT PHASH_TABLE_CELL *HashBlock,
2559 OUT BLOCK_OFFSET *HBOffset,
2560 IN ULONG HashTableSize)
2561 {
2562 PHASH_TABLE_CELL NewHashBlock;
2563 ULONG NewHashSize;
2564 NTSTATUS Status;
2565
2566 Status = STATUS_SUCCESS;
2567 *HashBlock = NULL;
2568 NewHashSize = sizeof(HASH_TABLE_CELL) +
2569 (HashTableSize - 1) * sizeof(HASH_RECORD);
2570 Status = CmiAllocateBlock(RegistryHive,
2571 (PVOID*) &NewHashBlock,
2572 NewHashSize,
2573 HBOffset);
2574
2575 if ((NewHashBlock == NULL) || (!NT_SUCCESS(Status)))
2576 {
2577 Status = STATUS_INSUFFICIENT_RESOURCES;
2578 }
2579 else
2580 {
2581 NewHashBlock->Id = REG_HASH_TABLE_BLOCK_ID;
2582 NewHashBlock->HashTableSize = HashTableSize;
2583 *HashBlock = NewHashBlock;
2584 }
2585
2586 return Status;
2587 }
2588
2589
2590 PKEY_CELL
2591 CmiGetKeyFromHashByIndex(PREGISTRY_HIVE RegistryHive,
2592 PHASH_TABLE_CELL HashBlock,
2593 ULONG Index)
2594 {
2595 BLOCK_OFFSET KeyOffset;
2596 PKEY_CELL KeyCell;
2597
2598 if (HashBlock == NULL)
2599 return NULL;
2600
2601 if (IsVolatileHive(RegistryHive))
2602 {
2603 KeyCell = (PKEY_CELL) HashBlock->Table[Index].KeyOffset;
2604 }
2605 else
2606 {
2607 KeyOffset = HashBlock->Table[Index].KeyOffset;
2608 KeyCell = CmiGetBlock(RegistryHive, KeyOffset, NULL);
2609 }
2610 CmiLockBlock(RegistryHive, KeyCell);
2611
2612 return KeyCell;
2613 }
2614
2615
2616 NTSTATUS
2617 CmiAddKeyToHashTable(PREGISTRY_HIVE RegistryHive,
2618 PHASH_TABLE_CELL HashBlock,
2619 PKEY_CELL NewKeyCell,
2620 BLOCK_OFFSET NKBOffset)
2621 {
2622 ULONG i;
2623
2624 for (i = 0; i < HashBlock->HashTableSize; i++)
2625 {
2626 if (HashBlock->Table[i].KeyOffset == 0)
2627 {
2628 HashBlock->Table[i].KeyOffset = NKBOffset;
2629 RtlCopyMemory(&HashBlock->Table[i].HashValue, NewKeyCell->Name, 4);
2630 return STATUS_SUCCESS;
2631 }
2632 }
2633
2634 return STATUS_UNSUCCESSFUL;
2635 }
2636
2637
2638 NTSTATUS
2639 CmiRemoveKeyFromHashTable(PREGISTRY_HIVE RegistryHive,
2640 PHASH_TABLE_CELL HashBlock,
2641 BLOCK_OFFSET NKBOffset)
2642 {
2643 ULONG i;
2644
2645 for (i = 0; i < HashBlock->HashTableSize; i++)
2646 {
2647 if (HashBlock->Table[i].KeyOffset == NKBOffset)
2648 {
2649 HashBlock->Table[i].KeyOffset = 0;
2650 RtlZeroMemory(&HashBlock->Table[i].HashValue, 4);
2651 return STATUS_SUCCESS;
2652 }
2653 }
2654
2655 return STATUS_UNSUCCESSFUL;
2656 }
2657
2658
2659 NTSTATUS
2660 CmiAllocateValueCell(PREGISTRY_HIVE RegistryHive,
2661 PVALUE_CELL *ValueCell,
2662 BLOCK_OFFSET *VBOffset,
2663 IN PUNICODE_STRING ValueName)
2664 {
2665 PVALUE_CELL NewValueCell;
2666 NTSTATUS Status;
2667 BOOLEAN Packable;
2668 ULONG NameSize;
2669 ULONG i;
2670
2671 Status = STATUS_SUCCESS;
2672
2673 NameSize = CmiGetPackedNameLength(ValueName,
2674 &Packable);
2675
2676 DPRINT("ValueName->Length %lu NameSize %lu\n", ValueName->Length, NameSize);
2677
2678 Status = CmiAllocateBlock(RegistryHive,
2679 (PVOID*) &NewValueCell,
2680 sizeof(VALUE_CELL) + NameSize,
2681 VBOffset);
2682 if ((NewValueCell == NULL) || (!NT_SUCCESS(Status)))
2683 {
2684 Status = STATUS_INSUFFICIENT_RESOURCES;
2685 }
2686 else
2687 {
2688 NewValueCell->Id = REG_VALUE_CELL_ID;
2689 NewValueCell->NameSize = NameSize;
2690 if (Packable)
2691 {
2692 /* Pack the value name */
2693 for (i = 0; i < NameSize; i++)
2694 NewValueCell->Name[i] = (CHAR)ValueName->Buffer[i];
2695 NewValueCell->Flags |= REG_VALUE_NAME_PACKED;
2696 }
2697 else
2698 {
2699 /* Copy the value name */
2700 RtlCopyMemory(NewValueCell->Name,
2701 ValueName->Buffer,
2702 NameSize);
2703 NewValueCell->Flags = 0;
2704 }
2705 NewValueCell->DataType = 0;
2706 NewValueCell->DataSize = 0;
2707 NewValueCell->DataOffset = 0xffffffff;
2708 *ValueCell = NewValueCell;
2709 }
2710
2711 return Status;
2712 }
2713
2714
2715 NTSTATUS
2716 CmiDestroyValueCell(PREGISTRY_HIVE RegistryHive,
2717 PVALUE_CELL ValueCell,
2718 BLOCK_OFFSET VBOffset)
2719 {
2720 NTSTATUS Status;
2721 PVOID pBlock;
2722 PHBIN pBin;
2723
2724 DPRINT("CmiDestroyValueCell(Cell %p Offset %lx)\n", ValueCell, VBOffset);
2725
2726 VERIFY_VALUE_CELL(ValueCell);
2727
2728 /* Destroy the data cell */
2729 if (ValueCell->DataSize > 4)
2730 {
2731 pBlock = CmiGetBlock(RegistryHive, ValueCell->DataOffset, &pBin);
2732 Status = CmiDestroyBlock(RegistryHive, pBlock, ValueCell->DataOffset);
2733 if (!NT_SUCCESS(Status))
2734 {
2735 return Status;
2736 }
2737
2738 /* Update time of heap */
2739 if (IsPermanentHive(RegistryHive))
2740 ZwQuerySystemTime((PTIME) &pBin->DateModified);
2741 }
2742
2743 /* Destroy the value cell */
2744 Status = CmiDestroyBlock(RegistryHive, ValueCell, VBOffset);
2745
2746 /* Update time of heap */
2747 if (IsPermanentHive(RegistryHive) && CmiGetBlock(RegistryHive, VBOffset, &pBin))
2748 {
2749 ZwQuerySystemTime((PTIME) &pBin->DateModified);
2750 }
2751
2752 return Status;
2753 }
2754
2755
2756 NTSTATUS
2757 CmiAddBin(PREGISTRY_HIVE RegistryHive,
2758 PVOID *NewBlock,
2759 BLOCK_OFFSET *NewBlockOffset)
2760 {
2761 PCELL_HEADER tmpBlock;
2762 PHBIN * tmpBlockList;
2763 PHBIN tmpBin;
2764
2765 tmpBin = ExAllocatePool(PagedPool, REG_BLOCK_SIZE);
2766 if (tmpBin == NULL)
2767 {
2768 return STATUS_INSUFFICIENT_RESOURCES;
2769 }
2770
2771 tmpBin->BlockId = REG_BIN_ID;
2772 tmpBin->BlockOffset = RegistryHive->FileSize - REG_BLOCK_SIZE;
2773 RegistryHive->FileSize += REG_BLOCK_SIZE;
2774 tmpBin->BlockSize = REG_BLOCK_SIZE;
2775 tmpBin->Unused1 = 0;
2776 ZwQuerySystemTime((PTIME) &tmpBin->DateModified);
2777 tmpBin->Unused2 = 0;
2778
2779 /* Increase size of list of blocks */
2780 tmpBlockList = ExAllocatePool(NonPagedPool,
2781 sizeof(PHBIN *) * (RegistryHive->BlockListSize + 1));
2782 if (tmpBlockList == NULL)
2783 {
2784 ExFreePool(tmpBin);
2785 return STATUS_INSUFFICIENT_RESOURCES;
2786 }
2787
2788 if (RegistryHive->BlockListSize > 0)
2789 {
2790 memcpy(tmpBlockList,
2791 RegistryHive->BlockList,
2792 sizeof(PHBIN *)*(RegistryHive->BlockListSize));
2793 ExFreePool(RegistryHive->BlockList);
2794 }
2795
2796 RegistryHive->BlockList = tmpBlockList;
2797 RegistryHive->BlockList[RegistryHive->BlockListSize++] = tmpBin;
2798
2799 /* Initialize a free block in this heap : */
2800 tmpBlock = (PCELL_HEADER)((ULONG_PTR) tmpBin + REG_HBIN_DATA_OFFSET);
2801 tmpBlock->CellSize = (REG_BLOCK_SIZE - REG_HBIN_DATA_OFFSET);
2802
2803 /* Grow bitmap if necessary */
2804 if (IsVolatileHive(RegistryHive) &&
2805 (RegistryHive->BlockListSize % (sizeof(ULONG) * 8) == 0))
2806 {
2807 PULONG BitmapBuffer;
2808 ULONG BitmapSize;
2809
2810 DPRINT1("Grow hive bitmap\n");
2811
2812 /* Calculate bitmap size in bytes (always a multiple of 32 bits) */
2813 BitmapSize = ROUND_UP(RegistryHive->BlockListSize, sizeof(ULONG) * 8) / 8;
2814 DPRINT1("RegistryHive->BlockListSize: %lu\n", RegistryHive->BlockListSize);
2815 DPRINT1("BitmapSize: %lu Bytes %lu Bits\n", BitmapSize, BitmapSize * 8);
2816 BitmapBuffer = (PULONG)ExAllocatePool(PagedPool,
2817 BitmapSize);
2818 RtlZeroMemory(BitmapBuffer, BitmapSize);
2819 RtlCopyMemory(BitmapBuffer,
2820 RegistryHive->DirtyBitMap.Buffer,
2821 RegistryHive->DirtyBitMap.SizeOfBitMap);
2822 ExFreePool(RegistryHive->BitmapBuffer);
2823 RegistryHive->BitmapBuffer = BitmapBuffer;
2824 RtlInitializeBitMap(&RegistryHive->DirtyBitMap,
2825 RegistryHive->BitmapBuffer,
2826 BitmapSize * 8);
2827 }
2828
2829 *NewBlock = (PVOID) tmpBlock;
2830
2831 if (NewBlockOffset)
2832 *NewBlockOffset = tmpBin->BlockOffset + REG_HBIN_DATA_OFFSET;
2833
2834 /* FIXME: set first dword to block_offset of another free bloc */
2835
2836 /* Mark new bin dirty */
2837 CmiMarkBinDirty(RegistryHive,
2838 tmpBin->BlockOffset);
2839
2840 return STATUS_SUCCESS;
2841 }
2842
2843
2844 NTSTATUS
2845 CmiAllocateBlock(PREGISTRY_HIVE RegistryHive,
2846 PVOID *Block,
2847 LONG BlockSize,
2848 BLOCK_OFFSET * pBlockOffset)
2849 {
2850 PCELL_HEADER NewBlock;
2851 NTSTATUS Status;
2852 PHBIN pBin;
2853
2854 Status = STATUS_SUCCESS;
2855
2856 /* Round to 16 bytes multiple */
2857 BlockSize = (BlockSize + sizeof(DWORD) + 15) & 0xfffffff0;
2858
2859 /* Handle volatile hives first */
2860 if (IsVolatileHive(RegistryHive))
2861 {
2862 NewBlock = ExAllocatePool(NonPagedPool, BlockSize);
2863
2864 if (NewBlock == NULL)
2865 {
2866 Status = STATUS_INSUFFICIENT_RESOURCES;
2867 }
2868 else
2869 {
2870 RtlZeroMemory(NewBlock, BlockSize);
2871 NewBlock->CellSize = BlockSize;
2872 CmiLockBlock(RegistryHive, NewBlock);
2873 *Block = NewBlock;
2874 if (pBlockOffset)
2875 *pBlockOffset = (BLOCK_OFFSET) NewBlock;
2876 }
2877 }
2878 else
2879 {
2880 ULONG i;
2881
2882 /* first search in free blocks */
2883 NewBlock = NULL;
2884 for (i = 0; i < RegistryHive->FreeListSize; i++)
2885 {
2886 if (RegistryHive->FreeList[i]->CellSize >= BlockSize)
2887 {
2888 PVOID Temp;
2889
2890 NewBlock = RegistryHive->FreeList[i];
2891 if (pBlockOffset)
2892 *pBlockOffset = RegistryHive->FreeListOffset[i];
2893
2894 /* Update time of heap */
2895 Temp = CmiGetBlock(RegistryHive, RegistryHive->FreeListOffset[i], &pBin);
2896
2897 if (Temp)
2898 {
2899 ZwQuerySystemTime((PTIME) &pBin->DateModified);
2900 CmiMarkBlockDirty(RegistryHive, RegistryHive->FreeListOffset[i]);
2901 }
2902
2903 if ((i + 1) < RegistryHive->FreeListSize)
2904 {
2905 RtlMoveMemory(&RegistryHive->FreeList[i],
2906 &RegistryHive->FreeList[i + 1],
2907 sizeof(RegistryHive->FreeList[0])
2908 * (RegistryHive->FreeListSize - i - 1));
2909 RtlMoveMemory(&RegistryHive->FreeListOffset[i],
2910 &RegistryHive->FreeListOffset[i + 1],
2911 sizeof(RegistryHive->FreeListOffset[0])
2912 * (RegistryHive->FreeListSize - i - 1));
2913 }
2914 RegistryHive->FreeListSize--;
2915 break;
2916 }
2917 }
2918
2919 /* Need to extend hive file : */
2920 if (NewBlock == NULL)
2921 {
2922 /* Add a new block */
2923 Status = CmiAddBin(RegistryHive, (PVOID *) &NewBlock , pBlockOffset);
2924 }
2925
2926 if (NT_SUCCESS(Status))
2927 {
2928 *Block = NewBlock;
2929
2930 /* Split the block in two parts */
2931 if (NewBlock->CellSize > BlockSize)
2932 {
2933 NewBlock = (PCELL_HEADER) ((ULONG_PTR) NewBlock+BlockSize);
2934 NewBlock->CellSize = ((PCELL_HEADER) (*Block))->CellSize - BlockSize;
2935 CmiAddFree(RegistryHive,
2936 NewBlock,
2937 *pBlockOffset + BlockSize,
2938 TRUE);
2939 CmiMarkBlockDirty(RegistryHive,
2940 *pBlockOffset + BlockSize);
2941 }
2942 else if (NewBlock->CellSize < BlockSize)
2943 {
2944 return(STATUS_UNSUCCESSFUL);
2945 }
2946
2947 RtlZeroMemory(*Block, BlockSize);
2948 ((PCELL_HEADER) (*Block))->CellSize = -BlockSize;
2949 CmiLockBlock(RegistryHive, *Block);
2950 }
2951 }
2952
2953 return(Status);
2954 }
2955
2956
2957 NTSTATUS
2958 CmiDestroyBlock(PREGISTRY_HIVE RegistryHive,
2959 PVOID Block,
2960 BLOCK_OFFSET Offset)
2961 {
2962 NTSTATUS Status;
2963 PHBIN pBin;
2964
2965 Status = STATUS_SUCCESS;
2966
2967 if (IsVolatileHive(RegistryHive))
2968 {
2969 CmiReleaseBlock(RegistryHive, Block);
2970 ExFreePool(Block);
2971 }
2972 else
2973 {
2974 PCELL_HEADER pFree = Block;
2975
2976 if (pFree->CellSize < 0)
2977 pFree->CellSize = -pFree->CellSize;
2978
2979 /* Clear block (except the block size) */
2980 RtlZeroMemory(((PVOID)pFree) + sizeof(ULONG),
2981 pFree->CellSize - sizeof(ULONG));
2982
2983 /* add block to the list of free blocks */
2984 CmiAddFree(RegistryHive, Block, Offset, TRUE);
2985 CmiReleaseBlock(RegistryHive, Block);
2986
2987 /* Update time of heap */
2988 if (IsPermanentHive(RegistryHive) && CmiGetBlock(RegistryHive, Offset,&pBin))
2989 ZwQuerySystemTime((PTIME) &pBin->DateModified);
2990
2991 CmiMarkBlockDirty(RegistryHive, Offset);
2992
2993 /* FIXME: Set first dword to block_offset of another free block ? */
2994 /* FIXME: Concatenate with previous and next block if free */
2995 }
2996
2997 return Status;
2998 }
2999
3000
3001 static BOOLEAN
3002 CmiMergeFree(PREGISTRY_HIVE RegistryHive,
3003 PCELL_HEADER FreeBlock,
3004 BLOCK_OFFSET FreeOffset)
3005 {
3006 BLOCK_OFFSET BlockOffset;
3007 BLOCK_OFFSET BinOffset;
3008 ULONG BlockSize;
3009 ULONG BinSize;
3010 PHBIN Bin;
3011 ULONG i;
3012
3013 DPRINT("CmiMergeFree(Block %lx Offset %lx Size %lx) called\n",
3014 FreeBlock, FreeOffset, FreeBlock->CellSize);
3015
3016 CmiGetBlock(RegistryHive,
3017 FreeOffset,
3018 &Bin);
3019 DPRINT("Bin %p\n", Bin);
3020 if (Bin == NULL)
3021 return(FALSE);
3022
3023 BinOffset = Bin->BlockOffset;
3024 BinSize = Bin->BlockSize;
3025 DPRINT("Bin %p Offset %lx Size %lx\n", Bin, BinOffset, BinSize);
3026
3027 for (i = 0; i < RegistryHive->FreeListSize; i++)
3028 {
3029 BlockOffset = RegistryHive->FreeListOffset[i];
3030 BlockSize = RegistryHive->FreeList[i]->CellSize;
3031 if (BlockOffset > BinOffset &&
3032 BlockOffset < BinOffset + BinSize)
3033 {
3034 DPRINT("Free block: Offset %lx Size %lx\n",
3035 BlockOffset, BlockSize);
3036
3037 if ((i < (RegistryHive->FreeListSize - 1)) &&
3038 (BlockOffset + BlockSize == FreeOffset) &&
3039 (FreeOffset + FreeBlock->CellSize == RegistryHive->FreeListOffset[i + 1]))
3040 {
3041 DPRINT("Merge current block with previous and next block\n");
3042
3043 RegistryHive->FreeList[i]->CellSize +=
3044 (FreeBlock->CellSize + RegistryHive->FreeList[i + 1]->CellSize);
3045
3046 FreeBlock->CellSize = 0;
3047 RegistryHive->FreeList[i + 1]->CellSize = 0;
3048
3049
3050 if ((i + 2) < RegistryHive->FreeListSize)
3051 {
3052 RtlMoveMemory(&RegistryHive->FreeListOffset[i + 1],
3053 &RegistryHive->FreeListOffset[i + 2],
3054 sizeof(RegistryHive->FreeListOffset[0])
3055 * (RegistryHive->FreeListSize - i - 2));
3056 }
3057 RegistryHive->FreeListSize--;
3058
3059 CmiMarkBlockDirty(RegistryHive, BlockOffset);
3060
3061 return(TRUE);
3062 }
3063 else if (BlockOffset + BlockSize == FreeOffset)
3064 {
3065 DPRINT("Merge current block with previous block\n");
3066
3067 RegistryHive->FreeList[i]->CellSize += FreeBlock->CellSize;
3068 FreeBlock->CellSize = 0;
3069
3070 CmiMarkBlockDirty(RegistryHive, BlockOffset);
3071
3072 return(TRUE);
3073 }
3074 else if (FreeOffset + FreeBlock->CellSize == BlockOffset)
3075 {
3076 DPRINT("Merge current block with next block\n");
3077
3078 FreeBlock->CellSize += RegistryHive->FreeList[i]->CellSize;
3079 RegistryHive->FreeList[i]->CellSize = 0;
3080 RegistryHive->FreeList[i] = FreeBlock;
3081 RegistryHive->FreeListOffset[i] = FreeOffset;
3082
3083 CmiMarkBlockDirty(RegistryHive, FreeOffset);
3084
3085 return(TRUE);
3086 }
3087 }
3088 }
3089
3090 return(FALSE);
3091 }
3092
3093
3094 NTSTATUS
3095 CmiAddFree(PREGISTRY_HIVE RegistryHive,
3096 PCELL_HEADER FreeBlock,
3097 BLOCK_OFFSET FreeOffset,
3098 BOOLEAN MergeFreeBlocks)
3099 {
3100 PCELL_HEADER *tmpList;
3101 BLOCK_OFFSET *tmpListOffset;
3102 LONG minInd;
3103 LONG maxInd;
3104 LONG medInd;
3105
3106 assert(RegistryHive);
3107 assert(FreeBlock);
3108
3109 DPRINT("FreeBlock %.08lx FreeOffset %.08lx\n",
3110 FreeBlock, FreeOffset);
3111
3112 /* Merge free blocks */
3113 if (MergeFreeBlocks == TRUE)
3114 {
3115 if (CmiMergeFree(RegistryHive, FreeBlock, FreeOffset))
3116 return(STATUS_SUCCESS);
3117 }
3118
3119 if ((RegistryHive->FreeListSize + 1) > RegistryHive->FreeListMax)
3120 {
3121 tmpList = ExAllocatePool(PagedPool,
3122 sizeof(PCELL_HEADER) * (RegistryHive->FreeListMax + 32));
3123 if (tmpList == NULL)
3124 return STATUS_INSUFFICIENT_RESOURCES;
3125
3126 tmpListOffset = ExAllocatePool(PagedPool,
3127 sizeof(BLOCK_OFFSET *) * (RegistryHive->FreeListMax + 32));
3128
3129 if (tmpListOffset == NULL)
3130 {
3131 ExFreePool(tmpList);
3132 return STATUS_INSUFFICIENT_RESOURCES;
3133 }
3134
3135 if (RegistryHive->FreeListMax)
3136 {
3137 RtlMoveMemory(tmpList,
3138 RegistryHive->FreeList,
3139 sizeof(PCELL_HEADER) * (RegistryHive->FreeListMax));
3140 RtlMoveMemory(tmpListOffset,
3141 RegistryHive->FreeListOffset,
3142 sizeof(BLOCK_OFFSET *) * (RegistryHive->FreeListMax));
3143 ExFreePool(RegistryHive->FreeList);
3144 ExFreePool(RegistryHive->FreeListOffset);
3145 }
3146 RegistryHive->FreeList = tmpList;
3147 RegistryHive->FreeListOffset = tmpListOffset;
3148 RegistryHive->FreeListMax += 32;
3149 }
3150
3151 /* Add new offset to free list, maintaining list in ascending order */
3152 if ((RegistryHive->FreeListSize == 0)
3153 || (RegistryHive->FreeListOffset[RegistryHive->FreeListSize-1] < FreeOffset))
3154 {
3155 /* Add to end of list */
3156 RegistryHive->FreeList[RegistryHive->FreeListSize] = FreeBlock;
3157 RegistryHive->FreeListOffset[RegistryHive->FreeListSize++] = FreeOffset;
3158 }
3159 else if (RegistryHive->FreeListOffset[0] > FreeOffset)
3160 {
3161 /* Add to begin of list */
3162 RtlMoveMemory(&RegistryHive->FreeList[1],
3163 &RegistryHive->FreeList[0],
3164 sizeof(RegistryHive->FreeList[0]) * RegistryHive->FreeListSize);
3165 RtlMoveMemory(&RegistryHive->FreeListOffset[1],
3166 &RegistryHive->FreeListOffset[0],
3167 sizeof(RegistryHive->FreeListOffset[0]) * RegistryHive->FreeListSize);
3168 RegistryHive->FreeList[0] = FreeBlock;
3169 RegistryHive->FreeListOffset[0] = FreeOffset;
3170 RegistryHive->FreeListSize++;
3171 }
3172 else
3173 {
3174 /* Search where to insert */
3175 minInd = 0;
3176 maxInd = RegistryHive->FreeListSize - 1;
3177 while ((maxInd - minInd) > 1)
3178 {
3179 medInd = (minInd + maxInd) / 2;
3180 if (RegistryHive->FreeListOffset[medInd] > FreeOffset)
3181 maxInd = medInd;
3182 else
3183 minInd = medInd;
3184 }
3185
3186 /* Insert before maxInd */
3187 RtlMoveMemory(&RegistryHive->FreeList[maxInd+1],
3188 &RegistryHive->FreeList[maxInd],
3189 sizeof(RegistryHive->FreeList[0]) * (RegistryHive->FreeListSize - minInd));
3190 RtlMoveMemory(&RegistryHive->FreeListOffset[maxInd + 1],
3191 &RegistryHive->FreeListOffset[maxInd],
3192 sizeof(RegistryHive->FreeListOffset[0]) * (RegistryHive->FreeListSize-minInd));
3193 RegistryHive->FreeList[maxInd] = FreeBlock;
3194 RegistryHive->FreeListOffset[maxInd] = FreeOffset;
3195 RegistryHive->FreeListSize++;
3196 }
3197
3198 return STATUS_SUCCESS;
3199 }
3200
3201
3202 PVOID
3203 CmiGetBlock(PREGISTRY_HIVE RegistryHive,
3204 BLOCK_OFFSET BlockOffset,
3205 PHBIN * ppBin)
3206 {
3207 if (ppBin)
3208 *ppBin = NULL;
3209
3210 if ((BlockOffset == 0) || (BlockOffset == (ULONG_PTR) -1))
3211 return NULL;
3212
3213 if (IsVolatileHive(RegistryHive))
3214 {
3215 return (PVOID) BlockOffset;
3216 }
3217 else
3218 {
3219 PHBIN pBin;
3220
3221 pBin = RegistryHive->BlockList[BlockOffset / 4096];
3222 if (ppBin)
3223 *ppBin = pBin;
3224 return((PVOID)((ULONG_PTR)pBin + (BlockOffset - pBin->BlockOffset)));
3225 }
3226 }
3227
3228
3229 VOID
3230 CmiLockBlock(PREGISTRY_HIVE RegistryHive,
3231 PVOID Block)
3232 {
3233 if (IsPermanentHive(RegistryHive))
3234 {
3235 /* FIXME: Implement */
3236 }
3237 }
3238
3239
3240 VOID
3241 CmiReleaseBlock(PREGISTRY_HIVE RegistryHive,
3242 PVOID Block)
3243 {
3244 if (IsPermanentHive(RegistryHive))
3245 {
3246 /* FIXME: Implement */
3247 }
3248 }
3249
3250
3251 VOID
3252 CmiMarkBlockDirty(PREGISTRY_HIVE RegistryHive,
3253 BLOCK_OFFSET BlockOffset)
3254 {
3255 PDATA_CELL Cell;
3256 LONG CellSize;
3257 ULONG BlockNumber;
3258 ULONG BlockCount;
3259
3260 if (IsVolatileHive(RegistryHive))
3261 return;
3262
3263 DPRINT("CmiMarkBlockDirty(Offset 0x%lx)\n", (ULONG)BlockOffset);
3264
3265 BlockNumber = (ULONG)BlockOffset / 4096;
3266
3267 Cell = CmiGetBlock(RegistryHive,
3268 BlockOffset,
3269 NULL);
3270
3271 CellSize = Cell->CellSize;
3272 if (CellSize < 0)
3273 CellSize = -CellSize;
3274
3275 BlockCount = (ROUND_UP(BlockOffset + CellSize, 4096) - ROUND_DOWN(BlockOffset, 4096)) / 4096;
3276
3277 DPRINT(" BlockNumber %lu Size %lu (%s) BlockCount %lu\n",
3278 BlockNumber,
3279 CellSize,
3280 (Cell->CellSize < 0) ? "used" : "free",
3281 BlockCount);
3282
3283 RegistryHive->HiveDirty = TRUE;
3284 RtlSetBits(&RegistryHive->DirtyBitMap,
3285 BlockNumber,
3286 BlockCount);
3287 }
3288
3289
3290 VOID
3291 CmiMarkBinDirty(PREGISTRY_HIVE RegistryHive,
3292 BLOCK_OFFSET BinOffset)
3293 {
3294 ULONG BlockNumber;
3295 ULONG BlockCount;
3296 PHBIN Bin;
3297
3298 if (IsVolatileHive(RegistryHive))
3299 return;
3300
3301 DPRINT("CmiMarkBinDirty(Offset 0x%lx)\n", (ULONG)BinOffset);
3302
3303 BlockNumber = (ULONG)BinOffset / 4096;
3304
3305 Bin = RegistryHive->BlockList[BlockNumber];
3306
3307 BlockCount = Bin->BlockSize / 4096;
3308
3309 DPRINT(" BlockNumber %lu Size %lu BlockCount %lu\n",
3310 BlockNumber,
3311 Bin->BlockSize,
3312 BlockCount);
3313
3314 RegistryHive->HiveDirty = TRUE;
3315 RtlSetBits(&RegistryHive->DirtyBitMap,
3316 BlockNumber,
3317 BlockCount);
3318 }
3319
3320
3321 ULONG
3322 CmiGetPackedNameLength(IN PUNICODE_STRING Name,
3323 OUT PBOOLEAN Packable)
3324 {
3325 ULONG i;
3326
3327 if (Packable != NULL)
3328 *Packable = TRUE;
3329
3330 for (i = 0; i < Name->Length; i++)
3331 {
3332 if (Name->Buffer[i] > 0xFF)
3333 {
3334 if (Packable != NULL)
3335 *Packable = FALSE;
3336 return(Name->Length);
3337 }
3338 }
3339
3340 return(Name->Length / sizeof(WCHAR));
3341 }
3342
3343
3344 BOOLEAN
3345 CmiComparePackedNames(IN PUNICODE_STRING Name,
3346 IN PCHAR NameBuffer,
3347 IN USHORT NameBufferSize,
3348 IN BOOLEAN NamePacked)
3349 {
3350 PWCHAR UNameBuffer;
3351 ULONG i;
3352
3353 if (NamePacked == TRUE)
3354 {
3355 if (Name->Length != NameBufferSize * sizeof(WCHAR))
3356 return(FALSE);
3357
3358 for (i = 0; i < Name->Length / sizeof(WCHAR); i++)
3359 {
3360 if (RtlUpcaseUnicodeChar(Name->Buffer[i]) != RtlUpcaseUnicodeChar((WCHAR)NameBuffer[i]))
3361 return(FALSE);
3362 }
3363 }
3364 else
3365 {
3366 if (Name->Length != NameBufferSize)
3367 return(FALSE);
3368
3369 UNameBuffer = (PWCHAR)NameBuffer;
3370
3371 for (i = 0; i < Name->Length / sizeof(WCHAR); i++)
3372 {
3373 if (RtlUpcaseUnicodeChar(Name->Buffer[i]) != RtlUpcaseUnicodeChar(UNameBuffer[i]))
3374 return(FALSE);
3375 }
3376 }
3377
3378 return(TRUE);
3379 }
3380
3381
3382 VOID
3383 CmiCopyPackedName(PWCHAR NameBuffer,
3384 PCHAR PackedNameBuffer,
3385 ULONG PackedNameSize)
3386 {
3387 ULONG i;
3388
3389 for (i = 0; i < PackedNameSize; i++)
3390 NameBuffer[i] = (WCHAR)PackedNameBuffer[i];
3391 }
3392
3393 /* EOF */