/*++ 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("") )); } 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); }