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

681 lines
18 KiB
C

/*++
Copyright (c) 2000 Microsoft Corporation
Module Name:
rules.c
Abstract:
Implements the "rule" algorithm that scores script patterns and keeps them
in reverse-sorted order.
Author:
Jim Schmidt (jimschm) 12-May-2000
Revision History:
<alias> <date> <comments>
--*/
//
// Includes
//
#include "pch.h"
#include "v1p.h"
#define DBG_V1 "v1"
//
// Strings
//
// None
//
// Constants
//
// None
//
// Macros
//
// None
//
// Types
//
typedef struct _TAG_RULE {
PCTSTR ObjectBase;
MIG_OBJECTSTRINGHANDLE ObjectPattern;
POBSPARSEDPATTERN ParsedPattern;
UINT Score;
ACTIONGROUP ActionGroup;
DWORD ActionFlags;
ACTION_STRUCT ActionStruct;
struct _TAG_RULE *NextRule;
} RULE, *PRULE;
typedef struct _TAG_CHAR_NODE {
PRULE RuleList;
WORD Char;
WORD Flags;
struct _TAG_CHAR_NODE *NextLevel;
struct _TAG_CHAR_NODE *NextPeer;
} CHAR_NODE, *PCHAR_NODE;
typedef struct {
MIG_OBJECTTYPEID ObjectTypeId;
PRULE RuleList;
PCHAR_NODE FirstLevel;
} TYPE_RULE, *PTYPE_RULE;
typedef struct {
MIG_OBJECTTYPEID ObjectTypeId;
TYPE_RULE TypeRule;
} TYPETORULE, *PTYPETORULE;
//
// Globals
//
GROWBUFFER g_TypeToIncRule = INIT_GROWBUFFER;
GROWBUFFER g_TypeToPriRule = INIT_GROWBUFFER;
GROWBUFFER g_TypeToCollRule = INIT_GROWBUFFER;
GROWBUFFER g_TypeRuleList = INIT_GROWBUFFER;
PMHANDLE g_RulePool;
//
// Macro expansion list
//
// None
//
// Private function prototypes
//
// None
//
// Macro expansion definition
//
// None
//
// Code
//
BOOL
pAddRuleToTypeRule (
IN PTYPE_RULE TypeRule,
IN PRULE Rule
)
{
PCHAR_NODE node, currNode, prevNode;
PTSTR objectBase;
PCTSTR p;
WORD w;
BOOL found;
if (Rule->ObjectBase) {
currNode = TypeRule->FirstLevel;
prevNode = currNode;
objectBase = DuplicatePathString (Rule->ObjectBase, 0);
CharLower (objectBase);
p = objectBase;
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_RulePool, sizeof (CHAR_NODE));
ZeroMemory (node, sizeof (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_RulePool, sizeof (CHAR_NODE));
ZeroMemory (node, sizeof (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 (objectBase);
} else {
Rule->NextRule = TypeRule->RuleList;
TypeRule->RuleList = Rule;
}
return TRUE;
}
UINT
pComputeSubScore (
IN BOOL ExcludeLastPatSeg,
IN PCTSTR String,
IN UINT WildcardScore,
IN UINT FixedCharScore,
IN UINT WackScoreBeforeWildcard,
IN UINT WackScoreAfterWildcard
)
{
PCTSTR p;
BOOL skipExtendedPattern;
UINT score = 0;
BOOL patternEncountered = FALSE;
CHARTYPE ch;
UINT state = 0;
UINT delScore = 0;
for (p = String ; *p ; p = _tcsinc (p)) {
skipExtendedPattern = FALSE;
switch (_tcsnextc (p)) {
case TEXT('*'):
if (state == 1) {
state = 2;
}
if (state == 2) {
delScore += WildcardScore;
}
score += WildcardScore;
skipExtendedPattern = TRUE;
patternEncountered = TRUE;
break;
case TEXT('?'):
if (state == 1) {
state = 2;
}
if (state == 2) {
delScore += WildcardScore;
}
score += WildcardScore;
skipExtendedPattern = TRUE;
patternEncountered = TRUE;
break;
case TEXT('\\'):
state = 1;
if (patternEncountered) {
score += WackScoreAfterWildcard;
delScore = WackScoreAfterWildcard;
} else {
score += WackScoreBeforeWildcard;
delScore = WackScoreBeforeWildcard;
}
break;
case TEXT(':'):
//
// Special case: if just a drive spec with no wacks,
// add the wack score
//
if (p[1] == 0) {
score += WackScoreBeforeWildcard;
break;
}
// fall through
default:
state = 0;
delScore = 0;
score += FixedCharScore;
break;
}
if (skipExtendedPattern) {
if (_tcsnextc (_tcsinc (p)) == TEXT('[')) {
do {
p = _tcsinc (p);
ch = (CHARTYPE) _tcsnextc (p);
if (ch == TEXT('^')) {
p++;
}
} while (ch != TEXT(']'));
}
}
}
if (ExcludeLastPatSeg) {
if (score > delScore) {
score -= delScore;
if (delScore && score > 0) {
score -= 1;
}
} else {
score = 0;
}
}
return score;
}
UINT
pComputeScore (
IN MIG_OBJECTSTRINGHANDLE EncodedString
)
{
PCTSTR node;
PCTSTR leaf;
UINT score = 0;
IsmCreateObjectStringsFromHandle (EncodedString, &node, &leaf);
if (node) {
score += 1000 * pComputeSubScore (TRUE, node, 0, 10, 1000, 500);
}
if (leaf) {
score += pComputeSubScore (FALSE, leaf, 0, 10, 0, 0);
}
IsmDestroyObjectString (node);
IsmDestroyObjectString (leaf);
return score;
}
PTYPE_RULE
pGetListForType (
IN PGROWBUFFER TypeToRule,
IN MIG_OBJECTTYPEID ObjectTypeId
)
{
PTYPE_RULE pos;
PTYPE_RULE end;
ObjectTypeId &= ~(PLATFORM_MASK);
pos = (PTYPE_RULE) TypeToRule->Buf;
end = (PTYPE_RULE) (TypeToRule->Buf + TypeToRule->End);
while (pos < end) {
if (pos->ObjectTypeId == ObjectTypeId) {
return pos;
}
pos++;
}
pos = (PTYPE_RULE) GbGrow (TypeToRule, sizeof (TYPE_RULE));
ZeroMemory (pos, sizeof (TYPE_RULE));
pos->ObjectTypeId = ObjectTypeId;
return pos;
}
VOID
InitRules (
VOID
)
{
g_RulePool = PmCreateNamedPoolEx ("Rule Data", 32768);
PmDisableTracking (g_RulePool);
}
VOID
TerminateRules (
VOID
)
{
GbFree (&g_TypeToIncRule);
GbFree (&g_TypeToPriRule);
GbFree (&g_TypeToCollRule);
GbFree (&g_TypeRuleList);
PmEmptyPool (g_RulePool);
PmDestroyPool (g_RulePool);
INVALID_POINTER (g_RulePool);
}
UINT
pGetActionWeight (
IN ACTIONGROUP ActionGroup
)
{
switch (ActionGroup) {
case ACTIONGROUP_DEFAULTPRIORITY:
return ACTIONWEIGHT_DEFAULTPRIORITY;
case ACTIONGROUP_SPECIFICPRIORITY:
return ACTIONWEIGHT_SPECIFICPRIORITY;
case ACTIONGROUP_EXCLUDE:
return ACTIONWEIGHT_EXCLUDE;
case ACTIONGROUP_EXCLUDEEX:
return ACTIONWEIGHT_EXCLUDEEX;
case ACTIONGROUP_INCLUDE:
return ACTIONWEIGHT_INCLUDE;
case ACTIONGROUP_INCLUDEEX:
return ACTIONWEIGHT_INCLUDEEX;
case ACTIONGROUP_RENAME:
return ACTIONWEIGHT_RENAME;
case ACTIONGROUP_RENAMEEX:
return ACTIONWEIGHT_RENAMEEX;
case ACTIONGROUP_INCLUDERELEVANT:
return ACTIONWEIGHT_INCLUDERELEVANT;
case ACTIONGROUP_INCLUDERELEVANTEX:
return ACTIONWEIGHT_INCLUDERELEVANTEX;
case ACTIONGROUP_RENAMERELEVANT:
return ACTIONWEIGHT_RENAMERELEVANT;
case ACTIONGROUP_RENAMERELEVANTEX:
return ACTIONWEIGHT_RENAMERELEVANTEX;
case ACTIONGROUP_REGFILE:
return ACTIONWEIGHT_REGFILE;
case ACTIONGROUP_REGFILEEX:
return ACTIONWEIGHT_REGFILEEX;
case ACTIONGROUP_REGFOLDER:
return ACTIONWEIGHT_REGFOLDER;
case ACTIONGROUP_REGFOLDEREX:
return ACTIONWEIGHT_REGFOLDEREX;
case ACTIONGROUP_REGICON:
return ACTIONWEIGHT_REGICON;
case ACTIONGROUP_REGICONEX:
return ACTIONWEIGHT_REGICONEX;
case ACTIONGROUP_DELREGKEY:
return ACTIONWEIGHT_DELREGKEY;
default:
return 0;
}
}
BOOL
AddRuleEx (
IN MIG_OBJECTTYPEID Type,
IN MIG_OBJECTSTRINGHANDLE ObjectBase,
IN MIG_OBJECTSTRINGHANDLE ObjectPattern,
IN ACTIONGROUP ActionGroup,
IN DWORD ActionFlags,
IN PACTION_STRUCT ActionStruct, OPTIONAL
IN RULEGROUP RuleGroup
)
{
PTYPE_RULE typeRule;
MIG_SEGMENTS nodeSegment;
MIG_SEGMENTS leafSegment;
PCTSTR ourEncodedString;
PCTSTR node;
PCTSTR leaf;
PRULE rule;
PGROWBUFFER ruleStruct;
switch (RuleGroup) {
case RULEGROUP_NORMAL:
ruleStruct = &g_TypeToIncRule;
break;
case RULEGROUP_PRIORITY:
ruleStruct = &g_TypeToPriRule;
break;
case RULEGROUP_COLLPATTERN:
ruleStruct = &g_TypeToCollRule;
break;
}
typeRule = pGetListForType (ruleStruct, Type);
if (!typeRule) {
return FALSE;
}
//
// Make sure both node an leaf are specified
//
IsmCreateObjectStringsFromHandleEx (ObjectPattern, &node, &leaf, TRUE);
nodeSegment.Segment = node ? node : TEXT("*");
nodeSegment.IsPattern = TRUE;
leafSegment.Segment = leaf ? leaf : TEXT("*");
leafSegment.IsPattern = TRUE;
ourEncodedString = IsmCreateObjectPattern (
&nodeSegment,
1,
&leafSegment,
1
);
IsmDestroyObjectString (node);
IsmDestroyObjectString (leaf);
//
// Insert the rule based on score
//
rule = PmGetMemory (g_RulePool, sizeof (RULE));
ZeroMemory (rule, sizeof (RULE));
if (ObjectBase) {
IsmCreateObjectStringsFromHandle (ObjectBase, &node, &leaf);
if (node) {
rule->ObjectBase = PmDuplicateString (g_RulePool, node);
}
IsmDestroyObjectString (node);
IsmDestroyObjectString (leaf);
}
rule->ObjectPattern = PmDuplicateString (g_RulePool, ourEncodedString);
rule->ParsedPattern = ObsCreateParsedPatternEx (g_RulePool, ourEncodedString, FALSE);
MYASSERT (rule->ParsedPattern);
if (rule->ParsedPattern) {
rule->Score = pComputeScore (ourEncodedString);
rule->Score = rule->Score * 10 + pGetActionWeight (ActionGroup);
rule->ActionGroup = ActionGroup;
rule->ActionFlags = ActionFlags;
if (ActionStruct) {
if (ActionStruct->ObjectBase) {
rule->ActionStruct.ObjectBase = PmDuplicateString (g_RulePool, ActionStruct->ObjectBase);
}
if (ActionStruct->ObjectDest) {
rule->ActionStruct.ObjectDest = PmDuplicateString (g_RulePool, ActionStruct->ObjectDest);
}
if (ActionStruct->AddnlDest) {
rule->ActionStruct.AddnlDest = PmDuplicateString (g_RulePool, ActionStruct->AddnlDest);
}
if (ActionStruct->ObjectHint) {
rule->ActionStruct.ObjectHint = PmDuplicateString (g_RulePool, ActionStruct->ObjectHint);
}
}
pAddRuleToTypeRule (typeRule, rule);
} else {
IsmCreateObjectStringsFromHandleEx (ourEncodedString, &node, &leaf, TRUE);
LOG ((LOG_ERROR, (PCSTR) MSG_OBJECT_SPEC_ERROR, node, leaf));
IsmDestroyObjectString (node);
IsmDestroyObjectString (leaf);
}
IsmDestroyObjectHandle (ourEncodedString);
return TRUE;
}
BOOL
QueryRuleEx (
IN MIG_OBJECTTYPEID Type,
IN MIG_OBJECTSTRINGHANDLE EncodedString,
IN PCTSTR ObjectNode,
OUT PACTIONGROUP ActionGroup,
OUT PDWORD ActionFlags,
OUT PACTION_STRUCT ActionStruct, OPTIONAL
IN RULEGROUP RuleGroup
)
{
PTYPE_RULE typeRule;
PCHAR_NODE charNode;
PTSTR objectBase;
PCTSTR p;
WORD w;
PRULE rule;
PRULE foundRule;
UINT maxScore;
ACTIONGROUP initialAction = ACTIONGROUP_NONE;
DWORD matchingFlags = 0;
PGROWBUFFER ruleStruct;
switch (RuleGroup) {
case RULEGROUP_NORMAL:
ruleStruct = &g_TypeToIncRule;
break;
case RULEGROUP_PRIORITY:
ruleStruct = &g_TypeToPriRule;
break;
case RULEGROUP_COLLPATTERN:
ruleStruct = &g_TypeToCollRule;
break;
}
if (ActionStruct) {
ZeroMemory (ActionStruct, sizeof (ACTION_STRUCT));
}
typeRule = pGetListForType (ruleStruct, Type);
if (!typeRule) {
return FALSE;
}
//
// Let's walk the structure finding all possible rules and put them in a grow buffer
// Later we'll examine the rules one by one. Note that the root rules always qualify
//
if (ObjectNode) {
objectBase = DuplicatePathString (ObjectNode, 0);
CharLower (objectBase);
}
g_TypeRuleList.End = 0;
p = objectBase;
if (p) {
w = (WORD) _tcsnextc (p);
charNode = typeRule->FirstLevel;
while (charNode && *p) {
if (charNode->Char == w) {
if (charNode->RuleList) {
CopyMemory (GbGrow (&g_TypeRuleList, sizeof (PRULE)), &(charNode->RuleList), sizeof (PRULE));
}
charNode = charNode->NextLevel;
p = _tcsinc (p);
w = (WORD) _tcsnextc (p);
} else {
charNode = charNode->NextPeer;
}
}
}
maxScore = 0;
foundRule = NULL;
while (g_TypeRuleList.End) {
CopyMemory (&rule, &(g_TypeRuleList.Buf[g_TypeRuleList.End - sizeof (PRULE)]), sizeof (PRULE));
while (rule) {
if (maxScore <= rule->Score) {
if (IsmParsedPatternMatch ((MIG_PARSEDPATTERN)rule->ParsedPattern, Type, EncodedString)) {
if (foundRule && (maxScore == rule->Score)) {
if (initialAction == rule->ActionGroup) {
matchingFlags |= rule->ActionFlags;
}
} else {
foundRule = rule;
initialAction = foundRule->ActionGroup;
matchingFlags = foundRule->ActionFlags;
maxScore = rule->Score;
}
}
}
rule = rule->NextRule;
}
g_TypeRuleList.End -= sizeof (PRULE);
}
rule = typeRule->RuleList;
while (rule) {
if (maxScore <= rule->Score) {
if (IsmParsedPatternMatch ((MIG_PARSEDPATTERN)rule->ParsedPattern, Type, EncodedString)) {
if (foundRule && (maxScore == rule->Score)) {
if (initialAction == rule->ActionGroup) {
matchingFlags |= rule->ActionFlags;
}
} else {
foundRule = rule;
initialAction = foundRule->ActionGroup;
matchingFlags = foundRule->ActionFlags;
maxScore = rule->Score;
}
}
}
rule = rule->NextRule;
}
if (foundRule) {
*ActionGroup = initialAction;
*ActionFlags = matchingFlags;
if (ActionStruct && (!ActionStruct->ObjectBase) && (foundRule->ActionStruct.ObjectBase)) {
ActionStruct->ObjectBase = foundRule->ActionStruct.ObjectBase;
}
if (ActionStruct && (!ActionStruct->ObjectDest) && (foundRule->ActionStruct.ObjectDest)) {
ActionStruct->ObjectDest = foundRule->ActionStruct.ObjectDest;
}
if (ActionStruct && (!ActionStruct->AddnlDest) && (foundRule->ActionStruct.AddnlDest)) {
ActionStruct->AddnlDest = foundRule->ActionStruct.AddnlDest;
}
if (ActionStruct && (!ActionStruct->ObjectHint) && (foundRule->ActionStruct.ObjectHint)) {
ActionStruct->ObjectHint = foundRule->ActionStruct.ObjectHint;
}
}
FreePathString (objectBase);
return (foundRule != NULL);
}