https://git.reactos.org/?p=reactos.git;a=commitdiff;h=9d15fb927941f29a88559…
commit 9d15fb927941f29a8855944fa68376b1fec9b77e
Author: Ged Murphy <gedmurphy(a)gmail.com>
AuthorDate: Thu Oct 12 15:32:30 2017 +0100
Start to implement fltmgr tests [WIP] (#52)
[FLTMGR]
- Partially implement registering contexts
- Add a misc file which contains stubs of the APIs needed in the test suite
- Export some APIs needed by the test suite
[KMTESTS]
- Create a File System Mini-filter wrapper to host drivers for the filter manager
tests
- Add a test file which will be used for testing that mini-filters load correctly
- Add a test file which will be used to write tests for IRP_MJ_CREATE requests
---
drivers/filters/CMakeLists.txt | 2 +-
drivers/filters/fltmgr/CMakeLists.txt | 1 +
drivers/filters/fltmgr/Context.c | 103 +++-
drivers/filters/fltmgr/Interface.c | 12 +
drivers/filters/fltmgr/Messaging.c | 2 +-
drivers/filters/fltmgr/Misc.c | 56 +++
drivers/filters/fltmgr/fltmgr.spec | 7 +-
modules/rostests/kmtests/CMakeLists.txt | 1 +
modules/rostests/kmtests/fltmgr/CMakeLists.txt | 3 +
.../kmtests/fltmgr/fltmgr_create/CMakeLists.txt | 14 +
.../kmtests/fltmgr/fltmgr_create/fltmgr_create.c | 147 ++++++
.../kmtests/fltmgr/fltmgr_load/CMakeLists.txt | 14 +
.../kmtests/fltmgr/fltmgr_load/fltmgr_load.c | 234 +++++++++
modules/rostests/kmtests/include/kmt_platform.h | 3 +
modules/rostests/kmtests/include/kmt_test.h | 23 +
.../kmtests/kmtest_drv/kmtest_fsminifilter.c | 525 +++++++++++++++++++++
16 files changed, 1139 insertions(+), 8 deletions(-)
diff --git a/drivers/filters/CMakeLists.txt b/drivers/filters/CMakeLists.txt
index 7b70050409..2d135dd919 100644
--- a/drivers/filters/CMakeLists.txt
+++ b/drivers/filters/CMakeLists.txt
@@ -1,2 +1,2 @@
-#add_subdirectory(fltmgr)
+add_subdirectory(fltmgr)
add_subdirectory(mountmgr)
diff --git a/drivers/filters/fltmgr/CMakeLists.txt
b/drivers/filters/fltmgr/CMakeLists.txt
index ea527186d2..f3d52e2200 100644
--- a/drivers/filters/fltmgr/CMakeLists.txt
+++ b/drivers/filters/fltmgr/CMakeLists.txt
@@ -5,6 +5,7 @@ list(APPEND SOURCE
Interface.c
Lib.c
Messaging.c
+ Misc.c
Object.c
${CMAKE_CURRENT_BINARY_DIR}/fltmgr.def
fltmgr.h)
diff --git a/drivers/filters/fltmgr/Context.c b/drivers/filters/fltmgr/Context.c
index ead64cda27..7e6d03c62c 100644
--- a/drivers/filters/fltmgr/Context.c
+++ b/drivers/filters/fltmgr/Context.c
@@ -27,7 +27,7 @@ static
NTSTATUS
SetupContextHeader(
_In_ PFLT_FILTER Filter,
- _In_ PFLT_CONTEXT_REGISTRATION ContextPtr,
+ _In_ PCFLT_CONTEXT_REGISTRATION ContextPtr,
_Out_ PALLOCATE_CONTEXT_HEADER ContextHeader
);
@@ -43,9 +43,102 @@ NTSTATUS
FltpRegisterContexts(_In_ PFLT_FILTER Filter,
_In_ const FLT_CONTEXT_REGISTRATION *Context)
{
- UNREFERENCED_PARAMETER(Filter);
- UNREFERENCED_PARAMETER(Context);
- return STATUS_NOT_IMPLEMENTED;
+ PCFLT_CONTEXT_REGISTRATION ContextPtr;
+ PALLOCATE_CONTEXT_HEADER ContextHeader, Prev;
+ PVOID Buffer;
+ ULONG BufferSize = 0;
+ USHORT i;
+ NTSTATUS Status;
+
+ /* Loop through all entries in the context registration array */
+ ContextPtr = Context;
+ while (ContextPtr)
+ {
+ /* Bail if we found the terminator */
+ if (ContextPtr->ContextType == FLT_CONTEXT_END)
+ break;
+
+ /* Make sure we have a valid context */
+ if (IsContextTypeValid(ContextPtr->ContextType))
+ {
+ /* Each context is backed by a crtl struct. Reserve space for it */
+ BufferSize += sizeof(STREAM_LIST_CTRL);
+ }
+
+ /* Move to the next entry */
+ ContextPtr++;
+ }
+
+ /* Bail if we found no valid registration requests */
+ if (BufferSize == 0)
+ {
+ return STATUS_SUCCESS;
+ }
+
+ /* Allocate the pool that'll hold the context crtl structs */
+ Buffer = ExAllocatePoolWithTag(NonPagedPool, BufferSize, FM_TAG_CONTEXT_REGISTA);
+ if (!Buffer) return STATUS_INSUFFICIENT_RESOURCES;
+
+ RtlZeroMemory(Buffer, BufferSize);
+
+ /* Setup our loop data */
+ ContextHeader = Buffer;
+ Prev = NULL;
+ Status = STATUS_SUCCESS;
+
+ for (i = 0; i < MAX_CONTEXT_TYPES; i++)
+ {
+ ContextPtr = (PFLT_CONTEXT_REGISTRATION)Context;
+ while (ContextPtr)
+ {
+ /* We don't support variable sized contents yet */
+ FLT_ASSERT(ContextPtr->Size != FLT_VARIABLE_SIZED_CONTEXTS);
+
+ /* Bail if we found the terminator */
+ if (ContextPtr->ContextType == FLT_CONTEXT_END)
+ break;
+
+ /* Size and pooltag are only checked when ContextAllocateCallback is null */
+ if (ContextPtr->ContextAllocateCallback == FALSE &&
ContextPtr->PoolTag == FALSE)
+ {
+ Status = STATUS_FLT_INVALID_CONTEXT_REGISTRATION;
+ goto Quit;
+ }
+
+ /* Make sure we have a valid context */
+ if (IsContextTypeValid(ContextPtr->ContextType))
+ {
+ Status = SetupContextHeader(Filter, ContextPtr, ContextHeader);
+ if (NT_SUCCESS(Status))
+ {
+ if (Prev)
+ {
+ Prev->Next = ContextHeader;
+ }
+
+ Filter->SupportedContexts[i] = ContextHeader;
+ }
+ }
+
+ Prev = ContextHeader;
+
+ /* Move to the next entry */
+ ContextPtr++;
+ }
+ }
+
+Quit:
+ if (NT_SUCCESS(Status))
+ {
+ Filter->SupportedContextsListHead = Buffer;
+ }
+ else
+ {
+ ExFreePoolWithTag(Buffer, FM_TAG_CONTEXT_REGISTA);
+ //FIXME: Cleanup anything that SetupContextHeader may have allocated
+ }
+
+ return Status;
}
@@ -72,7 +165,7 @@ IsContextTypeValid(_In_ FLT_CONTEXT_TYPE ContextType)
static
NTSTATUS
SetupContextHeader(_In_ PFLT_FILTER Filter,
- _In_ PFLT_CONTEXT_REGISTRATION ContextPtr,
+ _In_ PCFLT_CONTEXT_REGISTRATION ContextPtr,
_Out_ PALLOCATE_CONTEXT_HEADER ContextHeader)
{
return 0;
diff --git a/drivers/filters/fltmgr/Interface.c b/drivers/filters/fltmgr/Interface.c
index 7854000b8b..be1288a7c2 100644
--- a/drivers/filters/fltmgr/Interface.c
+++ b/drivers/filters/fltmgr/Interface.c
@@ -17,6 +17,18 @@
/* DATA *********************************************************************/
+#define VALID_FAST_IO_DISPATCH_HANDLER(_FastIoDispatchPtr, _FieldName) \
+ (((_FastIoDispatchPtr) != NULL) && \
+ (((_FastIoDispatchPtr)->SizeOfFastIoDispatch) >= \
+ (FIELD_OFFSET(FAST_IO_DISPATCH, _FieldName) + sizeof(void *))) && \
+ ((_FastIoDispatchPtr)->_FieldName != NULL))
+
+#define IS_MY_DEVICE_OBJECT(_devObj) \
+ (((_devObj) != NULL) && \
+ ((_devObj)->DriverObject == Dispatcher::DriverObject) && \
+ ((_devObj)->DeviceExtension != NULL))
+
+
DRIVER_INITIALIZE DriverEntry;
NTSTATUS
NTAPI
diff --git a/drivers/filters/fltmgr/Messaging.c b/drivers/filters/fltmgr/Messaging.c
index e6e4473fab..97e6a94c9c 100644
--- a/drivers/filters/fltmgr/Messaging.c
+++ b/drivers/filters/fltmgr/Messaging.c
@@ -125,7 +125,7 @@ FltCreateCommunicationPort(_In_ PFLT_FILTER Filter,
FltObjectDereference(Filter);
}
- return STATUS_NOT_IMPLEMENTED;
+ return Status;
}
_IRQL_requires_max_(PASSIVE_LEVEL)
diff --git a/drivers/filters/fltmgr/Misc.c b/drivers/filters/fltmgr/Misc.c
new file mode 100644
index 0000000000..3ef1424d5f
--- /dev/null
+++ b/drivers/filters/fltmgr/Misc.c
@@ -0,0 +1,56 @@
+/*
+ * PROJECT: Filesystem Filter Manager
+ * LICENSE: GPL - See COPYING in the top level directory
+ * FILE: drivers/filters/fltmgr/Misc.c
+ * PURPOSE: Uncataloged functions
+ * PROGRAMMERS: Ged Murphy (gedmurphy(a)reactos.org)
+ */
+
+/* INCLUDES ******************************************************************/
+
+#include "fltmgr.h"
+#include "fltmgrint.h"
+
+#define NDEBUG
+#include <debug.h>
+
+
+/* DATA *********************************************************************/
+
+
+
+
+/* EXPORTED FUNCTIONS ******************************************************/
+
+NTSTATUS
+FLTAPI
+FltBuildDefaultSecurityDescriptor(
+ _Outptr_ PSECURITY_DESCRIPTOR *SecurityDescriptor,
+ _In_ ACCESS_MASK DesiredAccess
+)
+{
+ UNREFERENCED_PARAMETER(SecurityDescriptor);
+ UNREFERENCED_PARAMETER(DesiredAccess);
+ return 0;
+}
+
+VOID
+FLTAPI
+FltFreeSecurityDescriptor(
+ _In_ PSECURITY_DESCRIPTOR SecurityDescriptor
+)
+{
+ UNREFERENCED_PARAMETER(SecurityDescriptor);
+}
+
+NTSTATUS
+FLTAPI
+FltGetDiskDeviceObject(
+ _In_ PFLT_VOLUME Volume,
+ _Outptr_ PDEVICE_OBJECT *DiskDeviceObject
+)
+{
+ UNREFERENCED_PARAMETER(Volume);
+ UNREFERENCED_PARAMETER(DiskDeviceObject);
+ return 0;
+}
\ No newline at end of file
diff --git a/drivers/filters/fltmgr/fltmgr.spec b/drivers/filters/fltmgr/fltmgr.spec
index 2967a05d7a..9e18cd5997 100644
--- a/drivers/filters/fltmgr/fltmgr.spec
+++ b/drivers/filters/fltmgr/fltmgr.spec
@@ -2,4 +2,9 @@
@ stdcall FltRegisterFilter(ptr ptr ptr)
@ stdcall FltUnregisterFilter(ptr)
@ stdcall FltCloseCommunicationPort(ptr)
-
+ @ stdcall FltStartFiltering(ptr)
+ @ stdcall FltCreateCommunicationPort(ptr ptr ptr ptr ptr ptr ptr long)
+ @ stdcall FltBuildDefaultSecurityDescriptor(ptr long)
+ @ stdcall FltFreeSecurityDescriptor(ptr)
+ @ stdcall FltGetDiskDeviceObject(ptr ptr)
+
diff --git a/modules/rostests/kmtests/CMakeLists.txt
b/modules/rostests/kmtests/CMakeLists.txt
index dfc6c98d0a..d51ef000c7 100644
--- a/modules/rostests/kmtests/CMakeLists.txt
+++ b/modules/rostests/kmtests/CMakeLists.txt
@@ -5,6 +5,7 @@ include_directories(include)
# subdirectories containing special-purpose drivers
#
add_subdirectory(example)
+add_subdirectory(fltmgr)
add_subdirectory(hidparse)
add_subdirectory(kernel32)
add_subdirectory(ntos_cc)
diff --git a/modules/rostests/kmtests/fltmgr/CMakeLists.txt
b/modules/rostests/kmtests/fltmgr/CMakeLists.txt
new file mode 100644
index 0000000000..fd7a55e6bc
--- /dev/null
+++ b/modules/rostests/kmtests/fltmgr/CMakeLists.txt
@@ -0,0 +1,3 @@
+
+add_subdirectory(fltmgr_load)
+add_subdirectory(fltmgr_create)
diff --git a/modules/rostests/kmtests/fltmgr/fltmgr_create/CMakeLists.txt
b/modules/rostests/kmtests/fltmgr/fltmgr_create/CMakeLists.txt
new file mode 100644
index 0000000000..435293967e
--- /dev/null
+++ b/modules/rostests/kmtests/fltmgr/fltmgr_create/CMakeLists.txt
@@ -0,0 +1,14 @@
+
+include_directories(../../include)
+
+list(APPEND FLTMGR_TEST_DRV_SOURCE
+ ../../kmtest_drv/kmtest_fsminifilter.c
+ fltmgr_create.c)
+
+add_library(fltmgr_create SHARED ${FLTMGR_TEST_DRV_SOURCE})
+set_module_type(fltmgr_create kernelmodedriver)
+target_link_libraries(fltmgr_create kmtest_printf ${PSEH_LIB})
+add_importlibs(fltmgr_create fltmgr ntoskrnl hal)
+add_target_compile_definitions(fltmgr_create KMT_STANDALONE_DRIVER KMT_FILTER_DRIVER
NTDDI_VERSION=NTDDI_WS03SP1)
+#add_pch(example_drv ../include/kmt_test.h)
+add_rostests_file(TARGET fltmgr_create)
diff --git a/modules/rostests/kmtests/fltmgr/fltmgr_create/fltmgr_create.c
b/modules/rostests/kmtests/fltmgr/fltmgr_create/fltmgr_create.c
new file mode 100644
index 0000000000..6c28f3ef18
--- /dev/null
+++ b/modules/rostests/kmtests/fltmgr/fltmgr_create/fltmgr_create.c
@@ -0,0 +1,147 @@
+/*
+ * PROJECT: ReactOS kernel-mode tests - Filter Manager
+ * LICENSE: GPLv2+ - See COPYING in the top level directory
+ * PURPOSE: Tests for checking the create operations
+ * PROGRAMMER: Ged Murphy <gedmurphy(a)reactos.org>
+ */
+
+#include <kmt_test.h>
+#include <fltkernel.h>
+
+//#define NDEBUG
+#include <debug.h>
+
+/* prototypes */
+static
+FLT_PREOP_CALLBACK_STATUS
+FLTAPI
+TestFilterPreOperation(
+ _Inout_ PFLT_CALLBACK_DATA Data,
+ _In_ PCFLT_RELATED_OBJECTS FltObjects,
+ _Outptr_result_maybenull_ PVOID *CompletionContext
+);
+
+static
+FLT_POSTOP_CALLBACK_STATUS
+FLTAPI
+TestFilterPostOperation(
+ _Inout_ PFLT_CALLBACK_DATA Data,
+ _In_ PCFLT_RELATED_OBJECTS FltObjects,
+ _In_opt_ PVOID CompletionContext,
+ _In_ FLT_POST_OPERATION_FLAGS Flags
+);
+
+
+/* Globals */
+static PDRIVER_OBJECT TestDriverObject;
+
+
+CONST FLT_OPERATION_REGISTRATION Callbacks[] =
+{
+ { IRP_MJ_CREATE,
+ 0,
+ TestFilterPreOperation,
+ TestFilterPostOperation },
+
+ { IRP_MJ_OPERATION_END }
+};
+
+
+NTSTATUS
+TestEntry(
+ IN PDRIVER_OBJECT DriverObject,
+ IN PCUNICODE_STRING RegistryPath,
+ OUT PCWSTR *DeviceName,
+ IN OUT INT *Flags)
+{
+ NTSTATUS Status = STATUS_SUCCESS;
+
+ PAGED_CODE();
+
+ UNREFERENCED_PARAMETER(RegistryPath);
+ UNREFERENCED_PARAMETER(Flags);
+
+ DPRINT("Entry!\n");
+
+ ok_irql(PASSIVE_LEVEL);
+ TestDriverObject = DriverObject;
+
+ *DeviceName = L"fltmgr_create";
+
+ trace("Hi, this is the filter manager create test driver\n");
+
+ (VOID)KmtFilterRegisterCallbacks(Callbacks);
+
+ return Status;
+}
+
+VOID
+TestFilterUnload(
+ IN ULONG Flags)
+{
+ PAGED_CODE();
+
+ DPRINT("Unload!\n");
+
+ ok_irql(PASSIVE_LEVEL);
+
+ trace("Unloading filter manager test driver\n");
+}
+
+VOID
+TestQueryTeardown(
+ _In_ PCFLT_RELATED_OBJECTS FltObjects,
+ _In_ FLT_INSTANCE_QUERY_TEARDOWN_FLAGS Flags)
+{
+ UNREFERENCED_PARAMETER(FltObjects);
+ UNREFERENCED_PARAMETER(Flags);
+}
+
+NTSTATUS
+TestInstanceSetup(
+ _In_ PCFLT_RELATED_OBJECTS FltObjects,
+ _In_ FLT_INSTANCE_SETUP_FLAGS Flags,
+ _In_ DEVICE_TYPE VolumeDeviceType,
+ _In_ FLT_FILESYSTEM_TYPE VolumeFilesystemType,
+ _In_ PUNICODE_STRING VolumeName,
+ _In_ ULONG SectorSize,
+ _In_ ULONG ReportedSectorSize
+)
+{
+ trace("Received an attach request for VolumeType 0x%X, FileSystemType
%d\n",
+ VolumeDeviceType,
+ VolumeFilesystemType);
+
+ return STATUS_FLT_DO_NOT_ATTACH;
+}
+
+static
+FLT_PREOP_CALLBACK_STATUS
+FLTAPI
+TestFilterPreOperation(
+ _Inout_ PFLT_CALLBACK_DATA Data,
+ _In_ PCFLT_RELATED_OBJECTS FltObjects,
+ _Outptr_result_maybenull_ PVOID *CompletionContext)
+{
+ PFLT_IO_PARAMETER_BLOCK Iopb = Data->Iopb;
+
+ ok_eq_hex(Iopb->MajorFunction, IRP_MJ_CREATE);
+
+ return FLT_PREOP_SUCCESS_NO_CALLBACK;
+}
+
+static
+FLT_POSTOP_CALLBACK_STATUS
+FLTAPI
+TestFilterPostOperation(
+ _Inout_ PFLT_CALLBACK_DATA Data,
+ _In_ PCFLT_RELATED_OBJECTS FltObjects,
+ _In_opt_ PVOID CompletionContext,
+ _In_ FLT_POST_OPERATION_FLAGS Flags)
+{
+ PFLT_IO_PARAMETER_BLOCK Iopb = Data->Iopb;
+
+ ok_eq_hex(Iopb->MajorFunction, IRP_MJ_CREATE);
+
+ return FLT_POSTOP_FINISHED_PROCESSING;
+}
\ No newline at end of file
diff --git a/modules/rostests/kmtests/fltmgr/fltmgr_load/CMakeLists.txt
b/modules/rostests/kmtests/fltmgr/fltmgr_load/CMakeLists.txt
new file mode 100644
index 0000000000..7fa022d154
--- /dev/null
+++ b/modules/rostests/kmtests/fltmgr/fltmgr_load/CMakeLists.txt
@@ -0,0 +1,14 @@
+
+include_directories(../../include)
+
+list(APPEND FLTMGR_TEST_DRV_SOURCE
+ ../../kmtest_drv/kmtest_fsminifilter.c
+ fltmgr_load.c)
+
+add_library(fltmgr_load SHARED ${FLTMGR_TEST_DRV_SOURCE})
+set_module_type(fltmgr_load kernelmodedriver)
+target_link_libraries(fltmgr_load kmtest_printf ${PSEH_LIB})
+add_importlibs(fltmgr_load fltmgr ntoskrnl hal)
+add_target_compile_definitions(fltmgr_load KMT_STANDALONE_DRIVER KMT_FILTER_DRIVER
NTDDI_VERSION=NTDDI_WS03SP1)
+#add_pch(example_drv ../include/kmt_test.h)
+add_rostests_file(TARGET fltmgr_load)
diff --git a/modules/rostests/kmtests/fltmgr/fltmgr_load/fltmgr_load.c
b/modules/rostests/kmtests/fltmgr/fltmgr_load/fltmgr_load.c
new file mode 100644
index 0000000000..7b9f5235cb
--- /dev/null
+++ b/modules/rostests/kmtests/fltmgr/fltmgr_load/fltmgr_load.c
@@ -0,0 +1,234 @@
+/*
+ * PROJECT: ReactOS kernel-mode tests - Filter Manager
+ * LICENSE: GPLv2+ - See COPYING in the top level directory
+ * PURPOSE: Tests for checking filters load correctly
+ * PROGRAMMER: Ged Murphy <gedmurphy(a)reactos.org>
+ */
+
+#include <kmt_test.h>
+#include <fltkernel.h>
+
+//#define NDEBUG
+#include <debug.h>
+
+/* prototypes */
+NTSTATUS
+FLTAPI
+TestClientConnect(
+ _In_ PFLT_PORT ClientPort,
+ _In_opt_ PVOID ServerPortCookie,
+ _In_reads_bytes_opt_(SizeOfContext) PVOID ConnectionContext,
+ _In_ ULONG SizeOfContext,
+ _Outptr_result_maybenull_ PVOID *ConnectionPortCookie
+);
+
+VOID
+FLTAPI
+TestClientDisconnect(
+ _In_opt_ PVOID ConnectionCookie
+);
+
+NTSTATUS
+FLTAPI
+TestMessageHandler(
+ _In_opt_ PVOID ConnectionCookie,
+ _In_reads_bytes_opt_(InputBufferLength) PVOID InputBuffer,
+ _In_ ULONG InputBufferLength,
+ _Out_writes_bytes_to_opt_(OutputBufferLength, *ReturnOutputBufferLength) PVOID
OutputBuffer,
+ _In_ ULONG OutputBufferLength,
+ _Out_ PULONG ReturnOutputBufferLength
+);
+
+
+/* Globals */
+static PDRIVER_OBJECT TestDriverObject;
+
+
+
+/**
+ * @name TestEntry
+ *
+ * Test entry point.
+ * This is called by DriverEntry as early as possible, but with ResultBuffer
+ * initialized, so that test macros work correctly
+ *
+ * @param DriverObject
+ * Driver Object.
+ * This is guaranteed not to have been touched by DriverEntry before
+ * the call to TestEntry
+ * @param RegistryPath
+ * Driver Registry Path
+ * This is guaranteed not to have been touched by DriverEntry before
+ * the call to TestEntry
+ * @param DeviceName
+ * Pointer to receive a test-specific name for the device to create
+ * @param Flags
+ * Pointer to a flags variable instructing DriverEntry how to proceed.
+ * See the KMT_TESTENTRY_FLAGS enumeration for possible values
+ * Initialized to zero on entry
+ *
+ * @return Status.
+ * DriverEntry will fail if this is a failure status
+ */
+NTSTATUS
+TestEntry(
+ IN PDRIVER_OBJECT DriverObject,
+ IN PCUNICODE_STRING RegistryPath,
+ OUT PCWSTR *DeviceName,
+ IN OUT INT *Flags)
+{
+ NTSTATUS Status = STATUS_SUCCESS;
+
+ PAGED_CODE();
+
+ UNREFERENCED_PARAMETER(RegistryPath);
+ UNREFERENCED_PARAMETER(Flags);
+
+ DPRINT("Entry!\n");
+
+ ok_irql(PASSIVE_LEVEL);
+ TestDriverObject = DriverObject;
+
+ *DeviceName = L"fltmgr_load";
+
+ trace("Hi, this is the filter manager load test driver\n");
+
+ KmtFilterRegisterComms(TestClientConnect, TestClientDisconnect, TestMessageHandler,
1);
+
+ return Status;
+}
+
+/**
+ * @name TestUnload
+ *
+ * Test unload routine.
+ * This is called by the driver's Unload routine as early as possible, with
+ * ResultBuffer and the test device object still valid, so that test macros
+ * work correctly
+ *
+ * @param DriverObject
+ * Driver Object.
+ * This is guaranteed not to have been touched by Unload before the call
+ * to TestEntry
+ *
+ * @return Status
+ */
+VOID
+TestFilterUnload(
+ IN ULONG Flags)
+{
+ PAGED_CODE();
+
+ DPRINT("Unload!\n");
+
+ ok_irql(PASSIVE_LEVEL);
+
+ trace("Unloading filter manager load test driver\n");
+}
+
+
+/**
+* @name TestInstanceSetup
+*
+* Test volume attach routine.
+* This is called by the driver's InstanceSetupCallback routine in response to
+* a new volume attaching.
+*
+* @param FltObjects
+* Filter Object Pointers
+* Pointer to an FLT_RELATED_OBJECTS structure that contains opaque pointers
+* for the objects related to the current operation
+* @param Flags
+* Bitmask of flags that indicate why the instance is being attached
+* @param VolumeDeviceType
+* Device type of the file system volume
+* @param VolumeFilesystemType
+* File system type of the volume
+* @param VolumeName
+* Unicode string containing the name of the volume.
+* The string is only valid within the context of this function
+* @param SectorSize
+* Adjusts the sector size to a minimum of 0x200, which is more reliable
+* @param ReportedSectorSize
+* Sector size of the volume as reported by the filter manager
+*
+* @return Status.
+* Return STATUS_SUCCESS to attach or STATUS_FLT_DO_NOT_ATTACH to ignore
+*/
+NTSTATUS
+TestInstanceSetup(
+ _In_ PCFLT_RELATED_OBJECTS FltObjects,
+ _In_ FLT_INSTANCE_SETUP_FLAGS Flags,
+ _In_ DEVICE_TYPE VolumeDeviceType,
+ _In_ FLT_FILESYSTEM_TYPE VolumeFilesystemType,
+ _In_ PUNICODE_STRING VolumeName,
+ _In_ ULONG SectorSize,
+ _In_ ULONG ReportedSectorSize
+)
+{
+ trace("Received an attach request for VolumeType 0x%X, FileSystemType
%d\n",
+ VolumeDeviceType,
+ VolumeFilesystemType);
+
+ /* We're not interested in attaching to any volumes in this test */
+ return STATUS_FLT_DO_NOT_ATTACH;
+}
+
+/**
+* @name TestQueryTeardown
+*
+* Test volume attach routine.
+* This is called by the driver's InstanceSetupCallback routine in response to
+* a new volume attaching.
+*
+* @param FltObjects
+* Filter Object Pointers
+* Pointer to an FLT_RELATED_OBJECTS structure that contains opaque pointers
+* for the objects related to the current operation
+* @param Flags
+* Flag that indicates why the minifilter driver instance is being torn down
+*
+*/
+VOID
+TestQueryTeardown(
+ _In_ PCFLT_RELATED_OBJECTS FltObjects,
+ _In_ FLT_INSTANCE_QUERY_TEARDOWN_FLAGS Flags)
+{
+ trace("Received a teardown request, Flags %lu\n", Flags);
+
+ UNREFERENCED_PARAMETER(FltObjects);
+ UNREFERENCED_PARAMETER(Flags);
+}
+
+NTSTATUS
+FLTAPI
+TestClientConnect(
+ _In_ PFLT_PORT ClientPort,
+ _In_opt_ PVOID ServerPortCookie,
+ _In_reads_bytes_opt_(SizeOfContext) PVOID ConnectionContext,
+ _In_ ULONG SizeOfContext,
+ _Outptr_result_maybenull_ PVOID *ConnectionPortCookie)
+{
+ return 0;
+}
+
+VOID
+FLTAPI
+TestClientDisconnect(
+ _In_opt_ PVOID ConnectionCookie)
+{
+
+}
+
+NTSTATUS
+FLTAPI
+TestMessageHandler(
+ _In_opt_ PVOID ConnectionCookie,
+ _In_reads_bytes_opt_(InputBufferLength) PVOID InputBuffer,
+ _In_ ULONG InputBufferLength,
+ _Out_writes_bytes_to_opt_(OutputBufferLength, *ReturnOutputBufferLength) PVOID
OutputBuffer,
+ _In_ ULONG OutputBufferLength,
+ _Out_ PULONG ReturnOutputBufferLength)
+{
+ return 0;
+}
diff --git a/modules/rostests/kmtests/include/kmt_platform.h
b/modules/rostests/kmtests/include/kmt_platform.h
index 4efdc583bb..9e732c397a 100644
--- a/modules/rostests/kmtests/include/kmt_platform.h
+++ b/modules/rostests/kmtests/include/kmt_platform.h
@@ -25,6 +25,9 @@
#include <ndk/obfuncs.h>
#include <ndk/sefuncs.h>
#include <ntstrsafe.h>
+#if defined KMT_FILTER_DRIVER
+#include <fltkernel.h>
+#endif
#elif defined KMT_USER_MODE
#define WIN32_NO_STATUS
diff --git a/modules/rostests/kmtests/include/kmt_test.h
b/modules/rostests/kmtests/include/kmt_test.h
index b2de5bc19a..5941676140 100644
--- a/modules/rostests/kmtests/include/kmt_test.h
+++ b/modules/rostests/kmtests/include/kmt_test.h
@@ -117,6 +117,29 @@ NTSTATUS TestEntry(IN PDRIVER_OBJECT DriverObject, IN
PCUNICODE_STRING RegistryP
VOID TestUnload(IN PDRIVER_OBJECT DriverObject);
#endif /* defined KMT_STANDALONE_DRIVER */
+#ifdef KMT_FILTER_DRIVER
+#ifndef KMT_KERNEL_MODE
+#define KMT_KERNEL_MODE
+#endif
+
+NTSTATUS KmtFilterRegisterCallbacks(_In_ CONST FLT_OPERATION_REGISTRATION
*OperationRegistration);
+
+typedef enum
+{
+ TESTENTRY_NO_REGISTER_FILTER = 1,
+ TESTENTRY_NO_CREATE_COMMS_PORT = 2,
+ TESTENTRY_NO_START_FILTERING = 4,
+} KMT_MINIFILTER_FLAGS;
+
+VOID TestFilterUnload(_In_ ULONG Flags);
+NTSTATUS TestInstanceSetup(_In_ PCFLT_RELATED_OBJECTS FltObjects, _In_
FLT_INSTANCE_SETUP_FLAGS Flags, _In_ DEVICE_TYPE VolumeDeviceType, _In_
FLT_FILESYSTEM_TYPE VolumeFilesystemType, _In_ PUNICODE_STRING VolumeName, _In_ ULONG
RealSectorSize, _In_ ULONG SectorSize);
+VOID TestQueryTeardown(_In_ PCFLT_RELATED_OBJECTS FltObjects, _In_
FLT_INSTANCE_QUERY_TEARDOWN_FLAGS Flags);
+
+NTSTATUS KmtFilterRegisterComms(_In_ PFLT_CONNECT_NOTIFY ConnectNotifyCallback, _In_
PFLT_DISCONNECT_NOTIFY DisconnectNotifyCallback, _In_opt_ PFLT_MESSAGE_NOTIFY
MessageNotifyCallback, _In_ LONG MaxClientConnections);
+
+#endif/* defined KMT_FILTER_DRIVER */
+
+
#ifdef KMT_KERNEL_MODE
/* Device Extension layout */
typedef struct
diff --git a/modules/rostests/kmtests/kmtest_drv/kmtest_fsminifilter.c
b/modules/rostests/kmtests/kmtest_drv/kmtest_fsminifilter.c
new file mode 100644
index 0000000000..2de7f3b159
--- /dev/null
+++ b/modules/rostests/kmtests/kmtest_drv/kmtest_fsminifilter.c
@@ -0,0 +1,525 @@
+/*
+ * PROJECT: ReactOS kernel-mode tests - Filter Manager
+ * LICENSE: GPLv2+ - See COPYING in the top level directory
+ * PURPOSE: FS Mini-filter wrapper to host the filter manager tests
+ * PROGRAMMER: Ged Murphy <ged.murphy(a)reactos.org>
+ */
+
+#include <ntifs.h>
+#include <ndk/ketypes.h>
+#include <fltkernel.h>
+
+#define KMT_DEFINE_TEST_FUNCTIONS
+#include <kmt_test.h>
+
+#define NDEBUG
+#include <debug.h>
+
+#include <kmt_public.h>
+
+#define KMTEST_FILTER_POOL_TAG 'fTMK'
+
+
+typedef struct _FILTER_DATA
+{
+ PDRIVER_OBJECT DriverObject;
+ FLT_REGISTRATION FilterRegistration;
+ PFLT_FILTER Filter;
+ PFLT_PORT ServerPort;
+
+} FILTER_DATA, *PFILTER_DATA;
+
+
+/* Prototypes */
+DRIVER_INITIALIZE DriverEntry;
+
+/* Globals */
+static PDRIVER_OBJECT TestDriverObject;
+static FILTER_DATA FilterData;
+static PFLT_OPERATION_REGISTRATION Callbacks = NULL;
+static PFLT_CONTEXT_REGISTRATION Contexts = NULL;
+
+static PFLT_CONNECT_NOTIFY FilterConnect = NULL;
+static PFLT_DISCONNECT_NOTIFY FilterDisconnect = NULL;
+static PFLT_MESSAGE_NOTIFY FilterMessage = NULL;
+static LONG MaxConnections = 0;
+
+NTSTATUS
+FLTAPI
+FilterUnload(
+ _In_ FLT_FILTER_UNLOAD_FLAGS Flags
+);
+
+NTSTATUS
+FLTAPI
+FilterInstanceSetup(
+ _In_ PCFLT_RELATED_OBJECTS FltObjects,
+ _In_ FLT_INSTANCE_SETUP_FLAGS Flags,
+ _In_ DEVICE_TYPE VolumeDeviceType,
+ _In_ FLT_FILESYSTEM_TYPE VolumeFilesystemType
+);
+
+NTSTATUS
+FLTAPI
+FilterQueryTeardown(
+ _In_ PCFLT_RELATED_OBJECTS FltObjects,
+ _In_ FLT_INSTANCE_QUERY_TEARDOWN_FLAGS Flags
+);
+
+FLT_PREOP_CALLBACK_STATUS
+FLTAPI
+FilterPreOperation(
+ _Inout_ PFLT_CALLBACK_DATA Data,
+ _In_ PCFLT_RELATED_OBJECTS FltObjects,
+ _Outptr_result_maybenull_ PVOID *CompletionContext
+);
+
+FLT_POSTOP_CALLBACK_STATUS
+FLTAPI
+FilterPostOperation(
+ _Inout_ PFLT_CALLBACK_DATA Data,
+ _In_ PCFLT_RELATED_OBJECTS FltObjects,
+ _In_opt_ PVOID CompletionContext,
+ _In_ FLT_POST_OPERATION_FLAGS Flags
+);
+
+
+
+FLT_REGISTRATION FilterRegistration =
+{
+ sizeof(FLT_REGISTRATION), // Size
+ FLT_REGISTRATION_VERSION, // Version
+ 0, // Flags
+ NULL, // ContextRegistration
+ NULL, // OperationRegistration
+ FilterUnload, // FilterUnloadCallback
+ FilterInstanceSetup, // InstanceSetupCallback
+ FilterQueryTeardown, // InstanceQueryTeardownCallback
+ NULL, // InstanceTeardownStartCallback
+ NULL, // InstanceTeardownCompleteCallback
+ NULL, // AmFilterGenerateFileNameCallback
+ NULL, // AmFilterNormalizeNameComponentCallback
+ NULL, // NormalizeContextCleanupCallback
+#if FLT_MGR_LONGHORN
+ NULL, // TransactionNotificationCallback
+ NULL, // AmFilterNormalizeNameComponentExCallback
+#endif
+};
+
+
+
+/* Filter Interface Routines ****************************/
+
+/**
+ * @name DriverEntry
+ *
+ * Driver entry point.
+ *
+ * @param DriverObject
+ * Driver Object
+ * @param RegistryPath
+ * Driver Registry Path
+ *
+ * @return Status
+ */
+NTSTATUS
+NTAPI
+DriverEntry(
+ IN PDRIVER_OBJECT DriverObject,
+ IN PUNICODE_STRING RegistryPath)
+{
+ NTSTATUS Status = STATUS_SUCCESS;
+ OBJECT_ATTRIBUTES ObjectAttributes;
+ PSECURITY_DESCRIPTOR SecurityDescriptor;
+ UNICODE_STRING DeviceName;
+ WCHAR DeviceNameBuffer[128] = L"\\Device\\Kmtest-";
+ PCWSTR DeviceNameSuffix;
+ INT Flags = 0;
+ PKPRCB Prcb;
+
+ PAGED_CODE();
+ //__debugbreak();
+ DPRINT("DriverEntry\n");
+
+ RtlZeroMemory(&FilterData, sizeof(FILTER_DATA));
+
+ Prcb = KeGetCurrentPrcb();
+ KmtIsCheckedBuild = (Prcb->BuildType & PRCB_BUILD_DEBUG) != 0;
+ KmtIsMultiProcessorBuild = (Prcb->BuildType & PRCB_BUILD_UNIPROCESSOR) == 0;
+ TestDriverObject = DriverObject;
+
+
+ /* call TestEntry */
+ RtlInitUnicodeString(&DeviceName, DeviceNameBuffer);
+ DeviceName.MaximumLength = sizeof DeviceNameBuffer;
+ TestEntry(DriverObject, RegistryPath, &DeviceNameSuffix, &Flags);
+
+ RtlAppendUnicodeToString(&DeviceName, DeviceNameSuffix);
+
+ /* Register with the filter manager */
+ if (!(Flags & TESTENTRY_NO_REGISTER_FILTER))
+ {
+ Status = FltRegisterFilter(DriverObject,
+ &FilterRegistration,
+ &FilterData.Filter);
+ if (!NT_SUCCESS(Status))
+ {
+ DPRINT1("Failed to register the filter driver %wZ\n",
&DeviceName);
+ goto cleanup;
+ }
+ }
+
+ if (!(Flags & TESTENTRY_NO_CREATE_COMMS_PORT))
+ {
+ /* Create a security descriptor */
+ Status = FltBuildDefaultSecurityDescriptor(&SecurityDescriptor,
+ FLT_PORT_ALL_ACCESS);
+ if (!NT_SUCCESS(Status))
+ {
+ goto cleanup;
+ }
+
+ /* Initialize the security descriptor object */
+ InitializeObjectAttributes(&ObjectAttributes,
+ &DeviceName,
+ OBJ_KERNEL_HANDLE | OBJ_CASE_INSENSITIVE,
+ NULL,
+ SecurityDescriptor);
+
+
+ /* Create the usermode communication port */
+ Status = FltCreateCommunicationPort(FilterData.Filter,
+ &FilterData.ServerPort,
+ &ObjectAttributes,
+ NULL,
+ FilterConnect,
+ FilterDisconnect,
+ FilterMessage,
+ MaxConnections);
+
+ /* Free the security descriptor */
+ FltFreeSecurityDescriptor(SecurityDescriptor);
+
+ if (!NT_SUCCESS(Status))
+ {
+ goto cleanup;
+ }
+ }
+
+ if (!(Flags & TESTENTRY_NO_START_FILTERING))
+ {
+ /* Start filtering the requests */
+ Status = FltStartFiltering(FilterData.Filter);
+ }
+
+cleanup:
+ if (!NT_SUCCESS(Status))
+ {
+ if (FilterData.ServerPort)
+ {
+ FltCloseCommunicationPort(FilterData.ServerPort);
+ }
+ if (FilterData.Filter)
+ {
+ FltUnregisterFilter(FilterData.Filter);
+ }
+ }
+
+ return Status;
+}
+
+/**
+ * @name DriverUnload
+ *
+ * Driver cleanup funtion.
+ *
+ * @param Flags
+ * Flags describing the unload request
+ */
+NTSTATUS
+FLTAPI
+FilterUnload(
+ _In_ FLT_FILTER_UNLOAD_FLAGS Flags)
+{
+ PAGED_CODE();
+ UNREFERENCED_PARAMETER(Flags);
+
+ DPRINT("DriverUnload\n");
+
+ TestFilterUnload(Flags);
+
+ /* Close the port and unregister the filter */
+ if (FilterData.ServerPort)
+ {
+ FltCloseCommunicationPort(FilterData.ServerPort);
+ FilterData.ServerPort = NULL;
+ }
+ if (FilterData.Filter)
+ {
+ FltUnregisterFilter(FilterData.Filter);
+ FilterData.Filter = NULL;
+ }
+
+ if (Callbacks)
+ {
+ ExFreePoolWithTag(Callbacks, KMTEST_FILTER_POOL_TAG);
+ Callbacks = NULL;
+ }
+
+ return STATUS_SUCCESS;
+}
+
+
+/**
+ * @name FilterInstanceSetup
+ *
+ * Volume attach routine
+ *
+ * @param FltObjects
+ * Filter Object Pointers
+ * Pointer to an FLT_RELATED_OBJECTS structure that contains opaque pointers
+ * for the objects related to the current operation
+ * @param Flags
+ * Bitmask of flags that indicate why the instance is being attached
+ * @param VolumeDeviceType
+ * Device type of the file system volume
+ * @param VolumeFilesystemType
+ * File system type of the volume
+ *
+ * @return Status.
+ * Return STATUS_SUCCESS to attach or STATUS_FLT_DO_NOT_ATTACH to ignore
+ */
+NTSTATUS
+FLTAPI
+FilterInstanceSetup(
+ _In_ PCFLT_RELATED_OBJECTS FltObjects,
+ _In_ FLT_INSTANCE_SETUP_FLAGS Flags,
+ _In_ DEVICE_TYPE VolumeDeviceType,
+ _In_ FLT_FILESYSTEM_TYPE VolumeFilesystemType)
+{
+#if 0
+ UCHAR VolPropBuffer[sizeof(FLT_VOLUME_PROPERTIES) + 512];
+ PFLT_VOLUME_PROPERTIES VolumeProperties = (PFLT_VOLUME_PROPERTIES)VolPropBuffer;
+#endif
+ PDEVICE_OBJECT DeviceObject = NULL;
+ UNICODE_STRING VolumeName;
+ ULONG ReportedSectorSize = 0;
+ ULONG SectorSize = 0;
+ NTSTATUS Status;
+
+ PAGED_CODE();
+
+ UNREFERENCED_PARAMETER(FltObjects);
+ UNREFERENCED_PARAMETER(Flags);
+
+ RtlInitUnicodeString(&VolumeName, NULL);
+#if 0 // FltGetVolumeProperties is not yet implemented
+ /* Get the properties of this volume */
+ Status = FltGetVolumeProperties(Volume,
+ VolumeProperties,
+ sizeof(VolPropBuffer),
+ &LengthReturned);
+ if (NT_SUCCESS(Status))
+ {
+ FLT_ASSERT((VolumeProperties->SectorSize == 0) ||
(VolumeProperties->SectorSize >= MIN_SECTOR_SIZE));
+ SectorSize = max(VolumeProperties->SectorSize, MIN_SECTOR_SIZE);
+ ReportedSectorSize = VolumeProperties->SectorSize;
+ }
+ else
+ {
+ DPRINT1("Failed to get the volume properties : 0x%X", Status);
+ return Status;
+ }
+#endif
+ /* Get the storage device object we want a name for */
+ Status = FltGetDiskDeviceObject(FltObjects->Volume, &DeviceObject);
+ if (NT_SUCCESS(Status))
+ {
+ /* Get the dos device name */
+ Status = IoVolumeDeviceToDosName(DeviceObject, &VolumeName);
+ if (NT_SUCCESS(Status))
+ {
+ DPRINT("VolumeDeviceType %lu, VolumeFilesystemType %lu, Real
SectSize=0x%04x, Reported SectSize=0x%04x, Name=\"%wZ\"",
+ VolumeDeviceType,
+ VolumeFilesystemType,
+ SectorSize,
+ ReportedSectorSize,
+ &VolumeName);
+
+ Status = TestInstanceSetup(FltObjects,
+ Flags,
+ VolumeDeviceType,
+ VolumeFilesystemType,
+ &VolumeName,
+ SectorSize,
+ ReportedSectorSize);
+
+ /* The buffer was allocated by the IoMgr */
+ ExFreePool(VolumeName.Buffer);
+ }
+ }
+
+ return Status;
+}
+
+
+/**
+ * @name FilterQueryTeardown
+ *
+ * Volume detatch routine
+ *
+ * @param FltObjects
+ * Filter Object Pointers
+ * Pointer to an FLT_RELATED_OBJECTS structure that contains opaque pointers
+ * for the objects related to the current operation
+ * @param Flags
+ * Flag that indicates why the minifilter driver instance is being torn down
+ *
+ */
+NTSTATUS
+FLTAPI
+FilterQueryTeardown(
+ _In_ PCFLT_RELATED_OBJECTS FltObjects,
+ _In_ FLT_INSTANCE_QUERY_TEARDOWN_FLAGS Flags)
+{
+ PAGED_CODE();
+
+ TestQueryTeardown(FltObjects, Flags);
+
+ /* We always allow a volume to detach */
+ return STATUS_SUCCESS;
+}
+
+
+/* Public Routines **************************************/
+
+NTSTATUS
+KmtFilterRegisterCallbacks(
+ _In_ CONST FLT_OPERATION_REGISTRATION *OperationRegistration)
+{
+ ULONG Count = 0;
+ INT i;
+
+ if (Callbacks)
+ {
+ return STATUS_ALREADY_REGISTERED;
+ }
+
+ /* Count how many IRPs being registered */
+ for (i = 0; i < IRP_MJ_MAXIMUM_FUNCTION; i++)
+ {
+ if (OperationRegistration[i].MajorFunction == IRP_MJ_OPERATION_END)
+ break;
+ Count++;
+ }
+
+ /* Allocate enough pool to hold a copy of the array */
+ Callbacks = ExAllocatePoolWithTag(NonPagedPool,
+ sizeof(FLT_OPERATION_REGISTRATION) * (Count + 1),
+ KMTEST_FILTER_POOL_TAG);
+ if (Callbacks == NULL)
+ {
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ /* Copy the array, but using the our own pre/post callbacks */
+ for (i = 0; i < Count; i++)
+ {
+ Callbacks[i].MajorFunction = OperationRegistration[i].MajorFunction;
+ Callbacks[i].Flags = OperationRegistration[i].Flags;
+ Callbacks[i].PreOperation = FilterPreOperation;
+ Callbacks[i].PostOperation = FilterPostOperation;
+ }
+
+ /* Terminate the array */
+ Callbacks[Count].MajorFunction = IRP_MJ_OPERATION_END;
+
+ return STATUS_SUCCESS;
+}
+
+NTSTATUS
+KmtFilterRegisterContexts(
+ _In_ PFLT_CONTEXT_REGISTRATION ContextRegistration,
+ _In_ PVOID Callback)
+{
+ UNREFERENCED_PARAMETER(ContextRegistration);
+ UNREFERENCED_PARAMETER(Callback);
+ UNREFERENCED_PARAMETER(Contexts);
+ return STATUS_NOT_IMPLEMENTED;
+}
+
+NTSTATUS
+KmtFilterRegisterComms(
+ _In_ PFLT_CONNECT_NOTIFY ConnectNotifyCallback,
+ _In_ PFLT_DISCONNECT_NOTIFY DisconnectNotifyCallback,
+ _In_opt_ PFLT_MESSAGE_NOTIFY MessageNotifyCallback,
+ _In_ LONG MaxClientConnections)
+{
+ FilterConnect = ConnectNotifyCallback;
+ FilterDisconnect = DisconnectNotifyCallback;
+ FilterMessage = MessageNotifyCallback;
+ MaxConnections = MaxClientConnections;
+
+ return STATUS_SUCCESS;
+}
+
+
+/* Private Routines ******************************************/
+
+FLT_PREOP_CALLBACK_STATUS
+FLTAPI
+FilterPreOperation(
+ _Inout_ PFLT_CALLBACK_DATA Data,
+ _In_ PCFLT_RELATED_OBJECTS FltObjects,
+ _Outptr_result_maybenull_ PVOID *CompletionContext)
+{
+ FLT_PREOP_CALLBACK_STATUS Status;
+ UCHAR MajorFunction;
+ INT i;
+
+ Status = FLT_PREOP_SUCCESS_NO_CALLBACK;
+ MajorFunction = Data->Iopb->MajorFunction;
+
+ for (i = 0; i < sizeof(Callbacks) / sizeof(Callbacks[0]); i++)
+ {
+ if (MajorFunction == Callbacks[i].MajorFunction)
+ {
+ // Call their pre-callback
+ Status = Callbacks[i].PreOperation(Data,
+ FltObjects,
+ CompletionContext);
+ }
+ }
+
+ return Status;
+}
+
+FLT_POSTOP_CALLBACK_STATUS
+FLTAPI
+FilterPostOperation(
+ _Inout_ PFLT_CALLBACK_DATA Data,
+ _In_ PCFLT_RELATED_OBJECTS FltObjects,
+ _In_opt_ PVOID CompletionContext,
+ _In_ FLT_POST_OPERATION_FLAGS Flags)
+{
+ FLT_POSTOP_CALLBACK_STATUS Status;
+ UCHAR MajorFunction;
+ INT i;
+
+ Status = FLT_POSTOP_FINISHED_PROCESSING;
+ MajorFunction = Data->Iopb->MajorFunction;
+
+ for (i = 0; i < sizeof(Callbacks) / sizeof(Callbacks[0]); i++)
+ {
+ if (MajorFunction == Callbacks[i].MajorFunction)
+ {
+ // Call their post-callback
+ Status = Callbacks[i].PostOperation(Data,
+ FltObjects,
+ CompletionContext,
+ Flags);
+ }
+ }
+
+ return Status;
+}