2 * PROJECT: ReactOS Kernel
3 * LICENSE: GPL - See COPYING in the top level directory
4 * FILE: ntoskrnl/fsrtl/filtrctx.c
5 * PURPOSE: File Stream Filter Context support for File System Drivers
6 * PROGRAMMERS: Pierre Schweitzer (pierre.schweitzer@reactos.org)
9 /* INCLUDES ******************************************************************/
15 /* PRIVATE FUNCTIONS *********************************************************/
17 typedef struct _FILE_OBJECT_FILTER_CONTEXTS
19 FAST_MUTEX FilterContextsMutex
;
20 LIST_ENTRY FilterContexts
;
21 } FILE_OBJECT_FILTER_CONTEXTS
, *PFILE_OBJECT_FILTER_CONTEXTS
;
28 FsRtlPTeardownPerFileObjectContexts(IN PFILE_OBJECT FileObject
)
30 PFILE_OBJECT_FILTER_CONTEXTS FOContext
= NULL
;
34 if (!(FOContext
= IoGetFileObjectFilterContext(FileObject
)))
39 ASSERT(IoChangeFileObjectFilterContext(FileObject
, FOContext
, FALSE
) == STATUS_SUCCESS
);
40 ASSERT(IsListEmpty(&(FOContext
->FilterContexts
)));
42 ExFreePoolWithTag(FOContext
, 'FOCX');
46 /* PUBLIC FUNCTIONS **********************************************************/
49 * @name FsRtlIsPagingFile
52 * The FsRtlIsPagingFile routine checks if the FileObject is a Paging File.
55 * A pointer to the File Object to be tested.
57 * @return TRUE if the File is a Paging File, FALSE otherwise.
64 FsRtlIsPagingFile(IN PFILE_OBJECT FileObject
)
66 return MmIsFileObjectAPagingFile(FileObject
);
72 PFSRTL_PER_FILEOBJECT_CONTEXT
74 FsRtlLookupPerFileObjectContext(IN PFILE_OBJECT FileObject
,
75 IN PVOID OwnerId OPTIONAL
,
76 IN PVOID InstanceId OPTIONAL
)
78 PLIST_ENTRY NextEntry
;
79 PFILE_OBJECT_FILTER_CONTEXTS FOContext
= NULL
;
80 PFSRTL_PER_FILEOBJECT_CONTEXT TmpPerFOContext
, PerFOContext
= NULL
;
82 if (!FileObject
|| !(FOContext
= IoGetFileObjectFilterContext(FileObject
)))
87 ExAcquireFastMutex(&(FOContext
->FilterContextsMutex
));
89 /* If list is empty, no need to browse it */
90 if (!IsListEmpty(&(FOContext
->FilterContexts
)))
92 for (NextEntry
= FOContext
->FilterContexts
.Flink
;
93 NextEntry
!= &(FOContext
->FilterContexts
);
94 NextEntry
= NextEntry
->Flink
)
96 /* If we don't have any criteria for search, first entry will be enough */
97 if (!OwnerId
&& !InstanceId
)
99 PerFOContext
= (PFSRTL_PER_FILEOBJECT_CONTEXT
)NextEntry
;
102 /* Else, we've to find something that matches with the parameters. */
105 TmpPerFOContext
= CONTAINING_RECORD(NextEntry
, FSRTL_PER_FILEOBJECT_CONTEXT
, Links
);
106 if ((InstanceId
&& TmpPerFOContext
->InstanceId
== InstanceId
&& TmpPerFOContext
->OwnerId
== OwnerId
) ||
107 (OwnerId
&& TmpPerFOContext
->OwnerId
== OwnerId
))
109 PerFOContext
= TmpPerFOContext
;
116 ExReleaseFastMutex(&(FOContext
->FilterContextsMutex
));
124 PFSRTL_PER_STREAM_CONTEXT
126 FsRtlLookupPerStreamContextInternal(IN PFSRTL_ADVANCED_FCB_HEADER AdvFcbHeader
,
127 IN PVOID OwnerId OPTIONAL
,
128 IN PVOID InstanceId OPTIONAL
)
130 PLIST_ENTRY NextEntry
;
131 PFSRTL_PER_STREAM_CONTEXT TmpPerStreamContext
, PerStreamContext
= NULL
;
133 ASSERT(AdvFcbHeader
);
134 ASSERT(FlagOn(AdvFcbHeader
->Flags2
, FSRTL_FLAG2_SUPPORTS_FILTER_CONTEXTS
));
136 ExAcquireFastMutex(AdvFcbHeader
->FastMutex
);
138 /* If list is empty, no need to browse it */
139 if (!IsListEmpty(&(AdvFcbHeader
->FilterContexts
)))
141 for (NextEntry
= AdvFcbHeader
->FilterContexts
.Flink
;
142 NextEntry
!= &(AdvFcbHeader
->FilterContexts
);
143 NextEntry
= NextEntry
->Flink
)
145 /* If we don't have any criteria for search, first entry will be enough */
146 if (!OwnerId
&& !InstanceId
)
148 PerStreamContext
= (PFSRTL_PER_STREAM_CONTEXT
)NextEntry
;
151 /* Else, we've to find something that matches with the parameters. */
154 TmpPerStreamContext
= CONTAINING_RECORD(NextEntry
, FSRTL_PER_STREAM_CONTEXT
, Links
);
155 if ((InstanceId
&& TmpPerStreamContext
->InstanceId
== InstanceId
&& TmpPerStreamContext
->OwnerId
== OwnerId
) ||
156 (OwnerId
&& TmpPerStreamContext
->OwnerId
== OwnerId
))
158 PerStreamContext
= TmpPerStreamContext
;
165 ExReleaseFastMutex(AdvFcbHeader
->FastMutex
);
167 return PerStreamContext
;
175 FsRtlInsertPerFileObjectContext(IN PFILE_OBJECT FileObject
,
176 IN PFSRTL_PER_FILEOBJECT_CONTEXT Ptr
)
178 PFILE_OBJECT_FILTER_CONTEXTS FOContext
= NULL
;
182 return STATUS_INVALID_PARAMETER
;
185 if (!(FileObject
->Flags
& FO_FILE_OBJECT_HAS_EXTENSION
))
187 return STATUS_INVALID_DEVICE_REQUEST
;
190 /* Get filter contexts */
191 FOContext
= IoGetFileObjectFilterContext(FileObject
);
194 /* If there's none, allocate new structure */
195 FOContext
= ExAllocatePoolWithTag(NonPagedPool
, sizeof(FILE_OBJECT_FILTER_CONTEXTS
), 'FOCX');
198 return STATUS_INSUFFICIENT_RESOURCES
;
202 ExInitializeFastMutex(&(FOContext
->FilterContextsMutex
));
203 InitializeListHead(&(FOContext
->FilterContexts
));
206 if (!IoChangeFileObjectFilterContext(FileObject
, FOContext
, TRUE
))
208 /* If it fails, it means that someone else has set it in the meanwhile */
209 ExFreePoolWithTag(FOContext
, 'FOCX');
211 /* So, we can get it */
212 FOContext
= IoGetFileObjectFilterContext(FileObject
);
215 /* If we fall down here, something went very bad. This shouldn't happen */
217 return STATUS_UNSUCCESSFUL
;
222 /* Finally, insert */
223 ExAcquireFastMutex(&(FOContext
->FilterContextsMutex
));
224 InsertHeadList(&(FOContext
->FilterContexts
), &(Ptr
->Links
));
225 ExReleaseFastMutex(&(FOContext
->FilterContextsMutex
));
227 return STATUS_SUCCESS
;
235 FsRtlInsertPerStreamContext(IN PFSRTL_ADVANCED_FCB_HEADER AdvFcbHeader
,
236 IN PFSRTL_PER_STREAM_CONTEXT PerStreamContext
)
238 if (!(AdvFcbHeader
) || !(AdvFcbHeader
->Flags2
& FSRTL_FLAG2_SUPPORTS_FILTER_CONTEXTS
))
240 return STATUS_INVALID_DEVICE_REQUEST
;
243 ExAcquireFastMutex(AdvFcbHeader
->FastMutex
);
244 InsertHeadList(&(AdvFcbHeader
->FilterContexts
), &(PerStreamContext
->Links
));
245 ExReleaseFastMutex(AdvFcbHeader
->FastMutex
);
246 return STATUS_SUCCESS
;
252 PFSRTL_PER_FILEOBJECT_CONTEXT
254 FsRtlRemovePerFileObjectContext(IN PFILE_OBJECT FileObject
,
255 IN PVOID OwnerId OPTIONAL
,
256 IN PVOID InstanceId OPTIONAL
)
258 PLIST_ENTRY NextEntry
;
259 PFILE_OBJECT_FILTER_CONTEXTS FOContext
= NULL
;
260 PFSRTL_PER_FILEOBJECT_CONTEXT TmpPerFOContext
, PerFOContext
= NULL
;
262 if (!FileObject
|| !(FOContext
= IoGetFileObjectFilterContext(FileObject
)))
267 ExAcquireFastMutex(&(FOContext
->FilterContextsMutex
));
269 /* If list is empty, no need to browse it */
270 if (!IsListEmpty(&(FOContext
->FilterContexts
)))
272 for (NextEntry
= FOContext
->FilterContexts
.Flink
;
273 NextEntry
!= &(FOContext
->FilterContexts
);
274 NextEntry
= NextEntry
->Flink
)
276 /* If we don't have any criteria for search, first entry will be enough */
277 if (!OwnerId
&& !InstanceId
)
279 PerFOContext
= (PFSRTL_PER_FILEOBJECT_CONTEXT
)NextEntry
;
282 /* Else, we've to find something that matches with the parameters. */
285 TmpPerFOContext
= CONTAINING_RECORD(NextEntry
, FSRTL_PER_FILEOBJECT_CONTEXT
, Links
);
286 if ((InstanceId
&& TmpPerFOContext
->InstanceId
== InstanceId
&& TmpPerFOContext
->OwnerId
== OwnerId
) ||
287 (OwnerId
&& TmpPerFOContext
->OwnerId
== OwnerId
))
289 PerFOContext
= TmpPerFOContext
;
295 /* Finally remove entry from list */
298 RemoveEntryList(&(PerFOContext
->Links
));
302 ExReleaseFastMutex(&(FOContext
->FilterContextsMutex
));
310 PFSRTL_PER_STREAM_CONTEXT
312 FsRtlRemovePerStreamContext(IN PFSRTL_ADVANCED_FCB_HEADER AdvFcbHeader
,
313 IN PVOID OwnerId OPTIONAL
,
314 IN PVOID InstanceId OPTIONAL
)
316 PLIST_ENTRY NextEntry
;
317 PFSRTL_PER_STREAM_CONTEXT TmpPerStreamContext
, PerStreamContext
= NULL
;
319 if (!(AdvFcbHeader
) || !(AdvFcbHeader
->Flags2
& FSRTL_FLAG2_SUPPORTS_FILTER_CONTEXTS
))
324 ExAcquireFastMutex(AdvFcbHeader
->FastMutex
);
325 /* If list is empty, no need to browse it */
326 if (!IsListEmpty(&(AdvFcbHeader
->FilterContexts
)))
328 for (NextEntry
= AdvFcbHeader
->FilterContexts
.Flink
;
329 NextEntry
!= &(AdvFcbHeader
->FilterContexts
);
330 NextEntry
= NextEntry
->Flink
)
332 /* If we don't have any criteria for search, first entry will be enough */
333 if (!OwnerId
&& !InstanceId
)
335 PerStreamContext
= (PFSRTL_PER_STREAM_CONTEXT
)NextEntry
;
338 /* Else, we've to find something that matches with the parameters. */
341 TmpPerStreamContext
= CONTAINING_RECORD(NextEntry
, FSRTL_PER_STREAM_CONTEXT
, Links
);
342 if ((InstanceId
&& TmpPerStreamContext
->InstanceId
== InstanceId
&& TmpPerStreamContext
->OwnerId
== OwnerId
) ||
343 (OwnerId
&& TmpPerStreamContext
->OwnerId
== OwnerId
))
345 PerStreamContext
= TmpPerStreamContext
;
351 /* Finally remove entry from list */
352 if (PerStreamContext
)
354 RemoveEntryList(&(PerStreamContext
->Links
));
357 ExReleaseFastMutex(AdvFcbHeader
->FastMutex
);
359 return PerStreamContext
;
368 FsRtlTeardownPerStreamContexts(IN PFSRTL_ADVANCED_FCB_HEADER AdvFcbHeader
)
370 PLIST_ENTRY NextEntry
;
371 volatile BOOLEAN IsMutexLocked
= FALSE
;
372 PFSRTL_PER_STREAM_CONTEXT PerStreamContext
;
376 /* Acquire mutex to deal with the list */
377 ExAcquireFastMutex(AdvFcbHeader
->FastMutex
);
378 IsMutexLocked
= TRUE
;
380 /* While there are items... */
381 while (!IsListEmpty(&(AdvFcbHeader
->FilterContexts
)))
384 NextEntry
= RemoveHeadList(&(AdvFcbHeader
->FilterContexts
));
385 PerStreamContext
= CONTAINING_RECORD(NextEntry
, FSRTL_PER_STREAM_CONTEXT
, Links
);
387 /* Release mutex before calling callback */
388 ExReleaseFastMutex(AdvFcbHeader
->FastMutex
);
389 IsMutexLocked
= FALSE
;
391 /* Call the callback */
392 ASSERT(PerStreamContext
->FreeCallback
);
393 (*PerStreamContext
->FreeCallback
)(PerStreamContext
);
395 /* Relock the list to continue */
396 ExAcquireFastMutex(AdvFcbHeader
->FastMutex
);
397 IsMutexLocked
= TRUE
;
402 /* If mutex was locked, release */
405 ExReleaseFastMutex(AdvFcbHeader
->FastMutex
);