2 * PROJECT: Filesystem Filter Manager
3 * LICENSE: GPL - See COPYING in the top level directory
4 * FILE: drivers/filters/fltmgr/Filter.c
5 * PURPOSE: Handles registration of mini filters
6 * PROGRAMMERS: Ged Murphy (gedmurphy@reactos.org)
9 /* INCLUDES ******************************************************************/
12 #include "fltmgrint.h"
18 /* DATA *********************************************************************/
20 #define SERVICES_KEY L"\\Registry\\Machine\\System\\CurrentControlSet\\Services\\"
21 #define MAX_KEY_LENGTH 0x200
24 FltpStartingToDrainObject(
25 _Inout_ PFLT_OBJECT Object
29 /* EXPORTED FUNCTIONS ******************************************************/
33 FltLoadFilter(_In_ PCUNICODE_STRING FilterName
)
35 UNICODE_STRING DriverServiceName
;
36 UNICODE_STRING ServicesKey
;
37 CHAR Buffer
[MAX_KEY_LENGTH
];
39 /* Setup the base services key */
40 RtlInitUnicodeString(&ServicesKey
, SERVICES_KEY
);
42 /* Initialize the string data */
43 DriverServiceName
.Length
= 0;
44 DriverServiceName
.Buffer
= (PWCH
)Buffer
;
45 DriverServiceName
.MaximumLength
= MAX_KEY_LENGTH
;
47 /* Create the full service key for this filter */
48 RtlCopyUnicodeString(&DriverServiceName
, &ServicesKey
);
49 RtlAppendUnicodeStringToString(&DriverServiceName
, FilterName
);
51 /* Ask the kernel to load it for us */
52 return ZwLoadDriver(&DriverServiceName
);
57 FltUnloadFilter(_In_ PCUNICODE_STRING FilterName
)
59 UNREFERENCED_PARAMETER(FilterName
);
60 return STATUS_NOT_IMPLEMENTED
;
65 FltRegisterFilter(_In_ PDRIVER_OBJECT DriverObject
,
66 _In_
const FLT_REGISTRATION
*Registration
,
67 _Out_ PFLT_FILTER
*RetFilter
)
69 PFLT_OPERATION_REGISTRATION Callbacks
;
71 ULONG CallbackBufferSize
;
72 ULONG FilterBufferSize
;
77 /* Make sure we're targeting the correct major revision */
78 if ((Registration
->Version
& 0xFF00) != FLT_MAJOR_VERSION
)
80 return STATUS_INVALID_PARAMETER
;
83 /* Make sure our namespace callbacks are valid */
84 if ((!Registration
->GenerateFileNameCallback
&& Registration
->NormalizeNameComponentCallback
) ||
85 (!Registration
->NormalizeNameComponentCallback
&& Registration
->NormalizeContextCleanupCallback
))
87 return STATUS_INVALID_PARAMETER
;
90 /* Count the number of operations that were requested */
91 Callbacks
= (PFLT_OPERATION_REGISTRATION
)Registration
->OperationRegistration
;
96 /* Bail when we find the last one */
97 if (Callbacks
->MajorFunction
== IRP_MJ_OPERATION_END
)
100 /* Move to the next item */
104 /* Calculate the buffer sizes */
105 CallbackBufferSize
= Count
* sizeof(FLT_OPERATION_REGISTRATION
);
106 FilterBufferSize
= sizeof(FLT_FILTER
) +
108 DriverObject
->DriverExtension
->ServiceKeyName
.Length
;
110 /* Allocate a buffer to hold our filter data */
111 Filter
= ExAllocatePoolWithTag(NonPagedPool
,
114 if (Filter
== NULL
) return STATUS_INSUFFICIENT_RESOURCES
;
115 RtlZeroMemory(Filter
, FilterBufferSize
);
117 /* Find the end of the fixed struct */
118 Ptr
= (PCHAR
)(Filter
+ 1);
120 /* Store a copy of the driver object of this filter */
121 Filter
->DriverObject
= DriverObject
;
123 /* Initialize the base object data */
124 Filter
->Base
.Flags
= FLT_OBFL_TYPE_FILTER
;
125 Filter
->Base
.PointerCount
= 1;
126 FltpExInitializeRundownProtection(&Filter
->Base
.RundownRef
);
127 FltObjectReference(&Filter
->Base
);
129 /* Set the callback addresses */
130 Filter
->FilterUnload
= Registration
->FilterUnloadCallback
;
131 Filter
->InstanceSetup
= Registration
->InstanceSetupCallback
;
132 Filter
->InstanceQueryTeardown
= Registration
->InstanceQueryTeardownCallback
;
133 Filter
->InstanceTeardownStart
= Registration
->InstanceTeardownStartCallback
;
134 Filter
->InstanceTeardownComplete
= Registration
->InstanceTeardownCompleteCallback
;
135 Filter
->GenerateFileName
= Registration
->GenerateFileNameCallback
;
136 Filter
->NormalizeNameComponent
= Registration
->NormalizeNameComponentCallback
;
137 Filter
->NormalizeContextCleanup
= Registration
->NormalizeContextCleanupCallback
;
139 /* Initialize the instance list */
140 ExInitializeResourceLite(&Filter
->InstanceList
.rLock
);
141 InitializeListHead(&Filter
->InstanceList
.rList
);
142 Filter
->InstanceList
.rCount
= 0;
144 ExInitializeFastMutex(&Filter
->ActiveOpens
.mLock
);
145 InitializeListHead(&Filter
->ActiveOpens
.mList
);
146 Filter
->ActiveOpens
.mCount
= 0;
148 /* Initialize the usermode port list */
149 ExInitializeFastMutex(&Filter
->PortList
.mLock
);
150 InitializeListHead(&Filter
->PortList
.mList
);
151 Filter
->PortList
.mCount
= 0;
153 /* We got this far, assume success from here */
154 Status
= STATUS_SUCCESS
;
156 /* Check if the caller requested any context data */
157 if (Registration
->ContextRegistration
)
159 /* Register the contexts for this filter */
160 Status
= FltpRegisterContexts(Filter
, Registration
->ContextRegistration
);
161 if (NT_SUCCESS(Status
))
167 /* Check if the caller is registering any callbacks */
168 if (Registration
->OperationRegistration
)
170 /* The callback data comes after the fixed struct */
171 Filter
->Operations
= (PFLT_OPERATION_REGISTRATION
)Ptr
;
172 Ptr
+= (Count
* sizeof(FLT_OPERATION_REGISTRATION
));
174 /* Tag the operation data onto the end of the filter data */
175 RtlCopyMemory(Filter
->Operations
, Registration
->OperationRegistration
, CallbackBufferSize
);
177 /* walk through the requested callbacks */
178 for (Callbacks
= Filter
->Operations
;
179 Callbacks
->MajorFunction
!= IRP_MJ_OPERATION_END
;
182 // http://fsfilters.blogspot.co.uk/2011/03/how-file-system-filters-attach-to_17.html
183 /* Check if this is an attach to a volume */
184 if (Callbacks
->MajorFunction
== IRP_MJ_VOLUME_MOUNT
)
186 Filter
->PreVolumeMount
= Callbacks
->PreOperation
;
187 Filter
->PostVolumeMount
= Callbacks
->PostOperation
;
189 else if (Callbacks
->MajorFunction
== IRP_MJ_SHUTDOWN
)
191 Callbacks
->PostOperation
= NULL
;
196 /* Add the filter name buffer onto the end of the data and fill in the string */
197 Filter
->Name
.Length
= 0;
198 Filter
->Name
.MaximumLength
= DriverObject
->DriverExtension
->ServiceKeyName
.Length
;
199 Filter
->Name
.Buffer
= (PWCH
)Ptr
;
200 RtlCopyUnicodeString(&Filter
->Name
, &DriverObject
->DriverExtension
->ServiceKeyName
);
203 // - Get the altitude string
204 // - Slot the filter into the correct altitude location
209 if (!NT_SUCCESS(Status
))
211 // Add cleanup for context resources
213 ExDeleteResourceLite(&Filter
->InstanceList
.rLock
);
214 ExFreePoolWithTag(Filter
, FM_TAG_FILTER
);
222 FltUnregisterFilter(_In_ PFLT_FILTER Filter
)
224 PFLT_INSTANCE Instance
;
225 PLIST_ENTRY CurrentEntry
;
228 /* Set the draining flag */
229 Status
= FltpStartingToDrainObject(&Filter
->Base
);
230 if (!NT_SUCCESS(Status
))
232 /* Someone already unregistered us, just remove our ref and bail */
233 FltObjectDereference(&Filter
->Base
);
237 /* Lock the instance list */
238 KeEnterCriticalRegion();
239 ExAcquireResourceSharedLite(&Filter
->InstanceList
.rLock
, TRUE
);
241 /* Set the first entry in the list */
242 CurrentEntry
= Filter
->InstanceList
.rList
.Flink
;
244 /* Free all instances referenced by the filter */
245 while (CurrentEntry
!= &Filter
->InstanceList
.rList
)
247 /* Get the record pointer */
248 Instance
= CONTAINING_RECORD(CurrentEntry
, FLT_INSTANCE
, FilterLink
);
253 /* Reset the pointer and move to next entry */
255 CurrentEntry
= CurrentEntry
->Flink
;
258 /* We're done with instances now */
259 ExReleaseResourceLite(&Filter
->InstanceList
.rLock
);
260 KeLeaveCriticalRegion();
262 /* Remove the reference from the base object */
263 FltObjectDereference(&Filter
->Base
);
265 /* Wait until we're sure nothing is using the filter */
266 FltpObjectRundownWait(&Filter
->Base
.RundownRef
);
268 /* Delete the instance list lock */
269 ExDeleteResourceLite(&Filter
->InstanceList
.rLock
);
271 /* We're finished cleaning up now */
272 FltpExRundownCompleted(&Filter
->Base
.RundownRef
);
274 /* Hand the memory back */
275 ExFreePoolWithTag(Filter
, FM_TAG_FILTER
);
280 FltStartFiltering(_In_ PFLT_FILTER Filter
)
284 /* Grab a ref to the filter */
285 Status
= FltObjectReference(&Filter
->Base
);
286 if (NT_SUCCESS(Status
))
288 /* Make sure we aren't already starting up */
289 if (!(Filter
->Flags
& FLTFL_FILTERING_INITIATED
))
295 Status
= STATUS_INVALID_PARAMETER
;
298 FltObjectDereference(&Filter
->Base
);
305 /* INTERNAL FUNCTIONS ******************************************************/
308 FltpStartingToDrainObject(_Inout_ PFLT_OBJECT Object
)
311 * Set the draining flag for the filter. This let's us force
312 * a post op callback for minifilters currently awaiting one.
314 if (InterlockedOr((PLONG
)&Object
->Flags
, FLT_OBFL_DRAINING
) & 1)
316 /* We've been called once, we're already being deleted */
317 return STATUS_FLT_DELETING_OBJECT
;
320 return STATUS_SUCCESS
;