From 2c3c2095fb346de9e1481a42391d416413f40749 Mon Sep 17 00:00:00 2001 From: Ged Murphy Date: Tue, 6 Sep 2016 16:47:43 +0000 Subject: [PATCH] [FLTMGR] - Implement FltLoadFilter and stub FltUnloadFilter - Register contexts if the caller requests (coming later) - Stubpliment FltStartFiltering svn path=/trunk/; revision=72594 --- reactos/drivers/filters/fltmgr/Filter.c | 321 ++++++++++++++++++++++++ 1 file changed, 321 insertions(+) create mode 100644 reactos/drivers/filters/fltmgr/Filter.c diff --git a/reactos/drivers/filters/fltmgr/Filter.c b/reactos/drivers/filters/fltmgr/Filter.c new file mode 100644 index 00000000000..71e45aea040 --- /dev/null +++ b/reactos/drivers/filters/fltmgr/Filter.c @@ -0,0 +1,321 @@ +/* +* PROJECT: Filesystem Filter Manager +* LICENSE: GPL - See COPYING in the top level directory +* FILE: drivers/filters/fltmgr/Filter.c +* PURPOSE: Handles registration of mini filters +* PROGRAMMERS: Ged Murphy (gedmurphy@reactos.org) +*/ + +/* INCLUDES ******************************************************************/ + +#include "fltmgr.h" +#include "fltmgrint.h" + +#define NDEBUG +#include + + +/* DATA *********************************************************************/ + +#define SERVICES_KEY L"\\Registry\\Machine\\System\\CurrentControlSet\\Services\\" +#define MAX_KEY_LENGTH 0x200 + +NTSTATUS +FltpStartingToDrainObject( + _Inout_ PFLT_OBJECT Object +); + + +/* EXPORTED FUNCTIONS ******************************************************/ + +NTSTATUS +NTAPI +FltLoadFilter(_In_ PCUNICODE_STRING FilterName) +{ + UNICODE_STRING DriverServiceName; + UNICODE_STRING ServicesKey; + CHAR Buffer[MAX_KEY_LENGTH]; + + /* Setup the base services key */ + RtlInitUnicodeString(&ServicesKey, SERVICES_KEY); + + /* Initialize the string data */ + DriverServiceName.Length = 0; + DriverServiceName.Buffer = (PWCH)Buffer; + DriverServiceName.MaximumLength = MAX_KEY_LENGTH; + + /* Create the full service key for this filter */ + RtlCopyUnicodeString(&DriverServiceName, &ServicesKey); + RtlAppendUnicodeStringToString(&DriverServiceName, FilterName); + + /* Ask the kernel to load it for us */ + return ZwLoadDriver(&DriverServiceName); +} + +NTSTATUS +NTAPI +FltUnloadFilter(_In_ PCUNICODE_STRING FilterName) +{ + UNREFERENCED_PARAMETER(FilterName); + return STATUS_NOT_IMPLEMENTED; +} + +NTSTATUS +NTAPI +FltRegisterFilter(_In_ PDRIVER_OBJECT DriverObject, + _In_ const FLT_REGISTRATION *Registration, + _Out_ PFLT_FILTER *RetFilter) +{ + PFLT_OPERATION_REGISTRATION Callbacks; + PFLT_FILTER Filter; + ULONG CallbackBufferSize; + ULONG FilterBufferSize; + ULONG Count = 0; + PCHAR Ptr; + NTSTATUS Status; + + /* Make sure we're targeting the correct major revision */ + if ((Registration->Version & 0xFF00) != FLT_MAJOR_VERSION) + { + return STATUS_INVALID_PARAMETER; + } + + /* Make sure our namespace callbacks are valid */ + if ((!Registration->GenerateFileNameCallback && Registration->NormalizeNameComponentCallback) || + (!Registration->NormalizeNameComponentCallback && Registration->NormalizeContextCleanupCallback)) + { + return STATUS_INVALID_PARAMETER; + } + + /* Count the number of operations that were requested */ + Callbacks = (PFLT_OPERATION_REGISTRATION)Registration->OperationRegistration; + while (Callbacks) + { + Count++; + + /* Bail when we find the last one */ + if (Callbacks->MajorFunction == IRP_MJ_OPERATION_END) + break; + + /* Move to the next item */ + Callbacks++; + } + + /* Calculate the buffer sizes */ + CallbackBufferSize = Count * sizeof(FLT_OPERATION_REGISTRATION); + FilterBufferSize = sizeof(FLT_FILTER) + + CallbackBufferSize + + DriverObject->DriverExtension->ServiceKeyName.Length; + + /* Allocate a buffer to hold our filter data */ + Filter = ExAllocatePoolWithTag(NonPagedPool, + FilterBufferSize, + FM_TAG_FILTER); + if (Filter == NULL) return STATUS_INSUFFICIENT_RESOURCES; + RtlZeroMemory(Filter, FilterBufferSize); + + /* Find the end of the fixed struct */ + Ptr = (PCHAR)(Filter + 1); + + /* Store a copy of the driver object of this filter */ + Filter->DriverObject = DriverObject; + + /* Initialize the base object data */ + Filter->Base.Flags = FLT_OBFL_TYPE_FILTER; + Filter->Base.PointerCount = 1; + FltpExInitializeRundownProtection(&Filter->Base.RundownRef); + FltObjectReference(&Filter->Base); + + /* Set the callback addresses */ + Filter->FilterUnload = Registration->FilterUnloadCallback; + Filter->InstanceSetup = Registration->InstanceSetupCallback; + Filter->InstanceQueryTeardown = Registration->InstanceQueryTeardownCallback; + Filter->InstanceTeardownStart = Registration->InstanceTeardownStartCallback; + Filter->InstanceTeardownComplete = Registration->InstanceTeardownCompleteCallback; + Filter->GenerateFileName = Registration->GenerateFileNameCallback; + Filter->NormalizeNameComponent = Registration->NormalizeNameComponentCallback; + Filter->NormalizeContextCleanup = Registration->NormalizeContextCleanupCallback; + + /* Initialize the instance list */ + ExInitializeResourceLite(&Filter->InstanceList.rLock); + InitializeListHead(&Filter->InstanceList.rList); + Filter->InstanceList.rCount = 0; + + ExInitializeFastMutex(&Filter->ActiveOpens.mLock); + InitializeListHead(&Filter->ActiveOpens.mList); + Filter->ActiveOpens.mCount = 0; + + /* Initialize the usermode port list */ + ExInitializeFastMutex(&Filter->PortList.mLock); + InitializeListHead(&Filter->PortList.mList); + Filter->PortList.mCount = 0; + + /* We got this far, assume success from here */ + Status = STATUS_SUCCESS; + + /* Check if the caller requested any context data */ + if (Registration->ContextRegistration) + { + /* Register the contexts for this filter */ + Status = FltpRegisterContexts(Filter, Registration->ContextRegistration); + if (NT_SUCCESS(Status)) + { + goto Quit; + } + } + + /* Check if the caller is registering any callbacks */ + if (Registration->OperationRegistration) + { + /* The callback data comes after the fixed struct */ + Filter->Operations = (PFLT_OPERATION_REGISTRATION)Ptr; + Ptr += (Count * sizeof(FLT_OPERATION_REGISTRATION)); + + /* Tag the operation data onto the end of the filter data */ + RtlCopyMemory(Filter->Operations, Registration->OperationRegistration, CallbackBufferSize); + + /* walk through the requested callbacks */ + for (Callbacks = Filter->Operations; + Callbacks->MajorFunction != IRP_MJ_OPERATION_END; + Callbacks++) + { + // http://fsfilters.blogspot.co.uk/2011/03/how-file-system-filters-attach-to_17.html + /* Check if this is an attach to a volume */ + if (Callbacks->MajorFunction == IRP_MJ_VOLUME_MOUNT) + { + Filter->PreVolumeMount = Callbacks->PreOperation; + Filter->PostVolumeMount = Callbacks->PostOperation; + } + else if (Callbacks->MajorFunction == IRP_MJ_SHUTDOWN) + { + Callbacks->PostOperation = NULL; + } + } + } + + /* Add the filter name buffer onto the end of the data and fill in the string */ + Filter->Name.Length = 0; + Filter->Name.MaximumLength = DriverObject->DriverExtension->ServiceKeyName.Length; + Filter->Name.Buffer = (PWCH)Ptr; + RtlCopyUnicodeString(&Filter->Name, &DriverObject->DriverExtension->ServiceKeyName); + + // + // - Get the altitude string + // - Slot the filter into the correct altitude location + // - More stuff?? + // + +Quit: + if (!NT_SUCCESS(Status)) + { + // Add cleanup for context resources + + ExDeleteResourceLite(&Filter->InstanceList.rLock); + ExFreePoolWithTag(Filter, FM_TAG_FILTER); + } + + return Status; +} + +VOID +FLTAPI +FltUnregisterFilter(_In_ PFLT_FILTER Filter) +{ + PFLT_INSTANCE Instance; + PLIST_ENTRY CurrentEntry; + NTSTATUS Status; + + /* Set the draining flag */ + Status = FltpStartingToDrainObject(&Filter->Base); + if (!NT_SUCCESS(Status)) + { + /* Someone already unregistered us, just remove our ref and bail */ + FltObjectDereference(&Filter->Base); + return; + } + + /* Lock the instance list */ + KeEnterCriticalRegion(); + ExAcquireResourceSharedLite(&Filter->InstanceList.rLock, TRUE); + + /* Set the first entry in the list */ + CurrentEntry = Filter->InstanceList.rList.Flink; + + /* Free all instances referenced by the filter */ + while (CurrentEntry != &Filter->InstanceList.rList) + { + /* Get the record pointer */ + Instance = CONTAINING_RECORD(CurrentEntry, FLT_INSTANCE, FilterLink); + + // FIXME: implement + (void)Instance; + + /* Reset the pointer and move to next entry */ + Instance = NULL; + CurrentEntry = CurrentEntry->Flink; + } + + /* We're done with instances now */ + ExReleaseResourceLite(&Filter->InstanceList.rLock); + KeLeaveCriticalRegion(); + + /* Remove the reference from the base object */ + FltObjectDereference(&Filter->Base); + + /* Wait until we're sure nothing is using the filter */ + FltpObjectRundownWait(&Filter->Base.RundownRef); + + /* Delete the instance list lock */ + ExDeleteResourceLite(&Filter->InstanceList.rLock); + + /* We're finished cleaning up now */ + FltpExRundownCompleted(&Filter->Base.RundownRef); + + /* Hand the memory back */ + ExFreePoolWithTag(Filter, FM_TAG_FILTER); +} + +NTSTATUS +NTAPI +FltStartFiltering(_In_ PFLT_FILTER Filter) +{ + NTSTATUS Status; + + /* Grab a ref to the filter */ + Status = FltObjectReference(&Filter->Base); + if (NT_SUCCESS(Status)) + { + /* Make sure we aren't already starting up */ + if (!(Filter->Flags & FLTFL_FILTERING_INITIATED)) + { + // Startup + } + else + { + Status = STATUS_INVALID_PARAMETER; + } + + FltObjectDereference(&Filter->Base); + } + + return Status; +} + + +/* INTERNAL FUNCTIONS ******************************************************/ + +NTSTATUS +FltpStartingToDrainObject(_Inout_ PFLT_OBJECT Object) +{ + /* + * Set the draining flag for the filter. This let's us force + * a post op callback for minifilters currently awaiting one. + */ + if (InterlockedOr((PLONG)&Object->Flags, FLT_OBFL_DRAINING) & 1) + { + /* We've been called once, we're already being deleted */ + return STATUS_FLT_DELETING_OBJECT; + } + + return STATUS_SUCCESS; +}