static _fileContext* _getOrSetContext ( PFLT_CALLBACK_DATA Data ) { NTSTATUS status = STATUS_SUCCESS; _fileContext* context = NULL; _fileContext* oldContext = NULL; status = FltGetFileContext( Data->Iopb->TargetInstance, Data->Iopb->TargetFileObject, &context ); if( STATUS_NOT_FOUND == status ) { status = FltAllocateContext( g_filter, FLT_FILE_CONTEXT, sizeof( _fileContext ), NonPagedPool, (PFLT_CONTEXT*)&context ); if( STATUS_SUCCESS == status ) { context->isNew = FALSE; context->isDelete = FALSE; context->isChanged = FALSE; context->isRead = FALSE; context->lastWritePid = 0; context->lastReadPid = 0; status = FltSetFileContext( Data->Iopb->TargetInstance, Data->Iopb->TargetFileObject, FLT_SET_CONTEXT_KEEP_IF_EXISTS, context, &oldContext ); if( STATUS_FLT_CONTEXT_ALREADY_DEFINED == status ) { FltReleaseContext( (PFLT_CONTEXT)context ); context = oldContext; } else if( STATUS_SUCCESS != status ) { FltReleaseContext( (PFLT_CONTEXT)context ); context = NULL; } } } if( NULL_CONTEXT == context ) { context = NULL; } return context; }
static NTSTATUS UcaSetContext(_In_ PFLT_INSTANCE Instance, _In_ PVOID Target, _In_ FLT_CONTEXT_TYPE ContextType, _In_ PFLT_CONTEXT NewContext, _Outptr_opt_result_maybenull_ PFLT_CONTEXT *OldContext) { NTSTATUS Status; PAGED_CODE(); switch (ContextType) { case FLT_STREAM_CONTEXT: Status = FltSetStreamContext(Instance, (PFILE_OBJECT)Target, FLT_SET_CONTEXT_KEEP_IF_EXISTS, NewContext, OldContext); break; case FLT_FILE_CONTEXT: Status = FltSetFileContext(Instance, (PFILE_OBJECT)Target, FLT_SET_CONTEXT_KEEP_IF_EXISTS, NewContext, OldContext); break; case FLT_TRANSACTION_CONTEXT: Status = FltSetTransactionContext(Instance, (PKTRANSACTION)Target, FLT_SET_CONTEXT_KEEP_IF_EXISTS, NewContext, OldContext); break; case FLT_INSTANCE_CONTEXT: Status = FltSetInstanceContext(Instance, FLT_SET_CONTEXT_KEEP_IF_EXISTS, NewContext, OldContext); break; default: Status = STATUS_INVALID_PARAMETER; break; } return Status; }
/*++ Routine Description: 这个函数找到目标文件的文件上下文。 如果上下文不存在,这个函数创建一个新的文件上下文附加在该文件上。 This routine finds the file context for the target file. Optionally, if the context does not exist this routing creates a new one and attaches the context to the file. Arguments: Cbd - Supplies a pointer to the callbackData which declares the requested operation. CreateIfNotFound - Supplies if the file context must be created if missing FileName - Supplies the file name FileContext - Returns the file context ContextCreated - Returns if a new context was created Return Value: Status --*/ NTSTATUS CtxFindOrCreateFileContext ( __in PFLT_CALLBACK_DATA Cbd, __in BOOLEAN CreateIfNotFound, __in_opt PUNICODE_STRING FileName, __deref_out PCTX_FILE_CONTEXT *FileContext, __out_opt PBOOLEAN ContextCreated ) { NTSTATUS status; PCTX_FILE_CONTEXT fileContext; PCTX_FILE_CONTEXT oldFileContext; PAGED_CODE(); *FileContext = NULL; if (ContextCreated != NULL) *ContextCreated = FALSE; // 首先,尝试获取文件上下文。 // First try to get the file context. DebugTrace( DEBUG_TRACE_FILE_CONTEXT_OPERATIONS, ("[Ctx]: Trying to get file context (FileObject = %p, Instance = %p)\n", Cbd->Iopb->TargetFileObject, Cbd->Iopb->TargetInstance) ); status = FltGetFileContext( Cbd->Iopb->TargetInstance, Cbd->Iopb->TargetFileObject, &fileContext ); // 如果调用失败是因为上下文不存在,并且用户想创建一个新的话,那么就创建一个 // If the call failed because the context does not exist // and the user wants to creat a new one, the create a // new context if (!NT_SUCCESS( status ) && (status == STATUS_NOT_FOUND) && CreateIfNotFound) { // 创建一个文件上下文 // Create a file context DebugTrace( DEBUG_TRACE_FILE_CONTEXT_OPERATIONS, ("[Ctx]: Creating file context (FileObject = %p, Instance = %p)\n", Cbd->Iopb->TargetFileObject, Cbd->Iopb->TargetInstance) ); status = CtxCreateFileContext( FileName, &fileContext ); if (!NT_SUCCESS( status )) { DebugTrace( DEBUG_TRACE_ERROR | DEBUG_TRACE_FILE_CONTEXT_OPERATIONS, ("[Ctx]: Failed to create file 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_FILE_CONTEXT_OPERATIONS, ("[Ctx]: Setting file context %p (FileObject = %p, Instance = %p)\n", fileContext, Cbd->Iopb->TargetFileObject, Cbd->Iopb->TargetInstance) ); status = FltSetFileContext( Cbd->Iopb->TargetInstance, Cbd->Iopb->TargetFileObject, FLT_SET_CONTEXT_KEEP_IF_EXISTS, fileContext, &oldFileContext ); if (!NT_SUCCESS( status )) { DebugTrace( DEBUG_TRACE_FILE_CONTEXT_OPERATIONS, ("[Ctx]: Failed to set file context with status 0x%x. (FileObject = %p, Instance = %p)\n", status, Cbd->Iopb->TargetFileObject, Cbd->Iopb->TargetInstance) ); // 由于FltSetFileContext()调用失败,释放上下文 // We release the context here because FltSetFileContext failed // // 如果FltSetFileContext()成功,这个上下文会返回给调用者。 // 调用者使用这个上下文,当使用完毕之后释放它。 // If FltSetFileContext 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_FILE_CONTEXT_OPERATIONS, ("[Ctx]: Releasing file context %p (FileObject = %p, Instance = %p)\n", fileContext, Cbd->Iopb->TargetFileObject, Cbd->Iopb->TargetInstance) ); FltReleaseContext( fileContext ); if (status != STATUS_FLT_CONTEXT_ALREADY_DEFINED) { // // FltSetFileContext failed for a reason other than the context already // existing on the file. 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_FILE_CONTEXT_OPERATIONS, ("[Ctx]: Failed to set file context with status 0x%x != STATUS_FLT_CONTEXT_ALREADY_DEFINED. (FileObject = %p, Instance = %p)\n", status, Cbd->Iopb->TargetFileObject, Cbd->Iopb->TargetInstance) ); return status; } // 竞争条件。 // Race condition. Someone has set a context after we queried it. // Use the already set context instead DebugTrace( DEBUG_TRACE_FILE_CONTEXT_OPERATIONS, ("[Ctx]: File context already defined. Retaining old file context %p (FileObject = %p, Instance = %p)\n", oldFileContext, Cbd->Iopb->TargetFileObject, Cbd->Iopb->TargetInstance) ); // // Return the existing context. Note that the new context that we allocated has already been // realeased above. fileContext = oldFileContext; status = STATUS_SUCCESS; } else { if (ContextCreated != NULL) *ContextCreated = TRUE; } } *FileContext = fileContext; return status; }
NTSTATUS CtxFindOrCreateFileContext ( __in PFLT_CALLBACK_DATA Cbd, __in BOOLEAN CreateIfNotFound, __in_opt PUNICODE_STRING FileName, __deref_out PCTX_FILE_CONTEXT *FileContext, __out_opt PBOOLEAN ContextCreated ) /*++ Routine Description: This routine finds the file context for the target file. Optionally, if the context does not exist this routing creates a new one and attaches the context to the file. Arguments: Cbd - Supplies a pointer to the callbackData which declares the requested operation. CreateIfNotFound - Supplies if the file context must be created if missing FileName - Supplies the file name FileContext - Returns the file context ContextCreated - Returns if a new context was created Return Value: Status --*/ { NTSTATUS status; PCTX_FILE_CONTEXT fileContext; PCTX_FILE_CONTEXT oldFileContext; PAGED_CODE(); *FileContext = NULL; if (ContextCreated != NULL) *ContextCreated = FALSE; // // First try to get the file context. // DebugTrace( DEBUG_TRACE_FILE_CONTEXT_OPERATIONS, ("[Ctx]: Trying to get file context (FileObject = %p, Instance = %p)\n", Cbd->Iopb->TargetFileObject, Cbd->Iopb->TargetInstance) ); status = FltGetFileContext( Cbd->Iopb->TargetInstance, Cbd->Iopb->TargetFileObject, &fileContext ); // // If the call failed because the context does not exist // and the user wants to creat a new one, the create a // new context // if (!NT_SUCCESS( status ) && (status == STATUS_NOT_FOUND) && CreateIfNotFound) { // // Create a file context // DebugTrace( DEBUG_TRACE_FILE_CONTEXT_OPERATIONS, ("[Ctx]: Creating file context (FileObject = %p, Instance = %p)\n", Cbd->Iopb->TargetFileObject, Cbd->Iopb->TargetInstance) ); status = CtxCreateFileContext( FileName, &fileContext ); if (!NT_SUCCESS( status )) { DebugTrace( DEBUG_TRACE_ERROR | DEBUG_TRACE_FILE_CONTEXT_OPERATIONS, ("[Ctx]: Failed to create file 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_FILE_CONTEXT_OPERATIONS, ("[Ctx]: Setting file context %p (FileObject = %p, Instance = %p)\n", fileContext, Cbd->Iopb->TargetFileObject, Cbd->Iopb->TargetInstance) ); status = FltSetFileContext( Cbd->Iopb->TargetInstance, Cbd->Iopb->TargetFileObject, FLT_SET_CONTEXT_KEEP_IF_EXISTS, fileContext, &oldFileContext ); if (!NT_SUCCESS( status )) { DebugTrace( DEBUG_TRACE_FILE_CONTEXT_OPERATIONS, ("[Ctx]: Failed to set file context with status 0x%x. (FileObject = %p, Instance = %p)\n", status, Cbd->Iopb->TargetFileObject, Cbd->Iopb->TargetInstance) ); // // We release the context here because FltSetFileContext failed // // If FltSetFileContext 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_FILE_CONTEXT_OPERATIONS, ("[Ctx]: Releasing file context %p (FileObject = %p, Instance = %p)\n", fileContext, Cbd->Iopb->TargetFileObject, Cbd->Iopb->TargetInstance) ); FltReleaseContext( fileContext ); if (status != STATUS_FLT_CONTEXT_ALREADY_DEFINED) { // // FltSetFileContext failed for a reason other than the context already // existing on the file. 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_FILE_CONTEXT_OPERATIONS, ("[Ctx]: Failed to set file context with status 0x%x != STATUS_FLT_CONTEXT_ALREADY_DEFINED. (FileObject = %p, Instance = %p)\n", status, Cbd->Iopb->TargetFileObject, Cbd->Iopb->TargetInstance) ); return status; } // // Race condition. Someone has set a context after we queried it. // Use the already set context instead // DebugTrace( DEBUG_TRACE_FILE_CONTEXT_OPERATIONS, ("[Ctx]: File context already defined. Retaining old file context %p (FileObject = %p, Instance = %p)\n", oldFileContext, Cbd->Iopb->TargetFileObject, Cbd->Iopb->TargetInstance) ); // // Return the existing context. Note that the new context that we allocated has already been // realeased above. // fileContext = oldFileContext; status = STATUS_SUCCESS; } else { if (ContextCreated != NULL) *ContextCreated = TRUE; } } *FileContext = fileContext; return status; }