3 * COPYRIGHT: See COPYING in the top level directory
4 * PROJECT: ReactOS kernel
5 * FILE: ntoskrnl/cm/import.c
6 * PURPOSE: Registry functions
7 * PROGRAMMERS: Rex Jolliff
12 #include <ddk/ntddk.h>
14 #include <internal/ob.h>
17 #include <internal/pool.h>
18 #include <internal/registry.h>
19 #include <internal/ntoskrnl.h>
22 #include <internal/debug.h>
26 /* GLOBALS ******************************************************************/
28 static BOOLEAN CmiHardwareHiveImported = FALSE;
30 /* FUNCTIONS ****************************************************************/
33 checkAndSkipMagic (PCHAR regChunk)
35 if (strncmp (regChunk,
37 strlen (REGISTRY_FILE_MAGIC)) != 0)
39 CPRINT ("incorrect magic number in registry chunk. expected: %s got:%.*s\n",
41 strlen (REGISTRY_FILE_MAGIC),
45 regChunk += strlen (REGISTRY_FILE_MAGIC);
46 DPRINT ("Found regsitry chunk magic value\n");
52 skipWhitespaceInChunk (PCHAR regChunk)
54 while (*regChunk && isspace (*regChunk))
57 return *regChunk ? regChunk : 0;
61 computeKeyNameSize (PCHAR regChunk)
65 while (*regChunk != 0 && *regChunk != ']')
75 allocateKeyName (PUNICODE_STRING newKeyName, int newKeySize)
77 if (newKeyName->MaximumLength < (newKeySize + 1) * sizeof (WCHAR))
79 if (newKeyName->Buffer != 0)
80 ExFreePool (newKeyName->Buffer);
81 newKeyName->Length = 0;
82 newKeyName->MaximumLength = (newKeySize + 1) * sizeof (WCHAR);
83 newKeyName->Buffer = ExAllocatePool (NonPagedPool, newKeyName->MaximumLength);
84 if (newKeyName->Buffer == 0)
86 CPRINT ("Could not allocate space for key name\n");
89 newKeyName->Buffer [0] = 0;
93 newKeyName->Length = 0;
94 newKeyName->Buffer [0] = 0;
101 skipToNextKeyInChunk (PCHAR regChunk)
103 while (*regChunk != 0 && *regChunk != '[')
105 while (*regChunk != 0 && *regChunk != '\n')
112 return *regChunk ? regChunk : 0;
116 getKeyNameFromChunk (PCHAR regChunk, PUNICODE_STRING newKeyName)
120 while (*regChunk != 0 && *regChunk != ']')
122 newKeyName->Buffer [index++] = *regChunk++;
124 newKeyName->Buffer [index] = '\0';
125 newKeyName->Length = index * sizeof (WCHAR);
127 return *regChunk ? regChunk : 0;
131 createNewKey (PUNICODE_STRING newKeyName)
134 OBJECT_ATTRIBUTES attributes;
135 HANDLE handleToReturn;
137 DPRINT ("Creating key (%wZ)\n", newKeyName);
138 InitializeObjectAttributes (&attributes,
143 status = NtCreateKey (&handleToReturn,
150 if (!NT_SUCCESS(status))
152 CPRINT ("Could not crete key (%wZ)\n", newKeyName);
153 return INVALID_HANDLE_VALUE;
156 return handleToReturn;
160 skipToNextKeyValueInChunk (PCHAR regChunk)
162 while (*regChunk != 0 && *regChunk != '\n')
164 regChunk = skipWhitespaceInChunk (regChunk);
170 computeKeyValueNameSize (PCHAR regChunk)
174 if (*regChunk != '\"')
177 while (*regChunk != 0 && *regChunk != '\"')
183 return regChunk ? size : 0;
187 getKeyValueNameFromChunk (PCHAR regChunk, PUNICODE_STRING newKeyName)
192 while (*regChunk != 0 && *regChunk != '\"')
194 newKeyName->Buffer [index++] = *regChunk++;
196 newKeyName->Buffer [index] = '\0';
197 newKeyName->Length = index * sizeof (WCHAR);
200 return *regChunk ? regChunk : 0;
204 getKeyValueTypeFromChunk (PCHAR regChunk, PCHAR dataFormat, int *keyValueType)
206 if (*regChunk == '\"')
208 strcpy (dataFormat, "string");
209 *keyValueType = REG_SZ;
211 else if (strncmp (regChunk, "hex", 3) == 0)
213 strcpy (dataFormat, "hex");
215 if (*regChunk == '(')
218 *keyValueType = atoi (regChunk);
219 while (*regChunk != 0 && *regChunk != ')')
224 *keyValueType = REG_BINARY;
225 if (*regChunk == ':')
228 else if (strncmp (regChunk, "dword", 5) == 0)
230 strcpy (dataFormat, "dword");
231 *keyValueType = REG_DWORD;
233 if (*regChunk == ':')
236 else if (strncmp (regChunk, "multi", 5) == 0)
238 strcpy (dataFormat, "multi");
239 *keyValueType = REG_MULTI_SZ;
241 if (*regChunk == ':')
244 else if (strncmp (regChunk, "expand", 6) == 0)
246 strcpy (dataFormat, "expand");
247 *keyValueType = REG_EXPAND_SZ;
249 if (*regChunk == ':')
257 return *regChunk ? regChunk : 0;
261 computeKeyValueDataSize (PCHAR regChunk, PCHAR dataFormat)
265 if (strcmp (dataFormat, "string") == 0)
268 while (*regChunk != 0 && *regChunk != '\"')
277 else if (strcmp (dataFormat, "hex") == 0)
279 while (*regChunk != 0 && isxdigit(*regChunk))
284 if (*regChunk == ',')
287 if (*regChunk == '\\')
290 regChunk = skipWhitespaceInChunk (regChunk);
295 else if (strcmp (dataFormat, "dword") == 0)
297 dataSize = sizeof(DWORD);
298 while (*regChunk != 0 && isxdigit(*regChunk))
303 else if (strcmp (dataFormat, "multi") == 0)
305 while (*regChunk == '\"')
308 while (*regChunk != 0 && *regChunk != '\"')
317 if (*regChunk == ',')
320 regChunk = skipWhitespaceInChunk (regChunk);
321 if (*regChunk == '\\')
324 regChunk = skipWhitespaceInChunk (regChunk);
333 else if (strcmp (dataFormat, "expand") == 0)
336 while (*regChunk != 0 && *regChunk != '\"')
354 allocateDataBuffer (PVOID * data, int * dataBufferSize, int dataSize)
356 if (*dataBufferSize < dataSize)
358 if (*dataBufferSize > 0)
360 *data = ExAllocatePool (NonPagedPool, dataSize);
361 *dataBufferSize = dataSize;
368 getKeyValueDataFromChunk (PCHAR regChunk, PCHAR dataFormat, PCHAR data)
374 if (strcmp (dataFormat, "string") == 0)
376 /* convert quoted string to zero-terminated Unicode string */
379 while (*regChunk != 0 && *regChunk != '\"')
381 *ptr++ = (WCHAR)*regChunk++;
386 else if (strcmp (dataFormat, "hex") == 0)
388 while (*regChunk != 0 && isxdigit (*regChunk))
390 dataValue = (isdigit (*regChunk) ? *regChunk - '0' :
391 tolower(*regChunk) - 'a' + 10) << 4;
393 dataValue += (isdigit (*regChunk) ? *regChunk - '0' :
394 tolower(*regChunk) - 'a' + 10);
397 if (*regChunk == ',')
400 if (*regChunk == '\\')
403 regChunk = skipWhitespaceInChunk (regChunk);
408 else if (strcmp (dataFormat, "dword") == 0)
411 while (*regChunk != 0 && isxdigit(*regChunk))
413 dataValue = (isdigit (*regChunk) ? *regChunk - '0' :
414 tolower(*regChunk) - 'a' + 10);
415 ulValue = (ulValue << 4) + dataValue;
418 memcpy(data, &ulValue, sizeof(ULONG));
420 else if (strcmp (dataFormat, "multi") == 0)
423 while (*regChunk == '\"')
426 while (*regChunk != 0 && *regChunk != '\"')
428 *ptr++ = (WCHAR)*regChunk++;
432 if (*regChunk == ',')
435 regChunk = skipWhitespaceInChunk (regChunk);
436 if (*regChunk == '\\')
439 regChunk = skipWhitespaceInChunk (regChunk);
447 else if (strcmp (dataFormat, "expand") == 0)
449 /* convert quoted string to zero-terminated Unicode string */
452 while (*regChunk != 0 && *regChunk != '\"')
454 *ptr++ = (WCHAR)*regChunk++;
464 return *regChunk ? regChunk : 0;
468 setKeyValue (HANDLE currentKey,
469 PUNICODE_STRING newValueName,
476 DPRINT ("Adding value (%wZ) to current key, with data type %d size %d\n",
480 status = NtSetValueKey (currentKey,
486 if (!NT_SUCCESS(status))
488 CPRINT ("could not set key value, rc:%08x\n", status);
496 CmImportTextHive(PCHAR ChunkBase,
499 HANDLE currentKey = INVALID_HANDLE_VALUE;
501 UNICODE_STRING newKeyName = {0, 0, 0};
502 char dataFormat [10];
505 int dataBufferSize = 0;
509 DPRINT("ChunkBase %p ChunkSize %lx\n", ChunkBase, ChunkSize);
511 regChunk = checkAndSkipMagic (ChunkBase);
515 while (regChunk != 0 && *regChunk != 0 && (((ULONG)regChunk-(ULONG)ChunkBase) < ChunkSize))
517 regChunk = skipWhitespaceInChunk (regChunk);
521 if (*regChunk == '[')
523 if (currentKey != INVALID_HANDLE_VALUE)
525 DPRINT("Closing current key: 0x%lx\n", currentKey);
526 NtClose (currentKey);
527 currentKey = INVALID_HANDLE_VALUE;
532 newKeySize = computeKeyNameSize (regChunk);
533 if (!allocateKeyName (&newKeyName, newKeySize))
539 regChunk = getKeyNameFromChunk (regChunk, &newKeyName);
543 currentKey = createNewKey (&newKeyName);
544 if (currentKey == INVALID_HANDLE_VALUE)
546 regChunk = skipToNextKeyInChunk (regChunk);
554 if (currentKey == INVALID_HANDLE_VALUE)
556 regChunk = skipToNextKeyInChunk (regChunk);
560 newKeySize = computeKeyValueNameSize (regChunk);
561 if (!allocateKeyName (&newKeyName, newKeySize))
567 regChunk = getKeyValueNameFromChunk (regChunk, &newKeyName);
571 if (*regChunk != '=')
573 regChunk = skipToNextKeyValueInChunk (regChunk);
578 regChunk = getKeyValueTypeFromChunk (regChunk, dataFormat, &keyValueType);
582 dataSize = computeKeyValueDataSize (regChunk, dataFormat);
583 if (!allocateDataBuffer (&data, &dataBufferSize, dataSize))
589 regChunk = getKeyValueDataFromChunk (regChunk, dataFormat, data);
593 if (!setKeyValue (currentKey, &newKeyName, keyValueType, data, dataSize))
601 if (currentKey != INVALID_HANDLE_VALUE)
603 NtClose (currentKey);
605 if (newKeyName.Buffer != 0)
607 ExFreePool (newKeyName.Buffer);
619 CmImportBinaryHive (PCHAR ChunkBase,
622 PREGISTRY_HIVE *RegistryHive)
625 PCELL_HEADER FreeBlock;
626 BLOCK_OFFSET BlockOffset;
633 *RegistryHive = NULL;
635 if (strncmp (ChunkBase, "regf", 4) != 0)
637 DPRINT1 ("Found invalid '%*s' magic\n", 4, ChunkBase);
641 /* Create a new hive */
642 Hive = ExAllocatePool (NonPagedPool,
643 sizeof(REGISTRY_HIVE));
649 sizeof(REGISTRY_HIVE));
654 /* Allocate hive header */
655 Hive->HiveHeader = (PHIVE_HEADER)ExAllocatePool (NonPagedPool,
656 sizeof(HIVE_HEADER));
657 if (Hive->HiveHeader == NULL)
659 DPRINT1 ("Allocating hive header failed\n");
664 /* Import the hive header */
665 RtlCopyMemory (Hive->HiveHeader,
667 sizeof(HIVE_HEADER));
669 /* Read update counter */
670 Hive->UpdateCounter = Hive->HiveHeader->UpdateCounter1;
672 /* Set the hive's size */
673 Hive->FileSize = ChunkSize;
675 /* Set the size of the block list */
676 Hive->BlockListSize = (Hive->FileSize / 4096) - 1;
678 /* Allocate block list */
679 DPRINT("Space needed for block list describing hive: 0x%x\n",
680 sizeof(PHBIN *) * Hive->BlockListSize);
681 Hive->BlockList = ExAllocatePool (NonPagedPool,
682 sizeof(PHBIN *) * Hive->BlockListSize);
683 if (Hive->BlockList == NULL)
685 DPRINT1 ("Allocating block list failed\n");
686 ExFreePool (Hive->HiveHeader);
691 /* Allocate the hive block */
692 Hive->BlockList[0] = ExAllocatePool (PagedPool,
693 Hive->FileSize - 4096);
694 if (Hive->BlockList[0] == NULL)
696 DPRINT1 ("Allocating the first hive block failed\n");
697 ExFreePool (Hive->BlockList);
698 ExFreePool (Hive->HiveHeader);
703 /* Import the hive block */
704 RtlCopyMemory (Hive->BlockList[0],
706 Hive->FileSize - 4096);
708 /* Initialize the free block list */
709 Hive->FreeListSize = 0;
710 Hive->FreeListMax = 0;
711 Hive->FreeList = NULL;
714 for (i = 0; i < Hive->BlockListSize; i++)
716 Hive->BlockList[i] = (PHBIN) (((ULONG_PTR)Hive->BlockList[0]) + BlockOffset);
717 Bin = (PHBIN) (((ULONG_PTR)Hive->BlockList[i]));
718 if (Bin->BlockId != REG_BIN_ID)
720 DPRINT1 ("Bad BlockId %x, offset %x\n", Bin->BlockId, BlockOffset);
723 // return STATUS_INSUFFICIENT_RESOURCES;
726 assertmsg((Bin->BlockSize % 4096) == 0, ("BlockSize (0x%.08x) must be multiplum of 4K\n", Bin->BlockSize));
728 if (Bin->BlockSize > 4096)
730 for (j = 1; j < Bin->BlockSize / 4096; j++)
732 Hive->BlockList[i + j] = Hive->BlockList[i];
737 /* Search free blocks and add to list */
738 FreeOffset = REG_HBIN_DATA_OFFSET;
739 while (FreeOffset < Bin->BlockSize)
741 FreeBlock = (PCELL_HEADER) ((ULONG_PTR)Hive->BlockList[i] + FreeOffset);
742 if (FreeBlock->CellSize > 0)
744 Status = CmiAddFree(Hive,
746 Hive->BlockList[i]->BlockOffset + FreeOffset,
748 if (!NT_SUCCESS(Status))
754 FreeOffset += FreeBlock->CellSize;
758 FreeOffset -= FreeBlock->CellSize;
761 BlockOffset += Bin->BlockSize;
764 if (!(Hive->Flags & HIVE_VOLATILE))
766 /* Calculate bitmap size in bytes (always a multiple of 32 bits) */
767 BitmapSize = ROUND_UP (Hive->BlockListSize, sizeof(ULONG) * 8) / 8;
768 DPRINT ("Hive->BlockListSize: %lu\n", Hive->BlockListSize);
769 DPRINT ("BitmapSize: %lu Bytes %lu Bits\n", BitmapSize, BitmapSize * 8);
771 /* Allocate bitmap */
772 Hive->BitmapBuffer = (PULONG)ExAllocatePool (PagedPool,
774 if (Hive->BitmapBuffer == NULL)
776 DPRINT1 ("Allocating the hive bitmap failed\n");
777 ExFreePool (Hive->BlockList[0]);
778 ExFreePool (Hive->BlockList);
779 ExFreePool (Hive->HiveHeader);
784 /* Initialize bitmap */
785 RtlInitializeBitMap (&Hive->DirtyBitMap,
788 RtlClearAllBits (&Hive->DirtyBitMap);
789 Hive->HiveDirty = FALSE;
792 /* Initialize the hive's executive resource */
793 ExInitializeResourceLite(&Hive->HiveResource);
795 /* Acquire hive list lock exclusively */
796 ExAcquireResourceExclusiveLite(&CmiHiveListLock, TRUE);
798 /* Add the new hive to the hive list */
799 InsertTailList(&CmiHiveListHead, &Hive->HiveList);
801 /* Release hive list lock */
802 ExReleaseResourceLite(&CmiHiveListLock);
804 *RegistryHive = Hive;
811 CmImportSystemHive(PCHAR ChunkBase,
814 PREGISTRY_HIVE RegistryHive;
815 UNICODE_STRING KeyName;
818 DPRINT ("CmImportSystemHive() called\n");
820 if (strncmp (ChunkBase, "REGEDIT4", 8) == 0)
822 DPRINT ("Found 'REGEDIT4' magic\n");
823 CmImportTextHive (ChunkBase, ChunkSize);
826 else if (strncmp (ChunkBase, "regf", 4) != 0)
828 DPRINT1 ("Found invalid '%.*s' magic\n", 4, ChunkBase);
832 DPRINT ("Found '%.*s' magic\n", 4, ChunkBase);
834 /* Import the binary system hive (non-volatile, offset-based, permanent) */
835 if (!CmImportBinaryHive (ChunkBase, ChunkSize, 0, &RegistryHive))
837 DPRINT1 ("CmiImportBinaryHive() failed\n", Status);
841 /* Attach it to the machine key */
842 RtlInitUnicodeString (&KeyName,
843 L"\\Registry\\Machine\\System");
844 Status = CmiConnectHive (RegistryHive,
846 if (!NT_SUCCESS(Status))
848 DPRINT1 ("CmiConnectHive() failed (Status %lx)\n", Status);
849 // CmiRemoveRegistryHive(RegistryHive);
853 /* Set the hive filename */
854 RtlCreateUnicodeString (&RegistryHive->HiveFileName,
857 /* Set the log filename */
858 RtlCreateUnicodeString (&RegistryHive->LogFileName,
866 CmImportHardwareHive(PCHAR ChunkBase,
869 PREGISTRY_HIVE RegistryHive;
870 OBJECT_ATTRIBUTES ObjectAttributes;
871 UNICODE_STRING KeyName;
876 DPRINT ("CmImportHardwareHive() called\n");
878 if (CmiHardwareHiveImported == TRUE)
881 if (ChunkBase == NULL &&
884 /* Create '\Registry\Machine\HARDWARE' key. */
885 RtlInitUnicodeString(&KeyName,
886 L"\\Registry\\Machine\\HARDWARE");
887 InitializeObjectAttributes (&ObjectAttributes,
892 Status = NtCreateKey (&HardwareKey,
899 if (!NT_SUCCESS(Status))
903 NtClose (HardwareKey);
905 /* Create '\Registry\Machine\HARDWARE\DESCRIPTION' key. */
906 RtlInitUnicodeString(&KeyName,
907 L"\\Registry\\Machine\\HARDWARE\\DESCRIPTION");
908 InitializeObjectAttributes (&ObjectAttributes,
913 Status = NtCreateKey (&HardwareKey,
920 if (!NT_SUCCESS(Status))
924 NtClose (HardwareKey);
926 /* Create '\Registry\Machine\HARDWARE\DEVICEMAP' key. */
927 RtlInitUnicodeString(&KeyName,
928 L"\\Registry\\Machine\\HARDWARE\\DEVICEMAP");
929 InitializeObjectAttributes (&ObjectAttributes,
934 Status = NtCreateKey (&HardwareKey,
941 if (!NT_SUCCESS(Status))
945 NtClose (HardwareKey);
947 /* Create '\Registry\Machine\HARDWARE\RESOURCEMAP' key. */
948 RtlInitUnicodeString(&KeyName,
949 L"\\Registry\\Machine\\HARDWARE\\RESOURCEMAP");
950 InitializeObjectAttributes (&ObjectAttributes,
955 Status = NtCreateKey (&HardwareKey,
962 if (!NT_SUCCESS(Status))
966 NtClose (HardwareKey);
971 if (strncmp (ChunkBase, "regf", 4) != 0)
973 DPRINT1 ("Found invalid '%.*s' magic\n", 4, ChunkBase);
977 DPRINT ("Found '%.*s' magic\n", 4, ChunkBase);
978 DPRINT ("ChunkBase %lx ChunkSize %lu\n", ChunkBase, ChunkSize);
980 /* Import the binary system hive (volatile, offset-based, permanent) */
981 if (!CmImportBinaryHive (ChunkBase, ChunkSize, HIVE_VOLATILE, &RegistryHive))
983 DPRINT1 ("CmiImportBinaryHive() failed\n", Status);
987 /* Attach it to the machine key */
988 RtlInitUnicodeString (&KeyName,
989 L"\\Registry\\Machine\\HARDWARE");
990 Status = CmiConnectHive (RegistryHive,
992 if (!NT_SUCCESS(Status))
994 DPRINT1 ("CmiConnectHive() failed (Status %lx)\n", Status);
995 // CmiRemoveRegistryHive(RegistryHive);
999 /* Set the hive filename */
1000 RtlInitUnicodeString (&RegistryHive->HiveFileName,
1003 /* Set the log filename */
1004 RtlInitUnicodeString (&RegistryHive->LogFileName,
1007 CmiHardwareHiveImported = TRUE;