windows-nt/Source/XPSP1/NT/base/ntsetup/win95upg/w95upgnt/merge/object.c
2020-09-26 16:20:57 +08:00

2569 lines
69 KiB
C

/*++
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;
}