windows-nt/Source/XPSP1/NT/windows/winstate/cobra/modules/sysmod/migdb.c
2020-09-26 16:20:57 +08:00

1494 lines
40 KiB
C

/*++
Copyright (c) 1997 Microsoft Corporation
Module Name:
migdb.c
Abstract:
This source implements old AppDb functionality
Author:
Calin Negreanu (calinn) 07-Jan-1998
Revision History:
jimschm 23-Sep-1998 Updated for new fileops code
jimschm 25-Feb-1998 Added UninstallSection support
calinn 19-Jan-1998 Added CANCELLED response
--*/
#include "pch.h"
#include "logmsg.h"
#include "osfiles.h"
#define DBG_MIGDB "MigDb"
#define S_STRINGS TEXT("Strings")
//
// Globals
//
PMHANDLE g_MigDbPool = NULL;
PMIGDB_CONTEXT g_ContextList = NULL;
HASHTABLE g_FileTable = NULL;
PMIGDB_TYPE_RULE g_TypeRule = NULL;
GROWBUFFER g_TypeRuleList = INIT_GROWBUFFER;
HINF g_OsFilesInf = INVALID_HANDLE_VALUE;
GROWBUFFER g_AttrGrowBuff = INIT_GROWBUFFER;
GROWBUFFER g_TypeGrowBuff = INIT_GROWBUFFER;
static PINFCONTEXT g_Line;
PMIGDB_HOOK_PROTOTYPE g_MigDbHook = NULL;
#define ArgFunction TEXT("ARG")
#define ArgFunctionLen 3
BOOL
pCallAction (
IN PMIGDB_CONTEXT MigDbContext
);
PMIGDB_ATTRIB
pLoadAttribData (
IN PCTSTR MultiSzStr
);
PMIGDB_HOOK_PROTOTYPE
SetMigDbHook (
PMIGDB_HOOK_PROTOTYPE HookFunction
)
{
PMIGDB_HOOK_PROTOTYPE savedHook;
savedHook = g_MigDbHook;
g_MigDbHook = HookFunction;
return savedHook;
}
INT
pGetAttribIndex (
IN PCTSTR AttribName
)
/*++
Routine Description:
This routine returns the index in attribute functions array for a specified attribute.
Arguments:
AttribName - Attribute name
Return value:
-1 - no such attribute in attribute table
--*/
{
INT attribIndex;
INT rc = 0;
PTSTR attrEnd = NULL;
TCHAR savedChar = 0;
attrEnd = (PTSTR) SkipSpaceR (AttribName, GetEndOfString (AttribName));
if (attrEnd != NULL) {
attrEnd = _tcsinc (attrEnd);
savedChar = attrEnd [0];
attrEnd [0] = 0;
}
__try {
attribIndex = MigDb_GetAttributeIdx (AttribName);
if (attribIndex == -1) {
LOG((LOG_ERROR, (PCSTR) MSG_MIGDB_ATTRIBUTE_NOT_FOUND, AttribName));
}
rc = attribIndex;
}
__finally {
if (attrEnd != NULL) {
attrEnd [0] = savedChar;
}
}
return rc;
}
BOOL
pValidateArg (
IN OUT PMIGDB_ATTRIB AttribStruct
)
{
MYASSERT (AttribStruct);
if (AttribStruct->ArgCount != MigDb_GetReqArgCount (AttribStruct->AttribIndex)) {
#ifdef DEBUG
if (AttribStruct->AttribIndex != -1) {
TCHAR Buffer[16384];
SetupGetLineText (g_Line, NULL, NULL, NULL, Buffer, ARRAYSIZE(Buffer), NULL);
DEBUGMSG ((
DBG_WHOOPS,
"Discarding attribute %s because of too few arguments.\n"
" Line: %s\n",
MigDb_GetAttributeName (AttribStruct->AttribIndex),
Buffer
));
}
#endif
AttribStruct->AttribIndex = -1;
return FALSE;
}
return TRUE;
}
#define STATE_ATTRNAME 1
#define STATE_ATTRARG 2
PMIGDB_ATTRIB
pLoadAttribData (
IN PCTSTR MultiSzStr
)
/*++
Routine Description:
This routine creates a list of MIGDB_ATTRIBs from a multisz.
Arguments:
MultiSzStr - multisz to be processed
Return value:
MIGDB_ATTRIB nodes
--*/
{
MULTISZ_ENUM multiSzEnum;
PMIGDB_ATTRIB result = NULL;
PMIGDB_ATTRIB tmpAttr = NULL;
INT state = STATE_ATTRNAME;
PTSTR currStrPtr = NULL;
PTSTR currArgPtr = NULL;
PTSTR endArgPtr = NULL;
TCHAR savedChar = 0;
g_AttrGrowBuff.End = 0;
if (EnumFirstMultiSz (&multiSzEnum, MultiSzStr)) {
do {
currStrPtr = (PTSTR) SkipSpace (multiSzEnum.CurrentString);
if (state == STATE_ATTRNAME) {
tmpAttr = (PMIGDB_ATTRIB) PmGetMemory (g_MigDbPool, sizeof (MIGDB_ATTRIB));
ZeroMemory (tmpAttr, sizeof (MIGDB_ATTRIB));
if (_tcsnextc (currStrPtr) == TEXT('!')) {
currStrPtr = _tcsinc (currStrPtr);
currStrPtr = (PTSTR) SkipSpace (currStrPtr);
tmpAttr->NotOperator = TRUE;
}
currArgPtr = _tcschr (currStrPtr, TEXT('('));
if (currArgPtr) {
endArgPtr = _tcsdec (currStrPtr, currArgPtr);
if (endArgPtr) {
endArgPtr = (PTSTR) SkipSpaceR (currStrPtr, endArgPtr);
endArgPtr = _tcsinc (endArgPtr);
}
else {
endArgPtr = currStrPtr;
}
savedChar = *endArgPtr;
*endArgPtr = 0;
tmpAttr->AttribIndex = pGetAttribIndex (currStrPtr);
*endArgPtr = savedChar;
currStrPtr = _tcsinc (currArgPtr);
state = STATE_ATTRARG;
}
else {
// this attribute has no arguments.
tmpAttr->AttribIndex = pGetAttribIndex (currStrPtr);
tmpAttr->Next = result;
result = tmpAttr;
pValidateArg (result);
continue;
}
}
if (state == STATE_ATTRARG) {
currStrPtr = (PTSTR) SkipSpace (currStrPtr);
endArgPtr = _tcsrchr (currStrPtr, TEXT(')'));
if (endArgPtr) {
endArgPtr = _tcsdec (currStrPtr, endArgPtr);
if (endArgPtr) {
endArgPtr = (PTSTR) SkipSpaceR (currStrPtr, endArgPtr);
endArgPtr = _tcsinc (endArgPtr);
}
else {
endArgPtr = currStrPtr;
}
savedChar = *endArgPtr;
*endArgPtr = 0;
}
GbMultiSzAppend (&g_AttrGrowBuff, currStrPtr);
tmpAttr->ArgCount++;
if (endArgPtr) {
*endArgPtr = savedChar;
tmpAttr->Arguments = PmDuplicateMultiSz (g_MigDbPool, (PTSTR)g_AttrGrowBuff.Buf);
g_AttrGrowBuff.End = 0;
state = STATE_ATTRNAME;
tmpAttr->Next = result;
result = tmpAttr;
pValidateArg (result);
}
}
} while (EnumNextMultiSz (&multiSzEnum));
}
return result;
}
BOOL
AddFileToMigDbLinkage (
IN PCTSTR FileName,
IN PINFCONTEXT Context, OPTIONAL
IN DWORD FieldIndex OPTIONAL
)
{
TCHAR tempField [MEMDB_MAX];
DWORD fieldIndex = FieldIndex;
PMIGDB_FILE migDbFile = NULL;
PMIGDB_ATTRIB migDbAttrib = NULL;
HASHITEM stringId;
FILE_LIST_STRUCT fileList;
//creating MIGDB_FILE structure for current file
migDbFile = (PMIGDB_FILE) PmGetMemory (g_MigDbPool, sizeof (MIGDB_FILE));
if (migDbFile != NULL) {
ZeroMemory (migDbFile, sizeof (MIGDB_FILE));
migDbFile->Section = g_ContextList->Sections;
if (Context) {
fieldIndex ++;
if (SetupGetMultiSzField (Context, fieldIndex, tempField, MEMDB_MAX, NULL)) {
g_Line = Context;
migDbFile->Attributes = pLoadAttribData (tempField);
if (g_MigDbHook != NULL) {
migDbAttrib = migDbFile->Attributes;
while (migDbAttrib) {
g_MigDbHook (FileName, g_ContextList, g_ContextList->Sections, migDbFile, migDbAttrib);
migDbAttrib = migDbAttrib->Next;
}
}
}
}
//adding this file into string table and create a MIGDB_FILE node. If file
//already exists in string table then just create another MIGDB_FILE node
//chained with already existing ones.
stringId = HtFindString (g_FileTable, FileName);
if (stringId) {
HtCopyStringData (g_FileTable, stringId, &fileList);
fileList.Last->Next = migDbFile;
fileList.Last = migDbFile;
HtSetStringData (g_FileTable, stringId, &fileList);
} else {
fileList.First = fileList.Last = migDbFile;
HtAddStringAndData (g_FileTable, FileName, &fileList);
}
}
return TRUE;
}
BOOL
pScanForFile (
IN PINFCONTEXT Context,
IN DWORD FieldIndex
)
/*++
Routine Description:
This routine updates migdb data structures loading a specified file info from inf file.
Creates a migdb file node and the file is added in a string table for fast query.
Arguments:
SectionStr - section to process
Return value:
TRUE - the operation was successful
FALSE - otherwise
--*/
{
TCHAR fileName [MEMDB_MAX];
//scanning for file name
if (!SetupGetStringField (Context, FieldIndex, fileName, MEMDB_MAX, NULL)) {
LOG ((LOG_ERROR, (PCSTR) MSG_MIGDB_BAD_FILENAME));
return FALSE;
}
return AddFileToMigDbLinkage (fileName, Context, FieldIndex);
}
BOOL
pMigDbAddRuleToTypeRule (
IN PMIGDB_TYPE_RULE TypeRule,
IN PMIGDB_RULE Rule
)
{
PMIGDB_CHAR_NODE node, currNode, prevNode;
PTSTR nodeBase;
PCTSTR p;
WORD w;
BOOL found;
if (Rule->NodeBase) {
currNode = TypeRule->FirstLevel;
prevNode = currNode;
nodeBase = DuplicatePathString (Rule->NodeBase, 0);
CharLower (nodeBase);
p = nodeBase;
while (*p) {
w = (WORD) _tcsnextc (p);
p = _tcsinc (p);
if (currNode) {
if (currNode->Char == w) {
if (!*p) {
Rule->NextRule = currNode->RuleList;
currNode->RuleList = Rule;
}
prevNode = currNode;
currNode = currNode->NextLevel;
} else {
found = FALSE;
while (!found && currNode->NextPeer) {
if (currNode->NextPeer->Char == w) {
if (!*p) {
Rule->NextRule = currNode->NextPeer->RuleList;
currNode->NextPeer->RuleList = Rule;
}
prevNode = currNode->NextPeer;
currNode = prevNode->NextLevel;
found = TRUE;
break;
}
currNode = currNode->NextPeer;
}
if (!found) {
node = PmGetMemory (g_MigDbPool, sizeof (MIGDB_CHAR_NODE));
ZeroMemory (node, sizeof (MIGDB_CHAR_NODE));
if (!*p) {
node->RuleList = Rule;
}
node->Char = w;
node->NextPeer = currNode->NextPeer;
currNode->NextPeer = node;
prevNode = node;
currNode = node->NextLevel;
}
}
} else {
node = PmGetMemory (g_MigDbPool, sizeof (MIGDB_CHAR_NODE));
ZeroMemory (node, sizeof (MIGDB_CHAR_NODE));
if (!*p) {
node->RuleList = Rule;
}
node->Char = w;
if (prevNode) {
prevNode->NextLevel = node;
} else {
TypeRule->FirstLevel = node;
}
prevNode = node;
currNode = prevNode->NextLevel;
}
}
FreePathString (nodeBase);
} else {
Rule->NextRule = TypeRule->RuleList;
TypeRule->RuleList = Rule;
}
return TRUE;
}
BOOL
AddPatternToMigDbLinkage (
IN PCTSTR LeafPattern,
IN PCTSTR NodePattern,
IN PINFCONTEXT Context, OPTIONAL
IN DWORD FieldIndex,
IN INT IncludeNodes
)
{
PMIGDB_RULE rule;
MIG_SEGMENTS nodeSegment;
MIG_SEGMENTS leafSegment;
PCTSTR ourEncodedString;
PCTSTR nodeBase;
TCHAR tempField [MEMDB_MAX];
DWORD fieldIndex = FieldIndex;
nodeSegment.Segment = NodePattern ? NodePattern : TEXT("*");
nodeSegment.IsPattern = TRUE;
leafSegment.Segment = LeafPattern ? LeafPattern : TEXT("*");
leafSegment.IsPattern = TRUE;
ourEncodedString = IsmCreateObjectPattern (
&nodeSegment,
1,
&leafSegment,
1
);
//
// build the rule
//
rule = PmGetMemory (g_MigDbPool, sizeof (MIGDB_RULE));
ZeroMemory (rule, sizeof (MIGDB_RULE));
if (NodePattern) {
nodeBase = GetPatternBase (NodePattern);
if (nodeBase) {
rule->NodeBase = PmDuplicateString (g_MigDbPool, nodeBase);
FreePathString (nodeBase);
}
}
rule->ObjectPattern = PmDuplicateString (g_MigDbPool, ourEncodedString);
rule->ParsedPattern = ObsCreateParsedPatternEx (g_MigDbPool, ourEncodedString, FALSE);
MYASSERT (rule->ParsedPattern);
if (rule->ParsedPattern) {
// add aditional information
rule->Section = g_ContextList->Sections;
if (Context) {
fieldIndex ++;
if (SetupGetMultiSzField (Context, fieldIndex, tempField, MEMDB_MAX, NULL)) {
g_Line = Context;
rule->Attributes = pLoadAttribData (tempField);
}
}
rule->IncludeNodes = IncludeNodes;
pMigDbAddRuleToTypeRule (g_TypeRule, rule);
}
IsmDestroyObjectHandle (ourEncodedString);
return TRUE;
}
BOOL
pScanForFilePattern (
IN PINFCONTEXT Context,
IN DWORD FieldIndex
)
/*++
Routine Description:
This routine updates migdb data structures loading a specified file pattern info from inf file.
Creates a migdb file node and the file is added in a string table for fast query.
Arguments:
Context - inf context for the section that we are currently processing
FieldIndex - field index to start with
Return value:
TRUE - the operation was successful
FALSE - otherwise
--*/
{
TCHAR leafPattern [MEMDB_MAX];
PCTSTR leafPatternExp = NULL;
TCHAR nodePattern [MEMDB_MAX];
PCTSTR nodePatternExp = NULL;
PCTSTR sanitizedPath = NULL;
INT includeNodes = 0;
BOOL result = TRUE;
//scanning for leaf pattern
if (!SetupGetStringField (Context, FieldIndex, leafPattern, MEMDB_MAX, NULL)) {
LOG ((LOG_ERROR, (PCSTR) MSG_MIGDB_BAD_FILENAME));
return FALSE;
}
leafPatternExp = IsmExpandEnvironmentString (PLATFORM_SOURCE, S_SYSENVVAR_GROUP, leafPattern, NULL);
FieldIndex ++;
//scanning for node pattern
if (!SetupGetStringField (Context, FieldIndex, nodePattern, MEMDB_MAX, NULL)) {
LOG ((LOG_ERROR, (PCSTR) MSG_MIGDB_BAD_FILENAME));
return FALSE;
}
nodePatternExp = IsmExpandEnvironmentString (PLATFORM_SOURCE, S_SYSENVVAR_GROUP, nodePattern, NULL);
if (nodePatternExp) {
sanitizedPath = SanitizePath (nodePatternExp);
}
FieldIndex ++;
//scanning for indicator if we should include the nodes as well
if (!SetupGetIntField (Context, FieldIndex, &includeNodes)) {
includeNodes = 0;
}
result = AddPatternToMigDbLinkage (
leafPatternExp?leafPatternExp:leafPattern,
sanitizedPath?sanitizedPath:nodePattern,
Context,
FieldIndex,
includeNodes
);
if (leafPatternExp) {
IsmReleaseMemory (leafPatternExp);
leafPatternExp = NULL;
}
if (nodePatternExp) {
IsmReleaseMemory (nodePatternExp);
nodePatternExp = NULL;
}
if (sanitizedPath) {
FreePathString (sanitizedPath);
}
return result;
}
/*++
Routine Description:
The subsequent two routines enumerate the sections with a particular name and
with .999 extension from an inf file.
Arguments:
SectEnum - enumeration structure
Return value:
TRUE - enumeration continues
FALSE - enumeration ended
--*/
typedef struct _SECT_ENUM {
HINF InfHandle;
INT SectIndex;
PTSTR SectNameEnd;
PTSTR SectName;
} SECT_ENUM, *PSECT_ENUM;
VOID
pAbortSectionEnum (
IN OUT PSECT_ENUM SectEnum
)
{
if (SectEnum && SectEnum->SectName) {
FreePathString (SectEnum->SectName);
SectEnum->SectName = NULL;
SectEnum->SectNameEnd = NULL;
}
}
BOOL
pEnumNextSection (
IN OUT PSECT_ENUM SectEnum
)
{
INFCONTEXT context;
BOOL result = FALSE;
if (SectEnum->SectIndex == -1) {
pAbortSectionEnum (SectEnum);
return FALSE;
}
SectEnum->SectIndex ++;
_stprintf (SectEnum->SectNameEnd, TEXT(".%d"), SectEnum->SectIndex);
result = SetupFindFirstLine (SectEnum->InfHandle, SectEnum->SectName, NULL, &context);
if (!result) {
pAbortSectionEnum (SectEnum);
}
return result;
}
BOOL
pEnumFirstSection (
OUT PSECT_ENUM SectEnum,
IN PCTSTR SectionStr,
IN HINF InfHandle
)
{
INFCONTEXT context;
ZeroMemory (SectEnum, sizeof (SECT_ENUM));
SectEnum->SectIndex = -1;
if (SetupFindFirstLine (InfHandle, SectionStr, NULL, &context)) {
//good, only one section
SectEnum->SectName = DuplicatePathString (SectionStr, 0);
return TRUE;
}
else {
//more than one section
SectEnum->SectIndex = 0;
SectEnum->InfHandle = InfHandle;
SectEnum->SectName = DuplicatePathString (SectionStr, 32);
if (SectEnum->SectName) {
SectEnum->SectNameEnd = GetEndOfString (SectEnum->SectName);
if (SectEnum->SectNameEnd) {
return pEnumNextSection (SectEnum);
}
}
}
// something went wrong, let's get out of here
return FALSE;
}
BOOL
pLoadSectionData (
IN PCTSTR SectionStr,
IN BOOL PatternScan
)
/*++
Routine Description:
This routine updates migdb data structures loading a specified section from inf file. For
every line in the section there is a migdb file node created. Also the file is added in
a string table for fast query.
Arguments:
SectionStr - section to process
Return value:
TRUE - the operation was successful
FALSE - otherwise
--*/
{
INFCONTEXT context;
SECT_ENUM sectEnum;
PMIGDB_SECTION migDbSection;
BOOL result = TRUE;
MYASSERT (g_OsFilesInf != INVALID_HANDLE_VALUE);
if (pEnumFirstSection (&sectEnum, SectionStr, g_OsFilesInf)) {
do {
//initialize the section (this context can have multiple sections)
//and parse the file info
migDbSection = (PMIGDB_SECTION) PmGetMemory (g_MigDbPool, sizeof (MIGDB_SECTION));
if (migDbSection != NULL) {
ZeroMemory (migDbSection, sizeof (MIGDB_SECTION));
migDbSection->Context = g_ContextList;
migDbSection->Next = g_ContextList->Sections;
g_ContextList->Sections = migDbSection;
if (SetupFindFirstLine (g_OsFilesInf, sectEnum.SectName, NULL, &context)) {
do {
if (PatternScan) {
if (!pScanForFilePattern (&context, 1)) {
return FALSE;
}
} else {
if (!pScanForFile (&context, 1)) {
return FALSE;
}
}
}
while (SetupFindNextLine (&context, &context));
}
}
else {
DEBUGMSG ((DBG_ERROR, "Unable to create section for %s", SectionStr));
}
}
while (pEnumNextSection (&sectEnum));
}
return result;
}
BOOL
pLoadTypeData (
IN PCTSTR TypeStr,
IN BOOL PatternScan
)
/*++
Routine Description:
This routine updates migdb data structures loading a specified type data from inf file. For
every line in type section there is a migdb context created. Also for every migdb context
the coresponding section(s) is processed.
Arguments:
TypeStr - file type to process
Return value:
TRUE - the operation was successful
FALSE - otherwise
--*/
{
TCHAR section [MEMDB_MAX];
TCHAR locSection [MEMDB_MAX];
TCHAR message [MEMDB_MAX];
TCHAR tempField [MEMDB_MAX];
PTSTR tempFieldPtr;
PTSTR endOfArg = NULL;
DWORD fieldIndex;
PMIGDB_CONTEXT migDbContext = NULL;
INFCONTEXT context, context1;
BOOL result = TRUE;
INT actionIndex;
MYASSERT (g_OsFilesInf != INVALID_HANDLE_VALUE);
g_TypeGrowBuff.End = 0;
if (SetupFindFirstLine (g_OsFilesInf, TypeStr, NULL, &context)) {
//let's identify the action function index to update MIGDB_CONTEXT structure
actionIndex = MigDb_GetActionIdx (TypeStr);
if (actionIndex == -1) {
LOG ((LOG_ERROR, (PCSTR) MSG_MIGDB_BAD_ACTION, TypeStr));
}
do {
if (!SetupGetStringField (&context, 1, section, MEMDB_MAX, NULL)) {
LOG ((LOG_ERROR, (PCSTR) MSG_MIGDB_BAD_OR_MISSING_SECTION, TypeStr));
return FALSE;
}
if (!SetupGetStringField (&context, 2, message, MEMDB_MAX, NULL)) {
message [0] = 0;
}
migDbContext = (PMIGDB_CONTEXT) PmGetMemory (g_MigDbPool, sizeof (MIGDB_CONTEXT));
if (migDbContext == NULL) {
DEBUGMSG ((DBG_ERROR, "Unable to create context for %s.", TypeStr));
return FALSE;
}
ZeroMemory (migDbContext, sizeof (MIGDB_CONTEXT));
migDbContext->Next = g_ContextList;
g_ContextList = migDbContext;
// update ActionIndex with known value
migDbContext->ActionIndex = actionIndex;
// update SectName field
migDbContext->SectName = PmDuplicateString (g_MigDbPool, section);
// update SectLocalizedName field
if (SetupFindFirstLine (g_OsFilesInf, S_STRINGS, section, &context1)) {
if (SetupGetStringField (&context1, 1, locSection, MEMDB_MAX, NULL)) {
migDbContext->SectLocalizedName = PmDuplicateString (g_MigDbPool, locSection);
}
}
// set SectNameForDisplay to localized name, or sect name if no localized name
if (migDbContext->SectLocalizedName) {
migDbContext->SectNameForDisplay = migDbContext->SectLocalizedName;
} else {
migDbContext->SectNameForDisplay = migDbContext->SectName;
}
// update Message field
if (message[0] != 0) {
migDbContext->Message = PmDuplicateString (g_MigDbPool, message);
}
// OK, now let's scan all the remaining fields
fieldIndex = 3;
do {
tempField [0] = 0;
if (SetupGetStringField (&context, fieldIndex, tempField, MEMDB_MAX, NULL)) {
if (StringIMatchCharCount (tempField, ArgFunction, ArgFunctionLen)) {
//we have an additional argument for action function
tempFieldPtr = _tcschr (tempField, TEXT('('));
if (tempFieldPtr != NULL) {
tempFieldPtr = (PTSTR) SkipSpace (_tcsinc (tempFieldPtr));
if (tempFieldPtr != NULL) {
endOfArg = _tcschr (tempFieldPtr, TEXT(')'));
if (endOfArg != NULL) {
*endOfArg = 0;
endOfArg = (PTSTR) SkipSpaceR (tempFieldPtr, endOfArg);
}
if (endOfArg != NULL) {
*_tcsinc (endOfArg) = 0;
GbMultiSzAppend (&g_TypeGrowBuff, tempFieldPtr);
}
ELSE_DEBUGMSG ((
DBG_WHOOPS,
"Improperly formatted arg: %s in %s",
tempField,
TypeStr
));
}
}
}
else {
//we have something else, probably file name and attributes
if (!PatternScan) {
if (_tcschr (tempField, TEXT('.')) == NULL) {
LOG ((LOG_ERROR, (PCSTR) MSG_MIGDB_DOT_SYNTAX_ERROR, TypeStr, section));
}
}
//therefore we initialize the section (this context will have
//only one section) and parse the file info
migDbContext->Sections = (PMIGDB_SECTION) PmGetMemory (
g_MigDbPool,
sizeof (MIGDB_SECTION)
);
if (migDbContext->Sections != NULL) {
ZeroMemory (migDbContext->Sections, sizeof (MIGDB_SECTION));
migDbContext->Sections->Context = migDbContext;
migDbContext->Arguments = PmDuplicateMultiSz (g_MigDbPool, (PTSTR)g_TypeGrowBuff.Buf);
g_TypeGrowBuff.End = 0;
if (PatternScan) {
if (!pScanForFilePattern (&context, fieldIndex)) {
return FALSE;
}
} else {
if (!pScanForFile (&context, fieldIndex)) {
return FALSE;
}
}
tempField [0] = 0;
}
else {
DEBUGMSG ((DBG_ERROR, "Unable to create section for %s/%s", TypeStr, section));
return FALSE;
}
}
}
fieldIndex ++;
} while (tempField [0] != 0);
if (migDbContext->Sections == NULL) {
//now let's add action function arguments in MIGDB_CONTEXT structure
migDbContext->Arguments = PmDuplicateMultiSz (g_MigDbPool, (PTSTR)g_TypeGrowBuff.Buf);
g_TypeGrowBuff.End = 0;
//let's go to the sections and scan all files
if (!pLoadSectionData (section, PatternScan)) {
return FALSE;
}
}
}
while (SetupFindNextLine (&context, &context));
}
return result;
}
BOOL
InitMigDb (
IN PCTSTR MigDbFile
)
/*++
Routine Description:
This routine initialize memory and data structures used by MigDb.
Arguments:
NONE
Return value:
TRUE - the operation was successful
FALSE - otherwise
--*/
{
INT i;
BOOL patternFormat;
PCTSTR typeStr;
MYASSERT (g_OsFilesInf == INVALID_HANDLE_VALUE);
g_OsFilesInf = InfOpenInfFile (MigDbFile);
if (g_OsFilesInf == INVALID_HANDLE_VALUE) {
return FALSE;
}
g_MigDbPool = PmCreateNamedPool ("MigDb Pool");
PmDisableTracking (g_MigDbPool);
g_FileTable = HtAllocWithData (sizeof (FILE_LIST_STRUCT));
if (g_FileTable == NULL) {
DEBUGMSG ((DBG_ERROR, "Cannot initialize memory for migdb operations"));
return FALSE;
}
//load known types from migdb
i = 0;
do {
typeStr = MigDb_GetActionName (i);
if (typeStr != NULL) {
patternFormat = MigDb_IsPatternFormat (i);
if (!pLoadTypeData (typeStr, patternFormat)) {
GbFree (&g_AttrGrowBuff);
GbFree (&g_TypeGrowBuff);
return FALSE;
}
}
i++;
}
while (typeStr != NULL);
GbFree (&g_AttrGrowBuff);
GbFree (&g_TypeGrowBuff);
return TRUE;
}
BOOL
InitMigDbEx (
IN HINF InfHandle
)
{
INT i;
BOOL patternFormat;
PCTSTR typeStr;
MYASSERT (g_OsFilesInf == INVALID_HANDLE_VALUE);
MYASSERT (InfHandle != INVALID_HANDLE_VALUE);
g_OsFilesInf = InfHandle;
if (g_OsFilesInf == INVALID_HANDLE_VALUE) {
return FALSE;
}
g_MigDbPool = PmCreateNamedPool ("MigDb Pool");
PmDisableTracking (g_MigDbPool);
g_FileTable = HtAllocWithData (sizeof (FILE_LIST_STRUCT));
g_TypeRule = PmGetMemory (g_MigDbPool, sizeof (MIGDB_TYPE_RULE));
ZeroMemory (g_TypeRule, sizeof (MIGDB_TYPE_RULE));
if (g_FileTable == NULL) {
DEBUGMSG ((DBG_ERROR, "Cannot initialize memory for migdb operations"));
return FALSE;
}
//load known types from migdb
i = 0;
do {
typeStr = MigDb_GetActionName (i);
if (typeStr != NULL) {
patternFormat = MigDb_IsPatternFormat (i);
if (!pLoadTypeData (typeStr, patternFormat)) {
GbFree (&g_AttrGrowBuff);
GbFree (&g_TypeGrowBuff);
return FALSE;
}
}
i++;
}
while (typeStr != NULL);
GbFree (&g_AttrGrowBuff);
GbFree (&g_TypeGrowBuff);
return TRUE;
}
BOOL
DoneMigDbEx (
VOID
)
/*++
Routine Description:
This routine cleans up all memory used by MigDb.
Arguments:
NONE
Return value:
always TRUE
--*/
{
PMIGDB_CONTEXT migDbContext = NULL;
// first, let's walk through any context and check if it's a required one
migDbContext = g_ContextList;
while (migDbContext) {
if ((!MigDb_CallWhenTriggered (migDbContext->ActionIndex)) &&
(migDbContext->TriggerCount == 0)
) {
pCallAction (migDbContext);
}
migDbContext = migDbContext->Next;
}
if (g_FileTable != NULL) {
HtFree (g_FileTable);
g_FileTable = NULL;
}
if (g_MigDbPool != NULL) {
PmEmptyPool (g_MigDbPool);
PmDestroyPool (g_MigDbPool);
g_MigDbPool = NULL;
}
g_ContextList = NULL;
return TRUE;
}
BOOL
DoneMigDb (
VOID
)
/*++
Routine Description:
This routine cleans up all memory used by MigDb.
Arguments:
NONE
Return value:
always TRUE
--*/
{
if (!DoneMigDbEx ()) {
return FALSE;
}
if (g_OsFilesInf != INVALID_HANDLE_VALUE) {
InfCloseInfFile (g_OsFilesInf);
g_OsFilesInf = INVALID_HANDLE_VALUE;
}
return TRUE;
}
BOOL
CallAttribute (
IN PMIGDB_ATTRIB MigDbAttrib,
IN PDBATTRIB_PARAMS AttribParams
)
/*++
Routine Description:
This routine calls a specified attribute function for a specified file.
Arguments:
MigDbAttrib - See definition.
AttribParams - See definition
Return value:
TRUE - if attribute function succeded
FALSE - otherwise
--*/
{
PATTRIBUTE_PROTOTYPE p;
BOOL b;
if (MigDbAttrib->AttribIndex == -1) {
//invalid index for attribute function
return FALSE;
}
p = MigDb_GetAttributeAddr (MigDbAttrib->AttribIndex);
MYASSERT (p);
if (MigDbAttrib->NotOperator) {
b = !(p (AttribParams, MigDbAttrib->Arguments));
} else {
b = p (AttribParams, MigDbAttrib->Arguments);
}
return b;
}
BOOL
pCallAction (
IN PMIGDB_CONTEXT MigDbContext
)
/*++
Routine Description:
This routine calls an appropriate action for a specified migdb context.
Arguments:
MigDbContext - See definition.
Return value:
TRUE - if action function succeded
FALSE - otherwise
--*/
{
PACTION_PROTOTYPE p;
BOOL b;
p = MigDb_GetActionAddr (MigDbContext->ActionIndex);
MYASSERT (p);
b = p (MigDbContext);
return b;
}
BOOL
pCheckContext (
IN PMIGDB_CONTEXT MigDbContext,
IN BOOL Handled
)
/*++
Routine Description:
This routine checkes to see if a migdb context is met, that is if all sections
have Satisfied field TRUE.
Arguments:
MigDbContext - See definition.
Return value:
always TRUE
--*/
{
PMIGDB_SECTION migDbSection;
BOOL contextSelected;
BOOL result = FALSE;
migDbSection = MigDbContext->Sections;
contextSelected = TRUE;
while (migDbSection) {
if (!migDbSection->Satisfied) {
contextSelected = FALSE;
break;
}
migDbSection = migDbSection->Next;
}
if (contextSelected) {
MigDbContext->TriggerCount ++;
if (MigDbContext->ActionIndex == -1) {
//
// invalid index for action function
//
DEBUGMSG ((DBG_ERROR, "MigDb: Invalid action index"));
return FALSE;
}
//
// if appropriate call the action
//
if (MigDb_CallWhenTriggered (MigDbContext->ActionIndex)) {
if ((!Handled) ||
(MigDb_CallAlways (MigDbContext->ActionIndex))
) {
result = pCallAction (MigDbContext);
}
}
//clean up the grow buffer with file list
GbFree (&MigDbContext->FileList);
}
return result;
}
BOOL
pQueryRule (
IN MIG_OBJECTSTRINGHANDLE ObjectName,
IN PCTSTR ObjectNode
)
{
PTSTR objectBase = NULL;
PMIGDB_RULE rule;
PMIGDB_CHAR_NODE charNode;
PCTSTR p;
WORD w;
BOOL result = FALSE;
if (ObjectNode) {
objectBase = DuplicatePathString (ObjectNode, 0);
CharLower (objectBase);
}
g_TypeRuleList.End = 0;
p = objectBase;
if (p) {
w = (WORD) _tcsnextc (p);
charNode = g_TypeRule->FirstLevel;
while (charNode && *p) {
if (charNode->Char == w) {
if (charNode->RuleList) {
rule = charNode->RuleList;
while (rule) {
if (IsmParsedPatternMatch (
(MIG_PARSEDPATTERN)rule->ParsedPattern,
MIG_FILE_TYPE,
ObjectName
)) {
CopyMemory (
GbGrow (&g_TypeRuleList, sizeof (PMIGDB_RULE)),
&(rule),
sizeof (PMIGDB_RULE)
);
result = TRUE;
}
rule = rule->NextRule;
}
}
charNode = charNode->NextLevel;
p = _tcsinc (p);
w = (WORD) _tcsnextc (p);
} else {
charNode = charNode->NextPeer;
}
}
}
if (objectBase) {
FreePathString (objectBase);
}
return result;
}
BOOL
MigDbTestFile (
IN OUT PFILE_HELPER_PARAMS Params
)
/*++
Routine Description:
This is a callback function called for every file scanned. If the file is not handled we try
to see if we have this file in database. If so then we check for attributes, update the migdb
context and if necessarry call the appropriate action.
Arguments:
Params - See definition.
Return value:
TRUE - if operation was successful
FALSE - otherwise
--*/
{
HASHITEM stringId;
PMIGDB_RULE rule;
PMIGDB_FILE migDbFile;
PMIGDB_ATTRIB migDbAttrib;
DBATTRIB_PARAMS attribParams;
BOOL fileSelected;
PCTSTR fileName;
PCTSTR fileExt;
FILE_LIST_STRUCT fileList;
UINT index;
// we don't check the Handled field here because the code will be carefull enough not
// to call actions that are not gathering informations if the Handled field is not 0.
fileName = GetFileNameFromPath (Params->NativeObjectName);
fileExt = GetFileExtensionFromPath (fileName);
if (g_FileTable) {
stringId = HtFindString (g_FileTable, fileName);
if (stringId) {
//The string table has extra data (a pointer to a MigDbFile node)
HtCopyStringData (g_FileTable, stringId, &fileList);
migDbFile = fileList.First;
while (migDbFile) {
//check all attributes for this file
migDbAttrib = migDbFile->Attributes;
fileSelected = TRUE;
while (migDbAttrib != NULL) {
attribParams.FileParams = Params;
if (!CallAttribute (migDbAttrib, &attribParams)) {
fileSelected = FALSE;
break;
}
migDbAttrib = migDbAttrib->Next;
}
if (fileSelected) {
MYASSERT (migDbFile->Section);
//go to section and mark it as satisfied
migDbFile->Section->Satisfied = TRUE;
//go to context and add there the file we found in file list
GbMultiSzAppend (&migDbFile->Section->Context->FileList, Params->ObjectName);
//check if context is satisfied and if so then call the appropriate action
if (pCheckContext (migDbFile->Section->Context, Params->Handled)) {
Params->Handled = TRUE;
}
}
migDbFile = migDbFile->Next;
}
}
}
if (g_TypeRule) {
g_TypeRuleList.End = 0;
if (pQueryRule (Params->ObjectName, Params->ObjectNode)) {
// let's enumerate all the matching rules to check for attributes
index = 0;
while (index < g_TypeRuleList.End) {
CopyMemory (&rule, &(g_TypeRuleList.Buf[index]), sizeof (PMIGDB_RULE));
//check all attributes for this file
migDbAttrib = rule->Attributes;
fileSelected = TRUE;
while (migDbAttrib != NULL) {
attribParams.FileParams = Params;
if (!CallAttribute (migDbAttrib, &attribParams)) {
fileSelected = FALSE;
break;
}
migDbAttrib = migDbAttrib->Next;
}
if (fileSelected) {
//One last thing. See if this object is a node and the rule accepts nodes
if (!rule->IncludeNodes) {
if (IsmIsObjectHandleNodeOnly (Params->ObjectName)) {
fileSelected = FALSE;
}
}
if (fileSelected) {
MYASSERT (rule->Section);
//go to section and mark it as satisfied
rule->Section->Satisfied = TRUE;
//go to context and add there the file we found in file list
GbMultiSzAppend (&rule->Section->Context->FileList, Params->ObjectName);
//check if context is satisfied and if so then call the appropriate action
if (pCheckContext (rule->Section->Context, Params->Handled)) {
Params->Handled = TRUE;
}
}
}
index += sizeof (PMIGDB_RULE);
}
}
g_TypeRuleList.End = 0;
}
return TRUE;
}