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