/*++ Routine Description: This routine creates a stream handle context for the target stream handle. Optionally, if the context already exists, this routine replaces it with the new context and releases the old context Arguments: Cbd - Supplies a pointer to the callbackData which declares the requested operation. ReplaceIfExists - Supplies if the stream handle context must be replaced if already present StreamContext - Returns the stream context ContextReplaced - Returns if an existing context was replaced Return Value: Status --*/ NTSTATUS CtxCreateOrReplaceStreamHandleContext ( __in PFLT_CALLBACK_DATA Cbd, __in BOOLEAN ReplaceIfExists, __deref_out PCTX_STREAMHANDLE_CONTEXT *StreamHandleContext, __out_opt PBOOLEAN ContextReplaced ) { NTSTATUS status; PCTX_STREAMHANDLE_CONTEXT streamHandleContext; PCTX_STREAMHANDLE_CONTEXT oldStreamHandleContext; PAGED_CODE(); *StreamHandleContext = NULL; if (ContextReplaced != NULL) *ContextReplaced = FALSE; // // Create a stream context // DebugTrace( DEBUG_TRACE_STREAMHANDLE_CONTEXT_OPERATIONS, ("[Ctx]: Creating stream handle context (FileObject = %p, Instance = %p)\n", Cbd->Iopb->TargetFileObject, Cbd->Iopb->TargetInstance) ); status = CtxCreateStreamHandleContext( &streamHandleContext ); if (!NT_SUCCESS( status )) { DebugTrace( DEBUG_TRACE_ERROR | DEBUG_TRACE_STREAMHANDLE_CONTEXT_OPERATIONS, ("[Ctx]: Failed to create stream context with status 0x%x. (FileObject = %p, Instance = %p)\n", status, Cbd->Iopb->TargetFileObject, Cbd->Iopb->TargetInstance) ); return status; } // // Set the new context we just allocated on the file object // DebugTrace( DEBUG_TRACE_STREAMHANDLE_CONTEXT_OPERATIONS, ("[Ctx]: Setting stream context %p (FileObject = %p, Instance = %p, ReplaceIfExists = %x)\n", streamHandleContext, Cbd->Iopb->TargetFileObject, Cbd->Iopb->TargetInstance, ReplaceIfExists) ); status = FltSetStreamHandleContext( Cbd->Iopb->TargetInstance, Cbd->Iopb->TargetFileObject, ReplaceIfExists ? FLT_SET_CONTEXT_REPLACE_IF_EXISTS : FLT_SET_CONTEXT_KEEP_IF_EXISTS, streamHandleContext, &oldStreamHandleContext ); if (!NT_SUCCESS( status )) { DebugTrace( DEBUG_TRACE_STREAMHANDLE_CONTEXT_OPERATIONS, ("[Ctx]: Failed to set stream handle context with status 0x%x. (FileObject = %p, Instance = %p)\n", status, Cbd->Iopb->TargetFileObject, Cbd->Iopb->TargetInstance) ); // // We release the context here because FltSetStreamContext failed // // If FltSetStreamContext succeeded then the context will be returned // to the caller. The caller will use the context and then release it // when he is done with the context. // DebugTrace( DEBUG_TRACE_STREAMHANDLE_CONTEXT_OPERATIONS, ("[Ctx]: Releasing stream handle context %p (FileObject = %p, Instance = %p)\n", streamHandleContext, Cbd->Iopb->TargetFileObject, Cbd->Iopb->TargetInstance) ); FltReleaseContext( streamHandleContext ); if (status != STATUS_FLT_CONTEXT_ALREADY_DEFINED) { // // FltSetStreamContext failed for a reason other than the context already // existing on the stream. So the object now does not have any context set // on it. So we return failure to the caller. // DebugTrace( DEBUG_TRACE_ERROR | DEBUG_TRACE_STREAMHANDLE_CONTEXT_OPERATIONS, ("[Ctx]: Failed to set stream context with status 0x%x != STATUS_FLT_CONTEXT_ALREADY_DEFINED. (FileObject = %p, Instance = %p)\n", status, Cbd->Iopb->TargetFileObject, Cbd->Iopb->TargetInstance) ); return status; } // // We will reach here only if we have failed with STATUS_FLT_CONTEXT_ALREADY_DEFINED // and we can fail with that code only if the context already exists and we have used // the FLT_SET_CONTEXT_KEEP_IF_EXISTS flag ASSERT( ReplaceIfExists == FALSE ); // // Race condition. Someone has set a context after we queried it. // Use the already set context instead // DebugTrace( DEBUG_TRACE_STREAMHANDLE_CONTEXT_OPERATIONS, ("[Ctx]: Stream context already defined. Retaining old stream context %p (FileObject = %p, Instance = %p)\n", oldStreamHandleContext, Cbd->Iopb->TargetFileObject, Cbd->Iopb->TargetInstance) ); // // Return the existing context. Note that the new context that we allocated has already been // realeased above. // streamHandleContext = oldStreamHandleContext; status = STATUS_SUCCESS; } else { // // FltSetStreamContext has suceeded. The new context will be returned // to the caller. The caller will use the context and then release it // when he is done with the context. // // However, if we have replaced an existing context then we need to // release the old context so as to decrement the ref count on it. // // Note that the memory allocated to the objects within the context // will be freed in the context cleanup and must not be done here. // if ( ReplaceIfExists && oldStreamHandleContext != NULL) { DebugTrace( DEBUG_TRACE_STREAMHANDLE_CONTEXT_OPERATIONS, ("[Ctx]: Releasing old stream handle context %p (FileObject = %p, Instance = %p)\n", oldStreamHandleContext, Cbd->Iopb->TargetFileObject, Cbd->Iopb->TargetInstance) ); FltReleaseContext( oldStreamHandleContext ); if (ContextReplaced != NULL) *ContextReplaced = TRUE; } } *StreamHandleContext = streamHandleContext; return status; }
NTSTATUS CtxCreateOrReplaceStreamHandleContext ( __in PFLT_CALLBACK_DATA Cbd, __in BOOLEAN ReplaceIfExists, __deref_out PSTREAMHANDLE_CONTEXT *StreamHandleContext, __out_opt PBOOLEAN ContextReplaced ) /*++ Routine Description: This routine creates a stream handle context for the target stream handle. Optionally, if the context already exists, this routine replaces it with the new context and releases the old context Arguments: Cbd - Supplies a pointer to the callbackData which declares the requested operation. ReplaceIfExists - Supplies if the stream handle context must be replaced if already present StreamContext - Returns the stream context ContextReplaced - Returns if an existing context was replaced Return Value: Status --*/ { NTSTATUS status; PSTREAMHANDLE_CONTEXT streamHandleContext; PSTREAMHANDLE_CONTEXT oldStreamHandleContext; PAGED_CODE(); *StreamHandleContext = NULL; if (ContextReplaced != NULL) *ContextReplaced = FALSE; // // Create a stream context // status = CtxCreateStreamHandleContext( &streamHandleContext ); if (!NT_SUCCESS( status )) { return status; } // // Set the new context we just allocated on the file object // status = FltSetStreamHandleContext( Cbd->Iopb->TargetInstance, Cbd->Iopb->TargetFileObject, ReplaceIfExists ? FLT_SET_CONTEXT_REPLACE_IF_EXISTS : FLT_SET_CONTEXT_KEEP_IF_EXISTS, streamHandleContext, &oldStreamHandleContext ); if (!NT_SUCCESS( status )) { // // We release the context here because FltSetStreamContext failed // // If FltSetStreamContext succeeded then the context will be returned // to the caller. The caller will use the context and then release it // when he is done with the context. // FltReleaseContext( streamHandleContext ); if (status != STATUS_FLT_CONTEXT_ALREADY_DEFINED) { // // FltSetStreamContext failed for a reason other than the context already // existing on the stream. So the object now does not have any context set // on it. So we return failure to the caller. // return status; } // // We will reach here only if we have failed with STATUS_FLT_CONTEXT_ALREADY_DEFINED // and we can fail with that code only if the context already exists and we have used // the FLT_SET_CONTEXT_KEEP_IF_EXISTS flag ASSERT( ReplaceIfExists == FALSE ); // // Race condition. Someone has set a context after we queried it. // Use the already set context instead // // // Return the existing context. Note that the new context that we allocated has already been // realeased above. // streamHandleContext = oldStreamHandleContext; status = STATUS_SUCCESS; } else { // // FltSetStreamContext has suceeded. The new context will be returned // to the caller. The caller will use the context and then release it // when he is done with the context. // // However, if we have replaced an existing context then we need to // release the old context so as to decrement the ref count on it. // // Note that the memory allocated to the objects within the context // will be freed in the context cleanup and must not be done here. // if ( ReplaceIfExists && oldStreamHandleContext != NULL) { streamHandleContext->TaskState = oldStreamHandleContext->TaskState; FltReleaseContext( oldStreamHandleContext ); if (ContextReplaced != NULL) *ContextReplaced = TRUE; } } *StreamHandleContext = streamHandleContext; return status; }