📄 operations.c
字号:
/*++
Copyright (c) 1999 - 2002 Microsoft Corporation
Module Name:
operations.c
Abstract:
This is the i/o operations module of the kernel mode filter driver implementing
filter metadata management.
Environment:
Kernel mode
--*/
#include "pch.h"
//
// Missing error code on Win2k
//
#if (WINVER==0x0500)
#ifndef STATUS_INVALID_DEVICE_OBJECT_PARAMETER
#define STATUS_INVALID_DEVICE_OBJECT_PARAMETER ((NTSTATUS)0xC0000369L)
#endif
#endif
//
// Assign text sections for each routine.
//
#ifdef ALLOC_PRAGMA
#pragma alloc_text(PAGE, FmmPreCreate)
#pragma alloc_text(PAGE, FmmPostCreate)
#pragma alloc_text(PAGE, FmmPreCleanup)
#pragma alloc_text(PAGE, FmmPostCleanup)
#pragma alloc_text(PAGE, FmmPreFSControl)
#pragma alloc_text(PAGE, FmmPostFSControl)
#pragma alloc_text(PAGE, FmmPreDeviceControl)
#pragma alloc_text(PAGE, FmmPostDeviceControl)
#pragma alloc_text(PAGE, FmmPreShutdown)
#pragma alloc_text(PAGE, FmmPrePnp)
#endif
FLT_PREOP_CALLBACK_STATUS
FmmPreCreate (
IN OUT PFLT_CALLBACK_DATA Cbd,
IN PCFLT_RELATED_OBJECTS FltObjects,
OUT PVOID *CompletionContext
)
{
NTSTATUS status;
FLT_PREOP_CALLBACK_STATUS callbackStatus;
UNREFERENCED_PARAMETER( FltObjects );
UNREFERENCED_PARAMETER( CompletionContext );
PAGED_CODE();
DebugTrace( DEBUG_TRACE_ALL_IO,
("[Fmm]: FmmPreCreate -> Enter (Cbd = %p, FileObject = %p)\n",
Cbd,
FltObjects->FileObject) );
//
// Initialize defaults
//
status = STATUS_SUCCESS;
callbackStatus = FLT_PREOP_SUCCESS_NO_CALLBACK; // pass through - default is no post op callback
//
// Sanity check to ensure that the volume detection logic works
//
// If the filename length is 0 and the related file object is NULL,
// the the FO_VOLUME_OPEN flag must be set
//
ASSERT( (!(Cbd->Iopb->TargetFileObject->FileName.Length == 0 &&
Cbd->Iopb->TargetFileObject->RelatedFileObject == NULL)) ||
FlagOn( Cbd->Iopb->TargetFileObject->Flags, FO_VOLUME_OPEN ) );
if (FmmTargetIsVolumeOpen( Cbd )) {
//
// Check for implicit volume locks (primarily used by autochk)
//
if (!FlagOn( Cbd->Iopb->Parameters.Create.ShareAccess, FILE_SHARE_WRITE)) {
//
// This is an implicit volume lock
//
//
// Give up the metadata file handle and the metadata file object
//
status = FmmReleaseMetadataFileReferences( Cbd );
if ( NT_SUCCESS( status )) {
//
// Continue with the lock/dismount - we need to check if the
// lock operation suceeded in the post-op
//
callbackStatus = FLT_PREOP_SUCCESS_WITH_CALLBACK;
} else {
//
// Fail the lock/dismount
//
DebugTrace( DEBUG_TRACE_ERROR | DEBUG_TRACE_METADATA_OPERATIONS,
("[Fmm]: Failed to release metadata file references with status 0x%x for a volume lock/dismount\n",
status) );
//
// Since this operation has failed, FmmPreCreateCleanup will
// update Cbd->IoStatus.Status with the status code and
// complete the operation by returning FLT_PREOP_COMPLETE
//
}
}
//
// We do not need to process volume opens any further
//
goto FmmPreCreateCleanup;
}
//
// Here the filter can do any further processing it may want to do
// in the PreCreate Callback
//
FmmPreCreateCleanup:
//
// If any operation has failed then complete and fail the call
//
if (!NT_SUCCESS( status )) {
DebugTrace( DEBUG_TRACE_ERROR,
("[Fmm]: FmmPreCreate -> Failed with status 0x%x \n",
status) );
Cbd->IoStatus.Status = status;
callbackStatus = FLT_PREOP_COMPLETE;
}
DebugTrace( DEBUG_TRACE_ALL_IO,
("[Fmm]: FmmPreCreate -> Exit (Cbd = %p, FileObject = %p)\n",
Cbd,
FltObjects->FileObject) );
return callbackStatus;
}
FLT_POSTOP_CALLBACK_STATUS
FmmPostCreate (
IN OUT PFLT_CALLBACK_DATA Cbd,
IN PCFLT_RELATED_OBJECTS FltObjects,
IN PVOID CbdContext,
IN FLT_POST_OPERATION_FLAGS Flags
)
{
NTSTATUS status;
UNREFERENCED_PARAMETER( FltObjects );
UNREFERENCED_PARAMETER( CbdContext );
UNREFERENCED_PARAMETER( Flags );
PAGED_CODE();
DebugTrace( DEBUG_TRACE_ALL_IO,
("[Fmm]: FmmPostCreate -> Enter (Cbd = %p, FileObject = %p)\n",
Cbd,
FltObjects->FileObject) );
//
// Initialize defaults
//
status = STATUS_SUCCESS;
if (!FlagOn(Flags,FLTFL_POST_OPERATION_DRAINING) &&
FmmTargetIsVolumeOpen( Cbd )) {
//
// Check for implicit volume locks (primarily used by autochk)
//
if (!FlagOn( Cbd->Iopb->Parameters.Create.ShareAccess, FILE_SHARE_WRITE)) {
//
// This is an implicit volume lock
//
if (!NT_SUCCESS( Cbd->IoStatus.Status )) {
//
// The lock failed - reaquire our references to the metadata file
// handle and the metadata file object
//
status = FmmReacquireMetadataFileReferences( Cbd );
if (!NT_SUCCESS( status )) {
DebugTrace( DEBUG_TRACE_ERROR | DEBUG_TRACE_METADATA_OPERATIONS,
("[Fmm]: Failed to re-open metadata with status 0x%x after a failed lock with status 0x%x\n",
status,
Cbd->IoStatus.Status) );
//
// Sanity - we are now in a bad state. The lock has failed
// but we have not been able to re-acquire references to
// our metadata file
//
// It is always possible to fail with STATUS_INSUFFICIENT_RESOURCES
// so we should ignore that.
//
// It is also possible to fail if the instance context was in a transition state
// so we should ignore STATUS_FILE_LOCK_CONFLICT too.
//
ASSERT( (status == STATUS_INSUFFICIENT_RESOURCES) ||
(status == STATUS_FILE_LOCK_CONFLICT) );
}
} else {
//
// The lock operation suceeded - update the
// MetadataOpenTriggerFileObject in the instance context to
// the File Object that performed the lock operation. This
// is so we can recognize an implicit unlock at close time.
//
// You may have noticed that we set the
// MetadataOpenTriggerFileObject in pre-create and may be
// wondering why we set it again in this case. This is to
// support a lower filter doing a recursive lock operation
// from the top of the stack.
//
status = FmmSetMetadataOpenTriggerFileObject( Cbd );
if (!NT_SUCCESS( status )) {
DebugTrace( DEBUG_TRACE_ERROR | DEBUG_TRACE_METADATA_OPERATIONS,
("[Fmm]: Failed to update MetadataOpenTriggerFileObject in the instance context with status 0x%x after a successful lock.\n",
status,
Cbd->IoStatus.Status) );
//
// Sanity - we are now in a bad state. We have failed to set the TriggerFileObject
// We may not be able to detect an unlock operation on which we need to
// re-acquire our metadata file references
//
ASSERT( status == STATUS_FILE_LOCK_CONFLICT );
}
}
}
//
// We do not need to process volume opens any further
//
goto FmmPostCreateCleanup;
}
//
// Here the filter can do any further processing it may want to do
// in the PostCreate Callback
//
FmmPostCreateCleanup:
if (!NT_SUCCESS( status )) {
DebugTrace( DEBUG_TRACE_ERROR,
("[Fmm]: FmmPostCreate -> Failed with status 0x%x \n",
status) );
//
// It does not make sense to fail in the the post op, since the operation has completed
//
}
DebugTrace( DEBUG_TRACE_ALL_IO,
("[Fmm]: FmmPostCreate -> Exit (Cbd = %p, FileObject = %p, Status = 0x%08X)\n",
Cbd,
FltObjects->FileObject,
Cbd->IoStatus.Status) );
return FLT_POSTOP_FINISHED_PROCESSING;
}
FLT_PREOP_CALLBACK_STATUS
FmmPreCleanup (
IN OUT PFLT_CALLBACK_DATA Cbd,
IN PCFLT_RELATED_OBJECTS FltObjects,
OUT PVOID *CompletionContext
)
{
UNREFERENCED_PARAMETER( Cbd );
UNREFERENCED_PARAMETER( CompletionContext );
UNREFERENCED_PARAMETER( FltObjects );
PAGED_CODE();
DebugTrace( DEBUG_TRACE_ALL_IO,
("[Fmm]: FmmPreCleanup -> Enter (Cbd = %p, FileObject = %p)\n",
Cbd,
FltObjects->FileObject) );
DebugTrace( DEBUG_TRACE_ALL_IO,
("[Fmm]: FmmPreCleanup -> Exit (Cbd = %p, FileObject = %p)\n",
Cbd,
FltObjects->FileObject) );
return FLT_PREOP_SYNCHRONIZE;
}
FLT_POSTOP_CALLBACK_STATUS
FmmPostCleanup (
IN OUT PFLT_CALLBACK_DATA Cbd,
IN PCFLT_RELATED_OBJECTS FltObjects,
IN PVOID CbdContext,
IN FLT_POST_OPERATION_FLAGS Flags
)
{
PFMM_INSTANCE_CONTEXT instanceContext = NULL;
NTSTATUS status;
UNREFERENCED_PARAMETER( FltObjects );
UNREFERENCED_PARAMETER( CbdContext );
UNREFERENCED_PARAMETER( Flags );
ASSERT(!FlagOn(Flags,FLTFL_POST_OPERATION_DRAINING)); //can't drain this operation
//
// The pre-operation callback will return FLT_PREOP_SYNCHRONIZE if it needs a
// post operation callback. In this case, the Filter Manager will call the
// minifilter's post-operation callback in the context of the pre-operation
// thread, at IRQL <= APC_LEVEL. This allows the post-operation code to be
// pagable and also allows it to access paged data
//
PAGED_CODE();
DebugTrace( DEBUG_TRACE_ALL_IO,
("[Fmm]: FmmPostCleanup -> Enter (Cbd = %p, FileObject = %p)\n",
Cbd,
FltObjects->FileObject) );
//
// Initialize defaults
//
status = STATUS_SUCCESS;
if (FmmTargetIsVolumeOpen( Cbd )) {
if (NT_SUCCESS( Cbd->IoStatus.Status )) {
//
// A close on a volume handle could be an unlock if a lock was
// previously called on this handle. Check if this was a close
// on a volume handle on which a lock was previously successful.
// If so, re-acquire the references to our metadata file
//
status = FmmReacquireMetadataFileReferences( Cbd );
if (!NT_SUCCESS( status )) {
DebugTrace( DEBUG_TRACE_ERROR | DEBUG_TRACE_METADATA_OPERATIONS,
("[Fmm]: Failed to re-open metadata with status 0x%x after a successful unlock.\n",
status) );
//
// Sanity - we are now in a bad state. The volume was unlocked
// but we have not been able to re-acquire references to
// our metadata file
//
// Ntfs dismounts and remounts the volume after an unlock. So we ignore
// failures to open the metadata with STATUS_INVALID_DEVICE_OBJECT_PARAMETER
// because the volume should have been remounted and the metadata file
// should have been opened on the newly mounted instance of that volume
//
// Note however, that if this is an implicit lock (used by autoXXX.exe) then
// ntfs will not automatically dismount the volume. It relies on the application
// to restart the system if it has made any changes to the volume. If the
// application has not made any changes then ntfs will simply continue on
// after the unlock without dismounting the volume. Hence we cannot assume
// that ntfs always dismounts the volume. We need to try to re-acquire
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -