625 lines
18 KiB
C
625 lines
18 KiB
C
//-----------------------------------------------------------------------//
|
|
//
|
|
// File: copy.cpp
|
|
// Created: April 1997
|
|
// By: Martin Holladay (a-martih)
|
|
// Purpose: Registry Copy Support for REG.CPP
|
|
// Modification History:
|
|
// Copied from Update.cpp and modificd - April 1997 (a-martih)
|
|
// April 1999 Zeyong Xu: re-design, revision -> version 2.0
|
|
//
|
|
//------------------------------------------------------------------------//
|
|
|
|
#include "stdafx.h"
|
|
#include "reg.h"
|
|
|
|
//
|
|
// function prototypes
|
|
//
|
|
LONG CopyValue( HKEY hKey, LPCWSTR pwszValueName,
|
|
HKEY hDestKey, LPCWSTR pwszDestValueName,
|
|
BOOL* pbForce, LPCWSTR pwszSubKey );
|
|
LONG CopyEnumerateKey( HKEY hKey, LPCWSTR pwszSubKey,
|
|
HKEY hDestKey, LPCWSTR pwszDestSubKey,
|
|
BOOL* pbForce, BOOL bRecurseSubKeys, DWORD dwDepth );
|
|
BOOL ParseCopyCmdLine( DWORD argc,
|
|
LPCWSTR argv[],
|
|
PTREG_PARAMS pParams,
|
|
PTREG_PARAMS pDestParams, BOOL* pbUsage );
|
|
|
|
|
|
//
|
|
// implementation
|
|
//
|
|
|
|
//-----------------------------------------------------------------------//
|
|
//
|
|
// CopyRegistry()
|
|
//
|
|
//-----------------------------------------------------------------------//
|
|
|
|
LONG
|
|
CopyRegistry( DWORD argc, LPCWSTR argv[] )
|
|
{
|
|
// local variables
|
|
LONG lResult = 0;
|
|
HKEY hKey = NULL;
|
|
HKEY hDestKey = NULL;
|
|
BOOL bUsage = FALSE;
|
|
BOOL bResult = FALSE;
|
|
DWORD dwDisposition = 0;
|
|
TREG_PARAMS params;
|
|
TREG_PARAMS paramsDest;
|
|
|
|
if ( argc == 0 || argv == NULL )
|
|
{
|
|
SetLastError( ERROR_INVALID_PARAMETER );
|
|
ShowLastError( stderr );
|
|
return 1;
|
|
}
|
|
|
|
// initialize the global data structure
|
|
InitGlobalData( REG_COPY, ¶ms );
|
|
InitGlobalData( REG_COPY, ¶msDest );
|
|
|
|
//
|
|
// Parse the cmd-line
|
|
//
|
|
bResult = ParseCopyCmdLine( argc, argv, ¶ms, ¶msDest, &bUsage );
|
|
if( bResult == FALSE )
|
|
{
|
|
ShowLastErrorEx( stderr, SLE_INTERNAL );
|
|
FreeGlobalData( ¶ms );
|
|
FreeGlobalData( ¶msDest );
|
|
return 1;
|
|
}
|
|
|
|
// check whether we need to display the usage
|
|
if ( bUsage == TRUE )
|
|
{
|
|
Usage( REG_COPY );
|
|
FreeGlobalData( ¶ms );
|
|
FreeGlobalData( ¶msDest );
|
|
return 0;
|
|
}
|
|
|
|
//
|
|
// Connect to the Remote Machine(s) - if applicable
|
|
//
|
|
bResult = RegConnectMachine( ¶ms );
|
|
if( bResult == FALSE )
|
|
{
|
|
SaveErrorMessage( -1 );
|
|
ShowLastErrorEx( stderr, SLE_TYPE_ERROR | SLE_INTERNAL );
|
|
FreeGlobalData( ¶ms );
|
|
FreeGlobalData( ¶msDest );
|
|
return 1;
|
|
}
|
|
|
|
bResult = RegConnectMachine( ¶msDest );
|
|
if( bResult == FALSE )
|
|
{
|
|
SaveErrorMessage( -1 );
|
|
ShowLastErrorEx( stderr, SLE_TYPE_ERROR | SLE_INTERNAL );
|
|
FreeGlobalData( ¶ms );
|
|
FreeGlobalData( ¶msDest );
|
|
return 1;
|
|
}
|
|
|
|
// check whether source and destination are different or not
|
|
if ( params.hRootKey == paramsDest.hRootKey &&
|
|
StringCompare( params.pwszFullKey, paramsDest.pwszFullKey, TRUE, 0 ) == 0 )
|
|
{
|
|
SetLastError( (DWORD) MK_E_SYNTAX );
|
|
SetReason( ERROR_COPYTOSELF_COPY );
|
|
ShowLastErrorEx( stderr, SLE_INTERNAL );
|
|
FreeGlobalData( ¶ms );
|
|
FreeGlobalData( ¶msDest );
|
|
return 1;
|
|
}
|
|
|
|
//
|
|
// Now implement the body of the Copy Operation
|
|
//
|
|
lResult = RegOpenKeyEx(
|
|
params.hRootKey, params.pwszSubKey, 0, KEY_READ, &hKey );
|
|
if( lResult != ERROR_SUCCESS )
|
|
{
|
|
SaveErrorMessage( lResult );
|
|
ShowLastErrorEx( stderr, SLE_TYPE_ERROR | SLE_INTERNAL );
|
|
FreeGlobalData( ¶ms );
|
|
FreeGlobalData( ¶msDest );
|
|
return 1;
|
|
}
|
|
|
|
//
|
|
// Different Key or Different Root or Different Machine
|
|
// So Create/Open it
|
|
//
|
|
lResult = RegCreateKeyEx( paramsDest.hRootKey,paramsDest.pwszSubKey,
|
|
0, NULL, REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, &hDestKey, &dwDisposition);
|
|
if( lResult != ERROR_SUCCESS )
|
|
{
|
|
SafeCloseKey( &hKey );
|
|
SaveErrorMessage( lResult );
|
|
ShowLastErrorEx( stderr, SLE_TYPE_ERROR | SLE_INTERNAL );
|
|
FreeGlobalData( ¶ms );
|
|
FreeGlobalData( ¶msDest );
|
|
return 1;
|
|
}
|
|
|
|
//
|
|
// Recursively copy all subkeys and values
|
|
//
|
|
lResult = CopyEnumerateKey( hKey, params.pwszSubKey,
|
|
hDestKey, params.pwszSubKey, ¶ms.bForce, params.bRecurseSubKeys, 0 );
|
|
|
|
//
|
|
// lets clean up
|
|
//
|
|
SafeCloseKey( &hDestKey );
|
|
SafeCloseKey( &hKey );
|
|
FreeGlobalData( ¶ms );
|
|
FreeGlobalData( ¶msDest );
|
|
|
|
// return
|
|
return ((lResult == ERROR_SUCCESS) ? 0 : 1);
|
|
}
|
|
|
|
|
|
BOOL
|
|
ParseCopyCmdLine( DWORD argc, LPCWSTR argv[],
|
|
PTREG_PARAMS pParams, PTREG_PARAMS pDestParams, BOOL* pbUsage )
|
|
{
|
|
// local variables
|
|
DWORD dw = 0;
|
|
BOOL bResult = FALSE;
|
|
|
|
// check the input
|
|
if ( argc == 0 || argv == NULL ||
|
|
pParams == NULL || pDestParams == NULL || pbUsage == NULL )
|
|
{
|
|
SaveErrorMessage( ERROR_INVALID_PARAMETER );
|
|
return FALSE;
|
|
}
|
|
|
|
// check whether this function is being called for
|
|
// valid operation or not
|
|
if ( pParams->lOperation < 0 || pParams->lOperation >= REG_OPTIONS_COUNT )
|
|
{
|
|
SaveErrorMessage( ERROR_INVALID_PARAMETER );
|
|
return FALSE;
|
|
}
|
|
|
|
//
|
|
// Do we have a *valid* number of cmd-line params
|
|
//
|
|
if ( argc >= 3 && InString( argv[ 2 ], L"-?|/?|-h|/h", TRUE ) == TRUE )
|
|
{
|
|
if ( argc == 3 )
|
|
{
|
|
*pbUsage = TRUE;
|
|
return TRUE;
|
|
}
|
|
else
|
|
{
|
|
SetLastError( (DWORD) MK_E_SYNTAX );
|
|
SetReason2( 1, ERROR_INVALID_SYNTAX_WITHOPT, g_wszOptions[ REG_COPY ] );
|
|
return FALSE;
|
|
}
|
|
}
|
|
else if( argc < 4 || argc > 6 )
|
|
{
|
|
SetLastError( (DWORD) MK_E_SYNTAX );
|
|
SetReason2( 1, ERROR_INVALID_SYNTAX_WITHOPT, g_wszOptions[ REG_COPY ] );
|
|
return FALSE;
|
|
}
|
|
else if ( StringCompareEx( argv[ 1 ], L"COPY", TRUE, 0 ) != 0 )
|
|
{
|
|
SaveErrorMessage( ERROR_INVALID_PARAMETER );
|
|
return FALSE;
|
|
}
|
|
|
|
//
|
|
// Source Machine Name and Registry key
|
|
//
|
|
bResult = BreakDownKeyString( argv[ 2 ], pParams );
|
|
if( bResult == FALSE )
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
//
|
|
// Destination Machine Name and Registry key
|
|
//
|
|
bResult = BreakDownKeyString( argv[ 3 ], pDestParams );
|
|
if( bResult == FALSE )
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
// parsing
|
|
for( dw = 4; dw < argc; dw++ )
|
|
{
|
|
if( StringCompareEx( argv[ dw ], L"/f", TRUE, 0 ) == 0 )
|
|
{
|
|
if ( pParams->bForce == TRUE )
|
|
{
|
|
SetLastError( (DWORD) MK_E_SYNTAX );
|
|
SetReason2( 1, ERROR_INVALID_SYNTAX_WITHOPT, g_wszOptions[ REG_COPY ] );
|
|
return FALSE;
|
|
}
|
|
|
|
pParams->bForce = TRUE;
|
|
}
|
|
else if( StringCompare( argv[ dw ], L"/s", TRUE, 0 ) == 0 )
|
|
{
|
|
if ( pParams->bRecurseSubKeys == TRUE )
|
|
{
|
|
SetLastError( (DWORD) MK_E_SYNTAX );
|
|
SetReason2( 1, ERROR_INVALID_SYNTAX_WITHOPT, g_wszOptions[ REG_COPY ] );
|
|
return FALSE;
|
|
}
|
|
|
|
pParams->bRecurseSubKeys = TRUE;
|
|
}
|
|
else
|
|
{
|
|
SetLastError( (DWORD) MK_E_SYNTAX );
|
|
SetReason2( 1, ERROR_INVALID_SYNTAX_WITHOPT, g_wszOptions[ REG_COPY ] );
|
|
return FALSE;
|
|
}
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------//
|
|
//
|
|
// CopyValue()
|
|
//
|
|
//-----------------------------------------------------------------------//
|
|
|
|
LONG CopyValue( HKEY hKey, LPCWSTR pwszValueName,
|
|
HKEY hDestKey, LPCWSTR pwszDestValueName,
|
|
BOOL* pbForce, LPCWSTR pwszSubKey )
|
|
{
|
|
// local variables
|
|
LONG lResult = 0;
|
|
DWORD dwType = 0;
|
|
DWORD dwSize = 0;
|
|
BYTE* pBuffer = NULL;
|
|
LPCWSTR pwszList = NULL;
|
|
LPCWSTR pwszTemp = NULL;
|
|
LPCWSTR pwszFormat = NULL;
|
|
|
|
// check the input
|
|
if ( hKey == NULL || pwszValueName == NULL ||
|
|
hDestKey == NULL || pwszDestValueName == NULL ||
|
|
pbForce == NULL || pwszSubKey == NULL )
|
|
{
|
|
SaveErrorMessage( ERROR_INVALID_PARAMETER );
|
|
return ERROR_INVALID_PARAMETER;
|
|
}
|
|
|
|
//
|
|
// First find out how much memory to allocate.
|
|
//
|
|
lResult = RegQueryValueEx( hKey, pwszValueName, NULL, &dwType, NULL, &dwSize );
|
|
if( lResult != ERROR_SUCCESS )
|
|
{
|
|
SaveErrorMessage( lResult );
|
|
return lResult;
|
|
}
|
|
|
|
// allocate memory for getting the value from the registry
|
|
pBuffer = (BYTE*) AllocateMemory( (dwSize + 1) * sizeof(BYTE) );
|
|
if ( pBuffer == NULL )
|
|
{
|
|
SaveErrorMessage( ERROR_OUTOFMEMORY );
|
|
return ERROR_OUTOFMEMORY;
|
|
}
|
|
|
|
//
|
|
// Now get the data
|
|
//
|
|
lResult = RegQueryValueEx( hKey, pwszValueName, NULL, &dwType, pBuffer, &dwSize );
|
|
if( lResult != ERROR_SUCCESS )
|
|
{
|
|
FreeMemory( &pBuffer );
|
|
SaveErrorMessage( lResult );
|
|
return lResult;
|
|
}
|
|
|
|
//
|
|
// Copy it to the destination
|
|
//
|
|
if ( *pbForce == FALSE )
|
|
{
|
|
//
|
|
// See if it already exists
|
|
//
|
|
lResult = RegQueryValueEx( hDestKey, pwszDestValueName, 0, NULL, NULL, NULL );
|
|
if( lResult == ERROR_SUCCESS )
|
|
{
|
|
//
|
|
// prepare the prompt message
|
|
//
|
|
pwszFormat = GetResString2( IDS_OVERWRITE, 0 );
|
|
pwszList = GetResString2( IDS_CONFIRM_CHOICE_LIST, 1 );
|
|
if ( StringLength( pwszDestValueName, 0 ) == 0 )
|
|
{
|
|
pwszTemp = GetResString2( IDS_NONAME, 2 );
|
|
}
|
|
else
|
|
{
|
|
pwszTemp = pwszDestValueName;
|
|
}
|
|
|
|
// we will make use of the reason buffer for formatting
|
|
// the value name along with the sub key
|
|
SetReason2( 2, L"%s\\%s", pwszSubKey, pwszTemp );
|
|
pwszTemp = GetReason();
|
|
|
|
do
|
|
{
|
|
lResult = Prompt( pwszFormat, pwszTemp, pwszList, *pbForce );
|
|
} while ( lResult > 3 );
|
|
|
|
if ( lResult == 3 )
|
|
{
|
|
*pbForce = TRUE;
|
|
}
|
|
else if ( lResult != 1 )
|
|
{
|
|
FreeMemory( &pBuffer );
|
|
SaveErrorMessage( ERROR_CANCELLED );
|
|
return ERROR_CANCELLED;
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// Write the Value
|
|
//
|
|
lResult = RegSetValueEx( hDestKey, pwszDestValueName, 0, dwType, pBuffer, dwSize );
|
|
|
|
// release memory
|
|
FreeMemory( &pBuffer );
|
|
|
|
return lResult;
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------//
|
|
//
|
|
// EnumerateKey() - Recursive
|
|
//
|
|
//-----------------------------------------------------------------------//
|
|
|
|
LONG CopyEnumerateKey( HKEY hKey, LPCWSTR pwszSubKey,
|
|
HKEY hDestKey, LPCWSTR pwszDestSubKey,
|
|
BOOL* pbForce, BOOL bRecurseSubKeys, DWORD dwDepth )
|
|
{
|
|
// local variables
|
|
DWORD dw = 0;
|
|
LONG lResult = 0;
|
|
DWORD dwValues = 0;
|
|
DWORD dwSubKeys = 0;
|
|
DWORD dwLengthOfKeyName = 0;
|
|
DWORD dwLengthOfValueName = 0;
|
|
DWORD dwSize = 0;
|
|
DWORD dwDisposition = 0;
|
|
HKEY hSubKey = NULL;
|
|
HKEY hDestSubKey = NULL;
|
|
LPWSTR pwszNameBuf = NULL;
|
|
LPWSTR pwszNewSubKey = NULL;
|
|
LPWSTR pwszNewDestSubKey = NULL;
|
|
|
|
// check the input
|
|
if ( hKey == NULL || pwszSubKey == NULL ||
|
|
hDestKey == NULL || pwszDestSubKey == NULL || pbForce == NULL )
|
|
{
|
|
lResult = ERROR_INVALID_PARAMETER;
|
|
goto exitarea;
|
|
}
|
|
|
|
// query source key info
|
|
lResult = RegQueryInfoKey(
|
|
hKey, NULL, NULL, NULL,
|
|
&dwSubKeys, &dwLengthOfKeyName, NULL,
|
|
&dwValues, &dwLengthOfValueName, NULL, NULL, NULL );
|
|
if( lResult != ERROR_SUCCESS )
|
|
{
|
|
goto exitarea;
|
|
}
|
|
|
|
//
|
|
// SPECIAL CASE:
|
|
// -------------
|
|
// For HKLM\SYSTEM\CONTROLSET002 it is found to be API returning value 0 for dwMaxLength
|
|
// though there are subkeys underneath this -- to handle this, we are doing a workaround
|
|
// by assuming the max registry key length
|
|
//
|
|
if ( dwSubKeys != 0 && dwLengthOfKeyName == 0 )
|
|
{
|
|
dwLengthOfKeyName = 256;
|
|
}
|
|
else if ( dwLengthOfKeyName < 256 )
|
|
{
|
|
// always assume 100% more length that what is returned by the API
|
|
dwLengthOfKeyName *= 2;
|
|
}
|
|
|
|
//
|
|
// First enumerate all of the values
|
|
//
|
|
// bump the length to take into account the terminator.
|
|
dwLengthOfValueName++;
|
|
pwszNameBuf = (LPWSTR) AllocateMemory( dwLengthOfValueName * sizeof(WCHAR) );
|
|
if( pwszNameBuf == NULL)
|
|
{
|
|
lResult = ERROR_OUTOFMEMORY;
|
|
}
|
|
else
|
|
{
|
|
lResult = ERROR_SUCCESS;
|
|
for( dw = 0; dw < dwValues && lResult == ERROR_SUCCESS; dw++ )
|
|
{
|
|
dwSize = dwLengthOfValueName;
|
|
lResult = RegEnumValue( hKey, dw, pwszNameBuf, &dwSize, NULL, NULL, NULL, NULL);
|
|
if( lResult == ERROR_SUCCESS )
|
|
{
|
|
lResult = CopyValue( hKey, pwszNameBuf,
|
|
hDestKey, pwszNameBuf, pbForce, pwszSubKey );
|
|
if ( lResult == ERROR_CANCELLED )
|
|
{
|
|
// user chosed to just to skip this
|
|
lResult = ERROR_SUCCESS;
|
|
}
|
|
}
|
|
}
|
|
|
|
// release memory
|
|
FreeMemory( &pwszNameBuf );
|
|
|
|
if( bRecurseSubKeys == FALSE || lResult != ERROR_SUCCESS )
|
|
{
|
|
goto exitarea;
|
|
}
|
|
|
|
//
|
|
// Now Enumerate all of the keys
|
|
//
|
|
dwLengthOfKeyName++;
|
|
pwszNameBuf = (LPWSTR) AllocateMemory( dwLengthOfKeyName * sizeof(WCHAR) );
|
|
if( pwszNameBuf == NULL )
|
|
{
|
|
lResult = ERROR_NOT_ENOUGH_MEMORY;
|
|
}
|
|
else
|
|
{
|
|
hSubKey = NULL;
|
|
hDestSubKey = NULL;
|
|
for( dw = 0; dw < dwSubKeys; dw++ )
|
|
{
|
|
dwSize = dwLengthOfKeyName;
|
|
lResult = RegEnumKeyEx( hKey, dw,
|
|
pwszNameBuf, &dwSize, NULL, NULL, NULL, NULL );
|
|
if( lResult != ERROR_SUCCESS )
|
|
{
|
|
break;
|
|
}
|
|
|
|
//
|
|
// open up the subkey, create the destination key
|
|
// and enumerate it
|
|
//
|
|
lResult = RegOpenKeyEx( hKey, pwszNameBuf, 0, KEY_READ, &hSubKey );
|
|
if( lResult != ERROR_SUCCESS )
|
|
{
|
|
break;
|
|
}
|
|
|
|
lResult = RegCreateKeyEx( hDestKey,
|
|
pwszNameBuf, 0, NULL, REG_OPTION_NON_VOLATILE,
|
|
KEY_ALL_ACCESS, NULL, &hDestSubKey, &dwDisposition );
|
|
if( lResult != ERROR_SUCCESS )
|
|
{
|
|
break;
|
|
}
|
|
|
|
//
|
|
// Build up the needed string and go to town enumerating again
|
|
//
|
|
|
|
//
|
|
// new source sub key
|
|
dwSize = StringLength( pwszSubKey, 0 ) + StringLength( pwszNameBuf, 0 ) + 3;
|
|
pwszNewSubKey = (LPWSTR) AllocateMemory( dwSize * sizeof( WCHAR ) );
|
|
if( pwszNewSubKey == NULL )
|
|
{
|
|
lResult = ERROR_OUTOFMEMORY;
|
|
break;
|
|
}
|
|
|
|
if( StringLength( pwszSubKey, 0 ) > 0 )
|
|
{
|
|
StringCopy( pwszNewSubKey, pwszSubKey, dwSize );
|
|
StringConcat( pwszNewSubKey, L"\\", dwSize );
|
|
}
|
|
|
|
// ...
|
|
StringConcat( pwszNewSubKey, pwszNameBuf, dwSize );
|
|
|
|
//
|
|
// new destination sub key
|
|
dwSize = StringLength( pwszDestSubKey, 0 ) + StringLength( pwszNameBuf, 0 ) + 3;
|
|
pwszNewDestSubKey = (LPWSTR) AllocateMemory( dwSize * sizeof( WCHAR ) );
|
|
if( pwszDestSubKey == NULL )
|
|
{
|
|
lResult = ERROR_OUTOFMEMORY;
|
|
break;
|
|
}
|
|
|
|
if( StringLength( pwszDestSubKey, 0 ) > 0 )
|
|
{
|
|
StringCopy( pwszNewDestSubKey, pwszDestSubKey, dwSize);
|
|
StringConcat( pwszNewDestSubKey, L"\\", dwSize );
|
|
}
|
|
|
|
// ...
|
|
StringConcat( pwszNewDestSubKey, pwszNameBuf, dwSize );
|
|
|
|
// recursive copy
|
|
lResult = CopyEnumerateKey( hSubKey, pwszNewSubKey,
|
|
hDestSubKey, pwszNewDestSubKey, pbForce, bRecurseSubKeys, dwDepth + 1 );
|
|
|
|
SafeCloseKey( &hSubKey );
|
|
SafeCloseKey( &hDestSubKey );
|
|
FreeMemory( &pwszNewSubKey );
|
|
FreeMemory( &pwszNewDestSubKey );
|
|
}
|
|
|
|
// release all the key handles and memory allocated
|
|
if ( hSubKey != NULL )
|
|
{
|
|
SafeCloseKey( &hSubKey );
|
|
}
|
|
|
|
if ( hDestSubKey != NULL )
|
|
{
|
|
SafeCloseKey( &hDestSubKey );
|
|
}
|
|
|
|
// ...
|
|
FreeMemory( &pwszNameBuf );
|
|
FreeMemory( &pwszNewSubKey );
|
|
FreeMemory( &pwszNewDestSubKey );
|
|
}
|
|
}
|
|
|
|
exitarea:
|
|
|
|
// check the result and display the error message
|
|
// NOTE: error message display should be done only at the exit point
|
|
if ( dwDepth == 0 )
|
|
{
|
|
if ( lResult != ERROR_SUCCESS )
|
|
{
|
|
// display the error
|
|
SaveErrorMessage( lResult );
|
|
ShowLastErrorEx( stderr, SLE_TYPE_ERROR | SLE_INTERNAL );
|
|
}
|
|
else
|
|
{
|
|
SaveErrorMessage( ERROR_SUCCESS );
|
|
ShowLastErrorEx( stdout, SLE_INTERNAL );
|
|
}
|
|
}
|
|
|
|
// return
|
|
return lResult;
|
|
}
|