[FLTMGR] Latest from my branch (#135)
[reactos.git] / modules / rostests / kmtests / kmtest_drv / kmtest_fsminifilter.c
1 /*
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>
7 */
8
9 #include <ntifs.h>
10 #include <ndk/ketypes.h>
11 #include <fltkernel.h>
12
13 #define KMT_DEFINE_TEST_FUNCTIONS
14 #include <kmt_test.h>
15
16 #define NDEBUG
17 #include <debug.h>
18
19 #include <kmt_public.h>
20
21 #define KMTEST_FILTER_POOL_TAG 'fTMK'
22
23
24 typedef struct _FILTER_DATA
25 {
26 PDRIVER_OBJECT DriverObject;
27 FLT_REGISTRATION FilterRegistration;
28 PFLT_FILTER Filter;
29 PFLT_PORT ServerPort;
30
31 } FILTER_DATA, *PFILTER_DATA;
32
33
34 /* Prototypes */
35 DRIVER_INITIALIZE DriverEntry;
36
37 /* Globals */
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;
43
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;
48
49 NTSTATUS
50 FLTAPI
51 FilterUnload(
52 _In_ FLT_FILTER_UNLOAD_FLAGS Flags
53 );
54
55 NTSTATUS
56 FLTAPI
57 FilterInstanceSetup(
58 _In_ PCFLT_RELATED_OBJECTS FltObjects,
59 _In_ FLT_INSTANCE_SETUP_FLAGS Flags,
60 _In_ DEVICE_TYPE VolumeDeviceType,
61 _In_ FLT_FILESYSTEM_TYPE VolumeFilesystemType
62 );
63
64 NTSTATUS
65 FLTAPI
66 FilterQueryTeardown(
67 _In_ PCFLT_RELATED_OBJECTS FltObjects,
68 _In_ FLT_INSTANCE_QUERY_TEARDOWN_FLAGS Flags
69 );
70
71 FLT_PREOP_CALLBACK_STATUS
72 FLTAPI
73 FilterPreOperation(
74 _Inout_ PFLT_CALLBACK_DATA Data,
75 _In_ PCFLT_RELATED_OBJECTS FltObjects,
76 _Outptr_result_maybenull_ PVOID *CompletionContext
77 );
78
79 FLT_POSTOP_CALLBACK_STATUS
80 FLTAPI
81 FilterPostOperation(
82 _Inout_ PFLT_CALLBACK_DATA Data,
83 _In_ PCFLT_RELATED_OBJECTS FltObjects,
84 _In_opt_ PVOID CompletionContext,
85 _In_ FLT_POST_OPERATION_FLAGS Flags
86 );
87
88
89
90 FLT_REGISTRATION FilterRegistration =
91 {
92 sizeof(FLT_REGISTRATION), // Size
93 FLT_REGISTRATION_VERSION, // Version
94 0, // Flags
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
105 #if FLT_MGR_LONGHORN
106 NULL, // TransactionNotificationCallback
107 NULL, // AmFilterNormalizeNameComponentExCallback
108 #endif
109 };
110
111
112
113 /* Filter Interface Routines ****************************/
114
115 /**
116 * @name DriverEntry
117 *
118 * Driver entry point.
119 *
120 * @param DriverObject
121 * Driver Object
122 * @param RegistryPath
123 * Driver Registry Path
124 *
125 * @return Status
126 */
127 NTSTATUS
128 NTAPI
129 DriverEntry(
130 IN PDRIVER_OBJECT DriverObject,
131 IN PUNICODE_STRING RegistryPath)
132 {
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;
142 INT Flags = 0;
143 PKPRCB Prcb;
144
145 PAGED_CODE();
146 //__debugbreak();
147 DPRINT("DriverEntry\n");
148
149 RtlZeroMemory(&FilterData, sizeof(FILTER_DATA));
150
151 Prcb = KeGetCurrentPrcb();
152 KmtIsCheckedBuild = (Prcb->BuildType & PRCB_BUILD_DEBUG) != 0;
153 KmtIsMultiProcessorBuild = (Prcb->BuildType & PRCB_BUILD_UNIPROCESSOR) == 0;
154 TestDriverObject = DriverObject;
155
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);
159
160 if (!NT_SUCCESS(Status))
161 {
162 DPRINT1("Failed to get Kmtest device object pointer\n");
163 goto cleanup;
164 }
165
166 Status = ObReferenceObjectByPointer(KmtestDeviceObject, FILE_ALL_ACCESS, NULL, KernelMode);
167
168 if (!NT_SUCCESS(Status))
169 {
170 DPRINT1("Failed to reference Kmtest device object\n");
171 goto cleanup;
172 }
173
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);
181
182
183 /* call TestEntry */
184 RtlInitUnicodeString(&DeviceName, DeviceNameBuffer);
185 DeviceName.MaximumLength = sizeof DeviceNameBuffer;
186 TestEntry(DriverObject, RegistryPath, &DeviceNameSuffix, &Flags);
187
188 RtlAppendUnicodeToString(&DeviceName, DeviceNameSuffix);
189
190 /* Register with the filter manager */
191 if (!(Flags & TESTENTRY_NO_REGISTER_FILTER))
192 {
193 Status = FltRegisterFilter(DriverObject,
194 &FilterRegistration,
195 &FilterData.Filter);
196 if (!NT_SUCCESS(Status))
197 {
198 DPRINT1("Failed to register the filter driver %wZ\n", &DeviceName);
199 goto cleanup;
200 }
201 }
202
203 if (!(Flags & TESTENTRY_NO_CREATE_COMMS_PORT))
204 {
205 /* Create a security descriptor */
206 Status = FltBuildDefaultSecurityDescriptor(&SecurityDescriptor,
207 FLT_PORT_ALL_ACCESS);
208 if (!NT_SUCCESS(Status))
209 {
210 goto cleanup;
211 }
212
213 /* Initialize the security descriptor object */
214 InitializeObjectAttributes(&ObjectAttributes,
215 &DeviceName,
216 OBJ_KERNEL_HANDLE | OBJ_CASE_INSENSITIVE,
217 NULL,
218 SecurityDescriptor);
219
220
221 /* Create the usermode communication port */
222 Status = FltCreateCommunicationPort(FilterData.Filter,
223 &FilterData.ServerPort,
224 &ObjectAttributes,
225 NULL,
226 FilterConnect,
227 FilterDisconnect,
228 FilterMessage,
229 MaxConnections);
230
231 /* Free the security descriptor */
232 FltFreeSecurityDescriptor(SecurityDescriptor);
233
234 if (!NT_SUCCESS(Status))
235 {
236 goto cleanup;
237 }
238 }
239
240 if (!(Flags & TESTENTRY_NO_START_FILTERING))
241 {
242 /* Start filtering the requests */
243 Status = FltStartFiltering(FilterData.Filter);
244 }
245
246 cleanup:
247 if (!NT_SUCCESS(Status))
248 {
249 if (FilterData.ServerPort)
250 {
251 FltCloseCommunicationPort(FilterData.ServerPort);
252 }
253 if (FilterData.Filter)
254 {
255 FltUnregisterFilter(FilterData.Filter);
256 }
257 }
258
259 return Status;
260 }
261
262 /**
263 * @name DriverUnload
264 *
265 * Driver cleanup funtion.
266 *
267 * @param Flags
268 * Flags describing the unload request
269 */
270 NTSTATUS
271 FLTAPI
272 FilterUnload(
273 _In_ FLT_FILTER_UNLOAD_FLAGS Flags)
274 {
275 PAGED_CODE();
276 UNREFERENCED_PARAMETER(Flags);
277 //__debugbreak();
278
279 DPRINT("DriverUnload\n");
280
281 TestFilterUnload(Flags);
282
283 /* Close the port and unregister the filter */
284 if (FilterData.ServerPort)
285 {
286 FltCloseCommunicationPort(FilterData.ServerPort);
287 FilterData.ServerPort = NULL;
288 }
289 if (FilterData.Filter)
290 {
291 FltUnregisterFilter(FilterData.Filter);
292 FilterData.Filter = NULL;
293 }
294
295 if (Callbacks)
296 {
297 ExFreePoolWithTag(Callbacks, KMTEST_FILTER_POOL_TAG);
298 Callbacks = NULL;
299 }
300
301 return STATUS_SUCCESS;
302 }
303
304
305 /**
306 * @name FilterInstanceSetup
307 *
308 * Volume attach routine
309 *
310 * @param FltObjects
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
314 * @param Flags
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
320 *
321 * @return Status.
322 * Return STATUS_SUCCESS to attach or STATUS_FLT_DO_NOT_ATTACH to ignore
323 */
324 NTSTATUS
325 FLTAPI
326 FilterInstanceSetup(
327 _In_ PCFLT_RELATED_OBJECTS FltObjects,
328 _In_ FLT_INSTANCE_SETUP_FLAGS Flags,
329 _In_ DEVICE_TYPE VolumeDeviceType,
330 _In_ FLT_FILESYSTEM_TYPE VolumeFilesystemType)
331 {
332 #if 0
333 UCHAR VolPropBuffer[sizeof(FLT_VOLUME_PROPERTIES) + 512];
334 PFLT_VOLUME_PROPERTIES VolumeProperties = (PFLT_VOLUME_PROPERTIES)VolPropBuffer;
335 #endif
336 PDEVICE_OBJECT DeviceObject = NULL;
337 UNICODE_STRING VolumeName;
338 ULONG ReportedSectorSize = 0;
339 ULONG SectorSize = 0;
340 NTSTATUS Status;
341
342 PAGED_CODE();
343
344 UNREFERENCED_PARAMETER(FltObjects);
345 UNREFERENCED_PARAMETER(Flags);
346
347 if (!(Flags & TESTENTRY_NO_INSTANCE_SETUP))
348 {
349 RtlInitUnicodeString(&VolumeName, NULL);
350
351 #if 0 // FltGetVolumeProperties is not yet implemented
352 /* Get the properties of this volume */
353 Status = FltGetVolumeProperties(Volume,
354 VolumeProperties,
355 sizeof(VolPropBuffer),
356 &LengthReturned);
357 if (NT_SUCCESS(Status))
358 {
359 FLT_ASSERT((VolumeProperties->SectorSize == 0) || (VolumeProperties->SectorSize >= MIN_SECTOR_SIZE));
360 SectorSize = max(VolumeProperties->SectorSize, MIN_SECTOR_SIZE);
361 ReportedSectorSize = VolumeProperties->SectorSize;
362 }
363 else
364 {
365 DPRINT1("Failed to get the volume properties : 0x%X", Status);
366 return Status;
367 }
368 #endif
369 /* Get the storage device object we want a name for */
370 Status = FltGetDiskDeviceObject(FltObjects->Volume, &DeviceObject);
371 if (NT_SUCCESS(Status))
372 {
373 /* Get the dos device name */
374 Status = IoVolumeDeviceToDosName(DeviceObject, &VolumeName);
375 if (NT_SUCCESS(Status))
376 {
377 DPRINT("VolumeDeviceType %lu, VolumeFilesystemType %lu, Real SectSize=0x%04x, Reported SectSize=0x%04x, Name=\"%wZ\"",
378 VolumeDeviceType,
379 VolumeFilesystemType,
380 SectorSize,
381 ReportedSectorSize,
382 &VolumeName);
383
384 Status = TestInstanceSetup(FltObjects,
385 Flags,
386 VolumeDeviceType,
387 VolumeFilesystemType,
388 &VolumeName,
389 SectorSize,
390 ReportedSectorSize);
391
392 /* The buffer was allocated by the IoMgr */
393 ExFreePool(VolumeName.Buffer);
394 }
395 }
396 }
397
398 return Status;
399 }
400
401
402 /**
403 * @name FilterQueryTeardown
404 *
405 * Volume detatch routine
406 *
407 * @param FltObjects
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
411 * @param Flags
412 * Flag that indicates why the minifilter driver instance is being torn down
413 *
414 */
415 NTSTATUS
416 FLTAPI
417 FilterQueryTeardown(
418 _In_ PCFLT_RELATED_OBJECTS FltObjects,
419 _In_ FLT_INSTANCE_QUERY_TEARDOWN_FLAGS Flags)
420 {
421 PAGED_CODE();
422
423 if (!(Flags & TESTENTRY_NO_QUERY_TEARDOWN))
424 {
425 TestQueryTeardown(FltObjects, Flags);
426 }
427
428 /* We always allow a volume to detach */
429 return STATUS_SUCCESS;
430 }
431
432
433 /* Public Routines **************************************/
434
435 NTSTATUS
436 KmtFilterRegisterCallbacks(
437 _In_ CONST FLT_OPERATION_REGISTRATION *OperationRegistration)
438 {
439 ULONG Count = 0;
440 INT i;
441
442 if (Callbacks)
443 {
444 return STATUS_ALREADY_REGISTERED;
445 }
446
447 /* Count how many IRPs being registered */
448 for (i = 0; i < IRP_MJ_MAXIMUM_FUNCTION; i++)
449 {
450 if (OperationRegistration[i].MajorFunction == IRP_MJ_OPERATION_END)
451 break;
452 Count++;
453 }
454
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)
460 {
461 return STATUS_INSUFFICIENT_RESOURCES;
462 }
463
464 /* Copy the array, but using the our own pre/post callbacks */
465 for (i = 0; i < Count; i++)
466 {
467 Callbacks[i].MajorFunction = OperationRegistration[i].MajorFunction;
468 Callbacks[i].Flags = OperationRegistration[i].Flags;
469 Callbacks[i].PreOperation = FilterPreOperation;
470 Callbacks[i].PostOperation = FilterPostOperation;
471 }
472
473 /* Terminate the array */
474 Callbacks[Count].MajorFunction = IRP_MJ_OPERATION_END;
475
476 return STATUS_SUCCESS;
477 }
478
479 NTSTATUS
480 KmtFilterRegisterContexts(
481 _In_ PFLT_CONTEXT_REGISTRATION ContextRegistration,
482 _In_ PVOID Callback)
483 {
484 UNREFERENCED_PARAMETER(ContextRegistration);
485 UNREFERENCED_PARAMETER(Callback);
486 UNREFERENCED_PARAMETER(Contexts);
487 return STATUS_NOT_IMPLEMENTED;
488 }
489
490 NTSTATUS
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)
496 {
497 FilterConnect = ConnectNotifyCallback;
498 FilterDisconnect = DisconnectNotifyCallback;
499 FilterMessage = MessageNotifyCallback;
500 MaxConnections = MaxClientConnections;
501
502 return STATUS_SUCCESS;
503 }
504
505
506 /* Private Routines ******************************************/
507
508 FLT_PREOP_CALLBACK_STATUS
509 FLTAPI
510 FilterPreOperation(
511 _Inout_ PFLT_CALLBACK_DATA Data,
512 _In_ PCFLT_RELATED_OBJECTS FltObjects,
513 _Outptr_result_maybenull_ PVOID *CompletionContext)
514 {
515 FLT_PREOP_CALLBACK_STATUS Status;
516 UCHAR MajorFunction;
517 INT i;
518
519 Status = FLT_PREOP_SUCCESS_NO_CALLBACK;
520 MajorFunction = Data->Iopb->MajorFunction;
521
522 for (i = 0; i < sizeof(Callbacks) / sizeof(Callbacks[0]); i++)
523 {
524 if (MajorFunction == Callbacks[i].MajorFunction)
525 {
526 // Call their pre-callback
527 Status = Callbacks[i].PreOperation(Data,
528 FltObjects,
529 CompletionContext);
530 }
531 }
532
533 return Status;
534 }
535
536 FLT_POSTOP_CALLBACK_STATUS
537 FLTAPI
538 FilterPostOperation(
539 _Inout_ PFLT_CALLBACK_DATA Data,
540 _In_ PCFLT_RELATED_OBJECTS FltObjects,
541 _In_opt_ PVOID CompletionContext,
542 _In_ FLT_POST_OPERATION_FLAGS Flags)
543 {
544 FLT_POSTOP_CALLBACK_STATUS Status;
545 UCHAR MajorFunction;
546 INT i;
547
548 Status = FLT_POSTOP_FINISHED_PROCESSING;
549 MajorFunction = Data->Iopb->MajorFunction;
550
551 for (i = 0; i < sizeof(Callbacks) / sizeof(Callbacks[0]); i++)
552 {
553 if (MajorFunction == Callbacks[i].MajorFunction)
554 {
555 // Call their post-callback
556 Status = Callbacks[i].PostOperation(Data,
557 FltObjects,
558 CompletionContext,
559 Flags);
560 }
561 }
562
563 return Status;
564 }