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.
2130 lines
66 KiB
2130 lines
66 KiB
//--------------------------------------------------------------
|
|
//
|
|
// File: loaduser
|
|
//
|
|
// Contents: Load a user hive.
|
|
//
|
|
//---------------------------------------------------------------
|
|
|
|
#include "loadhead.cxx"
|
|
#pragma hdrstop
|
|
|
|
#include <common.hxx>
|
|
#include <objerror.h>
|
|
#include <userenv.h>
|
|
#include <userenvp.h>
|
|
|
|
#include <loadstate.hxx>
|
|
#include <bothchar.cxx>
|
|
|
|
|
|
class CRegFileList
|
|
{
|
|
public:
|
|
inline CRegFileList(TCHAR *ptsRoot,
|
|
TCHAR *ptsKey,
|
|
TCHAR *ptsVal,
|
|
TCHAR *ptsData,
|
|
DWORD dwValueType);
|
|
inline ~CRegFileList();
|
|
|
|
inline void SetNext(CRegFileList *prfl);
|
|
inline CRegFileList * GetNext(void) const;
|
|
|
|
inline void GetData(const TCHAR **pptsRoot,
|
|
const TCHAR **pptsKey,
|
|
const TCHAR **pptsVal,
|
|
const TCHAR **pptsData,
|
|
DWORD *pdwValType) const;
|
|
private:
|
|
TCHAR _tsRootName[MAX_PATH + 1];
|
|
TCHAR _tsKeyName[MAX_PATH + 1];
|
|
TCHAR _tsValueName[MAX_PATH + 1];
|
|
TCHAR _tsData[MAX_PATH + 1];
|
|
DWORD _dwValueType;
|
|
CRegFileList *_prflNext;
|
|
};
|
|
|
|
|
|
inline CRegFileList::CRegFileList(TCHAR *ptsRoot,
|
|
TCHAR *ptsKey,
|
|
TCHAR *ptsVal,
|
|
TCHAR *ptsData,
|
|
DWORD dwValueType)
|
|
{
|
|
if (ptsRoot != NULL && _tcslen(ptsRoot) <= MAX_PATH)
|
|
_tcscpy(_tsRootName, ptsRoot);
|
|
else
|
|
_tsRootName[0] = 0;
|
|
|
|
if (ptsKey != NULL && _tcslen(ptsKey) <= MAX_PATH)
|
|
_tcscpy(_tsKeyName, ptsKey);
|
|
else
|
|
_tsKeyName[0] = 0;
|
|
|
|
if (ptsVal != NULL && _tcslen(ptsVal) <= MAX_PATH)
|
|
_tcscpy(_tsValueName, ptsVal);
|
|
else
|
|
_tsValueName[0] = 0;
|
|
|
|
if (ptsData != NULL && _tcslen(ptsData) <= MAX_PATH)
|
|
_tcscpy(_tsData, ptsData);
|
|
else
|
|
_tsData[0] = 0;
|
|
|
|
_dwValueType = dwValueType;
|
|
_prflNext = NULL;
|
|
}
|
|
|
|
inline CRegFileList::~CRegFileList(void)
|
|
{
|
|
}
|
|
|
|
inline void CRegFileList::SetNext(CRegFileList *prfl)
|
|
{
|
|
_prflNext = prfl;
|
|
}
|
|
|
|
inline CRegFileList * CRegFileList::GetNext(void) const
|
|
{
|
|
return _prflNext;
|
|
}
|
|
|
|
inline void CRegFileList::GetData(const TCHAR **pptsRoot,
|
|
const TCHAR **pptsKey,
|
|
const TCHAR **pptsVal,
|
|
const TCHAR **pptsData,
|
|
DWORD *pdwValType) const
|
|
{
|
|
*pptsRoot = _tsRootName;
|
|
*pptsKey = _tsKeyName;
|
|
*pptsVal = _tsValueName;
|
|
*pptsData = _tsData;
|
|
*pdwValType = _dwValueType;
|
|
}
|
|
|
|
|
|
CRegFileList *g_prflStart;
|
|
|
|
//---------------------------------------------------------------
|
|
// Constants.
|
|
const DWORD SID_GUESS = 80;
|
|
const TCHAR HIVEFILE[] = TEXT("\\ntuser.dat");
|
|
const TCHAR HIVEPATH[] = TEXT("%temp%\\ntuser.dat");
|
|
|
|
const DWORD NUM_HASH_BUCKETS = 121;
|
|
|
|
const TCHAR FORCE_SECTION[] = TEXT("Force Win9x Settings");
|
|
const TCHAR RENAME_SECTION[] = TEXT("Map Win9x to WinNT");
|
|
const TCHAR FUNCTION_SECTION[] = TEXT("Win9x Data Conversion");
|
|
const TCHAR SUPPRESS_SECTION[] = TEXT("Suppress Win9x Settings");
|
|
const TCHAR FILE_SECTION[] = TEXT("Map paths");
|
|
const TCHAR DELETE_SECTION[] = TEXT("Suppress WinNT Settings");
|
|
|
|
//---------------------------------------------------------------
|
|
// Macros
|
|
|
|
// If this symbol is defined, loaduser will apply the state to the
|
|
// specified user and cannot be run as that user.
|
|
// If this symbols is not defined, loaduser will apply state to the
|
|
// current user.
|
|
#define SPECIFIC_USER 1
|
|
|
|
//---------------------------------------------------------------
|
|
// Globals.
|
|
|
|
HASH_HEAD HashTable[NUM_HASH_BUCKETS];
|
|
FUNCTION_FA_MAP FunctionTable[] = {
|
|
{ TEXT("ConvertRecentDocsMRU"), ConvertRecentDocsMRU },
|
|
{ TEXT("ConvertAppearanceScheme"), ConvertAppearanceScheme },
|
|
{ TEXT("ConvertLogFont"), ConvertLogFont },
|
|
{ TEXT("ConvertToDword"), ConvertToDword },
|
|
{ TEXT("ConvertToString"), ConvertToString },
|
|
{ TEXT("AntiAlias"), AntiAlias },
|
|
{ TEXT("FixActiveDesktop"), FixActiveDesktop },
|
|
{ NULL, NULL }
|
|
};
|
|
|
|
//---------------------------------------------------------------
|
|
DWORD ShiftXOR( DWORD x, TCHAR c )
|
|
{
|
|
if (x & 0x80000000)
|
|
return (x << 1) ^ c | 1;
|
|
else
|
|
return (x << 1) ^ c;
|
|
}
|
|
|
|
//---------------------------------------------------------------
|
|
// Create a case insensitive hash of the input.
|
|
DWORD Hash( TCHAR *ptsRoot, TCHAR *ptsKey, TCHAR *ptsValue )
|
|
{
|
|
DWORD x = 0;
|
|
DWORD i;
|
|
|
|
// Hash the ptsRoot.
|
|
if (ptsRoot != NULL)
|
|
for (i = 0; ptsRoot[i] != 0; i++)
|
|
x = ShiftXOR( x, _totupper(ptsRoot[i]) );
|
|
|
|
// Hash the key.
|
|
if (ptsKey != NULL)
|
|
for (i = 0; ptsKey[i] != 0; i++)
|
|
x = ShiftXOR( x, _totupper(ptsKey[i]) );
|
|
|
|
// Hash the value.
|
|
if (ptsValue != NULL)
|
|
for (i = 0; ptsValue[i] != 0; i++)
|
|
x = ShiftXOR( x, _totupper(ptsValue[i]) );
|
|
return x;
|
|
}
|
|
|
|
//---------------------------------------------------------------
|
|
DWORD null_tcsicmp( TCHAR *x, TCHAR *y )
|
|
{
|
|
if (x == NULL)
|
|
if (y == NULL)
|
|
return 0;
|
|
else
|
|
return -1;
|
|
else
|
|
if (y == NULL)
|
|
return 1;
|
|
else
|
|
return _tcsicmp( x, y );
|
|
}
|
|
|
|
//---------------------------------------------------------------
|
|
// Do a case insensitive comparision of the input.
|
|
BOOL Match( HASH_NODE *phnCurrent,
|
|
DWORD dwHash,
|
|
TCHAR *ptsRoot,
|
|
TCHAR *ptsKey,
|
|
TCHAR *ptsValue)
|
|
{
|
|
return phnCurrent->dwHash == dwHash &&
|
|
null_tcsicmp( phnCurrent->ptsRoot, ptsRoot ) == 0 &&
|
|
null_tcsicmp( phnCurrent->ptsKey, ptsKey ) == 0 &&
|
|
null_tcsicmp( phnCurrent->ptsValue, ptsValue ) == 0;
|
|
}
|
|
|
|
|
|
//---------------------------------------------------------------
|
|
HASH_NODE *Lookup( TCHAR *ptsRoot, TCHAR *ptsKey, TCHAR *ptsValue )
|
|
{
|
|
DWORD dwHash = Hash( ptsRoot, ptsKey, ptsValue );
|
|
DWORD dwBucket = dwHash % NUM_HASH_BUCKETS;
|
|
HASH_NODE *phnCurrent = (HASH_NODE *) HashTable[dwBucket].phhNext;
|
|
|
|
// Look at all the nodes in the bucket.
|
|
while (phnCurrent != (HASH_NODE *) &HashTable[dwBucket])
|
|
if (Match( phnCurrent, dwHash, ptsRoot, ptsKey, ptsValue ))
|
|
return phnCurrent;
|
|
else
|
|
phnCurrent = phnCurrent->phnNext;
|
|
return NULL;
|
|
}
|
|
|
|
//---------------------------------------------------------------
|
|
void Insert( HASH_NODE *phnNode )
|
|
{
|
|
DWORD dwHash = Hash( phnNode->ptsRoot,
|
|
phnNode->ptsKey,
|
|
phnNode->ptsValue );
|
|
DWORD dwBucket = dwHash % NUM_HASH_BUCKETS;
|
|
HASH_NODE *phnCurrent;
|
|
|
|
// Look for an existing node.
|
|
|
|
phnCurrent = Lookup( phnNode->ptsRoot,
|
|
phnNode->ptsKey,
|
|
phnNode->ptsValue );
|
|
|
|
// If found, copy in the state of the new node and free it.
|
|
if (phnCurrent != NULL)
|
|
{
|
|
// Assume that the new value or key have not been set.
|
|
if (phnNode->dwAction & rename_value_fa)
|
|
{
|
|
if (phnCurrent->ptsNewValue != NULL)
|
|
{
|
|
//Skip
|
|
if (_tcsicmp(phnCurrent->ptsNewValue, phnNode->ptsNewValue))
|
|
Win32Printf(LogFile,
|
|
"Warning: Skipping rename rule for %s\\%s [%s]"
|
|
" to %s due to previous rename rule "
|
|
"to %s.\r\n",
|
|
phnNode->ptsRoot,
|
|
phnNode->ptsKey,
|
|
phnNode->ptsValue,
|
|
phnNode->ptsNewValue,
|
|
phnCurrent->ptsNewValue);
|
|
goto cleanup;
|
|
}
|
|
else
|
|
phnCurrent->ptsNewValue = phnNode->ptsNewValue;
|
|
}
|
|
|
|
if (phnNode->dwAction & (rename_leaf_fa | rename_path_fa))
|
|
{
|
|
if (phnCurrent->ptsNewKey != NULL)
|
|
{
|
|
//Skip
|
|
if (_tcsicmp(phnCurrent->ptsNewKey, phnNode->ptsNewKey))
|
|
Win32Printf(LogFile,
|
|
"Warning: Skipping rename rule for %s\\%s "
|
|
"to %s due to previous rename rule to %s.\r\n",
|
|
phnNode->ptsRoot,
|
|
phnNode->ptsKey,
|
|
phnNode->ptsNewKey,
|
|
phnCurrent->ptsNewKey);
|
|
goto cleanup;
|
|
}
|
|
else
|
|
phnCurrent->ptsNewKey = phnNode->ptsNewKey;
|
|
}
|
|
|
|
if (phnNode->dwAction & function_fa)
|
|
{
|
|
if (phnCurrent->ptsFunction != NULL)
|
|
{
|
|
//Skip
|
|
if (_tcsicmp(phnCurrent->ptsNewKey, phnNode->ptsNewKey))
|
|
Win32Printf(LogFile,
|
|
"Warning: Skipping function rule for %s\\%s "
|
|
"to %s due to previous function call"
|
|
" to %s.\r\n",
|
|
phnNode->ptsRoot,
|
|
phnNode->ptsKey,
|
|
phnNode->ptsNewKey,
|
|
phnCurrent->ptsFunction);
|
|
goto cleanup;
|
|
}
|
|
else
|
|
phnCurrent->ptsFunction = phnNode->ptsNewKey;
|
|
}
|
|
|
|
phnCurrent->dwAction |= phnNode->dwAction;
|
|
|
|
if (VerboseReg)
|
|
LogReadRule( phnNode );
|
|
|
|
cleanup:
|
|
free( phnNode->ptsRoot );
|
|
free( phnNode->ptsKey );
|
|
free( phnNode->ptsValue );
|
|
free( phnNode );
|
|
}
|
|
|
|
// Insert the node.
|
|
else
|
|
{
|
|
phnCurrent = (HASH_NODE *) &HashTable[dwBucket];
|
|
phnNode->dwHash = dwHash;
|
|
phnNode->phnNext = phnCurrent->phnNext;
|
|
phnNode->phnPrev = phnCurrent;
|
|
phnCurrent->phnNext->phnPrev = phnNode;
|
|
phnCurrent->phnNext = phnNode;
|
|
|
|
if (phnNode->dwAction & function_fa)
|
|
{
|
|
phnNode->ptsFunction = phnNode->ptsNewKey;
|
|
phnNode->ptsNewKey = NULL;
|
|
}
|
|
if (VerboseReg)
|
|
LogReadRule( phnNode );
|
|
}
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Function: DeleteInf
|
|
//
|
|
// Synopsis: deletes values copied from .DEFAULT user hive
|
|
//
|
|
// Arguments:
|
|
//
|
|
// Returns: Appropriate status code
|
|
//
|
|
// History: 20-Sep-99 HenryLee Created
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
DWORD DeleteInf ()
|
|
{
|
|
DWORD dwResult = ERROR_SUCCESS;
|
|
HKEY hRootKey = NULL;
|
|
HKEY hKey = NULL;
|
|
|
|
for (DWORD dwBucket = 0; dwBucket < NUM_HASH_BUCKETS; dwBucket++)
|
|
{
|
|
HASH_NODE *phnCurrent = (HASH_NODE *) HashTable[dwBucket].phhNext;
|
|
|
|
// Look at all the nodes in the bucket.
|
|
while (phnCurrent != (HASH_NODE *) &HashTable[dwBucket])
|
|
{
|
|
if (phnCurrent->dwAction & delete_fa)
|
|
{
|
|
if (phnCurrent->ptsRoot != NULL)
|
|
{
|
|
if (_tcsicmp( TEXT("HKLM"), phnCurrent->ptsRoot ) == 0)
|
|
hRootKey = HKEY_LOCAL_MACHINE;
|
|
else
|
|
hRootKey = CurrentUser;
|
|
dwResult = RegOpenKeyEx( hRootKey,
|
|
phnCurrent->ptsKey,
|
|
NULL,
|
|
KEY_ALL_ACCESS,
|
|
&hKey );
|
|
if (dwResult == ERROR_SUCCESS)
|
|
{
|
|
dwResult = RegDeleteValue (hKey, phnCurrent->ptsValue);
|
|
RegCloseKey (hKey);
|
|
if (dwResult != ERROR_SUCCESS)
|
|
{
|
|
if (Verbose)
|
|
Win32Printf(LogFile,
|
|
"Warning. Cannot delete %s\\%s\n",
|
|
phnCurrent->ptsKey,
|
|
phnCurrent->ptsValue);
|
|
dwResult = ERROR_SUCCESS;
|
|
}
|
|
}
|
|
else dwResult = ERROR_SUCCESS; // keep on going
|
|
}
|
|
}
|
|
phnCurrent = phnCurrent->phnNext;
|
|
}
|
|
}
|
|
return dwResult;
|
|
}
|
|
|
|
|
|
DWORD ApplyRule(HASH_NODE *phnRule,
|
|
TCHAR *ptsKeyMatch,
|
|
TCHAR **pptsRoot,
|
|
TCHAR **pptsKey,
|
|
TCHAR **pptsValue,
|
|
DWORD *pdwType,
|
|
BYTE **ppbData,
|
|
DWORD *pdwDataLen,
|
|
BOOL *pfForce)
|
|
{
|
|
DWORD dwResult = ERROR_SUCCESS;
|
|
|
|
if (phnRule->dwAction & force_fa)
|
|
{
|
|
if (DebugOutput || VerboseReg)
|
|
Win32Printf(LogFile,
|
|
"Applying force rule to %s\\%s [%s]\r\n",
|
|
*pptsRoot,
|
|
*pptsKey,
|
|
(*pptsValue) ? *pptsValue : TEXT("NULL"));
|
|
|
|
*pfForce = TRUE;
|
|
}
|
|
|
|
if (phnRule->dwAction & function_fa)
|
|
{
|
|
FUNCTION_FA_MAP *pMap = FunctionTable;
|
|
while (pMap != NULL && pMap->ptsName != NULL)
|
|
{
|
|
if (lstrcmp (pMap->ptsName, phnRule->ptsFunction) == 0 &&
|
|
pMap->pfunction)
|
|
{
|
|
dwResult = (pMap->pfunction) (pdwType,
|
|
ppbData,
|
|
pdwDataLen);
|
|
LOG_ASSERT (dwResult);
|
|
}
|
|
pMap++;
|
|
}
|
|
if (DebugOutput || VerboseReg)
|
|
Win32Printf(LogFile,
|
|
"Applying function_fa rule to %s\\%s [%s] "
|
|
"(function %s)\r\n",
|
|
*pptsRoot,
|
|
*pptsKey,
|
|
(*pptsValue) ? *pptsValue : TEXT("NULL"),
|
|
phnRule->ptsFunction);
|
|
|
|
}
|
|
|
|
// Replace the path matched with the new path and leave the
|
|
// portion of the path that was not matched.
|
|
if (phnRule->dwAction & rename_path_fa)
|
|
{
|
|
DWORD dwLen = _tcslen( phnRule->ptsNewKey ) + _tcslen(ptsKeyMatch);
|
|
TCHAR * ptsBuffer = (TCHAR *) malloc( (dwLen + 1) *sizeof(TCHAR) );
|
|
LOG_ASSERT_EXPR( ptsBuffer != NULL,
|
|
IDS_NOT_ENOUGH_MEMORY,
|
|
dwResult,
|
|
ERROR_NOT_ENOUGH_MEMORY );
|
|
_tcscpy( ptsBuffer, phnRule->ptsNewKey );
|
|
_tcscat( ptsBuffer, ptsKeyMatch );
|
|
|
|
if (DebugOutput || VerboseReg)
|
|
Win32Printf(LogFile,
|
|
"Applying rename_path rule to %s\\%s [%s], "
|
|
"result %s\r\n",
|
|
*pptsRoot,
|
|
*pptsKey,
|
|
(*pptsValue) ? *pptsValue : TEXT("NULL"),
|
|
ptsBuffer);
|
|
free( *pptsKey );
|
|
*pptsKey = ptsBuffer;
|
|
}
|
|
|
|
// Replace the entire key with the new key.
|
|
if (phnRule->dwAction & rename_leaf_fa)
|
|
{
|
|
DWORD dwLen = _tcslen( phnRule->ptsNewKey ) + 1;
|
|
TCHAR *ptsBuffer = (TCHAR *) malloc( dwLen*sizeof(TCHAR) );
|
|
LOG_ASSERT_EXPR( ptsBuffer != NULL,
|
|
IDS_NOT_ENOUGH_MEMORY,
|
|
dwResult,
|
|
ERROR_NOT_ENOUGH_MEMORY );
|
|
_tcscpy( ptsBuffer, phnRule->ptsNewKey );
|
|
if (DebugOutput || VerboseReg)
|
|
Win32Printf(LogFile,
|
|
"Applying rename_leaf rule to %s\\%s [%s], "
|
|
"result %s\r\n",
|
|
*pptsRoot,
|
|
*pptsKey,
|
|
(*pptsValue) ? *pptsValue : TEXT("NULL"),
|
|
ptsBuffer);
|
|
free( *pptsKey );
|
|
*pptsKey = ptsBuffer;
|
|
}
|
|
|
|
// Replace the entire value with the new value.
|
|
if (phnRule->dwAction & rename_value_fa)
|
|
{
|
|
DWORD dwLen = _tcslen( phnRule->ptsNewValue ) + 1;
|
|
TCHAR *ptsBuffer = (TCHAR *) malloc( dwLen*sizeof(TCHAR) );
|
|
LOG_ASSERT_EXPR( ptsBuffer != NULL,
|
|
IDS_NOT_ENOUGH_MEMORY,
|
|
dwResult,
|
|
ERROR_NOT_ENOUGH_MEMORY );
|
|
_tcscpy( ptsBuffer, phnRule->ptsNewValue );
|
|
if (DebugOutput || VerboseReg)
|
|
Win32Printf(LogFile,
|
|
"Applying rename_value rule to %s\\%s [%s], "
|
|
"result %s\r\n",
|
|
*pptsRoot,
|
|
*pptsKey,
|
|
(*pptsValue) ? *pptsValue : TEXT("NULL"),
|
|
ptsBuffer);
|
|
|
|
free( *pptsValue );
|
|
*pptsValue = ptsBuffer;
|
|
}
|
|
|
|
// Ask what the new path should be.
|
|
if ((phnRule->dwAction & file_fa) && *pptsValue != NULL)
|
|
{
|
|
//Nothing to do here, we'll do this in Filter
|
|
}
|
|
|
|
if (!(SourceVersion & 0x80000000))
|
|
*pfForce = TRUE;
|
|
|
|
cleanup:
|
|
return dwResult;
|
|
}
|
|
|
|
/***************************************************************************
|
|
|
|
Filter
|
|
|
|
Look for a rule for each component of the path. If found, apply it.
|
|
|
|
***************************************************************************/
|
|
DWORD Filter( TCHAR **pptsRoot,
|
|
TCHAR **pptsKey,
|
|
TCHAR **pptsValue,
|
|
DWORD *pdwType,
|
|
BYTE **ppbData,
|
|
DWORD *pdwDataLen,
|
|
BOOL *pfForce )
|
|
{
|
|
DWORD dwKeyLen = _tcslen( *pptsKey ) + 1;
|
|
TCHAR *ptsKeyPath = (TCHAR *) _alloca( dwKeyLen*sizeof(TCHAR) );
|
|
TCHAR *ptsFrom;
|
|
TCHAR *ptsTo;
|
|
TCHAR *ptsEnd;
|
|
HASH_NODE *phnRule = NULL;
|
|
DWORD dwResult = ERROR_SUCCESS;
|
|
BOOL fSuppress = FALSE;
|
|
BOOL fFileRuleFound = FALSE;
|
|
|
|
//Make copies of all the initial keys
|
|
TCHAR *ptsRootBuf = (TCHAR *) _alloca((_tcslen(*pptsRoot) + 1) *
|
|
sizeof(TCHAR));
|
|
TCHAR *ptsKeyBuf = (TCHAR *) _alloca( dwKeyLen * sizeof(TCHAR) );
|
|
TCHAR *ptsValBuf = NULL;
|
|
|
|
if (*pptsValue)
|
|
{
|
|
ptsValBuf = (TCHAR *) _alloca((_tcslen(*pptsValue) + 1) *
|
|
sizeof(TCHAR));
|
|
_tcscpy(ptsValBuf, *pptsValue);
|
|
}
|
|
|
|
_tcscpy(ptsRootBuf, *pptsRoot);
|
|
_tcscpy(ptsKeyBuf, *pptsKey);
|
|
|
|
ptsFrom = ptsKeyBuf;
|
|
|
|
phnRule = NULL;
|
|
|
|
// Loop over each part of the key path.
|
|
ptsTo = ptsKeyPath;
|
|
|
|
while (ptsFrom[0] != 0)
|
|
{
|
|
// Copy the next segment from pptsKey to ptsKeyPath.
|
|
ptsEnd = _tcschr( &ptsFrom[1], L'\\' );
|
|
if (ptsEnd == NULL)
|
|
ptsEnd = ptsKeyBuf+dwKeyLen-1;
|
|
_tcsncpy( ptsTo, ptsFrom, ptsEnd-ptsFrom );
|
|
ptsTo[ptsEnd-ptsFrom] = 0;
|
|
ptsTo += ptsEnd-ptsFrom;
|
|
ptsFrom = ptsEnd;
|
|
|
|
if ( *pptsValue != NULL )
|
|
{
|
|
// First look up each piece with value attached
|
|
phnRule = Lookup( ptsRootBuf, ptsKeyPath, ptsValBuf );
|
|
|
|
// Apply only if recursive or at the end of the key
|
|
if (phnRule != NULL &&
|
|
((phnRule->dwAction & recursive_fa) || (ptsFrom[0]==0)))
|
|
{
|
|
dwResult = ApplyRule(phnRule,
|
|
ptsFrom,
|
|
pptsRoot,
|
|
pptsKey,
|
|
pptsValue,
|
|
pdwType,
|
|
ppbData,
|
|
pdwDataLen,
|
|
pfForce);
|
|
if (dwResult)
|
|
goto cleanup;
|
|
if (phnRule->dwAction & suppress_fa)
|
|
{
|
|
fSuppress = TRUE;
|
|
}
|
|
if (phnRule->dwAction & file_fa &&
|
|
(REG_SZ == *pdwType || REG_EXPAND_SZ == *pdwType || REG_MULTI_SZ == *pdwType))
|
|
{
|
|
fSuppress = TRUE;
|
|
fFileRuleFound = TRUE;
|
|
}
|
|
}
|
|
}
|
|
|
|
// Check with no value attached
|
|
phnRule = Lookup( ptsRootBuf, ptsKeyPath, NULL );
|
|
|
|
// Apply only if recursive or at the end of the key
|
|
if (phnRule != NULL &&
|
|
((phnRule->dwAction & recursive_fa) || (ptsFrom[0]==0)))
|
|
{
|
|
dwResult = ApplyRule(phnRule,
|
|
ptsFrom,
|
|
pptsRoot,
|
|
pptsKey,
|
|
pptsValue,
|
|
pdwType,
|
|
ppbData,
|
|
pdwDataLen,
|
|
pfForce);
|
|
if (dwResult)
|
|
goto cleanup;
|
|
|
|
if (phnRule->dwAction & suppress_fa)
|
|
{
|
|
fSuppress = TRUE;
|
|
}
|
|
if (phnRule->dwAction & file_fa &&
|
|
(REG_SZ == *pdwType || REG_EXPAND_SZ == *pdwType || REG_MULTI_SZ == *pdwType))
|
|
{
|
|
fSuppress = TRUE;
|
|
fFileRuleFound = TRUE;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (fFileRuleFound)
|
|
{
|
|
//Add to the list of files to be fixed up later.
|
|
CRegFileList *prfl = new CRegFileList(*pptsRoot,
|
|
*pptsKey,
|
|
*pptsValue,
|
|
(TCHAR *)*ppbData,
|
|
*pdwType);
|
|
|
|
if (prfl == NULL)
|
|
{
|
|
Win32PrintfResource(LogFile,
|
|
IDS_NOT_ENOUGH_MEMORY);
|
|
dwResult = ERROR_NOT_ENOUGH_MEMORY;
|
|
goto cleanup;
|
|
}
|
|
|
|
if (DebugOutput || VerboseReg)
|
|
Win32Printf(LogFile,
|
|
"Applying file_fa rule to %s\\%s [%s], "
|
|
"data = %s\r\n",
|
|
*pptsRoot,
|
|
*pptsKey,
|
|
(*pptsValue) ? *pptsValue : TEXT("NULL"),
|
|
(TCHAR *)*ppbData);
|
|
|
|
prfl->SetNext(g_prflStart);
|
|
g_prflStart = prfl;
|
|
}
|
|
|
|
if (fSuppress)
|
|
{
|
|
free(*pptsKey);
|
|
free(*pptsValue);
|
|
*pptsRoot = NULL;
|
|
*pptsKey = NULL;
|
|
*pptsValue = NULL;
|
|
}
|
|
|
|
cleanup:
|
|
if (Verbose && dwResult != ERROR_SUCCESS)
|
|
printf( "Filter failed with 0x%x\r\n", dwResult );
|
|
return dwResult;
|
|
}
|
|
|
|
//---------------------------------------------------------------
|
|
DWORD LoadSectionRules( const TCHAR *ptsSection, DWORD dwFlags )
|
|
{
|
|
INFCONTEXT ic;
|
|
DWORD dwResult = ERROR_SUCCESS;
|
|
BOOL fSuccess;
|
|
HASH_NODE *phnRule;
|
|
|
|
// Open the section.
|
|
fSuccess = SetupFindFirstLine( InputInf, ptsSection, NULL, &ic );
|
|
|
|
// Read all the rules in the section.
|
|
while (fSuccess)
|
|
{
|
|
// Parse the rule.
|
|
dwResult = ParseRule( &ic, &phnRule );
|
|
FAIL_ON_ERROR( dwResult );
|
|
if (dwFlags == function_fa) // remove the rename flags
|
|
{
|
|
phnRule->dwAction = function_fa;
|
|
}
|
|
else
|
|
{
|
|
phnRule->dwAction |= dwFlags;
|
|
}
|
|
|
|
// Save the rule in the hash table.
|
|
Insert( phnRule );
|
|
phnRule = NULL;
|
|
|
|
// Advance to the next line.
|
|
fSuccess = SetupFindNextLine( &ic, &ic );
|
|
}
|
|
|
|
cleanup:
|
|
return dwResult;
|
|
}
|
|
|
|
/***************************************************************************
|
|
|
|
InitializeHash
|
|
|
|
Read the filtering rules from the specified INF file. Read the rules
|
|
from the sections for forcing, suppressing, renaming, and functions.
|
|
|
|
***************************************************************************/
|
|
DWORD InitializeHash()
|
|
{
|
|
DWORD i;
|
|
DWORD dwResult = ERROR_SUCCESS;
|
|
INFCONTEXT ic;
|
|
BOOL fSuccess;
|
|
TCHAR *ptsBuffer;
|
|
CStringList *pslAdd = NULL;
|
|
CStringList *pslRen = NULL;
|
|
CStringList *pslFile = NULL;
|
|
CStringList *pslDel = NULL;
|
|
CStringList *pslCurr;
|
|
|
|
// Initialize the hash table.
|
|
for (i = 0; i < NUM_HASH_BUCKETS; i++)
|
|
{
|
|
HashTable[i].phhNext = &HashTable[i];
|
|
HashTable[i].phhPrev = &HashTable[i];
|
|
}
|
|
|
|
// Load rules from the filter sections.
|
|
|
|
// Since we try to force by default, it is okay to load in the Win9x force rules
|
|
// and apply them even if the source is NT. If they exist, we'll force overwriting,
|
|
// but if not, no harm done.
|
|
dwResult = LoadSectionRules( FORCE_SECTION, force_fa );
|
|
LOG_ASSERT( dwResult );
|
|
|
|
// We shouldn't write these keys regardless of the source OS
|
|
dwResult = LoadSectionRules( SUPPRESS_SECTION, suppress_fa );
|
|
LOG_ASSERT( dwResult );
|
|
|
|
// This section describes keys that should be removed from the default hive before
|
|
// migrating the settings. It is not specific to any source OS.
|
|
dwResult = LoadSectionRules( DELETE_SECTION, delete_fa );
|
|
LOG_ASSERT( dwResult );
|
|
|
|
if (SourceVersion & 0x80000000)
|
|
{
|
|
dwResult = LoadSectionRules( RENAME_SECTION, 0 );
|
|
LOG_ASSERT( dwResult );
|
|
dwResult = LoadSectionRules( FILE_SECTION, file_fa );
|
|
LOG_ASSERT( dwResult );
|
|
dwResult = LoadSectionRules( FUNCTION_SECTION, function_fa );
|
|
LOG_ASSERT( dwResult );
|
|
}
|
|
|
|
// Load from copied rules sections.
|
|
dwResult = LoadSectionRules( EXTENSION_ADDREG_SECTION, force_fa );
|
|
LOG_ASSERT( dwResult );
|
|
dwResult = LoadSectionRules( EXTENSION_RENREG_SECTION, 0 );
|
|
LOG_ASSERT( dwResult );
|
|
dwResult = LoadSectionRules( EXTENSION_REGFILE_SECTION, file_fa );
|
|
LOG_ASSERT( dwResult );
|
|
dwResult = LoadSectionRules( EXTENSION_DELREG_SECTION, suppress_fa );
|
|
LOG_ASSERT( dwResult );
|
|
|
|
// Open the section list.
|
|
fSuccess = SetupFindFirstLine( InputInf, EXTENSION_SECTION, NULL, &ic );
|
|
if (!fSuccess)
|
|
return ERROR_SUCCESS;
|
|
|
|
// Allocate the section name lists.
|
|
pslAdd = new CStringList( 0 );
|
|
pslRen = new CStringList( 0 );
|
|
pslFile = new CStringList( 0 );
|
|
pslDel = new CStringList( 0 );
|
|
if (pslAdd == NULL || pslRen == NULL || pslFile == NULL || pslDel == NULL)
|
|
{
|
|
dwResult = ERROR_NOT_ENOUGH_MEMORY;
|
|
LOG_ASSERT( dwResult );
|
|
}
|
|
|
|
// Make lists of the names of sections of each type.
|
|
do
|
|
{
|
|
// Parse the line.
|
|
dwResult = ParseSectionList( &ic, &ptsBuffer, &pslCurr );
|
|
FAIL_ON_ERROR( dwResult );
|
|
|
|
// Save the value if its one of the ones we are looking for.
|
|
if (ptsBuffer != NULL)
|
|
{
|
|
if (_tcsicmp( ptsBuffer, ADDREG_LABEL ) == 0)
|
|
pslAdd->Add( pslCurr );
|
|
else if (_tcsicmp( ptsBuffer, RENREG_LABEL ) == 0)
|
|
pslRen->Add( pslCurr );
|
|
else if (_tcsicmp( ptsBuffer, REGFILE_LABEL ) == 0)
|
|
pslFile->Add( pslCurr );
|
|
else if (_tcsicmp( ptsBuffer, DELREG_LABEL ) == 0)
|
|
pslDel->Add( pslCurr );
|
|
else if (!_tcsicmp( ptsBuffer, COPYFILES_LABEL ) &&
|
|
!_tcsicmp( ptsBuffer, DELFILES_LABEL ))
|
|
LOG_ASSERT_EXPR( FALSE, IDS_INF_ERROR, dwResult, SPAPI_E_GENERAL_SYNTAX );
|
|
free( ptsBuffer );
|
|
}
|
|
|
|
// Advance to the next line.
|
|
fSuccess = SetupFindNextLine( &ic, &ic );
|
|
|
|
} while( fSuccess);
|
|
|
|
// Process all the addreg sections.
|
|
for (pslCurr = pslAdd->Next();
|
|
pslCurr != pslAdd;
|
|
pslCurr = pslCurr->Next())
|
|
{
|
|
dwResult = LoadSectionRules( pslCurr->String(), force_fa );
|
|
LOG_ASSERT( dwResult );
|
|
}
|
|
|
|
// Process all the renreg sections.
|
|
for (pslCurr = pslRen->Next();
|
|
pslCurr != pslRen;
|
|
pslCurr = pslCurr->Next())
|
|
{
|
|
dwResult = LoadSectionRules( pslCurr->String(), 0 );
|
|
LOG_ASSERT( dwResult );
|
|
}
|
|
|
|
// Process all the regfile sections.
|
|
for (pslCurr = pslFile->Next();
|
|
pslCurr != pslFile;
|
|
pslCurr = pslCurr->Next())
|
|
{
|
|
dwResult = LoadSectionRules( pslCurr->String(), file_fa );
|
|
LOG_ASSERT( dwResult );
|
|
}
|
|
|
|
// Process all the delreg sections.
|
|
for (pslCurr = pslDel->Next();
|
|
pslCurr != pslDel;
|
|
pslCurr = pslCurr->Next())
|
|
{
|
|
dwResult = LoadSectionRules( pslCurr->String(), suppress_fa );
|
|
LOG_ASSERT( dwResult );
|
|
}
|
|
|
|
cleanup:
|
|
if (pslAdd != NULL)
|
|
delete pslAdd;
|
|
if (pslRen != NULL)
|
|
delete pslRen;
|
|
if (pslFile != NULL)
|
|
delete pslFile;
|
|
if (pslDel != NULL)
|
|
delete pslDel;
|
|
return dwResult;
|
|
}
|
|
|
|
/***************************************************************************
|
|
|
|
ParseAssignment
|
|
|
|
Parse the line into a variable name and a value name. Allow optional
|
|
whitespace and quotes around the variable or value names. This function
|
|
allocates buffers for the variable and value names which the caller must
|
|
free. Return a NULL pointer for the variable name if the line cannot be
|
|
parsed.
|
|
|
|
Note: The caller is required to free the following variables even if
|
|
this function fails.
|
|
pptsVar
|
|
pptsValue
|
|
|
|
***************************************************************************/
|
|
DWORD ParseAssignment( INFCONTEXT *pic,
|
|
DWORD dwLen,
|
|
TCHAR **pptsVar,
|
|
TCHAR **pptsValue )
|
|
{
|
|
BOOL fSuccess;
|
|
DWORD dwResult = ERROR_SUCCESS;
|
|
DWORD dwVarLen;
|
|
DWORD dwValueLen;
|
|
|
|
// Initialize out params
|
|
*pptsVar = *pptsValue = NULL;
|
|
|
|
// Query the two lengths we need
|
|
fSuccess = SetupGetStringField( pic, 0, NULL, 0, &dwVarLen );
|
|
LOG_ASSERT_GLE( fSuccess, dwResult );
|
|
|
|
fSuccess = SetupGetStringField( pic, 1, NULL, 0, &dwValueLen );
|
|
LOG_ASSERT_GLE( fSuccess, dwResult );
|
|
|
|
// Allocate memory for both
|
|
*pptsVar = (TCHAR *) malloc( dwVarLen * sizeof(TCHAR) );
|
|
*pptsValue = (TCHAR *) malloc( dwValueLen * sizeof(TCHAR) );
|
|
if( *pptsVar == NULL || *pptsValue == NULL )
|
|
{
|
|
free(*pptsVar);
|
|
free(*pptsValue);
|
|
*pptsVar = *pptsValue = NULL;
|
|
|
|
Win32PrintfResource( LogFile, IDS_NOT_ENOUGH_MEMORY );
|
|
return ERROR_NOT_ENOUGH_MEMORY;
|
|
}
|
|
|
|
// Read the variable name
|
|
fSuccess = SetupGetStringField( pic, 0, *pptsVar, dwVarLen, NULL );
|
|
LOG_ASSERT_EXPR(fSuccess, IDS_GETSTRINGFIELD_ERROR,
|
|
dwResult, SPAPI_E_SECTION_NAME_TOO_LONG);
|
|
|
|
// Read the value name
|
|
fSuccess = SetupGetStringField( pic, 1, *pptsValue, dwValueLen, NULL );
|
|
LOG_ASSERT_EXPR(fSuccess, IDS_GETSTRINGFIELD_ERROR,
|
|
dwResult, SPAPI_E_SECTION_NAME_TOO_LONG);
|
|
|
|
cleanup:
|
|
return dwResult;
|
|
}
|
|
|
|
|
|
/***************************************************************************
|
|
|
|
ReadUser
|
|
|
|
Read the user section of migration.inf and return the values for the
|
|
name of the settings section, the user name, and the domain name.
|
|
|
|
Note: The caller is required to free the following variables even if
|
|
this function fails.
|
|
pptsSettingsSection
|
|
pptsDomainName
|
|
pptsUsername
|
|
|
|
***************************************************************************/
|
|
DWORD ReadUser( TCHAR **pptsSettingsSection,
|
|
TCHAR **pptsDomainName,
|
|
TCHAR **pptsUsername )
|
|
{
|
|
DWORD dwResult;
|
|
BOOL fSuccess;
|
|
INFCONTEXT ic;
|
|
DWORD dwReqLen;
|
|
TCHAR *var;
|
|
TCHAR *value;
|
|
TCHAR *user_section = NULL;
|
|
|
|
// Find the section for users.
|
|
fSuccess = SetupFindFirstLine( InputInf, USERS_SECTION, NULL, &ic );
|
|
if (fSuccess == FALSE)
|
|
{
|
|
dwResult = GetLastError();
|
|
if (Verbose)
|
|
Win32Printf(LogFile,
|
|
"ERROR: Could not find %s in Input INF: %d\r\n",
|
|
USERS_SECTION, dwResult);
|
|
LOG_ASSERT( dwResult );
|
|
}
|
|
|
|
// Find the name of the section containing user info.
|
|
do
|
|
{
|
|
// Find the length of the line.
|
|
dwReqLen = 0;
|
|
fSuccess = SetupGetLineText( &ic, NULL, NULL, NULL, NULL, 0, &dwReqLen );
|
|
if (dwReqLen == 0)
|
|
LOG_ASSERT_GLE( fSuccess, dwResult );
|
|
|
|
// Parse the line.
|
|
dwResult = ParseAssignment( &ic, dwReqLen, &var, &value );
|
|
FAIL_ON_ERROR( dwResult );
|
|
|
|
// Save the value if its one of the ones we are looking for.
|
|
if (var != NULL)
|
|
{
|
|
if (_tcsicmp( var, TEXT("section") ) == 0)
|
|
user_section = value;
|
|
else
|
|
free( value );
|
|
free( var );
|
|
}
|
|
|
|
// Advance to the next line.
|
|
fSuccess = SetupFindNextLine( &ic, &ic );
|
|
|
|
} while( fSuccess);
|
|
|
|
// Find the section for the user.
|
|
fSuccess = SetupFindFirstLine( InputInf, user_section, NULL, &ic );
|
|
LOG_ASSERT_GLE( fSuccess, dwResult );
|
|
|
|
// Read each line in the section.
|
|
do
|
|
{
|
|
// Find the length of the line.
|
|
dwReqLen = 0;
|
|
fSuccess = SetupGetLineText( &ic, NULL, NULL, NULL, NULL, 0, &dwReqLen );
|
|
if (dwReqLen == 0)
|
|
LOG_ASSERT_GLE( fSuccess, dwResult );
|
|
|
|
// Parse the line.
|
|
dwResult = ParseAssignment( &ic, dwReqLen, &var, &value );
|
|
FAIL_ON_ERROR( dwResult );
|
|
|
|
// Save the value if its one of the ones we are looking for.
|
|
if (var != NULL)
|
|
{
|
|
if (_tcsicmp( var, TEXT("user") ) == 0)
|
|
*pptsUsername = value;
|
|
else if (_tcsicmp( var, TEXT("domain") ) == 0)
|
|
*pptsDomainName = value;
|
|
else if (_tcsicmp( var, TEXT("section") ) == 0)
|
|
*pptsSettingsSection = value;
|
|
else
|
|
free( value );
|
|
free( var );
|
|
}
|
|
|
|
// Advance to the next line.
|
|
fSuccess = SetupFindNextLine( &ic, &ic );
|
|
|
|
} while( fSuccess);
|
|
|
|
// It is an error if the username, domainname, or settings section
|
|
// isn't specified.
|
|
if (*pptsUsername == NULL || *pptsDomainName == NULL || *pptsSettingsSection == NULL)
|
|
{
|
|
Win32PrintfResource( LogFile, IDS_INF_ERROR );
|
|
dwResult = SPAPI_E_GENERAL_SYNTAX;
|
|
}
|
|
|
|
cleanup:
|
|
if (user_section != NULL)
|
|
free( user_section );
|
|
return dwResult;
|
|
}
|
|
|
|
/***************************************************************************
|
|
|
|
ParseRegistry
|
|
|
|
Parse a line describing a registry key or value.
|
|
|
|
reg-root-string, [subkey], [value-name], [flags], [value]
|
|
|
|
reg-root-string One of HKCR, HKCU, HKLM, HKU, HKR
|
|
subkey String name of subkey, may be quoted.
|
|
value-name String name of value, may be quoted.
|
|
flags One of the following
|
|
0x0 REG_SZ
|
|
0x10000 REG_MULTI_SZ
|
|
0x20000 REG_EXPAND_SZ
|
|
0x1 REG_BINARY
|
|
0x10001 REG_DWORD
|
|
|
|
0x100001 REG_MULTI_SZ stored as binary because it
|
|
contains embedded newlines.
|
|
0x200001 REG_EXPAND_SZ stored as binary because it
|
|
contains embedded newlines.
|
|
0x400001 REG_SZ stored as binary because it
|
|
contains embedded newlines.
|
|
0x800000 REG_NONE
|
|
other custom registry type directly copied
|
|
|
|
value Depends on flags
|
|
REG_SZ String, may be quoted.
|
|
REG_MULTI_SZ List of comma separated strings, each of
|
|
which may be quoted.
|
|
REG_EXPAND_SZ String, may be quoted.
|
|
REG_BINARY List of comma separated bytes in hex.
|
|
REG_DWORD Integer
|
|
|
|
Note: The caller is required to free the following variables even if
|
|
this function fails.
|
|
pptsRootName
|
|
key_name
|
|
value_name
|
|
data
|
|
|
|
***************************************************************************/
|
|
DWORD ParseRegistry( INFCONTEXT *pic, DWORD line_len,
|
|
TCHAR **pptsRootName, TCHAR **key_name,
|
|
TCHAR **value_name,
|
|
DWORD *value_type, TCHAR **data, DWORD *data_len )
|
|
{
|
|
DWORD len;
|
|
DWORD temp;
|
|
BYTE *bytes;
|
|
DWORD size = line_len*sizeof(TCHAR);
|
|
DWORD req_size;
|
|
BOOL fSuccess;
|
|
DWORD dwResult = ERROR_SUCCESS;
|
|
|
|
// Allocate memory for all the parameters.
|
|
*key_name = (TCHAR *) malloc( size );
|
|
*value_name = (TCHAR *) malloc( size );
|
|
*data = (TCHAR *) malloc( size );
|
|
*pptsRootName = (TCHAR *) malloc( size );
|
|
if (*key_name == NULL || *value_name == NULL || *data == NULL ||
|
|
*pptsRootName == NULL)
|
|
{
|
|
free( *key_name );
|
|
free( *value_name );
|
|
free( *data );
|
|
free( *pptsRootName );
|
|
*key_name = NULL;
|
|
*value_name = NULL;
|
|
*data = NULL;
|
|
*pptsRootName = NULL;
|
|
Win32PrintfResource( LogFile, IDS_NOT_ENOUGH_MEMORY );
|
|
return ERROR_NOT_ENOUGH_MEMORY;
|
|
}
|
|
|
|
// Get the reg-root-string.
|
|
fSuccess = SetupGetStringField( pic, 1, *pptsRootName, line_len, &req_size );
|
|
LOG_ASSERT_EXPR( fSuccess, IDS_INF_ERROR, dwResult, SPAPI_E_GENERAL_SYNTAX );
|
|
|
|
// Verify that it is HKR or HKLM.
|
|
fSuccess = (_tcsicmp( TEXT("HKR"), *pptsRootName ) == 0) ||
|
|
(_tcsicmp( TEXT("HKLM"), *pptsRootName ) == 0);
|
|
LOG_ASSERT_EXPR( fSuccess, IDS_INF_ERROR, dwResult, SPAPI_E_GENERAL_SYNTAX );
|
|
|
|
// Get the subkey.
|
|
fSuccess = SetupGetStringField( pic, 2, *key_name, line_len, &req_size );
|
|
LOG_ASSERT_EXPR( fSuccess, IDS_INF_ERROR, dwResult, SPAPI_E_GENERAL_SYNTAX );
|
|
|
|
// Get the value name.
|
|
fSuccess = SetupGetStringField( pic, 3, *value_name, line_len, &req_size );
|
|
LOG_ASSERT_EXPR( fSuccess, IDS_INF_ERROR, dwResult, SPAPI_E_GENERAL_SYNTAX );
|
|
|
|
// Get the flags. _tcstol detects a leading 0x and converts from hex.
|
|
fSuccess = SetupGetIntField( pic, 4, (int *) value_type );
|
|
|
|
// Read the data based on the data type.
|
|
if (fSuccess) // value_type is valid
|
|
{
|
|
// Read a string.
|
|
if (*value_type == 0)
|
|
{
|
|
fSuccess = SetupGetStringField( pic, 5, *data, line_len, &req_size );
|
|
LOG_ASSERT_EXPR( fSuccess, IDS_INF_ERROR, dwResult, SPAPI_E_GENERAL_SYNTAX );
|
|
|
|
*data_len = req_size*sizeof(TCHAR);
|
|
*value_type = REG_SZ;
|
|
}
|
|
|
|
// Read an expand string.
|
|
else if (*value_type == 0x20000)
|
|
{
|
|
fSuccess = SetupGetStringField( pic, 5, *data, line_len, &req_size );
|
|
LOG_ASSERT_EXPR( fSuccess, IDS_INF_ERROR, dwResult, SPAPI_E_GENERAL_SYNTAX );
|
|
*data_len = req_size*sizeof(TCHAR);
|
|
*value_type = REG_EXPAND_SZ;
|
|
}
|
|
|
|
// Read a multi string.
|
|
else if (*value_type == 0x10000)
|
|
{
|
|
fSuccess = SetupGetMultiSzField( pic, 5, *data, line_len, &req_size );
|
|
LOG_ASSERT_EXPR( fSuccess, IDS_INF_ERROR, dwResult, SPAPI_E_GENERAL_SYNTAX );
|
|
*data_len = req_size*sizeof(TCHAR);
|
|
*value_type = REG_MULTI_SZ;
|
|
}
|
|
|
|
// Read a dword.
|
|
else if (*value_type == 0x10001)
|
|
{
|
|
fSuccess = SetupGetIntField( pic, 5, (int *) *data );
|
|
LOG_ASSERT_EXPR( fSuccess, IDS_INF_ERROR, dwResult, SPAPI_E_GENERAL_SYNTAX );
|
|
*data_len = sizeof(DWORD);
|
|
*value_type = REG_DWORD;
|
|
}
|
|
|
|
// Read a binary.
|
|
else
|
|
{
|
|
fSuccess = SetupGetBinaryField( pic, 5, (BYTE *) *data, size, &req_size );
|
|
LOG_ASSERT_EXPR( fSuccess, IDS_INF_ERROR, dwResult, SPAPI_E_GENERAL_SYNTAX );
|
|
*data_len = req_size;
|
|
if (*value_type == 1)
|
|
*value_type = REG_BINARY;
|
|
else if (*value_type == 0x100001)
|
|
*value_type = REG_MULTI_SZ;
|
|
else if (*value_type == 0x200001)
|
|
*value_type = REG_EXPAND_SZ;
|
|
else if (*value_type == 0x400001)
|
|
*value_type = REG_SZ;
|
|
else if (*value_type == 0x800000)
|
|
*value_type = REG_NONE;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
*value_type = REG_NONE;
|
|
*data_len = 0;
|
|
*data = NULL;
|
|
}
|
|
|
|
cleanup:
|
|
return dwResult;
|
|
}
|
|
|
|
//---------------------------------------------------------------
|
|
DWORD CopyInf( const TCHAR *ptsSettingsSection )
|
|
{
|
|
DWORD dwResult;
|
|
BOOL fSuccess;
|
|
INFCONTEXT ic;
|
|
DWORD line_len = 0;
|
|
DWORD dwReqLen;
|
|
TCHAR *ptsKeyName = NULL;
|
|
TCHAR *ptsValueName = NULL;
|
|
TCHAR *ptsRootName = NULL;
|
|
DWORD dwValueType;
|
|
BYTE *data = NULL;
|
|
DWORD dwDataLen;
|
|
HKEY hKey = NULL;
|
|
BOOL fForce;
|
|
BOOL fExist;
|
|
HKEY hRootKey;
|
|
|
|
if (Verbose)
|
|
{
|
|
Win32Printf(LogFile, "Processing Section [%s]\r\n", ptsSettingsSection);
|
|
}
|
|
// Find the section.
|
|
fSuccess = SetupFindFirstLine( InputInf, ptsSettingsSection, NULL, &ic );
|
|
if (!fSuccess)
|
|
return ERROR_SUCCESS;
|
|
|
|
// Process each line in the section.
|
|
do
|
|
{
|
|
// Determine the line length.
|
|
fForce = FALSE;
|
|
fSuccess = SetupGetLineText( &ic,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
0,
|
|
&dwReqLen );
|
|
if (dwReqLen == 0)
|
|
LOG_ASSERT_GLE( fSuccess, dwResult );
|
|
|
|
// Parse the line.
|
|
dwResult = ParseRegistry( &ic,
|
|
dwReqLen,
|
|
&ptsRootName,
|
|
&ptsKeyName,
|
|
&ptsValueName,
|
|
&dwValueType,
|
|
(TCHAR **) &data,
|
|
&dwDataLen );
|
|
FAIL_ON_ERROR( dwResult );
|
|
|
|
if (ptsKeyName != NULL)
|
|
{
|
|
if ( VerboseReg )
|
|
{
|
|
Win32Printf(LogFile,
|
|
"Processing Key: ");
|
|
WriteKey( LogFile, dwValueType, ptsRootName, ptsKeyName, ptsValueName, data, dwDataLen);
|
|
}
|
|
|
|
dwResult = Filter( &ptsRootName,
|
|
&ptsKeyName,
|
|
&ptsValueName,
|
|
&dwValueType,
|
|
&data,
|
|
&dwDataLen,
|
|
&fForce );
|
|
FAIL_ON_ERROR( dwResult );
|
|
|
|
// Create or open the key.
|
|
if (ptsRootName != NULL)
|
|
{
|
|
if (_tcsicmp( TEXT("HKLM"), ptsRootName ) == 0)
|
|
{
|
|
if (UserPortion)
|
|
{
|
|
goto cleanup;
|
|
}
|
|
hRootKey = HKEY_LOCAL_MACHINE;
|
|
}
|
|
else
|
|
{
|
|
hRootKey = CurrentUser;
|
|
}
|
|
|
|
dwResult = RegCreateKeyEx( hRootKey,
|
|
ptsKeyName,
|
|
0,
|
|
NULL,
|
|
REG_OPTION_NON_VOLATILE,
|
|
KEY_ALL_ACCESS,
|
|
NULL,
|
|
&hKey,
|
|
NULL );
|
|
#ifndef SPECIFIC_USER
|
|
if (dwResult == ERROR_ACCESS_DENIED)
|
|
{
|
|
Win32PrintfResource( LogFile,
|
|
IDS_REG_ACCESS,
|
|
ptsRootName,
|
|
ptsKeyName,
|
|
NULL );
|
|
dwResult = ERROR_SUCCESS;
|
|
}
|
|
else
|
|
#endif
|
|
if (data != NULL)
|
|
{
|
|
LOG_ASSERT( dwResult );
|
|
|
|
// ptsValueName == NULL means key's unnamed
|
|
// or default value
|
|
if (!fForce)
|
|
fExist = RegQueryValueEx( hKey,
|
|
ptsValueName,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
NULL ) == ERROR_SUCCESS;
|
|
|
|
// Set values that don't exist or are forced.
|
|
if (fForce || !fExist)
|
|
{
|
|
if ( VerboseReg )
|
|
{
|
|
Win32Printf(LogFile,
|
|
"=> Writing Key: ");
|
|
WriteKey( LogFile, dwValueType, ptsRootName, ptsKeyName, ptsValueName, data, dwDataLen);
|
|
}
|
|
dwResult = RegSetValueEx( hKey,
|
|
ptsValueName,
|
|
NULL,
|
|
dwValueType,
|
|
data,
|
|
dwDataLen );
|
|
LOG_ASSERT( dwResult );
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
|
|
// Free strings from the parser.
|
|
free( ptsRootName );
|
|
free( ptsKeyName );
|
|
free( ptsValueName );
|
|
free( data );
|
|
RegCloseKey( hKey );
|
|
ptsRootName = NULL;
|
|
hKey = NULL;
|
|
ptsKeyName = NULL;
|
|
ptsValueName = NULL;
|
|
data = NULL;
|
|
}
|
|
|
|
// Skip to the next line.
|
|
fSuccess = SetupFindNextLine( &ic, &ic );
|
|
|
|
} while(fSuccess);
|
|
|
|
cleanup:
|
|
// Close the key.
|
|
if (hKey != NULL)
|
|
RegCloseKey( hKey );
|
|
|
|
// Free strings from the parser.
|
|
free( ptsRootName );
|
|
free( ptsKeyName );
|
|
free( ptsValueName );
|
|
free( data );
|
|
return dwResult;
|
|
}
|
|
|
|
/***************************************************************************
|
|
|
|
BuildHive
|
|
|
|
This function creates a hive for the specified user by copying the
|
|
default hive and adding all the registry keys in migration.inf according
|
|
to the registry rules. The function returns the path to the hive. The
|
|
caller is required to free the path to the hive even when this function
|
|
fails.
|
|
|
|
***************************************************************************/
|
|
DWORD BuildHive( TCHAR *ptsSettingsSection, TCHAR **pptsHiveName )
|
|
{
|
|
TCHAR tsDefaultUser[MAX_PATH];
|
|
DWORD dwDefaultUserLen = sizeof(tsDefaultUser);
|
|
DWORD dwResult = ERROR_SUCCESS;
|
|
DWORD dwLen;
|
|
BOOL fSuccess;
|
|
|
|
#ifdef SPECIFIC_USER
|
|
// Find the location of the default user profile.
|
|
fSuccess = GetDefaultUserProfileDirectory( tsDefaultUser,
|
|
&dwDefaultUserLen );
|
|
LOG_ASSERT_GLE( fSuccess, dwResult );
|
|
if (dwDefaultUserLen + sizeof(HIVEFILE)+2 > MAX_PATH*sizeof(TCHAR) )
|
|
{
|
|
Win32PrintfResource( LogFile, IDS_FAILED );
|
|
dwResult = ERROR_INTERNAL_ERROR;
|
|
goto cleanup;
|
|
}
|
|
_tcscat( tsDefaultUser, HIVEFILE );
|
|
|
|
// Compute a path for the temporary hive.
|
|
*pptsHiveName = (TCHAR *) malloc( MAX_PATH*sizeof(TCHAR) );
|
|
LOG_ASSERT_EXPR( *pptsHiveName != NULL, IDS_NOT_ENOUGH_MEMORY, dwResult,
|
|
ERROR_NOT_ENOUGH_MEMORY );
|
|
dwLen = ExpandEnvironmentStrings( HIVEPATH, *pptsHiveName, MAX_PATH );
|
|
LOG_ASSERT_EXPR( dwLen != 0 && dwLen <= MAX_PATH, IDS_FAILED, dwResult,
|
|
ERROR_INTERNAL_ERROR );
|
|
|
|
// To handle errors better, preemptively unload any old key in the
|
|
// registry at the path this function uses.
|
|
RegUnLoadKey( HKEY_USERS, BUILDKEY );
|
|
|
|
// Copy the default user hive to the temporary location.
|
|
fSuccess = CopyFile( tsDefaultUser, *pptsHiveName, FALSE );
|
|
LOG_ASSERT_GLE( fSuccess, dwResult );
|
|
|
|
if (DebugOutput)
|
|
Win32Printf(LogFile, "Loading the hive from %s\r\n", *pptsHiveName);
|
|
// Load the hive.
|
|
dwResult = RegLoadKey( HKEY_USERS, BUILDKEY, *pptsHiveName );
|
|
LOG_ASSERT( dwResult );
|
|
|
|
// Open the registry key.
|
|
dwResult = RegOpenKeyEx( HKEY_USERS,
|
|
BUILDKEY,
|
|
0,
|
|
KEY_ALL_ACCESS,
|
|
&CurrentUser );
|
|
LOG_ASSERT( dwResult );
|
|
#else
|
|
dwResult = RegOpenKeyEx( HKEY_CURRENT_USER,
|
|
NULL,
|
|
0,
|
|
KEY_ALL_ACCESS,
|
|
&CurrentUser );
|
|
LOG_ASSERT( dwResult );
|
|
#endif
|
|
|
|
dwResult = DeleteInf (); // delete unwanted .DEFAULT values
|
|
FAIL_ON_ERROR (dwResult);
|
|
|
|
// Process the INF file.
|
|
dwResult = CopyInf( ptsSettingsSection );
|
|
FAIL_ON_ERROR( dwResult );
|
|
|
|
cleanup:
|
|
return dwResult;
|
|
}
|
|
|
|
//---------------------------------------------------------------
|
|
void CleanupUser()
|
|
{
|
|
// Close the key.
|
|
if (CurrentUser != NULL)
|
|
{
|
|
RegCloseKey( CurrentUser );
|
|
CurrentUser = NULL;
|
|
}
|
|
|
|
// Unload the hive.
|
|
RegUnLoadKey( HKEY_USERS, BUILDKEY );
|
|
}
|
|
|
|
//---------------------------------------------------------------
|
|
DWORD CreateUserProfileFromName( TCHAR *ptsDomainName,
|
|
TCHAR *ptsUsername,
|
|
TCHAR *ptsHiveName )
|
|
{
|
|
SID *pSid;
|
|
DWORD dwSidLen = SID_GUESS;
|
|
TCHAR *ptsFullName;
|
|
DWORD dwDomainLen;
|
|
DWORD dwUserLen;
|
|
SID_NAME_USE sid_use;
|
|
DWORD dwResult = ERROR_SUCCESS;
|
|
BOOL fSuccess;
|
|
|
|
#ifdef SPECIFIC_USER
|
|
// Create the user profile when /u or (/f without /q flag) was used
|
|
if ((FALSE == CopyUser) &&
|
|
((FALSE == CopyFiles) || (TRUE == TestMode)))
|
|
#endif
|
|
return ERROR_SUCCESS;
|
|
|
|
#ifdef SPECIFIC_USER
|
|
//Close the registry keys and stuff, we'll get them back after we create
|
|
//the profile.
|
|
CleanupUser();
|
|
|
|
dwDomainLen = _tcslen( ptsDomainName ) + 1;
|
|
dwUserLen = _tcslen( ptsUsername ) + 1;
|
|
|
|
// Allocate space to hold the sid and construct the full domain\username.
|
|
pSid = (SID *) _alloca( dwSidLen );
|
|
ptsFullName = (TCHAR *) _alloca( (dwDomainLen + dwUserLen + 2) *
|
|
sizeof(TCHAR) );
|
|
|
|
_tcscpy( ptsFullName, ptsDomainName );
|
|
ptsFullName[dwDomainLen-1] = L'\\';
|
|
_tcscpy( &ptsFullName[dwDomainLen], ptsUsername );
|
|
|
|
// Get the SID for the specified user.
|
|
fSuccess = LookupAccountName( NULL,
|
|
ptsFullName,
|
|
pSid,
|
|
&dwSidLen,
|
|
ptsDomainName,
|
|
&dwDomainLen,
|
|
&sid_use);
|
|
if (!fSuccess)
|
|
{
|
|
// Try allocating a bigger buffer.
|
|
if (dwSidLen > SID_GUESS)
|
|
{
|
|
pSid = (SID *) _alloca( dwSidLen );
|
|
fSuccess = LookupAccountName( NULL,
|
|
ptsFullName,
|
|
pSid,
|
|
&dwSidLen,
|
|
ptsDomainName,
|
|
&dwDomainLen,
|
|
&sid_use);
|
|
}
|
|
if (fSuccess == FALSE)
|
|
{
|
|
dwResult = GetLastError();
|
|
if (DebugOutput)
|
|
{
|
|
Win32Printf(LogFile,
|
|
"Could not find account name for %s: %d\r\n",
|
|
ptsFullName, dwResult);
|
|
}
|
|
}
|
|
LOG_ASSERT( dwResult );
|
|
}
|
|
|
|
// Allocate memory to hold the path to the user profile.
|
|
UserPath = (TCHAR *) malloc( MAX_PATH*sizeof(TCHAR) );
|
|
UserPath[0]=0;
|
|
LOG_ASSERT_EXPR( UserPath != NULL, IDS_NOT_ENOUGH_MEMORY, dwResult,
|
|
ERROR_NOT_ENOUGH_MEMORY );
|
|
|
|
// Create the user profile directory.
|
|
fSuccess = CreateUserProfile( pSid,
|
|
ptsUsername,
|
|
ptsHiveName,
|
|
UserPath,
|
|
MAX_PATH*sizeof(TCHAR) );
|
|
if (DebugOutput)
|
|
Win32Printf(LogFile,
|
|
"Creating Profile for %s in %s from %s\r\n",
|
|
ptsUsername, UserPath, ptsHiveName);
|
|
if (fSuccess == FALSE)
|
|
{
|
|
dwResult = GetLastError();
|
|
if (dwResult == ERROR_SHARING_VIOLATION)
|
|
{
|
|
Win32PrintfResource( LogFile, IDS_CANT_LOAD_CURRENT_USER );
|
|
goto cleanup;
|
|
}
|
|
LOG_ASSERT( dwResult );
|
|
}
|
|
if (0 == UserPath[0])
|
|
{
|
|
Win32PrintfResource( LogFile, IDS_USER_PROFILE_FAILED );
|
|
dwResult = ERROR_INTERNAL_ERROR;
|
|
goto cleanup;
|
|
}
|
|
|
|
//Reopen the new hive
|
|
TCHAR _tcsHivePath[MAX_PATH + 1];
|
|
if (_tcslen(UserPath) + _tcslen(HIVEFILE) > MAX_PATH)
|
|
{
|
|
if (DebugOutput)
|
|
{
|
|
Win32Printf(LogFile, "Error: hivepath too long %s%s\r\n", UserPath, HIVEFILE);
|
|
}
|
|
dwResult = ERROR_FILENAME_EXCED_RANGE;
|
|
goto cleanup;
|
|
}
|
|
_tcscpy(_tcsHivePath, UserPath);
|
|
_tcscat(_tcsHivePath, HIVEFILE);
|
|
|
|
dwResult = RegLoadKey(HKEY_USERS, BUILDKEY, _tcsHivePath);
|
|
if (DebugOutput)
|
|
Win32Printf(LogFile, "Loading hive from %s\r\n", _tcsHivePath);
|
|
if (dwResult)
|
|
{
|
|
LOG_ASSERT( dwResult );
|
|
}
|
|
|
|
//Reopen the registry from the new location
|
|
dwResult = RegOpenKeyEx(HKEY_USERS,
|
|
BUILDKEY,
|
|
0,
|
|
KEY_ALL_ACCESS,
|
|
&CurrentUser);
|
|
if (dwResult)
|
|
{
|
|
LOG_ASSERT(dwResult);
|
|
}
|
|
|
|
cleanup:
|
|
return dwResult;
|
|
#endif
|
|
}
|
|
|
|
//---------------------------------------------------------------
|
|
DWORD FixSpecial()
|
|
{
|
|
CRegFileList *prfl = g_prflStart;
|
|
DWORD dwResult = ERROR_SUCCESS;
|
|
|
|
while (prfl != NULL)
|
|
{
|
|
const TCHAR *ptsRoot, *ptsKey, *ptsVal, *ptsData;
|
|
DWORD dwValueType;
|
|
TCHAR *ptsLocation, *ptsFinalValue;
|
|
TCHAR tsExpand[MAX_PATH + 1];
|
|
TCHAR tsTemp[MAX_PATH + 1];
|
|
|
|
prfl->GetData(&ptsRoot, &ptsKey, &ptsVal, &ptsData, &dwValueType);
|
|
|
|
dwResult = WhereIsThisFile(ptsData, &ptsLocation);
|
|
if (ERROR_NOT_FOUND == dwResult)
|
|
{
|
|
ptsLocation = (TCHAR *)ptsData;
|
|
}
|
|
else if (ERROR_SUCCESS != dwResult)
|
|
{
|
|
return dwResult;
|
|
}
|
|
|
|
|
|
//Expand any environment strings in the original data with
|
|
//the values for the user we're loading for. If the final
|
|
//paths match, we'll retain the version of the data with the
|
|
//unexpanded environment variables in it. Otherwise, we take
|
|
//the full path.
|
|
if (_tcslen(ptsData) > MAX_PATH)
|
|
{
|
|
if (DebugOutput)
|
|
{
|
|
Win32Printf(LogFile, "Error: ptsData too long %s\r\n", ptsData);
|
|
}
|
|
return ERROR_FILENAME_EXCED_RANGE;
|
|
}
|
|
_tcscpy(tsExpand, ptsData);
|
|
dwResult = ExpandEnvStringForUser(tsExpand,
|
|
tsTemp,
|
|
&ptsFinalValue);
|
|
if (dwResult)
|
|
return dwResult;
|
|
|
|
if (_tcsicmp(ptsLocation, ptsFinalValue) == 0)
|
|
{
|
|
//They're the same, use the string with the environment
|
|
//variables in it.
|
|
ptsFinalValue = (TCHAR *)ptsData;
|
|
}
|
|
else
|
|
{
|
|
ptsFinalValue = ptsLocation;
|
|
}
|
|
|
|
if (ptsRoot != NULL)
|
|
{
|
|
HKEY hRootKey;
|
|
HKEY hKey;
|
|
|
|
if (_tcsicmp(TEXT("HKLM"), ptsRoot) == 0)
|
|
hRootKey = HKEY_LOCAL_MACHINE;
|
|
else
|
|
hRootKey = CurrentUser;
|
|
|
|
dwResult = RegCreateKeyEx(hRootKey,
|
|
ptsKey,
|
|
NULL,
|
|
NULL,
|
|
REG_OPTION_NON_VOLATILE,
|
|
KEY_ALL_ACCESS,
|
|
NULL,
|
|
&hKey,
|
|
NULL);
|
|
|
|
LOG_ASSERT(dwResult);
|
|
if ( VerboseReg )
|
|
{
|
|
Win32Printf(LogFile,
|
|
"=> Writing Key: ");
|
|
WriteKey(LogFile,
|
|
dwValueType, (TCHAR *)ptsRoot, (TCHAR *)ptsKey, (TCHAR *)ptsVal, (UCHAR *)ptsFinalValue, _tcslen(ptsFinalValue)+1);
|
|
}
|
|
|
|
dwResult = RegSetValueEx(hKey,
|
|
ptsVal,
|
|
NULL,
|
|
dwValueType,
|
|
(BYTE *)ptsFinalValue,
|
|
(_tcslen(ptsFinalValue) + 1) *
|
|
sizeof(TCHAR));
|
|
RegCloseKey(hKey);
|
|
LOG_ASSERT(dwResult);
|
|
}
|
|
|
|
free(ptsLocation);
|
|
|
|
// Next:
|
|
CRegFileList *prflPrev;
|
|
prflPrev = prfl;
|
|
|
|
prfl = prfl->GetNext();
|
|
delete prflPrev;
|
|
g_prflStart = prfl;
|
|
}
|
|
|
|
cleanup:
|
|
return dwResult;
|
|
}
|
|
|
|
//---------------------------------------------------------------
|
|
DWORD LoadUser( TCHAR **pptsDomainName,
|
|
TCHAR **pptsUsername,
|
|
TCHAR **pptsHiveName )
|
|
{
|
|
TCHAR *ptsSettingsSection = NULL;
|
|
DWORD dwResult;
|
|
|
|
// Initialize the hash table with the filter rules.
|
|
dwResult = InitializeHash( );
|
|
FAIL_ON_ERROR( dwResult );
|
|
|
|
// Fetch user info only if /u or (/f without /q) flag was used
|
|
if ((FALSE == CopyUser) &&
|
|
((FALSE == CopyFiles) || (TRUE == TestMode)))
|
|
{
|
|
// Open the registry key.
|
|
dwResult = RegOpenKeyEx( HKEY_CURRENT_USER,
|
|
NULL,
|
|
0,
|
|
KEY_ALL_ACCESS,
|
|
&CurrentUser );
|
|
LOG_ASSERT( dwResult );
|
|
return ERROR_SUCCESS;
|
|
}
|
|
|
|
// Read the user information from the inf file.
|
|
dwResult = ReadUser( &ptsSettingsSection, pptsDomainName, pptsUsername );
|
|
FAIL_ON_ERROR( dwResult );
|
|
|
|
#ifdef SPECIFIC_USER
|
|
// Enable some privileges.
|
|
dwResult = EnableBackupPrivilege();
|
|
FAIL_ON_ERROR( dwResult );
|
|
#endif
|
|
|
|
// If the user was on a Win9x machine,
|
|
// apply all the settings to a new hive.
|
|
dwResult = BuildHive( ptsSettingsSection, pptsHiveName );
|
|
FAIL_ON_ERROR( dwResult );
|
|
|
|
cleanup:
|
|
if (ptsSettingsSection != NULL)
|
|
free( ptsSettingsSection );
|
|
return dwResult;
|
|
}
|
|
|
|
//---------------------------------------------------------------
|
|
DWORD ProcessExtensions()
|
|
{
|
|
// Apply registry keys in the copied state section.
|
|
return CopyInf( EXTENSION_STATE_SECTION );
|
|
}
|
|
|
|
|
|
//*****************************************************************
|
|
//
|
|
// Synopsis: Build a file list string out of a CStringList.
|
|
//
|
|
// History: 11/14/1999 Created by WeiruC.
|
|
//
|
|
// Return Value: Win32 error code.
|
|
//
|
|
//*****************************************************************
|
|
|
|
DWORD BuildFileListString(CStringList* fileList, TCHAR** tcsFileList)
|
|
{
|
|
DWORD cFileListBuffer = 10240; // length of file list string buffer
|
|
DWORD cFileListString = 0; // length of file list string
|
|
DWORD rv = ERROR_SUCCESS; // return value
|
|
TCHAR* tcsTargetFileName = NULL;
|
|
TCHAR* tmpStringBuffer;
|
|
CStringList* cur;
|
|
|
|
*tcsFileList = new TCHAR[cFileListBuffer];
|
|
**tcsFileList = TEXT('\0');
|
|
|
|
if(fileList == NULL || (fileList->String())[0] == TEXT('\0'))
|
|
{
|
|
return rv;
|
|
}
|
|
|
|
cur = fileList->Next();
|
|
|
|
//
|
|
// For every file in the source file list, call Phil's code to figure out
|
|
// where that file is migrated to, and then add it to the target file list
|
|
// string.
|
|
//
|
|
|
|
do
|
|
{
|
|
rv = WhereIsThisFile(cur->String(), &tcsTargetFileName);
|
|
if(rv == ERROR_SUCCESS)
|
|
{
|
|
if(cFileListBuffer - cFileListString <= _tcslen(tcsTargetFileName))
|
|
{
|
|
//
|
|
// String buffer is not big enough. Double it.
|
|
//
|
|
|
|
tmpStringBuffer = *tcsFileList;
|
|
*tcsFileList = new TCHAR[cFileListBuffer *= 2];
|
|
_tcscpy(*tcsFileList, tmpStringBuffer);
|
|
delete []tmpStringBuffer;
|
|
}
|
|
|
|
//
|
|
// Add the new file name to the new file list.
|
|
//
|
|
|
|
_tcscat(*tcsFileList, tcsTargetFileName);
|
|
_tcscat(*tcsFileList, TEXT(" "));
|
|
|
|
cFileListString += _tcslen(tcsTargetFileName) + 1;
|
|
}
|
|
|
|
if(tcsTargetFileName != NULL)
|
|
{
|
|
free(tcsTargetFileName);
|
|
tcsTargetFileName = NULL;
|
|
}
|
|
|
|
if(cur == fileList)
|
|
{
|
|
break;
|
|
}
|
|
|
|
//
|
|
// Go to the next file.
|
|
//
|
|
|
|
cur = cur->Next();
|
|
}
|
|
while(TRUE);
|
|
|
|
if(tcsTargetFileName != NULL)
|
|
{
|
|
free(tcsTargetFileName);
|
|
}
|
|
|
|
return rv;
|
|
}
|
|
|
|
|
|
//*****************************************************************
|
|
//
|
|
// Synopsis: Run an executable in a child process.
|
|
//
|
|
// History: 11/14/1999 Created by WeiruC.
|
|
//
|
|
// Return Value: Win32 error code.
|
|
//
|
|
//*****************************************************************
|
|
|
|
DWORD RunCommandInChildProcess(CStringList* command, CStringList* fileList)
|
|
{
|
|
SECURITY_ATTRIBUTES sa; // allow handles to be inherited
|
|
DWORD rv = ERROR_SUCCESS; // return value
|
|
STARTUPINFO si;
|
|
PROCESS_INFORMATION pi;
|
|
TCHAR* tcsFileList = NULL;
|
|
TCHAR* cur;
|
|
CStringList* tmp; // used when growing the string
|
|
TCHAR fileName[MAX_PATH + 1];
|
|
TCHAR* commandLine = NULL; // command line
|
|
DWORD commandLineLen = 0; // command line length
|
|
DWORD cFileList = 10240; // string length of tcsFileList
|
|
|
|
ZeroMemory(&si, sizeof(STARTUPINFO));
|
|
si.cb = sizeof(STARTUPINFO);
|
|
|
|
//
|
|
// Build the file list string. We ignore error here. If a file is not picked
|
|
// up, we'll still pass it to the command. We'll let the user's executable
|
|
// handle the error.
|
|
//
|
|
|
|
BuildFileListString(fileList, &tcsFileList);
|
|
|
|
//
|
|
// Initialize the command line. We can either do two loops to count how big
|
|
// a string we need for the command line, or do one loops and just set a
|
|
// max limit on how long the command line is allowed. We probably won't
|
|
// have that many commands or arguments anyway.
|
|
//
|
|
|
|
commandLineLen += _tcslen(command->String()) + 3; // '"' + '"' + ' '
|
|
commandLineLen += _tcslen(tcsFileList) + 1; // ' '
|
|
for(tmp = command->Next(); tmp != command; tmp = tmp->Next())
|
|
{
|
|
commandLineLen += _tcslen(tmp->String()) + 3; // '"' + '"' + ' '
|
|
}
|
|
commandLine = new TCHAR[commandLineLen + _tcslen(tcsFileList) + 1];
|
|
commandLine[0] = TEXT('\0');
|
|
MakeCommandLine(command, command->Next(), commandLine);
|
|
_tcscat(commandLine, tcsFileList);
|
|
|
|
if(!CreateProcess(NULL,
|
|
commandLine,
|
|
NULL,
|
|
NULL,
|
|
TRUE,
|
|
0,
|
|
NULL,
|
|
NULL,
|
|
&si,
|
|
&pi))
|
|
{
|
|
rv = GetLastError();
|
|
goto cleanup;
|
|
}
|
|
|
|
cleanup:
|
|
|
|
if(tcsFileList != NULL)
|
|
{
|
|
delete []tcsFileList;
|
|
}
|
|
|
|
if(commandLine != NULL)
|
|
{
|
|
delete []commandLine;
|
|
}
|
|
|
|
return rv;
|
|
}
|
|
|
|
|
|
//*****************************************************************
|
|
//
|
|
// Synopsis: Process the [Run These Commands] extension section in an inf
|
|
// file.
|
|
//
|
|
// History: 11/14/1999 Created by WeiruC.
|
|
//
|
|
// Return Value: Win32 error code.
|
|
//
|
|
//*****************************************************************
|
|
|
|
DWORD ProcessExecExtensions()
|
|
{
|
|
DWORD rv = ERROR_SUCCESS; // return value
|
|
BOOL success = TRUE; // value returned by setup functions
|
|
INFCONTEXT context; // used by setup inf functions
|
|
INFCONTEXT contextOutput; // Run These Commands Output section
|
|
TCHAR* label = NULL; // label in inf file
|
|
TCHAR* labelOutput = NULL; // label in inf file
|
|
CStringList* command = NULL; // command
|
|
CStringList* fileList = NULL; // file list from Scanstate
|
|
|
|
if(InputInf == INVALID_HANDLE_VALUE)
|
|
{
|
|
return ERROR_SUCCESS;
|
|
}
|
|
|
|
//
|
|
// Find the section in the inf file. If it doesn't exist, do nothing and
|
|
// return ERROR_SUCCESS.
|
|
//
|
|
|
|
if(!SetupFindFirstLine(InputInf, EXECUTABLE_EXT_SECTION, NULL, &context))
|
|
{
|
|
return ERROR_SUCCESS;
|
|
}
|
|
|
|
//
|
|
// Process each line in the section:
|
|
// Find matching file list from Scanstate
|
|
// run the command
|
|
//
|
|
|
|
do
|
|
{
|
|
//
|
|
// Parse the line.
|
|
//
|
|
|
|
rv = ParseSectionList(&context, &label, &command);
|
|
FAIL_ON_ERROR(rv);
|
|
|
|
if((command->String())[0] != TEXT('\0'))
|
|
{
|
|
//
|
|
// Find matching output from Scanstate.
|
|
//
|
|
|
|
if(SetupFindFirstLine(InputInf,
|
|
EXECUTABLE_EXTOUT_SECTION,
|
|
label,
|
|
&contextOutput))
|
|
{
|
|
//
|
|
// Parse the line.
|
|
//
|
|
|
|
rv = ParseSectionList(&contextOutput, &labelOutput, &fileList);
|
|
FAIL_ON_ERROR(rv);
|
|
}
|
|
|
|
//
|
|
// Create a child process to run the command. Ignore error and
|
|
// continue to run the next command.
|
|
//
|
|
|
|
RunCommandInChildProcess(command, fileList);
|
|
}
|
|
|
|
//
|
|
// Clean up and reinitialize.
|
|
//
|
|
|
|
if(label)
|
|
{
|
|
free(label);
|
|
label = NULL;
|
|
}
|
|
if(labelOutput)
|
|
{
|
|
free(labelOutput);
|
|
labelOutput = NULL;
|
|
}
|
|
if(command)
|
|
{
|
|
delete command;
|
|
command = NULL;
|
|
}
|
|
if(fileList)
|
|
{
|
|
delete fileList;
|
|
fileList = NULL;
|
|
}
|
|
}
|
|
while(SetupFindNextLine(&context, &context));
|
|
|
|
cleanup:
|
|
|
|
if(label)
|
|
{
|
|
free(label);
|
|
}
|
|
if(labelOutput)
|
|
{
|
|
free(labelOutput);
|
|
labelOutput = NULL;
|
|
}
|
|
if(command)
|
|
{
|
|
delete command;
|
|
}
|
|
if(fileList)
|
|
{
|
|
delete fileList;
|
|
fileList = NULL;
|
|
}
|
|
|
|
return rv;
|
|
}
|