[FLTMGR]
[reactos.git] / reactos / drivers / filters / fltmgr / Registration.c
1 /*
2 * PROJECT: Filesystem Filter Manager
3 * LICENSE: GPL - See COPYING in the top level directory
4 * FILE: drivers/fs_minifilter/fltmgr/Registration.c
5 * PURPOSE: Handles registration of mini filters
6 * PROGRAMMERS: Ged Murphy (gedmurphy@reactos.org)
7 */
8
9 /* INCLUDES ******************************************************************/
10
11 #include "fltmgr.h"
12
13 #define NDEBUG
14 #include <debug.h>
15
16
17 /* DATA *********************************************************************/
18
19
20 NTSTATUS
21 FltpStartingToDrainObject(
22 _Inout_ PFLT_OBJECT Object
23 );
24
25
26 /* EXPORTED FUNCTIONS ******************************************************/
27
28 NTSTATUS
29 NTAPI
30 FltRegisterFilter(_In_ PDRIVER_OBJECT DriverObject,
31 _In_ const FLT_REGISTRATION *Registration,
32 _Out_ PFLT_FILTER *RetFilter)
33 {
34 PFLT_OPERATION_REGISTRATION Callbacks;
35 PFLT_FILTER Filter;
36 ULONG CallbackBufferSize;
37 ULONG FilterBufferSize;
38 ULONG Count = 0;
39 PCHAR Ptr;
40 NTSTATUS Status;
41
42 Status = 0; //remove me
43
44 /* Make sure we're targeting the correct major revision */
45 if ((Registration->Version & 0xFF00) != FLT_MAJOR_VERSION)
46 {
47 return STATUS_INVALID_PARAMETER;
48 }
49
50 /* Make sure our namespace callbacks are valid */
51 if ((!Registration->GenerateFileNameCallback && Registration->NormalizeNameComponentCallback) ||
52 (!Registration->NormalizeNameComponentCallback && Registration->NormalizeContextCleanupCallback))
53 {
54 return STATUS_INVALID_PARAMETER;
55 }
56
57 /* Count the number of operations that were requested */
58 Callbacks = (PFLT_OPERATION_REGISTRATION)Registration->OperationRegistration;
59 while (Callbacks)
60 {
61 Count++;
62
63 /* Bail when we find the last one */
64 if (Callbacks->MajorFunction == IRP_MJ_OPERATION_END)
65 break;
66
67 /* Move to the next item */
68 Callbacks++;
69 }
70
71 /* Calculate the buffer sizes */
72 CallbackBufferSize = Count * sizeof(FLT_OPERATION_REGISTRATION);
73 FilterBufferSize = sizeof(FLT_FILTER) + CallbackBufferSize +
74 DriverObject->DriverExtension->ServiceKeyName.Length;
75
76 /* Allocate a buffer to hold our filter data */
77 Filter = ExAllocatePoolWithTag(NonPagedPool,
78 FilterBufferSize,
79 FM_TAG_FILTER);
80 if (Filter == NULL) return STATUS_INSUFFICIENT_RESOURCES;
81 RtlZeroMemory(Filter, FilterBufferSize);
82
83 /* Find the end of the fixed struct */
84 Ptr = (PCHAR)(Filter + 1);
85
86 /* Store a copy of the driver object of this filter */
87 Filter->DriverObject = DriverObject;
88
89 /* Initialize the base object data */
90 Filter->Base.Flags = FLT_OBFL_TYPE_FILTER;
91 Filter->Base.PointerCount = 1;
92 FltpExInitializeRundownProtection(&Filter->Base.RundownRef);
93 FltObjectReference(&Filter->Base);
94
95 /* Set the callback addresses */
96 Filter->FilterUnload = Registration->FilterUnloadCallback;
97 Filter->InstanceSetup = Registration->InstanceSetupCallback;
98 Filter->InstanceQueryTeardown = Registration->InstanceQueryTeardownCallback;
99 Filter->InstanceTeardownStart = Registration->InstanceTeardownStartCallback;
100 Filter->InstanceTeardownComplete = Registration->InstanceTeardownCompleteCallback;
101 Filter->GenerateFileName = Registration->GenerateFileNameCallback;
102 Filter->NormalizeNameComponent = Registration->NormalizeNameComponentCallback;
103 Filter->NormalizeContextCleanup = Registration->NormalizeContextCleanupCallback;
104
105 /* Initialize the instance list */
106 ExInitializeResourceLite(&Filter->InstanceList.rLock);
107 InitializeListHead(&Filter->InstanceList.rList);
108 Filter->InstanceList.rCount = 0;
109
110 ExInitializeFastMutex(&Filter->ActiveOpens.mLock);
111 InitializeListHead(&Filter->ActiveOpens.mList);
112 Filter->ActiveOpens.mCount = 0;
113
114 /* Initialize the usermode port list */
115 ExInitializeFastMutex(&Filter->PortList.mLock);
116 InitializeListHead(&Filter->PortList.mList);
117 Filter->PortList.mCount = 0;
118
119 /* Check if the caller requested any context data */
120 if (Registration->ContextRegistration)
121 {
122 // register the context information
123 }
124
125 if (Registration->OperationRegistration)
126 {
127 /* The callback data comes after the fixed struct */
128 Filter->Operations = (PFLT_OPERATION_REGISTRATION)Ptr;
129 Ptr += (Count * sizeof(FLT_OPERATION_REGISTRATION));
130
131 /* Tag the operation data onto the end of the filter data */
132 RtlCopyMemory(Filter->Operations, Registration->OperationRegistration, CallbackBufferSize);
133
134 /* walk through the requested callbacks */
135 for (Callbacks = Filter->Operations;
136 Callbacks->MajorFunction != IRP_MJ_OPERATION_END;
137 Callbacks++)
138 {
139 // http://fsfilters.blogspot.co.uk/2011/03/how-file-system-filters-attach-to_17.html
140 /* Check if this is an attach to a volume */
141 if (Callbacks->MajorFunction == IRP_MJ_VOLUME_MOUNT)
142 {
143 Filter->PreVolumeMount = Callbacks->PreOperation;
144 Filter->PostVolumeMount = Callbacks->PostOperation;
145 }
146 else if (Callbacks->MajorFunction == IRP_MJ_SHUTDOWN)
147 {
148 Callbacks->PostOperation = NULL;
149 }
150 }
151 }
152
153 /* Add the filter name buffer onto the end of the data and fill in the string */
154 Filter->Name.Length = 0;
155 Filter->Name.MaximumLength = DriverObject->DriverExtension->ServiceKeyName.Length;
156 Filter->Name.Buffer = (PWCH)Ptr;
157 RtlCopyUnicodeString(&Filter->Name, &DriverObject->DriverExtension->ServiceKeyName);
158
159 //
160 // - Get the altitude string
161 // - Slot the filter into the correct altitude location
162 // - More stuff??
163 //
164
165 //Quit:
166 if (!NT_SUCCESS(Status))
167 {
168 // Add cleanup for context resources
169
170 ExDeleteResourceLite(&Filter->InstanceList.rLock);
171 ExFreePoolWithTag(Filter, FM_TAG_FILTER);
172 }
173
174 return Status;
175 }
176
177 VOID
178 FLTAPI
179 FltUnregisterFilter(_In_ PFLT_FILTER Filter)
180 {
181 PFLT_INSTANCE Instance;
182 PLIST_ENTRY CurrentEntry;
183 NTSTATUS Status;
184
185 /* Set the draining flag */
186 Status = FltpStartingToDrainObject(&Filter->Base);
187 if (!NT_SUCCESS(Status))
188 {
189 /* Someone already unregistered us, just remove our ref and bail */
190 FltObjectDereference(&Filter->Base);
191 return;
192 }
193
194 /* Lock the instance list */
195 KeEnterCriticalRegion();
196 ExAcquireResourceSharedLite(&Filter->InstanceList.rLock, TRUE);
197
198 /* Set the first entry in the list */
199 CurrentEntry = Filter->InstanceList.rList.Flink;
200
201 /* Free all instances referenced by the filter */
202 while (CurrentEntry != &Filter->InstanceList.rList)
203 {
204 /* Get the record pointer */
205 Instance = CONTAINING_RECORD(CurrentEntry, FLT_INSTANCE, FilterLink);
206
207 // FIXME: implement
208
209 /* Reset the pointer and move to next entry */
210 Instance = NULL;
211 CurrentEntry = CurrentEntry->Flink;
212 }
213
214 /* We're done with instances now */
215 ExReleaseResourceLite(&Filter->InstanceList.rLock);
216 KeLeaveCriticalRegion();
217
218 /* Remove the reference from the base object */
219 FltObjectDereference(&Filter->Base);
220
221 /* Wait until we're sure nothing is using the filter */
222 FltpObjectRundownWait(&Filter->Base.RundownRef);
223
224 /* Delete the instance list lock */
225 ExDeleteResourceLite(&Filter->InstanceList.rLock);
226
227 /* We're finished cleaning up now */
228 FltpExRundownCompleted(&Filter->Base.RundownRef);
229
230 /* Hand the memory back */
231 ExFreePoolWithTag(Filter, FM_TAG_FILTER);
232 }
233
234
235 /* INTERNAL FUNCTIONS ******************************************************/
236
237 NTSTATUS
238 FltpStartingToDrainObject(_Inout_ PFLT_OBJECT Object)
239 {
240 /*
241 * Set the draining flag for the filter. This let's us force
242 * a post op callback for minifilters currently awaiting one.
243 */
244 if (InterlockedOr((PLONG)&Object->Flags, FLT_OBFL_DRAINING) & 1)
245 {
246 /* We've been called once, we're already being deleted */
247 return STATUS_FLT_DELETING_OBJECT;
248 }
249
250 return STATUS_SUCCESS;
251 }