test: cmnotify.c File Reference

Main Page | Class Hierarchy | Class List | File List | Class Members | File Members

# cmnotify.c File Reference

`#include "cmp.h"`

Go to the source code of this file.

## Defines

#define | CmpCheckPostBlock(a)

## Functions

VOID | CmpReportNotifyHelper (PCM_KEY_CONTROL_BLOCK KeyControlBlock, IN PHHIVE SearchHive, IN PHHIVE Hive, IN PCM_KEY_NODE Node, IN ULONG Filter)
VOID | CmpCancelSlavePost (PCM_POST_BLOCK PostBlock, PLIST_ENTRY DelayedDeref)
VOID | CmpFreeSlavePost (PCM_POST_BLOCK MasterPostBlock)
VOID | CmpAddToDelayedDeref (PCM_POST_BLOCK PostBlock, PLIST_ENTRY DelayedDeref)
VOID | CmpDelayedDerefKeys (PLIST_ENTRY DelayedDeref)
BOOLEAN | CmpNotifyTriggerCheck (IN PCM_NOTIFY_BLOCK NotifyBlock, IN PHHIVE Hive, IN PCM_KEY_NODE Node)
VOID | CmpDummyApc (struct _KAPC *Apc, PVOID *SystemArgument1, PVOID *SystemArgument2)
VOID | CmpReportNotify (PCM_KEY_CONTROL_BLOCK KeyControlBlock, PHHIVE Hive, HCELL_INDEX Cell, ULONG Filter)
VOID | CmpPostNotify (PCM_NOTIFY_BLOCK NotifyBlock, PUNICODE_STRING Name OPTIONAL, ULONG Filter, NTSTATUS Status, PLIST_ENTRY ExternalKeyDeref OPTIONAL)
VOID | CmpPostApc (struct _KAPC *Apc, PKNORMAL_ROUTINE *NormalRoutine, PVOID *NormalContext, PVOID *SystemArgument1, PVOID *SystemArgument2)
VOID | CmpPostApcRunDown (struct _KAPC *Apc)
VOID | CmNotifyRunDown (PETHREAD Thread)
VOID | CmpFlushNotify (PCM_KEY_BODY KeyBody)
NTSTATUS | CmpNotifyChangeKey (IN PCM_KEY_BODY KeyBody, IN PCM_POST_BLOCK PostBlock, IN ULONG CompletionFilter, IN BOOLEAN WatchTree, IN PVOID Buffer, IN ULONG BufferSize, IN PCM_POST_BLOCK MasterPostBlock)

## Variables

PCMHIVE | CmpMasterHive

## Define Documentation

#define CmpCheckPostBlock | ( | a |  | ) |

| Definition at line 85 of file cmnotify.c. Referenced by CmpPostApc().

## Function Documentation

VOID CmNotifyRunDown | ( | PETHREAD | Thread | ) |

Definition at line 1028 of file cmnotify.c.

References _CM_ASYNC_USER_POST_BLOCK::Apc, APC_LEVEL, _CM_POST_BLOCK_UNION::AsyncUser, _CM_POST_BLOCK::CancelPostList, CML_API, CMLOG, CmpCancelSlavePost(), CmpClearListEntry, CmpFreePostBlock(), CmpFreeSlavePost(), CmpLockRegistryExclusive(), CmpRemoveEntryList, CmpSetIoStatus, CmpUnlockRegistry(), CMS_EXCEPTION, CMS_NTAPI, EXCEPTION_EXECUTE_HANDLER, FALSE, _CM_ASYNC_USER_POST_BLOCK::IoStatusBlock, IsMasterPostBlock, KeLowerIrql(), KeRaiseIrql(), KeRemoveQueueApc(), KeSetEvent(), L, _CM_POST_BLOCK::NotifyList, NULL, ObDereferenceObject, PAGED_CODE, PostAsyncUser, _ETHREAD::PostBlockList, PostBlockType, PsGetCurrentProcess, _CM_POST_BLOCK::ThreadList, TRUE, _CM_POST_BLOCK::u, and _CM_ASYNC_USER_POST_BLOCK::UserEvent.

Referenced by PspExitThread().

    01033                    :
    01034
    01035     This routine is called from PspExitThread to clean up any pending
    01036     notify requests.
    01037
    01038     It will traverse the thread's PostBlockList, for each PostBlock it
    01039     finds, it will:
    01040
    01041         1.  Remove it from the relevent NotifyBlock.  This requires
    01042             that we hold the Registry mutex.
    01043
    01044         2.  Remove it from the thread's PostBlockList.  This requires
    01045             that we run at APC level.
    01046
    01047         3.  By the time this procedure runs, user apcs are not interesting
    01048             and neither are SystemEvents, so do not bother processing
    01049             them.
    01050
    01051             UserEvents and IoStatusBlocks could be refered to by other
    01052             threads in the same process, or even a different process,
    01053             so process them so those threads know what happened, use
    01054             status code of STATUS_NOTIFY_CLEANUP.
    01055
    01056             If the notify is a master one, cancel all slave notifications.
    01057             Else only remove this notification from the master CancelPortList
    01058
    01059         4.  Free the post block.
    01060
    01061 Arguments:
    01062
    01063     Thread - pointer to the executive thread object for the thread
    01064              we wish to do rundown on.
    01065
    01066 Return Value:
    01067
    01068     NONE.
    01069
    01070 --*/
    01071 {
    01072     PCM_POST_BLOCK      PostBlock;
    01073     PCM_NOTIFY_BLOCK    NotifyBlock;
    01074     KIRQL               OldIrql;
    01075
    01076     PAGED_CODE();
    01077
    01078     if ( IsListEmpty(&(Thread->PostBlockList)) == TRUE ) {
    01079         return;
    01080     }
    01081
    01082     CMLOG(CML_API, CMS_NTAPI) {
    01083         KdPrint(("CmNotifyRunDown: ethread:%08lx\n", Thread));
    01084     }
    01085
    01086     CmpLockRegistryExclusive();
    01087
    01088         //
    01089     // Aquire exclusive access over the postlist(s)
    01090     //
    01091     // This is not needed (see the rule above)
    01092     //LOCK_POST_LIST();
    01093
    01094     KeRaiseIrql(APC_LEVEL, &OldIrql);
    01095     while (IsListEmpty(&(Thread->PostBlockList)) == FALSE) {
    01096
    01097         //
    01098         // remove from thread list
    01099         //
    01100         PostBlock = (PCM_POST_BLOCK)RemoveHeadList(&(Thread->PostBlockList));
    01101         PostBlock = CONTAINING_RECORD(
    01102                         PostBlock,
    01103                         CM_POST_BLOCK,
    01104                         ThreadList
    01105                         );
    01106
    01107         // Protect for multiple deletion of the same object
    01108         CmpClearListEntry(&(PostBlock->ThreadList));
    01109
    01110         CMLOG(CML_API, CMS_NTAPI) {
    01111 #if DBG
    01112             if(PostBlock->TraceIntoDebugger) {
    01113                 KdPrint(("[CM]CmpNotifyRunDown: ethread:%08lx, PostBlock:%08lx\n", Thread,PostBlock));
    01114             }
    01115 #endif
    01116         }
    01117
    01118         //
    01119         // Canceling a master notification implies canceling all the slave notifications
    01120         // from the CancelPostList
    01121         //
    01122         if(IsMasterPostBlock(PostBlock)) {
    01123             CMLOG(CML_API, CMS_NTAPI) {
    01124 #if DBG
    01125                 if(PostBlock->TraceIntoDebugger) {
    01126                         KdPrint(("[CM]\tCmpNotifyRunDown: PostBlock:%08lx is a master block\n", PostBlock));
    01127                 }
    01128 #endif
    01129             }
    01130             //
    01131             // at this point, CmpReportNotify and friends will no longer
    01132             // attempt to post this post block.
    01133             //
    01134             if (PostBlockType(PostBlock) == PostAsyncUser) {
    01135                 //
    01136                 // report status and wake up any threads that might otherwise
    01137                 // be stuck.  also drop any event references we hold
    01138                 //
    01139                 //  Sundown only: Use a 32bit IO_STATUS_BLOCK if the caller is 32bit.
    01140
    01141                 try {
    01142                     CmpSetIoStatus(PostBlock->u->AsyncUser.IoStatusBlock,
    01143                                    STATUS_NOTIFY_CLEANUP,
    01144                                    0L,
    01145                                    PsGetCurrentProcess()->Wow64Process != NULL);
    01146                 } except (EXCEPTION_EXECUTE_HANDLER) {
    01147                     CMLOG(CML_API, CMS_EXCEPTION) {
    01148                         KdPrint(("!!CmNotifyRundown: code:%08lx\n", GetExceptionCode()));
    01149                     }
    01150                     NOTHING;
    01151                 }
    01152
    01153                 if (PostBlock->u->AsyncUser.UserEvent != NULL) {
    01154                     KeSetEvent(
    01155                         PostBlock->u->AsyncUser.UserEvent,
    01156                         0,
    01157                         FALSE
    01158                         );
    01159                     ObDereferenceObject(PostBlock->u->AsyncUser.UserEvent);
    01160                 }
    01161
    01162                 //
    01163                 // Cancel the APC. Otherwise the rundown routine will also
    01164                 // free the post block if the APC happens to be queued at
    01165                 // this point. If the APC is queued, then the post block has
    01166                 // already been removed from the notify list, so don't remove
    01167                 // it again.
    01168                 //
    01169                 if (!KeRemoveQueueApc(PostBlock->u->AsyncUser.Apc)) {
    01170
    01171                     //
    01172                     // remove from notify block's list
    01173                     //
    01174                     // Use Cmp variant to protect for multiple deletion of the same object
    01175                     CmpRemoveEntryList(&(PostBlock->NotifyList));
    01176                 }
    01177             } else {
    01178                 //
    01179                 // remove from notify block's list
    01180                 //
    01181                 // Use Cmp variant to protect for multiple deletion of the same object
    01182                 CmpRemoveEntryList(&(PostBlock->NotifyList));
    01183             }
    01184
    01185             //
    01186             // Cancel all slave Post requests that may be linked to self
    01187             //
    01188             CmpCancelSlavePost(PostBlock,NULL); // we do not want delayed deref
    01189                         //
    01190                         // Free the slave Post blocks too
    01191                         //
    01192                         CmpFreeSlavePost(PostBlock);
    01193         } else {
    01194
    01195             CMLOG(CML_API, CMS_NTAPI) {
    01196 #if DBG
    01197                 if(PostBlock->TraceIntoDebugger) {
    01198                     KdPrint(("[CM]\tCmpNotifyRunDown: PostBlock:%08lx is a slave block\n", PostBlock));
    01199                 }
    01200 #endif
    01201             }
    01202             //
    01203             // Is a slave PostBlock, just remove self from the Notify PostList
    01204             //
    01205             // Use Cmp variant to protect for multiple deletion of the same object
    01206             CmpRemoveEntryList(&(PostBlock->NotifyList));
    01207
    01208             //
    01209             // and unchain from the Master CancelPostList
    01210             //
    01211             // Use Cmp variant to protect for multiple deletion of the same object
    01212             CmpRemoveEntryList(&(PostBlock->CancelPostList));
    01213
    01214         }
    01215
    01216         //
    01217         // Free the post block.  Use Ex call because PostBlocks are NOT
    01218         // part of the global registry pool computation, but are instead
    01219         // part of NonPagedPool with Quota.
    01220         //
    01221         CmpFreePostBlock(PostBlock);
    01222     }
    01223
    01224     KeLowerIrql(OldIrql);
    01225
    01226     // This is not needed (see the rule above)
    01227     //UNLOCK_POST_LIST();
    01228
    01229     CmpUnlockRegistry();
    01230     return;
    01231 }

VOID CmpAddToDelayedDeref | ( | PCM_POST_BLOCK | PostBlock,
|  | PLIST_ENTRY | DelayedDeref
| ) |

Definition at line 1845 of file cmnotify.c.

References ASSERT, _CM_POST_KEY_BODY::KeyBody, _CM_POST_KEY_BODY::KeyBodyList, NULL, PAGED_CODE, and _CM_POST_BLOCK::PostKeyBody.

Referenced by CmpCancelSlavePost(), and CmpPostNotify().

    01851                    :
    01852
    01853     Add the key body attached to the post block to the delayed deref list.
    01854     Cleans the post block KeyBody member, so it will not be dereferenced
    01855     when the post block is freed.
    01856
    01857 Arguments:
    01858
    01859     PostBlock - pointer to structure that describes the post requests.
    01860
    01861     DelayedDeref - the delayed deref list
    01862
    01863 Return Value:
    01864
    01865     NONE.
    01866
    01867 --*/
    01868
    01869 {
    01870     PAGED_CODE();
    01871
    01872     // common sense
    01873     ASSERT( PostBlock != NULL );
    01874
    01875     if( PostBlock->PostKeyBody ) {
    01876         //
    01877         // If the post block has a keybody attached, add it to delayed deref list and
    01878         // clear the post block member. The key body will be deref'd prior after
    01879         // postblock lock is released.
    01880         //
    01881
    01882         // extra validation
    01883         ASSERT(PostBlock->PostKeyBody->KeyBody != NULL);
    01884         ASSERT(DelayedDeref);
    01885
    01886         // add it to the end of the list
    01887         InsertTailList(
    01888             DelayedDeref,
    01889             &(PostBlock->PostKeyBody->KeyBodyList)
    01890             );
    01891
    01892         // make sure we don't deref it in CmpFreePostBlock
    01893         PostBlock->PostKeyBody = NULL;
    01894     }
    01895
    01896     return;
    01897 }

VOID CmpCancelSlavePost | ( | PCM_POST_BLOCK | PostBlock,
|  | PLIST_ENTRY | DelayedDeref
| ) |

Definition at line 1738 of file cmnotify.c.

References ASSERT, ASSERT_CM_LOCK_OWNED, _CM_POST_BLOCK::CancelPostList, CML_MAJOR, CMLOG, CmpAddToDelayedDeref(), CmpRemoveEntryList, CMS_NOTIFY, IsMasterPostBlock, _CM_POST_BLOCK::NotifyList, PAGED_CODE, and TRUE.

Referenced by CmNotifyRunDown(), and CmpPostNotify().

    01744                    :
    01745
    01746         Unlink the slave postblock from its notify list and dereferences (or adds to the delayed deref list)
    01747         the keybody related to this thread. This should disable the slave post block.
    01748         It will be cleared later in CmpPostApc.
    01749
    01750 Arguments:
    01751
    01752     MasterPostBlock - pointer to structure that describes the post requests.
    01753                 It should be a master post!!
    01754     DelayedDeref - pointer to list of delayed deref keybodies. If this parameter is not NULL,
    01755                 the keybody for the slave is not cleared before calling CmpFreePostBlock,
    01756                 and instead is added to the list
    01757
    01758
    01759 Return Value:
    01760
    01761     NONE.
    01762
    01763 --*/
    01764 {
    01765     PCM_POST_BLOCK  SlavePostBlock;
    01766
    01767     PAGED_CODE();
    01768     CMLOG(CML_MAJOR, CMS_NOTIFY) {
    01769         KdPrint(("CmpCancelSlavePost:\t"));
    01770         KdPrint(("MasterPostBlock:%08lx\n", MasterPostBlock));
    01771     }
    01772
    01773     ASSERT_CM_LOCK_OWNED();
    01774
    01775     ASSERT(IsMasterPostBlock(MasterPostBlock));
    01776
    01777     CMLOG(CML_MAJOR, CMS_NOTIFY) {
    01778 #if DBG
    01779         if(MasterPostBlock->TraceIntoDebugger) {
    01780             KdPrint(("[CM]CmCancelSlavePost: MasterPostBlock:%08lx\n", MasterPostBlock));
    01781         }
    01782 #endif
    01783     }
    01784
    01785     if (IsListEmpty(&(MasterPostBlock->CancelPostList)) == TRUE) {
    01786         //
    01787         // Nothing to cancel, just return
    01788         //
    01789         CMLOG(CML_MAJOR, CMS_NOTIFY) {
    01790 #if DBG
    01791             if(MasterPostBlock->TraceIntoDebugger) {
    01792                 KdPrint(("[CM]CmCancelSlavePost: MasterPostBlock:%08lx has no slaves\n", MasterPostBlock));
    01793             }
    01794 #endif
    01795         }
    01796
    01797         return;
    01798     }
    01799
    01800
    01801     //
    01802     // Pull all the entries in the cancel post list and unlink them (when they are slave requests)
    01803     // We base here on the assumption that there is only one slave.
    01804     //
    01805     //     NOTE!!!
    01806     //       When more than slave allowed, here to modify
    01807     //
    01808
    01809
    01810     SlavePostBlock = (PCM_POST_BLOCK)MasterPostBlock->CancelPostList.Flink;
    01811     SlavePostBlock = CONTAINING_RECORD(SlavePostBlock,
    01812                                        CM_POST_BLOCK,
    01813                                        CancelPostList);
    01814
    01815     CMLOG(CML_MAJOR, CMS_NOTIFY) {
    01816 #if DBG
    01817         if(MasterPostBlock->TraceIntoDebugger) {
    01818             KdPrint(("[CM]CmCancelSlavePost: Cleaning SlavePostBlock:%08lx\n", SlavePostBlock));
    01819         }
    01820 #endif
    01821     }
    01822
    01823     //
    01824     // This should be true !
    01825     //
    01826     ASSERT( !IsMasterPostBlock(SlavePostBlock) );
    01827
    01828     //
    01829     // Remove it from notify block's list
    01830     //
    01831     // Use Cmp variant to protect for multiple deletion of the same object
    01832         // This will disable the notifications that might come on the slave key
    01833         //
    01834     CmpRemoveEntryList(&(SlavePostBlock->NotifyList));
    01835
    01836     if( DelayedDeref ) {
    01837         //
    01838         // the caller wants to handle key body dereferenciation by himself
    01839         //
    01840         CmpAddToDelayedDeref(SlavePostBlock,DelayedDeref);
    01841     }
    01842 }

VOID CmpDelayedDerefKeys | ( | PLIST_ENTRY | DelayedDeref | ) |

Definition at line 1900 of file cmnotify.c.

References ASSERT, CM_POST_KEY_BODY, ExFreePool(), FALSE, KEY_BODY_TYPE, _CM_POST_KEY_BODY::KeyBody, NULL, ObDereferenceObject, PAGED_CODE, PCM_POST_KEY_BODY, and _CM_KEY_BODY::Type.

Referenced by CmpPostNotify(), and CmpReportNotifyHelper().

    01905                    :
    01906
    01907     Walk through the entire list, dereference each keybody and free storage for the
    01908     CM_POST_KEY_BODY allocated for this purpose.
    01909
    01910 Arguments:
    01911
    01912     DelayedDeref - the delayed deref list
    01913
    01914 Return Value:
    01915
    01916     NONE.
    01917
    01918 --*/
    01919 {
    01920     PCM_POST_KEY_BODY   PostKeyBody;
    01921
    01922     PAGED_CODE();
    01923
    01924     // common sense
    01925     ASSERT( DelayedDeref != NULL );
    01926
    01927     while(IsListEmpty(DelayedDeref) == FALSE) {
    01928         //
    01929         // Remove from the delayed deref list and deref the coresponding keybody
    01930         // free the storage associated with CM_POST_KEY_BODY
    01931         //
    01932         PostKeyBody = (PCM_POST_KEY_BODY)RemoveHeadList(DelayedDeref);
    01933         PostKeyBody = CONTAINING_RECORD(PostKeyBody,
    01934                                       CM_POST_KEY_BODY,
    01935                                       KeyBodyList);
    01936
    01937         // extra validation
    01938         ASSERT(PostKeyBody->KeyBody != NULL);
    01939         // this should be a valid key body
    01940         ASSERT(PostKeyBody->KeyBody->Type == KEY_BODY_TYPE);
    01941
    01942         // at last ..... dereference the key object
    01943         ObDereferenceObject(PostKeyBody->KeyBody);
    01944
    01945         // Free the storage for the CM_POST_KEY_BODY object (allocated by CmpAllocatePostBlock)
    01946         ExFreePool(PostKeyBody);
    01947     }
    01948 }

VOID CmpDummyApc | ( | struct _KAPC * | Apc,
|  | PVOID * | SystemArgument1,
|  | PVOID * | SystemArgument2
| ) |

Definition at line 159 of file cmnotify.c.

Referenced by NtNotifyChangeMultipleKeys().

    00166                    :
    00167
    00168     Dummy routine to prevent user-mode callers to set special kernel apcs
    00169
    00170 Arguments:
    00171
    00172     Apc - pointer to apc object
    00173
    00174     SystemArgument1 -  IN: Status value for IoStatusBlock
    00175                       OUT: Ptr to IoStatusBlock (2nd arg to user apc routine)
    00176
    00177     SystemArgument2 - Pointer to the PostBlock
    00178
    00179 Return Value:
    00180
    00181     NONE.
    00182
    00183 --*/
    00184 {
    00185     UNREFERENCED_PARAMETER(Apc);
    00186     UNREFERENCED_PARAMETER(SystemArgument1);
    00187     UNREFERENCED_PARAMETER(SystemArgument2);
    00188 }

VOID CmpFlushNotify | ( | PCM_KEY_BODY | KeyBody | ) |

Definition at line 1235 of file cmnotify.c.

References ASSERT, ASSERT_CM_LOCK_OWNED, CML_MAJOR, CmLockHive, CMLOG, CmpClearListEntry, CmpInitializeKeyNameString(), CmpPostNotify(), CMS_NOTIFY, CmUnlockHive, DbgPrint, _CM_KEY_CONTROL_BLOCK::Delete, ExAllocatePool, ExFreePool(), FALSE, Hive, _CM_NOTIFY_BLOCK::HiveList, HiveList, _CM_KEY_BODY::KeyControlBlock, _CM_KEY_CONTROL_BLOCK::KeyHive, KeyName, _CM_KEY_CONTROL_BLOCK::KeyNode, MAX_KEY_NAME_LENGTH, _CM_KEY_BODY::NotifyBlock, NULL, PAGED_CODE, PagedPool, _CM_NOTIFY_BLOCK::PostList, SeReleaseSubjectContext(), and _CM_NOTIFY_BLOCK::SubjectContext.

Referenced by CmDeleteKey(), CmpDeleteKeyObject(), CmpRefreshHive(), and NtUnloadKey().

    01240                    :
    01241
    01242     Clean up notifyblock when a handle is closed or the key it refers
    01243     to is deleted.
    01244
    01245 Arguments:
    01246
    01247     KeyBody - supplies pointer to key object body for handle we
    01248                 are cleaning up.
    01249
    01250 Return Value:
    01251
    01252     NONE
    01253
    01254 --*/
    01255 {
    01256     PCM_NOTIFY_BLOCK    NotifyBlock;
    01257     PCMHIVE             Hive;
    01258
    01259     PAGED_CODE();
    01260     ASSERT_CM_LOCK_OWNED();
    01261
    01262     if (KeyBody->NotifyBlock == NULL) {
    01263         return;
    01264     }
    01265
    01266 #ifdef KCB_TO_KEYBODY_LINK
    01267     ASSERT( KeyBody->KeyControlBlock->Delete == FALSE );
    01268 #endif
    01269
    01270     CMLOG(CML_MAJOR, CMS_NOTIFY) {
    01271 #if DBG
    01272         WCHAR                   *NameBuffer = NULL;
    01273         UNICODE_STRING          KeyName;
    01274
    01275         KdPrint(("[CM]CmpFlushNotify: NotifyBlock = %08lx\n",KeyBody->NotifyBlock));
    01276         NameBuffer = ExAllocatePool(PagedPool, MAX_KEY_NAME_LENGTH);
    01277         if(NameBuffer && KeyBody->KeyControlBlock->KeyNode) {
    01278            CmpInitializeKeyNameString(KeyBody->KeyControlBlock->KeyNode,&KeyName,NameBuffer);
    01279            KdPrint(("\t[CM]CmpFlushNotify: Key = %.*S\n",KeyName.Length / sizeof(WCHAR),KeyName.Buffer));
    01280            ExFreePool(NameBuffer);
    01281         }
    01282 #endif
    01283     }
    01284
    01285     //
    01286     // Lock the hive exclusively to prevent multiple threads from whacking
    01287     // on the list.
    01288     //
    01289     Hive = CONTAINING_RECORD(KeyBody->KeyControlBlock->KeyHive,
    01290                              CMHIVE,
    01291                              Hive);
    01292     CmLockHive(Hive);
    01293     //
    01294     // Reread the notify block in case it has already been freed.
    01295     //
    01296     NotifyBlock = KeyBody->NotifyBlock;
    01297     if (NotifyBlock == NULL) {
    01298         CmUnlockHive(Hive);
    01299         return;
    01300     }
    01301
    01302     //
    01303     // Clean up all PostBlocks waiting on the NotifyBlock
    01304     //
    01305     if (IsListEmpty(&(NotifyBlock->PostList)) == FALSE) {
    01306         CmpPostNotify(
    01307             NotifyBlock,
    01308             NULL,
    01309             0,
    01310             STATUS_NOTIFY_CLEANUP,
    01311             NULL
    01312             );
    01313     }
    01314
    01315     //
    01316     // Release the subject context
    01317     //
    01318     SeReleaseSubjectContext(&NotifyBlock->SubjectContext);
    01319
    01320     //
    01321     // IMPLEMENTATION NOTE:
    01322     //      If we ever do code to report names and types of events,
    01323     //      this is the place to free the buffer.
    01324     //
    01325
    01326     //
    01327     // Remove the NotifyBlock from the hive chain
    01328     //
    01329     NotifyBlock->HiveList.Blink->Flink = NotifyBlock->HiveList.Flink;
    01330     if (NotifyBlock->HiveList.Flink != NULL) {
    01331         NotifyBlock->HiveList.Flink->Blink = NotifyBlock->HiveList.Blink;
    01332     }
    01333
    01334     // Protect for multiple deletion of the same object
    01335     CmpClearListEntry(&(NotifyBlock->HiveList));
    01336
    01337     KeyBody->NotifyBlock = NULL;
    01338
    01339 #ifdef _CM_ENTRYLIST_MANIPULATION
    01340     if (IsListEmpty(&(NotifyBlock->PostList)) == FALSE) {
    01341         DbgPrint("CmpFlushNotify: NotifyBlock %08lx\n",NotifyBlock);
    01342         DbgBreakPoint();
    01343     }
    01344     //check is the notify has been deleted from the hive notify list
    01345     {
    01346         PCM_NOTIFY_BLOCK ValidNotifyBlock;
    01347         PLIST_ENTRY NotifyPtr;
    01348
    01349         NotifyPtr = &(Hive->NotifyList);
    01350
    01351         while (NotifyPtr->Flink != NULL) {
    01352             NotifyPtr = NotifyPtr->Flink;
    01353
    01354             ValidNotifyBlock = CONTAINING_RECORD(NotifyPtr, CM_NOTIFY_BLOCK, HiveList);
    01355             if( ValidNotifyBlock == NotifyBlock ) {
    01356                 DbgPrint("CmpFlushNotify: NotifyBlock %08lx is about to be deleted but is still in the hive notify list\n",NotifyBlock);
    01357                 DbgBreakPoint();
    01358             }
    01359         }
    01360     }
    01361     RtlZeroMemory((PVOID)NotifyBlock, sizeof(CM_NOTIFY_BLOCK));
    01362 #endif
    01363
    01364     CmUnlockHive(Hive);
    01365
    01366     //
    01367     // Free the block, clean up the KeyBody
    01368     //
    01369     ExFreePool(NotifyBlock);
    01370     return;
    01371 }

VOID CmpFreeSlavePost | ( | PCM_POST_BLOCK | MasterPostBlock | ) |

Definition at line 1634 of file cmnotify.c.

References ASSERT, _CM_POST_BLOCK::CancelPostList, CML_MAJOR, CMLOG, CmpFreePostBlock(), CmpRemoveEntryList, CMS_NOTIFY, IsMasterPostBlock, PAGED_CODE, _CM_POST_BLOCK::ThreadList, and TRUE.

Referenced by CmNotifyRunDown(), CmpPostApc(), and CmpPostApcRunDown().

    01639                    :
    01640
    01641         Free the slave post block related to this master post block
    01642
    01643 Arguments:
    01644
    01645     MasterPostBlock - pointer to structure that describes the post requests.
    01646                 It should be a master post!!
    01647 Return Value:
    01648
    01649     NONE.
    01650
    01651 --*/
    01652 {
    01653     PCM_POST_BLOCK  SlavePostBlock;
    01654
    01655     PAGED_CODE();
    01656     CMLOG(CML_MAJOR, CMS_NOTIFY) {
    01657         KdPrint(("CmpCancelSlavePost:\t"));
    01658         KdPrint(("MasterPostBlock:%08lx\n", MasterPostBlock));
    01659     }
    01660
    01661     ASSERT(IsMasterPostBlock(MasterPostBlock));
    01662
    01663     CMLOG(CML_MAJOR, CMS_NOTIFY) {
    01664 #if DBG
    01665         if(MasterPostBlock->TraceIntoDebugger) {
    01666             KdPrint(("[CM]CmCancelSlavePost: MasterPostBlock:%08lx\n", MasterPostBlock));
    01667         }
    01668 #endif
    01669     }
    01670
    01671     if (IsListEmpty(&(MasterPostBlock->CancelPostList)) == TRUE) {
    01672         //
    01673         // Nothing to cancel, just return
    01674         //
    01675         CMLOG(CML_MAJOR, CMS_NOTIFY) {
    01676 #if DBG
    01677             if(MasterPostBlock->TraceIntoDebugger) {
    01678                 KdPrint(("[CM]CmCancelSlavePost: MasterPostBlock:%08lx has no slaves\n", MasterPostBlock));
    01679             }
    01680 #endif
    01681         }
    01682
    01683         return;
    01684     }
    01685
    01686
    01687     //
    01688     // Pull all the entries in the cancel post list and unlink them (when they are slave requests)
    01689     // We base here on the assumption that there is only one slave.
    01690     //
    01691     //     NOTE!!!
    01692     //       When more than slave allowed, here to modify
    01693     //
    01694
    01695
    01696     SlavePostBlock = (PCM_POST_BLOCK)MasterPostBlock->CancelPostList.Flink;
    01697     SlavePostBlock = CONTAINING_RECORD(SlavePostBlock,
    01698                                        CM_POST_BLOCK,
    01699                                        CancelPostList);
    01700
    01701     CMLOG(CML_MAJOR, CMS_NOTIFY) {
    01702 #if DBG
    01703         if(MasterPostBlock->TraceIntoDebugger) {
    01704             KdPrint(("[CM]CmCancelSlavePost: Cleaning SlavePostBlock:%08lx\n", SlavePostBlock));
    01705         }
    01706 #endif
    01707     }
    01708
    01709     //
    01710     // This should be true !
    01711     //
    01712     ASSERT( !IsMasterPostBlock(SlavePostBlock) );
    01713
    01714     //
    01715     // Unchain from the Master CancelPostList
    01716     //
    01717     // Use Cmp variant to protect for multiple deletion of the same object
    01718     CmpRemoveEntryList(&(SlavePostBlock->CancelPostList));
    01719
    01720     //
    01721     // delist the post block from the thread postblocklist
    01722     //
    01723     // Use Cmp variant to protect for multiple deletion of the same object
    01724     CmpRemoveEntryList(&(SlavePostBlock->ThreadList));
    01725
    01726     //
    01727     // Free the post block.
    01728     //
    01729     CmpFreePostBlock(SlavePostBlock);
    01730
    01731     //
    01732     // Result validation. was it the only slave?
    01733     //
    01734     ASSERT(IsListEmpty(&(MasterPostBlock->CancelPostList)));
    01735 }

NTSTATUS CmpNotifyChangeKey | ( | IN PCM_KEY_BODY | KeyBody,
|  | IN PCM_POST_BLOCK | PostBlock,
|  | IN ULONG | CompletionFilter,
|  | IN BOOLEAN | WatchTree,
|  | IN PVOID | Buffer,
|  | IN ULONG | BufferSize,
|  | IN PCM_POST_BLOCK | MasterPostBlock
| ) |

Definition at line 1378 of file cmnotify.c.

References APC_LEVEL, ASSERT, ASSERT_CM_LOCK_OWNED_EXCLUSIVE, CM_NOTIFY_BLOCK, CML_MINOR, CML_WORKER, CMLOG, CmpFreePostBlock(), CmpInitializeKeyNameString(), CmpPostNotify(), CMS_NOTIFY, CMS_POOL, ExAllocatePool, ExAllocatePoolWithQuotaTag, ExFreePool(), FALSE, _CM_NOTIFY_BLOCK::Filter, Hive, _CM_NOTIFY_BLOCK::HiveList, HiveList, IsMasterPostBlock, KeLowerIrql(), KeRaiseIrql(), _CM_NOTIFY_BLOCK::KeyBody, _CM_NOTIFY_BLOCK::KeyControlBlock, KeyName, MAX_KEY_NAME_LENGTH, _CM_NOTIFY_BLOCK::NotifyPending, NULL, PAGED_CODE, PagedPool, POOL_QUOTA_FAIL_INSTEAD_OF_RAISE, _CM_NOTIFY_BLOCK::PostList, PsGetCurrentThread, SeCaptureSubjectContext(), _CM_NOTIFY_BLOCK::SubjectContext, _CM_KEY_CONTROL_BLOCK::TotalLevels, TRUE, WatchTree, and _CM_NOTIFY_BLOCK::WatchTree.

Referenced by NtNotifyChangeMultipleKeys().

    01389                    :
    01390
    01391     This routine sets up the NotifyBlock, and attaches the PostBlock
    01392     to it.  When it returns, the Notify is visible to the system,
    01393     and will receive event reports.
    01394
    01395     If there is already an event report pending, then the notify
    01396     call will be satisified at once.
    01397
    01398 Arguments:
    01399
    01400     KeyBody - pointer to key object that handle refers to, allows access
    01401               to key control block, notify block, etc.
    01402
    01403     PostBlock - pointer to structure that describes how/where the caller
    01404                 is to be notified.
    01405
    01406                 WARNING:    PostBlock must come from Pool, THIS routine
    01407                             will keep it, back side will free it.  This
    01408                             routine WILL free it in case of error.
    01409
    01410     CompletionFilter - what types of events the caller wants to see
    01411
    01412     WatchTree - TRUE to watch whole subtree, FALSE to watch only immediate
    01413                 key the notify is applied to
    01414
    01415     Buffer - pointer to area to recieve notify data
    01416
    01417     BufferSize - size of buffer, also size user would like to allocate
    01418                  for internal buffer
    01419
    01420     MasterPostBlock - the post block of the master notification. Used to
    01421                       insert the PostBlock into the CancelPostList list.
    01422
    01423 Return Value:
    01424
    01425     Status.
    01426
    01427 --*/
    01428 {
    01429     PCM_NOTIFY_BLOCK    NotifyBlock;
    01430     PCM_NOTIFY_BLOCK    node;
    01431     PLIST_ENTRY         ptr;
    01432     PCMHIVE             Hive;
    01433     KIRQL               OldIrql;
    01434
    01435     PAGED_CODE();
    01436     CMLOG(CML_WORKER, CMS_NOTIFY) {
    01437         KdPrint(("CmpNotifyChangeKey:\n"));
    01438         KdPrint(("\tKeyBody:%08lx PostBlock:%08lx ", KeyBody, PostBlock));
    01439         KdPrint(("Filter:%08lx WatchTree:%08lx\n", CompletionFilter, WatchTree));
    01440 #if DBG
    01441         if(PostBlock->TraceIntoDebugger) {
    01442             WCHAR                   *NameBuffer = NULL;
    01443             UNICODE_STRING          KeyName;
    01444
    01445             KdPrint(("[CM]CmpNotifyChangeKey: PostBlock:%08lx\tMasterBlock: %08lx\n", PostBlock,MasterPostBlock));
    01446             NameBuffer = ExAllocatePool(PagedPool, MAX_KEY_NAME_LENGTH);
    01447             if(NameBuffer&&KeyBody->KeyControlBlock->KeyNode) {
    01448                CmpInitializeKeyNameString(KeyBody->KeyControlBlock->KeyNode,&KeyName,NameBuffer);
    01449                KdPrint(("\t[CM]CmpNotifyChangeKey: Key = %.*S\n",KeyName.Length / sizeof(WCHAR),KeyName.Buffer));
    01450                ExFreePool(NameBuffer);
    01451             }
    01452         }
    01453 #endif
    01454     }
    01455
    01456     //
    01457     // The registry lock should be aquired exclusively by the caller !!!
    01458     //
    01459     ASSERT_CM_LOCK_OWNED_EXCLUSIVE();
    01460
    01461     if (KeyBody->KeyControlBlock->Delete) {
    01462 #ifdef KCB_TO_KEYBODY_LINK
    01463         ASSERT( KeyBody->NotifyBlock == NULL );
    01464 #endif
    01465         CmpFreePostBlock(PostBlock);
    01466         return STATUS_KEY_DELETED;
    01467     }
    01468
    01469     Hive = (PCMHIVE)KeyBody->KeyControlBlock->KeyHive;
    01470     Hive = CONTAINING_RECORD(Hive, CMHIVE, Hive);
    01471     NotifyBlock = KeyBody->NotifyBlock;
    01472
    01473     if (NotifyBlock == NULL) {
    01474         //
    01475         // Set up new notify session
    01476         //
    01477         NotifyBlock = ExAllocatePoolWithQuotaTag(PagedPool|POOL_QUOTA_FAIL_INSTEAD_OF_RAISE,sizeof(CM_NOTIFY_BLOCK),CM_NOTIFYBLOCK_TAG);
    01478         CMLOG(CML_MINOR, CMS_POOL) {
    01479             KdPrint(("**CmpNotifyChangeKey: allocate:%08lx, ", sizeof(CM_NOTIFY_BLOCK)));
    01480             KdPrint(("type:%d, at:%08lx\n", PagedPool, NotifyBlock));
    01481         }
    01482
    01483         if (NotifyBlock == NULL) {
    01484             CmpFreePostBlock(PostBlock);
    01485             return STATUS_INSUFFICIENT_RESOURCES;
    01486         }
    01487         NotifyBlock->KeyControlBlock = KeyBody->KeyControlBlock;
    01488         NotifyBlock->Filter = CompletionFilter;
    01489         NotifyBlock->WatchTree = WatchTree;
    01490         NotifyBlock->NotifyPending = FALSE;
    01491         InitializeListHead(&(NotifyBlock->PostList));
    01492         KeyBody->NotifyBlock = NotifyBlock;
    01493         NotifyBlock->KeyBody = KeyBody;
    01494         ASSERT( KeyBody->KeyControlBlock->Delete == FALSE );
    01495
    01496         CMLOG(CML_WORKER, CMS_NOTIFY) {
    01497 #if DBG
    01498             if(PostBlock->TraceIntoDebugger) {
    01499                 WCHAR                   *NameBuffer = NULL;
    01500                 UNICODE_STRING          KeyName;
    01501
    01502                 NameBuffer = ExAllocatePool(PagedPool, MAX_KEY_NAME_LENGTH);
    01503                 if(NameBuffer) {
    01504                    CmpInitializeKeyNameString(KeyBody->KeyControlBlock->KeyNode,&KeyName,NameBuffer);
    01505                    KdPrint(("[CM]\tCmpNotifyChangeKey: New NotifyBlock at:%08lx was allocated for Key = %.*S\n",NotifyBlock,KeyName.Length / sizeof(WCHAR),KeyName.Buffer));
    01506                    ExFreePool(NameBuffer);
    01507                 }
    01508             }
    01509 #endif
    01510         }
    01511
    01512         //
    01513         // IMPLEMENTATION NOTE:
    01514         //      If we ever want to actually return the buffers full of
    01515         //      data, the buffer should be allocated and its address
    01516         //      stored in the notify block here.
    01517         //
    01518
    01519         //
    01520         // Capture the subject context so we can do checking once the
    01521         // notify goes off.
    01522         //
    01523         SeCaptureSubjectContext(&NotifyBlock->SubjectContext);
    01524
    01525         //
    01526         // Attach notify block to hive in properly sorted order
    01527         //
    01528         ptr = &(Hive->NotifyList);
    01529         while (TRUE) {
    01530             if (ptr->Flink == NULL) {
    01531                 //
    01532                 // End of list, add self after ptr.
    01533                 //
    01534                 ptr->Flink = &(NotifyBlock->HiveList);
    01535                 NotifyBlock->HiveList.Flink = NULL;
    01536                 NotifyBlock->HiveList.Blink = ptr;
    01537                 break;
    01538             }
    01539
    01540             ptr = ptr->Flink;
    01541
    01542             node = CONTAINING_RECORD(ptr, CM_NOTIFY_BLOCK, HiveList);
    01543
    01544             if (node->KeyControlBlock->TotalLevels >
    01545                 KeyBody->KeyControlBlock->TotalLevels)
    01546             {
    01547                 //
    01548                 // ptr -> notify with longer name than us, insert in FRONT
    01549                 //
    01550                 NotifyBlock->HiveList.Flink = ptr;
    01551                 ptr->Blink->Flink = &(NotifyBlock->HiveList);
    01552                 NotifyBlock->HiveList.Blink = ptr->Blink;
    01553                 ptr->Blink = &(NotifyBlock->HiveList);
    01554                 break;
    01555             }
    01556         }
    01557     }
    01558
    01559
    01560     //
    01561     // Add post block to front of notify block's list, and add it to thread list.
    01562     //
    01563     InsertHeadList(
    01564         &(NotifyBlock->PostList),
    01565         &(PostBlock->NotifyList)
    01566         );
    01567
    01568
    01569
    01570     if( IsMasterPostBlock(PostBlock) ) {
    01571         //
    01572         // Protect against outrageous calls
    01573         //
    01574         ASSERT(PostBlock == MasterPostBlock);
    01575
    01576         //
    01577         // When the notification is a master one, initialize the CancelPostList list
    01578         //
    01579         InitializeListHead(&(PostBlock->CancelPostList));
    01580     } else {
    01581         //
    01582         // Add PostBlock at the end of the CancelPostList list from the master post
    01583         //
    01584         InsertTailList(
    01585             &(MasterPostBlock->CancelPostList),
    01586             &(PostBlock->CancelPostList)
    01587             );
    01588     }
    01589
    01590
    01591     KeRaiseIrql(APC_LEVEL, &OldIrql);
    01592     InsertHeadList(
    01593         &(PsGetCurrentThread()->PostBlockList),
    01594         &(PostBlock->ThreadList)
    01595         );
    01596
    01597     CMLOG(CML_WORKER, CMS_NOTIFY) {
    01598 #if DBG
    01599         if(PostBlock->TraceIntoDebugger) {
    01600             KdPrint(("[CM]\tCmpNotifyChangeKey: Attaching the post:%08lx\t to thread:%08lx\n",PostBlock,PsGetCurrentThread()));
    01601         }
    01602 #endif
    01603     }
    01604
    01605     KeLowerIrql(OldIrql);
    01606
    01607     //
    01608     // If there is a notify pending (will not be if we just created
    01609     // the notify block) then post it at once.  Note that this call
    01610     // ALWAYS returns STATUS_PENDING unless it fails.  Caller must
    01611     // ALWAYS look in IoStatusBlock to see what happened.
    01612     //
    01613     if (NotifyBlock->NotifyPending == TRUE) {
    01614         CmpPostNotify(
    01615             NotifyBlock,
    01616             NULL,
    01617             0,
    01618             STATUS_NOTIFY_ENUM_DIR,
    01619             NULL
    01620             );
    01621         //
    01622         // return STATUS_SUCCESS to signal to the caller the the notify already been triggered
    01623         //
    01624         return STATUS_SUCCESS;
    01625     }
    01626
    01627     //
    01628     // return STATUS_PENDING to signal to the caller the the notify has not been triggered yet
    01629     //
    01630     return STATUS_PENDING;
    01631 }

BOOLEAN CmpNotifyTriggerCheck | ( | IN PCM_NOTIFY_BLOCK | NotifyBlock,
|  | IN PHHIVE | Hive,
|  | IN PCM_KEY_NODE | Node
| ) |

Definition at line 281 of file cmnotify.c.

References ASSERT, CM_POST_BLOCK, CmpCheckNotifyAccess(), FALSE, Hive, _CM_POST_BLOCK::NotifyList, PAGED_CODE, POST_BLOCK_TYPE, PostAsyncKernel, PostBlockType, and TRUE.

Referenced by CmpReportNotifyHelper().

    00288                    :
    00289
    00290     Checks if a notify can be triggered
    00291
    00292 Arguments:
    00293
    00294     NotifyBlock - the notify block
    00295
    00296     Hive - Supplies hive containing node to match with.
    00297
    00298     Node - pointer to key to match with (and check access to)
    00299
    00300
    00301 Return Value:
    00302
    00303     TRUE - yes.
    00304     FALSE - no
    00305
    00306 --*/
    00307 {
    00308     PCM_POST_BLOCK PostBlock;
    00309     POST_BLOCK_TYPE NotifyType;
    00310
    00311     PAGED_CODE();
    00312
    00313     if(IsListEmpty(&(NotifyBlock->PostList)) == FALSE) {
    00314
    00315         //
    00316         // check if it is a kernel notify. Look at the first post block
    00317         // to see that. If is a kernel post-block, then all posts in
    00318         // the list should be kernel notifies
    00319         //
    00320         PostBlock = (PCM_POST_BLOCK)NotifyBlock->PostList.Flink;
    00321         PostBlock = CONTAINING_RECORD(PostBlock,
    00322                                       CM_POST_BLOCK,
    00323                                       NotifyList);
    00324
    00325         NotifyType = PostBlockType(PostBlock);
    00326
    00327         if( NotifyType == PostAsyncKernel ) {
    00328             // this is a kernel notify; always trigger it
    00329 #if DBG
    00330             //
    00331             // DEBUG only code: All post blocks should be of the same type
    00332             // (kernel/user)
    00333             //
    00334             while( PostBlock->NotifyList.Flink != &(NotifyBlock->PostList) ) {
    00335                 PostBlock = (PCM_POST_BLOCK)PostBlock->NotifyList.Flink;
    00336                 PostBlock = CONTAINING_RECORD(PostBlock,
    00337                                             CM_POST_BLOCK,
    00338                                             NotifyList);
    00339
    00340                 //KdPrint(("CmpNotifyTriggerCheck : NotifyBlock = %lx\n",NotifyBlock));
    00341
    00342                 ASSERT( PostBlockType(PostBlock) == NotifyType );
    00343             }
    00344 #endif
    00345
    00346             return TRUE;
    00347         }
    00348     }
    00349
    00350     //
    00351     // else, check if the caller has the right access
    00352     //
    00353     return CmpCheckNotifyAccess(NotifyBlock,Hive,Node);
    00354 }

VOID CmpPostApc | ( | struct _KAPC * | Apc,
|  | PKNORMAL_ROUTINE * | NormalRoutine,
|  | PVOID * | NormalContext,
|  | PVOID * | SystemArgument1,
|  | PVOID * | SystemArgument2
| ) |

Definition at line 804 of file cmnotify.c.

References _CM_POST_BLOCK_UNION::AsyncUser, CML_MAJOR, CMLOG, CmpCheckPostBlock, CmpFreePostBlock(), CmpFreeSlavePost(), CmpRemoveEntryList, CmpSetIoStatus, CMS_NOTIFY, EXCEPTION_EXECUTE_HANDLER, FALSE, _CM_ASYNC_USER_POST_BLOCK::IoStatusBlock, KeSetEvent(), L, NULL, ObDereferenceObject, PAGED_CODE, PsGetCurrentProcess, _CM_POST_BLOCK::ThreadList, _CM_POST_BLOCK::u, and _CM_ASYNC_USER_POST_BLOCK::UserEvent.

Referenced by NtNotifyChangeMultipleKeys().

    00813                    :
    00814
    00815     This is the kernel apc routine.  It is called for all notifies,
    00816     regardless of what form of notification the caller requested.
    00817
    00818     We compute the postblock address from the apc object address.
    00819     IoStatus is set.  SystemEvent and UserEvent will be signalled
    00820     as appropriate.  If the user requested an APC, then NormalRoutine
    00821     will be set at entry and executed when we exit.  The PostBlock
    00822     is freed here.
    00823
    00824 Arguments:
    00825
    00826     Apc - pointer to apc object
    00827
    00828     NormalRoutine - Will be called when we return
    00829
    00830     NormalContext - will be 1st argument to normal routine, ApcContext
    00831                     passed in when NtNotifyChangeKey was called
    00832
    00833     SystemArgument1 -  IN: Status value for IoStatusBlock
    00834                       OUT: Ptr to IoStatusBlock (2nd arg to user apc routine)
    00835
    00836     SystemArgument2 - Pointer to the PostBlock
    00837
    00838 Return Value:
    00839
    00840     NONE.
    00841
    00842 --*/
    00843 {
    00844     PCM_POST_BLOCK  PostBlock;
    00845
    00846     PAGED_CODE();
    00847     CMLOG(CML_MAJOR, CMS_NOTIFY) {
    00848         KdPrint(("CmpPostApc:\n"));
    00849         KdPrint(("\tApc:%08lx ", Apc));
    00850         KdPrint(("NormalRoutine:%08lx\n", NormalRoutine));
    00851         KdPrint(("\tNormalContext:%08lx", NormalContext));
    00852         KdPrint(("\tSystemArgument1=IoStatusBlock:%08lx\n", SystemArgument1));
    00853     }
    00854
    00855
    00856     PostBlock = *(PCM_POST_BLOCK *)SystemArgument2;
    00857
    00858     CMLOG(CML_MAJOR, CMS_NOTIFY) {
    00859 #if DBG
    00860         if(PostBlock->TraceIntoDebugger) {
    00861             KdPrint(("[CM]CmpPostApc: PostBlock:%08lx\n", PostBlock));
    00862         }
    00863 #endif
    00864     }
    00865     //
    00866     // Fill in IO Status Block
    00867     //
    00868     // IMPLEMENTATION NOTE:
    00869     //      If we ever want to actually implement the code that returns
    00870     //      names of things that changed, this is the place to copy the
    00871     //      buffer into the caller's buffer.
    00872     //
    00873     //  Sundown only: Use a 32bit IO_STATUS_BLOCK if the caller is 32bit.
    00874
    00875     try {
    00876         CmpSetIoStatus(PostBlock->u->AsyncUser.IoStatusBlock,
    00877                        *((ULONG *)SystemArgument1),
    00878                        0L,
    00879                        PsGetCurrentProcess()->Wow64Process != NULL);
    00880     } except (EXCEPTION_EXECUTE_HANDLER) {
    00881         NOTHING;
    00882     }
    00883     *SystemArgument1 = PostBlock->u->AsyncUser.IoStatusBlock;
    00884
    00885     //
    00886     // This is an Async notify, do all work here, including
    00887     // cleaning up the post block
    00888     //
    00889
    00890     //
    00891     // Signal UserEvent if present, and deref it.
    00892     //
    00893     if (PostBlock->u->AsyncUser.UserEvent != NULL) {
    00894         KeSetEvent(PostBlock->u->AsyncUser.UserEvent,
    00895                    0,
    00896                    FALSE);
    00897         ObDereferenceObject(PostBlock->u->AsyncUser.UserEvent);
    00898     }
    00899
    00900     //
    00901     // remove the post block from the thread list, and free it
    00902     //
    00903     // Use Cmp variant to protect for multiple deletion of the same object
    00904     CmpRemoveEntryList(&(PostBlock->ThreadList));
    00905
    00906     // debug only checks
    00907     CmpCheckPostBlock(PostBlock);
    00908     //
    00909         // Free the slave post block to avoid "dangling" postblocks
    00910         //
    00911         CmpFreeSlavePost(PostBlock);
    00912     //
    00913         // free this post block
    00914         //
    00915         CmpFreePostBlock(PostBlock);
    00916
    00917     return;
    00918 }

VOID CmpPostApcRunDown | ( | struct _KAPC * | Apc | ) |

Definition at line 922 of file cmnotify.c.

References APC_LEVEL, _CM_POST_BLOCK_UNION::AsyncUser, CML_MAJOR, CMLOG, CmpFreePostBlock(), CmpFreeSlavePost(), CmpRemoveEntryList, CmpSetIoStatus, CMS_NOTIFY, EXCEPTION_EXECUTE_HANDLER, FALSE, _CM_ASYNC_USER_POST_BLOCK::IoStatusBlock, KeLowerIrql(), KeRaiseIrql(), KeSetEvent(), L, NULL, ObDereferenceObject, PAGED_CODE, PsGetCurrentProcess, _KAPC::SystemArgument2, _CM_POST_BLOCK::ThreadList, _CM_POST_BLOCK::u, and _CM_ASYNC_USER_POST_BLOCK::UserEvent.

Referenced by NtNotifyChangeMultipleKeys().

    00927                    :
    00928
    00929     This routine is called to clear away apcs in the apc queue
    00930     of a thread that has been terminated.
    00931
    00932     Since the apc is in the apc queue, we know that it is NOT in
    00933     any NotifyBlock's post list.  It is, however, in the threads's
    00934     PostBlockList.
    00935
    00936     Therefore, poke any user events so that waiters are not stuck,
    00937     drop the references so the event can be cleaned up, delist the
    00938     PostBlock and free it.
    00939
    00940     Since we are cleaning up the thread, SystemEvents are not interesting.
    00941
    00942     Since the apc is in the apc queue, we know that if there were any other
    00943     notifications related to this one, they are cleaned up by the
    00944     CmPostNotify routine
    00945
    00946 Arguments:
    00947
    00948     Apc - pointer to apc object
    00949
    00950 Return Value:
    00951
    00952     NONE.
    00953
    00954 --*/
    00955 {
    00956     PCM_POST_BLOCK  PostBlock;
    00957     KIRQL           OldIrql;
    00958
    00959     PAGED_CODE();
    00960     CMLOG(CML_MAJOR, CMS_NOTIFY) {
    00961         KdPrint(("CmpApcRunDown:"));
    00962         KdPrint(("\tApc:%08lx \n", Apc));
    00963     }
    00964
    00965     KeRaiseIrql(APC_LEVEL, &OldIrql);
    00966
    00967     PostBlock = (PCM_POST_BLOCK)Apc->SystemArgument2;
    00968
    00969     CMLOG(CML_MAJOR, CMS_NOTIFY) {
    00970 #if DBG
    00971         if(PostBlock->TraceIntoDebugger) {
    00972             KdPrint(("[CM]CmpPostApcRunDown: PostBlock:%08lx\n", PostBlock));
    00973         }
    00974 #endif
    00975     }
    00976
    00977     //
    00978     // report status and wake up any threads that might otherwise
    00979     // be stuck.  also drop any event references we hold
    00980     //
    00981     //  Sundown only: Use a 32bit IO_STATUS_BLOCK if the caller is 32bit.
    00982
    00983     try {
    00984         CmpSetIoStatus(PostBlock->u->AsyncUser.IoStatusBlock,
    00985                        STATUS_NOTIFY_CLEANUP,
    00986                        0L,
    00987                        PsGetCurrentProcess()->Wow64Process != NULL);
    00988     } except (EXCEPTION_EXECUTE_HANDLER) {
    00989         NOTHING;
    00990     }
    00991
    00992     if (PostBlock->u->AsyncUser.UserEvent != NULL) {
    00993         KeSetEvent(
    00994             PostBlock->u->AsyncUser.UserEvent,
    00995             0,
    00996             FALSE
    00997             );
    00998         ObDereferenceObject(PostBlock->u->AsyncUser.UserEvent);
    00999     }
    01000
    01001     //
    01002     // delist the post block
    01003     //
    01004     // Use Cmp variant to protect for multiple deletion of the same object
    01005     CmpRemoveEntryList(&(PostBlock->ThreadList));
    01006
    01007         //
    01008         // Free the slave post block to avoid "dangling" postblocks
    01009         //
    01010         CmpFreeSlavePost(PostBlock);
    01011     //
    01012     // Free the post block.  Use Ex call because PostBlocks are NOT
    01013     // part of the global registry pool computation, but are instead
    01014     // part of NonPagedPool with Quota.
    01015     //
    01016     CmpFreePostBlock(PostBlock);
    01017
    01018     KeLowerIrql(OldIrql);
    01019
    01020     return;
    01021 }

VOID CmpPostNotify | ( | PCM_NOTIFY_BLOCK | NotifyBlock,
|  | PUNICODE_STRING Name | OPTIONAL,
|  | ULONG | Filter,
|  | NTSTATUS | Status,
|  | PLIST_ENTRY ExternalKeyDeref | OPTIONAL
| ) |

Definition at line 487 of file cmnotify.c.

References _CM_ASYNC_USER_POST_BLOCK::Apc, APC_LEVEL, ASSERT, ASSERT_CM_LOCK_OWNED, _CM_POST_BLOCK_UNION::AsyncUser, _CM_POST_BLOCK::CancelPostList, ClearMasterPostBlockFlag, CML_MAJOR, CMLOG, CmpAddToDelayedDeref(), CmpCancelSlavePost(), CmpClearListEntry, CmpDelayedDerefKeys(), CmpFreePostBlock(), CmpInitializeKeyNameString(), CmpRemoveEntryList, CMS_NOTIFY, ExAllocatePool, ExFreePool(), ExQueueWorkItem(), FALSE, Filter, IsMasterPostBlock, KeInsertQueueApc(), KeLowerIrql(), KeRaiseIrql(), KeSetEvent(), _CM_NOTIFY_BLOCK::KeyControlBlock, KeyName, _CM_KEY_CONTROL_BLOCK::KeyNode, LOCK_POST_LIST, MAX_KEY_NAME_LENGTH, Name, _CM_POST_BLOCK::NotifyList, _CM_NOTIFY_BLOCK::NotifyPending, _CM_POST_BLOCK::NotifyType, NULL, ObDereferenceObject, PAGED_CODE, PagedPool, PostAsyncKernel, PostAsyncUser, PostBlockType, _CM_NOTIFY_BLOCK::PostList, PostSynchronous, SetMasterPostBlockFlag, Status, _CM_SYNC_POST_BLOCK::Status, _CM_POST_BLOCK_UNION::Sync, _CM_SYNC_POST_BLOCK::SystemEvent, _CM_POST_BLOCK::ThreadList, TRUE, _CM_POST_BLOCK::u, and UNLOCK_POST_LIST.

Referenced by CmpCloseKeyObject(), CmpFlushNotify(), CmpNotifyChangeKey(), and CmpReportNotifyHelper().

    00496                    :
    00497
    00498     Actually report the notify event by signalling events, enqueing
    00499     APCs, and so forth.
    00500
    00501     When Status is STATUS_NOTIFY_CLEANUP:
    00502
    00503       - if the post block is a slave one, just cancel it.
    00504       - if the post block is a master one, cancel all slave post blocks
    00505         and trigger event on the master block.
    00506
    00507 Comments:
    00508
    00509     This routine is using a "delayed dereferencing" technique to prevent
    00510     deadlocks that may appear when a keybody is dereferenced while holding
    00511     the post block lock. As for this, a list with keybodies that have to be
    00512     dereferenced is constructed while walking the list of postblocks attached
    00513     to the current notify block and the related (slave or master) post blocks.
    00514     The list is built by tricking postblocks. For all postblock about to be
    00515     freed the PostKeyBody member is added to the local list and then set to NULL
    00516     on the postblock. This will avoid the key body dereferencing in CmpFreePostBlock.
    00517     Instead, after the postblock lock is released, the local list is iterated and
    00518     the keybodies are dereferenced and the storage for associated CM_POST_KEY_BODY
    00519     objects is freed.
    00520
    00521
    00522 Arguments:
    00523
    00524     NotifyBlock - pointer to structure that describes the notify
    00525                   operation.  (Where to post to)
    00526
    00527     Name - name of key at which event occurred.
    00528
    00529     Filter - nature of event
    00530
    00531     Status - completion status to report
    00532
    00533     ExternalKeyDeref - this parameter (when not NULL) specifies that the caller doesn't
    00534                     want any keybody to be dereferenced while in this routine
    00535
    00536 Return Value:
    00537
    00538     NONE.
    00539
    00540 --*/
    00541 {
    00542     PCM_POST_BLOCK      PostBlock;
    00543     PCM_POST_BLOCK      SlavePostBlock;
    00544     LIST_ENTRY          LocalDelayedDeref;
    00545     KIRQL               OldIrql;
    00546     PLIST_ENTRY         DelayedDeref;
    00547
    00548     Filter;
    00549     Name;
    00550
    00551     PAGED_CODE();
    00552     CMLOG(CML_MAJOR, CMS_NOTIFY) {
    00553         KdPrint(("CmpPostNotify:\n"));
    00554         KdPrint(("\tNotifyBlock:%08lx  ", NotifyBlock));
    00555         KdPrint(("\tName = %wZ\n", Name));
    00556         KdPrint(("\tFilter:%08lx  Status=%08lx\n", Filter, Status));
    00557     }
    00558     ASSERT_CM_LOCK_OWNED();
    00559
    00560     if( ARGUMENT_PRESENT(ExternalKeyDeref) ) {
    00561         //
    00562         // The caller want to do all keybody dereferencing by himself
    00563         //
    00564         DelayedDeref = ExternalKeyDeref;
    00565     } else {
    00566         // local delayed dereferencing (the caller doesn't care!)
    00567         DelayedDeref = &LocalDelayedDeref;
    00568         InitializeListHead(DelayedDeref);
    00569     }
    00570
    00571     //
    00572     // Aquire exclusive access over the postlist(s)
    00573     //
    00574     LOCK_POST_LIST();
    00575
    00576     if (IsListEmpty(&(NotifyBlock->PostList)) == TRUE) {
    00577         //
    00578         // Nothing to post, set a mark and return
    00579         //
    00580         NotifyBlock->NotifyPending = TRUE;
    00581         UNLOCK_POST_LIST();
    00582         return;
    00583     }
    00584     NotifyBlock->NotifyPending = FALSE;
    00585
    00586     //
    00587     // IMPLEMENTATION NOTE:
    00588     //      If we ever want to actually implement the code that returns
    00589     //      names of things that changed, this is the place to add the
    00590     //      name and operation type to the buffer.
    00591     //
    00592
    00593     //
    00594     // Pull and post all the entries in the post list
    00595     //
    00596     while (IsListEmpty(&(NotifyBlock->PostList)) == FALSE) {
    00597
    00598         //
    00599         // Remove from the notify block list, and enqueue the apc.
    00600         // The apc will remove itself from the thread list
    00601         //
    00602         PostBlock = (PCM_POST_BLOCK)RemoveHeadList(&(NotifyBlock->PostList));
    00603         PostBlock = CONTAINING_RECORD(PostBlock,
    00604                                       CM_POST_BLOCK,
    00605                                       NotifyList);
    00606
    00607         // Protect for multiple deletion of the same object
    00608         CmpClearListEntry(&(PostBlock->NotifyList));
    00609
    00610         CMLOG(CML_MAJOR, CMS_NOTIFY) {
    00611 #if DBG
    00612             if(PostBlock->TraceIntoDebugger) {
    00613                 WCHAR                   *NameBuffer = NULL;
    00614                 UNICODE_STRING          KeyName;
    00615
    00616                 NameBuffer = ExAllocatePool(PagedPool, MAX_KEY_NAME_LENGTH);
    00617                 if(NameBuffer) {
    00618                    CmpInitializeKeyNameString(NotifyBlock->KeyControlBlock->KeyNode,&KeyName,NameBuffer);
    00619                    KdPrint(("[CM]CmpPostNotify: NotifyBlock:%08lx\tKey = %.*S\n",NotifyBlock,KeyName.Length / sizeof(WCHAR),KeyName.Buffer));
    00620                    ExFreePool(NameBuffer);
    00621                 }
    00622                 KdPrint(("[CM]\tCmpPostNotify: PostBlock:%08lx\n", PostBlock));
    00623             }
    00624 #endif
    00625         }
    00626
    00627         if( (Status == STATUS_NOTIFY_CLEANUP) && !IsMasterPostBlock(PostBlock) ) {
    00628             //
    00629             // Cleanup notification (i.e. the key handle was closed or the key was deleted)
    00630             // When the post is a slave one, just cancel it. Canceling means:
    00631             //      1. Removing from the notify PostList (aldready done at this point - see above)
    00632             //      2. Unchaining from the Master Block CancelPostList
    00633             //      3. Delisting from the thread PostBlockList
    00634             //      4. Actually freeing the memory
    00635             //
    00636
    00637             // Use Cmp variant to protect for multiple deletion of the same object
    00638             CmpRemoveEntryList(&(PostBlock->CancelPostList));
    00639             //
    00640             // FIX 289351
    00641             //
    00642             // Use Cmp variant to protect for multiple deletion of the same object
    00643             KeRaiseIrql(APC_LEVEL, &OldIrql);
    00644             CmpRemoveEntryList(&(PostBlock->ThreadList));
    00645             KeLowerIrql(OldIrql);
    00646
    00647             if( PostBlock->NotifyType != PostSynchronous ) {
    00648
    00649                 // add to the deref list and clean the post block
    00650                 CmpAddToDelayedDeref(PostBlock,DelayedDeref);
    00651
    00652                 //
    00653                 // Front-end routine will do self cleanup for syncrounous notifications
    00654                 CmpFreePostBlock(PostBlock);
    00655             }
    00656
    00657             CMLOG(CML_MAJOR, CMS_NOTIFY) {
    00658 #if DBG
    00659                 if(PostBlock->TraceIntoDebugger) {
    00660                     KdPrint(("[CM]\tCmpPostNotify: PostBlock:%08lx is a slave block,and notify is CLEANUP==> just cleanning\n", PostBlock));
    00661                 }
    00662 #endif
    00663             }
    00664
    00665             continue; //try the next one
    00666         }
    00667
    00668         //
    00669         // Simulate that this block is the master one, so we can free the others
    00670         // Doing that will ensure the right memory dealocation when the master
    00671         // (from now on this block) will be freed.
    00672         //
    00673         if(!IsMasterPostBlock(PostBlock)) {
    00674             //
    00675             // oops.,this is not the master block, we have some more work to do
    00676             //
    00677             SlavePostBlock = PostBlock;
    00678             do {
    00679                 SlavePostBlock = (PCM_POST_BLOCK)SlavePostBlock->CancelPostList.Flink;
    00680                 SlavePostBlock = CONTAINING_RECORD(SlavePostBlock,
    00681                                                    CM_POST_BLOCK,
    00682                                                    CancelPostList);
    00683                 //
    00684                 // reset the "master flag" if set
    00685                 //
    00686                 ClearMasterPostBlockFlag(SlavePostBlock);
    00687             } while (SlavePostBlock != PostBlock);
    00688
    00689             //
    00690             // Make this post block the master one
    00691             //
    00692             SetMasterPostBlockFlag(PostBlock);
    00693         }
    00694
    00695         CMLOG(CML_MAJOR, CMS_NOTIFY) {
    00696 #if DBG
    00697             if(PostBlock->TraceIntoDebugger) {
    00698                 KdPrint(("[CM]\tCmpPostNotify: Master block switched to :%08lx\n", PostBlock));
    00699             }
    00700 #endif
    00701         }
    00702
    00703         //
    00704         // Cancel all slave Post requests that may be linked to self
    00705         //
    00706
    00707         if( PostBlockType(PostBlock) != PostSynchronous ) {
    00708             //
    00709             // Front-end routine will do self cleanup for syncrounous notifications
    00710             CmpCancelSlavePost(PostBlock,DelayedDeref);
    00711             //
    00712             // Do the same for the master (in case master and slave got switched)
    00713             // This will avoid dereferencing the keybody from CmpPostApc
    00714             CmpAddToDelayedDeref(PostBlock,DelayedDeref);
    00715         }
    00716
    00717         switch (PostBlockType(PostBlock)) {
    00718             case PostSynchronous:
    00719                 //
    00720                 // This is a SYNC notify call.  There will be no user event,
    00721                 // and no user apc routine.  Quick exit here, just fill in
    00722                 // the Status and poke the event.
    00723                 //
    00724                 // Holder of the systemevent will wake up and free the
    00725                 // postblock.  If we free it here, we get a race & bugcheck.
    00726                 //
    00727                 // Set the flink to NULL so that the front side can tell this
    00728                 // has been removed if its wait aborts.
    00729                 //
    00730                 PostBlock->NotifyList.Flink = NULL;
    00731                 PostBlock->u->Sync.Status = Status;
    00732                 KeSetEvent(PostBlock->u->Sync.SystemEvent,
    00733                            0,
    00734                            FALSE);
    00735                 break;
    00736
    00737             case PostAsyncUser:
    00738                 //
    00739                 // Insert the APC into the queue
    00740                 //
    00741                 KeInsertQueueApc(PostBlock->u->AsyncUser.Apc,
    00742                                  (PVOID)ULongToPtr(Status),
    00743                                  (PVOID)PostBlock,
    00744                                  0);
    00745                 break;
    00746
    00747             case PostAsyncKernel:
    00748                 //
    00749                 // Queue the work item, then free the post block.
    00750                 //
    00751                 if (PostBlock->u->AsyncKernel.WorkItem != NULL) {
    00752                     ExQueueWorkItem(PostBlock->u->AsyncKernel.WorkItem,
    00753                                     PostBlock->u->AsyncKernel.QueueType);
    00754                 }
    00755                 //
    00756                 // Signal Event if present, and deref it.
    00757                 //
    00758                 if (PostBlock->u->AsyncKernel.Event != NULL) {
    00759                     KeSetEvent(PostBlock->u->AsyncKernel.Event,
    00760                                0,
    00761                                FALSE);
    00762                     ObDereferenceObject(PostBlock->u->AsyncKernel.Event);
    00763                 }
    00764
    00765                                 //
    00766                                 // Multiple async kernel notification are not allowed
    00767                                 //
    00768                                 ASSERT(IsListEmpty(&(PostBlock->CancelPostList)) == TRUE);
    00769                                 //
    00770                 // remove the post block from the thread list, and free it
    00771                 //
    00772                 // Use Cmp variant to protect for multiple deletion of the same object
    00773                 KeRaiseIrql(APC_LEVEL, &OldIrql);
    00774                 CmpRemoveEntryList(&(PostBlock->ThreadList));
    00775                 KeLowerIrql(OldIrql);
    00776
    00777                 // it was already added to delayed deref.
    00778                 CmpFreePostBlock(PostBlock);
    00779                 break;
    00780         }
    00781     }
    00782
    00783     UNLOCK_POST_LIST();
    00784
    00785     //
    00786     // At this point we have a list of keybody elements that have to be dereferenciated
    00787     // and the associated storage for the covering objects freed. The keybodies in this
    00788     // list have only one reference count on them (they were referenced only in
    00789     // NtNotifyChangeMultipleKeys), dereferencing them here should free the object
    00790     //
    00791
    00792     if( ARGUMENT_PRESENT(ExternalKeyDeref) ) {
    00793         // do nothing; the caller wants to handle the dereferenciation by himself!
    00794     } else {
    00795         // dereferenciate all keybodies in the delayed list
    00796         CmpDelayedDerefKeys(DelayedDeref);
    00797     }
    00798
    00799     return;
    00800 }

VOID CmpReportNotify | ( | PCM_KEY_CONTROL_BLOCK | KeyControlBlock,
|  | PHHIVE | Hive,
|  | HCELL_INDEX | Cell,
|  | ULONG | Filter
| ) |

Definition at line 191 of file cmnotify.c.

    00199                    :
    00200
    00201     This routine is called when a notifiable event occurs. It will
    00202     apply CmpReportNotifyHelper to the hive the event occured in,
    00203     and the master hive if different.
    00204
    00205 Arguments:
    00206
    00207     KeyControlBlock - KCB of the key at which the event occured.
    00208             For create or delete this is the created or deleted key.
    00209
    00210     Hive - pointer to hive containing cell of Key at which event occured.
    00211
    00212     Cell - cell of Key at which event occured
    00213
    00214             (hive and cell correspond with name.)
    00215
    00216     Filter - event to be reported
    00217
    00218 Return Value:
    00219
    00220     NONE.
    00221
    00222 --*/
    00223 {
    00224     PCM_KEY_NODE pcell;
    00225     ULONG       flags;
    00226     ULONG       i;
    00227
    00228     PAGED_CODE();
    00229     CMLOG(CML_WORKER, CMS_NOTIFY) {
    00230         KdPrint(("CmpReportNotify:\n"));
    00231         KdPrint(("\tHive:%08lx Cell:%08lx Filter:%08lx\n", Hive, Cell, Filter));
    00232     }
    00233
    00234     pcell = (PCM_KEY_NODE)HvGetCell(Hive, Cell);
    00235     //
    00236     // If the operation was create or delete, treat it as a change
    00237     // to the parent.
    00238     //
    00239     if (Filter == REG_NOTIFY_CHANGE_NAME) {
    00240         flags = pcell->Flags;
    00241         Cell = pcell->Parent;
    00242         if (flags & KEY_HIVE_ENTRY) {
    00243             Hive = &(CmpMasterHive->Hive);
    00244             pcell = (PCM_KEY_NODE)HvGetCell(Hive, Cell);
    00245         }
    00246
    00247
    00248         KeyControlBlock = KeyControlBlock->ParentKcb;
    00249
    00250         //
    00251         // if we're at an exit/link node, back up the real node
    00252         // that MUST be it's parent.
    00253         //
    00254         if (pcell->Flags & KEY_HIVE_EXIT) {
    00255             Cell = pcell->Parent;
    00256         }
    00257         pcell = (PCM_KEY_NODE)HvGetCell(Hive, Cell);
    00258     }
    00259
    00260     //
    00261     // Report to notifies waiting on the event's hive
    00262     //
    00263     CmpReportNotifyHelper(KeyControlBlock, Hive, Hive, pcell, Filter);
    00264
    00265
    00266     //
    00267     // If containing hive is not the master hive, apply to master hive
    00268     //
    00269     if (Hive != &(CmpMasterHive->Hive)) {
    00270         CmpReportNotifyHelper(KeyControlBlock,
    00271                               &(CmpMasterHive->Hive),
    00272                               Hive,
    00273                               pcell,
    00274                               Filter);
    00275     }
    00276
    00277     return;
    00278 }

VOID CmpReportNotifyHelper | ( | PCM_KEY_CONTROL_BLOCK | KeyControlBlock,
|  | IN PHHIVE | SearchHive,
|  | IN PHHIVE | Hive,
|  | IN PCM_KEY_NODE | Node,
|  | IN ULONG | Filter
| ) |

Definition at line 357 of file cmnotify.c.

References APC_LEVEL, CM_NOTIFY_BLOCK, CmpDelayedDerefKeys(), CmpNotifyTriggerCheck(), CmpPostNotify(), Filter, _CM_NOTIFY_BLOCK::Filter, Hive, HiveList, kcb(), KeLowerIrql(), KeRaiseIrql(), _CM_NOTIFY_BLOCK::KeyControlBlock, _CM_KEY_CONTROL_BLOCK::KeyNode, _CMHIVE::NotifyList, NULL, PAGED_CODE, _CM_KEY_CONTROL_BLOCK::TotalLevels, TRUE, USHORT, and _CM_NOTIFY_BLOCK::WatchTree.

Referenced by CmpReportNotify().

    00366                    :
    00367
    00368     Scan the list of active notifies for the specified hive.  For
    00369     any with scope including KeyControlBlock and filter matching
    00370     Filter, and with proper security access, post the notify.
    00371
    00372 Arguments:
    00373
    00374     Name - canonical path name (as in a key control block) of the key
    00375             at which the event occured.  (This is the name for
    00376             reporting purposes.)
    00377
    00378     SearchHive - hive to search for matches (which notify list to check)
    00379
    00380     Hive - Supplies hive containing node to match with.
    00381
    00382     Node - pointer to key to match with (and check access to)
    00383
    00384     Filter - type of event
    00385
    00386 Return Value:
    00387
    00388     NONE.
    00389
    00390 --*/
    00391 {
    00392     PLIST_ENTRY         NotifyPtr;
    00393     PCM_NOTIFY_BLOCK    NotifyBlock;
    00394     PCMHIVE             CmSearchHive;
    00395     PUNICODE_STRING     NotifyName;
    00396     KIRQL               OldIrql;
    00397     LIST_ENTRY          DelayedDeref;
    00398
    00399     PAGED_CODE();
    00400
    00401     KeRaiseIrql(APC_LEVEL, &OldIrql);
    00402
    00403     CmSearchHive = CONTAINING_RECORD(SearchHive, CMHIVE, Hive);
    00404
    00405     NotifyPtr = &(CmSearchHive->NotifyList);
    00406
    00407     InitializeListHead(&(DelayedDeref));
    00408
    00409     while (NotifyPtr->Flink != NULL) {
    00410
    00411         NotifyPtr = NotifyPtr->Flink;
    00412
    00413         NotifyBlock = CONTAINING_RECORD(NotifyPtr, CM_NOTIFY_BLOCK, HiveList);
    00414         if (NotifyBlock->KeyControlBlock->TotalLevels > KeyControlBlock->TotalLevels) {
    00415             //
    00416             // list is level sorted, we're past all shorter entries
    00417             //
    00418             break;
    00419         } else {
    00420             PCM_KEY_CONTROL_BLOCK kcb;
    00421             USHORT LevelDiff, l;
    00422
    00423             LevelDiff = KeyControlBlock->TotalLevels - NotifyBlock->KeyControlBlock->TotalLevels;
    00424
    00425             kcb = KeyControlBlock;
    00426             for (l=0; l<LevelDiff; l++) {
    00427                 kcb = kcb->ParentKcb;
    00428             }
    00429
    00430             if (kcb == NotifyBlock->KeyControlBlock) {
    00431                 //
    00432                 // This Notify path is the prefix of this kcb.
    00433                 //
    00434                 if ((NotifyBlock->Filter & Filter)
    00435                             &&
    00436                     ((NotifyBlock->WatchTree == TRUE) ||
    00437                      (Node == NotifyBlock->KeyControlBlock->KeyNode))
    00438                    )
    00439                 {
    00440                     // Filter matches, this event is relevent to this notify
    00441                     //                  AND
    00442                     // Either the notify spans the whole subtree, or the cell
    00443                     // (key) of interest is the one it applies to
    00444                     //
    00445                     // THEREFORE:   The notify is relevent.
    00446                     //
    00447
    00448                     //
    00449                     // Correct scope, does caller have access?
    00450                     //
    00451                     if (CmpNotifyTriggerCheck(NotifyBlock,Hive,Node)) {
    00452                         //
    00453                         // Notify block has KEY_NOTIFY access to the node
    00454                         // the event occured at.  It is relevent.  Therefore,
    00455                         // it gets to see this event.  Post and be done.
    00456                         //
    00457                         // we specify that we want no key body dereferenciation
    00458                         // during the CmpPostNotify call. This is to prevent the
    00459                         // deletion of the current notify block
    00460                         //
    00461                         CmpPostNotify(
    00462                             NotifyBlock,
    00463                             NULL,
    00464                             Filter,
    00465                             STATUS_NOTIFY_ENUM_DIR,
    00466                             &DelayedDeref
    00467                             );
    00468
    00469                     }  // else no KEY_NOTIFY access to node event occured at
    00470                 } // else not relevent (wrong scope, filter, etc)
    00471             }
    00472         }
    00473     }
    00474
    00475     //
    00476     // finish the job started in CmpPostNotify (i.e. dereference the keybodies
    00477     // we prevented. this may cause some notifyblocks to be freed
    00478     //
    00479     CmpDelayedDerefKeys(&DelayedDeref);
    00480
    00481     KeLowerIrql(OldIrql);
    00482     return;
    00483 }

## Variable Documentation

PCMHIVE CmpMasterHive

| Definition at line 93 of file cmnotify.c.