[NTOSKRNL]

Implement NtSaveKey/NtSaveKeyEx and its backend CmSaveKey.
CORE-8259 #resolve #comment Committed in revision r63495.


svn path=/trunk/; revision=63495
This commit is contained in:
Aleksandar Andrejevic 2014-05-29 19:44:36 +00:00
parent 836f7cd6d3
commit 0d6c552a9d
5 changed files with 388 additions and 4 deletions

View file

@ -5,6 +5,7 @@
* PURPOSE: Configuration Manager - Internal Registry APIs
* PROGRAMMERS: Alex Ionescu (alex.ionescu@reactos.org)
* Eric Kohl
* Aleksandar Andrejevic <theflash AT sdf DOT lonestar DOT org>
*/
/* INCLUDES ******************************************************************/
@ -2120,3 +2121,227 @@ CmCountOpenSubKeys(IN PCM_KEY_CONTROL_BLOCK RootKcb,
return SubKeys;
}
HCELL_INDEX
NTAPI
CmpCopyCell(IN PHHIVE SourceHive,
IN HCELL_INDEX SourceCell,
IN PHHIVE DestinationHive,
IN HSTORAGE_TYPE StorageType)
{
PCELL_DATA SourceData;
PCELL_DATA DestinationData = NULL;
HCELL_INDEX DestinationCell = HCELL_NIL;
LONG DataSize;
PAGED_CODE();
/* Get the data and the size of the source cell */
SourceData = HvGetCell(SourceHive, SourceCell);
DataSize = HvGetCellSize(SourceHive, SourceData);
/* Allocate a new cell in the destination hive */
DestinationCell = HvAllocateCell(DestinationHive,
DataSize,
StorageType,
HCELL_NIL);
if (DestinationCell == HCELL_NIL) goto Cleanup;
/* Get the data of the destination cell */
DestinationData = HvGetCell(DestinationHive, DestinationCell);
/* Copy the data from the source cell to the destination cell */
RtlMoveMemory(DestinationData, SourceData, DataSize);
Cleanup:
/* Release the cells */
if (SourceData) HvReleaseCell(SourceHive, SourceCell);
if (DestinationData) HvReleaseCell(DestinationHive, DestinationCell);
/* Return the destination cell index */
return DestinationCell;
}
static
NTSTATUS
NTAPI
CmpDeepCopyKeyInternal(IN PHHIVE SourceHive,
IN HCELL_INDEX SrcKeyCell,
IN PHHIVE DestinationHive,
IN HCELL_INDEX Parent,
IN HSTORAGE_TYPE StorageType,
OUT PHCELL_INDEX DestKeyCell OPTIONAL)
{
NTSTATUS Status;
PCM_KEY_NODE SrcNode, DestNode;
HCELL_INDEX NewKeyCell, SubKey, NewSubKey;
ULONG Index, SubKeyCount;
PAGED_CODE();
DPRINT("CmpDeepCopyKeyInternal(0x%08X, 0x%08X, 0x%08X, 0x%08X, 0x%08X, 0x%08X)\n",
SourceHive,
SrcKeyCell,
DestinationHive,
Parent,
StorageType,
DestKeyCell);
/* Get the source cell node */
SrcNode = HvGetCell(SourceHive, SrcKeyCell);
/* Sanity check */
ASSERT(SrcNode->Signature == CM_KEY_NODE_SIGNATURE);
/* Create a simple copy of the source key */
NewKeyCell = CmpCopyCell(SourceHive,
SrcKeyCell,
DestinationHive,
StorageType);
if (NewKeyCell == HCELL_NIL)
{
/* Not enough storage space */
Status = STATUS_INSUFFICIENT_RESOURCES;
goto Cleanup;
}
/* Get the destination cell node */
DestNode = HvGetCell(DestinationHive, NewKeyCell);
/* Set the parent */
DestNode->Parent = Parent;
// TODO: These should also be copied!
DestNode->Security = DestNode->Class = HCELL_NIL;
/* Copy the value list */
Status = CmpCopyKeyValueList(SourceHive,
&SrcNode->ValueList,
DestinationHive,
&DestNode->ValueList,
StorageType);
if (!NT_SUCCESS(Status)) goto Cleanup;
/* Clear the invalid subkey index */
DestNode->SubKeyCounts[Stable] = DestNode->SubKeyCounts[Volatile] = 0;
DestNode->SubKeyLists[Stable] = DestNode->SubKeyLists[Volatile] = HCELL_NIL;
/* Calculate the total number of subkeys */
SubKeyCount = SrcNode->SubKeyCounts[Stable] + SrcNode->SubKeyCounts[Volatile];
/* Loop through all the subkeys */
for (Index = 0; Index < SubKeyCount; Index++)
{
/* Get the subkey */
SubKey = CmpFindSubKeyByNumber(SourceHive, SrcNode, Index);
ASSERT(SubKey != HCELL_NIL);
/* Call the function recursively for the subkey */
Status = CmpDeepCopyKeyInternal(SourceHive,
SubKey,
DestinationHive,
NewKeyCell,
StorageType,
&NewSubKey);
if (!NT_SUCCESS(Status)) goto Cleanup;
/* Add the copy of the subkey to the new key */
if (!CmpAddSubKey(DestinationHive,
NewKeyCell,
NewSubKey))
{
Status = STATUS_INSUFFICIENT_RESOURCES;
goto Cleanup;
}
}
/* Set the cell index if requested and return success */
if (DestKeyCell) *DestKeyCell = NewKeyCell;
Status = STATUS_SUCCESS;
Cleanup:
/* Release the cells */
if (SrcNode) HvReleaseCell(SourceHive, SrcKeyCell);
if (DestNode) HvReleaseCell(DestinationHive, NewKeyCell);
return Status;
}
NTSTATUS
NTAPI
CmpDeepCopyKey(IN PHHIVE SourceHive,
IN HCELL_INDEX SrcKeyCell,
IN PHHIVE DestinationHive,
IN HSTORAGE_TYPE StorageType,
OUT PHCELL_INDEX DestKeyCell OPTIONAL)
{
/* Call the internal function */
return CmpDeepCopyKeyInternal(SourceHive,
SrcKeyCell,
DestinationHive,
HCELL_NIL,
StorageType,
DestKeyCell);
}
NTSTATUS
NTAPI
CmSaveKey(IN PCM_KEY_CONTROL_BLOCK Kcb,
IN HANDLE FileHandle,
IN ULONG Flags)
{
NTSTATUS Status = STATUS_SUCCESS;
PCMHIVE KeyHive = NULL;
PAGED_CODE();
DPRINT("CmSaveKey(0x%08X, 0x%08X, %lu)\n", Kcb, FileHandle, Flags);
/* Lock the registry and KCB */
CmpLockRegistry();
CmpAcquireKcbLockShared(Kcb);
if (Kcb->Delete)
{
/* The source key has been deleted, do nothing */
Status = STATUS_KEY_DELETED;
goto Cleanup;
}
/* Create a new hive that will hold the key */
Status = CmpInitializeHive(&KeyHive,
HINIT_CREATE,
HIVE_VOLATILE,
HFILE_TYPE_PRIMARY,
NULL,
NULL,
NULL,
NULL,
NULL,
0);
if (!NT_SUCCESS(Status)) goto Cleanup;
/* Copy the key recursively into the new hive */
Status = CmpDeepCopyKey(Kcb->KeyHive,
Kcb->KeyCell,
&KeyHive->Hive,
Stable,
&KeyHive->Hive.BaseBlock->RootCell);
if (!NT_SUCCESS(Status)) goto Cleanup;
/* Set the primary handle of the hive */
KeyHive->FileHandles[HFILE_TYPE_PRIMARY] = FileHandle;
/* Dump the hive into the file */
HvWriteHive(&KeyHive->Hive);
Cleanup:
/* Free the hive */
if (KeyHive) CmpDestroyHive(KeyHive);
/* Release the locks */
CmpReleaseKcbLock(Kcb);
CmpUnlockRegistry();
return Status;
}

View file

@ -238,6 +238,28 @@ CmpInitializeHive(OUT PCMHIVE *RegistryHive,
return STATUS_SUCCESS;
}
NTSTATUS
NTAPI
CmpDestroyHive(IN PCMHIVE CmHive)
{
/* Remove the hive from the list */
ExAcquirePushLockExclusive(&CmpHiveListHeadLock);
RemoveEntryList(&CmHive->HiveList);
ExReleasePushLock(&CmpHiveListHeadLock);
/* Delete the flusher lock */
ExDeleteResourceLite(CmHive->FlusherLock);
ExFreePoolWithTag(CmHive->FlusherLock, TAG_CM);
/* Delete the view lock */
ExFreePoolWithTag(CmHive->ViewLock, TAG_CM);
/* Free the hive */
HvFree(&CmHive->Hive);
return STATUS_SUCCESS;
}
NTSTATUS
NTAPI
CmpOpenHiveFiles(IN PCUNICODE_STRING BaseName,

View file

@ -361,3 +361,62 @@ CmpRemoveValueFromList(IN PHHIVE Hive,
ChildList->Count = Count;
return STATUS_SUCCESS;
}
NTSTATUS
NTAPI
CmpCopyKeyValueList(IN PHHIVE SourceHive,
IN PCHILD_LIST SrcValueList,
IN PHHIVE DestinationHive,
IN OUT PCHILD_LIST DestValueList,
IN HSTORAGE_TYPE StorageType)
{
NTSTATUS Status = STATUS_SUCCESS;
HCELL_INDEX CellIndex = HCELL_NIL;
ULONG Index;
PCELL_DATA SrcListData = NULL;
PCELL_DATA DestListData = NULL;
PAGED_CODE();
/* Set the count */
DestValueList->Count = SrcValueList->Count;
/* Check if the list is empty */
if (!DestValueList->Count)
{
DestValueList->List = HCELL_NIL;
return STATUS_SUCCESS;
}
/* Create a simple copy of the list */
CellIndex = CmpCopyCell(SourceHive,
SrcValueList->List,
DestinationHive,
StorageType);
if (CellIndex == HCELL_NIL) return STATUS_INSUFFICIENT_RESOURCES;
/* Get the source and the destination value list */
SrcListData = HvGetCell(SourceHive, SrcValueList->List);
DestListData = HvGetCell(DestinationHive, CellIndex);
/* Copy the actual values */
for (Index = 0; Index < SrcValueList->Count; Index++)
{
DestListData->u.KeyList[Index] = CmpCopyCell(SourceHive,
SrcListData->u.KeyList[Index],
DestinationHive,
StorageType);
if (DestListData->u.KeyList[Index] == HCELL_NIL)
{
Status = STATUS_INSUFFICIENT_RESOURCES;
break;
}
}
/* Release the cells */
if (SrcListData) HvReleaseCell(SourceHive, SrcValueList->List);
if (DestListData) HvReleaseCell(DestinationHive, CellIndex);
return Status;
}

View file

@ -1148,8 +1148,8 @@ NTAPI
NtSaveKey(IN HANDLE KeyHandle,
IN HANDLE FileHandle)
{
UNIMPLEMENTED;
return STATUS_NOT_IMPLEMENTED;
/* Call the extended API */
return NtSaveKeyEx(KeyHandle, FileHandle, REG_STANDARD_FORMAT);
}
NTSTATUS
@ -1158,8 +1158,43 @@ NtSaveKeyEx(IN HANDLE KeyHandle,
IN HANDLE FileHandle,
IN ULONG Flags)
{
UNIMPLEMENTED;
return STATUS_NOT_IMPLEMENTED;
NTSTATUS Status;
PCM_KEY_BODY KeyObject;
KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
PAGED_CODE();
DPRINT("NtSaveKeyEx(0x%08X, 0x%08X, %lu)\n", KeyHandle, FileHandle, Flags);
/* Verify the flags */
if ((Flags != REG_STANDARD_FORMAT)
&& (Flags != REG_LATEST_FORMAT)
&& (Flags != REG_NO_COMPRESSION))
{
/* Only one of these values can be specified */
return STATUS_INVALID_PARAMETER;
}
/* Check for the SeBackupPrivilege */
if (!SeSinglePrivilegeCheck(SeBackupPrivilege, PreviousMode))
{
return STATUS_PRIVILEGE_NOT_HELD;
}
/* Verify that the handle is valid and is a registry key */
Status = ObReferenceObjectByHandle(KeyHandle,
KEY_READ,
CmpKeyObjectType,
PreviousMode,
(PVOID*)&KeyObject,
NULL);
if (!NT_SUCCESS(Status)) return Status;
/* Call the internal API */
Status = CmSaveKey(KeyObject->KeyControlBlock, FileHandle, Flags);
ObDereferenceObject(KeyObject);
return Status;
}
NTSTATUS

View file

@ -786,6 +786,12 @@ CmpInitializeHive(
IN ULONG CheckFlags
);
NTSTATUS
NTAPI
CmpDestroyHive(
IN PCMHIVE CmHive
);
PSECURITY_DESCRIPTOR
NTAPI
CmpHiveRootSecurityDescriptor(
@ -1322,6 +1328,16 @@ CmpGetValueData(
OUT PHCELL_INDEX CellToRelease
);
NTSTATUS
NTAPI
CmpCopyKeyValueList(
IN PHHIVE SourceHive,
IN PCHILD_LIST SrcValueList,
IN PHHIVE DestinationHive,
IN OUT PCHILD_LIST DestValueList,
IN HSTORAGE_TYPE StorageType
);
//
// Boot Routines
//
@ -1527,6 +1543,33 @@ CmCountOpenSubKeys(
IN BOOLEAN RemoveEmptyCacheEntries
);
HCELL_INDEX
NTAPI
CmpCopyCell(
IN PHHIVE SourceHive,
IN HCELL_INDEX SourceCell,
IN PHHIVE DestinationHive,
IN HSTORAGE_TYPE StorageType
);
NTSTATUS
NTAPI
CmpDeepCopyKey(
IN PHHIVE SourceHive,
IN HCELL_INDEX SrcKeyCell,
IN PHHIVE DestinationHive,
IN HSTORAGE_TYPE StorageType,
OUT PHCELL_INDEX DestKeyCell OPTIONAL
);
NTSTATUS
NTAPI
CmSaveKey(
IN PCM_KEY_CONTROL_BLOCK Kcb,
IN HANDLE FileHandle,
IN ULONG Flags
);
//
// Startup and Shutdown
//