?? fspyctx.c
字號:
/*++
Copyright (c) 1998-1999 Microsoft Corporation
Module Name:
context.c
Abstract:
This module contains all of the routines for tracking names using
the new Stream Context feature. It does this by attaching a context
structure to a stream whenever a new name is requested. It does
properly handle when files and directories are renamed.
Note that StreamContexts are a new feature in the system and are not
supported by all file systems. All of the standard Microsoft file
systems support them (NTFS, fat, cdfs, udfs, rdr2) but there may be 3rd
party file systems that do not. This is one of the main reasons why
track names by stream contexts is not enabled by default.
Environment:
Kernel mode
--*/
#include <ntifs.h>
#include "filespy.h"
#include "fspyKern.h"
#include "namelookup.h"
#if USE_STREAM_CONTEXTS
#if WINVER < 0x0501
#error Stream contexts on only supported on Windows XP or later.
#endif
////////////////////////////////////////////////////////////////////////
//
// Local prototypes
//
////////////////////////////////////////////////////////////////////////
VOID
SpyDeleteContextCallback(
IN PVOID Context
);
//
// linker commands
//
#ifdef ALLOC_PRAGMA
#pragma alloc_text( PAGE, SpyInitDeviceNamingEnvironment )
#pragma alloc_text( PAGE, SpyCleanupDeviceNamingEnvironment )
#pragma alloc_text( PAGE, SpyDeleteAllContexts )
#pragma alloc_text( PAGE, SpyDeleteContext )
#pragma alloc_text( PAGE, SpyDeleteContextCallback )
#pragma alloc_text( PAGE, SpyLinkContext )
#pragma alloc_text( PAGE, SpyCreateContext )
#pragma alloc_text( PAGE, SpyFindExistingContext )
#pragma alloc_text( PAGE, SpyReleaseContext )
#endif // ALLOC_PRAGMA
///////////////////////////////////////////////////////////////////////////
//
// Context support routines
//
///////////////////////////////////////////////////////////////////////////
VOID
SpyInitNamingEnvironment (
VOID
)
/*++
Routine Description:
Init global variables
Arguments:
None
Return Value:
None.
--*/
{
}
VOID
SpyLogIrp (
IN PIRP Irp,
OUT PRECORD_LIST RecordList
)
/*++
Routine Description:
Records the Irp necessary information according to LoggingFlags in
RecordList. For any activity on the Irp path of a device being
logged, this function should get called twice: once on the IRPs
originating path and once on the IRPs completion path.
Arguments:
Irp - The Irp that contains the information we want to record.
LoggingFlags - The flags that say what to log.
RecordList - The PRECORD_LIST in which the Irp information is stored.
Context - if non-zero, an existing context record for this entry.
Return Value:
None.
--*/
{
PRECORD_IRP pRecordIrp = &RecordList->LogRecord.Record.RecordIrp;
PIO_STACK_LOCATION pIrpStack = IoGetCurrentIrpStackLocation(Irp);
PDEVICE_OBJECT deviceObject;
PFILESPY_DEVICE_EXTENSION devExt;
PSPY_STREAM_CONTEXT pContext;
NAME_LOOKUP_FLAGS lookupFlags = 0;
NTSTATUS status;
FILE_STANDARD_INFORMATION standardInformation;
//
// Init locals
//
deviceObject = pIrpStack->DeviceObject;
devExt = deviceObject->DeviceExtension;
//
// Record the information we use for an originating Irp. We first
// need to initialize some of the RECORD_LIST and RECORD_IRP fields.
// Then get the interesting information from the Irp.
//
SetFlag( RecordList->LogRecord.RecordType, RECORD_TYPE_IRP );
pRecordIrp->IrpMajor = pIrpStack->MajorFunction;
pRecordIrp->IrpMinor = pIrpStack->MinorFunction;
pRecordIrp->IrpFlags = Irp->Flags;
pRecordIrp->FileObject = (FILE_ID)pIrpStack->FileObject;
pRecordIrp->DeviceObject = (FILE_ID)deviceObject;
pRecordIrp->ProcessId = (FILE_ID)PsGetCurrentProcessId();
pRecordIrp->ThreadId = (FILE_ID)PsGetCurrentThreadId();
pRecordIrp->Argument1 = pIrpStack->Parameters.Others.Argument1;
pRecordIrp->Argument2 = pIrpStack->Parameters.Others.Argument2;
pRecordIrp->Argument3 = pIrpStack->Parameters.Others.Argument3;
pRecordIrp->Argument4 = pIrpStack->Parameters.Others.Argument4;
KeQuerySystemTime( &pRecordIrp->OriginatingTime );
//
// Do different things based on the operation
//
switch (pIrpStack->MajorFunction) {
case IRP_MJ_CREATE:
//
// OPEN/CREATE file
//
// Only record the desired access if this is a CREATE IRP.
//
pRecordIrp->DesiredAccess = pIrpStack->Parameters.Create.SecurityContext->DesiredAccess;
//
// Set out name lookup state
//
SetFlag( lookupFlags, NLFL_IN_CREATE );
//
// Flag if opening the directory of the given file
//
if (FlagOn( pIrpStack->Flags, SL_OPEN_TARGET_DIRECTORY )) {
SetFlag( lookupFlags, NLFL_OPEN_TARGET_DIR );
}
//
// Set if opening by ID
//
if (FlagOn( pIrpStack->Parameters.Create.Options, FILE_OPEN_BY_FILE_ID )) {
SetFlag( lookupFlags, NLFL_OPEN_BY_ID );
}
//
// We are in pre-create, we can not attach a context to the file
// object yet so simply create a context. If it fails no name
// will be logged.
// Note: We may already have a context on this file but we can't
// find it yet because the FsContext field is not setup yet.
// We go ahead and get a context so we will have a name if
// the operations fails. We will detect the duplicate
// context during the post-create and delete the new one.
//
status = SpyCreateContext( deviceObject,
pIrpStack->FileObject,
lookupFlags,
&pContext );
if (NT_SUCCESS(status)) {
SPY_LOG_PRINT( SPYDEBUG_TRACE_CONTEXT_OPS,
("FileSpy!SpyLogIrp: Created (%p) Fl=%02x Use=%d \"%wZ\"\n",
pContext,
pContext->Flags,
pContext->UseCount,
&pContext->Name) );
//
// If a context was found save it and mark that to sync back
// to the dispatch routine to complete this operation.
//
ASSERT(RecordList->NewContext == NULL);
RecordList->NewContext = pContext;
SetFlag( RecordList->Flags, RLFL_SYNC_TO_DISPATCH );
}
break;
case IRP_MJ_CLOSE:
//
// CLOSE FILE
//
// If this is a close we can only look up the name in the name
// cache. It is possible that the close could be occurring
// during a cleanup operation in the file system (i.e., before we
// have received the cleanup completion) and requesting the name
// would cause a deadlock in the file system.
//
SetFlag( lookupFlags, NLFL_ONLY_CHECK_CACHE );
break;
case IRP_MJ_SET_INFORMATION:
if (FileRenameInformation ==
pIrpStack->Parameters.SetFile.FileInformationClass)
{
//
// RENAME FILE
//
// We are doing a rename. First get a context for the
// given file. If this fails, mark that we don't want to
// try and lookup a name.
//
status = SpyGetContext( deviceObject,
pIrpStack->FileObject,
lookupFlags,
&pContext );
if (!NT_SUCCESS(status)) {
//
// If we couldn't get a context simply delete all
// existing ones (since we don't know what this rename
// will change) and mark not to do a lookup.
//
SetFlag( lookupFlags, NLFL_NO_LOOKUP );
SpyDeleteAllContexts( deviceObject );
break;
}
//
// We retrieved a context, save it in the record and mark
// that we want to handle this during post rename.
//
ASSERT(RecordList->NewContext == NULL);
RecordList->NewContext = pContext;
SetFlag( RecordList->Flags, RLFL_SYNC_TO_DISPATCH );
//
// We need to decide if we are renaming a file or a
// directory because we need to handle this differently
//
status = SpyQueryInformationFile( devExt->NLExtHeader.AttachedToDeviceObject,
pIrpStack->FileObject,
&standardInformation,
sizeof( standardInformation ),
FileStandardInformation,
NULL );
if (!NT_SUCCESS(status)) {
//
// We can't tell if it is a file or directory, assume
// the worst case and handle it like a directory.
//
InterlockedIncrement( &devExt->AllContextsTemporary );
SpyDeleteAllContexts( deviceObject );
SetFlag( RecordList->Flags, RLFL_IS_DIRECTORY );
break;
}
if (standardInformation.Directory) {
//
// Renaming a directory. Mark that any contexts
// created while the rename is in progress should be
// temporary. This way there is no window where
// we may get an old stale name. Then delete all
// existing contexts. NOTE: the context we hold will
// not actually be deleted until we release it.
//
InterlockedIncrement( &devExt->AllContextsTemporary );
SpyDeleteAllContexts( deviceObject );
SetFlag( RecordList->Flags, RLFL_IS_DIRECTORY );
} else {
//
// We are renaming a file. Mark the context so it will
// not be used. This way if someone accesses this file
// while it is being renamed they will lookup the
// name again so we will always get an accurate name.
// This context will be deleted during post rename
// processing
//
SetFlag( pContext->Flags, CTXFL_DoNotUse);
}
}
break;
}
//
// If the flag IRP_PAGING_IO is set in this IRP, we cannot query the name
// because it can lead to deadlocks. Therefore, add in the flag so that
// we will only try to find the name in our cache.
//
if (FlagOn( Irp->Flags, IRP_PAGING_IO )) {
ASSERT( !FlagOn( lookupFlags, NLFL_NO_LOOKUP ) );
SetFlag( lookupFlags, NLFL_ONLY_CHECK_CACHE );
}
SetFlag( lookupFlags, NLFL_USE_DOS_DEVICE_NAME );
SpySetName( RecordList,
deviceObject,
pIrpStack->FileObject,
lookupFlags,
(PSPY_STREAM_CONTEXT)RecordList->NewContext );
}
VOID
SpyLogIrpCompletion (
IN PIRP Irp,
PRECORD_LIST RecordList
)
/*++
Routine Description:
This routine performs post-operation logging of the IRP.
Arguments:
DeviceObject - Pointer to device object FileSpy attached to the file system
filter stack for the volume receiving this I/O request.
Irp - Pointer to the request packet representing the I/O request.
Record - RecordList
Return Value:
None.
--*/
{
PIO_STACK_LOCATION pIrpStack = IoGetCurrentIrpStackLocation(Irp);
PRECORD_IRP pRecordIrp;
PDEVICE_OBJECT deviceObject;
PFILESPY_DEVICE_EXTENSION devExt;
PSPY_STREAM_CONTEXT pContext;
//
// Init locals
//
deviceObject = pIrpStack->DeviceObject;
devExt = deviceObject->DeviceExtension;
ASSERT(deviceObject ==
(PDEVICE_OBJECT)RecordList->LogRecord.Record.RecordIrp.DeviceObject);
//
// Do completion processing based on the operation
//
switch (pIrpStack->MajorFunction) {
case IRP_MJ_CREATE:
//
// CREATE FILE
//
// NOTE: When processing CREATE completion IRPS this completion
// routine is never called at DISPATCH level, it is always
// synchronized back to the dispatch routine. This is
// controlled by the setting of the RLFL_SYNC_TO_DISPATCH
// flag in the log record.
//
if (NULL != (pContext = RecordList->NewContext)) {
//
// Mark context field so it won't be freed later
//
RecordList->NewContext = NULL;
//
// If the operation succeeded and an FsContext is defined,
// then attach the context. Else when the context is
// released it will be freed.
//
if (NT_SUCCESS(Irp->IoStatus.Status) &&
(NULL != pIrpStack->FileObject->FsContext)) {
SpyLinkContext( deviceObject,
pIrpStack->FileObject,
&pContext );
SPY_LOG_PRINT( SPYDEBUG_TRACE_CONTEXT_OPS,
("FileSpy!SpyLogIrpCompletion: Link (%p) Fl=%02x Use=%d \"%wZ\"\n",
pContext,
pContext->Flags,
pContext->UseCount,
&pContext->Name) );
KdPrint(("sfilter!SfCreate: %s \n",pContext->Name));
}
//
// Now release the context
//
SpyReleaseContext( pContext );
}
break;
case IRP_MJ_SET_INFORMATION:
if (FileRenameInformation ==
pIrpStack->Parameters.SetFile.FileInformationClass)
{
//
// RENAMING FILE
//
// NOTE: When processing RENAME completion IRPS this
// completion routine is never called at DISPATCH level,
// it is always synchronized back to the dispatch
// routine. This is controlled by the setting of the
// RLFL_SYNC_TO_DISPATCH flag in the log record.
//
if (NULL != (pContext = RecordList->NewContext)) {
//
// Mark context field so it won't be freed later
//
RecordList->NewContext = NULL;
//
// See if renaming a directory
?? 快捷鍵說明
復(fù)制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -