windows-nt/Source/XPSP1/NT/windows/winstate/cobra/engine/ism/flowctrl.c
2020-09-26 16:20:57 +08:00

3277 lines
90 KiB
C

/*++
Copyright (c) 1997 Microsoft Corporation
Module Name:
flowctrl.c
Abstract:
Implements the control functionality for the ISM. This includes the enumeration manager, transport marshalling
and apply module ordering.
Author:
Marc R. Whitten (marcw) 15-Nov-1999
Revision History:
marcw 1-Dec-1999 Added function level callback prioritization and non-enumerated callbacks.
--*/
//
// Includes
//
#include "pch.h"
#include "ism.h"
#include "ismp.h"
#define DBG_FLOW "FlowCtrl"
//
// Strings
//
#define S_INI_SGMFUNCTIONHIGHPRIORITY TEXT("Source.Gather Function High Priority")
#define S_INI_SGMFUNCTIONLOWPRIORITY TEXT("Source.Gather Function Low Priority")
#define S_INI_DGMFUNCTIONHIGHPRIORITY TEXT("Destination.Gather Function High Priority")
#define S_INI_DGMFUNCTIONLOWPRIORITY TEXT("Destination.Gather Function Low Priority")
//
// Constants
//
#define MINIMUM_FUNCTION_PRIORITY 0xFFFFFFFF
#define MIDDLE_FUNCTION_PRIORITY 0x80000000
#define MAXIMUM_FUNCTION_PRIORITY 0x00000000
#define CALLBEFOREOBJECTENUMERATIONS 0
#define CALLAFTEROBJECTENUMERATIONS 1
//
// Macros
//
#define CALLBACK_ENUMFLAGS_TOP(b) ((PCALLBACK_ENUMFLAGS) ((b)->End > 0 ? ((b)->Buf + (b)->End - sizeof (CALLBACK_ENUMFLAGS)) : NULL))
//
// Types
//
typedef struct {
UINT Level;
BOOL Enabled;
UINT EnableLevel;
DWORD Flags;
} CALLBACK_ENUMFLAGS, *PCALLBACK_ENUMFLAGS;
typedef enum {
CALLBACK_NORMAL = 0x00000001,
CALLBACK_HOOK,
CALLBACK_EXCLUSION,
CALLBACK_PHYSICAL_ENUM,
CALLBACK_PHYSICAL_ACQUIRE
} CALLBACK_TYPE;
typedef struct _TAG_CALLBACKDATA {
//
// Callback Data
//
FARPROC Function;
FARPROC Function2;
UINT MaxLevel;
UINT MinLevel;
PPARSEDPATTERN NodeParsedPattern;
PPARSEDPATTERN ExplodedNodeParsedPattern;
PPARSEDPATTERN LeafParsedPattern;
PPARSEDPATTERN ExplodedLeafParsedPattern;
PCTSTR Pattern;
ULONG_PTR CallbackArg;
CALLBACK_TYPE CallbackType;
//
// Enumeration Control Members
//
GROWBUFFER EnumFlags;
BOOL Done;
BOOL Error;
//
// Prioritization and Identification Members
//
PCTSTR Group;
PCTSTR Identifier;
UINT Priority;
//
// Linkage.
//
struct _TAG_CALLBACKDATA * Next;
struct _TAG_CALLBACKDATA * Prev;
} CALLBACKDATA, *PCALLBACKDATA;
typedef struct _TAG_ENUMDATA {
PCTSTR Pattern;
PPARSEDPATTERN NodeParsedPattern;
PPARSEDPATTERN ExplodedNodeParsedPattern;
PPARSEDPATTERN LeafParsedPattern;
PPARSEDPATTERN ExplodedLeafParsedPattern;
//
// Linkage.
//
struct _TAG_ENUMDATA * Next;
struct _TAG_ENUMDATA * Prev;
} ENUMDATA, *PENUMDATA;
typedef struct {
MIG_OBJECTTYPEID ObjectTypeId;
PCTSTR TypeName;
PCALLBACKDATA PreEnumerationFunctionList;
PCALLBACKDATA PostEnumerationFunctionList;
PCALLBACKDATA FunctionList;
PCALLBACKDATA ExclusionList;
PCALLBACKDATA PhysicalEnumList;
PCALLBACKDATA PhysicalAcquireList;
PENUMDATA FirstEnum;
PENUMDATA LastEnum;
} TYPEENUMINFO, *PTYPEENUMINFO;
typedef BOOL (NONENUMERATEDCALLBACK)(VOID);
typedef NONENUMERATEDCALLBACK *PNONENUMERATEDCALLBACK;
typedef struct {
MIG_OBJECTTYPEID ObjectTypeId;
PMIG_PHYSICALENUMADD AddCallback;
ULONG_PTR AddCallbackArg;
PCTSTR Node;
PCTSTR Leaf;
} ENUMADDCALLBACK, *PENUMADDCALLBACK;
//
// Globals
//
PGROWLIST g_TypeData = NULL;
PGROWLIST g_GlobalTypeData = NULL;
PCALLBACKDATA g_PreEnumerationFunctionList = NULL;
PCALLBACKDATA g_PostEnumerationFunctionList = NULL;
PMHANDLE g_GlobalQueuePool;
PMHANDLE g_UntrackedFlowPool;
PMHANDLE g_CurrentQueuePool;
GROWBUFFER g_EnumerationList = INIT_GROWBUFFER;
GROWLIST g_AcquireList = INIT_GROWLIST;
GROWLIST g_EnumList = INIT_GROWLIST;
GROWLIST g_EnumAddList = INIT_GROWLIST;
#ifdef DEBUG
PCTSTR g_QueueFnName;
#define SETQUEUEFN(x) g_QueueFnName = x
#else
#define SETQUEUEFN(x)
#endif
//
// Macro expansion list
//
// None
//
// Private function prototypes
//
VOID
pAddStaticExclusion (
IN MIG_OBJECTTYPEID ObjectTypeId,
IN MIG_OBJECTSTRINGHANDLE EncodedFullName
);
//
// Macro expansion definition
//
// None
//
// Code
//
BOOL
pInsertCallbackIntoSortedList (
IN PMHANDLE Pool,
IN OUT PCALLBACKDATA * Head,
IN PCALLBACKDATA Data
)
/*++
Routine Description:
pInsertCallback into sorted list.
Arguments:
Pool - Specifies the pool to allocate from
Head - Specifies this head of the callback data list.
Data - Specifies the data to add to the list.
Return Value:
TRUE if the callbackdata was successfully added to the list, FALSE
otherwise.
--*/
{
PCALLBACKDATA cur = *Head;
PCALLBACKDATA last = NULL;
PCALLBACKDATA dataCopy = NULL;
dataCopy = (PCALLBACKDATA) PmGetMemory (Pool, sizeof (CALLBACKDATA));
CopyMemory (dataCopy, Data, sizeof (CALLBACKDATA));
if (!cur || dataCopy->Priority < cur->Priority) {
//
// Add to the head of the list if necessary.
//
dataCopy->Next = cur;
if (cur) {
cur->Prev = dataCopy;
}
*Head = dataCopy;
}
else {
//
// Add inside the list.
// Always goes through the while loop once (see the if above)
//
while (dataCopy->Priority >= cur->Priority) {
last = cur;
if (!cur->Next) {
break;
}
cur = cur->Next;
}
//
// Add immediately after cur
//
dataCopy->Next = last->Next;
last->Next = dataCopy;
dataCopy->Prev = last;
}
return TRUE;
}
BOOL
pRegisterCallback (
IN PMHANDLE Pool,
IN OUT PCALLBACKDATA * FunctionList,
IN FARPROC Callback,
IN FARPROC Callback2,
IN ULONG_PTR CallbackArg,
IN MIG_OBJECTSTRINGHANDLE Pattern, OPTIONAL
IN PCTSTR FunctionId, OPTIONAL
IN CALLBACK_TYPE CallbackType
)
/*++
Routine Description:
pRegisterCallback does the actual work of adding a callback to the
necessary flow control data structures.
Arguments:
Pool - Specifies the pool to allocate from
FunctionList - Specifies the list of callback functions that will be
updated with the new function.
Callback - Specifies the callback function to register
Callback2 - Specifies the second callback function to register
CallbackArg - Specifies a caller-defined value to be passed back on each
enumeration
Pattern - Optionally specifies the pattern that to be associated with
the callback function
FunctionId - Specifies the Function Identifer for the callback. This is used
for function level prioritization.
Return Value:
TRUE if the callback was successfully registered. FALSE otherwise.
--*/
{
CALLBACKDATA data;
INFSTRUCT is = INITINFSTRUCT_PMHANDLE;
PTSTR nodePattern = NULL;
PTSTR leafPattern = NULL;
PCTSTR lowPriorityStr;
PCTSTR highPriorityStr;
BOOL result = TRUE;
MYASSERT (g_CurrentGroup);
//
// Initialize callback data.
//
ZeroMemory (&data, sizeof (CALLBACKDATA));
__try {
data.Function = Callback;
data.Function2 = Callback2;
data.CallbackArg = CallbackArg;
data.Group = PmDuplicateString (Pool, g_CurrentGroup);
data.CallbackType = CallbackType;
if (FunctionId) {
data.Identifier = PmDuplicateString (Pool, FunctionId);
}
//
// Store pattern information (pattern, max level, min level)
//
if (Pattern) {
data.Pattern = PmDuplicateString (Pool, Pattern);
ObsSplitObjectStringEx (Pattern, &nodePattern, &leafPattern, NULL, FALSE);
if (!nodePattern && !leafPattern) {
DEBUGMSG ((DBG_ERROR, "Pattern specified has null node and leaf"));
result = FALSE;
__leave;
}
if (nodePattern) {
GetNodePatternMinMaxLevels (nodePattern, NULL, &data.MinLevel, &data.MaxLevel);
data.NodeParsedPattern = CreateParsedPatternEx (Pool, nodePattern);
if (data.NodeParsedPattern) {
data.ExplodedNodeParsedPattern = ExplodeParsedPatternEx (Pool, data.NodeParsedPattern);
}
ObsFree (nodePattern);
nodePattern = NULL;
} else {
if (data.CallbackType == CALLBACK_NORMAL) {
DEBUGMSG ((DBG_ERROR, "%s: Pattern must specify a node %s", g_QueueFnName, data.Pattern));
result = FALSE;
__leave;
} else {
GetNodePatternMinMaxLevels (TEXT("*"), NULL, &data.MinLevel, &data.MaxLevel);
data.NodeParsedPattern = CreateParsedPatternEx (Pool, TEXT("*"));
data.ExplodedNodeParsedPattern = ExplodeParsedPatternEx (Pool, data.NodeParsedPattern);
DestroyParsedPattern (data.NodeParsedPattern);
data.NodeParsedPattern = NULL;
}
}
if (leafPattern) {
data.LeafParsedPattern = CreateParsedPatternEx (Pool, leafPattern);
if (data.LeafParsedPattern) {
data.ExplodedLeafParsedPattern = ExplodeParsedPatternEx (Pool, data.LeafParsedPattern);
}
ObsFree (leafPattern);
leafPattern = NULL;
}
}
//
// Get the priority for this function.
//
data.Priority = MIDDLE_FUNCTION_PRIORITY;
if (FunctionId) {
if (g_IsmModulePlatformContext == PLATFORM_SOURCE) {
lowPriorityStr = S_INI_SGMFUNCTIONLOWPRIORITY;
highPriorityStr = S_INI_SGMFUNCTIONHIGHPRIORITY;
} else {
lowPriorityStr = S_INI_DGMFUNCTIONLOWPRIORITY;
highPriorityStr = S_INI_DGMFUNCTIONHIGHPRIORITY;
}
if (InfFindFirstLine (g_IsmInf, highPriorityStr, FunctionId, &is)) {
data.Priority = MAXIMUM_FUNCTION_PRIORITY + is.Context.Line;
}
else if (InfFindFirstLine (g_IsmInf, lowPriorityStr, FunctionId, &is)) {
data.Priority = MINIMUM_FUNCTION_PRIORITY - is.Context.Line;
}
InfCleanUpInfStruct (&is);
}
//
// Add the function to the list.
//
pInsertCallbackIntoSortedList (Pool, FunctionList, &data);
}
__finally {
InfCleanUpInfStruct (&is);
if (nodePattern) {
ObsFree (nodePattern);
nodePattern = NULL;
}
if (leafPattern) {
ObsFree (leafPattern);
leafPattern = NULL;
}
if (!result) {
if (data.NodeParsedPattern) {
DestroyParsedPattern (data.NodeParsedPattern);
}
if (data.ExplodedNodeParsedPattern) {
DestroyParsedPattern (data.ExplodedNodeParsedPattern);
}
if (data.LeafParsedPattern) {
DestroyParsedPattern (data.LeafParsedPattern);
}
if (data.ExplodedLeafParsedPattern) {
DestroyParsedPattern (data.ExplodedLeafParsedPattern);
}
ZeroMemory (&data, sizeof (CALLBACKDATA));
}
}
return result;
}
BOOL
pTestContainer (
IN PPARSEDPATTERN NodeContainer,
IN PPARSEDPATTERN NodeContained,
IN PPARSEDPATTERN LeafContainer,
IN PPARSEDPATTERN LeafContained
)
{
MYASSERT (NodeContainer);
MYASSERT (NodeContained);
if ((!NodeContainer) ||
(!NodeContained)
) {
return FALSE;
}
if (!IsExplodedParsedPatternContainedEx (NodeContainer, NodeContained, FALSE)) {
//they don't match
return FALSE;
}
if (!LeafContained) {
if (LeafContainer) {
// If there is a leaf pattern for container the caller will get nodes
// only if the node pattern has wild chars. So, since we know that the
// contained node pattern is included in the container node pattern
// we just need to see if the container node pattern includes wild chars.
return WildCharsPattern (NodeContainer);
} else {
//both are NULL so...
return TRUE;
}
} else {
if (!LeafContainer) {
// Even if the contained has a leaf pattern, it will get nodes only if
// the node pattern has wild chars. So, since we know that the contained
// node pattern is included in the container node pattern we just need
// to see if the contained node pattern includes wild chars
return WildCharsPattern (NodeContained);
} else {
//return the actual match of non-null parsed patterns
return IsExplodedParsedPatternContainedEx (LeafContainer, LeafContained, TRUE);
}
}
}
BOOL
pTestContainerEx (
IN PPARSEDPATTERN NodeContainer,
IN PPARSEDPATTERN NodeContained,
IN PPARSEDPATTERN LeafContainer,
IN PPARSEDPATTERN LeafContained
)
{
MYASSERT (NodeContainer);
MYASSERT (NodeContained);
if ((!NodeContainer) ||
(!NodeContained)
) {
return FALSE;
}
if (!DoExplodedParsedPatternsIntersect (NodeContainer, NodeContained)) {
if (!DoExplodedParsedPatternsIntersectEx (NodeContainer, NodeContained, TRUE)) {
return FALSE;
}
}
if (!LeafContained) {
if (LeafContainer) {
// If there is a leaf pattern for container the caller will get nodes
// only if the node pattern has wild chars. So, since we know that the
// contained node pattern is included in the container node pattern
// we just need to see if the container node pattern includes wild chars.
return WildCharsPattern (NodeContainer);
} else {
//both are NULL so...
return TRUE;
}
} else {
if (!LeafContainer) {
// Even if the contained has a leaf pattern, it will get nodes only if
// the node pattern has wild chars. So, since we know that the contained
// node pattern is included in the container node pattern we just need
// to see if the contained node pattern includes wild chars
return WildCharsPattern (NodeContained);
} else {
//return the actual match of non-null parsed patterns
return DoExplodedParsedPatternsIntersect (LeafContainer, LeafContained);
}
}
}
BOOL
pAddEnumeration (
IN PMHANDLE Pool,
IN OUT PTYPEENUMINFO TypeEnumInfo,
IN MIG_OBJECTSTRINGHANDLE ObjectPattern
)
/*++
Routine Description:
pAddEnumeration Adds an enumeration string to the list of enumerations
needed for a given type. Because the flow control module tries to use only
a minimal set of enumerations, the actual enumeration may not be added.
After a successful call to this function, any data needed by the specified
enumeration will be enumerated.
Arguments:
Pool - Specifies the pool to allocate from
TypeEnumInfo - Specifies the type info structure that will receive the new
enumeration data.
ObjectPattern - Specifies the enumeration pattern to add to the type.
Return Value:
TRUE if the pattern was successfully added, FALSE otherwise.
--*/
{
PENUMDATA enumData;
PENUMDATA oldEnumData;
PCTSTR nodePattern = NULL;
PCTSTR leafPattern = NULL;
PPARSEDPATTERN nodeParsedPattern = NULL;
PPARSEDPATTERN explodedNodeParsedPattern = NULL;
PPARSEDPATTERN leafParsedPattern = NULL;
PPARSEDPATTERN explodedLeafParsedPattern = NULL;
//
// Add this to the enumeration list unless its already listed.
//
if (!ObsSplitObjectStringEx (ObjectPattern, &nodePattern, &leafPattern, NULL, FALSE)) {
DEBUGMSG ((DBG_ERROR, "Bad pattern detected in pAddEnumeration: %s", ObjectPattern));
return FALSE;
}
if (nodePattern) {
nodeParsedPattern = CreateParsedPatternEx (Pool, nodePattern);
if (nodeParsedPattern) {
explodedNodeParsedPattern = ExplodeParsedPatternEx (Pool, nodeParsedPattern);
}
ObsFree (nodePattern);
INVALID_POINTER (nodePattern);
}
if (leafPattern) {
leafParsedPattern = CreateParsedPatternEx (Pool, leafPattern);
if (leafParsedPattern) {
explodedLeafParsedPattern = ExplodeParsedPatternEx (Pool, leafParsedPattern);
}
ObsFree (leafPattern);
INVALID_POINTER (leafPattern);
}
enumData = TypeEnumInfo->FirstEnum;
while (enumData) {
if (pTestContainer (enumData->ExplodedNodeParsedPattern, explodedNodeParsedPattern, enumData->ExplodedLeafParsedPattern, explodedLeafParsedPattern)) {
DEBUGMSG ((DBG_FLOW, "Enumeration %s not added. It will be handled during enumeration %s.", ObjectPattern, enumData->Pattern));
break;
}
if (pTestContainer (explodedNodeParsedPattern, enumData->ExplodedNodeParsedPattern, explodedLeafParsedPattern, enumData->ExplodedLeafParsedPattern)) {
DEBUGMSG ((DBG_FLOW, "Enumeration %s will replace enumeration %s.", ObjectPattern, enumData->Pattern));
if (enumData->Prev) {
enumData->Prev->Next = enumData->Next;
}
if (enumData->Next) {
enumData->Next->Prev = enumData->Prev;
}
if (TypeEnumInfo->FirstEnum == enumData) {
TypeEnumInfo->FirstEnum = enumData->Next;
}
if (TypeEnumInfo->LastEnum == enumData) {
TypeEnumInfo->LastEnum = enumData->Prev;
}
PmReleaseMemory (Pool, enumData->Pattern);
DestroyParsedPattern (enumData->ExplodedLeafParsedPattern);
DestroyParsedPattern (enumData->LeafParsedPattern);
DestroyParsedPattern (enumData->ExplodedNodeParsedPattern);
DestroyParsedPattern (enumData->NodeParsedPattern);
oldEnumData = enumData;
enumData = enumData->Next;
PmReleaseMemory (Pool, oldEnumData);
} else {
enumData = enumData->Next;
}
}
if (enumData == NULL) {
DEBUGMSG ((DBG_FLOW, "Adding Enumeration %s to the list of enumerations of type %s.", ObjectPattern, TypeEnumInfo->TypeName));
enumData = (PENUMDATA) PmGetMemory (Pool, sizeof (ENUMDATA));
ZeroMemory (enumData, sizeof (ENUMDATA));
enumData->Pattern = PmDuplicateString (Pool, ObjectPattern);
enumData->NodeParsedPattern = nodeParsedPattern;
enumData->ExplodedNodeParsedPattern = explodedNodeParsedPattern;
enumData->LeafParsedPattern = leafParsedPattern;
enumData->ExplodedLeafParsedPattern = explodedLeafParsedPattern;
if (TypeEnumInfo->LastEnum) {
TypeEnumInfo->LastEnum->Next = enumData;
}
enumData->Prev = TypeEnumInfo->LastEnum;
TypeEnumInfo->LastEnum = enumData;
if (!TypeEnumInfo->FirstEnum) {
TypeEnumInfo->FirstEnum = enumData;
}
} else {
DestroyParsedPattern (explodedLeafParsedPattern);
DestroyParsedPattern (leafParsedPattern);
DestroyParsedPattern (explodedNodeParsedPattern);
DestroyParsedPattern (nodeParsedPattern);
}
return TRUE;
}
PTYPEENUMINFO
pGetTypeEnumInfo (
IN MIG_OBJECTTYPEID ObjectTypeId,
IN BOOL GlobalData
)
/*++
Routine Description:
pGetTypeEnumInfo returns the TypeEnumInfo for a specified type.
Arguments:
ObjectTypeId - Specifies the object type.
GlobalData - Specifies TRUE if the type enum data is global to the whole process,
or FALSE if it is specific to the current enumeration queue.
Return Value:
A TypeEnumInfo structure if one was found, NULL otherwise.
--*/
{
UINT i;
UINT count;
PTYPEENUMINFO rTypeEnumInfo;
PGROWLIST *typeData;
if (GlobalData) {
typeData = &g_GlobalTypeData;
} else {
typeData = &g_TypeData;
}
if (!(*typeData)) {
return NULL;
}
count = GlGetSize (*typeData);
//
// Find the matching type info for this item.
//
for (i = 0; i < count; i++) {
rTypeEnumInfo = (PTYPEENUMINFO) GlGetItem (*typeData, i);
if (rTypeEnumInfo->ObjectTypeId == ObjectTypeId) {
return rTypeEnumInfo;
}
}
return NULL;
}
BOOL
pProcessQueueEnumeration (
IN MIG_OBJECTTYPEID ObjectTypeId,
IN MIG_OBJECTSTRINGHANDLE ObjectPattern,
IN FARPROC Callback,
IN FARPROC Callback2, OPTIONAL
IN ULONG_PTR CallbackArg, OPTIONAL
IN PCTSTR FunctionId, OPTIONAL
IN CALLBACK_TYPE CallbackType
)
/*++
Routine Description:
pProcessQueueEnumeration is used by Source Gather Modules and Destination Gather Modules
in order to register a callback function to be called for a particular object enumeration.
Arguments:
ObjectTypeId - Specifies the object type for the enumeration.
ObjectPattern - Specifies the enumeration pattern to use.
Callback - Specifies the function to callback during the enumeration
Callback2 - Specifies the second function to callback during the enumeration (used
for the free function of physical hooks)
CallbackArg - Specifies a caller-defined value to be passed back on
each enumeration
FunctionId - Specifies the function identifier string, which is used
to prioritize function calls. The function string must
match the priorization string in the control INF file.
GrowEnumPattern - Specifies if the global enumeration pattern should be
grown to include this one. If FALSE, this function just
wants to be called back for all objects matching the
pattern but does not want to force the enumeration of
the pattern.
ExclusionCallback - Specifies TRUE if Callback is an exclusion callback, or
FALSE if Callback is an object enum callback
Return Value:
TRUE if the enumeration was successfully queued, FALSE otherwise.
--*/
{
PTYPEENUMINFO typeEnumInfo;
PCALLBACKDATA * list;
BOOL globalData;
BOOL result = FALSE;
MIG_OBJECTSTRINGHANDLE handle = NULL;
PMHANDLE pool;
__try {
MYASSERT (ObjectTypeId);
if (!ObjectPattern) {
handle = IsmCreateSimpleObjectPattern (NULL, TRUE, NULL, TRUE);
ObjectPattern = handle;
if (!handle) {
MYASSERT (FALSE);
__leave;
}
}
if (CallbackType == CALLBACK_PHYSICAL_ACQUIRE ||
CallbackType == CALLBACK_PHYSICAL_ENUM ||
CallbackType == CALLBACK_EXCLUSION
) {
globalData = TRUE;
pool = g_GlobalQueuePool;
} else {
globalData = FALSE;
pool = g_CurrentQueuePool;
}
if (!g_CurrentGroup) {
DEBUGMSG ((DBG_ERROR, "%s called outside of ISM-managed callback", g_QueueFnName));
__leave;
}
typeEnumInfo = pGetTypeEnumInfo (ObjectTypeId, globalData);
if (!typeEnumInfo) {
DEBUGMSG ((DBG_ERROR, "%s: %d does not match a known object type.", g_QueueFnName, ObjectTypeId));
__leave;
}
//
// Save away the callback function and associated data.
//
switch (CallbackType) {
case CALLBACK_EXCLUSION:
list = &typeEnumInfo->ExclusionList;
break;
case CALLBACK_PHYSICAL_ENUM:
list = &typeEnumInfo->PhysicalEnumList;
break;
case CALLBACK_PHYSICAL_ACQUIRE:
list = &typeEnumInfo->PhysicalAcquireList;
break;
default:
list = &typeEnumInfo->FunctionList;
break;
}
if (!pRegisterCallback (
pool,
list,
Callback,
Callback2,
CallbackArg,
ObjectPattern,
FunctionId,
CallbackType
)) {
__leave;
}
if (CallbackType == CALLBACK_NORMAL) {
//
// Save the pattern into the object tree and link the callback function with it.
//
if (!pAddEnumeration (pool, typeEnumInfo, ObjectPattern)) {
__leave;
}
}
result = TRUE;
}
__finally {
if (handle) {
IsmDestroyObjectHandle (handle);
}
}
return result;
}
BOOL
IsmProhibitPhysicalEnum (
IN MIG_OBJECTTYPEID ObjectTypeId,
IN MIG_OBJECTSTRINGHANDLE ObjectPattern,
IN PMIG_PHYSICALENUMCHECK EnumCheckCallback, OPTIONAL
IN ULONG_PTR CallbackArg, OPTIONAL
IN PCTSTR FunctionId OPTIONAL
)
{
SETQUEUEFN(TEXT("IsmProhibitPhysicalEnum"));
if (!ObjectPattern) {
DEBUGMSG ((DBG_ERROR, "IsmProhibitPhysicalEnum: ObjectPattern is required"));
return FALSE;
}
return pProcessQueueEnumeration (
ObjectTypeId,
ObjectPattern,
(FARPROC) EnumCheckCallback,
NULL,
CallbackArg,
FunctionId,
CALLBACK_PHYSICAL_ENUM
);
}
BOOL
IsmAddToPhysicalEnum (
IN MIG_OBJECTTYPEID ObjectTypeId,
IN MIG_OBJECTSTRINGHANDLE ObjectBase,
IN PMIG_PHYSICALENUMADD EnumAddCallback,
IN ULONG_PTR CallbackArg OPTIONAL
)
{
PCTSTR newNode = NULL;
PCTSTR newLeaf = NULL;
UINT u;
UINT count;
ENUMADDCALLBACK callbackStruct;
PENUMADDCALLBACK storedStruct;
BOOL result = FALSE;
UINT newTchars;
UINT existTchars;
UINT tchars;
CHARTYPE ch;
if (!ObjectTypeId || !ObjectBase || !EnumAddCallback) {
SetLastError (ERROR_INVALID_PARAMETER);
return FALSE;
}
//
// First test to see if the object base is already listed
//
ObsSplitObjectStringEx (ObjectBase, &newNode, &newLeaf, NULL, TRUE);
if (!newNode) {
DEBUGMSG ((DBG_ERROR, "IsmAddToPhysicalEnum requires a node"));
} else {
count = GlGetSize (&g_EnumAddList);
for (u = 0 ; u < count ; u++) {
storedStruct = (PENUMADDCALLBACK) GlGetItem (&g_EnumAddList, u);
MYASSERT (storedStruct);
if (storedStruct->AddCallback != EnumAddCallback) {
if (StringIMatch (newNode, storedStruct->Node)) {
//
// Node is the same; leaf must be unique
//
if (!newLeaf || !storedStruct->Leaf) {
DEBUGMSG ((DBG_ERROR, "IsmAddToPhysicalEnum requires a unique object for %s", newNode));
break;
}
if (StringIMatch (newLeaf, storedStruct->Leaf)) {
DEBUGMSG ((
DBG_ERROR,
"IsmAddToPhysicalEnum does not have a unique leaf for %s leaf %s",
newNode,
newLeaf
));
break;
}
} else if (!newLeaf) {
//
// New node cannot be a prefix of an existing node, and vice-versa
//
newTchars = TcharCount (newNode);
existTchars = TcharCount (storedStruct->Node);
tchars = min (newTchars, existTchars);
//
// Compare only when new node might consume stored node
//
if (existTchars == tchars) {
// stored node is shortest; ignore if it has a leaf
if (storedStruct->Leaf) {
continue;
}
}
if (StringIMatchTcharCount (newNode, storedStruct->Node, tchars)) {
//
// Verify the end of the common prefix lands on either a nul or a
// backslash. Otherwise, the prefix isn't common.
//
if (tchars == newTchars) {
ch = (CHARTYPE) _tcsnextc (newNode + tchars);
} else {
ch = (CHARTYPE) _tcsnextc (storedStruct->Node + tchars);
}
if (!ch || ch == TEXT('\\')) {
if (tchars == newTchars) {
DEBUGMSG ((
DBG_ERROR,
"IsmAddToPhysicalEnum: %s is already handled by %s",
newNode,
storedStruct->Node
));
} else {
DEBUGMSG ((
DBG_ERROR,
"IsmAddToPhysicalEnum: %s is already handled by %s",
storedStruct->Node,
newNode
));
}
break;
}
}
}
}
}
if (u >= count) {
ZeroMemory (&callbackStruct, sizeof (callbackStruct));
callbackStruct.ObjectTypeId = ObjectTypeId & ~(PLATFORM_MASK);
callbackStruct.Node = PmDuplicateString (g_UntrackedFlowPool, newNode);
callbackStruct.Leaf = newLeaf ? PmDuplicateString (g_UntrackedFlowPool, newLeaf) : NULL;
callbackStruct.AddCallback = EnumAddCallback;
callbackStruct.AddCallbackArg = CallbackArg;
GlAppend (&g_EnumAddList, (PBYTE) &callbackStruct, sizeof (ENUMADDCALLBACK));
result = TRUE;
}
}
ObsFree (newNode);
ObsFree (newLeaf);
return result;
}
BOOL
IsmRegisterPhysicalAcquireHook (
IN MIG_OBJECTTYPEID ObjectTypeId,
IN MIG_OBJECTSTRINGHANDLE ObjectPattern, OPTIONAL
IN PMIG_PHYSICALACQUIREHOOK HookCallback,
IN PMIG_PHYSICALACQUIREFREE FreeCallback, OPTIONAL
IN ULONG_PTR CallbackArg, OPTIONAL
IN PCTSTR FunctionId OPTIONAL
)
{
ObjectTypeId &= ~PLATFORM_MASK;
SETQUEUEFN(TEXT("IsmRegisterPhysicalAcquireHook"));
return pProcessQueueEnumeration (
ObjectTypeId,
ObjectPattern,
(FARPROC) HookCallback,
(FARPROC) FreeCallback,
CallbackArg,
FunctionId,
CALLBACK_PHYSICAL_ACQUIRE
);
}
BOOL
IsmRegisterStaticExclusion (
IN MIG_OBJECTTYPEID ObjectTypeId,
IN MIG_OBJECTSTRINGHANDLE EncodedObjectName
)
{
ObjectTypeId = FixEnumerationObjectTypeId (ObjectTypeId);
pAddStaticExclusion (ObjectTypeId, EncodedObjectName);
return TRUE;
}
UINT
WINAPI
pMakeApplyCallback (
IN PCMIG_OBJECTENUMDATA Data,
IN ULONG_PTR CallerArg
)
{
if (CallerArg & QUEUE_MAKE_APPLY) {
IsmMakeApplyObject (Data->ObjectTypeId, Data->ObjectName);
} else if (CallerArg & QUEUE_MAKE_PERSISTENT) {
IsmMakePersistentObject (Data->ObjectTypeId, Data->ObjectName);
}
if (CallerArg & QUEUE_OVERWRITE_DEST) {
IsmAbandonObjectOnCollision ((Data->ObjectTypeId & ~PLATFORM_MASK)|PLATFORM_DESTINATION, Data->ObjectName);
} else if (CallerArg & QUEUE_DONT_OVERWRITE_DEST) {
IsmAbandonObjectOnCollision ((Data->ObjectTypeId & ~PLATFORM_MASK)|PLATFORM_SOURCE, Data->ObjectName);
}
if (CallerArg & QUEUE_MAKE_NONCRITICAL) {
IsmMakeNonCriticalObject (Data->ObjectTypeId, Data->ObjectName);
}
return CALLBACK_ENUM_CONTINUE;
}
BOOL
IsmQueueEnumeration (
IN MIG_OBJECTTYPEID ObjectTypeId,
IN MIG_OBJECTSTRINGHANDLE ObjectPattern, OPTIONAL
IN PMIG_OBJECTENUMCALLBACK Callback, OPTIONAL
IN ULONG_PTR CallbackArg, OPTIONAL
IN PCTSTR FunctionId OPTIONAL
)
/*++
Routine Description:
IsmQueueEnumeration is used by Source Gather Modules and Destination Gather
Modules in order to register a callback function to be called for a
particular object enumeration.
Arguments:
ObjectTypeId - Specifies the object type for the enumeration.
ObjectPattern - Specifies the enumeration pattern to use. If not specified,
all objects for ObjectTypeId are queued.
Callback - Specifies the function to callback during the enumeration.
If not defined, the built-in ISM callback is used (which
marks the objects as persistent).
CallbackArg - Specifies a caller-defined value to be passed back on
each enumeration. If Callback is NULL, then this argument
specifies zero or more of the following flags:
QUEUE_MAKE_PERSISTENT or QUEUE_MAKE_APPLY (mutually exclusive)
QUEUE_OVERWRITE_DEST or QUEUE_DONT_OVERWRITE_DEST (mutually exclusive)
FunctionId - Specifies the function identifier string, which is used to
prioritize function calls. The function string must match
the priorization string in the control INF file. If
Callback is NULL, then this parameter is forced to the value
"SetDestPriority", "MakePersistent" or "MakeApply" depending
on CallbackArg.
Return Value:
TRUE if the enumeration was successfully queued, FALSE otherwise.
--*/
{
ObjectTypeId = FixEnumerationObjectTypeId (ObjectTypeId);
SETQUEUEFN(TEXT("IsmQueueEnumeration"));
if (!Callback) {
Callback = pMakeApplyCallback;
if (!CallbackArg) {
CallbackArg = QUEUE_MAKE_APPLY;
}
if (CallbackArg & QUEUE_MAKE_APPLY) {
FunctionId = TEXT("MakeApply");
} else if (CallbackArg & QUEUE_MAKE_PERSISTENT) {
FunctionId = TEXT("MakePersistent");
} else {
FunctionId = TEXT("SetDestPriority");
}
}
return pProcessQueueEnumeration (
ObjectTypeId,
ObjectPattern,
(FARPROC) Callback,
NULL,
CallbackArg,
FunctionId,
CALLBACK_NORMAL
);
}
BOOL
IsmHookEnumeration (
IN MIG_OBJECTTYPEID ObjectTypeId,
IN MIG_OBJECTSTRINGHANDLE ObjectPattern,
IN PMIG_OBJECTENUMCALLBACK Callback,
IN ULONG_PTR CallbackArg, OPTIONAL
IN PCTSTR FunctionId OPTIONAL
)
/*++
Routine Description:
IsmHookEnumeration is used by Source Gather Modules and Destination Gather Modules
in order to register a callback function to be called for a particular object enumeration. The
difference to IsmQueueEnumeration is that this function does not expand the
global enumeration pattern.
Arguments:
ObjectTypeId - Specifies the object type for the enumeration.
ObjectPattern - Specifies the enumeration pattern to use. If not specified,
all objects of type ObjectTypeId are hooked.
Callback - Specifies the function to callback during the enumeration
CallbackArg - Specifies a caller-defined value to be passed back on
each enumeration
FunctionId - Specifies the function identifier string, which is used to
prioritize function calls. The function string must match
the priorization string in the control INF file.
Return Value:
TRUE if the enumeration was successfully queued, FALSE otherwise.
--*/
{
ObjectTypeId = FixEnumerationObjectTypeId (ObjectTypeId);
SETQUEUEFN(TEXT("IsmHookEnumeration"));
return pProcessQueueEnumeration (
ObjectTypeId,
ObjectPattern,
(FARPROC) Callback,
NULL,
CallbackArg,
FunctionId,
CALLBACK_HOOK
);
}
BOOL
IsmRegisterDynamicExclusion (
IN MIG_OBJECTTYPEID ObjectTypeId,
IN MIG_OBJECTSTRINGHANDLE ObjectPattern, OPTIONAL
IN PMIG_DYNAMICEXCLUSIONCALLBACK Callback,
IN ULONG_PTR CallbackArg, OPTIONAL
IN PCTSTR FunctionId OPTIONAL
)
{
ObjectTypeId = FixEnumerationObjectTypeId (ObjectTypeId);
SETQUEUEFN(TEXT("IsmRegisterDynamicExclusion"));
return pProcessQueueEnumeration (
ObjectTypeId,
ObjectPattern,
(FARPROC) Callback,
NULL,
CallbackArg,
FunctionId,
CALLBACK_EXCLUSION
);
}
BOOL
pRegisterNonEnumeratedCallback (
IN FARPROC Callback,
IN UINT WhenCalled,
IN PCTSTR FunctionId, OPTIONAL
IN BOOL PerTypeId,
IN MIG_OBJECTTYPEID ObjectTypeId
)
/*++
Routine Description:
IsmRegisterNonEnumeratedCallback is used to register a function to be
called either before or after the enumeration of data.
Arguments:
Callback - Specifies the function to call.
WhenCalled - Specifies the timing of the non-enumerated callback. Either
CALLBEFOREOBJECTENUMERATIONS or CALLAFTEROBJECTENUMERATIONS
FunctionId - Optionally specifies the function identifier string. This
parameter can be used to add function level prioritization to
the module.
PerTypeId - Specifies if the pre or post enumeration callback is per type
ObjectTypeId - Specifies the object type id if PerTypeId is TRUE
Return Value:
TRUE if the function was successfully registered. FALSE otherwise.
--*/
{
PTYPEENUMINFO typeEnumInfo;
PCALLBACKDATA * list;
MYASSERT (Callback);
MYASSERT (WhenCalled == CALLBEFOREOBJECTENUMERATIONS || WhenCalled == CALLAFTEROBJECTENUMERATIONS);
if (!g_CurrentGroup) {
DEBUGMSG ((DBG_ERROR, "IsmRegisterNonEnumeratedCallback called outside of ISM-managed callback."));
return FALSE;
}
if (PerTypeId) {
typeEnumInfo = pGetTypeEnumInfo (ObjectTypeId, FALSE);
if (!typeEnumInfo) {
DEBUGMSG ((DBG_ERROR, "IsmRegisterNonEnumeratedCallback: %d does not match a known object type.", ObjectTypeId));
return FALSE;
}
if (WhenCalled == CALLBEFOREOBJECTENUMERATIONS) {
list = &(typeEnumInfo->PreEnumerationFunctionList);
}
else {
list = &(typeEnumInfo->PostEnumerationFunctionList);
}
} else {
if (WhenCalled == CALLBEFOREOBJECTENUMERATIONS) {
list = &g_PreEnumerationFunctionList;
}
else {
list = &g_PostEnumerationFunctionList;
}
}
return pRegisterCallback (
g_CurrentQueuePool,
list,
(FARPROC) Callback,
NULL,
(ULONG_PTR) 0,
NULL,
FunctionId,
CALLBACK_NORMAL
);
}
BOOL
IsmRegisterPreEnumerationCallback (
IN PMIG_PREENUMCALLBACK Callback,
IN PCTSTR FunctionId OPTIONAL
)
{
return pRegisterNonEnumeratedCallback (
(FARPROC) Callback,
CALLBEFOREOBJECTENUMERATIONS,
FunctionId,
FALSE,
0
);
}
BOOL
IsmRegisterTypePreEnumerationCallback (
IN MIG_OBJECTTYPEID ObjectTypeId,
IN PMIG_PREENUMCALLBACK Callback,
IN PCTSTR FunctionId OPTIONAL
)
{
ObjectTypeId = FixEnumerationObjectTypeId (ObjectTypeId);
return pRegisterNonEnumeratedCallback (
(FARPROC) Callback,
CALLBEFOREOBJECTENUMERATIONS,
FunctionId,
TRUE,
ObjectTypeId
);
}
BOOL
IsmRegisterPostEnumerationCallback (
IN PMIG_POSTENUMCALLBACK Callback,
IN PCTSTR FunctionId OPTIONAL
)
{
return pRegisterNonEnumeratedCallback (
(FARPROC) Callback,
CALLAFTEROBJECTENUMERATIONS,
FunctionId,
FALSE,
0
);
}
BOOL
IsmRegisterTypePostEnumerationCallback (
IN MIG_OBJECTTYPEID ObjectTypeId,
IN PMIG_POSTENUMCALLBACK Callback,
IN PCTSTR FunctionId OPTIONAL
)
{
ObjectTypeId = FixEnumerationObjectTypeId (ObjectTypeId);
return pRegisterNonEnumeratedCallback (
(FARPROC) Callback,
CALLAFTEROBJECTENUMERATIONS,
FunctionId,
TRUE,
ObjectTypeId
);
}
VOID
pCreateFunctionListForPattern (
IN OUT PGROWLIST List,
IN PTYPEENUMINFO TypeEnumInfo,
IN PCTSTR Pattern,
IN PPARSEDPATTERN ExplodedNodeParsedPattern,
IN PPARSEDPATTERN ExplodedLeafParsedPattern,
IN CALLBACK_TYPE CallbackType
)
/*++
Routine Description:
pCreateFunctionListForPattern enumerates all callback functions for a given
type and determines if they could be interested in an enumeration keyed off
of the given pattern. Since we use a minimal list of patterns, at each
pattern we must come up with the list of callback functions associated with
patterns contained by our minimal pattern.
Arguments:
List - Specifies the growlist where the callback functions are to be
stored. After the function's return, this list contains all
callback functions that are needed for the given enumeration
pattern.
TypeEnumInfo - Specifies the type to draw potential callback functions from.
Pattern - Specifies the minimal pattern to that will be used for
enumeration.
ExplodedNodeParsedPattern - Specifies the node portion of Pattern, in pre-parsed
exploded format.
ExplodedLeafParsedPattern - Specifies the leaf portion of Pattern, in pre-parsed
exploded format.
CallbackType - Specifies which type of callback list to use (a CALLBACK_* constant)
Return Value:
None.
--*/
{
PCALLBACKDATA data;
BOOL processHooks = FALSE;
if (!TypeEnumInfo) {
return;
}
//
// Loop through all functions for this type, and add functions that fall under the
// current enumeration pattern.
//
switch (CallbackType) {
case CALLBACK_EXCLUSION:
data = TypeEnumInfo->ExclusionList;
break;
default:
data = TypeEnumInfo->FunctionList;
processHooks = TRUE;
break;
}
if (!data) {
return;
}
while (data) {
if (pTestContainer (
ExplodedNodeParsedPattern,
data->ExplodedNodeParsedPattern,
ExplodedLeafParsedPattern,
data->ExplodedLeafParsedPattern
)) {
GlAppend (List, (PBYTE) data, sizeof (CALLBACKDATA));
} else if (processHooks) {
if (data->CallbackType == CALLBACK_HOOK) {
if (pTestContainerEx (
data->ExplodedNodeParsedPattern,
ExplodedNodeParsedPattern,
data->ExplodedLeafParsedPattern,
ExplodedLeafParsedPattern
)) {
GlAppend (List, (PBYTE) data, sizeof (CALLBACKDATA));
}
}
}
data = data->Next;
}
}
VOID
pDestroyFunctionListForPattern (
IN OUT PGROWLIST List
)
/*++
Routine Description:
This function simply cleans up the resources associated with a function
list.
Arguments:
List - Specifies the growlist of callbackdata to clean up.
Return Value:
None.
--*/
{
UINT i;
PCALLBACKDATA data;
UINT count;
//
// Clean up enum modification stacks.
//
count = GlGetSize (List);
for (i = 0; i < count; i++) {
data = (PCALLBACKDATA) GlGetItem (List, i);
GbFree (&data->EnumFlags);
}
//
// Clean up list itself.
//
GlFree (List);
}
VOID
pAddStaticExclusion (
IN MIG_OBJECTTYPEID ObjectTypeId,
IN MIG_OBJECTSTRINGHANDLE EncodedFullName
)
{
HASHTABLE exclusionTable;
if (!EncodedFullName) {
//
// Ignore request for bad name
//
return;
}
ObjectTypeId = ObjectTypeId & (~PLATFORM_MASK);
exclusionTable = GetTypeExclusionTable (ObjectTypeId);
if (!exclusionTable) {
return;
}
HtAddString (exclusionTable, EncodedFullName);
}
BOOL
pIsObjectExcluded (
IN MIG_OBJECTTYPEID ObjectTypeId,
IN MIG_OBJECTSTRINGHANDLE EncodedFullName
)
{
HASHTABLE exclusionTable;
if (!EncodedFullName) {
return FALSE;
}
//
// Check the hash table for an entry
//
ObjectTypeId = ObjectTypeId & (~PLATFORM_MASK);
exclusionTable = GetTypeExclusionTable (ObjectTypeId);
if (!exclusionTable) {
return FALSE;
}
if (HtFindString (exclusionTable, EncodedFullName)) {
return TRUE;
}
return FALSE;
}
BOOL
pIsObjectNodeExcluded (
IN MIG_OBJECTTYPEID ObjectTypeId,
IN PCTSTR NodePattern,
OUT PBOOL PossiblePatternMatch OPTIONAL
)
{
HASHTABLE exclusionTable;
HASHTABLE_ENUM e;
PCTSTR node;
PTSTR wackedExclusion;
PCTSTR firstWildcard = NULL;
PCTSTR wildcard1;
PCTSTR wildcard2;
UINT patternStrTchars;
UINT hashStrTchars;
BOOL match = FALSE;
ObjectTypeId = ObjectTypeId & (~PLATFORM_MASK);
exclusionTable = GetTypeExclusionTable (ObjectTypeId);
if (!exclusionTable) {
return FALSE;
}
//
// If NodePattern is a pattern, then PossiblePatternMatch is specified.
// Otherwise, NodePattern is a specific node.
//
if (PossiblePatternMatch) {
//
// Computer the length of the non-pattern portion
//
*PossiblePatternMatch = FALSE;
firstWildcard = NULL;
wildcard1 = ObsFindNonEncodedCharInEncodedString (NodePattern, TEXT('*'));
wildcard2 = ObsFindNonEncodedCharInEncodedString (NodePattern, TEXT('?'));
if (wildcard1) {
firstWildcard = wildcard1;
}
if (wildcard2) {
if ((!firstWildcard) || (firstWildcard > wildcard2)) {
firstWildcard = wildcard2;
}
}
if (!firstWildcard) {
firstWildcard = GetEndOfString (NodePattern);
}
} else {
firstWildcard = GetEndOfString (NodePattern);
}
//
// Enumerate all exclusions and check NodePattern against them
//
patternStrTchars = (HALF_PTR) (firstWildcard - NodePattern);
if (EnumFirstHashTableString (&e, exclusionTable)) {
do {
if (IsmIsObjectHandleNodeOnly (e.String)) {
IsmCreateObjectStringsFromHandle (e.String, &node, NULL);
MYASSERT (node);
hashStrTchars = TcharCount (node);
if (hashStrTchars < patternStrTchars) {
//
// Require exclusion to be a prefix, ending in a backslash
//
wackedExclusion = DuplicatePathString (node, sizeof (TCHAR));
AppendWack (wackedExclusion);
if (StringIPrefix (NodePattern, wackedExclusion)) {
match = TRUE;
}
FreePathString (wackedExclusion);
} else {
//
// Require exclusion to match identically
//
if (hashStrTchars == patternStrTchars &&
StringIMatch (NodePattern, e.String)
) {
match = TRUE;
} else if (PossiblePatternMatch && !match) {
//
// We *might* have an exclusion match (we can't tell).
// If the pattern contains no wacks, then we assume
// the enumerated node will determine exclusion
// properly.
//
// This could be optimized further by checking if the
// character set of NodePattern is a subset of the
// exclusion string.
//
if (!_tcschr (NodePattern, TEXT('\\'))) {
*PossiblePatternMatch = TRUE;
}
}
}
IsmDestroyObjectString (node);
}
} while (!match && EnumNextHashTableString (&e));
}
return match;
}
BOOL
pShouldCallGatherCallback (
IN PMIG_TYPEOBJECTENUM Object,
IN PCALLBACKDATA Callback
)
/*++
Routine Description:
This function encapsulates the logic needed to determine wether or not to
callback the specified callback. This is necessary because patterns
requested by various Data Gather Modules are collapsed into a minimal set
of enumeration patterns. Therefore, we only know that a particular callback
may be interested in the current object. This function is used to make
sure.
Arguments:
Object - Specifies the current object being enumerated.
Callback - Specifies the callback data to be checked. This may be modified,
if a previous enumeration change request by the callback has now
expired.
Return Value:
TRUE if the callback should be called, FALSE otherwise.
--*/
{
PCALLBACK_ENUMFLAGS flags;
BOOL result = FALSE;
PTSTR tempString;
if (Object->Level >= Callback->MinLevel && Object->Level <= Callback->MaxLevel ) {
//
// Don't call callbacks that have signaled they are finished or that have errored.
//
if (Callback->Done || Callback->Error) {
return FALSE;
}
//
// See if there is a enumeration modification in effect for this callback.
//
flags = CALLBACK_ENUMFLAGS_TOP(&Callback->EnumFlags);
//
// Remove stale entries in the modification list.
//
while (flags) {
if (Object->IsNode) {
if (flags->Level > Object->Level) {
Callback->EnumFlags.End -= sizeof (CALLBACK_ENUMFLAGS);
flags = CALLBACK_ENUMFLAGS_TOP (&Callback->EnumFlags);
continue;
}
if ((flags->Level == Object->Level) && (flags->Flags == CALLBACK_SKIP_LEAVES)) {
Callback->EnumFlags.End -= sizeof (CALLBACK_ENUMFLAGS);
flags = CALLBACK_ENUMFLAGS_TOP (&Callback->EnumFlags);
continue;
}
}
if (Object->IsLeaf) {
if (flags->Level > (Object->Level + 1)) {
Callback->EnumFlags.End -= sizeof (CALLBACK_ENUMFLAGS);
flags = CALLBACK_ENUMFLAGS_TOP (&Callback->EnumFlags);
continue;
}
}
break;
}
if (flags && (!flags->Enabled) && Object->IsNode && (flags->EnableLevel == Object->Level)) {
flags->Enabled = TRUE;
}
//
// Check flags to see if we should call this function.
//
if (flags) {
if (flags->Enabled && flags->Flags == CALLBACK_THIS_TREE_ONLY) {
if (flags->Level == Object->Level) {
Callback->Done = TRUE;
return FALSE;
}
}
if (flags->Enabled && flags->Flags == CALLBACK_SKIP_LEAVES) {
if ((Object->IsLeaf) && (flags->Level == Object->Level + 1)) {
return FALSE;
}
}
if (flags->Enabled && flags->Flags == CALLBACK_SKIP_NODES) {
if (flags->Level <= Object->Level){
return FALSE;
}
}
if (flags->Enabled && flags->Flags == CALLBACK_SKIP_TREE) {
if (flags->Level <= (Object->IsLeaf?Object->Level+1:Object->Level)){
return FALSE;
}
}
}
//
// If we haven't failed out yet, do a pattern match against the function's requested
// enumeration.
//
result = TRUE;
if (Object->ObjectNode) {
if (Callback->NodeParsedPattern) {
result = TestParsedPattern (Callback->NodeParsedPattern, Object->ObjectNode);
if (!result) {
//
// let's try one more time with a wack at the end
//
tempString = JoinText (Object->ObjectNode, TEXT("\\"));
result = TestParsedPattern (Callback->NodeParsedPattern, tempString);
FreeText (tempString);
}
} else {
result = Object->ObjectLeaf != NULL;
}
}
if (result && Object->ObjectLeaf) {
if (Callback->LeafParsedPattern) {
result = TestParsedPattern (Callback->LeafParsedPattern, Object->ObjectLeaf);
if (!result &&
((Object->ObjectTypeId & (~PLATFORM_MASK)) == MIG_FILE_TYPE) &&
(_tcschr (Object->ObjectLeaf, TEXT('.')) == NULL)
) {
// let's try one more thing
tempString = JoinText (Object->ObjectLeaf, TEXT("."));
result = TestParsedPattern (Callback->LeafParsedPattern, tempString);
FreeText (tempString);
}
}
}
}
return result;
}
BOOL
pProcessCallbackReturnCode (
IN DWORD ReturnCode,
IN PMIG_TYPEOBJECTENUM Object,
IN OUT PCALLBACKDATA Callback
)
/*++
Routine Description:
This function encapsulates the logic for handling the return code of a
callback function. Callback functions have the capability to alter the
behavior of the enumeration with respect to themselves. This function takes
care of logging those change requests.
Arguments:
ReturnCode - Specifies a callback return code.
Object - Specifies the current object being enumerated.
Callback - Specifies the callback data structure responsible for the
return code. May be modified if a change is required by the
callback.
Return Value:
TRUE if the return code was successfully processed, FALSE otherwise.
--*/
{
PCALLBACK_ENUMFLAGS flags;
if (ReturnCode & CALLBACK_ERROR) {
//
// the callback function encountered some error, will never be called again
//
Callback->Error = TRUE;
DEBUGMSG ((DBG_ERROR, "A callback function returned an error while enumerating %s.", Object->ObjectName));
//
// NTRAID#NTBUG9-153257-2000/08/01-jimschm Add appropriate error handling here.
//
} else if (ReturnCode & CALLBACK_DONE_ENUMERATING) {
//
// the callback function is done enumerating, will never be called again
//
Callback->Done = TRUE;
} else if (ReturnCode != CALLBACK_ENUM_CONTINUE) {
//
// Save callback enumeration flags into the callback's private stack.
//
if (ReturnCode & CALLBACK_THIS_TREE_ONLY) {
flags = (PCALLBACK_ENUMFLAGS) GbGrow (&Callback->EnumFlags, sizeof(CALLBACK_ENUMFLAGS));
flags->Level = Object->Level;
flags->EnableLevel = Object->Level;
flags->Enabled = FALSE;
flags->Flags = CALLBACK_THIS_TREE_ONLY;
}
if (ReturnCode & CALLBACK_SKIP_NODES) {
flags = (PCALLBACK_ENUMFLAGS) GbGrow (&Callback->EnumFlags, sizeof(CALLBACK_ENUMFLAGS));
flags->Level = Object->IsLeaf?Object->Level+1:Object->Level;
flags->EnableLevel = Object->IsLeaf?Object->Level+1:Object->Level;
flags->Enabled = FALSE;
flags->Flags = CALLBACK_SKIP_NODES;
}
if (ReturnCode & CALLBACK_SKIP_TREE) {
flags = (PCALLBACK_ENUMFLAGS) GbGrow (&Callback->EnumFlags, sizeof(CALLBACK_ENUMFLAGS));
flags->Level = Object->Level + 1;
flags->EnableLevel = 0;
flags->Enabled = TRUE;
flags->Flags = CALLBACK_SKIP_TREE;
}
if (ReturnCode & CALLBACK_SKIP_LEAVES) {
flags = (PCALLBACK_ENUMFLAGS) GbGrow (&Callback->EnumFlags, sizeof(CALLBACK_ENUMFLAGS));
flags->Level = Object->Level + 1;
flags->EnableLevel = 0;
flags->Enabled = TRUE;
flags->Flags = CALLBACK_SKIP_LEAVES;
}
}
return TRUE;
}
BOOL
pDoSingleEnumeration (
IN PTYPEENUMINFO GlobalTypeEnumInfo,
IN PTYPEENUMINFO TypeEnumInfo,
IN PCTSTR ObjectPattern,
IN BOOL CallNormalCallbacks,
IN MIG_PROGRESSSLICEID SliceId OPTIONAL
)
/*++
Routine Description:
Given a type structure and a pattern, this function runs an enumeration
based on that pattern, calling all callbacks as needed in that enumeration.
Arguments:
GlobalTypeEnumInfo - Specifies the type data for the exclude list. This parameter
supplies the excluded pattern list.
TypeEnumInfo - Specifies the type data for the enumeration to be run. This
parameter supplies the queued pattern lists.
ObjectPattern - Specifies the pattern for the enumeration.
CallNormalCallbacks - Specifies TRUE for normal callbacks to be processed,
or FALSE for hook callbacks to be processed
SliceId - Specifies the progress bar slice ID, or 0 for no slice. If
specified, the slice ID will cause ticks to be generated for
each container at level 3.
Return Value:
TRUE if the enumeration was run successfully, FALSE otherwise.
--*/
{
MIG_TYPEOBJECTENUM eObjects;
GROWLIST funList = INIT_GROWLIST;
GROWLIST exclFunList = INIT_GROWLIST;
UINT i;
PCALLBACKDATA callbackData;
DWORD rc;
MIG_OBJECTENUMDATA publicData;
PTSTR leafPattern = NULL;
PTSTR nodePattern = NULL;
PPARSEDPATTERN nodeParsedPattern = NULL;
PPARSEDPATTERN explodedNodeParsedPattern = NULL;
PPARSEDPATTERN leafParsedPattern = NULL;
PPARSEDPATTERN explodedLeafParsedPattern = NULL;
PMIG_OBJECTENUMCALLBACK obEnumCallback;
PMIG_DYNAMICEXCLUSIONCALLBACK exclusionCallback;
UINT size;
BOOL stop;
BOOL b;
BOOL fSkip;
UINT fIndex;
BOOL result = TRUE;
static DWORD ticks;
static UINT objects;
BOOL extraExcludeCheck = FALSE;
MIG_APPINFO appInfo;
//
// Is entire pattern excluded?
//
ObsSplitObjectStringEx (ObjectPattern, &nodePattern, &leafPattern, NULL, FALSE);
if (nodePattern) {
if (pIsObjectNodeExcluded (
TypeEnumInfo->ObjectTypeId,
nodePattern,
&extraExcludeCheck
)) {
DEBUGMSG ((DBG_FLOW, "Pattern %s is completely excluded", ObjectPattern));
ObsFree (nodePattern);
return TRUE;
}
}
//
// Prepare parsed patterns for speed
//
if (nodePattern) {
nodeParsedPattern = CreateParsedPatternEx (g_CurrentQueuePool, nodePattern);
if (nodeParsedPattern) {
explodedNodeParsedPattern = ExplodeParsedPatternEx (g_CurrentQueuePool, nodeParsedPattern);
}
ObsFree (nodePattern);
INVALID_POINTER (nodePattern);
}
if (leafPattern) {
leafParsedPattern = CreateParsedPatternEx (g_CurrentQueuePool, leafPattern);
if (leafParsedPattern) {
explodedLeafParsedPattern = ExplodeParsedPatternEx (g_CurrentQueuePool, leafParsedPattern);
}
ObsFree (leafPattern);
INVALID_POINTER (leafPattern);
}
//
// Perform enumeration
//
if (EnumFirstObjectOfType (&eObjects, TypeEnumInfo->ObjectTypeId, ObjectPattern, NODE_LEVEL_MAX)) {
DEBUGMSG ((DBG_FLOW, "Enumerating objects of type %s with pattern %s.", TypeEnumInfo->TypeName, ObjectPattern));
//
// Get list of functions that want things from this particular enumeration.
//
pCreateFunctionListForPattern (
&funList,
TypeEnumInfo,
ObjectPattern,
explodedNodeParsedPattern,
explodedLeafParsedPattern,
CALLBACK_NORMAL
);
pCreateFunctionListForPattern (
&exclFunList,
GlobalTypeEnumInfo,
ObjectPattern,
explodedNodeParsedPattern,
explodedLeafParsedPattern,
CALLBACK_EXCLUSION
);
MYASSERT ((!CallNormalCallbacks) || GlGetSize (&funList));
do {
//
// Should enumeration of this object be skipped?
//
objects++;
LOG ((LOG_STATUS, (PCSTR) MSG_OBJECT_STATUS, objects, eObjects.NativeObjectName));
if (!eObjects.ObjectLeaf) {
// send our status to the app, but only for nodes to keep it fast
ZeroMemory (&appInfo, sizeof (MIG_APPINFO));
appInfo.Phase = g_CurrentPhase;
appInfo.SubPhase = 0;
appInfo.ObjectTypeId = (eObjects.ObjectTypeId & (~PLATFORM_MASK));
appInfo.ObjectName = eObjects.ObjectName;
IsmSendMessageToApp (ISMMESSAGE_APP_INFO, (ULONG_PTR) (&appInfo));
}
//
// Is this object at level 3? If so, tick the progress bar.
//
if (g_ProgressBarFn) {
if (SliceId && !eObjects.ObjectLeaf && eObjects.SubLevel <= 3) {
IsmTickProgressBar (SliceId, 1);
}
}
if (extraExcludeCheck && eObjects.ObjectNode) {
if (pIsObjectNodeExcluded (
TypeEnumInfo->ObjectTypeId,
eObjects.ObjectNode,
NULL
)) {
DEBUGMSG ((DBG_FLOW, "Node %s is completely excluded", ObjectPattern));
AbortCurrentNodeEnum (&eObjects);
continue;
}
}
if (pIsObjectExcluded (eObjects.ObjectTypeId, eObjects.ObjectName)) {
DEBUGMSG ((DBG_FLOW, "Object %s is excluded", eObjects.ObjectName));
//
// If leaf is empty, abort enum of this node
//
if (!eObjects.ObjectLeaf) {
AbortCurrentNodeEnum (&eObjects);
}
continue;
}
if (eObjects.ObjectLeaf) {
b = pIsObjectExcluded (
eObjects.ObjectTypeId,
ObsGetNodeLeafDivider (eObjects.ObjectName)
);
if (b) {
DEBUGMSG ((DBG_FLOW, "Leaf %s is excluded", eObjects.ObjectLeaf));
continue;
}
}
//
// Call all dynamic exclusion functions
//
stop = FALSE;
size = GlGetSize (&exclFunList);
for (i = 0; i < size ; i++) {
callbackData = (PCALLBACKDATA) GlGetItem (&exclFunList, i);
if (pShouldCallGatherCallback (&eObjects, callbackData)) {
//
// Call the callback function
//
MYASSERT (!g_CurrentGroup);
g_CurrentGroup = callbackData->Group;
exclusionCallback = (PMIG_DYNAMICEXCLUSIONCALLBACK) callbackData->Function;
stop = exclusionCallback (
eObjects.ObjectTypeId,
eObjects.ObjectName,
callbackData->CallbackArg
);
g_CurrentGroup = NULL;
if (stop) {
break;
}
}
}
if (stop) {
DEBUGMSG ((
DBG_FLOW,
"Object %s is dynamically excluded",
eObjects.ObjectName
));
continue;
}
//
// Check if the user wants to cancel. If yes, fail with an error.
//
if (IsmCheckCancel()) {
AbortObjectOfTypeEnum (&eObjects);
SetLastError (ERROR_CANCELLED);
result = FALSE;
break;
}
//
// Cycle through each of the list of functions looking for any that care about the current data.
//
size = GlGetSize (&funList);
g_EnumerationList.End = 0;
for (i = 0; i < size ; i++) {
callbackData = (PCALLBACKDATA) GlGetItem (&funList, i);
if (CallNormalCallbacks || (callbackData->CallbackType == CALLBACK_HOOK)) {
if (pShouldCallGatherCallback (&eObjects, callbackData)) {
fSkip = FALSE;
if (g_EnumerationList.End) {
fIndex = 0;
while (fIndex < g_EnumerationList.End) {
if (*((ULONG_PTR *)(g_EnumerationList.Buf + fIndex)) == (ULONG_PTR)callbackData->Function) {
fSkip = TRUE;
}
fIndex += sizeof (callbackData->Function);
if (*((ULONG_PTR *)(g_EnumerationList.Buf + fIndex)) != (ULONG_PTR)callbackData->CallbackArg) {
fSkip = FALSE;
}
fIndex += sizeof (callbackData->CallbackArg);
if (fSkip) {
break;
}
}
}
if (!fSkip) {
CopyMemory (
GbGrow (&g_EnumerationList, sizeof (callbackData->Function)),
&(callbackData->Function),
sizeof (callbackData->Function)
);
CopyMemory (
GbGrow (&g_EnumerationList, sizeof (callbackData->CallbackArg)),
&(callbackData->CallbackArg),
sizeof (callbackData->CallbackArg)
);
//
// Copy the enumeration info to the public structure
//
publicData.ObjectTypeId = TypeEnumInfo->ObjectTypeId;
publicData.ObjectName = eObjects.ObjectName;
publicData.NativeObjectName = eObjects.NativeObjectName;
publicData.ObjectNode = eObjects.ObjectNode;
publicData.ObjectLeaf = eObjects.ObjectLeaf;
publicData.Level = eObjects.Level;
publicData.SubLevel = eObjects.SubLevel;
publicData.IsLeaf = eObjects.IsLeaf;
publicData.IsNode = eObjects.IsNode;
publicData.Details.DetailsSize = eObjects.Details.DetailsSize;
publicData.Details.DetailsData = eObjects.Details.DetailsData;
//
// Call the callback function
//
MYASSERT (!g_CurrentGroup);
g_CurrentGroup = callbackData->Group;
obEnumCallback = (PMIG_OBJECTENUMCALLBACK) callbackData->Function;
rc = obEnumCallback (&publicData, callbackData->CallbackArg);
g_CurrentGroup = NULL;
if (rc != CALLBACK_ENUM_CONTINUE) {
//
// Callback wants to make some sort of modification to its enumeration.
//
pProcessCallbackReturnCode (rc, &eObjects, callbackData);
}
}
}
}
}
} while (EnumNextObjectOfType (&eObjects));
//
// Clean up function list.
//
pDestroyFunctionListForPattern (&funList);
pDestroyFunctionListForPattern (&exclFunList);
}
ELSE_DEBUGMSG ((DBG_FLOW, "No objects found matching enumeration pattern %s.", ObjectPattern));
DestroyParsedPattern (explodedLeafParsedPattern);
DestroyParsedPattern (leafParsedPattern);
DestroyParsedPattern (explodedNodeParsedPattern);
DestroyParsedPattern (nodeParsedPattern);
return result;
}
VOID
pCreatePhysicalTypeCallbackList (
IN MIG_OBJECTTYPEID ObjectTypeId,
IN MIG_OBJECTSTRINGHANDLE ObjectName,
IN CALLBACK_TYPE CallbackType,
IN OUT PGROWLIST List
)
{
PTYPEENUMINFO typeEnumInfo;
PCTSTR node;
PCTSTR leaf;
PCALLBACKDATA callbackData;
BOOL callFn;
//
// Test object against all patterns of the type
//
typeEnumInfo = pGetTypeEnumInfo (ObjectTypeId & (~PLATFORM_MASK), TRUE);
if (!typeEnumInfo) {
return;
}
ObsSplitObjectStringEx (ObjectName, &node, &leaf, NULL, TRUE);
if (!node && !leaf) {
return;
}
switch (CallbackType) {
case CALLBACK_PHYSICAL_ENUM:
callbackData = typeEnumInfo->PhysicalEnumList;
break;
case CALLBACK_PHYSICAL_ACQUIRE:
callbackData = typeEnumInfo->PhysicalAcquireList;
break;
default:
MYASSERT (FALSE);
return;
}
while (callbackData) {
MYASSERT (callbackData->NodeParsedPattern);
if (!node || TestParsedPattern (callbackData->NodeParsedPattern, node)) {
if (callbackData->LeafParsedPattern && leaf) {
callFn = TestParsedPattern (callbackData->LeafParsedPattern, leaf);
} else if (leaf && !callbackData->LeafParsedPattern) {
callFn = FALSE;
} else {
callFn = TRUE;
}
if (callFn) {
GlAppend (List, (PBYTE) callbackData, sizeof (CALLBACKDATA));
}
}
callbackData = callbackData->Next;
}
ObsFree (node);
ObsFree (leaf);
}
BOOL
ExecutePhysicalAcquireCallbacks (
IN MIG_OBJECTTYPEID ObjectTypeId,
IN MIG_OBJECTSTRINGHANDLE ObjectName,
IN PMIG_CONTENT Content, OPTIONAL
IN MIG_CONTENTTYPE ContentType,
IN UINT MemoryContentLimit,
OUT PMIG_CONTENT *NewContent
)
{
UINT count;
UINT u;
PCALLBACKDATA callbackData;
PMIG_PHYSICALACQUIREFREE acquireFree = NULL;
PMIG_PHYSICALACQUIREHOOK acquireHook;
PMIG_CONTENT updatedContent;
BOOL result = TRUE;
PMIG_CONTENT currentContent;
pCreatePhysicalTypeCallbackList (
ObjectTypeId,
ObjectName,
CALLBACK_PHYSICAL_ACQUIRE,
&g_AcquireList
);
count = GlGetSize (&g_AcquireList);
currentContent = Content;
for (u = 0 ; u < count ; u++) {
//
// Call this function
//
callbackData = (PCALLBACKDATA) GlGetItem (&g_AcquireList, u);
acquireHook = (PMIG_PHYSICALACQUIREHOOK) callbackData->Function;
if (acquireHook) {
updatedContent = NULL;
if (!acquireHook (
ObjectName,
currentContent,
ContentType,
MemoryContentLimit,
&updatedContent,
FALSE,
callbackData->CallbackArg
)) {
//
// Hook says "don't acquire"
//
result = FALSE;
}
if (!result || updatedContent) {
if (currentContent != Content) {
//
// Free previous hook content change
//
if (acquireFree) {
acquireFree (currentContent);
acquireFree = NULL;
}
currentContent = NULL;
}
if (updatedContent) {
//
// Hook provided replacement content
//
currentContent = updatedContent;
acquireFree = (PMIG_PHYSICALACQUIREFREE) callbackData->Function2;
} else {
break; // don't acquire -- we can stop now
}
}
}
}
if (currentContent && acquireFree) {
currentContent->IsmHandle = acquireFree;
}
*NewContent = currentContent != Content ? currentContent : NULL;
GlReset (&g_AcquireList);
return result;
}
BOOL
FreeViaAcquirePhysicalCallback (
IN PMIG_CONTENT Content
)
{
PMIG_PHYSICALACQUIREFREE acquireFree;
if (!Content->IsmHandle) {
return FALSE;
}
acquireFree = (PMIG_PHYSICALACQUIREFREE) Content->IsmHandle;
if (acquireFree) {
acquireFree (Content);
}
return TRUE;
}
BOOL
ExecutePhysicalEnumCheckCallbacks (
IN PMIG_TYPEOBJECTENUM ObjectEnum
)
{
UINT count;
UINT u;
PCALLBACKDATA callbackData;
PMIG_PHYSICALENUMCHECK enumCheck;
BOOL result = TRUE;
pCreatePhysicalTypeCallbackList (
ObjectEnum->ObjectTypeId,
ObjectEnum->ObjectName,
CALLBACK_PHYSICAL_ENUM,
&g_EnumList
);
count = GlGetSize (&g_EnumList);
for (u = 0 ; u < count ; u++) {
//
// Call this function
//
callbackData = (PCALLBACKDATA) GlGetItem (&g_EnumList, u);
enumCheck = (PMIG_PHYSICALENUMCHECK) callbackData->Function;
if (enumCheck) {
if (!enumCheck (ObjectEnum, callbackData->CallbackArg)) {
//
// Hook says "skip"
//
result = FALSE;
break;
}
} else {
//
// No callback means "skip"
//
result = FALSE;
break;
}
}
GlReset (&g_EnumList);
return result;
}
BOOL
ExecutePhysicalEnumAddCallbacks (
IN OUT PMIG_TYPEOBJECTENUM ObjectEnum,
IN MIG_OBJECTSTRINGHANDLE Pattern,
IN MIG_PARSEDPATTERN ParsedPattern,
IN OUT PUINT CurrentCallback
)
{
BOOL result = FALSE;
BOOL done;
PENUMADDCALLBACK callback;
MIG_OBJECTTYPEID objectTypeId;
objectTypeId = ObjectEnum->ObjectTypeId & ~(PLATFORM_MASK);
do {
done = TRUE;
if (GlGetSize (&g_EnumAddList) > *CurrentCallback) {
callback = (PENUMADDCALLBACK) GlGetItem (&g_EnumAddList, *CurrentCallback);
MYASSERT (callback);
MYASSERT (callback->AddCallback);
if (callback->ObjectTypeId != objectTypeId) {
result = FALSE;
} else {
result = callback->AddCallback (ObjectEnum, Pattern, ParsedPattern, callback->AddCallbackArg, FALSE);
}
if (!result) {
*CurrentCallback += 1;
done = FALSE;
}
}
} while (!done);
return result;
}
VOID
AbortPhysicalEnumCallback (
IN PMIG_TYPEOBJECTENUM ObjectEnum, ZEROED
IN UINT CurrentCallback
)
{
PENUMADDCALLBACK callback;
if (GlGetSize (&g_EnumAddList) > CurrentCallback) {
callback = (PENUMADDCALLBACK) GlGetItem (&g_EnumAddList, CurrentCallback);
MYASSERT (callback);
MYASSERT (callback->AddCallback);
callback->AddCallback (ObjectEnum, NULL, NULL, callback->AddCallbackArg, TRUE);
}
ZeroMemory (ObjectEnum, sizeof (MIG_TYPEOBJECTENUM));
}
UINT
pEstimateSingleEnumerationTicks (
IN PTYPEENUMINFO TypeEnumInfo,
IN PCTSTR ObjectPattern
)
/*++
Routine Description:
Given a type structure and a pattern, this function runs an enumeration
based on that pattern, counting all the containers 3 levels deep. This
is a quick approximation of how much work there is to do.
Arguments:
TypeEnumInfo - Specifies the type data for the enumeration to be run.
ObjectPattern - Specifies the pattern for the enumeration.
Return Value:
The number of containers exactly 3 levels deep in the object pattern.
--*/
{
MIG_TYPEOBJECTENUM eObjects;
PTSTR nodePattern = NULL;
UINT ticks = 0;
MIG_OBJECTSTRINGHANDLE nodeOnlyPattern;
ObsSplitObjectStringEx (ObjectPattern, &nodePattern, NULL, NULL, FALSE);
if (nodePattern) {
nodeOnlyPattern = ObsBuildEncodedObjectStringEx (nodePattern, NULL, FALSE);
ObsFree (nodePattern);
INVALID_POINTER (nodePattern);
} else {
return 0;
}
if (EnumFirstObjectOfType (&eObjects, TypeEnumInfo->ObjectTypeId, nodeOnlyPattern, 3)) {
DEBUGMSG ((DBG_FLOW, "Estimating number of objects of type %s with pattern %s.", TypeEnumInfo->TypeName, nodeOnlyPattern));
do {
if (eObjects.SubLevel <= 3) {
ticks++;
}
} while (EnumNextObjectOfType (&eObjects));
}
ELSE_DEBUGMSG ((DBG_FLOW, "No objects found matching enumeration pattern %s.", nodeOnlyPattern));
ObsFree (nodeOnlyPattern);
return ticks;
}
BOOL
pCallNonEnumeratedCallbacks (
IN PCALLBACKDATA FunctionList
)
/*++
Routine Description:
This function simply takes the provided list of CALLBACKDATA and for each
function, calls it as a non-enumerated callback.
Arguments:
FunctionList - Specifies the list of functions to call.
Return Value:
TRUE if all functions were called successfully. FALSE otherwise.
--*/
{
PCALLBACKDATA cur;
BOOL rc;
cur = FunctionList;
while (cur) {
MYASSERT (!g_CurrentGroup);
g_CurrentGroup = cur->Group;
rc = ((PNONENUMERATEDCALLBACK) cur->Function) ();
if (!rc) {
DEBUGMSG ((
DBG_FLOW,
"Group %s returned an error while calling its NonEnumerated Callback with id %s.",
g_CurrentGroup,
cur->Identifier ? cur->Identifier : TEXT("<Unidentified Function>")
));
}
g_CurrentGroup = NULL;
cur = cur->Next;
}
return TRUE;
}
UINT
EstimateAllObjectEnumerations (
MIG_PROGRESSSLICEID SliceId,
BOOL PreEstimate
)
/*++
Routine Description:
EstimateAllObjectEnumerations computes a tick estimate for all enumerations
that have been requested by Data Gather Modules (by calling
IsmQueueEnumeration).
The function loops through all known types and for each needed enumeration
of that type, then calls down to a worker function to call to perform the
actual enumeration.
Arguments:
None.
Return Value:
TRUE if enumerations were completed successfully. FALSE otherwise.
--*/
{
PTYPEENUMINFO typeEnumInfo;
MIG_OBJECTTYPEID typeId;
PENUMDATA enumData;
UINT ticks = 0;
if (g_CurrentGroup) {
DEBUGMSG ((DBG_ERROR, "EstimateAllObjectEnumerations cannot be called during another callback"));
return 0;
}
if (!g_ProgressBarFn) {
//
// No need to estimate; no progress bar callback
//
return 0;
}
//
// Initialize type data with all known types. Note that we require
// the type manager to have been initialized before we are.
//
typeId = IsmGetFirstObjectTypeId ();
if (!typeId) {
DEBUGMSG ((DBG_ERROR, "EstimateAllObjectEnumerations: No known types to enumerate"));
return 0;
}
do {
if (g_IsmModulePlatformContext == PLATFORM_CURRENT) {
typeId |= g_IsmCurrentPlatform;
} else {
typeId |= g_IsmModulePlatformContext;
}
typeEnumInfo = pGetTypeEnumInfo (typeId, FALSE);
//
// For each enumeration of this type, call the enumeration worker function
//
enumData = typeEnumInfo->FirstEnum;
while (enumData) {
if (PreEstimate) {
ticks ++;
} else {
ticks += pEstimateSingleEnumerationTicks (typeEnumInfo, enumData->Pattern);
}
if (SliceId) {
IsmTickProgressBar (SliceId, 1);
}
enumData = enumData->Next;
}
typeId &= ~(PLATFORM_MASK);
typeId = IsmGetNextObjectTypeId (typeId);
} while (typeId != 0);
return ticks;
}
BOOL
DoAllObjectEnumerations (
IN MIG_PROGRESSSLICEID SliceId
)
/*++
Routine Description:
DoAllObjectEnumerations is responsible for processing all enumerations that
have been requested by Data Gather Modules (by calling
IsmQueueEnumeration).
The function:
(1) Calls Pre EnumerationFunctions
(2) Loops through all known types and for each needed enumeration of that type,
calls down to a worker function to call to perform the actual enumeration.
(3) Calls Post Enumeration Functions
Arguments:
None.
Return Value:
TRUE if enumerations were completed successfully. FALSE otherwise.
--*/
{
PTYPEENUMINFO globalTypeEnumInfo;
PTYPEENUMINFO typeEnumInfo;
MIG_OBJECTTYPEID typeId;
PENUMDATA enumData;
BOOL result = TRUE;
if (g_CurrentGroup) {
DEBUGMSG ((DBG_ERROR, "DoAllObjectEnumerations cannot be called during another callback"));
return FALSE;
}
//
// Call any Pre-ObjectEnumeration functions.
//
pCallNonEnumeratedCallbacks (g_PreEnumerationFunctionList);
//
// Initialize type data with all known types. Note that we require
// type type manager to have been initialized before we are.
//
typeId = IsmGetFirstObjectTypeId ();
if (!typeId) {
DEBUGMSG ((DBG_ERROR, "DoAllObjectEnumerations: No known types to enumerate"));
return FALSE;
}
do {
if (g_IsmModulePlatformContext == PLATFORM_CURRENT) {
typeId |= g_IsmCurrentPlatform;
} else {
typeId |= g_IsmModulePlatformContext;
}
globalTypeEnumInfo = pGetTypeEnumInfo (typeId, TRUE);
typeEnumInfo = pGetTypeEnumInfo (typeId, FALSE);
pCallNonEnumeratedCallbacks (typeEnumInfo->PreEnumerationFunctionList);
//
// For each enumeration of this type, call the enumeration worker function
//
enumData = typeEnumInfo->FirstEnum;
while (enumData && result) {
result = pDoSingleEnumeration (
globalTypeEnumInfo,
typeEnumInfo,
enumData->Pattern,
TRUE,
SliceId
);
enumData = enumData->Next;
}
if (result) {
result = pCallNonEnumeratedCallbacks (typeEnumInfo->PostEnumerationFunctionList);
}
typeId &= ~(PLATFORM_MASK);
typeId = IsmGetNextObjectTypeId (typeId);
} while ((typeId != 0) && result);
//
// Call any Post-ObjectEnumeration functions.
//
if (result) {
result = pCallNonEnumeratedCallbacks (g_PostEnumerationFunctionList);
}
return result;
}
VOID
IsmExecuteHooks (
IN MIG_OBJECTTYPEID ObjectTypeId,
IN MIG_OBJECTSTRINGHANDLE ObjectName
)
{
PTYPEENUMINFO globalTypeEnumInfo;
PTYPEENUMINFO typeEnumInfo;
PENUMDATA enumData;
PCTSTR oldCurrentGroup;
PCTSTR node = NULL;
PCTSTR leaf = NULL;
PCTSTR tempString;
BOOL result;
ObjectTypeId = FixEnumerationObjectTypeId (ObjectTypeId);
globalTypeEnumInfo = pGetTypeEnumInfo (ObjectTypeId, TRUE);
typeEnumInfo = pGetTypeEnumInfo (ObjectTypeId, FALSE);
if (!globalTypeEnumInfo || !typeEnumInfo) {
SetLastError (ERROR_INVALID_PARAMETER);
return;
}
enumData = typeEnumInfo->FirstEnum;
if (!ObsSplitObjectStringEx (ObjectName, &node, &leaf, NULL, TRUE)) {
DEBUGMSG ((DBG_ERROR, "Bad encoded object detected in IsmExecuteHooks: %s", ObjectName));
return;
}
while (enumData) {
result = TestParsedPattern (enumData->NodeParsedPattern, node);
if (!result) {
//
// let's try one more time with a wack at the end
//
tempString = JoinText (node, TEXT("\\"));
result = TestParsedPattern (enumData->NodeParsedPattern, tempString);
FreeText (tempString);
}
if (result && leaf) {
if (!enumData->LeafParsedPattern) {
result = FALSE;
} else {
result = TestParsedPattern (enumData->LeafParsedPattern, leaf);
if (!result &&
((ObjectTypeId & (~PLATFORM_MASK)) == MIG_FILE_TYPE) &&
(_tcschr (leaf, TEXT('.')) == NULL)
) {
// let's try one more thing
tempString = JoinText (leaf, TEXT("."));
result = TestParsedPattern (enumData->LeafParsedPattern, tempString);
FreeText (tempString);
}
}
}
if (result) {
DEBUGMSG ((DBG_FLOW, "IsmExecuteHooks request for an object that was or will be enumerated: %s", ObjectName));
break;
}
enumData = enumData->Next;
}
ObsFree (node);
ObsFree (leaf);
oldCurrentGroup = g_CurrentGroup;
g_CurrentGroup = NULL;
pDoSingleEnumeration (globalTypeEnumInfo, typeEnumInfo, ObjectName, FALSE, 0);
g_CurrentGroup = oldCurrentGroup;
SetLastError (ERROR_SUCCESS);
}
BOOL
InitializeFlowControl (
VOID
)
/*++
Routine Description:
InitializeFlowControl is called to ready the flow control unit for work.
This function takes care of initialization of basic resources needed by the
flow control unit.
Flow control is dependent upon the type manager module and can only be
initialized after type manager intialization is completed.
Arguments:
None.
Return Value:
TRUE if flow control was able to successfully initialize, FALSE otherwise.
--*/
{
g_GlobalQueuePool = PmCreateNamedPool ("Global Queue Pool");
g_UntrackedFlowPool = PmCreatePool();
PmDisableTracking (g_UntrackedFlowPool);
g_CurrentQueuePool = PmCreateNamedPoolEx ("Current Queue Pool", 32768);
return TRUE;
}
VOID
pAddTypeToEnumerationEnvironment (
IN PMHANDLE Pool,
IN PGROWLIST *TypeData,
IN MIG_OBJECTTYPEID TypeId
)
{
TYPEENUMINFO data;
ZeroMemory (&data, sizeof (TYPEENUMINFO));
data.ObjectTypeId = TypeId | g_IsmModulePlatformContext;
data.TypeName = PmDuplicateString (Pool, GetObjectTypeName (TypeId));
GlAppend (*TypeData, (PBYTE) &data, sizeof (TYPEENUMINFO));
}
VOID
AddTypeToGlobalEnumerationEnvironment (
IN MIG_OBJECTTYPEID TypeId
)
{
pAddTypeToEnumerationEnvironment (g_GlobalQueuePool, &g_GlobalTypeData, TypeId);
}
BOOL
PrepareEnumerationEnvironment (
BOOL GlobalEnv
)
{
MIG_OBJECTTYPEID typeId;
PGROWLIST *typeData;
PMHANDLE pool;
if (GlobalEnv) {
typeData = &g_GlobalTypeData;
pool = g_GlobalQueuePool;
} else {
typeData = &g_TypeData;
pool = g_CurrentQueuePool;
}
*typeData = (PGROWLIST) PmGetMemory (pool, sizeof (GROWLIST));
ZeroMemory (*typeData, sizeof (GROWLIST));
//
// Initialize type data with all known types. For global types, we expect
// this list to be empty.
//
typeId = IsmGetFirstObjectTypeId ();
while (typeId) {
pAddTypeToEnumerationEnvironment (pool, typeData, typeId);
typeId = IsmGetNextObjectTypeId (typeId);
}
return TRUE;
}
BOOL
ClearEnumerationEnvironment (
IN BOOL GlobalData
)
{
PGROWLIST *typeData;
if (GlobalData) {
typeData = &g_GlobalTypeData;
} else {
typeData = &g_TypeData;
}
if (*typeData) {
//
// Clean up the grow lists, but forget about the rest because
// it all was allocated from the queue pool
//
GlFree (*typeData);
*typeData = NULL;
}
g_PreEnumerationFunctionList = NULL;
g_PostEnumerationFunctionList = NULL;
if (GlobalData) {
PmEmptyPool (g_GlobalQueuePool);
} else {
PmEmptyPool (g_CurrentQueuePool);
}
return TRUE;
}
VOID
TerminateFlowControl (
VOID
)
/*++
Routine Description:
TerminateFlowControl should be called when flow control services are no
longer needed. This function ensures that flow control resources are freed.
Arguments:
None.
Return Value:
None.
--*/
{
GbFree (&g_EnumerationList);
PmEmptyPool (g_CurrentQueuePool);
PmDestroyPool (g_CurrentQueuePool);
g_CurrentQueuePool = NULL;
PmEmptyPool (g_GlobalQueuePool);
PmDestroyPool (g_GlobalQueuePool);
g_GlobalQueuePool = NULL;
PmEmptyPool (g_UntrackedFlowPool);
PmDestroyPool (g_UntrackedFlowPool);
g_UntrackedFlowPool = NULL;
GlFree (&g_AcquireList);
GlFree (&g_EnumList);
GlFree (&g_EnumAddList);
}