2 * PROJECT: ReactOS kernel-mode tests - Filter Manager
3 * LICENSE: GPLv2+ - See COPYING in the top level directory
4 * PURPOSE: FS Mini-filter wrapper to host the filter manager tests
5 * PROGRAMMER: Thomas Faber <thomas.faber@reactos.org>
6 * Ged Murphy <ged.murphy@reactos.org>
10 #include <ndk/ketypes.h>
11 #include <fltkernel.h>
13 #define KMT_DEFINE_TEST_FUNCTIONS
19 #include <kmt_public.h>
21 #define KMTEST_FILTER_POOL_TAG 'fTMK'
24 typedef struct _FILTER_DATA
26 PDRIVER_OBJECT DriverObject
;
27 FLT_REGISTRATION FilterRegistration
;
31 } FILTER_DATA
, *PFILTER_DATA
;
35 DRIVER_INITIALIZE DriverEntry
;
38 static PDRIVER_OBJECT TestDriverObject
;
39 static PDEVICE_OBJECT KmtestDeviceObject
;
40 static FILTER_DATA FilterData
;
41 static PFLT_OPERATION_REGISTRATION Callbacks
= NULL
;
42 static PFLT_CONTEXT_REGISTRATION Contexts
= NULL
;
44 static PFLT_CONNECT_NOTIFY FilterConnect
= NULL
;
45 static PFLT_DISCONNECT_NOTIFY FilterDisconnect
= NULL
;
46 static PFLT_MESSAGE_NOTIFY FilterMessage
= NULL
;
47 static LONG MaxConnections
= 0;
52 _In_ FLT_FILTER_UNLOAD_FLAGS Flags
58 _In_ PCFLT_RELATED_OBJECTS FltObjects
,
59 _In_ FLT_INSTANCE_SETUP_FLAGS Flags
,
60 _In_ DEVICE_TYPE VolumeDeviceType
,
61 _In_ FLT_FILESYSTEM_TYPE VolumeFilesystemType
67 _In_ PCFLT_RELATED_OBJECTS FltObjects
,
68 _In_ FLT_INSTANCE_QUERY_TEARDOWN_FLAGS Flags
71 FLT_PREOP_CALLBACK_STATUS
74 _Inout_ PFLT_CALLBACK_DATA Data
,
75 _In_ PCFLT_RELATED_OBJECTS FltObjects
,
76 _Outptr_result_maybenull_ PVOID
*CompletionContext
79 FLT_POSTOP_CALLBACK_STATUS
82 _Inout_ PFLT_CALLBACK_DATA Data
,
83 _In_ PCFLT_RELATED_OBJECTS FltObjects
,
84 _In_opt_ PVOID CompletionContext
,
85 _In_ FLT_POST_OPERATION_FLAGS Flags
90 FLT_REGISTRATION FilterRegistration
=
92 sizeof(FLT_REGISTRATION
), // Size
93 FLT_REGISTRATION_VERSION
, // Version
95 NULL
, // ContextRegistration
96 NULL
, // OperationRegistration
97 FilterUnload
, // FilterUnloadCallback
98 FilterInstanceSetup
, // InstanceSetupCallback
99 FilterQueryTeardown
, // InstanceQueryTeardownCallback
100 NULL
, // InstanceTeardownStartCallback
101 NULL
, // InstanceTeardownCompleteCallback
102 NULL
, // AmFilterGenerateFileNameCallback
103 NULL
, // AmFilterNormalizeNameComponentCallback
104 NULL
, // NormalizeContextCleanupCallback
106 NULL
, // TransactionNotificationCallback
107 NULL
, // AmFilterNormalizeNameComponentExCallback
113 /* Filter Interface Routines ****************************/
118 * Driver entry point.
120 * @param DriverObject
122 * @param RegistryPath
123 * Driver Registry Path
130 IN PDRIVER_OBJECT DriverObject
,
131 IN PUNICODE_STRING RegistryPath
)
133 NTSTATUS Status
= STATUS_SUCCESS
;
134 OBJECT_ATTRIBUTES ObjectAttributes
;
135 PSECURITY_DESCRIPTOR SecurityDescriptor
;
136 UNICODE_STRING DeviceName
;
137 WCHAR DeviceNameBuffer
[128] = L
"\\Device\\Kmtest-";
138 UNICODE_STRING KmtestDeviceName
;
139 PFILE_OBJECT KmtestFileObject
;
140 PKMT_DEVICE_EXTENSION KmtestDeviceExtension
;
141 PCWSTR DeviceNameSuffix
;
147 DPRINT("DriverEntry\n");
149 RtlZeroMemory(&FilterData
, sizeof(FILTER_DATA
));
151 Prcb
= KeGetCurrentPrcb();
152 KmtIsCheckedBuild
= (Prcb
->BuildType
& PRCB_BUILD_DEBUG
) != 0;
153 KmtIsMultiProcessorBuild
= (Prcb
->BuildType
& PRCB_BUILD_UNIPROCESSOR
) == 0;
154 TestDriverObject
= DriverObject
;
156 /* get the Kmtest device, so that we get a ResultBuffer pointer */
157 RtlInitUnicodeString(&KmtestDeviceName
, KMTEST_DEVICE_DRIVER_PATH
);
158 Status
= IoGetDeviceObjectPointer(&KmtestDeviceName
, FILE_ALL_ACCESS
, &KmtestFileObject
, &KmtestDeviceObject
);
160 if (!NT_SUCCESS(Status
))
162 DPRINT1("Failed to get Kmtest device object pointer\n");
166 Status
= ObReferenceObjectByPointer(KmtestDeviceObject
, FILE_ALL_ACCESS
, NULL
, KernelMode
);
168 if (!NT_SUCCESS(Status
))
170 DPRINT1("Failed to reference Kmtest device object\n");
174 ObDereferenceObject(KmtestFileObject
);
175 KmtestFileObject
= NULL
;
176 KmtestDeviceExtension
= KmtestDeviceObject
->DeviceExtension
;
177 ResultBuffer
= KmtestDeviceExtension
->ResultBuffer
;
178 DPRINT("KmtestDeviceObject: %p\n", (PVOID
)KmtestDeviceObject
);
179 DPRINT("KmtestDeviceExtension: %p\n", (PVOID
)KmtestDeviceExtension
);
180 DPRINT("Setting ResultBuffer: %p\n", (PVOID
)ResultBuffer
);
184 RtlInitUnicodeString(&DeviceName
, DeviceNameBuffer
);
185 DeviceName
.MaximumLength
= sizeof DeviceNameBuffer
;
186 TestEntry(DriverObject
, RegistryPath
, &DeviceNameSuffix
, &Flags
);
188 RtlAppendUnicodeToString(&DeviceName
, DeviceNameSuffix
);
190 /* Register with the filter manager */
191 if (!(Flags
& TESTENTRY_NO_REGISTER_FILTER
))
193 Status
= FltRegisterFilter(DriverObject
,
196 if (!NT_SUCCESS(Status
))
198 DPRINT1("Failed to register the filter driver %wZ\n", &DeviceName
);
203 if (!(Flags
& TESTENTRY_NO_CREATE_COMMS_PORT
))
205 /* Create a security descriptor */
206 Status
= FltBuildDefaultSecurityDescriptor(&SecurityDescriptor
,
207 FLT_PORT_ALL_ACCESS
);
208 if (!NT_SUCCESS(Status
))
213 /* Initialize the security descriptor object */
214 InitializeObjectAttributes(&ObjectAttributes
,
216 OBJ_KERNEL_HANDLE
| OBJ_CASE_INSENSITIVE
,
221 /* Create the usermode communication port */
222 Status
= FltCreateCommunicationPort(FilterData
.Filter
,
223 &FilterData
.ServerPort
,
231 /* Free the security descriptor */
232 FltFreeSecurityDescriptor(SecurityDescriptor
);
234 if (!NT_SUCCESS(Status
))
240 if (!(Flags
& TESTENTRY_NO_START_FILTERING
))
242 /* Start filtering the requests */
243 Status
= FltStartFiltering(FilterData
.Filter
);
247 if (!NT_SUCCESS(Status
))
249 if (FilterData
.ServerPort
)
251 FltCloseCommunicationPort(FilterData
.ServerPort
);
253 if (FilterData
.Filter
)
255 FltUnregisterFilter(FilterData
.Filter
);
265 * Driver cleanup funtion.
268 * Flags describing the unload request
273 _In_ FLT_FILTER_UNLOAD_FLAGS Flags
)
276 UNREFERENCED_PARAMETER(Flags
);
279 DPRINT("DriverUnload\n");
281 TestFilterUnload(Flags
);
283 /* Close the port and unregister the filter */
284 if (FilterData
.ServerPort
)
286 FltCloseCommunicationPort(FilterData
.ServerPort
);
287 FilterData
.ServerPort
= NULL
;
289 if (FilterData
.Filter
)
291 FltUnregisterFilter(FilterData
.Filter
);
292 FilterData
.Filter
= NULL
;
297 ExFreePoolWithTag(Callbacks
, KMTEST_FILTER_POOL_TAG
);
301 return STATUS_SUCCESS
;
306 * @name FilterInstanceSetup
308 * Volume attach routine
311 * Filter Object Pointers
312 * Pointer to an FLT_RELATED_OBJECTS structure that contains opaque pointers
313 * for the objects related to the current operation
315 * Bitmask of flags that indicate why the instance is being attached
316 * @param VolumeDeviceType
317 * Device type of the file system volume
318 * @param VolumeFilesystemType
319 * File system type of the volume
322 * Return STATUS_SUCCESS to attach or STATUS_FLT_DO_NOT_ATTACH to ignore
327 _In_ PCFLT_RELATED_OBJECTS FltObjects
,
328 _In_ FLT_INSTANCE_SETUP_FLAGS Flags
,
329 _In_ DEVICE_TYPE VolumeDeviceType
,
330 _In_ FLT_FILESYSTEM_TYPE VolumeFilesystemType
)
333 UCHAR VolPropBuffer
[sizeof(FLT_VOLUME_PROPERTIES
) + 512];
334 PFLT_VOLUME_PROPERTIES VolumeProperties
= (PFLT_VOLUME_PROPERTIES
)VolPropBuffer
;
336 PDEVICE_OBJECT DeviceObject
= NULL
;
337 UNICODE_STRING VolumeName
;
338 ULONG ReportedSectorSize
= 0;
339 ULONG SectorSize
= 0;
344 UNREFERENCED_PARAMETER(FltObjects
);
345 UNREFERENCED_PARAMETER(Flags
);
347 if (!(Flags
& TESTENTRY_NO_INSTANCE_SETUP
))
349 RtlInitUnicodeString(&VolumeName
, NULL
);
351 #if 0 // FltGetVolumeProperties is not yet implemented
352 /* Get the properties of this volume */
353 Status
= FltGetVolumeProperties(Volume
,
355 sizeof(VolPropBuffer
),
357 if (NT_SUCCESS(Status
))
359 FLT_ASSERT((VolumeProperties
->SectorSize
== 0) || (VolumeProperties
->SectorSize
>= MIN_SECTOR_SIZE
));
360 SectorSize
= max(VolumeProperties
->SectorSize
, MIN_SECTOR_SIZE
);
361 ReportedSectorSize
= VolumeProperties
->SectorSize
;
365 DPRINT1("Failed to get the volume properties : 0x%X", Status
);
369 /* Get the storage device object we want a name for */
370 Status
= FltGetDiskDeviceObject(FltObjects
->Volume
, &DeviceObject
);
371 if (NT_SUCCESS(Status
))
373 /* Get the dos device name */
374 Status
= IoVolumeDeviceToDosName(DeviceObject
, &VolumeName
);
375 if (NT_SUCCESS(Status
))
377 DPRINT("VolumeDeviceType %lu, VolumeFilesystemType %lu, Real SectSize=0x%04x, Reported SectSize=0x%04x, Name=\"%wZ\"",
379 VolumeFilesystemType
,
384 Status
= TestInstanceSetup(FltObjects
,
387 VolumeFilesystemType
,
392 /* The buffer was allocated by the IoMgr */
393 ExFreePool(VolumeName
.Buffer
);
403 * @name FilterQueryTeardown
405 * Volume detatch routine
408 * Filter Object Pointers
409 * Pointer to an FLT_RELATED_OBJECTS structure that contains opaque pointers
410 * for the objects related to the current operation
412 * Flag that indicates why the minifilter driver instance is being torn down
418 _In_ PCFLT_RELATED_OBJECTS FltObjects
,
419 _In_ FLT_INSTANCE_QUERY_TEARDOWN_FLAGS Flags
)
423 if (!(Flags
& TESTENTRY_NO_QUERY_TEARDOWN
))
425 TestQueryTeardown(FltObjects
, Flags
);
428 /* We always allow a volume to detach */
429 return STATUS_SUCCESS
;
433 /* Public Routines **************************************/
436 KmtFilterRegisterCallbacks(
437 _In_ CONST FLT_OPERATION_REGISTRATION
*OperationRegistration
)
444 return STATUS_ALREADY_REGISTERED
;
447 /* Count how many IRPs being registered */
448 for (i
= 0; i
< IRP_MJ_MAXIMUM_FUNCTION
; i
++)
450 if (OperationRegistration
[i
].MajorFunction
== IRP_MJ_OPERATION_END
)
455 /* Allocate enough pool to hold a copy of the array */
456 Callbacks
= ExAllocatePoolWithTag(NonPagedPool
,
457 sizeof(FLT_OPERATION_REGISTRATION
) * (Count
+ 1),
458 KMTEST_FILTER_POOL_TAG
);
459 if (Callbacks
== NULL
)
461 return STATUS_INSUFFICIENT_RESOURCES
;
464 /* Copy the array, but using the our own pre/post callbacks */
465 for (i
= 0; i
< Count
; i
++)
467 Callbacks
[i
].MajorFunction
= OperationRegistration
[i
].MajorFunction
;
468 Callbacks
[i
].Flags
= OperationRegistration
[i
].Flags
;
469 Callbacks
[i
].PreOperation
= FilterPreOperation
;
470 Callbacks
[i
].PostOperation
= FilterPostOperation
;
473 /* Terminate the array */
474 Callbacks
[Count
].MajorFunction
= IRP_MJ_OPERATION_END
;
476 return STATUS_SUCCESS
;
480 KmtFilterRegisterContexts(
481 _In_ PFLT_CONTEXT_REGISTRATION ContextRegistration
,
484 UNREFERENCED_PARAMETER(ContextRegistration
);
485 UNREFERENCED_PARAMETER(Callback
);
486 UNREFERENCED_PARAMETER(Contexts
);
487 return STATUS_NOT_IMPLEMENTED
;
491 KmtFilterRegisterComms(
492 _In_ PFLT_CONNECT_NOTIFY ConnectNotifyCallback
,
493 _In_ PFLT_DISCONNECT_NOTIFY DisconnectNotifyCallback
,
494 _In_opt_ PFLT_MESSAGE_NOTIFY MessageNotifyCallback
,
495 _In_ LONG MaxClientConnections
)
497 FilterConnect
= ConnectNotifyCallback
;
498 FilterDisconnect
= DisconnectNotifyCallback
;
499 FilterMessage
= MessageNotifyCallback
;
500 MaxConnections
= MaxClientConnections
;
502 return STATUS_SUCCESS
;
506 /* Private Routines ******************************************/
508 FLT_PREOP_CALLBACK_STATUS
511 _Inout_ PFLT_CALLBACK_DATA Data
,
512 _In_ PCFLT_RELATED_OBJECTS FltObjects
,
513 _Outptr_result_maybenull_ PVOID
*CompletionContext
)
515 FLT_PREOP_CALLBACK_STATUS Status
;
519 Status
= FLT_PREOP_SUCCESS_NO_CALLBACK
;
520 MajorFunction
= Data
->Iopb
->MajorFunction
;
522 for (i
= 0; i
< sizeof(Callbacks
) / sizeof(Callbacks
[0]); i
++)
524 if (MajorFunction
== Callbacks
[i
].MajorFunction
)
526 // Call their pre-callback
527 Status
= Callbacks
[i
].PreOperation(Data
,
536 FLT_POSTOP_CALLBACK_STATUS
539 _Inout_ PFLT_CALLBACK_DATA Data
,
540 _In_ PCFLT_RELATED_OBJECTS FltObjects
,
541 _In_opt_ PVOID CompletionContext
,
542 _In_ FLT_POST_OPERATION_FLAGS Flags
)
544 FLT_POSTOP_CALLBACK_STATUS Status
;
548 Status
= FLT_POSTOP_FINISHED_PROCESSING
;
549 MajorFunction
= Data
->Iopb
->MajorFunction
;
551 for (i
= 0; i
< sizeof(Callbacks
) / sizeof(Callbacks
[0]); i
++)
553 if (MajorFunction
== Callbacks
[i
].MajorFunction
)
555 // Call their post-callback
556 Status
= Callbacks
[i
].PostOperation(Data
,