mirror of https://github.com/tongzx/nt5src
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1294 lines
39 KiB
1294 lines
39 KiB
//--------------------------------------------------------------
|
|
//
|
|
// 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;
|
|
}
|