reactos/reactos/tools/mkhive/registry.c
Jérôme Gardou d01ad886a0 [MKHIVE]
- Perform a case insensitive comparison to find existing subkeys in the tree.
Dedicated to Hervé ;-)

svn path=/trunk/; revision=64516
2014-10-03 22:19:07 +00:00

707 lines
15 KiB
C

/*
* ReactOS kernel
* Copyright (C) 2006 ReactOS Team
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
/* COPYRIGHT: See COPYING in the top level directory
* PROJECT: ReactOS hive maker
* FILE: tools/mkhive/registry.c
* PURPOSE: Registry code
* PROGRAMMER: Hervé Poussineau
*/
/*
* TODO:
* - Implement RegDeleteKeyW()
* - Implement RegEnumValue()
* - Implement RegQueryValueExW()
*/
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#define NDEBUG
#include "mkhive.h"
#define REG_DATA_SIZE_MASK 0x7FFFFFFF
#define REG_DATA_IN_OFFSET 0x80000000
static CMHIVE RootHive;
static MEMKEY RootKey;
CMHIVE DefaultHive; /* \Registry\User\.DEFAULT */
CMHIVE SamHive; /* \Registry\Machine\SAM */
CMHIVE SecurityHive; /* \Registry\Machine\SECURITY */
CMHIVE SoftwareHive; /* \Registry\Machine\SOFTWARE */
CMHIVE SystemHive; /* \Registry\Machine\SYSTEM */
static MEMKEY
CreateInMemoryStructure(
IN PCMHIVE RegistryHive,
IN HCELL_INDEX KeyCellOffset,
IN PCUNICODE_STRING KeyName)
{
MEMKEY Key;
Key = (MEMKEY) malloc (sizeof(KEY));
if (!Key)
return NULL;
InitializeListHead (&Key->SubKeyList);
InitializeListHead (&Key->ValueList);
InitializeListHead (&Key->KeyList);
Key->SubKeyCount = 0;
Key->ValueCount = 0;
Key->NameSize = KeyName->Length;
/* FIXME: It's not enough to allocate this way, because later
this memory gets overwritten with bigger names */
Key->Name = malloc (Key->NameSize);
if (!Key->Name)
return NULL;
memcpy(Key->Name, KeyName->Buffer, KeyName->Length);
Key->DataType = 0;
Key->DataSize = 0;
Key->Data = NULL;
Key->RegistryHive = RegistryHive;
Key->KeyCellOffset = KeyCellOffset;
Key->KeyCell = (PCM_KEY_NODE)HvGetCell (&RegistryHive->Hive, Key->KeyCellOffset);
if (!Key->KeyCell)
{
free(Key->Name);
free(Key);
return NULL;
}
Key->KeyCell->SubKeyLists[Stable] = HCELL_NIL;
Key->KeyCell->SubKeyLists[Volatile] = HCELL_NIL;
Key->LinkedKey = NULL;
return Key;
}
static LONG
RegpOpenOrCreateKey(
IN HKEY hParentKey,
IN PCWSTR KeyName,
IN BOOL AllowCreation,
OUT PHKEY Key)
{
PWSTR LocalKeyName;
PWSTR End;
UNICODE_STRING KeyString;
NTSTATUS Status;
MEMKEY ParentKey;
MEMKEY CurrentKey;
PLIST_ENTRY Ptr;
PCM_KEY_NODE SubKeyCell;
HCELL_INDEX BlockOffset;
DPRINT("RegpCreateOpenKey('%S')\n", KeyName);
if (*KeyName == L'\\')
{
KeyName++;
ParentKey = RootKey;
}
else if (hParentKey == NULL)
{
ParentKey = RootKey;
}
else
{
ParentKey = HKEY_TO_MEMKEY(RootKey);
}
LocalKeyName = (PWSTR)KeyName;
for (;;)
{
End = (PWSTR)strchrW(LocalKeyName, '\\');
if (End)
{
KeyString.Buffer = LocalKeyName;
KeyString.Length = KeyString.MaximumLength =
(USHORT)((ULONG_PTR)End - (ULONG_PTR)LocalKeyName);
}
else
{
RtlInitUnicodeString(&KeyString, LocalKeyName);
if (KeyString.Length == 0)
{
/* Trailing backslash char; we're done */
break;
}
}
/* Redirect from 'CurrentControlSet' to 'ControlSet001' */
if (!strncmpW(LocalKeyName, L"CurrentControlSet", 17) &&
ParentKey->NameSize == 12 &&
!memcmp(ParentKey->Name, L"SYSTEM", 12))
RtlInitUnicodeString(&KeyString, L"ControlSet001");
/* Check subkey in memory structure */
Ptr = ParentKey->SubKeyList.Flink;
while (Ptr != &ParentKey->SubKeyList)
{
CurrentKey = CONTAINING_RECORD(Ptr, KEY, KeyList);
if (CurrentKey->NameSize == KeyString.Length
&& strncmpiW(CurrentKey->Name, KeyString.Buffer, KeyString.Length / sizeof(WCHAR)) == 0)
{
goto nextsubkey;
}
Ptr = Ptr->Flink;
}
Status = CmiScanForSubKey(
ParentKey->RegistryHive,
ParentKey->KeyCell,
&KeyString,
OBJ_CASE_INSENSITIVE,
&SubKeyCell,
&BlockOffset);
if (AllowCreation && Status == STATUS_OBJECT_NAME_NOT_FOUND)
{
Status = CmiAddSubKey(
ParentKey->RegistryHive,
ParentKey->KeyCell,
ParentKey->KeyCellOffset,
&KeyString,
0,
&SubKeyCell,
&BlockOffset);
}
if (!NT_SUCCESS(Status))
return ERROR_UNSUCCESSFUL;
/* Now, SubKeyCell/BlockOffset are valid */
CurrentKey = CreateInMemoryStructure(
ParentKey->RegistryHive,
BlockOffset,
&KeyString);
if (!CurrentKey)
return ERROR_OUTOFMEMORY;
/* Add CurrentKey in ParentKey */
InsertTailList(&ParentKey->SubKeyList, &CurrentKey->KeyList);
ParentKey->SubKeyCount++;
nextsubkey:
ParentKey = CurrentKey;
if (End)
LocalKeyName = End + 1;
else
break;
}
*Key = MEMKEY_TO_HKEY(ParentKey);
return ERROR_SUCCESS;
}
LONG WINAPI
RegCreateKeyW(
IN HKEY hKey,
IN LPCWSTR lpSubKey,
OUT PHKEY phkResult)
{
return RegpOpenOrCreateKey(hKey, lpSubKey, TRUE, phkResult);
}
static PWSTR
MultiByteToWideChar(
IN PCSTR MultiByteString)
{
ANSI_STRING Source;
UNICODE_STRING Destination;
NTSTATUS Status;
RtlInitAnsiString(&Source, MultiByteString);
Status = RtlAnsiStringToUnicodeString(&Destination, &Source, TRUE);
if (!NT_SUCCESS(Status))
return NULL;
return Destination.Buffer;
}
LONG WINAPI
RegCreateKeyA(
IN HKEY hKey,
IN LPCSTR lpSubKey,
OUT PHKEY phkResult)
{
PWSTR lpSubKeyW;
LONG rc;
lpSubKeyW = MultiByteToWideChar(lpSubKey);
if (!lpSubKeyW)
return ERROR_OUTOFMEMORY;
rc = RegCreateKeyW(hKey, lpSubKeyW, phkResult);
free(lpSubKeyW);
return rc;
}
LONG WINAPI
RegDeleteKeyW(
IN HKEY hKey,
IN LPCWSTR lpSubKey)
{
DPRINT1("FIXME: implement RegDeleteKeyW!\n");
return ERROR_SUCCESS;
}
LONG WINAPI
RegDeleteKeyA(
IN HKEY hKey,
IN LPCSTR lpSubKey)
{
PWSTR lpSubKeyW = NULL;
LONG rc;
if (lpSubKey != NULL && strchr(lpSubKey, '\\') != NULL)
return ERROR_INVALID_PARAMETER;
if (lpSubKey)
{
lpSubKeyW = MultiByteToWideChar(lpSubKey);
if (!lpSubKeyW)
return ERROR_OUTOFMEMORY;
}
rc = RegDeleteKeyW(hKey, lpSubKeyW);
if (lpSubKey)
free(lpSubKeyW);
return rc;
}
LONG WINAPI
RegOpenKeyW(
IN HKEY hKey,
IN LPCWSTR lpSubKey,
OUT PHKEY phkResult)
{
return RegpOpenOrCreateKey(hKey, lpSubKey, FALSE, phkResult);
}
LONG WINAPI
RegOpenKeyA(
IN HKEY hKey,
IN LPCSTR lpSubKey,
OUT PHKEY phkResult)
{
PWSTR lpSubKeyW;
LONG rc;
lpSubKeyW = MultiByteToWideChar(lpSubKey);
if (!lpSubKeyW)
return ERROR_OUTOFMEMORY;
rc = RegOpenKeyW(hKey, lpSubKeyW, phkResult);
free(lpSubKeyW);
return rc;
}
static LONG
RegpOpenOrCreateValue(
IN HKEY hKey,
IN LPCWSTR ValueName,
IN BOOL AllowCreation,
OUT PCM_KEY_VALUE *ValueCell,
OUT PHCELL_INDEX ValueCellOffset)
{
MEMKEY ParentKey;
UNICODE_STRING ValueString;
NTSTATUS Status;
ParentKey = HKEY_TO_MEMKEY(hKey);
RtlInitUnicodeString(&ValueString, ValueName);
Status = CmiScanForValueKey(
ParentKey->RegistryHive,
ParentKey->KeyCell,
&ValueString,
ValueCell,
ValueCellOffset);
if (AllowCreation && Status == STATUS_OBJECT_NAME_NOT_FOUND)
{
Status = CmiAddValueKey(
ParentKey->RegistryHive,
ParentKey->KeyCell,
ParentKey->KeyCellOffset,
&ValueString,
ValueCell,
ValueCellOffset);
}
if (!NT_SUCCESS(Status))
return ERROR_UNSUCCESSFUL;
return ERROR_SUCCESS;
}
LONG WINAPI
RegSetValueExW(
IN HKEY hKey,
IN LPCWSTR lpValueName OPTIONAL,
IN ULONG Reserved,
IN ULONG dwType,
IN const UCHAR* lpData,
IN USHORT cbData)
{
MEMKEY Key, DestKey;
PHKEY phKey;
PCM_KEY_VALUE ValueCell;
HCELL_INDEX ValueCellOffset;
PVOID DataCell;
LONG DataCellSize;
NTSTATUS Status;
if (dwType == REG_LINK)
{
/* Special handling of registry links */
if (cbData != sizeof(PVOID))
return STATUS_INVALID_PARAMETER;
phKey = (PHKEY)lpData;
Key = HKEY_TO_MEMKEY(hKey);
DestKey = HKEY_TO_MEMKEY(*phKey);
/* Create the link in memory */
Key->DataType = REG_LINK;
Key->LinkedKey = DestKey;
/* Create the link in registry hive (if applicable) */
if (Key->RegistryHive != DestKey->RegistryHive)
return STATUS_SUCCESS;
DPRINT1("Save link to registry\n");
return STATUS_NOT_IMPLEMENTED;
}
if ((cbData & REG_DATA_SIZE_MASK) != cbData)
return STATUS_UNSUCCESSFUL;
Key = HKEY_TO_MEMKEY(hKey);
Status = RegpOpenOrCreateValue(hKey, lpValueName, TRUE, &ValueCell, &ValueCellOffset);
if (!NT_SUCCESS(Status))
return ERROR_UNSUCCESSFUL;
/* Get size of the allocated cellule (if any) */
if (!(ValueCell->DataLength & REG_DATA_IN_OFFSET) &&
(ValueCell->DataLength & REG_DATA_SIZE_MASK) != 0)
{
DataCell = HvGetCell(&Key->RegistryHive->Hive, ValueCell->Data);
if (!DataCell)
return ERROR_UNSUCCESSFUL;
DataCellSize = -HvGetCellSize(&Key->RegistryHive->Hive, DataCell);
}
else
{
DataCell = NULL;
DataCellSize = 0;
}
if (cbData <= sizeof(HCELL_INDEX))
{
/* If data size <= sizeof(HCELL_INDEX) then store data in the data offset */
DPRINT("ValueCell->DataLength %u\n", ValueCell->DataLength);
if (DataCell)
HvFreeCell(&Key->RegistryHive->Hive, ValueCell->Data);
RtlCopyMemory(&ValueCell->Data, lpData, cbData);
ValueCell->DataLength = (ULONG)(cbData | REG_DATA_IN_OFFSET);
ValueCell->Type = dwType;
HvMarkCellDirty(&Key->RegistryHive->Hive, ValueCellOffset, FALSE);
}
else
{
if (cbData > (SIZE_T)DataCellSize)
{
/* New data size is larger than the current, destroy current
* data block and allocate a new one. */
HCELL_INDEX NewOffset;
DPRINT("ValueCell->DataLength %u\n", ValueCell->DataLength);
NewOffset = HvAllocateCell(&Key->RegistryHive->Hive, cbData, Stable, HCELL_NIL);
if (NewOffset == HCELL_NIL)
{
DPRINT("HvAllocateCell() failed with status 0x%08x\n", Status);
return ERROR_UNSUCCESSFUL;
}
if (DataCell)
HvFreeCell(&Key->RegistryHive->Hive, ValueCell->Data);
ValueCell->Data = NewOffset;
DataCell = (PVOID)HvGetCell(&Key->RegistryHive->Hive, NewOffset);
}
/* Copy new contents to cellule */
RtlCopyMemory(DataCell, lpData, cbData);
ValueCell->DataLength = (ULONG)(cbData & REG_DATA_SIZE_MASK);
ValueCell->Type = dwType;
HvMarkCellDirty(&Key->RegistryHive->Hive, ValueCell->Data, FALSE);
HvMarkCellDirty(&Key->RegistryHive->Hive, ValueCellOffset, FALSE);
}
if (cbData > Key->KeyCell->MaxValueDataLen)
Key->KeyCell->MaxValueDataLen = cbData;
HvMarkCellDirty(&Key->RegistryHive->Hive, Key->KeyCellOffset, FALSE);
DPRINT("Return status 0x%08x\n", Status);
return Status;
}
LONG WINAPI
RegSetValueExA(
IN HKEY hKey,
IN LPCSTR lpValueName OPTIONAL,
IN ULONG Reserved,
IN ULONG dwType,
IN const UCHAR* lpData,
IN ULONG cbData)
{
LPWSTR lpValueNameW = NULL;
const UCHAR* lpDataW;
USHORT cbDataW;
LONG rc = ERROR_SUCCESS;
DPRINT("RegSetValueA(%s)\n", lpValueName);
if (lpValueName)
{
lpValueNameW = MultiByteToWideChar(lpValueName);
if (!lpValueNameW)
return ERROR_OUTOFMEMORY;
}
if ((dwType == REG_SZ || dwType == REG_EXPAND_SZ || dwType == REG_MULTI_SZ)
&& cbData != 0)
{
ANSI_STRING AnsiString;
UNICODE_STRING Data;
if (lpData[cbData - 1] != '\0')
cbData++;
RtlInitAnsiString(&AnsiString, NULL);
AnsiString.Buffer = (PSTR)lpData;
AnsiString.Length = (USHORT)cbData - 1;
AnsiString.MaximumLength = (USHORT)cbData;
RtlAnsiStringToUnicodeString (&Data, &AnsiString, TRUE);
lpDataW = (const UCHAR*)Data.Buffer;
cbDataW = Data.MaximumLength;
}
else
{
lpDataW = lpData;
cbDataW = (USHORT)cbData;
}
if (rc == ERROR_SUCCESS)
rc = RegSetValueExW(hKey, lpValueNameW, 0, dwType, lpDataW, cbDataW);
if (lpValueNameW)
free(lpValueNameW);
if (lpData != lpDataW)
free((PVOID)lpDataW);
return rc;
}
LONG WINAPI
RegQueryValueExW(
IN HKEY hKey,
IN LPCWSTR lpValueName,
IN PULONG lpReserved,
OUT PULONG lpType,
OUT PUCHAR lpData,
OUT PSIZE_T lpcbData)
{
//ParentKey = HKEY_TO_MEMKEY(RootKey);
PCM_KEY_VALUE ValueCell;
HCELL_INDEX ValueCellOffset;
LONG rc;
rc = RegpOpenOrCreateValue(
hKey,
lpValueName,
FALSE,
&ValueCell,
&ValueCellOffset);
if (rc != ERROR_SUCCESS)
return rc;
DPRINT1("RegQueryValueExW(%S) not implemented\n", lpValueName);
/* ValueCell and ValueCellOffset are valid */
return ERROR_UNSUCCESSFUL;
}
LONG WINAPI
RegQueryValueExA(
IN HKEY hKey,
IN LPCSTR lpValueName,
IN PULONG lpReserved,
OUT PULONG lpType,
OUT PUCHAR lpData,
OUT PSIZE_T lpcbData)
{
LPWSTR lpValueNameW = NULL;
LONG rc;
if (lpValueName)
{
lpValueNameW = MultiByteToWideChar(lpValueName);
if (!lpValueNameW)
return ERROR_OUTOFMEMORY;
}
rc = RegQueryValueExW(hKey, lpValueNameW, lpReserved, lpType, lpData, lpcbData);
if (lpValueNameW)
free(lpValueNameW);
return rc;
}
LONG WINAPI
RegDeleteValueW(
IN HKEY hKey,
IN LPCWSTR lpValueName OPTIONAL)
{
DPRINT1("RegDeleteValueW() unimplemented\n");
return ERROR_UNSUCCESSFUL;
}
LONG WINAPI
RegDeleteValueA(
IN HKEY hKey,
IN LPCSTR lpValueName OPTIONAL)
{
LPWSTR lpValueNameW;
LONG rc;
if (lpValueName)
{
lpValueNameW = MultiByteToWideChar(lpValueName);
if (!lpValueNameW)
return ERROR_OUTOFMEMORY;
rc = RegDeleteValueW(hKey, lpValueNameW);
free(lpValueNameW);
}
else
rc = RegDeleteValueW(hKey, NULL);
return rc;
}
static BOOL
ConnectRegistry(
IN HKEY RootKey,
IN PCMHIVE HiveToConnect,
IN LPCWSTR Path)
{
NTSTATUS Status;
MEMKEY NewKey;
LONG rc;
Status = CmiInitializeTempHive(HiveToConnect);
if (!NT_SUCCESS(Status))
{
DPRINT1("CmiInitializeTempHive() failed with status 0x%08x\n", Status);
return FALSE;
}
/* Create key */
rc = RegCreateKeyW(
RootKey,
Path,
(PHKEY)&NewKey);
if (rc != ERROR_SUCCESS)
return FALSE;
NewKey->RegistryHive = HiveToConnect;
NewKey->KeyCellOffset = HiveToConnect->Hive.BaseBlock->RootCell;
NewKey->KeyCell = (PCM_KEY_NODE)HvGetCell (&HiveToConnect->Hive, NewKey->KeyCellOffset);
return TRUE;
}
LIST_ENTRY CmiHiveListHead;
VOID
RegInitializeRegistry(VOID)
{
UNICODE_STRING RootKeyName = RTL_CONSTANT_STRING(L"\\");
NTSTATUS Status;
HKEY ControlSetKey;
InitializeListHead(&CmiHiveListHead);
Status = CmiInitializeTempHive(&RootHive);
if (!NT_SUCCESS(Status))
{
DPRINT1("CmiInitializeTempHive() failed with status 0x%08x\n", Status);
return;
}
RootKey = CreateInMemoryStructure(
&RootHive,
RootHive.Hive.BaseBlock->RootCell,
&RootKeyName);
/* Create DEFAULT key */
ConnectRegistry(
NULL,
&DefaultHive,
L"Registry\\User\\.DEFAULT");
/* Create SAM key */
ConnectRegistry(
NULL,
&SamHive,
L"Registry\\Machine\\SAM");
/* Create SECURITY key */
ConnectRegistry(
NULL,
&SecurityHive,
L"Registry\\Machine\\SECURITY");
/* Create SOFTWARE key */
ConnectRegistry(
NULL,
&SoftwareHive,
L"Registry\\Machine\\SOFTWARE");
/* Create SYSTEM key */
ConnectRegistry(
NULL,
&SystemHive,
L"Registry\\Machine\\SYSTEM");
/* Create 'ControlSet001' key */
RegCreateKeyW(
NULL,
L"Registry\\Machine\\SYSTEM\\ControlSet001",
&ControlSetKey);
}
VOID
RegShutdownRegistry(VOID)
{
/* FIXME: clean up the complete hive */
free(RootKey->Name);
free(RootKey);
}
/* EOF */