mirror of
https://github.com/reactos/reactos.git
synced 2025-08-06 18:53:33 +00:00
578 lines
12 KiB
C
578 lines
12 KiB
C
/* $Id: import.c,v 1.5 2002/04/27 19:00:14 ekohl Exp $
|
|
*
|
|
* COPYRIGHT: See COPYING in the top level directory
|
|
* PROJECT: ReactOS kernel
|
|
* FILE: ntoskrnl/cm/import.c
|
|
* PURPOSE: Registry functions
|
|
* PROGRAMMERS: Rex Jolliff
|
|
*/
|
|
|
|
#include <ctype.h>
|
|
|
|
#include <ddk/ntddk.h>
|
|
#include <roscfg.h>
|
|
#include <internal/ob.h>
|
|
#include <limits.h>
|
|
#include <string.h>
|
|
#include <internal/pool.h>
|
|
#include <internal/registry.h>
|
|
|
|
#define NDEBUG
|
|
#include <internal/debug.h>
|
|
|
|
#include "cm.h"
|
|
|
|
static PCHAR
|
|
checkAndSkipMagic (PCHAR regChunk)
|
|
{
|
|
if (strncmp (regChunk,
|
|
REGISTRY_FILE_MAGIC,
|
|
strlen (REGISTRY_FILE_MAGIC)) != 0)
|
|
{
|
|
CPRINT ("incorrect magic number in registry chunk. expected: %s got:%.*s\n",
|
|
REGISTRY_FILE_MAGIC,
|
|
strlen (REGISTRY_FILE_MAGIC),
|
|
regChunk);
|
|
return 0;
|
|
}
|
|
regChunk += strlen (REGISTRY_FILE_MAGIC);
|
|
DPRINT ("Found regsitry chunk magic value\n");
|
|
|
|
return regChunk;
|
|
}
|
|
|
|
static PCHAR
|
|
skipWhitespaceInChunk (PCHAR regChunk)
|
|
{
|
|
while (*regChunk && isspace (*regChunk))
|
|
regChunk++;
|
|
|
|
return *regChunk ? regChunk : 0;
|
|
}
|
|
|
|
static int
|
|
computeKeyNameSize (PCHAR regChunk)
|
|
{
|
|
int copyCount = 0;
|
|
|
|
while (*regChunk != 0 && *regChunk != ']')
|
|
{
|
|
copyCount++;
|
|
regChunk++;
|
|
}
|
|
|
|
return copyCount;
|
|
}
|
|
|
|
static BOOLEAN
|
|
allocateKeyName (PUNICODE_STRING newKeyName, int newKeySize)
|
|
{
|
|
if (newKeyName->MaximumLength < (newKeySize + 1) * sizeof (WCHAR))
|
|
{
|
|
if (newKeyName->Buffer != 0)
|
|
ExFreePool (newKeyName->Buffer);
|
|
newKeyName->Length = 0;
|
|
newKeyName->MaximumLength = (newKeySize + 1) * sizeof (WCHAR);
|
|
newKeyName->Buffer = ExAllocatePool (NonPagedPool, newKeyName->MaximumLength);
|
|
if (newKeyName->Buffer == 0)
|
|
{
|
|
CPRINT ("Could not allocate space for key name\n");
|
|
return FALSE;
|
|
}
|
|
newKeyName->Buffer [0] = 0;
|
|
}
|
|
else
|
|
{
|
|
newKeyName->Length = 0;
|
|
newKeyName->Buffer [0] = 0;
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
static PCHAR
|
|
skipToNextKeyInChunk (PCHAR regChunk)
|
|
{
|
|
while (*regChunk != 0 && *regChunk != '[')
|
|
{
|
|
while (*regChunk != 0 && *regChunk != '\n')
|
|
{
|
|
regChunk++;
|
|
}
|
|
regChunk++;
|
|
}
|
|
|
|
return *regChunk ? regChunk : 0;
|
|
}
|
|
|
|
static PCHAR
|
|
getKeyNameFromChunk (PCHAR regChunk, PUNICODE_STRING newKeyName)
|
|
{
|
|
int index = 0;
|
|
|
|
while (*regChunk != 0 && *regChunk != ']')
|
|
{
|
|
newKeyName->Buffer [index++] = *regChunk++;
|
|
}
|
|
newKeyName->Buffer [index] = '\0';
|
|
newKeyName->Length = index * sizeof (WCHAR);
|
|
|
|
return *regChunk ? regChunk : 0;
|
|
}
|
|
|
|
static HANDLE
|
|
createNewKey (PUNICODE_STRING newKeyName)
|
|
{
|
|
NTSTATUS status;
|
|
OBJECT_ATTRIBUTES attributes;
|
|
HANDLE handleToReturn;
|
|
|
|
DPRINT ("Creating key (%wZ)\n", newKeyName);
|
|
InitializeObjectAttributes (&attributes,
|
|
newKeyName,
|
|
0,
|
|
0,
|
|
NULL);
|
|
status = NtCreateKey (&handleToReturn,
|
|
KEY_ALL_ACCESS,
|
|
&attributes,
|
|
0,
|
|
NULL,
|
|
REG_OPTION_VOLATILE,
|
|
NULL);
|
|
if (!NT_SUCCESS(status))
|
|
{
|
|
CPRINT ("Could not crete key (%wZ)\n", newKeyName);
|
|
return INVALID_HANDLE_VALUE;
|
|
}
|
|
|
|
return handleToReturn;
|
|
}
|
|
|
|
static PCHAR
|
|
skipToNextKeyValueInChunk (PCHAR regChunk)
|
|
{
|
|
while (*regChunk != 0 && *regChunk != '\n')
|
|
regChunk++;
|
|
regChunk = skipWhitespaceInChunk (regChunk);
|
|
|
|
return regChunk;
|
|
}
|
|
|
|
static int
|
|
computeKeyValueNameSize (PCHAR regChunk)
|
|
{
|
|
int size = 0;
|
|
|
|
if (*regChunk != '\"')
|
|
return 0;
|
|
regChunk++;
|
|
while (*regChunk != 0 && *regChunk != '\"')
|
|
{
|
|
size++;
|
|
regChunk++;
|
|
}
|
|
|
|
return regChunk ? size : 0;
|
|
}
|
|
|
|
static PCHAR
|
|
getKeyValueNameFromChunk (PCHAR regChunk, PUNICODE_STRING newKeyName)
|
|
{
|
|
int index = 0;
|
|
|
|
regChunk++;
|
|
while (*regChunk != 0 && *regChunk != '\"')
|
|
{
|
|
newKeyName->Buffer [index++] = *regChunk++;
|
|
}
|
|
newKeyName->Buffer [index] = '\0';
|
|
newKeyName->Length = index * sizeof (WCHAR);
|
|
regChunk++;
|
|
|
|
return *regChunk ? regChunk : 0;
|
|
}
|
|
|
|
static PCHAR
|
|
getKeyValueTypeFromChunk (PCHAR regChunk, PCHAR dataFormat, int *keyValueType)
|
|
{
|
|
if (*regChunk == '\"')
|
|
{
|
|
strcpy (dataFormat, "string");
|
|
*keyValueType = REG_SZ;
|
|
}
|
|
else if (strncmp (regChunk, "hex", 3) == 0)
|
|
{
|
|
strcpy (dataFormat, "hex");
|
|
regChunk += 3;
|
|
if (*regChunk == '(')
|
|
{
|
|
regChunk++;
|
|
*keyValueType = atoi (regChunk);
|
|
while (*regChunk != 0 && *regChunk != ')')
|
|
regChunk++;
|
|
regChunk++;
|
|
}
|
|
else
|
|
*keyValueType = REG_BINARY;
|
|
if (*regChunk == ':')
|
|
regChunk++;
|
|
}
|
|
else if (strncmp (regChunk, "dword", 5) == 0)
|
|
{
|
|
strcpy (dataFormat, "dword");
|
|
*keyValueType = REG_DWORD;
|
|
regChunk += 5;
|
|
if (*regChunk == ':')
|
|
regChunk++;
|
|
}
|
|
else if (strncmp (regChunk, "multi", 5) == 0)
|
|
{
|
|
strcpy (dataFormat, "multi");
|
|
*keyValueType = REG_MULTI_SZ;
|
|
regChunk += 5;
|
|
if (*regChunk == ':')
|
|
regChunk++;
|
|
}
|
|
else
|
|
{
|
|
UNIMPLEMENTED;
|
|
}
|
|
|
|
return *regChunk ? regChunk : 0;
|
|
}
|
|
|
|
static int
|
|
computeKeyValueDataSize (PCHAR regChunk, PCHAR dataFormat)
|
|
{
|
|
int dataSize = 0;
|
|
|
|
if (strcmp (dataFormat, "string") == 0)
|
|
{
|
|
regChunk++;
|
|
while (*regChunk != 0 && *regChunk != '\"')
|
|
{
|
|
dataSize++;
|
|
dataSize++;
|
|
regChunk++;
|
|
}
|
|
dataSize++;
|
|
dataSize++;
|
|
}
|
|
else if (strcmp (dataFormat, "hex") == 0)
|
|
{
|
|
while (*regChunk != 0 && isxdigit(*regChunk))
|
|
{
|
|
regChunk++;
|
|
regChunk++;
|
|
dataSize++;
|
|
if (*regChunk == ',')
|
|
{
|
|
regChunk++;
|
|
if (*regChunk == '\\')
|
|
{
|
|
regChunk++;
|
|
regChunk = skipWhitespaceInChunk (regChunk);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else if (strcmp (dataFormat, "dword") == 0)
|
|
{
|
|
dataSize = sizeof(DWORD);
|
|
while (*regChunk != 0 && isxdigit(*regChunk))
|
|
{
|
|
regChunk++;
|
|
}
|
|
}
|
|
else if (strcmp (dataFormat, "multi") == 0)
|
|
{
|
|
while (*regChunk == '\"')
|
|
{
|
|
regChunk++;
|
|
while (*regChunk != 0 && *regChunk != '\"')
|
|
{
|
|
dataSize++;
|
|
dataSize++;
|
|
regChunk++;
|
|
}
|
|
regChunk++;
|
|
dataSize++;
|
|
dataSize++;
|
|
if (*regChunk == ',')
|
|
{
|
|
regChunk++;
|
|
regChunk = skipWhitespaceInChunk (regChunk);
|
|
if (*regChunk == '\\')
|
|
{
|
|
regChunk++;
|
|
regChunk = skipWhitespaceInChunk (regChunk);
|
|
}
|
|
}
|
|
else
|
|
break;
|
|
}
|
|
dataSize++;
|
|
dataSize++;
|
|
}
|
|
else
|
|
{
|
|
UNIMPLEMENTED;
|
|
}
|
|
|
|
return dataSize;
|
|
}
|
|
|
|
static BOOLEAN
|
|
allocateDataBuffer (PVOID * data, int * dataBufferSize, int dataSize)
|
|
{
|
|
if (*dataBufferSize < dataSize)
|
|
{
|
|
if (*dataBufferSize > 0)
|
|
ExFreePool (*data);
|
|
*data = ExAllocatePool (NonPagedPool, dataSize);
|
|
*dataBufferSize = dataSize;
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
static PCHAR
|
|
getKeyValueDataFromChunk (PCHAR regChunk, PCHAR dataFormat, PCHAR data)
|
|
{
|
|
char dataValue;
|
|
ULONG ulValue;
|
|
PWCHAR ptr;
|
|
|
|
if (strcmp (dataFormat, "string") == 0)
|
|
{
|
|
/* convert quoted string to zero-terminated Unicode string */
|
|
ptr = (PWCHAR)data;
|
|
regChunk++;
|
|
while (*regChunk != 0 && *regChunk != '\"')
|
|
{
|
|
*ptr++ = (WCHAR)*regChunk++;
|
|
}
|
|
*ptr = 0;
|
|
regChunk++;
|
|
}
|
|
else if (strcmp (dataFormat, "hex") == 0)
|
|
{
|
|
while (*regChunk != 0 && isxdigit (*regChunk))
|
|
{
|
|
dataValue = (isdigit (*regChunk) ? *regChunk - '0' :
|
|
tolower(*regChunk) - 'a') << 4;
|
|
regChunk++;
|
|
dataValue += (isdigit (*regChunk) ? *regChunk - '0' :
|
|
tolower(*regChunk) - 'a');
|
|
regChunk++;
|
|
*data++ = dataValue;
|
|
if (*regChunk == ',')
|
|
{
|
|
regChunk++;
|
|
if (*regChunk == '\\')
|
|
{
|
|
regChunk++;
|
|
regChunk = skipWhitespaceInChunk (regChunk);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else if (strcmp (dataFormat, "dword") == 0)
|
|
{
|
|
ulValue = 0;
|
|
while (*regChunk != 0 && isxdigit(*regChunk))
|
|
{
|
|
dataValue = (isdigit (*regChunk) ? *regChunk - '0' :
|
|
tolower(*regChunk) - 'a');
|
|
ulValue = (ulValue << 4) + dataValue;
|
|
regChunk++;
|
|
}
|
|
memcpy(data, &ulValue, sizeof(ULONG));
|
|
}
|
|
else if (strcmp (dataFormat, "multi") == 0)
|
|
{
|
|
ptr = (PWCHAR)data;
|
|
while (*regChunk == '\"')
|
|
{
|
|
regChunk++;
|
|
while (*regChunk != 0 && *regChunk != '\"')
|
|
{
|
|
*ptr++ = (WCHAR)*regChunk++;
|
|
}
|
|
regChunk++;
|
|
*ptr++ = 0;
|
|
if (*regChunk == ',')
|
|
{
|
|
regChunk++;
|
|
regChunk = skipWhitespaceInChunk (regChunk);
|
|
if (*regChunk == '\\')
|
|
{
|
|
regChunk++;
|
|
regChunk = skipWhitespaceInChunk (regChunk);
|
|
}
|
|
}
|
|
else
|
|
break;
|
|
}
|
|
*ptr = 0;
|
|
}
|
|
else
|
|
{
|
|
UNIMPLEMENTED;
|
|
}
|
|
|
|
return *regChunk ? regChunk : 0;
|
|
}
|
|
|
|
static BOOLEAN
|
|
setKeyValue (HANDLE currentKey,
|
|
PUNICODE_STRING newValueName,
|
|
ULONG keyValueType,
|
|
PVOID data,
|
|
ULONG dataSize)
|
|
{
|
|
NTSTATUS status;
|
|
|
|
DPRINT ("Adding value (%wZ) to current key, with data type %d size %d\n",
|
|
newValueName,
|
|
keyValueType,
|
|
dataSize);
|
|
status = NtSetValueKey (currentKey,
|
|
newValueName,
|
|
0,
|
|
keyValueType,
|
|
data,
|
|
dataSize);
|
|
if (!NT_SUCCESS(status))
|
|
{
|
|
CPRINT ("could not set key value, rc:%08x\n", status);
|
|
return FALSE;
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
VOID
|
|
CmImportHive(PCHAR ChunkBase,
|
|
ULONG ChunkSize)
|
|
{
|
|
HANDLE currentKey = INVALID_HANDLE_VALUE;
|
|
int newKeySize;
|
|
UNICODE_STRING newKeyName = {0, 0, 0};
|
|
char dataFormat [10];
|
|
int keyValueType;
|
|
int dataSize = 0;
|
|
int dataBufferSize = 0;
|
|
PVOID data = 0;
|
|
PCHAR regChunk;
|
|
|
|
DPRINT("ChunkBase %p ChunkSize %lx\n", ChunkBase, ChunkSize);
|
|
|
|
regChunk = checkAndSkipMagic (ChunkBase);
|
|
if (regChunk == 0)
|
|
return;
|
|
|
|
while (regChunk != 0 && *regChunk != 0 && (((ULONG)regChunk-(ULONG)ChunkBase) < ChunkSize))
|
|
{
|
|
regChunk = skipWhitespaceInChunk (regChunk);
|
|
if (regChunk == 0)
|
|
continue;
|
|
|
|
if (*regChunk == '[')
|
|
{
|
|
if (currentKey != INVALID_HANDLE_VALUE)
|
|
{
|
|
DPRINT("Closing current key: 0x%lx\n", currentKey);
|
|
NtClose (currentKey);
|
|
currentKey = INVALID_HANDLE_VALUE;
|
|
}
|
|
|
|
regChunk++;
|
|
|
|
newKeySize = computeKeyNameSize (regChunk);
|
|
if (!allocateKeyName (&newKeyName, newKeySize))
|
|
{
|
|
regChunk = 0;
|
|
continue;
|
|
}
|
|
|
|
regChunk = getKeyNameFromChunk (regChunk, &newKeyName);
|
|
if (regChunk == 0)
|
|
continue;
|
|
|
|
currentKey = createNewKey (&newKeyName);
|
|
if (currentKey == INVALID_HANDLE_VALUE)
|
|
{
|
|
regChunk = skipToNextKeyInChunk (regChunk);
|
|
continue;
|
|
}
|
|
|
|
regChunk++;
|
|
}
|
|
else
|
|
{
|
|
if (currentKey == INVALID_HANDLE_VALUE)
|
|
{
|
|
regChunk = skipToNextKeyInChunk (regChunk);
|
|
continue;
|
|
}
|
|
|
|
newKeySize = computeKeyValueNameSize (regChunk);
|
|
if (!allocateKeyName (&newKeyName, newKeySize))
|
|
{
|
|
regChunk = 0;
|
|
continue;
|
|
}
|
|
|
|
regChunk = getKeyValueNameFromChunk (regChunk, &newKeyName);
|
|
if (regChunk == 0)
|
|
continue;
|
|
|
|
if (*regChunk != '=')
|
|
{
|
|
regChunk = skipToNextKeyValueInChunk (regChunk);
|
|
continue;
|
|
}
|
|
regChunk++;
|
|
|
|
regChunk = getKeyValueTypeFromChunk (regChunk, dataFormat, &keyValueType);
|
|
if (regChunk == 0)
|
|
continue;
|
|
|
|
dataSize = computeKeyValueDataSize (regChunk, dataFormat);
|
|
if (!allocateDataBuffer (&data, &dataBufferSize, dataSize))
|
|
{
|
|
regChunk = 0;
|
|
continue;
|
|
}
|
|
|
|
regChunk = getKeyValueDataFromChunk (regChunk, dataFormat, data);
|
|
if (regChunk == 0)
|
|
continue;
|
|
|
|
if (!setKeyValue (currentKey, &newKeyName, keyValueType, data, dataSize))
|
|
{
|
|
regChunk = 0;
|
|
continue;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (currentKey != INVALID_HANDLE_VALUE)
|
|
{
|
|
NtClose (currentKey);
|
|
}
|
|
if (newKeyName.Buffer != 0)
|
|
{
|
|
ExFreePool (newKeyName.Buffer);
|
|
}
|
|
if (data != 0)
|
|
{
|
|
ExFreePool (data);
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
|