1295 lines
39 KiB
C++
1295 lines
39 KiB
C++
//--------------------------------------------------------------
|
||
//
|
||
// 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;
|
||
}
|