mirror of https://github.com/lianthony/NT4.0
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
670 lines
16 KiB
670 lines
16 KiB
/*++
|
|
|
|
Copyright (c) 1992 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
cmtrecpy.c
|
|
|
|
Abstract:
|
|
|
|
This file contains code for CmpCopyTree, misc copy utility routines.
|
|
|
|
Author:
|
|
|
|
Bryan M. Willman (bryanwi) 15-Jan-92
|
|
|
|
Revision History:
|
|
|
|
--*/
|
|
|
|
#include "cmp.h"
|
|
|
|
|
|
//
|
|
// stack used for directing nesting of tree copy. gets us off
|
|
// the kernel stack and thus allows for VERY deep nesting
|
|
//
|
|
|
|
#define CMP_INITIAL_STACK_SIZE 1024 // ENTRIES
|
|
|
|
typedef struct {
|
|
HCELL_INDEX SourceCell;
|
|
HCELL_INDEX TargetCell;
|
|
ULONG i;
|
|
} CMP_COPY_STACK_ENTRY, *PCMP_COPY_STACK_ENTRY;
|
|
|
|
BOOLEAN
|
|
CmpCopyTree2(
|
|
PCMP_COPY_STACK_ENTRY CmpCopyStack,
|
|
ULONG CmpCopyStackSize,
|
|
ULONG CmpCopyStackTop,
|
|
PHHIVE CmpSourceHive,
|
|
PHHIVE CmpTargetHive
|
|
);
|
|
|
|
#ifdef ALLOC_PRAGMA
|
|
#pragma alloc_text(PAGE,CmpCopyTree)
|
|
#pragma alloc_text(PAGE,CmpCopyTree2)
|
|
#pragma alloc_text(PAGE,CmpCopyKeyPartial)
|
|
#pragma alloc_text(PAGE,CmpCopyValue)
|
|
#pragma alloc_text(PAGE,CmpCopyCell)
|
|
#endif
|
|
|
|
//
|
|
// Routine to actually call to do a tree copy
|
|
//
|
|
|
|
BOOLEAN
|
|
CmpCopyTree(
|
|
PHHIVE SourceHive,
|
|
HCELL_INDEX SourceCell,
|
|
PHHIVE TargetHive,
|
|
HCELL_INDEX TargetCell
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Do a tree copy from source to destination. The source root key
|
|
and target root key must exist in advance. Their subkeys,
|
|
and full trees under the subkeys will be copied.
|
|
|
|
The root nodes themselves, and their value entries, will NOT
|
|
be copied.
|
|
|
|
NOTE: If this call fails part way through, it will NOT undo
|
|
any successfully completed key copies, thus a partial
|
|
tree copy CAN occur.
|
|
|
|
NOTE: VOLATILE KEYS and their CHILDREN are NOT COPIED.
|
|
|
|
Arguments:
|
|
|
|
SourceHive - pointer to hive control structure for source
|
|
|
|
SourceCell - index of cell at root of tree to copy
|
|
|
|
TargetHive - pointer to hive control structure for target
|
|
|
|
TargetCell - pointer to cell at root of target tree
|
|
|
|
Return Value:
|
|
|
|
BOOLEAN - Result code from call, among the following:
|
|
TRUE - it worked
|
|
FALSE - the tree copy was not completed (though more than 0
|
|
keys may have been copied)
|
|
|
|
--*/
|
|
{
|
|
BOOLEAN result;
|
|
PCMP_COPY_STACK_ENTRY CmpCopyStack;
|
|
|
|
CMLOG(CML_MAJOR, CMS_SAVRES) {
|
|
KdPrint(("CmpCopyTree:\n"));
|
|
}
|
|
|
|
CmpCopyStack = ExAllocatePool(
|
|
PagedPool,
|
|
sizeof(CMP_COPY_STACK_ENTRY)*CMP_INITIAL_STACK_SIZE
|
|
);
|
|
if (CmpCopyStack == NULL) {
|
|
return FALSE;
|
|
}
|
|
CmpCopyStack[0].SourceCell = SourceCell;
|
|
CmpCopyStack[0].TargetCell = TargetCell;
|
|
|
|
result = CmpCopyTree2(
|
|
CmpCopyStack,
|
|
CMP_INITIAL_STACK_SIZE,
|
|
0,
|
|
SourceHive,
|
|
TargetHive
|
|
);
|
|
|
|
ExFreePool(CmpCopyStack);
|
|
return result;
|
|
}
|
|
|
|
|
|
//
|
|
// Helper
|
|
//
|
|
|
|
BOOLEAN
|
|
CmpCopyTree2(
|
|
PCMP_COPY_STACK_ENTRY CmpCopyStack,
|
|
ULONG CmpCopyStackSize,
|
|
ULONG CmpCopyStackTop,
|
|
PHHIVE CmpSourceHive,
|
|
PHHIVE CmpTargetHive
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Do a tree copy from source to destination. The source root key
|
|
and target root key must exist in advance. Their subkeys,
|
|
and full trees under the subkeys will be copied.
|
|
|
|
The root notes themselves, and their value entries, will NOT
|
|
be copied.
|
|
|
|
NOTE: If this call fails part way through, it will NOT undo
|
|
any successfully completed key copies, thus a partial
|
|
tree copy CAN occur.
|
|
|
|
NOTE: DO NOT CALL THIS DIRECTLY, CALL CmpCopyTree()!
|
|
|
|
NOTE: VOLATILE KEYS and their CHILDREN are NOT COPIED.
|
|
|
|
Arguments:
|
|
|
|
(All of these are "virtual globals")
|
|
|
|
CmpCopyStack - "global" pointer to stack for frames
|
|
|
|
CmpCopyStackSize - alloced size of stack
|
|
|
|
CmpCopyStackTop - current top
|
|
|
|
CmpSourceHive, CmpTargetHive - source and target hives
|
|
|
|
Return Value:
|
|
|
|
BOOLEAN - Result code from call, among the following:
|
|
TRUE - it worked
|
|
FALSE - the tree copy was not completed (though more than 0
|
|
keys may have been copied)
|
|
|
|
--*/
|
|
{
|
|
PCMP_COPY_STACK_ENTRY Frame;
|
|
HCELL_INDEX SourceChild;
|
|
HCELL_INDEX NewSubKey;
|
|
|
|
CMLOG(CML_MINOR, CMS_SAVRES) {
|
|
KdPrint(("CmpCopyTree2:\n"));
|
|
}
|
|
|
|
//
|
|
// outer loop, apply to entire tree, emulate recursion here
|
|
// jump to here is a virtual call
|
|
//
|
|
Outer: while (TRUE) {
|
|
|
|
Frame = &(CmpCopyStack[CmpCopyStackTop]);
|
|
|
|
Frame->i = 0;
|
|
|
|
//
|
|
// inner loop, applies to one key
|
|
// jump to here is a virtual return
|
|
//
|
|
Inner: while (TRUE) {
|
|
|
|
SourceChild = CmpFindSubKeyByNumber(CmpSourceHive,
|
|
(PCM_KEY_NODE)HvGetCell(CmpSourceHive,Frame->SourceCell),
|
|
Frame->i);
|
|
|
|
if (SourceChild == HCELL_NIL) {
|
|
break;
|
|
}
|
|
(Frame->i)++;
|
|
|
|
if (HvGetCellType(SourceChild) == Volatile) {
|
|
|
|
//
|
|
// we've stepped through all the stable children into
|
|
// the volatile ones, we are done.
|
|
//
|
|
break;
|
|
}
|
|
|
|
if (HvGetCellType(SourceChild) == Stable) {
|
|
|
|
NewSubKey = CmpCopyKeyPartial(
|
|
CmpSourceHive,
|
|
SourceChild,
|
|
CmpTargetHive,
|
|
Frame->TargetCell,
|
|
TRUE
|
|
);
|
|
|
|
if (NewSubKey != HCELL_NIL) {
|
|
|
|
if ( ! CmpAddSubKey(
|
|
CmpTargetHive,
|
|
Frame->TargetCell,
|
|
NewSubKey
|
|
)
|
|
)
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
//
|
|
// We succeeded in copying the subkey, apply
|
|
// ourselves to it
|
|
//
|
|
CmpCopyStackTop++;
|
|
|
|
if (CmpCopyStackTop >= CmpCopyStackSize) {
|
|
|
|
//
|
|
// if we're here, it means that the tree
|
|
// we're trying to copy is more than 1024
|
|
// COMPONENTS deep (from 2048 to 256k bytes)
|
|
// we could grow the stack, but this is pretty
|
|
// severe, so return FALSE and fail the copy
|
|
//
|
|
return FALSE;
|
|
}
|
|
|
|
CmpCopyStack[CmpCopyStackTop].SourceCell =
|
|
SourceChild;
|
|
|
|
CmpCopyStack[CmpCopyStackTop].TargetCell =
|
|
NewSubKey;
|
|
|
|
goto Outer;
|
|
|
|
} else {
|
|
return FALSE;
|
|
}
|
|
|
|
} // if HvGetCellType()
|
|
} // Inner: while
|
|
|
|
if (CmpCopyStackTop == 0) {
|
|
return TRUE;
|
|
}
|
|
|
|
CmpCopyStackTop--;
|
|
Frame = &(CmpCopyStack[CmpCopyStackTop]);
|
|
goto Inner;
|
|
|
|
} // Outer: while
|
|
|
|
}
|
|
|
|
|
|
HCELL_INDEX
|
|
CmpCopyKeyPartial(
|
|
PHHIVE SourceHive,
|
|
HCELL_INDEX SourceKeyCell,
|
|
PHHIVE TargetHive,
|
|
HCELL_INDEX Parent,
|
|
BOOLEAN CopyValues
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Copy a key body and all of its values, but NOT its subkeylist or
|
|
subkey entries. SubKeyList.Count will be set to 0.
|
|
|
|
Arguments:
|
|
|
|
SourceHive - pointer to hive control structure for source
|
|
|
|
SourceKeyCell - value entry being copied
|
|
|
|
TargetHive - pointer to hive control structure for target
|
|
|
|
Parent - parent value to set into newly created key body
|
|
|
|
CopyValues - if FALSE value entries will not be copied, if TRUE, they will
|
|
|
|
Return Value:
|
|
|
|
HCELL_INDEX - Cell of body of new key entry, or HCELL_NIL
|
|
if some error.
|
|
|
|
--*/
|
|
{
|
|
NTSTATUS status;
|
|
HCELL_INDEX newkey = HCELL_NIL;
|
|
HCELL_INDEX newclass = HCELL_NIL;
|
|
HCELL_INDEX newsecurity = HCELL_NIL;
|
|
HCELL_INDEX newlist = HCELL_NIL;
|
|
HCELL_INDEX newvalue;
|
|
BOOLEAN success = FALSE;
|
|
ULONG i;
|
|
PCELL_DATA psrckey;
|
|
PCM_KEY_NODE ptarkey;
|
|
PCELL_DATA psrclist;
|
|
PCELL_DATA ptarlist;
|
|
PCELL_DATA psrcsecurity;
|
|
HCELL_INDEX security;
|
|
HCELL_INDEX class;
|
|
ULONG classlength;
|
|
ULONG count;
|
|
ULONG Type;
|
|
|
|
CMLOG(CML_MINOR, CMS_SAVRES) {
|
|
KdPrint(("CmpCopyKeyPartial:\n"));
|
|
KdPrint(("\tSHive=%08lx SCell=%08lx\n",SourceHive,SourceKeyCell));
|
|
KdPrint(("\tTHive=%08lx\n",TargetHive));
|
|
}
|
|
|
|
|
|
//
|
|
// get description of source
|
|
//
|
|
if (Parent == HCELL_NIL) {
|
|
//
|
|
// This is a root node we are creating, so don't make it volatile.
|
|
//
|
|
Type = Stable;
|
|
} else {
|
|
Type = HvGetCellType(Parent);
|
|
}
|
|
psrckey = HvGetCell(SourceHive, SourceKeyCell);
|
|
security = psrckey->u.KeyNode.u1.s1.Security;
|
|
class = psrckey->u.KeyNode.u1.s1.Class;
|
|
classlength = psrckey->u.KeyNode.ClassLength;
|
|
|
|
//
|
|
// Allocate and copy the body
|
|
//
|
|
newkey = CmpCopyCell(SourceHive, SourceKeyCell, TargetHive, Type);
|
|
if (newkey == HCELL_NIL) {
|
|
goto DoFinally;
|
|
}
|
|
|
|
//
|
|
// Allocate and copy class
|
|
//
|
|
if (classlength > 0) {
|
|
newclass = CmpCopyCell(SourceHive, class, TargetHive, Type);
|
|
if (newclass == HCELL_NIL) {
|
|
goto DoFinally;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Fill in the target body
|
|
//
|
|
ptarkey = (PCM_KEY_NODE)HvGetCell(TargetHive, newkey);
|
|
|
|
ptarkey->u1.s1.Class = newclass;
|
|
ptarkey->u1.s1.Security = HCELL_NIL;
|
|
ptarkey->SubKeyLists[Stable] = HCELL_NIL;
|
|
ptarkey->SubKeyLists[Volatile] = HCELL_NIL;
|
|
ptarkey->SubKeyCounts[Stable] = 0;
|
|
ptarkey->SubKeyCounts[Volatile] = 0;
|
|
ptarkey->Parent = Parent;
|
|
|
|
ptarkey->Flags = (psrckey->u.KeyNode.Flags & KEY_COMP_NAME);
|
|
if (Parent == HCELL_NIL) {
|
|
ptarkey->Flags |= KEY_HIVE_ENTRY + KEY_NO_DELETE;
|
|
}
|
|
|
|
//
|
|
// Allocate and copy security
|
|
//
|
|
psrcsecurity = HvGetCell(SourceHive, security);
|
|
|
|
status = CmpAssignSecurityDescriptor(TargetHive,
|
|
newkey,
|
|
ptarkey,
|
|
&(psrcsecurity->u.KeySecurity.Descriptor),
|
|
PagedPool);
|
|
if (!NT_SUCCESS(status)) {
|
|
goto DoFinally;
|
|
}
|
|
|
|
|
|
//
|
|
// Set up the value list
|
|
//
|
|
count = psrckey->u.KeyNode.ValueList.Count;
|
|
|
|
if ((count == 0) || (CopyValues == FALSE)) {
|
|
ptarkey->ValueList.List = HCELL_NIL;
|
|
ptarkey->ValueList.Count = 0;
|
|
success = TRUE;
|
|
} else {
|
|
|
|
psrclist = HvGetCell(SourceHive, psrckey->u.KeyNode.ValueList.List);
|
|
|
|
newlist = HvAllocateCell(
|
|
TargetHive,
|
|
count * sizeof(HCELL_INDEX),
|
|
Type
|
|
);
|
|
if (newlist == HCELL_NIL) {
|
|
goto DoFinally;
|
|
}
|
|
ptarkey->ValueList.List = newlist;
|
|
ptarlist = HvGetCell(TargetHive, newlist);
|
|
|
|
|
|
//
|
|
// Copy the values
|
|
//
|
|
for (i = 0; i < count; i++) {
|
|
|
|
newvalue = CmpCopyValue(
|
|
SourceHive,
|
|
psrclist->u.KeyList[i],
|
|
TargetHive,
|
|
Type
|
|
);
|
|
|
|
if (newvalue != HCELL_NIL) {
|
|
|
|
ptarlist->u.KeyList[i] = newvalue;
|
|
|
|
} else {
|
|
|
|
for (; i > 0; i--) {
|
|
HvFreeCell(
|
|
TargetHive,
|
|
ptarlist->u.KeyList[i - 1]
|
|
);
|
|
}
|
|
goto DoFinally;
|
|
}
|
|
}
|
|
success = TRUE;
|
|
}
|
|
|
|
DoFinally:
|
|
if (success == FALSE) {
|
|
|
|
if (newlist != HCELL_NIL) {
|
|
HvFreeCell(TargetHive, newlist);
|
|
}
|
|
|
|
if (newsecurity != HCELL_NIL) {
|
|
HvFreeCell(TargetHive, newsecurity);
|
|
}
|
|
|
|
if (newclass != HCELL_NIL) {
|
|
HvFreeCell(TargetHive, newclass);
|
|
}
|
|
|
|
if (newkey != HCELL_NIL) {
|
|
HvFreeCell(TargetHive, newkey);
|
|
}
|
|
|
|
return HCELL_NIL;
|
|
|
|
} else {
|
|
|
|
return newkey;
|
|
}
|
|
}
|
|
|
|
|
|
HCELL_INDEX
|
|
CmpCopyValue(
|
|
PHHIVE SourceHive,
|
|
HCELL_INDEX SourceValueCell,
|
|
PHHIVE TargetHive,
|
|
HSTORAGE_TYPE Type
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Copy a value entry. Copies the body of a value entry and the
|
|
data. Returns cell of new value entry.
|
|
|
|
Arguments:
|
|
|
|
SourceHive - pointer to hive control structure for source
|
|
|
|
SourceValueCell - value entry being copied
|
|
|
|
TargetHive - pointer to hive control structure for target
|
|
|
|
Type - storage type to allocate for target (stable or volatile)
|
|
|
|
Return Value:
|
|
|
|
HCELL_INDEX - Cell of body of new value entry, or HCELL_NIL
|
|
if some error.
|
|
|
|
--*/
|
|
{
|
|
HCELL_INDEX newvalue;
|
|
HCELL_INDEX newdata;
|
|
PCELL_DATA pvalue;
|
|
ULONG datalength;
|
|
HCELL_INDEX olddata;
|
|
ULONG tempdata;
|
|
BOOLEAN small;
|
|
|
|
CMLOG(CML_MINOR, CMS_SAVRES) {
|
|
KdPrint(("CmpCopyValue:\n"));
|
|
KdPrint(("\tSHive=%08lx SCell=%08lx\n",SourceHive,SourceValueCell));
|
|
KdPrint(("\tTargetHive=%08lx\n",TargetHive));
|
|
}
|
|
|
|
//
|
|
// get source data
|
|
//
|
|
pvalue = HvGetCell(SourceHive, SourceValueCell);
|
|
small = CmpIsHKeyValueSmall(datalength, pvalue->u.KeyValue.DataLength);
|
|
olddata = pvalue->u.KeyValue.Data;
|
|
|
|
//
|
|
// Copy body
|
|
//
|
|
newvalue = CmpCopyCell(SourceHive, SourceValueCell, TargetHive, Type);
|
|
if (newvalue == HCELL_NIL) {
|
|
return HCELL_NIL;
|
|
}
|
|
|
|
//
|
|
// Copy data (if any)
|
|
//
|
|
if (datalength > 0) {
|
|
|
|
if (datalength > CM_KEY_VALUE_SMALL) {
|
|
|
|
//
|
|
// there's data, and it's "big", so do standard copy
|
|
//
|
|
newdata = CmpCopyCell(SourceHive, olddata, TargetHive, Type);
|
|
|
|
if (newdata == HCELL_NIL) {
|
|
HvFreeCell(TargetHive, newvalue);
|
|
return HCELL_NIL;
|
|
}
|
|
|
|
pvalue = HvGetCell(TargetHive, newvalue);
|
|
pvalue->u.KeyValue.Data = newdata;
|
|
pvalue->u.KeyValue.DataLength = datalength;
|
|
|
|
} else {
|
|
|
|
//
|
|
// the data is small, but may be stored in either large or
|
|
// small format for historical reasons
|
|
//
|
|
if (small) {
|
|
|
|
//
|
|
// data is already small, so just do a body to body copy
|
|
//
|
|
tempdata = pvalue->u.KeyValue.Data;
|
|
|
|
} else {
|
|
|
|
//
|
|
// data is stored externally in old cell, will be internal in new
|
|
//
|
|
pvalue = HvGetCell(SourceHive, pvalue->u.KeyValue.Data);
|
|
tempdata = *((PULONG)pvalue);
|
|
}
|
|
pvalue = HvGetCell(TargetHive, newvalue);
|
|
pvalue->u.KeyValue.Data = tempdata;
|
|
pvalue->u.KeyValue.DataLength =
|
|
datalength + CM_KEY_VALUE_SPECIAL_SIZE;
|
|
|
|
}
|
|
}
|
|
|
|
return newvalue;
|
|
}
|
|
|
|
|
|
HCELL_INDEX
|
|
CmpCopyCell(
|
|
PHHIVE SourceHive,
|
|
HCELL_INDEX SourceCell,
|
|
PHHIVE TargetHive,
|
|
HSTORAGE_TYPE Type
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Copy SourceHive.SourceCell to TargetHive.TargetCell.
|
|
|
|
Arguments:
|
|
|
|
SourceHive - pointer to hive control structure for source
|
|
|
|
SourceCell - index of cell to copy from
|
|
|
|
TargetHive - pointer to hive control structure for target
|
|
|
|
Type - storage type (stable or volatile) of new cell
|
|
|
|
Return Value:
|
|
|
|
HCELL_INDEX of new cell, or HCELL_NIL if failure.
|
|
|
|
--*/
|
|
{
|
|
PVOID psource;
|
|
PVOID ptarget;
|
|
ULONG size;
|
|
HCELL_INDEX newcell;
|
|
|
|
CMLOG(CML_MINOR, CMS_SAVRES) {
|
|
KdPrint(("CmpCopyCell:\n"));
|
|
KdPrint(("\tSourceHive=%08lx SourceCell=%08lx\n",SourceHive,SourceCell));
|
|
KdPrint(("\tTargetHive=%08lx\n",TargetHive));
|
|
}
|
|
|
|
psource = HvGetCell(SourceHive, SourceCell);
|
|
size = HvGetCellSize(SourceHive, psource);
|
|
|
|
newcell = HvAllocateCell(TargetHive, size, Type);
|
|
if (newcell == HCELL_NIL) {
|
|
return HCELL_NIL;
|
|
}
|
|
|
|
ptarget = HvGetCell(TargetHive, newcell);
|
|
|
|
RtlCopyMemory(ptarget, psource, size);
|
|
|
|
return newcell;
|
|
}
|