windows-nt/Source/XPSP1/NT/windows/winstate/v1/common/bothchar.cxx
2020-09-26 16:20:57 +08:00

1295 lines
39 KiB
C++
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

//--------------------------------------------------------------
//
// File: bothchar
//
// Contents: Functions that need to be compiled as ascii for
// scanstate and unicode for loadstate.
//
//---------------------------------------------------------------
#include "bothchar.hxx"
//---------------------------------------------------------------
// Constants
UCHAR EMPTY_STRING[] = "";
const UCHAR NEWLINE_SET[256] =
{
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
};
const DWORD VERBOSE_BIT = 0x01; // used with -v flag
const DWORD DEBUGOUTPUT_BIT = 0x02; // used with -v flag
const DWORD VERBOSEREG_BIT = 0x04; // used with -v flag
#define LOADSTATE_KEY TEXT("Software\\Microsoft\\Windows\\CurrentVersion\\Loadstate")
//---------------------------------------------------------------
// Globals.
TCHAR *DomainName = NULL;
TCHAR *UserName = NULL;
TCHAR *UserPath = NULL;
//---------------------------------------------------------------
void CStringList::Add( CStringList *pslMore )
{
CStringList *b;
CStringList *c;
CStringList *d;
// Do nothing if there is no list.
if (pslMore == NULL)
return;
// Determine some nodes to work with.
b = pslMore->_pslNext;
c = pslMore;
d = _pslNext;
// Relink the list so head points to b is a list to c points to d is
// a list back to head.
_pslNext = b;
c->_pslNext = d;
}
//---------------------------------------------------------------
CStringList::CStringList( DWORD dwLen )
{
_pslNext = this;
if (dwLen == 0)
{
_ptsString = NULL;
_fHead = TRUE;
}
else
{
_fHead = FALSE;
_ptsString = (TCHAR *) malloc( dwLen*sizeof(TCHAR) );
}
}
//---------------------------------------------------------------
CStringList::~CStringList()
{
CStringList *pslCurrent = _pslNext;
CStringList *pslEnd;
// Non header nodes just free their string.
if (_ptsString != NULL)
free( _ptsString );
// Header nodes free the list.
if (_fHead)
{
while (pslCurrent != this)
{
pslEnd = pslCurrent->_pslNext;
delete pslCurrent;
pslCurrent = pslEnd;
}
}
}
//---------------------------------------------------------------
DWORD ParseSectionList( INFCONTEXT *pic,
TCHAR **pptsLabel,
CStringList **pslList )
{
DWORD len;
BOOL fSuccess;
DWORD dwFields;
DWORD i;
DWORD dwResult = ERROR_SUCCESS;
CStringList *pslCurrent;
// Initialize output
*pslList = NULL;
// Query the length of the label name
fSuccess = SetupGetStringField( pic, 0, NULL, 0, &len );
LOG_ASSERT_GLE( fSuccess, dwResult );
// Allocate space
*pptsLabel = (TCHAR *) malloc( len * sizeof(TCHAR) );
LOG_ASSERT_EXPR( *pptsLabel != NULL, IDS_NOT_ENOUGH_MEMORY, dwResult,
ERROR_NOT_ENOUGH_MEMORY );
// Read the label name
fSuccess = SetupGetStringField( pic, 0, *pptsLabel, len, NULL );
LOG_ASSERT_GLE( fSuccess, dwResult );
// Find out how many fields are on the line.
dwFields = SetupGetFieldCount( pic );
LOG_ASSERT_GLE( dwFields != 0, dwResult );
// Read each field.
for (i = 1; i <= dwFields; i++)
{
// Query the length of the field
fSuccess = SetupGetStringField( pic, i, NULL, 0, &len );
LOG_ASSERT_GLE( fSuccess, dwResult );
// Allocate a new node.
pslCurrent = new CStringList( len );
LOG_ASSERT_EXPR( pslCurrent != NULL,
IDS_NOT_ENOUGH_MEMORY,
dwResult,
ERROR_NOT_ENOUGH_MEMORY);
LOG_ASSERT_EXPR( pslCurrent->String() != NULL,
IDS_NOT_ENOUGH_MEMORY,
dwResult,
ERROR_NOT_ENOUGH_MEMORY );
// Copy the field into the node.
fSuccess = SetupGetStringField( pic, i, pslCurrent->String(), len, NULL );
LOG_ASSERT_GLE( fSuccess, dwResult );
// Link the node in the list.
if (*pslList == NULL)
*pslList = pslCurrent;
else
(*pslList)->Add( pslCurrent );
}
cleanup:
return dwResult;
}
/***************************************************************************
ParseRegPath
Read a string field from a line in the rules inf file and parse it
into a root, key, and value. All components of the reg path are optional.
root\key [value]
***************************************************************************/
DWORD ParseRegPath( INFCONTEXT *pic,
DWORD dwField,
TCHAR **pptsRoot,
TCHAR **pptsKey,
TCHAR **pptsValue )
{
TCHAR *ptsBuffer = NULL;
TCHAR *ptsStop;
TCHAR *ptsStart;
TCHAR *bracket;
BOOL fSuccess;
DWORD dwLen = 0;
DWORD dwResult = ERROR_SUCCESS;
//Null out return values in case of later error.
*pptsRoot = NULL;
*pptsKey = NULL;
*pptsValue = NULL;
// Compute the length of the reg path field.
SetupGetStringField( pic, dwField, NULL, 0, &dwLen );
// Allocate a buffer.
ptsBuffer = (TCHAR *) malloc( dwLen*sizeof(TCHAR) );
LOG_ASSERT_EXPR( ptsBuffer != NULL, IDS_NOT_ENOUGH_MEMORY, dwResult,
ERROR_NOT_ENOUGH_MEMORY );
// Get the whole reg path. The function fails if the field is empty.
fSuccess = SetupGetStringField( pic, dwField, ptsBuffer, dwLen, &dwLen );
if (!fSuccess)
{
free( ptsBuffer );
return ERROR_SUCCESS;
}
// Look for a backslash.
ptsStop = _tcschr( ptsBuffer, TEXT('\\') );
// If there wasn't one, there is no root.
if (ptsStop == NULL)
{
*pptsRoot = NULL;
ptsStart = ptsBuffer;
}
// If there was one, copy the root name.
else
{
*pptsRoot = (TCHAR *) malloc( ((ptsStop - ptsBuffer) + 1) *
sizeof(TCHAR) );
LOG_ASSERT_EXPR( *pptsRoot != NULL,
IDS_NOT_ENOUGH_MEMORY,
dwResult,
ERROR_NOT_ENOUGH_MEMORY );
_tcsncpy( *pptsRoot, ptsBuffer, ptsStop - ptsBuffer );
(*pptsRoot)[ptsStop - ptsBuffer] = 0;
ptsStart = ptsStop + 1;
}
// Look for an opening square bracket.
ptsStop = _tcschr( ptsStart, TEXT('[') );
// If there wasn't one, copy the rest of the string to the key name.
if (ptsStop == NULL)
{
if (ptsStart[0] == 0)
*pptsKey = NULL;
else
{
*pptsKey = (TCHAR *) malloc( (dwLen - (ptsStart - ptsBuffer)) *
sizeof(TCHAR) );
*pptsValue = NULL;
LOG_ASSERT_EXPR( *pptsKey != NULL,
IDS_NOT_ENOUGH_MEMORY,
dwResult,
ERROR_NOT_ENOUGH_MEMORY );
_tcscpy( *pptsKey, ptsStart );
}
}
// Handle an optional key and a value.
else
{
// Back up past any intervening white space.
bracket = ptsStop + 1;
while (ptsStop != ptsStart &&
(ptsStop[0] == TEXT(' ') || ptsStop[0] == TEXT('[')))
ptsStop -= 1;
// If there are any characters left, copy them to the key.
if (ptsStop != ptsStart)
{
ptsStop += 1;
*pptsKey = (TCHAR *) malloc( ((ptsStop - ptsStart) + 1) *
sizeof(TCHAR) );
LOG_ASSERT_EXPR( *pptsKey != NULL,
IDS_NOT_ENOUGH_MEMORY,
dwResult,
ERROR_NOT_ENOUGH_MEMORY );
_tcsncpy( *pptsKey, ptsStart, ptsStop - ptsStart );
(*pptsKey)[ptsStop - ptsStart] = 0;
}
else
*pptsKey = NULL;
// Find the closing square bracket.
ptsStart = bracket;
bracket = _tcschr( ptsStart, TEXT(']') );
LOG_ASSERT_EXPR( bracket != NULL,
IDS_INF_ERROR,
dwResult,
SPAPI_E_GENERAL_SYNTAX );
// Copy the value name.
*pptsValue = (TCHAR *) malloc( ((bracket - ptsStart) + 1) *
sizeof(TCHAR) );
LOG_ASSERT_EXPR( *pptsValue != NULL,
IDS_NOT_ENOUGH_MEMORY,
dwResult,
ERROR_NOT_ENOUGH_MEMORY );
_tcsncpy( *pptsValue, ptsStart, bracket - ptsStart );
(*pptsValue)[bracket - ptsStart] = 0;
}
cleanup:
if (ptsBuffer != NULL)
free( ptsBuffer );
return dwResult;
}
/***************************************************************************
ParseRule
Read a line from the rules inf file in one of the following formats.
When partial paths are specified, compute the full path. Create a rule
record from the line.
reg_path2 is optional and reg_path is parsed by the function
ParseRegPath into a root, key, and value.
reg-path1 = reg_path2
If reg_path2 contains just a leaf name, generate a full path using
the path from reg_path1 and replacing its leaf with the leaf from reg_path2.
***************************************************************************/
DWORD ParseRule( INFCONTEXT *pic, HASH_NODE **pphnRule )
{
TCHAR *ptsBuffer;
DWORD dwReqLen;
DWORD dwResult = ERROR_SUCCESS;
BOOL fSuccess;
TCHAR *ptsLast;
TCHAR *ptsTemp;
// Allocate a new rule.
*pphnRule = (HASH_NODE *) malloc( sizeof(HASH_NODE) );
LOG_ASSERT_EXPR( *pphnRule != NULL, IDS_NOT_ENOUGH_MEMORY, dwResult,
ERROR_NOT_ENOUGH_MEMORY );
(*pphnRule)->dwAction = 0;
(*pphnRule)->phnNext = 0;
(*pphnRule)->ptsNewValue = NULL;
(*pphnRule)->ptsNewKey = NULL;
(*pphnRule)->ptsFunction = NULL;
(*pphnRule)->ptsFileDest = NULL;
// Get the first reg path.
dwResult = ParseRegPath( pic,
0,
&(*pphnRule)->ptsRoot,
&(*pphnRule)->ptsKey,
&(*pphnRule)->ptsValue );
FAIL_ON_ERROR( dwResult );
// Get the second reg path.
dwResult = ParseRegPath( pic,
1,
&ptsBuffer,
&(*pphnRule)->ptsNewKey,
&(*pphnRule)->ptsNewValue );
FAIL_ON_ERROR( dwResult );
// Get the optional regfile destination
fSuccess = SetupGetStringField( pic, 2, NULL, 0, &dwReqLen );
if ((TRUE == fSuccess) && (dwReqLen > 0))
{
(*pphnRule)->ptsFileDest = (TCHAR *)malloc(dwReqLen * sizeof(TCHAR));
LOG_ASSERT_EXPR( (*pphnRule)->ptsFileDest != NULL, IDS_NOT_ENOUGH_MEMORY, dwResult,
ERROR_NOT_ENOUGH_MEMORY );
fSuccess = SetupGetStringField(pic, 2, (*pphnRule)->ptsFileDest, dwReqLen, NULL);
LOG_ASSERT_GLE(fSuccess, dwResult);
}
// If the original key ends with a star, remove it and set the recursive
// flag.
if ((*pphnRule)->ptsKey != NULL)
{
dwReqLen = _tcslen( (*pphnRule)->ptsKey );
if (dwReqLen > 2 &&
(*pphnRule)->ptsKey[dwReqLen-1] == TEXT('*') &&
(*pphnRule)->ptsKey[dwReqLen-2] == TEXT('\\'))
{
(*pphnRule)->dwAction |= recursive_fa;
(*pphnRule)->ptsKey[dwReqLen-2] = 0;
}
// If there is a new key, set the rename_leaf or rename_path flag.
if ((*pphnRule)->ptsNewKey != NULL)
if ((*pphnRule)->dwAction & recursive_fa)
(*pphnRule)->dwAction |= rename_path_fa;
else
(*pphnRule)->dwAction |= rename_leaf_fa;
}
// If there is a new value, set the rename_value flag.
if ((*pphnRule)->ptsNewValue != NULL)
(*pphnRule)->dwAction |= rename_value_fa;
// If the new key did not contain a root, compute a full path for it.
if (ptsBuffer == NULL &&
(*pphnRule)->ptsKey != NULL &&
(*pphnRule)->ptsNewKey != NULL)
{
// Find the last backslash in the key.
ptsLast = (*pphnRule)->ptsKey;
do
{
ptsTemp = _tcschr( ptsLast, TEXT('\\') );
if (ptsTemp != NULL)
ptsLast = ptsTemp+1;
} while (ptsTemp != NULL);
// Don't do anything if the original key contains just a leaf.
if (ptsLast != (*pphnRule)->ptsKey)
{
// Allocate a ptsBuffer to hold the old path and the new leaf.
free( ptsBuffer );
dwReqLen = _tcslen( (*pphnRule)->ptsNewKey ) +
(ptsLast - (*pphnRule)->ptsKey) + 2;
ptsBuffer = (TCHAR *) malloc( dwReqLen*sizeof(TCHAR) );
LOG_ASSERT_EXPR( ptsBuffer != NULL,
IDS_NOT_ENOUGH_MEMORY,
dwResult,
ERROR_NOT_ENOUGH_MEMORY );
// Copy in the old path and the new leaf.
_tcsncpy( ptsBuffer,
(*pphnRule)->ptsKey,
(ptsLast - (*pphnRule)->ptsKey) );
_tcscpy( &ptsBuffer[ptsLast-(*pphnRule)->ptsKey],
(*pphnRule)->ptsNewKey );
free( (*pphnRule)->ptsNewKey );
(*pphnRule)->ptsNewKey = ptsBuffer;
}
}
else
free(ptsBuffer);
// Consider freeing strings on error.
cleanup:
if (dwResult != ERROR_SUCCESS)
{
if (*pphnRule != NULL)
{
free((*pphnRule)->ptsRoot);
free((*pphnRule)->ptsKey);
free((*pphnRule)->ptsValue);
free((*pphnRule)->ptsNewKey);
free((*pphnRule)->ptsNewValue);
free((*pphnRule)->ptsFunction);
free((*pphnRule)->ptsFileDest);
free(*pphnRule);
*pphnRule = NULL;
}
}
return dwResult;
}
//---------------------------------------------------------------
// This function prints from an ascii format string to a unicode
// win32 file handle. It is not thread safe.
DWORD Win32Printf( HANDLE file, char *format, ... )
{
va_list va;
DWORD dwWritten;
DWORD dwLen;
DWORD dwWideLength;
WCHAR *pwsBuffer = NULL;
const ULONG LINEBUFSIZE = 4096;
#ifdef UNICODE
char *pszBuffer;
int iCharLen;
char szOutputBuffer[LINEBUFSIZE];
#endif
BOOL fSuccess;
TCHAR tcsPrintBuffer[LINEBUFSIZE];
TCHAR *ptsFormat;
#ifdef UNICODE
WCHAR wcsFormat[LINEBUFSIZE];
dwWideLength = MultiByteToWideChar(CP_ACP, 0, format, -1, NULL, 0);
if (dwWideLength >= LINEBUFSIZE)
{
pwsBuffer = (WCHAR *)_alloca( dwWideLength * sizeof(WCHAR));
if (pwsBuffer == NULL)
return ERROR_NOT_ENOUGH_MEMORY;
ptsFormat = pwsBuffer;
if (!MultiByteToWideChar( CP_ACP,
0,
format,
-1,
pwsBuffer,
dwWideLength ))
return GetLastError();
}
else
{
if (!MultiByteToWideChar(CP_ACP,
0,
format,
-1,
wcsFormat,
LINEBUFSIZE))
{
return GetLastError();
}
ptsFormat = wcsFormat;
}
#else
ptsFormat = format;
#endif
va_start( va, format );
// The doc says if wvsprintf fails, return value is less than
// the length of the expected output. Since its hard to know the
// correct output length, always clear the last error and always
// check it.
SetLastError(ERROR_SUCCESS);
wvsprintf( tcsPrintBuffer, ptsFormat, va );
va_end(va);
if (GetLastError() != ERROR_SUCCESS)
return GetLastError();
// When printing to the console or logfile use ascii.
// When printing to the migration file use Unicode.
dwLen = _tcslen(tcsPrintBuffer);
if ((file != OutputFile) || OutputAnsi)
{
#ifdef UNICODE
//Convert to ANSI for output
iCharLen = WideCharToMultiByte(CP_ACP,
0,
tcsPrintBuffer,
-1,
NULL,
0,
NULL,
NULL);
if (iCharLen >= LINEBUFSIZE)
{
pszBuffer = (char *)_alloca( iCharLen * sizeof(char));
if (pszBuffer == NULL)
return ERROR_OUTOFMEMORY;
if (!WideCharToMultiByte(CP_ACP,
0,
tcsPrintBuffer,
-1,
pszBuffer,
iCharLen,
NULL,
NULL))
return GetLastError();
pwsBuffer = (WCHAR *)pszBuffer;
}
else
{
if (!WideCharToMultiByte(CP_ACP,
0,
tcsPrintBuffer,
-1,
szOutputBuffer,
LINEBUFSIZE,
NULL,
NULL))
return GetLastError();
pwsBuffer = (WCHAR *)szOutputBuffer;
}
dwWideLength = dwLen;
#else
pwsBuffer = (WCHAR *) tcsPrintBuffer;
dwWideLength = dwLen;
#endif
}
else
{
#ifdef UNICODE
pwsBuffer = tcsPrintBuffer;
dwWideLength = dwLen * sizeof(WCHAR);
#else
// Allocate a buffer to hold the unicode string.
DEBUG_ASSERT( dwLen < LINEBUFSIZE );
dwWideLength = MultiByteToWideChar( CP_ACP,
0,
tcsPrintBuffer,
dwLen,
NULL,
0 );
pwsBuffer = (WCHAR *) _alloca( dwWideLength*sizeof(WCHAR) );
if (pwsBuffer == NULL)
return ERROR_NOT_ENOUGH_MEMORY;
// Convert the buffer to unicode.
dwWideLength = MultiByteToWideChar( CP_ACP,
0,
tcsPrintBuffer,
dwLen,
pwsBuffer,
dwWideLength );
if (dwWideLength == 0)
return GetLastError();
dwWideLength *= sizeof(WCHAR);
#endif
}
// Write the unicode string.
fSuccess = WriteFile( file, pwsBuffer, dwWideLength, &dwWritten, NULL );
if (!fSuccess || dwWideLength != dwWritten)
return GetLastError();
if (file == STDERR)
{
//Also write to the log file for these
fSuccess = WriteFile( LogFile,
pwsBuffer,
dwWideLength,
&dwWritten,
NULL );
if (!fSuccess || dwWideLength != dwWritten)
{
return GetLastError();
}
}
return ERROR_SUCCESS;
}
//*****************************************************************
//
// Synopsis: Recursive function to make the command line. We have to do
// this because CStringList stores the parameter in reverse
// order.
//
// Parameters: h
// We need to know when we reach the end of the
// CStringList, which is denoted by pointing back to the
// head of the chain. But in a recursive function we lose
// the head of the chain so it is passed in.
//
// History: 11/8/1999 Created by WeiruC.
//
// Return Value: Win32 error code.
//
//*****************************************************************
void MakeCommandLine(CStringList* h, CStringList* command, TCHAR* commandLine)
{
if (h==NULL || command == NULL || commandLine == NULL)
{
if (DebugOutput)
{
Win32Printf(LogFile, "Error: NULL pointer passed to MakeCommandLine\r\n");
}
_tcscpy(commandLine, TEXT(""));
return;
}
if(command->Next() != h)
{
MakeCommandLine(h, command->Next(), commandLine);
}
// No sizes of these buffers are passed in, so we must assume that there is enough space
_tcscat(commandLine, TEXT("\""));
_tcscat(commandLine, command->String());
_tcscat(commandLine, TEXT("\""));
_tcscat(commandLine, TEXT(" "));
}
//---------------------------------------------------------------
// This is a variation of strpbrk. It searchs a string that may
// contain nulls for any character in the set. It returns a pointer
// to the first character in the set or null if the string does
// not contain any characters in the set. Since the function
// searchs past nulls in the str parameter, the len parameter
// indicates the actual length of str. The set is an array of
// booleans.
UCHAR *mempbrk( UCHAR *str, DWORD len, const UCHAR set[256] )
{
DWORD i;
for (i = 0; i < len; i++)
if (set[str[i]] != 0)
return &str[i];
return NULL;
}
//---------------------------------------------------------------
DWORD WriteKey( HANDLE outfile, DWORD type, TCHAR *rootname, TCHAR *key, TCHAR *value_name,
UCHAR *data, DWORD data_len )
{
DWORD result = ERROR_SUCCESS;
DWORD j;
UCHAR *curr;
DWORD orig = 0;
// If a string contains an embedded carriage return or linefeed, save
// it as binary and convert it back to a string on read.
if (type == REG_SZ || type == REG_MULTI_SZ || type == REG_EXPAND_SZ)
{
curr = mempbrk( data, data_len, NEWLINE_SET );
if (curr != NULL)
{
if (type == REG_SZ)
orig = 0x400000;
else if (type == REG_MULTI_SZ)
orig = 0x100000;
else
orig = 0x200000;
type = REG_BINARY;
}
}
if (NULL == rootname)
rootname = TEXT("");
if (NULL == key)
key = TEXT("");
if (NULL == value_name)
value_name = TEXT("");
switch (type)
{
case REG_DWORD:
if (data == NULL)
*data = 0;
result = Win32Printf( outfile, "%s, \"%s\", \"%s\", 0x10001, 0x%x\r\n", rootname, key,
value_name, *((DWORD *) data) );
FAIL_ON_ERROR( result );
break;
case REG_EXPAND_SZ:
case REG_SZ:
if (data == NULL)
data = EMPTY_STRING;
result = Win32Printf( outfile, "%s, \"%s\", \"%s\", 0x%x, \"%s\"\r\n", rootname,
key, value_name,
type == REG_SZ ? FLG_ADDREG_TYPE_SZ : FLG_ADDREG_TYPE_EXPAND_SZ,
data );
FAIL_ON_ERROR( result );
break;
case REG_MULTI_SZ:
// Print the start of the line and the first string.
if (data == NULL)
data = EMPTY_STRING;
result = Win32Printf( outfile, "%s, \"%s\", \"%s\", 0x10000, \"%s\"", rootname,
key, value_name, data );
FAIL_ON_ERROR( result );
// Print each remaining string.
curr = data+strlen((char *) data)+1;
do
{
// Print a comma and the current string.
Win32Printf( outfile, ", \"%s\"", curr );
// Skip passed the current string and its null.
curr += strlen((char *) curr)+1;
} while ((DWORD) (curr - data) < data_len);
// Print the trailing newline.
result = Win32Printf( outfile, "\r\n" );
FAIL_ON_ERROR( result );
break;
case REG_BINARY:
case REG_NONE:
default: // Unknown types, just copy the type and treat the data as binary
// Print the start of the line.
result = Win32Printf( outfile, "%s, \"%s\", \"%s\", 0x%x",
rootname, key, value_name,
((type == REG_NONE ? 0x800000 : type ) | orig) );
FAIL_ON_ERROR( result );
// Print each byte in hex without the 0x prefix.
for (j = 0; j < data_len; j++)
{
result = Win32Printf( outfile, ",%x", data[j] );
FAIL_ON_ERROR( result );
if ( (j+1) % 20 == 0)
{
result = Win32Printf( outfile, "\\\r\n" );
FAIL_ON_ERROR( result );
}
}
result = Win32Printf( outfile, "\r\n" );
FAIL_ON_ERROR( result );
break;
}
cleanup:
return result;
}
//---------------------------------------------------------------
//
DWORD LogReadRule( HASH_NODE *phnNode )
{
DWORD dwRetval = ERROR_SUCCESS;
BOOL fRuleFound = FALSE;
dwRetval = Win32Printf(LogFile, "Read rule: ");
FAIL_ON_ERROR( dwRetval );
if (phnNode->dwAction & function_fa )
{
dwRetval = Win32Printf(LogFile, "function");
FAIL_ON_ERROR( dwRetval );
fRuleFound = TRUE;
}
if (phnNode->dwAction & (rename_leaf_fa | rename_path_fa | rename_value_fa))
{
dwRetval = Win32Printf(LogFile, "rename" );
FAIL_ON_ERROR( dwRetval );
fRuleFound = TRUE;
}
if (phnNode->dwAction & file_fa)
{
dwRetval = Win32Printf(LogFile, "copy file");
FAIL_ON_ERROR( dwRetval );
fRuleFound = TRUE;
}
if (phnNode->dwAction & delete_fa ||
phnNode->dwAction & suppress_fa)
{
dwRetval = Win32Printf(LogFile, "delete" );
FAIL_ON_ERROR( dwRetval );
fRuleFound = TRUE;
}
// If none of the above, then it must be an addreg
if ( fRuleFound == FALSE )
{
dwRetval = Win32Printf(LogFile, "addreg" );
FAIL_ON_ERROR( dwRetval );
}
dwRetval = Win32Printf(LogFile,
" %s\\%s ",
phnNode->ptsRoot,
phnNode->ptsKey);
FAIL_ON_ERROR( dwRetval );
if ( phnNode->ptsValue != NULL )
{
dwRetval = Win32Printf(LogFile,
"[%s] ",
phnNode->ptsValue );
FAIL_ON_ERROR( dwRetval );
}
if ( phnNode->ptsNewKey != NULL || phnNode->ptsNewValue != NULL )
{
dwRetval = Win32Printf(LogFile, "to ");
FAIL_ON_ERROR( dwRetval );
if (phnNode->ptsNewKey != NULL)
{
dwRetval = Win32Printf(LogFile,
"%s ",
phnNode->ptsNewKey);
FAIL_ON_ERROR( dwRetval );
}
if (phnNode->ptsNewValue != NULL)
{
dwRetval = Win32Printf(LogFile,
"[%s]",
phnNode->ptsNewValue);
FAIL_ON_ERROR( dwRetval );
}
}
dwRetval = Win32Printf(LogFile, "\r\n");
FAIL_ON_ERROR( dwRetval );
cleanup:
return (dwRetval);
}
//---------------------------------------------------------------
char *GetValueFromRegistry(const char *lpValue)
{
HKEY hKey;
char *buffer = NULL;
DWORD dwDataSize = 0;
DWORD result;
result = RegOpenKeyEx( HKEY_CURRENT_USER, LOADSTATE_KEY, 0, KEY_READ, &hKey );
FAIL_ON_ERROR( result );
// Determine size needed
dwDataSize = 0;
result = RegQueryValueExA( hKey, lpValue, NULL, NULL, NULL, &dwDataSize);
FAIL_ON_ERROR( result );
buffer = (char *)malloc((dwDataSize + 1) * sizeof(char));
if (NULL == buffer)
{
Win32PrintfResource(Console, IDS_NOT_ENOUGH_MEMORY);
goto cleanup;
}
result = RegQueryValueExA( hKey, lpValue, NULL, NULL,
(LPBYTE)buffer, &dwDataSize);
cleanup:
if ((ERROR_SUCCESS != result) && (NULL != buffer))
{
free(buffer);
buffer = NULL;
}
RegCloseKey(hKey);
return buffer;
}
#define MAX_VALUE_LENGTH 255
//---------------------------------------------------------------
DWORD OpenInfsFromRegistry()
{
HKEY hKey;
DWORD dwIndex = 0;
char szData[MAX_PATH + 1];
char szValueName[MAX_VALUE_LENGTH];
DWORD dwValueSize;
DWORD dwDataSize;
DWORD result = ERROR_SUCCESS;
result = RegOpenKeyEx( HKEY_CURRENT_USER, LOADSTATE_KEY, 0, KEY_READ, &hKey );
FAIL_ON_ERROR( result );
do
{
dwDataSize = MAX_PATH;
dwValueSize = MAX_VALUE_LENGTH;
result = RegEnumValueA(hKey, dwIndex,
szValueName, &dwValueSize,
NULL, NULL,
(UCHAR *)szData, &dwDataSize);
if (ERROR_NO_MORE_ITEMS != result)
{
FAIL_ON_ERROR( result );
// If this is an Inf* key, then open the Inf file
if (0 == strncmp(szValueName, "Inf", 3))
{
result = OpenInf( szData );
FAIL_ON_ERROR( result );
}
dwIndex++;
}
} while (ERROR_SUCCESS == result);
cleanup:
RegCloseKey(hKey);
return result;
}
//---------------------------------------------------------------
DWORD ParseParams( int argc, char *argv[], BOOL scan, TCHAR *pszFullLogFilename )
{
int i;
BOOL cleared_flags = FALSE;
DWORD result;
char *error;
int iarg;
BOOL fAppendLog = FALSE;
BOOL fLogFile = FALSE;
TCHAR *logfile = NULL;
TCHAR szArgv[MAX_PATH + 1];
char *lpData;
// Save the OS version.
Win9x = (GetVersion() & 0x80000000);
// Check all the parameters.
for (i = 1; i < argc; i++)
{
if (argv[i][0] == '/' ||
argv[i][0] == '-')
{
switch (tolower(argv[i][1]))
{
case 'a':
OutputAnsi = TRUE;
break;
case 'f':
CopyFiles = TRUE;
if (!cleared_flags)
{
CopyUser = FALSE;
CopySystem = FALSE;
SchedSystem = FALSE;
cleared_flags = TRUE;
}
break;
case 'i':
// Verify that there is a file name.
if (i == argc-1)
{
Win32PrintfResourceA( Console, IDS_INF_REQUIRED );
PrintHelp( scan );
return ERROR_INVALID_PARAMETER;
}
// Open the inf file.
i += 1;
result = OpenInf( argv[i] );
if (result != ERROR_SUCCESS)
return result;
break;
case 'l':
// Verify that there is a file name.
if (i == argc-1)
{
Win32PrintfResourceA( Console, IDS_LOG_REQUIRED );
PrintHelp( scan );
return ERROR_INVALID_PARAMETER;
}
// Fail if the log file was already specified.
if (fLogFile == TRUE)
{
Win32PrintfResourceA( Console, IDS_LOG_ONCE );
PrintHelp( scan );
return ERROR_INVALID_PARAMETER;
}
i += 1;
#ifdef _UNICODE
if (0 == MultiByteToWideChar (GetACP(), 0, argv[i], -1, szArgv, MAX_PATH))
{
result = GetLastError();
Win32PrintfResourceA( Console, IDS_INVALID_PARAMETER, argv[i] );
return result;
}
logfile = szArgv;
#else
logfile = argv[i];
#endif
fLogFile = TRUE;
break;
case 'm':
ReallyCopyFiles = FALSE;
break;
case 'p':
UserPortion = TRUE;
fAppendLog = TRUE;
if (!scan)
{
if (fLogFile == TRUE)
{
Win32PrintfResourceA( Console, IDS_LOG_ONCE );
PrintHelp( scan );
return ERROR_INVALID_PARAMETER;
}
lpData = GetValueFromRegistry("Logfile");
#ifdef _UNICODE
if (0 == MultiByteToWideChar (GetACP(), 0, lpData, -1, szArgv, MAX_PATH))
{
result = GetLastError();
Win32PrintfResourceA( Console, IDS_INVALID_PARAMETER, lpData);
return result;
}
logfile = szArgv;
#else
logfile = lpData;
#endif
fLogFile = TRUE;
MigrationPath = GetValueFromRegistry("Store");
if (MigrationPath != NULL)
{
MultiByteToWideChar(CP_ACP, 0, MigrationPath, -1,
wcsMigrationPath, MAX_PATH + 1);
}
OpenInfsFromRegistry();
}
break;
case 'q':
// TestMode will:
// - skip version checking the OS
// - not create a user hive with /f (still will with /u)
TestMode = TRUE;
break;
case 'r': // run once
SchedSystem = TRUE;
if (!cleared_flags)
{
CopyFiles = FALSE;
CopySystem = FALSE;
CopyUser = FALSE;
cleared_flags = TRUE;
}
break;
case 's':
CopySystem = TRUE;
if (!cleared_flags)
{
CopyFiles = FALSE;
CopyUser = FALSE;
SchedSystem = FALSE;
cleared_flags = TRUE;
}
break;
case 'u':
CopyUser = TRUE;
if (!cleared_flags)
{
CopyFiles = FALSE;
CopySystem = FALSE;
SchedSystem = FALSE;
cleared_flags = TRUE;
}
break;
case 'v':
// Verify that there is a verbosity argument
i += 1;
if ((i == argc) || (1 != sscanf(argv[i], "%d", &iarg)))
{
Win32PrintfResourceA( Console, IDS_VERBOSE_FLAG_REQUIRED );
PrintHelp( scan );
return ERROR_INVALID_PARAMETER;
}
if ( ( iarg & VERBOSE_BIT ) == VERBOSE_BIT )
{
Verbose = TRUE;
}
if ( ( iarg & DEBUGOUTPUT_BIT ) == DEBUGOUTPUT_BIT )
{
DebugOutput = TRUE;
}
if ( ( iarg & VERBOSEREG_BIT ) == VERBOSEREG_BIT )
{
VerboseReg = TRUE;
}
break;
case 'x':
if (!cleared_flags)
{
CopyFiles = FALSE;
CopySystem = FALSE;
CopyUser = FALSE;
SchedSystem = FALSE;
cleared_flags = TRUE;
}
break;
case '9':
Win9x = TRUE;
break;
default:
// There should be no other switches defined.
Win32PrintfResourceA( Console, IDS_INVALID_PARAMETER, argv[i] );
PrintHelp( scan );
return ERROR_INVALID_PARAMETER;
}
}
else if (MigrationPath != NULL)
{
// The path to the server should be specified exactly once.
Win32PrintfResourceA( Console, IDS_INVALID_PARAMETER, argv[i] );
PrintHelp( scan );
return ERROR_INVALID_PARAMETER;
}
else
{
// Save the migration path.
MigrationPath = argv[i];
DWORD ccMigPath;
if (!(ccMigPath = MultiByteToWideChar(CP_ACP,
0,
MigrationPath,
-1,
wcsMigrationPath,
MAX_PATH + 1)))
{
Win32PrintfResourceA( Console,
IDS_INVALID_PARAMETER,
MigrationPath );
PrintHelp( scan );
return ERROR_INVALID_PARAMETER;
}
}
}
// Verify that a path was specified.
if (MigrationPath == NULL)
{
Win32PrintfResourceA( Console, IDS_MISSING_MIGRATION );
PrintHelp( scan );
return ERROR_INVALID_PARAMETER;
}
// Open LogFile
if ( fLogFile == FALSE )
{
if (scan)
logfile = TEXT("scanstate.log");
else
logfile = TEXT("loadstate.log");
}
if (fAppendLog == FALSE)
{
// Delete any previous log
DeleteFile( logfile );
}
LogFile = CreateFile( logfile,
GENERIC_WRITE, 0, NULL,
fAppendLog ? OPEN_ALWAYS : CREATE_NEW,
FILE_ATTRIBUTE_NORMAL, NULL );
if (LogFile == INVALID_HANDLE_VALUE)
{
result = GetLastError();
Win32PrintfResourceA( Console, IDS_OPEN_LOG_ERROR, logfile );
error = NULL;
FormatMessageA( FORMAT_MESSAGE_ALLOCATE_BUFFER |
FORMAT_MESSAGE_FROM_SYSTEM,
0,
result,
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
(char *) &error,
0,
NULL );
if (error != NULL)
{
Win32Printf( Console, error );
LocalFree( error );
}
return result;
}
else if (fAppendLog == TRUE)
{
// Move file pointer to the end of the file,
// so we won't overwrite previous entries
result = SetFilePointer( LogFile, 0, NULL, FILE_END);
if ( result == INVALID_SET_FILE_POINTER )
{
result = GetLastError();
Win32PrintfResourceA( Console, IDS_OPEN_LOG_ERROR, logfile );
error = NULL;
FormatMessageA( FORMAT_MESSAGE_ALLOCATE_BUFFER |
FORMAT_MESSAGE_FROM_SYSTEM,
0,
result,
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
(char *) &error,
0,
NULL );
if (error != NULL)
{
Win32Printf( Console, error );
LocalFree( error );
}
return result;
}
}
TCHAR *ptsFileNamePart;
result = GetFullPathName( logfile, MAX_PATH, pszFullLogFilename, &ptsFileNamePart);
if (0 == result)
{
return GetLastError();
}
return ERROR_SUCCESS;
}