[NTOSKRNL]
authorAleksandar Andrejevic <aandrejevic@reactos.org>
Thu, 29 May 2014 19:44:36 +0000 (19:44 +0000)
committerAleksandar Andrejevic <aandrejevic@reactos.org>
Thu, 29 May 2014 19:44:36 +0000 (19:44 +0000)
Implement NtSaveKey/NtSaveKeyEx and its backend CmSaveKey.
CORE-8259 #resolve #comment Committed in revision r63495.

svn path=/trunk/; revision=63495

reactos/ntoskrnl/config/cmapi.c
reactos/ntoskrnl/config/cminit.c
reactos/ntoskrnl/config/cmvalue.c
reactos/ntoskrnl/config/ntapi.c
reactos/ntoskrnl/include/internal/cm.h

index ed2eda0..e52f572 100644 (file)
@@ -5,6 +5,7 @@
  * PURPOSE:         Configuration Manager - Internal Registry APIs
  * PROGRAMMERS:     Alex Ionescu (alex.ionescu@reactos.org)
  *                  Eric Kohl
  * 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 ******************************************************************/
  */
 
 /* INCLUDES ******************************************************************/
@@ -2120,3 +2121,227 @@ CmCountOpenSubKeys(IN PCM_KEY_CONTROL_BLOCK RootKcb,
 
     return SubKeys;
 }
 
     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;
+}
index 897e584..8689e8e 100644 (file)
@@ -238,6 +238,28 @@ CmpInitializeHive(OUT PCMHIVE *RegistryHive,
     return STATUS_SUCCESS;
 }
 
     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,
 NTSTATUS
 NTAPI
 CmpOpenHiveFiles(IN PCUNICODE_STRING BaseName,
index 0c401e6..30fd622 100644 (file)
@@ -361,3 +361,62 @@ CmpRemoveValueFromList(IN PHHIVE Hive,
     ChildList->Count = Count;
     return STATUS_SUCCESS;
 }
     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;
+}
index fe72872..b3bf0ec 100644 (file)
@@ -1148,8 +1148,8 @@ NTAPI
 NtSaveKey(IN HANDLE KeyHandle,
           IN HANDLE FileHandle)
 {
 NtSaveKey(IN HANDLE KeyHandle,
           IN HANDLE FileHandle)
 {
-    UNIMPLEMENTED;
-    return STATUS_NOT_IMPLEMENTED;
+    /* Call the extended API */
+    return NtSaveKeyEx(KeyHandle, FileHandle, REG_STANDARD_FORMAT);
 }
 
 NTSTATUS
 }
 
 NTSTATUS
@@ -1158,8 +1158,43 @@ NtSaveKeyEx(IN HANDLE KeyHandle,
             IN HANDLE FileHandle,
             IN ULONG Flags)
 {
             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
 }
 
 NTSTATUS
index d34f5b3..d4d7c9e 100644 (file)
@@ -786,6 +786,12 @@ CmpInitializeHive(
     IN ULONG CheckFlags
 );
 
     IN ULONG CheckFlags
 );
 
+NTSTATUS
+NTAPI
+CmpDestroyHive(
+    IN PCMHIVE CmHive
+);
+
 PSECURITY_DESCRIPTOR
 NTAPI
 CmpHiveRootSecurityDescriptor(
 PSECURITY_DESCRIPTOR
 NTAPI
 CmpHiveRootSecurityDescriptor(
@@ -1322,6 +1328,16 @@ CmpGetValueData(
     OUT PHCELL_INDEX CellToRelease
 );
 
     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
 //
 //
 // Boot Routines
 //
@@ -1527,6 +1543,33 @@ CmCountOpenSubKeys(
     IN BOOLEAN RemoveEmptyCacheEntries
 );
 
     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
 //
 //
 // Startup and Shutdown
 //