reactos/sdk/tools/mkhive/cmi.c

452 lines
13 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/cmi.c
* PURPOSE: Registry file manipulation routines
* PROGRAMMER: Hervé Poussineau
*/
#define NDEBUG
#include "mkhive.h"
PVOID
NTAPI
CmpAllocate(
IN SIZE_T Size,
IN BOOLEAN Paged,
IN ULONG Tag)
{
return (PVOID)malloc((size_t)Size);
}
VOID
NTAPI
CmpFree(
IN PVOID Ptr,
IN ULONG Quota)
{
free(Ptr);
}
static BOOLEAN
NTAPI
CmpFileRead(
IN PHHIVE RegistryHive,
IN ULONG FileType,
IN PULONG FileOffset,
OUT PVOID Buffer,
IN SIZE_T BufferLength)
{
PCMHIVE CmHive = (PCMHIVE)RegistryHive;
FILE *File = CmHive->FileHandles[HFILE_TYPE_PRIMARY];
if (fseek(File, *FileOffset, SEEK_SET) != 0)
return FALSE;
return (fread(Buffer, 1, BufferLength, File) == BufferLength);
}
static BOOLEAN
NTAPI
CmpFileWrite(
IN PHHIVE RegistryHive,
IN ULONG FileType,
IN PULONG FileOffset,
IN PVOID Buffer,
IN SIZE_T BufferLength)
{
PCMHIVE CmHive = (PCMHIVE)RegistryHive;
FILE *File = CmHive->FileHandles[HFILE_TYPE_PRIMARY];
if (fseek(File, *FileOffset, SEEK_SET) != 0)
return FALSE;
return (fwrite(Buffer, 1, BufferLength, File) == BufferLength);
}
static BOOLEAN
NTAPI
CmpFileSetSize(
IN PHHIVE RegistryHive,
IN ULONG FileType,
IN ULONG FileSize,
IN ULONG OldFileSize)
{
DPRINT1("CmpFileSetSize() unimplemented\n");
return FALSE;
}
static BOOLEAN
NTAPI
CmpFileFlush(
IN PHHIVE RegistryHive,
IN ULONG FileType,
PLARGE_INTEGER FileOffset,
ULONG Length)
{
PCMHIVE CmHive = (PCMHIVE)RegistryHive;
FILE *File = CmHive->FileHandles[HFILE_TYPE_PRIMARY];
return (fflush(File) == 0);
}
NTSTATUS
CmiInitializeHive(
IN OUT PCMHIVE Hive,
IN PCWSTR Name)
{
NTSTATUS Status;
RtlZeroMemory(Hive, sizeof(*Hive));
DPRINT("Hive 0x%p\n", Hive);
Status = HvInitialize(&Hive->Hive,
HINIT_CREATE,
HIVE_NOLAZYFLUSH,
HFILE_TYPE_PRIMARY,
0,
CmpAllocate,
CmpFree,
CmpFileSetSize,
CmpFileWrite,
CmpFileRead,
CmpFileFlush,
1,
NULL);
if (!NT_SUCCESS(Status))
{
return Status;
}
// HACK: See the HACK from r31253
if (!CmCreateRootNode(&Hive->Hive, Name))
{
HvFree(&Hive->Hive);
return STATUS_INSUFFICIENT_RESOURCES;
}
/* Add the new hive to the hive list */
InsertTailList(&CmiHiveListHead,
&Hive->HiveList);
return STATUS_SUCCESS;
}
NTSTATUS
CmiCreateSecurityKey(
IN PHHIVE Hive,
IN HCELL_INDEX Cell,
IN PUCHAR Descriptor,
IN ULONG DescriptorLength)
{
HCELL_INDEX SecurityCell;
PCM_KEY_NODE Node;
PCM_KEY_SECURITY Security;
Node = (PCM_KEY_NODE)HvGetCell(Hive, Cell);
SecurityCell = HvAllocateCell(Hive,
FIELD_OFFSET(CM_KEY_SECURITY, Descriptor) +
DescriptorLength,
Stable,
HCELL_NIL);
if (SecurityCell == HCELL_NIL)
{
HvReleaseCell(Hive, Cell);
return STATUS_INSUFFICIENT_RESOURCES;
}
Node->Security = SecurityCell;
Security = (PCM_KEY_SECURITY)HvGetCell(Hive, SecurityCell);
Security->Signature = CM_KEY_SECURITY_SIGNATURE;
Security->ReferenceCount = 1;
Security->DescriptorLength = DescriptorLength;
RtlMoveMemory(&Security->Descriptor,
Descriptor,
DescriptorLength);
Security->Flink = Security->Blink = SecurityCell;
HvReleaseCell(Hive, SecurityCell);
HvReleaseCell(Hive, Cell);
return STATUS_SUCCESS;
}
static NTSTATUS
CmiCreateSubKey(
IN PCMHIVE RegistryHive,
IN HCELL_INDEX ParentKeyCellOffset,
IN PCUNICODE_STRING SubKeyName,
IN BOOLEAN VolatileKey,
OUT HCELL_INDEX* pNKBOffset)
{
HCELL_INDEX NKBOffset;
PCM_KEY_NODE NewKeyCell;
UNICODE_STRING KeyName;
HSTORAGE_TYPE Storage;
/* Skip leading path separator if present */
if (SubKeyName->Buffer[0] == OBJ_NAME_PATH_SEPARATOR)
{
KeyName.Buffer = &SubKeyName->Buffer[1];
KeyName.Length = KeyName.MaximumLength = SubKeyName->Length - sizeof(WCHAR);
}
else
{
KeyName = *SubKeyName;
}
Storage = (VolatileKey ? Volatile : Stable);
NKBOffset = HvAllocateCell(&RegistryHive->Hive,
FIELD_OFFSET(CM_KEY_NODE, Name) +
CmpNameSize(&RegistryHive->Hive, &KeyName),
Storage,
HCELL_NIL);
if (NKBOffset == HCELL_NIL)
{
return STATUS_INSUFFICIENT_RESOURCES;
}
NewKeyCell = (PCM_KEY_NODE)HvGetCell(&RegistryHive->Hive, NKBOffset);
if (NewKeyCell == NULL)
{
HvFreeCell(&RegistryHive->Hive, NKBOffset);
return STATUS_INSUFFICIENT_RESOURCES;
}
NewKeyCell->Signature = CM_KEY_NODE_SIGNATURE;
NewKeyCell->Flags = (VolatileKey ? KEY_IS_VOLATILE : 0);
KeQuerySystemTime(&NewKeyCell->LastWriteTime);
NewKeyCell->Parent = ParentKeyCellOffset;
NewKeyCell->SubKeyCounts[Stable] = 0;
NewKeyCell->SubKeyCounts[Volatile] = 0;
NewKeyCell->SubKeyLists[Stable] = HCELL_NIL;
NewKeyCell->SubKeyLists[Volatile] = HCELL_NIL;
NewKeyCell->ValueList.Count = 0;
NewKeyCell->ValueList.List = HCELL_NIL;
NewKeyCell->Security = HCELL_NIL;
NewKeyCell->Class = HCELL_NIL;
NewKeyCell->ClassLength = 0;
NewKeyCell->MaxNameLen = 0;
NewKeyCell->MaxClassLen = 0;
NewKeyCell->MaxValueNameLen = 0;
NewKeyCell->MaxValueDataLen = 0;
NewKeyCell->NameLength = CmpCopyName(&RegistryHive->Hive, NewKeyCell->Name, &KeyName);
if (NewKeyCell->NameLength < KeyName.Length) NewKeyCell->Flags |= KEY_COMP_NAME;
/* Inherit the security from the parent */
if (ParentKeyCellOffset == HCELL_NIL)
{
// We are in fact creating a root key.
// This is not handled there, but when we
// call CmCreateRootNode instead.
ASSERT(FALSE);
}
else
{
/* Get the parent node */
PCM_KEY_NODE ParentKeyCell;
ParentKeyCell = (PCM_KEY_NODE)HvGetCell(&RegistryHive->Hive, ParentKeyCellOffset);
if (ParentKeyCell)
{
/* Inherit the security block of the parent */
NewKeyCell->Security = ParentKeyCell->Security;
if (NewKeyCell->Security != HCELL_NIL)
{
PCM_KEY_SECURITY Security;
Security = (PCM_KEY_SECURITY)HvGetCell(&RegistryHive->Hive, NewKeyCell->Security);
++Security->ReferenceCount;
HvReleaseCell(&RegistryHive->Hive, NewKeyCell->Security);
}
HvReleaseCell(&RegistryHive->Hive, ParentKeyCellOffset);
}
}
HvReleaseCell(&RegistryHive->Hive, NKBOffset);
*pNKBOffset = NKBOffset;
return STATUS_SUCCESS;
}
NTSTATUS
CmiAddSubKey(
IN PCMHIVE RegistryHive,
IN HCELL_INDEX ParentKeyCellOffset,
IN PCUNICODE_STRING SubKeyName,
IN BOOLEAN VolatileKey,
OUT HCELL_INDEX *pBlockOffset)
{
PCM_KEY_NODE ParentKeyCell;
HCELL_INDEX NKBOffset;
NTSTATUS Status;
/* Create the new key */
Status = CmiCreateSubKey(RegistryHive, ParentKeyCellOffset, SubKeyName, VolatileKey, &NKBOffset);
if (!NT_SUCCESS(Status))
return Status;
/* Mark the parent cell as dirty */
HvMarkCellDirty(&RegistryHive->Hive, ParentKeyCellOffset, FALSE);
if (!CmpAddSubKey(&RegistryHive->Hive, ParentKeyCellOffset, NKBOffset))
{
/* FIXME: delete newly created cell */
// CmpFreeKeyByCell(&RegistryHive->Hive, NewCell /*NKBOffset*/, FALSE);
ASSERT(FALSE);
return STATUS_UNSUCCESSFUL;
}
/* Get the parent node */
ParentKeyCell = (PCM_KEY_NODE)HvGetCell(&RegistryHive->Hive, ParentKeyCellOffset);
if (!ParentKeyCell)
{
/* FIXME: delete newly created cell */
return STATUS_UNSUCCESSFUL;
}
VERIFY_KEY_CELL(ParentKeyCell);
/* Update the timestamp */
KeQuerySystemTime(&ParentKeyCell->LastWriteTime);
/* Check if we need to update name maximum, update it if so */
if (ParentKeyCell->MaxNameLen < SubKeyName->Length)
ParentKeyCell->MaxNameLen = SubKeyName->Length;
/* Release the cell */
HvReleaseCell(&RegistryHive->Hive, ParentKeyCellOffset);
*pBlockOffset = NKBOffset;
return STATUS_SUCCESS;
}
NTSTATUS
CmiAddValueKey(
IN PCMHIVE RegistryHive,
IN PCM_KEY_NODE Parent,
IN PCUNICODE_STRING ValueName,
OUT PCM_KEY_VALUE *pValueCell,
OUT HCELL_INDEX *pValueCellOffset)
{
PCELL_DATA ValueListCell;
PCM_KEY_VALUE NewValueCell;
HCELL_INDEX ValueListCellOffset;
HCELL_INDEX NewValueCellOffset;
ULONG CellSize;
HSTORAGE_TYPE Storage;
#ifndef FIELD_SIZE
#define FIELD_SIZE(type, field) (sizeof(((type *)0)->field))
#endif
Storage = (Parent->Flags & KEY_IS_VOLATILE) ? Volatile : Stable;
if (Parent->ValueList.List == HCELL_NIL)
{
/* Allocate some room for the value list */
CellSize = FIELD_SIZE(CELL_DATA, u.KeyList) + (3 * sizeof(HCELL_INDEX));
ValueListCellOffset = HvAllocateCell(&RegistryHive->Hive, CellSize, Storage, HCELL_NIL);
if (ValueListCellOffset == HCELL_NIL)
return STATUS_INSUFFICIENT_RESOURCES;
ValueListCell = (PCELL_DATA)HvGetCell(&RegistryHive->Hive, ValueListCellOffset);
if (!ValueListCell)
{
HvFreeCell(&RegistryHive->Hive, ValueListCellOffset);
return STATUS_UNSUCCESSFUL;
}
Parent->ValueList.List = ValueListCellOffset;
}
else
{
ValueListCell = (PCELL_DATA)HvGetCell(&RegistryHive->Hive, Parent->ValueList.List);
if (!ValueListCell)
return STATUS_UNSUCCESSFUL;
CellSize = ABS_VALUE(HvGetCellSize(&RegistryHive->Hive, ValueListCell));
if (Parent->ValueList.Count >= CellSize / sizeof(HCELL_INDEX))
{
CellSize *= 2;
ValueListCellOffset = HvReallocateCell(&RegistryHive->Hive, Parent->ValueList.List, CellSize);
if (ValueListCellOffset == HCELL_NIL)
return STATUS_INSUFFICIENT_RESOURCES;
ValueListCell = (PCELL_DATA)HvGetCell(&RegistryHive->Hive, ValueListCellOffset);
if (!ValueListCell)
return STATUS_UNSUCCESSFUL;
Parent->ValueList.List = ValueListCellOffset;
}
}
NewValueCellOffset = HvAllocateCell(&RegistryHive->Hive,
FIELD_OFFSET(CM_KEY_VALUE, Name) +
CmpNameSize(&RegistryHive->Hive, (PUNICODE_STRING)ValueName),
Storage,
HCELL_NIL);
if (NewValueCellOffset == HCELL_NIL)
{
return STATUS_INSUFFICIENT_RESOURCES;
}
NewValueCell = (PCM_KEY_VALUE)HvGetCell(&RegistryHive->Hive, NewValueCellOffset);
if (NewValueCell == NULL)
{
HvFreeCell(&RegistryHive->Hive, NewValueCellOffset);
return STATUS_INSUFFICIENT_RESOURCES;
}
NewValueCell->Signature = CM_KEY_VALUE_SIGNATURE;
NewValueCell->NameLength = CmpCopyName(&RegistryHive->Hive,
NewValueCell->Name,
(PUNICODE_STRING)ValueName);
/* Check for compressed name */
if (NewValueCell->NameLength < ValueName->Length)
{
/* This is a compressed name */
NewValueCell->Flags = VALUE_COMP_NAME;
}
else
{
/* No flags to set */
NewValueCell->Flags = 0;
}
NewValueCell->Type = 0;
NewValueCell->DataLength = 0;
NewValueCell->Data = HCELL_NIL;
ValueListCell->u.KeyList[Parent->ValueList.Count] = NewValueCellOffset;
Parent->ValueList.Count++;
HvMarkCellDirty(&RegistryHive->Hive, Parent->ValueList.List, FALSE);
HvMarkCellDirty(&RegistryHive->Hive, NewValueCellOffset, FALSE);
*pValueCell = NewValueCell;
*pValueCellOffset = NewValueCellOffset;
return STATUS_SUCCESS;
}