mirror of https://github.com/tongzx/nt5src
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.
2568 lines
69 KiB
2568 lines
69 KiB
/*++
|
|
|
|
Copyright (c) 1996 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
object.c
|
|
|
|
Abstract:
|
|
|
|
Routines to manage an 'object' which currently can only be a registry
|
|
key, value name, value, handle and root handle.
|
|
|
|
Author:
|
|
|
|
Jim Schmidt (jimschm) 14-Feb-1997
|
|
|
|
Revision History:
|
|
|
|
marcw 09-Mar-1999 Don't create empty keys that didn't exist in Win9x Registry.
|
|
|
|
--*/
|
|
|
|
|
|
|
|
|
|
#include "pch.h"
|
|
#include "mergep.h"
|
|
|
|
extern POOLHANDLE g_TempPool;
|
|
extern DWORD g_ProgressBarCounter;
|
|
|
|
BOOL AllocObjectVal (IN OUT PDATAOBJECT SrcObPtr, IN PBYTE Value, IN DWORD Size, IN DWORD AllocSize);
|
|
VOID FreeObjectVal (IN OUT PDATAOBJECT SrcObPtr);
|
|
|
|
#define NON_ROOT_KEY(Key) ((Key) && ((UINT)(Key) < 0x7fffff00))
|
|
|
|
|
|
#ifdef DEBUG
|
|
|
|
static TCHAR g_DebugEncoding[MAX_ENCODED_RULE];
|
|
|
|
PCTSTR
|
|
DebugEncoder (
|
|
PVOID ObPtr
|
|
)
|
|
{
|
|
CreateObjectString ((CPDATAOBJECT) ObPtr, g_DebugEncoding);
|
|
return g_DebugEncoding;
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
PKEYPROPS
|
|
pCreateKeyPropsFromString (
|
|
PCTSTR KeyString,
|
|
BOOL Win95Flag
|
|
)
|
|
{
|
|
PKEYPROPS RegKey;
|
|
|
|
RegKey = (PKEYPROPS) PoolMemGetAlignedMemory (
|
|
g_TempPool,
|
|
sizeof (KEYPROPS) + SizeOfString (KeyString)
|
|
);
|
|
|
|
StringCopy (RegKey->KeyString, KeyString);
|
|
RegKey->UseCount = 1;
|
|
RegKey->OpenCount = 0;
|
|
RegKey->OpenKey = NULL;
|
|
RegKey->Win95 = Win95Flag;
|
|
|
|
return RegKey;
|
|
}
|
|
|
|
|
|
VOID
|
|
pFreeKeyProps (
|
|
PKEYPROPS RegKey
|
|
)
|
|
{
|
|
RegKey->UseCount--;
|
|
if (!RegKey->UseCount) {
|
|
|
|
// Close the key if it is open
|
|
if (NON_ROOT_KEY (RegKey->OpenKey)) {
|
|
if (RegKey->Win95) {
|
|
CloseRegKey95 (RegKey->OpenKey);
|
|
} else {
|
|
CloseRegKey (RegKey->OpenKey);
|
|
}
|
|
}
|
|
|
|
// Free the KEYPROPS memory
|
|
PoolMemReleaseMemory (g_TempPool, RegKey);
|
|
}
|
|
}
|
|
|
|
VOID
|
|
pIncKeyPropUse (
|
|
PKEYPROPS RegKey
|
|
)
|
|
{
|
|
RegKey->UseCount++;
|
|
if (RegKey->OpenKey) {
|
|
RegKey->OpenCount++;
|
|
}
|
|
}
|
|
|
|
PKEYPROPS
|
|
pCreateDuplicateKeyProps (
|
|
PKEYPROPS RegKey,
|
|
BOOL Win95Flag
|
|
)
|
|
{
|
|
PKEYPROPS NewRegKey;
|
|
|
|
NewRegKey = pCreateKeyPropsFromString (RegKey->KeyString, Win95Flag);
|
|
pFreeKeyProps (RegKey);
|
|
|
|
return NewRegKey;
|
|
}
|
|
|
|
|
|
HKEY
|
|
pGetWinNTKey (
|
|
HKEY Key
|
|
)
|
|
{
|
|
if (Key == HKEY_ROOT) {
|
|
return g_hKeyRootNT;
|
|
}
|
|
|
|
return Key;
|
|
}
|
|
|
|
HKEY
|
|
pGetWin95Key (
|
|
HKEY Key
|
|
)
|
|
{
|
|
if (Key == HKEY_ROOT) {
|
|
return g_hKeyRoot95;
|
|
}
|
|
|
|
return Key;
|
|
}
|
|
|
|
|
|
VOID
|
|
FixUpUserSpecifiedObject (
|
|
PTSTR Object
|
|
)
|
|
{
|
|
PTSTR p;
|
|
|
|
// Look for a space-open bracket pair
|
|
p = _tcsrchr (Object, TEXT('['));
|
|
if (p) {
|
|
p = _tcsdec2 (Object, p);
|
|
if (p && _tcsnextc (p) == TEXT(' ')) {
|
|
// Found: turn space into wack
|
|
_settchar (p, TEXT('\\'));
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
VOID
|
|
CreateObjectString (
|
|
IN CPDATAOBJECT InObPtr,
|
|
OUT PTSTR Object
|
|
)
|
|
{
|
|
PTSTR p;
|
|
|
|
*Object = 0;
|
|
|
|
// Add HKR
|
|
if (InObPtr->RootItem) {
|
|
StringCopy (Object, GetRootStringFromOffset (InObPtr->RootItem));
|
|
}
|
|
|
|
// If no root, start with a wack when key is not relative
|
|
else if (!(InObPtr->ObjectType & OT_REGISTRY_RELATIVE)) {
|
|
if (InObPtr->KeyPtr) {
|
|
StringCopy (Object, TEXT("\\"));
|
|
}
|
|
}
|
|
|
|
// Add key
|
|
if (InObPtr->KeyPtr) {
|
|
if (*Object) {
|
|
AppendWack (Object);
|
|
}
|
|
|
|
EncodeRuleChars (GetEndOfString (Object), InObPtr->KeyPtr->KeyString);
|
|
}
|
|
|
|
// Add tree
|
|
if (InObPtr->ObjectType & OT_TREE) {
|
|
if (*Object) {
|
|
AppendWack (Object);
|
|
StringCat (Object, TEXT("*"));
|
|
}
|
|
}
|
|
|
|
// Add value name
|
|
if (InObPtr->ValueName) {
|
|
if (*Object) {
|
|
AppendWack (Object);
|
|
}
|
|
|
|
p = _tcsappend (Object, TEXT("["));
|
|
EncodeRuleChars (p, InObPtr->ValueName);
|
|
StringCat (Object, TEXT("]"));
|
|
}
|
|
|
|
// Final product: HKR\Reg\Key\Path\*\[Root]
|
|
}
|
|
|
|
|
|
BOOL
|
|
GetRegistryKeyStrFromObject (
|
|
IN CPDATAOBJECT InObPtr,
|
|
OUT PTSTR RegKey
|
|
)
|
|
{
|
|
*RegKey = 0;
|
|
|
|
// Add HKR
|
|
if (InObPtr->RootItem) {
|
|
StringCopy (RegKey, GetRootStringFromOffset (InObPtr->RootItem));
|
|
} else {
|
|
return FALSE;
|
|
}
|
|
|
|
// Add key
|
|
if (InObPtr->KeyPtr) {
|
|
EncodeRuleChars (AppendWack (RegKey), InObPtr->KeyPtr->KeyString);
|
|
} else {
|
|
return FALSE;
|
|
}
|
|
|
|
// Final product: HKR\Reg\Key\Path
|
|
return TRUE;
|
|
}
|
|
|
|
BOOL
|
|
TrackedCreateObjectStruct (
|
|
IN PCTSTR Object,
|
|
OUT PDATAOBJECT OutObPtr,
|
|
IN BOOL Win95Flag /* , */
|
|
ALLOCATION_TRACKING_DEF
|
|
)
|
|
{
|
|
PCTSTR EndOfKey = NULL;
|
|
|
|
PCTSTR EndOfSpace;
|
|
PCTSTR ValueName;
|
|
PCTSTR ObjectStart;
|
|
TCHAR DecodeBuf[MAX_ENCODED_RULE];
|
|
DWORD Length;
|
|
DWORD RelativeFlag = 0;
|
|
BOOL TreeFlag = FALSE;
|
|
CHARTYPE ch = 0;
|
|
|
|
//
|
|
// Init
|
|
//
|
|
|
|
ObjectStart = SkipSpace (Object);
|
|
|
|
ZeroMemory (OutObPtr, sizeof (DATAOBJECT));
|
|
if (!(*ObjectStart)) {
|
|
DEBUGMSG ((DBG_WARNING, "CreateObjectStruct: Empty object"));
|
|
return TRUE;
|
|
}
|
|
|
|
if (Win95Flag) {
|
|
OutObPtr->ObjectType |= OT_WIN95;
|
|
}
|
|
|
|
//
|
|
// Root
|
|
//
|
|
|
|
OutObPtr->RootItem = GetOffsetOfRootString (ObjectStart, &Length);
|
|
if (OutObPtr->RootItem) {
|
|
ObjectStart += Length;
|
|
OutObPtr->ObjectType |= OT_REGISTRY;
|
|
|
|
// If we have HKR\*, make ObjectStart point to \*
|
|
if (_tcsnextc (ObjectStart) == TEXT('*')) {
|
|
ObjectStart = _tcsdec2 (Object, ObjectStart);
|
|
MYASSERT (ObjectStart);
|
|
}
|
|
|
|
}
|
|
|
|
// If no root, starting with a wack means 'relative to the current root'
|
|
else if (*ObjectStart == TEXT('\\')) {
|
|
ObjectStart = _tcsinc (ObjectStart);
|
|
}
|
|
|
|
// If no root and key does not start with a wack, means 'relative to current key'
|
|
else if (*ObjectStart != TEXT('[')) {
|
|
RelativeFlag = OT_REGISTRY_RELATIVE;
|
|
}
|
|
|
|
//
|
|
// Key
|
|
//
|
|
|
|
if (*ObjectStart) {
|
|
// Extract key, but not tree or valuename syntax
|
|
for (EndOfKey = ObjectStart ; *EndOfKey ; EndOfKey = _tcsinc (EndOfKey)) {
|
|
ch = (CHARTYPE)_tcsnextc (EndOfKey);
|
|
|
|
if (ch == TEXT('[') || ch == TEXT('*')) {
|
|
//
|
|
// EndOfKey points to start of value name or tree identifier
|
|
//
|
|
|
|
// Make it point to optional space before value, or
|
|
// make it point to wack before asterisk of the tree identifier
|
|
EndOfKey = _tcsdec2 (ObjectStart, EndOfKey);
|
|
|
|
// Verify that tree identifier points to wack-asterisk, otherwise
|
|
// return a syntax error
|
|
if (ch == TEXT('*')) {
|
|
if (!EndOfKey || _tcsnextc (EndOfKey) != TEXT('\\')) {
|
|
DEBUGMSG ((DBG_WARNING, "CreateObjectStruct: %s is not a valid object", Object));
|
|
return FALSE;
|
|
}
|
|
|
|
// Put EndOfKey on last character of the key
|
|
// (one char before \* tree identifer)
|
|
EndOfKey = _tcsdec2 (ObjectStart, EndOfKey);
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (EndOfKey) {
|
|
// EndOfKey points to the last character of the key, or the
|
|
// nul terminating the key. We need to trim trailing space.
|
|
EndOfSpace = SkipSpaceR (ObjectStart, EndOfKey);
|
|
|
|
// If EndOfSpace points to a wack, back it up one char (a key
|
|
// that does not have a tree identifier can end in a wack)
|
|
if (ch != TEXT('*')) {
|
|
if (_tcsnextc (EndOfSpace) == TEXT('\\')) {
|
|
EndOfSpace = _tcsdec2 (ObjectStart, EndOfSpace);
|
|
}
|
|
}
|
|
|
|
// Now make EndOfSpace point to the character after the end
|
|
if (EndOfSpace) { // always the case when we have a valid key
|
|
EndOfSpace = _tcsinc (EndOfSpace);
|
|
}
|
|
|
|
// Now make EndOfKey point to the first character after the key
|
|
// (which is either a nul, \*, \[valuename] or [valuename])
|
|
if (*EndOfKey) {
|
|
EndOfKey = _tcsinc (EndOfKey);
|
|
}
|
|
} else {
|
|
// no key found
|
|
EndOfSpace = NULL;
|
|
EndOfKey = ObjectStart;
|
|
}
|
|
|
|
// Decode key if it actually exists
|
|
if (ObjectStart < EndOfSpace) {
|
|
DecodeRuleCharsAB (DecodeBuf, ObjectStart, EndOfSpace);
|
|
SetRegistryKey (OutObPtr, DecodeBuf);
|
|
OutObPtr->ObjectType |= RelativeFlag;
|
|
} else {
|
|
// if HKR\*, set an empty key
|
|
if (_tcsnextc (ObjectStart) != '[' && ch == TEXT('*')) {
|
|
SetRegistryKey (OutObPtr, TEXT(""));
|
|
}
|
|
}
|
|
|
|
//
|
|
// Tree identifier exists
|
|
//
|
|
if (ch == TEXT('*')) {
|
|
OutObPtr->ObjectType |= OT_TREE;
|
|
|
|
// EndOfKey points to \*, so move it past the identifier
|
|
EndOfKey = _tcsinc (EndOfKey);
|
|
EndOfKey = _tcsinc (EndOfKey);
|
|
|
|
// If we are at a wack, skip past it.
|
|
if (_tcsnextc (EndOfKey) == TEXT('\\')) {
|
|
EndOfKey = _tcsinc (EndOfKey);
|
|
}
|
|
}
|
|
|
|
if (EndOfKey) {
|
|
ObjectStart = EndOfKey;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Value name
|
|
//
|
|
|
|
if (*ObjectStart) {
|
|
//
|
|
// ObjectStart may point to optional space
|
|
//
|
|
|
|
ObjectStart = SkipSpace (ObjectStart);
|
|
|
|
//
|
|
// ObjectStart now points to nul, [valuename] or syntax error
|
|
//
|
|
|
|
if (_tcsnextc (ObjectStart) == TEXT('[')) {
|
|
// Skip past optional spaces following bracket
|
|
ValueName = SkipSpace (_tcsinc (ObjectStart));
|
|
|
|
// Locate end of [valuename]
|
|
EndOfKey = ValueName;
|
|
while (TRUE) {
|
|
if (!(*EndOfKey)) {
|
|
DEBUGMSG ((DBG_WARNING, "CreateObjectStruct: Value name is incomplete in %s", Object));
|
|
return FALSE;
|
|
}
|
|
|
|
ch = (CHARTYPE)_tcsnextc (EndOfKey);
|
|
|
|
if (ch == TEXT(']')) {
|
|
// move to first space character before closing bracket,
|
|
// or leave it at the bracket if no space exists
|
|
EndOfKey = _tcsdec2 (ValueName, EndOfKey);
|
|
if (EndOfKey) {
|
|
EndOfKey = SkipSpaceR (ValueName, EndOfKey);
|
|
if (EndOfKey) {
|
|
EndOfKey = _tcsinc (EndOfKey);
|
|
}
|
|
} else {
|
|
EndOfKey = ValueName;
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
EndOfKey = _tcsinc (EndOfKey);
|
|
}
|
|
|
|
// Now decode ValueName, which may be empty
|
|
DecodeRuleCharsAB (DecodeBuf, ValueName, EndOfKey);
|
|
SetRegistryValueName (OutObPtr, DecodeBuf);
|
|
|
|
// Make ObjectStart point to nul
|
|
ObjectStart = SkipSpace (_tcsinc (EndOfKey));
|
|
}
|
|
|
|
if (*ObjectStart) {
|
|
DEBUGMSG ((DBG_WARNING, "CreateObjectStruct: %s does not have a valid value name", Object));
|
|
return FALSE;
|
|
}
|
|
}
|
|
|
|
//
|
|
// The next line is normally disabled, and is enabled only when
|
|
// tracking is needed.
|
|
//
|
|
|
|
//DebugRegisterAllocation (MERGE_OBJECT, OutObPtr, File, Line);
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
BOOL
|
|
CombineObjectStructs (
|
|
IN OUT PDATAOBJECT DestObPtr,
|
|
IN CPDATAOBJECT SrcObPtr
|
|
)
|
|
{
|
|
if (!SrcObPtr->ObjectType) {
|
|
DEBUGMSG ((DBG_WARNING, "CombineObjectStructs: Source is empty"));
|
|
return TRUE;
|
|
}
|
|
|
|
// The values and handles are no longer valid
|
|
FreeObjectVal (DestObPtr);
|
|
CloseObject (DestObPtr);
|
|
|
|
// Registry object merging
|
|
if (DestObPtr->ObjectType & OT_REGISTRY || !DestObPtr->ObjectType) {
|
|
if (SrcObPtr->ObjectType & OT_REGISTRY) {
|
|
//
|
|
// Verify objects are compatible
|
|
//
|
|
|
|
if ((SrcObPtr->ObjectType & OT_TREE) &&
|
|
(DestObPtr->ValueName)
|
|
) {
|
|
DEBUGMSG ((DBG_WHOOPS, "Cannot combine registry tree with valuename structs"));
|
|
return FALSE;
|
|
}
|
|
|
|
if ((DestObPtr->ObjectType & OT_TREE) &&
|
|
(SrcObPtr->ValueName)
|
|
) {
|
|
DEBUGMSG ((DBG_WHOOPS, "Cannot combine registry tree with valuename structs"));
|
|
return FALSE;
|
|
}
|
|
|
|
//
|
|
// Make dest ob the same platform as src ob
|
|
//
|
|
|
|
SetPlatformType (DestObPtr, IsWin95Object (SrcObPtr));
|
|
|
|
//
|
|
// Copy source's value name, key, type and root to dest
|
|
// (if they exist)
|
|
//
|
|
|
|
if (SrcObPtr->ValueName) {
|
|
SetRegistryValueName (DestObPtr, SrcObPtr->ValueName);
|
|
}
|
|
|
|
if (SrcObPtr->KeyPtr) {
|
|
if ((SrcObPtr->ObjectType & OT_REGISTRY_RELATIVE) &&
|
|
(DestObPtr->KeyPtr)
|
|
) {
|
|
TCHAR CompleteKeyName[MAX_ENCODED_RULE];
|
|
PTSTR p;
|
|
|
|
// Src is only specifying a key name. Peel off
|
|
// last key name of dest and replace it with
|
|
// src.
|
|
|
|
StringCopy (CompleteKeyName, DestObPtr->KeyPtr->KeyString);
|
|
p = _tcsrchr (CompleteKeyName, TEXT('\\'));
|
|
if (!p) {
|
|
p = CompleteKeyName;
|
|
} else {
|
|
p = _tcsinc (p);
|
|
}
|
|
|
|
StringCopy (p, SrcObPtr->KeyPtr->KeyString);
|
|
SetRegistryKey (DestObPtr, CompleteKeyName);
|
|
} else {
|
|
SetRegistryKey (DestObPtr, SrcObPtr->KeyPtr->KeyString);
|
|
}
|
|
}
|
|
|
|
if (SrcObPtr->ObjectType & OT_REGISTRY_TYPE) {
|
|
SetRegistryType (DestObPtr, SrcObPtr->Type);
|
|
}
|
|
|
|
if (SrcObPtr->RootItem) {
|
|
DestObPtr->RootItem = SrcObPtr->RootItem;
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
else {
|
|
DEBUGMSG ((DBG_WHOOPS, "Cannot combine registry struct with other type of struct"));
|
|
}
|
|
}
|
|
|
|
// Other type of object merging not supported
|
|
DEBUGMSG ((DBG_WHOOPS, "Cannot combine unsupported or garbage objects"));
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
BOOL
|
|
TrackedDuplicateObjectStruct (
|
|
OUT PDATAOBJECT DestObPtr,
|
|
IN CPDATAOBJECT SrcObPtr /* , */
|
|
ALLOCATION_TRACKING_DEF
|
|
)
|
|
{
|
|
ZeroMemory (DestObPtr, sizeof (DATAOBJECT));
|
|
|
|
//
|
|
// Create an object that has the same settings as the source,
|
|
// but duplicate all strings.
|
|
//
|
|
|
|
if (SrcObPtr->ObjectType & OT_REGISTRY) {
|
|
DestObPtr->ObjectType |= OT_REGISTRY;
|
|
}
|
|
|
|
if (SrcObPtr->KeyPtr) {
|
|
DestObPtr->KeyPtr = SrcObPtr->KeyPtr;
|
|
pIncKeyPropUse (DestObPtr->KeyPtr);
|
|
}
|
|
|
|
if (SrcObPtr->ValueName) {
|
|
if (!SetRegistryValueName (DestObPtr, SrcObPtr->ValueName)) {
|
|
LOG ((LOG_ERROR, "Error merging the registry (1)"));
|
|
return FALSE;
|
|
}
|
|
}
|
|
|
|
if (SrcObPtr->ObjectType & OT_VALUE) {
|
|
if (!AllocObjectVal (
|
|
DestObPtr,
|
|
SrcObPtr->Value.Buffer,
|
|
SrcObPtr->Value.Size,
|
|
SrcObPtr->Value.AllocatedSize
|
|
)) {
|
|
LOG ((LOG_ERROR, "Error merging the registry (2)"));
|
|
return FALSE;
|
|
}
|
|
}
|
|
|
|
if (SrcObPtr->ObjectType & OT_REGISTRY_TYPE) {
|
|
SetRegistryType (DestObPtr, SrcObPtr->Type);
|
|
}
|
|
|
|
DestObPtr->RootItem = SrcObPtr->RootItem;
|
|
|
|
#define DUP_OBJECT_FLAGS (OT_TREE|OT_WIN95|OT_REGISTRY_RELATIVE)
|
|
if (SrcObPtr->ObjectType & DUP_OBJECT_FLAGS) {
|
|
DestObPtr->ObjectType |= (SrcObPtr->ObjectType & DUP_OBJECT_FLAGS);
|
|
}
|
|
|
|
if (SrcObPtr->ObjectType & OT_REGISTRY_ENUM_KEY) {
|
|
DestObPtr->KeyEnum = SrcObPtr->KeyEnum;
|
|
DestObPtr->ObjectType |= OT_REGISTRY_ENUM_KEY;
|
|
}
|
|
|
|
if (SrcObPtr->ObjectType & OT_REGISTRY_ENUM_VALUENAME) {
|
|
DestObPtr->ValNameEnum = SrcObPtr->ValNameEnum;
|
|
DestObPtr->ObjectType |= OT_REGISTRY_ENUM_VALUENAME;
|
|
}
|
|
|
|
if (SrcObPtr->ObjectType & OT_REGISTRY_CLASS) {
|
|
if (!SetRegistryClass (DestObPtr, SrcObPtr->Class.Buffer, SrcObPtr->Class.Size)) {
|
|
LOG ((LOG_ERROR, "Error merging the registry (3)"));
|
|
return FALSE;
|
|
}
|
|
}
|
|
|
|
//
|
|
// The next line is normally disabled, and is enabled only when
|
|
// tracking is needed.
|
|
//
|
|
|
|
//DebugRegisterAllocation (MERGE_OBJECT, DestObPtr, File, Line);
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
BOOL
|
|
AllocObjectVal (
|
|
IN OUT PDATAOBJECT SrcObPtr,
|
|
IN PBYTE Value, OPTIONAL
|
|
IN DWORD Size,
|
|
IN DWORD AllocatedSize
|
|
)
|
|
{
|
|
SrcObPtr->Value.Buffer = PoolMemGetAlignedMemory (g_TempPool, AllocatedSize);
|
|
if (!SrcObPtr->Value.Buffer) {
|
|
DEBUGMSG ((DBG_WARNING, "AllocObjectVal failed to alloc memory"));
|
|
return FALSE;
|
|
}
|
|
|
|
SrcObPtr->Value.AllocatedSize = AllocatedSize;
|
|
SrcObPtr->Value.Size = Size;
|
|
|
|
if (Value) {
|
|
CopyMemory (SrcObPtr->Value.Buffer, Value, AllocatedSize);
|
|
}
|
|
|
|
SrcObPtr->ObjectType |= OT_VALUE;
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
VOID
|
|
FreeObjectVal (
|
|
IN OUT PDATAOBJECT SrcObPtr
|
|
)
|
|
{
|
|
if (SrcObPtr->ObjectType & OT_VALUE) {
|
|
PoolMemReleaseMemory (g_TempPool, SrcObPtr->Value.Buffer);
|
|
SrcObPtr->Value.Buffer = NULL;
|
|
SrcObPtr->ObjectType &= ~OT_VALUE;
|
|
}
|
|
}
|
|
|
|
|
|
VOID
|
|
CloseObject (
|
|
IN OUT PDATAOBJECT SrcObPtr
|
|
)
|
|
{
|
|
if (!(SrcObPtr->ObjectType & OT_OPEN)) {
|
|
return;
|
|
}
|
|
|
|
MYASSERT (IsRegistryKeyOpen (SrcObPtr));
|
|
|
|
|
|
SrcObPtr->KeyPtr->OpenCount -= 1;
|
|
|
|
if (!SrcObPtr->KeyPtr->OpenCount) {
|
|
|
|
if (NON_ROOT_KEY (SrcObPtr->KeyPtr->OpenKey)) {
|
|
|
|
if (IsWin95Object (SrcObPtr)) {
|
|
CloseRegKey95 (SrcObPtr->KeyPtr->OpenKey);
|
|
} else {
|
|
CloseRegKey (SrcObPtr->KeyPtr->OpenKey);
|
|
}
|
|
}
|
|
|
|
SrcObPtr->KeyPtr->OpenKey = NULL;
|
|
}
|
|
|
|
SrcObPtr->ObjectType &= ~OT_OPEN;
|
|
}
|
|
|
|
|
|
VOID
|
|
FreeObjectStruct (
|
|
IN OUT PDATAOBJECT SrcObPtr
|
|
)
|
|
{
|
|
PushError();
|
|
|
|
//
|
|
// The next line is normally disabled, and is enabled only when
|
|
// tracking is needed.
|
|
//
|
|
|
|
//DebugUnregisterAllocation (MERGE_OBJECT, SrcObPtr);
|
|
|
|
FreeObjectVal (SrcObPtr);
|
|
|
|
if (SrcObPtr->KeyPtr) {
|
|
pFreeKeyProps (SrcObPtr->KeyPtr);
|
|
}
|
|
if (SrcObPtr->ParentKeyPtr) {
|
|
pFreeKeyProps (SrcObPtr->ParentKeyPtr);
|
|
}
|
|
if (SrcObPtr->ValueName) {
|
|
PoolMemReleaseMemory (g_TempPool, (PVOID) SrcObPtr->ValueName);
|
|
}
|
|
if (SrcObPtr->ObjectType & OT_REGISTRY_CLASS) {
|
|
PoolMemReleaseMemory (g_TempPool, (PVOID) SrcObPtr->Class.Buffer);
|
|
}
|
|
|
|
ZeroMemory (SrcObPtr, sizeof (DATAOBJECT));
|
|
PopError();
|
|
}
|
|
|
|
BOOL
|
|
CreateObject (
|
|
IN OUT PDATAOBJECT SrcObPtr
|
|
)
|
|
{
|
|
DWORD rc;
|
|
DWORD DontCare;
|
|
PTSTR ClassPtr;
|
|
|
|
if (SrcObPtr->ObjectType & OT_OPEN) {
|
|
return TRUE;
|
|
}
|
|
|
|
if (SrcObPtr->KeyPtr) {
|
|
if (SrcObPtr->KeyPtr->OpenKey) {
|
|
SrcObPtr->ObjectType |= OT_OPEN;
|
|
SrcObPtr->KeyPtr->OpenCount++;
|
|
return TRUE;
|
|
}
|
|
|
|
if (IsWin95Object (SrcObPtr)) {
|
|
DEBUGMSG ((DBG_WHOOPS, "Cannot create Win95 registry objects (%s)", SrcObPtr->KeyPtr->KeyString));
|
|
return FALSE;
|
|
}
|
|
|
|
if (!SrcObPtr->KeyPtr->KeyString[0]) {
|
|
// This is the root of a hive
|
|
return OpenObject (SrcObPtr);
|
|
}
|
|
|
|
if (SrcObPtr->ObjectType & OT_REGISTRY_CLASS) {
|
|
ClassPtr = (PTSTR) SrcObPtr->Class.Buffer;
|
|
} else {
|
|
ClassPtr = TEXT("");
|
|
}
|
|
|
|
if (SrcObPtr->ParentKeyPtr && SrcObPtr->ParentKeyPtr->OpenKey && SrcObPtr->ChildKey) {
|
|
rc = TrackedRegCreateKeyEx (
|
|
SrcObPtr->ParentKeyPtr->OpenKey,
|
|
SrcObPtr->ChildKey,
|
|
0, ClassPtr, 0,
|
|
KEY_ALL_ACCESS, NULL,
|
|
&SrcObPtr->KeyPtr->OpenKey,
|
|
&DontCare
|
|
);
|
|
} else {
|
|
rc = TrackedRegCreateKeyEx (
|
|
pGetWinNTKey (GetRootKeyFromOffset (SrcObPtr->RootItem)),
|
|
SrcObPtr->KeyPtr->KeyString,
|
|
0,
|
|
ClassPtr,
|
|
0,
|
|
KEY_ALL_ACCESS,
|
|
NULL,
|
|
&SrcObPtr->KeyPtr->OpenKey,
|
|
&DontCare
|
|
);
|
|
}
|
|
|
|
if (rc == ERROR_INVALID_PARAMETER) {
|
|
//
|
|
// Attempt was made to create a key directly under HKLM. There is no
|
|
// backing storage, so the RegCreateKeyEx call failed with this error.
|
|
// We handle it gracefully...
|
|
//
|
|
|
|
DEBUGMSG ((DBG_WARNING, "CreateObject: Not possible to create %s on NT", SrcObPtr->KeyPtr->KeyString));
|
|
SetLastError (ERROR_SUCCESS);
|
|
return FALSE;
|
|
}
|
|
|
|
if (rc == ERROR_ACCESS_DENIED) {
|
|
//
|
|
// Attempt was made to create a key that has a strong ACL. We'll
|
|
// just assume success in this case.
|
|
//
|
|
|
|
LOG ((
|
|
LOG_INFORMATION,
|
|
"Can't create %s because access was denied",
|
|
SrcObPtr->KeyPtr->KeyString
|
|
));
|
|
|
|
SetLastError (ERROR_SUCCESS);
|
|
return FALSE;
|
|
}
|
|
|
|
if (rc != ERROR_SUCCESS) {
|
|
SetLastError (rc);
|
|
LOG ((LOG_ERROR, "Failed to create a registry key (%s)", SrcObPtr->KeyPtr->KeyString));
|
|
return FALSE;
|
|
}
|
|
|
|
SrcObPtr->KeyPtr->OpenCount = 1;
|
|
SrcObPtr->ObjectType |= OT_OPEN;
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
BOOL
|
|
OpenObject (
|
|
IN OUT PDATAOBJECT SrcObPtr
|
|
)
|
|
{
|
|
DWORD rc = ERROR_SUCCESS;
|
|
HKEY Parent;
|
|
#if CLASS_FIELD_ENABLED
|
|
TCHAR ClassBuf[MAX_CLASS_SIZE];
|
|
DWORD ClassBufSize = MAX_CLASS_SIZE;
|
|
#endif
|
|
|
|
if (SrcObPtr->ObjectType & OT_OPEN) {
|
|
return TRUE;
|
|
}
|
|
|
|
if (SrcObPtr->KeyPtr) {
|
|
if (SrcObPtr->KeyPtr->OpenKey) {
|
|
SrcObPtr->ObjectType |= OT_OPEN;
|
|
SrcObPtr->KeyPtr->OpenCount++;
|
|
return TRUE;
|
|
}
|
|
|
|
if (IsWin95Object (SrcObPtr)) {
|
|
if (SrcObPtr->ParentKeyPtr && SrcObPtr->ParentKeyPtr->OpenKey && SrcObPtr->ChildKey) {
|
|
rc = TrackedRegOpenKeyEx95 (
|
|
SrcObPtr->ParentKeyPtr->OpenKey,
|
|
SrcObPtr->ChildKey,
|
|
0,
|
|
KEY_READ,
|
|
&SrcObPtr->KeyPtr->OpenKey
|
|
);
|
|
} else {
|
|
Parent = pGetWin95Key (GetRootKeyFromOffset (SrcObPtr->RootItem));
|
|
|
|
if (*SrcObPtr->KeyPtr->KeyString || NON_ROOT_KEY (Parent)) {
|
|
rc = TrackedRegOpenKeyEx95 (
|
|
Parent,
|
|
SrcObPtr->KeyPtr->KeyString,
|
|
0,
|
|
KEY_READ,
|
|
&SrcObPtr->KeyPtr->OpenKey
|
|
);
|
|
} else {
|
|
|
|
SrcObPtr->KeyPtr->OpenKey = Parent;
|
|
|
|
}
|
|
}
|
|
}
|
|
else {
|
|
if (SrcObPtr->ParentKeyPtr && SrcObPtr->ParentKeyPtr->OpenKey && SrcObPtr->ChildKey) {
|
|
rc = TrackedRegOpenKeyEx (
|
|
SrcObPtr->ParentKeyPtr->OpenKey,
|
|
SrcObPtr->ChildKey,
|
|
0,
|
|
KEY_ALL_ACCESS,
|
|
&SrcObPtr->KeyPtr->OpenKey
|
|
);
|
|
} else {
|
|
Parent = pGetWinNTKey (GetRootKeyFromOffset (SrcObPtr->RootItem));
|
|
|
|
if (*SrcObPtr->KeyPtr->KeyString || NON_ROOT_KEY (Parent)) {
|
|
rc = TrackedRegOpenKeyEx (
|
|
Parent,
|
|
SrcObPtr->KeyPtr->KeyString,
|
|
0,
|
|
KEY_ALL_ACCESS,
|
|
&SrcObPtr->KeyPtr->OpenKey
|
|
);
|
|
} else {
|
|
|
|
SrcObPtr->KeyPtr->OpenKey = Parent;
|
|
|
|
}
|
|
}
|
|
}
|
|
|
|
if (rc != ERROR_SUCCESS) {
|
|
SetLastError (rc);
|
|
return FALSE;
|
|
}
|
|
|
|
SrcObPtr->ObjectType |= OT_OPEN;
|
|
SrcObPtr->KeyPtr->OpenCount = 1;
|
|
|
|
#if CLASS_FIELD_ENABLED
|
|
// Get the key's class
|
|
if (IsWin95Object (SrcObPtr)) {
|
|
rc = Win95RegQueryInfoKey (pGetWin95Key (SrcObPtr->RootKey),
|
|
ClassBuf,
|
|
&ClassBufSize,
|
|
NULL, // reserved
|
|
NULL, // sub key count
|
|
NULL, // max sub key len
|
|
NULL, // max class len
|
|
NULL, // values
|
|
NULL, // max value name len
|
|
NULL, // max value len
|
|
NULL, // security desc
|
|
NULL // last write time
|
|
);
|
|
} else {
|
|
rc = WinNTRegQueryInfoKey (pGetWin95Key (SrcObPtr->RootKey),
|
|
ClassBuf,
|
|
&ClassBufSize,
|
|
NULL, // reserved
|
|
NULL, // sub key count
|
|
|
|
NULL, // max sub key len
|
|
NULL, // max class len
|
|
NULL, // values
|
|
NULL, // max value name len
|
|
NULL, // max value len
|
|
NULL, // security desc
|
|
NULL // last write time
|
|
);
|
|
}
|
|
|
|
if (rc == ERROR_SUCCESS) {
|
|
DEBUGMSG ((DBG_VERBOSE, "Class size is %u for %s\\%s", ClassBufSize,
|
|
GetRootStringFromOffset (SrcObPtr->RootItem), SrcObPtr->KeyPtr->KeyString));
|
|
SetRegistryClass (SrcObPtr, ClassBuf, ClassBufSize);
|
|
}
|
|
#endif
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
VOID
|
|
pFixRegSzTermination (
|
|
IN OUT PDATAOBJECT SrcObPtr
|
|
)
|
|
{
|
|
BOOL addNul = FALSE;
|
|
PTSTR end;
|
|
PBYTE oldBuf;
|
|
UINT oldSize;
|
|
|
|
if (SrcObPtr->Type == REG_SZ || SrcObPtr->Type == REG_EXPAND_SZ) {
|
|
|
|
if (SrcObPtr->Value.Size & 1) {
|
|
//
|
|
// Force type to REG_NONE because we assume all REG_SZ
|
|
// and REG_EXPAND_SZ values are truncated.
|
|
//
|
|
|
|
SrcObPtr->Type = REG_NONE;
|
|
DEBUGMSG ((
|
|
DBG_WARNING,
|
|
"Truncation occurred because of odd string size for %s",
|
|
DebugEncoder (SrcObPtr)
|
|
));
|
|
} else {
|
|
|
|
//
|
|
// Check if we need to append a nul.
|
|
//
|
|
|
|
addNul = FALSE;
|
|
oldBuf = SrcObPtr->Value.Buffer;
|
|
oldSize = SrcObPtr->Value.Size;
|
|
|
|
if (oldSize < sizeof (TCHAR)) {
|
|
addNul = TRUE;
|
|
} else {
|
|
end = (PTSTR) (oldBuf + oldSize - sizeof (TCHAR));
|
|
addNul = (*end != 0);
|
|
}
|
|
|
|
if (addNul) {
|
|
if (AllocObjectVal (SrcObPtr, NULL, oldSize, oldSize + sizeof (TCHAR))) {
|
|
|
|
CopyMemory (SrcObPtr->Value.Buffer, oldBuf, oldSize);
|
|
end = (PTSTR) (SrcObPtr->Value.Buffer + oldSize);
|
|
*end = 0;
|
|
|
|
PoolMemReleaseMemory (g_TempPool, oldBuf);
|
|
} else {
|
|
SrcObPtr->Type = REG_NONE;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
BOOL
|
|
ReadObject (
|
|
IN OUT PDATAOBJECT SrcObPtr
|
|
)
|
|
{
|
|
return ReadObjectEx (SrcObPtr, FALSE);
|
|
}
|
|
|
|
BOOL
|
|
ReadObjectEx (
|
|
IN OUT PDATAOBJECT SrcObPtr,
|
|
IN BOOL QueryOnly
|
|
)
|
|
{
|
|
DWORD rc;
|
|
DWORD ReqSize;
|
|
|
|
// Skip if value has already been read
|
|
if (SrcObPtr->ObjectType & OT_VALUE) {
|
|
return TRUE;
|
|
}
|
|
|
|
// If registry key and valuename, query Win95 registry
|
|
if (IsObjectRegistryKeyAndVal (SrcObPtr)) {
|
|
// Open key if necessary
|
|
if (!OpenObject (SrcObPtr)) {
|
|
DEBUGMSG ((DBG_VERBOSE, "ReadObject failed because OpenObject failed"));
|
|
return FALSE;
|
|
}
|
|
|
|
// Get the value size
|
|
if (IsWin95Object (SrcObPtr)) {
|
|
ReqSize = 0; // Temporary fix for win95reg
|
|
rc = Win95RegQueryValueEx (SrcObPtr->KeyPtr->OpenKey,
|
|
SrcObPtr->ValueName,
|
|
NULL, &SrcObPtr->Type, NULL, &ReqSize);
|
|
|
|
} else {
|
|
rc = WinNTRegQueryValueEx (
|
|
SrcObPtr->KeyPtr->OpenKey,
|
|
SrcObPtr->ValueName,
|
|
NULL,
|
|
&SrcObPtr->Type,
|
|
NULL,
|
|
&ReqSize
|
|
);
|
|
|
|
if (rc == ERROR_ACCESS_DENIED) {
|
|
LOG ((
|
|
LOG_INFORMATION,
|
|
"Access denied for query of %s in %s",
|
|
SrcObPtr->ValueName,
|
|
SrcObPtr->KeyPtr->KeyString
|
|
));
|
|
ReqSize = 1;
|
|
SrcObPtr->Type = REG_NONE;
|
|
}
|
|
}
|
|
|
|
if (rc != ERROR_SUCCESS) {
|
|
|
|
DEBUGMSG_IF ((rc != ERROR_FILE_NOT_FOUND, DBG_WARNING,
|
|
"ReadObject failed for %s (type: %x)",
|
|
DebugEncoder (SrcObPtr), SrcObPtr->ObjectType));
|
|
|
|
DEBUGMSG_IF ((
|
|
!QueryOnly && rc == ERROR_FILE_NOT_FOUND,
|
|
DBG_WARNING,
|
|
"Object %s not found",
|
|
DebugEncoder (SrcObPtr)
|
|
));
|
|
|
|
SetLastError (rc);
|
|
return FALSE;
|
|
}
|
|
|
|
// Query only is used to see if the object exists
|
|
if (QueryOnly) {
|
|
return TRUE;
|
|
}
|
|
|
|
// Allocate a buffer for the value
|
|
if (!AllocObjectVal (SrcObPtr, NULL, ReqSize, ReqSize)) {
|
|
return FALSE;
|
|
}
|
|
|
|
// Get the the value
|
|
if (IsWin95Object (SrcObPtr)) {
|
|
rc = Win95RegQueryValueEx (SrcObPtr->KeyPtr->OpenKey,
|
|
SrcObPtr->ValueName,
|
|
NULL, &SrcObPtr->Type,
|
|
SrcObPtr->Value.Buffer,
|
|
&ReqSize);
|
|
} else {
|
|
rc = WinNTRegQueryValueEx (
|
|
SrcObPtr->KeyPtr->OpenKey,
|
|
SrcObPtr->ValueName,
|
|
NULL,
|
|
&SrcObPtr->Type,
|
|
SrcObPtr->Value.Buffer,
|
|
&ReqSize
|
|
);
|
|
|
|
if (rc == ERROR_ACCESS_DENIED) {
|
|
SrcObPtr->Type = REG_NONE;
|
|
SrcObPtr->Value.Size = 0;
|
|
rc = ERROR_SUCCESS;
|
|
}
|
|
}
|
|
|
|
if (rc != ERROR_SUCCESS) {
|
|
FreeObjectVal (SrcObPtr);
|
|
SetLastError (rc);
|
|
LOG ((LOG_ERROR, "Failed to read from the registry"));
|
|
return FALSE;
|
|
}
|
|
|
|
// The SrcObPtr->Type field is accurate
|
|
SrcObPtr->ObjectType |= OT_REGISTRY_TYPE;
|
|
|
|
// Fix REG_SZ or REG_EXPAND_SZ
|
|
pFixRegSzTermination (SrcObPtr);
|
|
|
|
//
|
|
// If necessary, convert the data
|
|
//
|
|
|
|
return FilterObject (SrcObPtr);
|
|
}
|
|
|
|
DEBUGMSG ((DBG_WHOOPS, "Read Object: Object type (%Xh) is not supported", SrcObPtr->ObjectType));
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
BOOL
|
|
WriteObject (
|
|
IN CPDATAOBJECT DestObPtr
|
|
)
|
|
{
|
|
DWORD rc;
|
|
|
|
// If registry key, make sure it exists
|
|
if ((DestObPtr->KeyPtr) &&
|
|
!IsWin95Object (DestObPtr)
|
|
) {
|
|
// Create or open key if necessary
|
|
if (!CreateObject (DestObPtr)) {
|
|
DEBUGMSG ((DBG_WARNING, "WriteObject: CreateObject failed for %s", DestObPtr->KeyPtr->KeyString));
|
|
return FALSE;
|
|
}
|
|
|
|
// If no value name and no value, skip
|
|
if (!(DestObPtr->ObjectType & OT_VALUE) && !(DestObPtr->ValueName)) {
|
|
return TRUE;
|
|
}
|
|
|
|
// If no type, specify it as REG_NONE
|
|
if (!IsRegistryTypeSpecified (DestObPtr)) {
|
|
SetRegistryType (DestObPtr, REG_NONE);
|
|
}
|
|
|
|
// Write the value
|
|
if (*DestObPtr->ValueName || NON_ROOT_KEY (DestObPtr->KeyPtr->OpenKey)) {
|
|
rc = WinNTRegSetValueEx (
|
|
DestObPtr->KeyPtr->OpenKey,
|
|
DestObPtr->ValueName,
|
|
0,
|
|
DestObPtr->Type,
|
|
DestObPtr->Value.Buffer,
|
|
DestObPtr->Value.Size
|
|
);
|
|
|
|
if (rc == ERROR_ACCESS_DENIED) {
|
|
//
|
|
// If access is denied, log & assume success
|
|
//
|
|
|
|
LOG ((
|
|
LOG_INFORMATION,
|
|
"Access denied; can't write registry value (%s [%s])",
|
|
DestObPtr->KeyPtr->KeyString,
|
|
DestObPtr->ValueName
|
|
));
|
|
rc = ERROR_SUCCESS;
|
|
}
|
|
|
|
} else {
|
|
rc = ERROR_SUCCESS;
|
|
}
|
|
|
|
if (rc != ERROR_SUCCESS) {
|
|
SetLastError (rc);
|
|
LOG ((LOG_ERROR, "Failed to set a registry value (%s [%s])", DestObPtr->KeyPtr->KeyString, DestObPtr->ValueName));
|
|
return FALSE;
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
DEBUGMSG ((DBG_WHOOPS, "Write Object: Object type (%Xh) is not supported", DestObPtr->ObjectType));
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
FILTERRETURN
|
|
CopySingleObject (
|
|
IN OUT PDATAOBJECT SrcObPtr,
|
|
IN OUT PDATAOBJECT DestObPtr,
|
|
IN FILTERFUNCTION FilterFn, OPTIONAL
|
|
IN PVOID FilterArg OPTIONAL
|
|
)
|
|
{
|
|
FILTERRETURN fr = FILTER_RETURN_FAIL;
|
|
DATAOBJECT TempOb;
|
|
|
|
if (!ReadObject (SrcObPtr)) {
|
|
if (GetLastError() == ERROR_FILE_NOT_FOUND) {
|
|
fr = FILTER_RETURN_CONTINUE;
|
|
}
|
|
else {
|
|
DEBUGMSG ((DBG_ERROR, "CopySingleObject: Cannot read object %s", DebugEncoder (SrcObPtr)));
|
|
}
|
|
|
|
return fr;
|
|
}
|
|
|
|
if (FilterFn) {
|
|
fr = FilterFn (SrcObPtr, DestObPtr, FILTER_VALUE_COPY, FilterArg);
|
|
if (fr != FILTER_RETURN_CONTINUE) {
|
|
|
|
// handled means skip copy but don't stop enum
|
|
if (fr == FILTER_RETURN_HANDLED) {
|
|
fr = FILTER_RETURN_CONTINUE;
|
|
}
|
|
|
|
// Debug version tells us when a filter failed
|
|
DEBUGMSG_IF ((fr == FILTER_RETURN_FAIL, DBG_VERBOSE, "CopySingleObject failed because filter function FILTER_VALUE_COPY failed"));
|
|
|
|
return fr;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Temporarily transfer SrcOb's value, value type and to DestOb
|
|
//
|
|
CopyMemory (&TempOb, DestObPtr, sizeof (DATAOBJECT));
|
|
|
|
DestObPtr->ObjectType |= SrcObPtr->ObjectType & (OT_VALUE|OT_REGISTRY_TYPE|OT_REGISTRY_CLASS);
|
|
DestObPtr->Value.Buffer = SrcObPtr->Value.Buffer;
|
|
DestObPtr->Value.Size = SrcObPtr->Value.Size;
|
|
DestObPtr->Class.Buffer = SrcObPtr->Class.Buffer;
|
|
DestObPtr->Class.Size = SrcObPtr->Class.Size;
|
|
DestObPtr->Type = SrcObPtr->Type;
|
|
|
|
//
|
|
// Write the dest ob
|
|
//
|
|
|
|
if (WriteObject (DestObPtr)) {
|
|
fr = FILTER_RETURN_CONTINUE;
|
|
} else {
|
|
DEBUGMSG ((DBG_ERROR, "CopySingleObject: Cannot write object %s", DebugEncoder (DestObPtr)));
|
|
}
|
|
|
|
//
|
|
// Restore the dest ob
|
|
//
|
|
|
|
CopyMemory (DestObPtr, &TempOb, sizeof (DATAOBJECT));
|
|
|
|
return fr;
|
|
}
|
|
|
|
|
|
FILTERRETURN
|
|
NextSubObjectEnum (
|
|
IN PDATAOBJECT RootSrcObPtr,
|
|
IN PDATAOBJECT RootDestObPtr, OPTIONAL
|
|
OUT PDATAOBJECT SubSrcObPtr,
|
|
OUT PDATAOBJECT SubDestObPtr,
|
|
IN FILTERFUNCTION FilterFn, OPTIONAL
|
|
IN PVOID FilterArg OPTIONAL
|
|
)
|
|
{
|
|
DWORD rc;
|
|
FILTERRETURN fr = FILTER_RETURN_FAIL;
|
|
PTSTR NewKey;
|
|
TCHAR KeyNameBuf[MAX_REGISTRY_KEY];
|
|
DWORD KeyNameBufSize;
|
|
TCHAR ClassBuf[MAX_CLASS_SIZE];
|
|
DWORD ClassBufSize;
|
|
FILETIME DontCare;
|
|
BOOL CreatedSubOb = FALSE;
|
|
|
|
if (IsObjectRegistryKeyOnly (RootSrcObPtr)) {
|
|
do {
|
|
MYASSERT (RootSrcObPtr->KeyPtr->OpenKey);
|
|
KeyNameBufSize = MAX_REGISTRY_KEY;
|
|
ClassBufSize = MAX_CLASS_SIZE;
|
|
fr = FILTER_RETURN_FAIL;
|
|
|
|
//
|
|
// Enumerate the next sub object
|
|
//
|
|
|
|
if (IsWin95Object (RootSrcObPtr)) {
|
|
rc = Win95RegEnumKey (
|
|
RootSrcObPtr->KeyPtr->OpenKey,
|
|
RootSrcObPtr->KeyEnum,
|
|
KeyNameBuf,
|
|
KeyNameBufSize
|
|
);
|
|
|
|
ClassBufSize = 0;
|
|
} else {
|
|
rc = WinNTRegEnumKeyEx (
|
|
RootSrcObPtr->KeyPtr->OpenKey,
|
|
RootSrcObPtr->KeyEnum,
|
|
KeyNameBuf,
|
|
&KeyNameBufSize,
|
|
NULL, // reserved
|
|
ClassBuf,
|
|
&ClassBufSize,
|
|
&DontCare // last write time
|
|
);
|
|
|
|
if (rc == ERROR_ACCESS_DENIED) {
|
|
LOG ((
|
|
LOG_INFORMATION,
|
|
"Access denied for enumeration of %s",
|
|
RootSrcObPtr->KeyPtr->KeyString
|
|
));
|
|
rc = ERROR_NO_MORE_ITEMS;
|
|
}
|
|
|
|
}
|
|
|
|
if (rc != ERROR_SUCCESS) {
|
|
SetLastError (rc);
|
|
if (rc == ERROR_NO_MORE_ITEMS) {
|
|
fr = FILTER_RETURN_DONE;
|
|
}
|
|
|
|
return fr;
|
|
}
|
|
|
|
//
|
|
// Create sub source object
|
|
//
|
|
|
|
CreatedSubOb = TRUE;
|
|
|
|
ZeroMemory (SubSrcObPtr, sizeof (DATAOBJECT));
|
|
SubSrcObPtr->ObjectType = RootSrcObPtr->ObjectType & (OT_WIN95|OT_TREE);
|
|
SubSrcObPtr->RootItem = RootSrcObPtr->RootItem;
|
|
SubSrcObPtr->ParentKeyPtr = RootSrcObPtr->KeyPtr;
|
|
pIncKeyPropUse (SubSrcObPtr->ParentKeyPtr);
|
|
|
|
MYASSERT (KeyNameBuf && *KeyNameBuf);
|
|
|
|
NewKey = JoinPaths (RootSrcObPtr->KeyPtr->KeyString, KeyNameBuf);
|
|
SetRegistryKey (SubSrcObPtr, NewKey);
|
|
FreePathString (NewKey);
|
|
|
|
SubSrcObPtr->ChildKey = _tcsrchr (SubSrcObPtr->KeyPtr->KeyString, TEXT('\\'));
|
|
if (SubSrcObPtr->ChildKey) {
|
|
SubSrcObPtr->ChildKey = _tcsinc (SubSrcObPtr->ChildKey);
|
|
} else {
|
|
SubSrcObPtr->ChildKey = SubSrcObPtr->KeyPtr->KeyString;
|
|
}
|
|
|
|
#if CLASS_FIELD_ENABLED
|
|
SetRegistryClass (SubSrcObPtr, ClassBuf, ClassBufSize);
|
|
#endif
|
|
|
|
//
|
|
// Create sub dest object
|
|
//
|
|
|
|
ZeroMemory (SubDestObPtr, sizeof (DATAOBJECT));
|
|
if (RootDestObPtr) {
|
|
SubDestObPtr->ObjectType = RootDestObPtr->ObjectType & OT_TREE;
|
|
SubDestObPtr->RootItem = RootDestObPtr->RootItem;
|
|
SubDestObPtr->ParentKeyPtr = RootDestObPtr->KeyPtr;
|
|
pIncKeyPropUse (SubDestObPtr->ParentKeyPtr);
|
|
|
|
// let's convert KeyNameBuf if it's a path and the path changed
|
|
ConvertWin9xCmdLine (KeyNameBuf, DEBUGENCODER(SubDestObPtr), NULL);
|
|
|
|
NewKey = JoinPaths (RootDestObPtr->KeyPtr->KeyString, KeyNameBuf);
|
|
SetRegistryKey (SubDestObPtr, NewKey);
|
|
FreePathString (NewKey);
|
|
|
|
SubDestObPtr->ChildKey = _tcsrchr (SubDestObPtr->KeyPtr->KeyString, TEXT('\\'));
|
|
if (SubDestObPtr->ChildKey) {
|
|
SubDestObPtr->ChildKey = _tcsinc (SubDestObPtr->ChildKey);
|
|
} else {
|
|
SubDestObPtr->ChildKey = SubDestObPtr->KeyPtr->KeyString;
|
|
}
|
|
|
|
#if CLASS_FIELD_ENABLED
|
|
SetRegistryClass (SubDestObPtr, ClassBuf, ClassBufSize);
|
|
#endif
|
|
}
|
|
|
|
if (FilterFn) {
|
|
fr = FilterFn (
|
|
SubSrcObPtr,
|
|
RootDestObPtr ? SubDestObPtr : NULL,
|
|
FILTER_KEY_ENUM,
|
|
FilterArg
|
|
);
|
|
|
|
if (fr == FILTER_RETURN_DELETED) {
|
|
CreatedSubOb = FALSE;
|
|
FreeObjectStruct (SubSrcObPtr);
|
|
FreeObjectStruct (SubDestObPtr);
|
|
}
|
|
|
|
// Debug version tells us when a filter fails
|
|
DEBUGMSG_IF ((
|
|
fr == FILTER_RETURN_FAIL,
|
|
DBG_VERBOSE,
|
|
"NextSubObjectEnum failed because filter function FILTER_KEY_ENUM failed"
|
|
));
|
|
|
|
} else {
|
|
fr = FILTER_RETURN_CONTINUE;
|
|
}
|
|
} while (fr == FILTER_RETURN_DELETED);
|
|
|
|
RootSrcObPtr->KeyEnum += 1;
|
|
}
|
|
|
|
if (fr != FILTER_RETURN_CONTINUE && fr != FILTER_RETURN_HANDLED) {
|
|
if (CreatedSubOb) {
|
|
FreeObjectStruct (SubSrcObPtr);
|
|
FreeObjectStruct (SubDestObPtr);
|
|
}
|
|
}
|
|
|
|
return fr;
|
|
}
|
|
|
|
|
|
BOOL
|
|
BeginSubObjectEnum (
|
|
IN PDATAOBJECT RootSrcObPtr,
|
|
IN PDATAOBJECT RootDestObPtr, OPTIONAL
|
|
OUT PDATAOBJECT SubSrcObPtr,
|
|
OUT PDATAOBJECT SubDestObPtr,
|
|
IN FILTERFUNCTION FilterFn, OPTIONAL
|
|
IN PVOID FilterArg OPTIONAL
|
|
)
|
|
{
|
|
if (IsObjectRegistryKeyOnly (RootSrcObPtr)) {
|
|
// Open key if necessary
|
|
if (!OpenObject (RootSrcObPtr)) {
|
|
if (GetLastError() == ERROR_FILE_NOT_FOUND) {
|
|
return FILTER_RETURN_DONE;
|
|
}
|
|
DEBUGMSG ((DBG_WARNING, "BeginSubObjectEnum: Can't open %s", DebugEncoder (RootSrcObPtr)));
|
|
return FILTER_RETURN_FAIL;
|
|
}
|
|
|
|
RootSrcObPtr->KeyEnum = 0;
|
|
|
|
return NextSubObjectEnum (RootSrcObPtr, RootDestObPtr, SubSrcObPtr, SubDestObPtr, FilterFn, FilterArg);
|
|
}
|
|
|
|
// Other object types do not have sub objects
|
|
DEBUGMSG ((DBG_WARNING, "BeginSubObjectEnum: Trying to enumerate unknown object"));
|
|
return FILTER_RETURN_FAIL;
|
|
}
|
|
|
|
|
|
FILTERRETURN
|
|
NextValueNameEnum (
|
|
IN PDATAOBJECT RootSrcObPtr,
|
|
IN PDATAOBJECT RootDestObPtr, OPTIONAL
|
|
OUT PDATAOBJECT ValSrcObPtr,
|
|
OUT PDATAOBJECT ValDestObPtr,
|
|
IN FILTERFUNCTION FilterFn, OPTIONAL
|
|
IN PVOID FilterArg OPTIONAL
|
|
)
|
|
{
|
|
DWORD rc;
|
|
FILTERRETURN fr = FILTER_RETURN_FAIL;
|
|
TCHAR ValNameBuf[MAX_REGISTRY_VALUE_NAME];
|
|
DWORD ValNameBufSize = MAX_REGISTRY_VALUE_NAME;
|
|
BOOL CreatedValOb = FALSE;
|
|
|
|
if (IsObjectRegistryKeyOnly (RootSrcObPtr)) {
|
|
MYASSERT (IsRegistryKeyOpen (RootSrcObPtr));
|
|
|
|
if (IsWin95Object (RootSrcObPtr)) {
|
|
rc = Win95RegEnumValue (
|
|
RootSrcObPtr->KeyPtr->OpenKey,
|
|
RootSrcObPtr->ValNameEnum,
|
|
ValNameBuf,
|
|
&ValNameBufSize,
|
|
NULL, // reserved
|
|
NULL, // type ptr
|
|
NULL, // value data ptr
|
|
NULL // value data size ptr
|
|
);
|
|
} else {
|
|
rc = WinNTRegEnumValue (
|
|
RootSrcObPtr->KeyPtr->OpenKey,
|
|
RootSrcObPtr->ValNameEnum,
|
|
ValNameBuf,
|
|
&ValNameBufSize,
|
|
NULL, // reserved
|
|
NULL, // type ptr
|
|
NULL, // value data ptr
|
|
NULL // value data size ptr
|
|
);
|
|
|
|
if (rc == ERROR_ACCESS_DENIED) {
|
|
LOG ((
|
|
LOG_INFORMATION,
|
|
"Access denied for enumeration of values in %s",
|
|
RootSrcObPtr->KeyPtr->KeyString
|
|
));
|
|
rc = ERROR_NO_MORE_ITEMS;
|
|
}
|
|
}
|
|
|
|
if (rc != ERROR_SUCCESS) {
|
|
SetLastError (rc);
|
|
if (rc == ERROR_NO_MORE_ITEMS) {
|
|
fr = FILTER_RETURN_DONE;
|
|
} else {
|
|
LOG ((LOG_ERROR, "Failed to enumerate a registry value"));
|
|
}
|
|
|
|
return fr;
|
|
}
|
|
|
|
//
|
|
// Create src value object
|
|
//
|
|
|
|
CreatedValOb = TRUE;
|
|
ZeroMemory (ValSrcObPtr, sizeof (DATAOBJECT));
|
|
|
|
ValSrcObPtr->ObjectType = RootSrcObPtr->ObjectType & OT_WIN95; // (OT_WIN95|OT_TREE) removed
|
|
ValSrcObPtr->RootItem = RootSrcObPtr->RootItem;
|
|
ValSrcObPtr->ParentKeyPtr = RootSrcObPtr->KeyPtr;
|
|
pIncKeyPropUse (ValSrcObPtr->ParentKeyPtr);
|
|
ValSrcObPtr->KeyPtr = RootSrcObPtr->KeyPtr;
|
|
pIncKeyPropUse (ValSrcObPtr->KeyPtr);
|
|
|
|
if (rc == ERROR_SUCCESS) {
|
|
SetRegistryValueName (ValSrcObPtr, ValNameBuf);
|
|
} else {
|
|
SetRegistryValueName (ValSrcObPtr, TEXT(""));
|
|
}
|
|
|
|
//
|
|
// Create dest value object
|
|
//
|
|
|
|
CreatedValOb = TRUE;
|
|
ZeroMemory (ValDestObPtr, sizeof (DATAOBJECT));
|
|
if (RootDestObPtr) {
|
|
ValDestObPtr->RootItem = RootDestObPtr->RootItem;
|
|
ValDestObPtr->ParentKeyPtr = RootDestObPtr->KeyPtr;
|
|
pIncKeyPropUse (ValDestObPtr->ParentKeyPtr);
|
|
ValDestObPtr->KeyPtr = RootDestObPtr->KeyPtr;
|
|
pIncKeyPropUse (ValDestObPtr->KeyPtr);
|
|
|
|
// let's convert ValNameBuf if it's a path and the path changed
|
|
ConvertWin9xCmdLine (ValNameBuf, DEBUGENCODER(ValDestObPtr), NULL);
|
|
|
|
if (rc == ERROR_SUCCESS) {
|
|
SetRegistryValueName (ValDestObPtr, ValNameBuf);
|
|
} else {
|
|
SetRegistryValueName (ValDestObPtr, TEXT(""));
|
|
}
|
|
}
|
|
|
|
if (FilterFn) {
|
|
fr = FilterFn (
|
|
ValSrcObPtr,
|
|
RootDestObPtr ? ValDestObPtr : NULL,
|
|
FILTER_VALUENAME_ENUM,
|
|
FilterArg
|
|
);
|
|
|
|
// Debug version tells us when a filter fails
|
|
DEBUGMSG_IF ((fr == FILTER_RETURN_FAIL, DBG_VERBOSE, "NextValueNameEnum failed because filter function FILTER_VALUENAME_ENUM failed"));
|
|
|
|
} else {
|
|
fr = FILTER_RETURN_CONTINUE;
|
|
}
|
|
|
|
RootSrcObPtr->ValNameEnum += 1;
|
|
}
|
|
|
|
if (fr != FILTER_RETURN_CONTINUE && fr != FILTER_RETURN_HANDLED) {
|
|
if (CreatedValOb) {
|
|
FreeObjectStruct (ValSrcObPtr);
|
|
FreeObjectStruct (ValDestObPtr);
|
|
}
|
|
}
|
|
|
|
return fr;
|
|
}
|
|
|
|
|
|
FILTERRETURN
|
|
BeginValueNameEnum (
|
|
IN PDATAOBJECT RootSrcObPtr,
|
|
IN PDATAOBJECT RootDestObPtr, OPTIONAL
|
|
OUT PDATAOBJECT ValSrcObPtr,
|
|
OUT PDATAOBJECT ValDestObPtr,
|
|
IN FILTERFUNCTION FilterFn, OPTIONAL
|
|
IN PVOID FilterArg OPTIONAL
|
|
)
|
|
{
|
|
if (IsObjectRegistryKeyOnly (RootSrcObPtr)) {
|
|
// Open key if necessary
|
|
if (!OpenObject (RootSrcObPtr)) {
|
|
if (GetLastError() == ERROR_FILE_NOT_FOUND) {
|
|
return FILTER_RETURN_DONE;
|
|
}
|
|
DEBUGMSG ((DBG_WARNING, "BeginValueNameEnum: Can't open %s", DebugEncoder (RootSrcObPtr)));
|
|
return FILTER_RETURN_FAIL;
|
|
}
|
|
|
|
RootSrcObPtr->ValNameEnum = 0;
|
|
|
|
return NextValueNameEnum (RootSrcObPtr, RootDestObPtr, ValSrcObPtr, ValDestObPtr, FilterFn, FilterArg);
|
|
}
|
|
|
|
// Other object types do not have sub objects
|
|
DEBUGMSG ((DBG_WARNING, "BeginValueNameEnum: Trying to enumerate unknown object"));
|
|
return FILTER_RETURN_FAIL;
|
|
}
|
|
|
|
|
|
FILTERRETURN
|
|
CopyObject (
|
|
IN PDATAOBJECT SrcObPtr,
|
|
IN CPDATAOBJECT DestObPtr, OPTIONAL
|
|
IN FILTERFUNCTION FilterFn, OPTIONAL
|
|
IN PVOID FilterArg OPTIONAL
|
|
)
|
|
{
|
|
DATAOBJECT ChildOb, ChildDestOb;
|
|
FILTERRETURN fr = FILTER_RETURN_FAIL;
|
|
BOOL suppressKey = FALSE;
|
|
|
|
//
|
|
// Progress bar update
|
|
//
|
|
g_ProgressBarCounter++;
|
|
if (g_ProgressBarCounter >= REGMERGE_TICK_THRESHOLD) {
|
|
g_ProgressBarCounter = 0;
|
|
TickProgressBar ();
|
|
}
|
|
|
|
//
|
|
// Tree copy
|
|
//
|
|
if (SrcObPtr->ObjectType & OT_TREE) {
|
|
if (DestObPtr) {
|
|
#ifdef DEBUG
|
|
//
|
|
// Verify destination does not specify value but does specify key
|
|
//
|
|
|
|
if (!IsObjectRegistryKeyOnly (DestObPtr)) {
|
|
DEBUGMSG ((
|
|
DBG_WHOOPS,
|
|
"CopyObject: Destination invalid for copy %s tree",
|
|
DebugEncoder (SrcObPtr)
|
|
));
|
|
|
|
return FILTER_RETURN_FAIL;
|
|
}
|
|
#endif
|
|
|
|
// The source object cannot specify a registry value either
|
|
MYASSERT (!(SrcObPtr->ValueName));
|
|
|
|
#ifndef VAR_PROGRESS_BAR
|
|
//
|
|
// Progress bar update
|
|
//
|
|
g_ProgressBarCounter++;
|
|
if (g_ProgressBarCounter >= REGMERGE_TICK_THRESHOLD) {
|
|
g_ProgressBarCounter = 0;
|
|
TickProgressBarDelta (1);
|
|
}
|
|
#endif
|
|
//
|
|
// Ask the filter if it wants to create the key unconditionally
|
|
//
|
|
|
|
if (FilterFn) {
|
|
|
|
//
|
|
// suppressKey should never be set if filterFn exists.
|
|
//
|
|
MYASSERT (!suppressKey)
|
|
|
|
fr = FilterFn (SrcObPtr, DestObPtr, FILTER_CREATE_KEY, FilterArg);
|
|
|
|
if (fr == FILTER_RETURN_FAIL || fr == FILTER_RETURN_DONE) {
|
|
|
|
// The done at the key create does not really mean end the whole copy!
|
|
if (fr == FILTER_RETURN_DONE) {
|
|
fr = FILTER_RETURN_CONTINUE;
|
|
}
|
|
|
|
return fr;
|
|
}
|
|
|
|
} else {
|
|
|
|
//
|
|
// Check to see if the win9x object actually exists. If not,
|
|
// we'll pass on FILTER_RETURN_DONE. We don't want to get
|
|
// empty keys created on nt where no keys existed on win9x.
|
|
//
|
|
|
|
if (!OpenObject (SrcObPtr)) {
|
|
|
|
suppressKey = TRUE;
|
|
fr = FILTER_RETURN_HANDLED;
|
|
}
|
|
else {
|
|
|
|
fr = FILTER_RETURN_CONTINUE;
|
|
}
|
|
}
|
|
|
|
if (fr == FILTER_RETURN_CONTINUE) {
|
|
|
|
if (!CreateObject (DestObPtr)) {
|
|
|
|
if (GetLastError() == ERROR_SUCCESS) {
|
|
//
|
|
// CreateObject failed but because the last error was
|
|
// ERROR_SUCCESS, we skip this registry node and continue
|
|
// processing as if the error didn't occur.
|
|
//
|
|
|
|
return FILTER_RETURN_CONTINUE;
|
|
}
|
|
else {
|
|
|
|
DEBUGMSG ((DBG_WARNING,
|
|
"CopyObject: CreateObject failed to create %s",
|
|
DebugEncoder (DestObPtr)
|
|
));
|
|
return FILTER_RETURN_FAIL;
|
|
}
|
|
}
|
|
|
|
}
|
|
}
|
|
|
|
//
|
|
// Copy all values (call CopyObject recursively)
|
|
//
|
|
|
|
SrcObPtr->ObjectType &= ~(OT_TREE);
|
|
|
|
if (FilterFn) {
|
|
|
|
//
|
|
// suppress key should never be set if there is a FilterFn.
|
|
//
|
|
MYASSERT (!suppressKey)
|
|
|
|
fr = FilterFn (SrcObPtr, DestObPtr, FILTER_PROCESS_VALUES, FilterArg);
|
|
|
|
// Debug version tells us that the filter failed
|
|
DEBUGMSG_IF ((fr == FILTER_RETURN_FAIL, DBG_VERBOSE, "CopyObject failed because filter function FILTER_PROCESS_VALUES failed"));
|
|
|
|
if (fr == FILTER_RETURN_FAIL || fr == FILTER_RETURN_DONE) {
|
|
DEBUGMSG ((DBG_VERBOSE, "CopyObject is exiting"));
|
|
SrcObPtr->ObjectType |= OT_TREE;
|
|
return fr;
|
|
}
|
|
} else {
|
|
fr = suppressKey ? FILTER_RETURN_HANDLED : FILTER_RETURN_CONTINUE;
|
|
}
|
|
|
|
//
|
|
// Skip copy of key's values if FilterFn returned FILTER_RETURN_HANDLED
|
|
//
|
|
|
|
if (fr == FILTER_RETURN_CONTINUE) {
|
|
fr = CopyObject (SrcObPtr, DestObPtr, FilterFn, FilterArg);
|
|
|
|
SrcObPtr->ObjectType |= OT_TREE;
|
|
if (fr != FILTER_RETURN_CONTINUE) {
|
|
return fr;
|
|
}
|
|
} else {
|
|
SrcObPtr->ObjectType |= OT_TREE;
|
|
}
|
|
|
|
//
|
|
// Enumerate all child objects and process them recursively
|
|
//
|
|
|
|
fr = BeginSubObjectEnum (
|
|
SrcObPtr,
|
|
DestObPtr,
|
|
&ChildOb,
|
|
&ChildDestOb,
|
|
FilterFn,
|
|
FilterArg
|
|
);
|
|
|
|
while (fr == FILTER_RETURN_CONTINUE || fr == FILTER_RETURN_HANDLED) {
|
|
|
|
if (fr == FILTER_RETURN_CONTINUE) {
|
|
fr = CopyObject (
|
|
&ChildOb,
|
|
DestObPtr ? &ChildDestOb : NULL,
|
|
FilterFn,
|
|
FilterArg
|
|
);
|
|
} else {
|
|
fr = FILTER_RETURN_CONTINUE;
|
|
}
|
|
|
|
FreeObjectStruct (&ChildOb);
|
|
FreeObjectStruct (&ChildDestOb);
|
|
|
|
if (fr != FILTER_RETURN_CONTINUE) {
|
|
return fr;
|
|
}
|
|
|
|
fr = NextSubObjectEnum (
|
|
SrcObPtr,
|
|
DestObPtr,
|
|
&ChildOb,
|
|
&ChildDestOb,
|
|
FilterFn,
|
|
FilterArg
|
|
);
|
|
}
|
|
|
|
// The end of enum does not really mean end the copy!
|
|
if (fr == FILTER_RETURN_DONE) {
|
|
fr = FILTER_RETURN_CONTINUE;
|
|
}
|
|
|
|
DEBUGMSG_IF ((fr == FILTER_RETURN_FAIL, DBG_VERBOSE,
|
|
"CopyObject: Filter in subob enum failed"));
|
|
}
|
|
|
|
//
|
|
// Copy all values of a key
|
|
//
|
|
|
|
else if (IsObjectRegistryKeyOnly (SrcObPtr)) {
|
|
|
|
#ifdef DEBUG
|
|
if (DestObPtr) {
|
|
//
|
|
// Verify destination does not specify value but does specify key
|
|
//
|
|
|
|
if (!IsObjectRegistryKeyOnly (DestObPtr)) {
|
|
DEBUGMSG ((
|
|
DBG_WHOOPS,
|
|
"CopyObject: Destination (%s) invalid for copy values in %s",
|
|
DebugEncoder (DestObPtr),
|
|
DebugEncoder (SrcObPtr)
|
|
));
|
|
|
|
return fr;
|
|
}
|
|
}
|
|
#endif
|
|
|
|
//
|
|
// Enumerate all values in the key
|
|
//
|
|
|
|
fr = BeginValueNameEnum (
|
|
SrcObPtr,
|
|
DestObPtr,
|
|
&ChildOb,
|
|
&ChildDestOb,
|
|
FilterFn,
|
|
FilterArg
|
|
);
|
|
|
|
if (fr == FILTER_RETURN_DONE) {
|
|
//
|
|
// No values in this key. Make sure DestObPtr is created.
|
|
//
|
|
|
|
if (DestObPtr && !suppressKey) {
|
|
if (!CreateObject (DestObPtr)) {
|
|
DEBUGMSG ((DBG_WARNING, "CopyObject: Could not create %s (type %x)",
|
|
DebugEncoder (DestObPtr), DestObPtr->ObjectType));
|
|
}
|
|
}
|
|
} else {
|
|
//
|
|
// For each value, call CopySingleObject
|
|
//
|
|
|
|
while (fr == FILTER_RETURN_CONTINUE || fr == FILTER_RETURN_HANDLED) {
|
|
|
|
if (fr == FILTER_RETURN_CONTINUE && DestObPtr) {
|
|
fr = CopySingleObject (&ChildOb, &ChildDestOb, FilterFn, FilterArg);
|
|
} else {
|
|
fr = FILTER_RETURN_CONTINUE;
|
|
}
|
|
|
|
FreeObjectStruct (&ChildOb);
|
|
FreeObjectStruct (&ChildDestOb);
|
|
|
|
if (fr != FILTER_RETURN_CONTINUE) {
|
|
DEBUGMSG ((DBG_VERBOSE, "CopyObject failed because CopySingleObject failed"));
|
|
return fr;
|
|
}
|
|
|
|
fr = NextValueNameEnum (
|
|
SrcObPtr,
|
|
DestObPtr,
|
|
&ChildOb,
|
|
&ChildDestOb,
|
|
FilterFn,
|
|
FilterArg
|
|
);
|
|
}
|
|
}
|
|
|
|
// The end of enum does not really mean end the copy!
|
|
if (fr == FILTER_RETURN_DONE) {
|
|
fr = FILTER_RETURN_CONTINUE;
|
|
}
|
|
|
|
DEBUGMSG_IF ((fr == FILTER_RETURN_FAIL, DBG_VERBOSE,
|
|
"CopyObject: Filter in val enum failed"));
|
|
}
|
|
|
|
//
|
|
// One value copy
|
|
//
|
|
|
|
else if (IsObjectRegistryKeyAndVal (SrcObPtr)) {
|
|
|
|
#ifdef DEBUG
|
|
if (DestObPtr) {
|
|
//
|
|
// BUGBUG -- what is this used for?
|
|
//
|
|
|
|
if (!(DestObPtr->ValueName)) {
|
|
if (!SetRegistryValueName (DestObPtr, SrcObPtr->ValueName)) {
|
|
DEBUGMSG ((DBG_VERBOSE, "CopyObject failed because SetRegistryValueName failed"));
|
|
return fr;
|
|
}
|
|
}
|
|
}
|
|
#endif
|
|
|
|
if (DestObPtr) {
|
|
fr = CopySingleObject (SrcObPtr, DestObPtr, FilterFn, FilterArg);
|
|
}
|
|
|
|
DEBUGMSG_IF ((fr == FILTER_RETURN_FAIL, DBG_VERBOSE,
|
|
"CopyObject: Filter in CopySingleObject failed"));
|
|
}
|
|
|
|
//
|
|
// Other object coping not supported
|
|
//
|
|
else {
|
|
DEBUGMSG ((
|
|
DBG_WHOOPS,
|
|
"CopyObject: Don't know how to copy object %s",
|
|
DebugEncoder (SrcObPtr)
|
|
));
|
|
}
|
|
|
|
return fr;
|
|
}
|
|
|
|
|
|
VOID
|
|
FreeRegistryKey (
|
|
PDATAOBJECT p
|
|
)
|
|
{
|
|
if (p->KeyPtr && (p->ObjectType & OT_REGISTRY)) {
|
|
pFreeKeyProps (p->KeyPtr);
|
|
p->KeyPtr = NULL;
|
|
}
|
|
}
|
|
|
|
VOID
|
|
FreeRegistryParentKey (
|
|
PDATAOBJECT p
|
|
)
|
|
{
|
|
if (p->ParentKeyPtr && (p->ObjectType & OT_REGISTRY)) {
|
|
pFreeKeyProps (p->ParentKeyPtr);
|
|
p->ParentKeyPtr = NULL;
|
|
}
|
|
}
|
|
|
|
BOOL
|
|
SetRegistryKey (
|
|
PDATAOBJECT p,
|
|
PCTSTR Key
|
|
)
|
|
{
|
|
FreeRegistryKey (p);
|
|
|
|
p->KeyPtr = pCreateKeyPropsFromString (Key, IsWin95Object (p));
|
|
if (!p->KeyPtr) {
|
|
DEBUGMSG ((DBG_WARNING, "SetRegistryKey failed to create KEYPROPS struct"));
|
|
return FALSE;
|
|
}
|
|
|
|
p->ObjectType |= OT_REGISTRY;
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
VOID
|
|
FreeRegistryValueName (
|
|
PDATAOBJECT p
|
|
)
|
|
{
|
|
if (p->ValueName && p->ObjectType & OT_REGISTRY) {
|
|
PoolMemReleaseMemory (g_TempPool, (PVOID) p->ValueName);
|
|
p->ValueName = NULL;
|
|
}
|
|
}
|
|
|
|
|
|
BOOL
|
|
SetRegistryValueName (
|
|
PDATAOBJECT p,
|
|
PCTSTR ValueName
|
|
)
|
|
{
|
|
FreeRegistryValueName (p);
|
|
p->ValueName = PoolMemDuplicateString (g_TempPool, ValueName);
|
|
if (!p->ValueName) {
|
|
DEBUGMSG ((DBG_WARNING, "SetRegistryValueName failed to duplicate string"));
|
|
return FALSE;
|
|
}
|
|
|
|
p->ObjectType |= OT_REGISTRY;
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
BOOL
|
|
SetRegistryClass (
|
|
PDATAOBJECT p,
|
|
PBYTE Class,
|
|
DWORD ClassSize
|
|
)
|
|
{
|
|
FreeRegistryClass (p);
|
|
|
|
p->Class.Buffer = PoolMemGetAlignedMemory (g_TempPool, ClassSize);
|
|
if (p->Class.Buffer) {
|
|
p->ObjectType |= OT_REGISTRY_CLASS|OT_REGISTRY;
|
|
p->Class.Size = ClassSize;
|
|
if (ClassSize) {
|
|
CopyMemory (p->Class.Buffer, Class, ClassSize);
|
|
}
|
|
} else {
|
|
p->ObjectType &= ~OT_REGISTRY_CLASS;
|
|
DEBUGMSG ((DBG_WARNING, "SetRegistryClass failed to duplicate string"));
|
|
return FALSE;
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
VOID
|
|
FreeRegistryClass (
|
|
PDATAOBJECT p
|
|
)
|
|
{
|
|
if (p->ObjectType & OT_REGISTRY_CLASS) {
|
|
PoolMemReleaseMemory (g_TempPool, (PVOID) p->Class.Buffer);
|
|
p->ObjectType &= ~OT_REGISTRY_CLASS;
|
|
}
|
|
}
|
|
|
|
VOID
|
|
SetRegistryType (
|
|
PDATAOBJECT p,
|
|
DWORD Type
|
|
)
|
|
{
|
|
p->Type = Type;
|
|
p->ObjectType |= OT_REGISTRY_TYPE|OT_REGISTRY;
|
|
}
|
|
|
|
BOOL
|
|
SetPlatformType (
|
|
PDATAOBJECT p,
|
|
BOOL Win95Type
|
|
)
|
|
{
|
|
if (Win95Type != IsWin95Object (p)) {
|
|
//
|
|
// We need to close the other platform valid handle. Otherwise
|
|
// all subsequent operations will fail because we will try to
|
|
// use an valid handle for a wrong platform.
|
|
//
|
|
CloseObject (p);
|
|
|
|
// key type is changing to be the opposite platform,
|
|
// so we have to create a duplicate key struct
|
|
// (except for the platform being different)
|
|
if (p->KeyPtr) {
|
|
p->KeyPtr = pCreateDuplicateKeyProps (p->KeyPtr, Win95Type);
|
|
if (!p->KeyPtr) {
|
|
return FALSE;
|
|
}
|
|
}
|
|
|
|
if (Win95Type) {
|
|
p->ObjectType |= OT_WIN95;
|
|
} else {
|
|
p->ObjectType &= ~OT_WIN95;
|
|
}
|
|
|
|
FreeRegistryParentKey (p);
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
BOOL
|
|
ReadWin95ObjectString (
|
|
PCTSTR ObjectStr,
|
|
PDATAOBJECT ObPtr
|
|
)
|
|
{
|
|
LONG rc = ERROR_INVALID_NAME;
|
|
BOOL b = FALSE;
|
|
|
|
if (!CreateObjectStruct (ObjectStr, ObPtr, WIN95OBJECT)) {
|
|
rc = GetLastError();
|
|
DEBUGMSG ((DBG_ERROR, "Read Win95 Object String: %s is invalid", ObjectStr));
|
|
goto c0;
|
|
}
|
|
|
|
if (!ReadObject (ObPtr)) {
|
|
rc = GetLastError();
|
|
if (rc == ERROR_FILE_NOT_FOUND || rc == ERROR_BADKEY) {
|
|
rc = ERROR_SUCCESS;
|
|
DEBUGMSG ((DBG_WARNING, "ReadWin95ObjectString: %s does not exist", ObjectStr));
|
|
}
|
|
|
|
FreeObjectStruct (ObPtr);
|
|
} else {
|
|
b = TRUE;
|
|
}
|
|
|
|
c0:
|
|
if (!b) {
|
|
SetLastError (rc);
|
|
}
|
|
|
|
return b;
|
|
}
|
|
|
|
|
|
BOOL
|
|
WriteWinNTObjectString (
|
|
PCTSTR ObjectStr,
|
|
CPDATAOBJECT SrcObPtr
|
|
)
|
|
{
|
|
DATAOBJECT DestOb, TempOb;
|
|
BOOL b = FALSE;
|
|
|
|
//
|
|
// 1. Create TempOb from destination object string
|
|
// 2. Copy SrcObPtr to DestOb
|
|
// 3. Override DestOb with any setting in TempOb
|
|
//
|
|
|
|
if (!CreateObjectStruct (ObjectStr, &TempOb, WINNTOBJECT)) {
|
|
DEBUGMSG ((DBG_ERROR, "WriteWinNTObjectString: %s struct cannot be created", ObjectStr));
|
|
goto c0;
|
|
}
|
|
|
|
if (!DuplicateObjectStruct (&DestOb, SrcObPtr)) {
|
|
goto c1;
|
|
}
|
|
|
|
if (!CombineObjectStructs (&DestOb, &TempOb)) {
|
|
goto c2;
|
|
}
|
|
|
|
MYASSERT (!(DestOb.ObjectType & OT_VALUE));
|
|
MYASSERT (SrcObPtr->ObjectType & OT_VALUE);
|
|
|
|
if (SrcObPtr->ObjectType & OT_REGISTRY_TYPE) {
|
|
DestOb.ObjectType |= OT_REGISTRY_TYPE;
|
|
DestOb.Type = SrcObPtr->Type;
|
|
}
|
|
|
|
ReplaceValue (&DestOb, SrcObPtr->Value.Buffer, SrcObPtr->Value.Size);
|
|
|
|
if (!WriteObject (&DestOb)) {
|
|
DEBUGMSG ((DBG_ERROR, "WriteWinNTObjectString: %s cannot be written", ObjectStr));
|
|
goto c2;
|
|
}
|
|
|
|
b = TRUE;
|
|
|
|
c2:
|
|
FreeObjectStruct (&DestOb);
|
|
|
|
|
|
c1:
|
|
FreeObjectStruct (&TempOb);
|
|
|
|
c0:
|
|
return b;
|
|
}
|
|
|
|
|
|
BOOL
|
|
ReplaceValue (
|
|
PDATAOBJECT ObPtr,
|
|
PBYTE NewValue,
|
|
DWORD Size
|
|
)
|
|
{
|
|
FreeObjectVal (ObPtr);
|
|
if (!AllocObjectVal (ObPtr, NewValue, Size, Size)) {
|
|
return FALSE;
|
|
}
|
|
|
|
// Fix REG_SZ or REG_EXPAND_SZ
|
|
pFixRegSzTermination (ObPtr);
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
BOOL
|
|
GetDwordFromObject (
|
|
CPDATAOBJECT ObPtr,
|
|
PDWORD DwordPtr OPTIONAL
|
|
)
|
|
{
|
|
DWORD d;
|
|
|
|
if (DwordPtr) {
|
|
*DwordPtr = 0;
|
|
}
|
|
|
|
if (!(ObPtr->ObjectType & OT_VALUE)) {
|
|
if (!ReadObject (ObPtr)) {
|
|
return FALSE;
|
|
}
|
|
}
|
|
|
|
if (!(ObPtr->ObjectType & OT_REGISTRY_TYPE)) {
|
|
return FALSE;
|
|
}
|
|
|
|
if (ObPtr->Type == REG_SZ) {
|
|
|
|
d = _tcstoul ((PCTSTR) ObPtr->Value.Buffer, NULL, 10);
|
|
|
|
} else if (
|
|
ObPtr->Type == REG_BINARY ||
|
|
ObPtr->Type == REG_NONE ||
|
|
ObPtr->Type == REG_DWORD
|
|
) {
|
|
|
|
if (ObPtr->Value.Size != sizeof (DWORD)) {
|
|
DEBUGMSG ((DBG_NAUSEA, "GetDwordFromObject: Value size is %u", ObPtr->Value.Size));
|
|
return FALSE;
|
|
}
|
|
|
|
d = *((PDWORD) ObPtr->Value.Buffer);
|
|
|
|
} else {
|
|
return FALSE;
|
|
}
|
|
|
|
if (DwordPtr) {
|
|
*DwordPtr = d;
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
PCTSTR
|
|
GetStringFromObject (
|
|
CPDATAOBJECT ObPtr
|
|
)
|
|
{
|
|
PTSTR result;
|
|
PTSTR resultPtr;
|
|
UINT i;
|
|
|
|
if (!(ObPtr->ObjectType & OT_VALUE)) {
|
|
if (!ReadObject (ObPtr)) {
|
|
return NULL;
|
|
}
|
|
}
|
|
|
|
if (!(ObPtr->ObjectType & OT_REGISTRY_TYPE)) {
|
|
return NULL;
|
|
}
|
|
|
|
if (ObPtr->Type == REG_SZ) {
|
|
result = AllocPathString (ObPtr->Value.Size);
|
|
_tcssafecpy (result, (PCTSTR) ObPtr->Value.Buffer, ObPtr->Value.Size / sizeof (TCHAR));
|
|
}
|
|
else if (ObPtr->Type == REG_DWORD) {
|
|
result = AllocPathString (11);
|
|
wsprintf (result, TEXT("%lu"), *((PDWORD) ObPtr->Value.Buffer));
|
|
}
|
|
else if (ObPtr->Type == REG_BINARY) {
|
|
result = AllocPathString (ObPtr->Value.Size?(ObPtr->Value.Size * 3):1);
|
|
resultPtr = result;
|
|
*resultPtr = 0;
|
|
for (i = 0; i < ObPtr->Value.Size; i++) {
|
|
wsprintf (resultPtr, TEXT("%02X"), ObPtr->Value.Buffer[i]);
|
|
resultPtr = GetEndOfString (resultPtr);
|
|
if (i < ObPtr->Value.Size - 1) {
|
|
_tcscat (resultPtr, TEXT(" "));
|
|
resultPtr = GetEndOfString (resultPtr);
|
|
}
|
|
}
|
|
} else {
|
|
return NULL;
|
|
}
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
FILTERRETURN
|
|
pDeleteDataObjectFilter (
|
|
IN CPDATAOBJECT SrcObjectPtr,
|
|
IN CPDATAOBJECT UnusedObPtr, OPTIONAL
|
|
IN FILTERTYPE FilterType,
|
|
IN PVOID UnusedArg OPTIONAL
|
|
)
|
|
{
|
|
if (FilterType == FILTER_KEY_ENUM) {
|
|
DeleteDataObject (SrcObjectPtr);
|
|
return FILTER_RETURN_DELETED;
|
|
}
|
|
return FILTER_RETURN_HANDLED;
|
|
}
|
|
|
|
BOOL
|
|
DeleteDataObject (
|
|
IN PDATAOBJECT ObjectPtr
|
|
)
|
|
{
|
|
FILTERRETURN fr;
|
|
DWORD rc;
|
|
|
|
ObjectPtr->ObjectType |= OT_TREE;
|
|
|
|
fr = CopyObject (ObjectPtr, NULL, pDeleteDataObjectFilter, NULL);
|
|
if (fr != FILTER_RETURN_FAIL) {
|
|
//
|
|
// Perform deletion
|
|
//
|
|
|
|
if (ObjectPtr->KeyPtr) {
|
|
CloseObject (ObjectPtr);
|
|
|
|
if (IsWin95Object (ObjectPtr)) {
|
|
DEBUGMSG ((DBG_WHOOPS, "CreateObject: Cannot delete a Win95 object (%s)", DebugEncoder (ObjectPtr)));
|
|
return FALSE;
|
|
}
|
|
|
|
if (ObjectPtr->ParentKeyPtr && ObjectPtr->ParentKeyPtr->OpenKey && ObjectPtr->ChildKey) {
|
|
rc = WinNTRegDeleteKey (
|
|
ObjectPtr->ParentKeyPtr->OpenKey,
|
|
ObjectPtr->ChildKey
|
|
);
|
|
|
|
if (rc == ERROR_ACCESS_DENIED) {
|
|
LOG ((
|
|
LOG_INFORMATION,
|
|
"Access denied trying to delete %s in %s",
|
|
ObjectPtr->ChildKey,
|
|
ObjectPtr->ParentKeyPtr->KeyString
|
|
));
|
|
rc = ERROR_SUCCESS;
|
|
}
|
|
|
|
} else {
|
|
rc = WinNTRegDeleteKey (
|
|
pGetWinNTKey (GetRootKeyFromOffset (ObjectPtr->RootItem)),
|
|
ObjectPtr->KeyPtr->KeyString
|
|
);
|
|
|
|
if (rc == ERROR_ACCESS_DENIED) {
|
|
LOG ((
|
|
LOG_INFORMATION,
|
|
"Access denied trying to delete %s",
|
|
ObjectPtr->KeyPtr->KeyString
|
|
));
|
|
rc = ERROR_SUCCESS;
|
|
}
|
|
}
|
|
|
|
if (rc != ERROR_SUCCESS) {
|
|
SetLastError (rc);
|
|
LOG ((LOG_ERROR, "Failed to delete registry key"));
|
|
return FALSE;
|
|
}
|
|
}
|
|
}
|
|
|
|
return fr != FILTER_RETURN_FAIL;
|
|
}
|
|
|
|
|
|
BOOL
|
|
RenameDataObject (
|
|
IN CPDATAOBJECT SrcObPtr,
|
|
IN CPDATAOBJECT DestObPtr
|
|
)
|
|
{
|
|
FILTERRETURN fr;
|
|
|
|
//
|
|
// Copy source to destination
|
|
//
|
|
|
|
fr = CopyObject (SrcObPtr, DestObPtr, NULL, NULL);
|
|
if (fr == FILTER_RETURN_FAIL) {
|
|
DEBUGMSG ((DBG_ERROR, "Rename Object: Could not copy source to destination"));
|
|
return FALSE;
|
|
}
|
|
|
|
//
|
|
// Delete source
|
|
//
|
|
|
|
if (!DeleteDataObject (SrcObPtr)) {
|
|
DEBUGMSG ((DBG_ERROR, "Rename Object: Could not delete destination"));
|
|
return FALSE;
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
BOOL
|
|
DeleteDataObjectValue(
|
|
IN CPDATAOBJECT ObPtr
|
|
)
|
|
{
|
|
HKEY hKey;
|
|
BOOL bResult;
|
|
HKEY Parent;
|
|
LONG rc;
|
|
|
|
if(!ObPtr || !IsObjectRegistryKeyAndVal(ObPtr)){
|
|
MYASSERT(FALSE);
|
|
return FALSE;
|
|
}
|
|
|
|
Parent = pGetWinNTKey (GetRootKeyFromOffset (ObPtr->RootItem));
|
|
if(NON_ROOT_KEY (Parent)){
|
|
MYASSERT(FALSE);
|
|
return FALSE;
|
|
}
|
|
|
|
if(ERROR_SUCCESS != TrackedRegOpenKeyEx(Parent, ObPtr->KeyPtr->KeyString, 0, KEY_ALL_ACCESS, &hKey)){
|
|
MYASSERT(FALSE);
|
|
return FALSE;
|
|
}
|
|
|
|
rc = WinNTRegDeleteValue(hKey, ObPtr->ValueName);
|
|
bResult = (rc == ERROR_SUCCESS);
|
|
|
|
if (rc == ERROR_ACCESS_DENIED) {
|
|
LOG ((
|
|
LOG_INFORMATION,
|
|
"Access denied trying to delete %s in %s",
|
|
ObPtr->KeyPtr->KeyString,
|
|
ObPtr->ValueName
|
|
));
|
|
bResult = TRUE;
|
|
}
|
|
|
|
CloseRegKey(hKey);
|
|
|
|
return bResult;
|
|
}
|
|
|