mirror of
https://github.com/reactos/reactos.git
synced 2024-08-21 19:03:01 +00:00
410 lines
12 KiB
C
410 lines
12 KiB
C
/*
|
|
* PROJECT: ReactOS Kernel
|
|
* LICENSE: GPL - See COPYING in the top level directory
|
|
* FILE: ntoskrnl/fsrtl/filtrctx.c
|
|
* PURPOSE: File Stream Filter Context support for File System Drivers
|
|
* PROGRAMMERS: Pierre Schweitzer (pierre.schweitzer@reactos.org)
|
|
*/
|
|
|
|
/* INCLUDES ******************************************************************/
|
|
|
|
#include <ntoskrnl.h>
|
|
#define NDEBUG
|
|
#include <debug.h>
|
|
|
|
/* PRIVATE FUNCTIONS *********************************************************/
|
|
|
|
typedef struct _FILE_OBJECT_FILTER_CONTEXTS
|
|
{
|
|
FAST_MUTEX FilterContextsMutex;
|
|
LIST_ENTRY FilterContexts;
|
|
} FILE_OBJECT_FILTER_CONTEXTS, *PFILE_OBJECT_FILTER_CONTEXTS;
|
|
|
|
/*
|
|
* @implemented
|
|
*/
|
|
VOID
|
|
NTAPI
|
|
FsRtlPTeardownPerFileObjectContexts(IN PFILE_OBJECT FileObject)
|
|
{
|
|
PFILE_OBJECT_FILTER_CONTEXTS FOContext = NULL;
|
|
|
|
ASSERT(FileObject);
|
|
|
|
if (!(FOContext = IoGetFileObjectFilterContext(FileObject)))
|
|
{
|
|
return;
|
|
}
|
|
|
|
ASSERT(IoChangeFileObjectFilterContext(FileObject, FOContext, FALSE) == STATUS_SUCCESS);
|
|
ASSERT(IsListEmpty(&(FOContext->FilterContexts)));
|
|
|
|
ExFreePoolWithTag(FOContext, 'FOCX');
|
|
}
|
|
|
|
|
|
/* PUBLIC FUNCTIONS **********************************************************/
|
|
|
|
/*++
|
|
* @name FsRtlIsPagingFile
|
|
* @implemented NT 5.2
|
|
*
|
|
* The FsRtlIsPagingFile routine checks if the FileObject is a Paging File.
|
|
*
|
|
* @param FileObject
|
|
* A pointer to the File Object to be tested.
|
|
*
|
|
* @return TRUE if the File is a Paging File, FALSE otherwise.
|
|
*
|
|
* @remarks None.
|
|
*
|
|
*--*/
|
|
LOGICAL
|
|
NTAPI
|
|
FsRtlIsPagingFile(IN PFILE_OBJECT FileObject)
|
|
{
|
|
return MmIsFileObjectAPagingFile(FileObject);
|
|
}
|
|
|
|
/*
|
|
* @implemented
|
|
*/
|
|
PFSRTL_PER_FILEOBJECT_CONTEXT
|
|
NTAPI
|
|
FsRtlLookupPerFileObjectContext(IN PFILE_OBJECT FileObject,
|
|
IN PVOID OwnerId OPTIONAL,
|
|
IN PVOID InstanceId OPTIONAL)
|
|
{
|
|
PLIST_ENTRY NextEntry;
|
|
PFILE_OBJECT_FILTER_CONTEXTS FOContext = NULL;
|
|
PFSRTL_PER_FILEOBJECT_CONTEXT TmpPerFOContext, PerFOContext = NULL;
|
|
|
|
if (!FileObject || !(FOContext = IoGetFileObjectFilterContext(FileObject)))
|
|
{
|
|
return NULL;
|
|
}
|
|
|
|
ExAcquireFastMutex(&(FOContext->FilterContextsMutex));
|
|
|
|
/* If list is empty, no need to browse it */
|
|
if (!IsListEmpty(&(FOContext->FilterContexts)))
|
|
{
|
|
for (NextEntry = FOContext->FilterContexts.Flink;
|
|
NextEntry != &(FOContext->FilterContexts);
|
|
NextEntry = NextEntry->Flink)
|
|
{
|
|
/* If we don't have any criteria for search, first entry will be enough */
|
|
if (!OwnerId && !InstanceId)
|
|
{
|
|
PerFOContext = (PFSRTL_PER_FILEOBJECT_CONTEXT)NextEntry;
|
|
break;
|
|
}
|
|
/* Else, we've to find something that matches with the parameters. */
|
|
else
|
|
{
|
|
TmpPerFOContext = CONTAINING_RECORD(NextEntry, FSRTL_PER_FILEOBJECT_CONTEXT, Links);
|
|
if ((InstanceId && TmpPerFOContext->InstanceId == InstanceId && TmpPerFOContext->OwnerId == OwnerId) ||
|
|
(OwnerId && TmpPerFOContext->OwnerId == OwnerId))
|
|
{
|
|
PerFOContext = TmpPerFOContext;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
ExReleaseFastMutex(&(FOContext->FilterContextsMutex));
|
|
|
|
return PerFOContext;
|
|
}
|
|
|
|
/*
|
|
* @implemented
|
|
*/
|
|
PFSRTL_PER_STREAM_CONTEXT
|
|
NTAPI
|
|
FsRtlLookupPerStreamContextInternal(IN PFSRTL_ADVANCED_FCB_HEADER AdvFcbHeader,
|
|
IN PVOID OwnerId OPTIONAL,
|
|
IN PVOID InstanceId OPTIONAL)
|
|
{
|
|
PLIST_ENTRY NextEntry;
|
|
PFSRTL_PER_STREAM_CONTEXT TmpPerStreamContext, PerStreamContext = NULL;
|
|
|
|
ASSERT(AdvFcbHeader);
|
|
ASSERT(FlagOn(AdvFcbHeader->Flags2, FSRTL_FLAG2_SUPPORTS_FILTER_CONTEXTS));
|
|
|
|
ExAcquireFastMutex(AdvFcbHeader->FastMutex);
|
|
|
|
/* If list is empty, no need to browse it */
|
|
if (!IsListEmpty(&(AdvFcbHeader->FilterContexts)))
|
|
{
|
|
for (NextEntry = AdvFcbHeader->FilterContexts.Flink;
|
|
NextEntry != &(AdvFcbHeader->FilterContexts);
|
|
NextEntry = NextEntry->Flink)
|
|
{
|
|
/* If we don't have any criteria for search, first entry will be enough */
|
|
if (!OwnerId && !InstanceId)
|
|
{
|
|
PerStreamContext = (PFSRTL_PER_STREAM_CONTEXT)NextEntry;
|
|
break;
|
|
}
|
|
/* Else, we've to find something that matches with the parameters. */
|
|
else
|
|
{
|
|
TmpPerStreamContext = CONTAINING_RECORD(NextEntry, FSRTL_PER_STREAM_CONTEXT, Links);
|
|
if ((InstanceId && TmpPerStreamContext->InstanceId == InstanceId && TmpPerStreamContext->OwnerId == OwnerId) ||
|
|
(OwnerId && TmpPerStreamContext->OwnerId == OwnerId))
|
|
{
|
|
PerStreamContext = TmpPerStreamContext;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
ExReleaseFastMutex(AdvFcbHeader->FastMutex);
|
|
|
|
return PerStreamContext;
|
|
}
|
|
|
|
/*
|
|
* @implemented
|
|
*/
|
|
NTSTATUS
|
|
NTAPI
|
|
FsRtlInsertPerFileObjectContext(IN PFILE_OBJECT FileObject,
|
|
IN PFSRTL_PER_FILEOBJECT_CONTEXT Ptr)
|
|
{
|
|
PFILE_OBJECT_FILTER_CONTEXTS FOContext = NULL;
|
|
|
|
if (!FileObject)
|
|
{
|
|
return STATUS_INVALID_PARAMETER;
|
|
}
|
|
|
|
if (!(FileObject->Flags & FO_FILE_OBJECT_HAS_EXTENSION))
|
|
{
|
|
return STATUS_INVALID_DEVICE_REQUEST;
|
|
}
|
|
|
|
/* Get filter contexts */
|
|
FOContext = IoGetFileObjectFilterContext(FileObject);
|
|
if (!FOContext)
|
|
{
|
|
/* If there's none, allocate new structure */
|
|
FOContext = ExAllocatePoolWithTag(NonPagedPool, sizeof(FILE_OBJECT_FILTER_CONTEXTS), 'FOCX');
|
|
if (!FOContext)
|
|
{
|
|
return STATUS_INSUFFICIENT_RESOURCES;
|
|
}
|
|
|
|
/* Initialize it */
|
|
ExInitializeFastMutex(&(FOContext->FilterContextsMutex));
|
|
InitializeListHead(&(FOContext->FilterContexts));
|
|
|
|
/* Set it */
|
|
if (!IoChangeFileObjectFilterContext(FileObject, FOContext, TRUE))
|
|
{
|
|
/* If it fails, it means that someone else has set it in the meanwhile */
|
|
ExFreePoolWithTag(FOContext, 'FOCX');
|
|
|
|
/* So, we can get it */
|
|
FOContext = IoGetFileObjectFilterContext(FileObject);
|
|
if (!FOContext)
|
|
{
|
|
/* If we fall down here, something went very bad. This shouldn't happen */
|
|
ASSERT(FALSE);
|
|
return STATUS_UNSUCCESSFUL;
|
|
}
|
|
}
|
|
}
|
|
|
|
/* Finally, insert */
|
|
ExAcquireFastMutex(&(FOContext->FilterContextsMutex));
|
|
InsertHeadList(&(FOContext->FilterContexts), &(Ptr->Links));
|
|
ExReleaseFastMutex(&(FOContext->FilterContextsMutex));
|
|
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
/*
|
|
* @implemented
|
|
*/
|
|
NTSTATUS
|
|
NTAPI
|
|
FsRtlInsertPerStreamContext(IN PFSRTL_ADVANCED_FCB_HEADER AdvFcbHeader,
|
|
IN PFSRTL_PER_STREAM_CONTEXT PerStreamContext)
|
|
{
|
|
if (!(AdvFcbHeader) || !(AdvFcbHeader->Flags2 & FSRTL_FLAG2_SUPPORTS_FILTER_CONTEXTS))
|
|
{
|
|
return STATUS_INVALID_DEVICE_REQUEST;
|
|
}
|
|
|
|
ExAcquireFastMutex(AdvFcbHeader->FastMutex);
|
|
InsertHeadList(&(AdvFcbHeader->FilterContexts), &(PerStreamContext->Links));
|
|
ExReleaseFastMutex(AdvFcbHeader->FastMutex);
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
/*
|
|
* @implemented
|
|
*/
|
|
PFSRTL_PER_FILEOBJECT_CONTEXT
|
|
NTAPI
|
|
FsRtlRemovePerFileObjectContext(IN PFILE_OBJECT FileObject,
|
|
IN PVOID OwnerId OPTIONAL,
|
|
IN PVOID InstanceId OPTIONAL)
|
|
{
|
|
PLIST_ENTRY NextEntry;
|
|
PFILE_OBJECT_FILTER_CONTEXTS FOContext = NULL;
|
|
PFSRTL_PER_FILEOBJECT_CONTEXT TmpPerFOContext, PerFOContext = NULL;
|
|
|
|
if (!FileObject || !(FOContext = IoGetFileObjectFilterContext(FileObject)))
|
|
{
|
|
return NULL;
|
|
}
|
|
|
|
ExAcquireFastMutex(&(FOContext->FilterContextsMutex));
|
|
|
|
/* If list is empty, no need to browse it */
|
|
if (!IsListEmpty(&(FOContext->FilterContexts)))
|
|
{
|
|
for (NextEntry = FOContext->FilterContexts.Flink;
|
|
NextEntry != &(FOContext->FilterContexts);
|
|
NextEntry = NextEntry->Flink)
|
|
{
|
|
/* If we don't have any criteria for search, first entry will be enough */
|
|
if (!OwnerId && !InstanceId)
|
|
{
|
|
PerFOContext = (PFSRTL_PER_FILEOBJECT_CONTEXT)NextEntry;
|
|
break;
|
|
}
|
|
/* Else, we've to find something that matches with the parameters. */
|
|
else
|
|
{
|
|
TmpPerFOContext = CONTAINING_RECORD(NextEntry, FSRTL_PER_FILEOBJECT_CONTEXT, Links);
|
|
if ((InstanceId && TmpPerFOContext->InstanceId == InstanceId && TmpPerFOContext->OwnerId == OwnerId) ||
|
|
(OwnerId && TmpPerFOContext->OwnerId == OwnerId))
|
|
{
|
|
PerFOContext = TmpPerFOContext;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
/* Finally remove entry from list */
|
|
if (PerFOContext)
|
|
{
|
|
RemoveEntryList(&(PerFOContext->Links));
|
|
}
|
|
}
|
|
|
|
ExReleaseFastMutex(&(FOContext->FilterContextsMutex));
|
|
|
|
return PerFOContext;
|
|
}
|
|
|
|
/*
|
|
* @implemented
|
|
*/
|
|
PFSRTL_PER_STREAM_CONTEXT
|
|
NTAPI
|
|
FsRtlRemovePerStreamContext(IN PFSRTL_ADVANCED_FCB_HEADER AdvFcbHeader,
|
|
IN PVOID OwnerId OPTIONAL,
|
|
IN PVOID InstanceId OPTIONAL)
|
|
{
|
|
PLIST_ENTRY NextEntry;
|
|
PFSRTL_PER_STREAM_CONTEXT TmpPerStreamContext, PerStreamContext = NULL;
|
|
|
|
if (!(AdvFcbHeader) || !(AdvFcbHeader->Flags2 & FSRTL_FLAG2_SUPPORTS_FILTER_CONTEXTS))
|
|
{
|
|
return NULL;
|
|
}
|
|
|
|
ExAcquireFastMutex(AdvFcbHeader->FastMutex);
|
|
/* If list is empty, no need to browse it */
|
|
if (!IsListEmpty(&(AdvFcbHeader->FilterContexts)))
|
|
{
|
|
for (NextEntry = AdvFcbHeader->FilterContexts.Flink;
|
|
NextEntry != &(AdvFcbHeader->FilterContexts);
|
|
NextEntry = NextEntry->Flink)
|
|
{
|
|
/* If we don't have any criteria for search, first entry will be enough */
|
|
if (!OwnerId && !InstanceId)
|
|
{
|
|
PerStreamContext = (PFSRTL_PER_STREAM_CONTEXT)NextEntry;
|
|
break;
|
|
}
|
|
/* Else, we've to find something that matches with the parameters. */
|
|
else
|
|
{
|
|
TmpPerStreamContext = CONTAINING_RECORD(NextEntry, FSRTL_PER_STREAM_CONTEXT, Links);
|
|
if ((InstanceId && TmpPerStreamContext->InstanceId == InstanceId && TmpPerStreamContext->OwnerId == OwnerId) ||
|
|
(OwnerId && TmpPerStreamContext->OwnerId == OwnerId))
|
|
{
|
|
PerStreamContext = TmpPerStreamContext;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
/* Finally remove entry from list */
|
|
if (PerStreamContext)
|
|
{
|
|
RemoveEntryList(&(PerStreamContext->Links));
|
|
}
|
|
}
|
|
ExReleaseFastMutex(AdvFcbHeader->FastMutex);
|
|
|
|
return PerStreamContext;
|
|
|
|
}
|
|
|
|
/*
|
|
* @implemented
|
|
*/
|
|
VOID
|
|
NTAPI
|
|
FsRtlTeardownPerStreamContexts(IN PFSRTL_ADVANCED_FCB_HEADER AdvFcbHeader)
|
|
{
|
|
PLIST_ENTRY NextEntry;
|
|
volatile BOOLEAN IsMutexLocked = FALSE;
|
|
PFSRTL_PER_STREAM_CONTEXT PerStreamContext;
|
|
|
|
_SEH2_TRY
|
|
{
|
|
/* Acquire mutex to deal with the list */
|
|
ExAcquireFastMutex(AdvFcbHeader->FastMutex);
|
|
IsMutexLocked = TRUE;
|
|
|
|
/* While there are items... */
|
|
while (!IsListEmpty(&(AdvFcbHeader->FilterContexts)))
|
|
{
|
|
/* ...remove one */
|
|
NextEntry = RemoveHeadList(&(AdvFcbHeader->FilterContexts));
|
|
PerStreamContext = CONTAINING_RECORD(NextEntry, FSRTL_PER_STREAM_CONTEXT, Links);
|
|
|
|
/* Release mutex before calling callback */
|
|
ExReleaseFastMutex(AdvFcbHeader->FastMutex);
|
|
IsMutexLocked = FALSE;
|
|
|
|
/* Call the callback */
|
|
ASSERT(PerStreamContext->FreeCallback);
|
|
(*PerStreamContext->FreeCallback)(PerStreamContext);
|
|
|
|
/* Relock the list to continue */
|
|
ExAcquireFastMutex(AdvFcbHeader->FastMutex);
|
|
IsMutexLocked = TRUE;
|
|
}
|
|
}
|
|
_SEH2_FINALLY
|
|
{
|
|
/* If mutex was locked, release */
|
|
if (IsMutexLocked)
|
|
{
|
|
ExReleaseFastMutex(AdvFcbHeader->FastMutex);
|
|
}
|
|
}
|
|
_SEH2_END;
|
|
}
|