📄 verfysup.c
字号:
/*++
Copyright (c) 1989-2000 Microsoft Corporation
Module Name:
VerfySup.c
Abstract:
This module implements the Fat Verify volume and fcb/dcb support
routines
--*/
#include "FatProcs.h"
//
// The Bug check file id for this module
//
#define BugCheckFileId (FAT_BUG_CHECK_VERFYSUP)
//
// The Debug trace level for this module
//
#define Dbg (DEBUG_TRACE_VERFYSUP)
//
// Local procedure prototypes
//
VOID
FatResetFcb (
IN PIRP_CONTEXT IrpContext,
IN PFCB Fcb
);
VOID
FatDetermineAndMarkFcbCondition (
IN PIRP_CONTEXT IrpContext,
IN PFCB Fcb
);
VOID
FatDeferredCleanVolume (
PVOID Parameter
);
NTSTATUS
FatMarkVolumeCompletionRoutine(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp,
IN PVOID Contxt
);
#ifdef ALLOC_PRAGMA
#pragma alloc_text(PAGE, FatCheckDirtyBit)
#pragma alloc_text(PAGE, FatVerifyOperationIsLegal)
#pragma alloc_text(PAGE, FatDeferredCleanVolume)
#pragma alloc_text(PAGE, FatDetermineAndMarkFcbCondition)
#pragma alloc_text(PAGE, FatQuickVerifyVcb)
#pragma alloc_text(PAGE, FatPerformVerify)
#pragma alloc_text(PAGE, FatMarkFcbCondition)
#pragma alloc_text(PAGE, FatResetFcb)
#pragma alloc_text(PAGE, FatVerifyVcb)
#pragma alloc_text(PAGE, FatVerifyFcb)
#endif
VOID
FatMarkFcbCondition (
IN PIRP_CONTEXT IrpContext,
IN PFCB Fcb,
IN FCB_CONDITION FcbCondition,
IN BOOLEAN Recursive
)
/*++
Routine Description:
This routines marks the entire Fcb/Dcb structure from Fcb down with
FcbCondition.
Arguments:
Fcb - Supplies the Fcb/Dcb being marked
FcbCondition - Supplies the setting to use for the Fcb Condition
Recursive - Specifies whether this condition should be applied to
all children (see the case where we are invalidating a live volume
for a case where this is now desireable).
Return Value:
None.
--*/
{
DebugTrace(+1, Dbg, "FatMarkFcbCondition, Fcb = %08lx\n", Fcb );
//
// If we are marking this Fcb something other than Good, we will need
// to have the Vcb exclusive.
//
ASSERT( FcbCondition != FcbNeedsToBeVerified ? TRUE :
FatVcbAcquiredExclusive(IrpContext, Fcb->Vcb) );
//
// If this is a PagingFile it has to be good.
//
if (FlagOn(Fcb->FcbState, FCB_STATE_PAGING_FILE)) {
Fcb->FcbCondition = FcbGood;
return;
}
//
// Update the condition of the Fcb.
//
Fcb->FcbCondition = FcbCondition;
DebugTrace(0, Dbg, "MarkFcb: %Z\n", &Fcb->FullFileName);
//
// This FastIo flag is based on FcbCondition, so update it now. This only
// applies to regular FCBs, of course.
//
if (Fcb->Header.NodeTypeCode == FAT_NTC_FCB) {
Fcb->Header.IsFastIoPossible = FatIsFastIoPossible( Fcb );
}
//
// Now if we marked NeedsVerify or Bad a directory then we also need to
// go and mark all of our children with the same condition.
//
if ( ((FcbCondition == FcbNeedsToBeVerified) ||
(FcbCondition == FcbBad)) &&
Recursive &&
((Fcb->Header.NodeTypeCode == FAT_NTC_DCB) ||
(Fcb->Header.NodeTypeCode == FAT_NTC_ROOT_DCB)) ) {
PFCB OriginalFcb = Fcb;
while ( (Fcb = FatGetNextFcbTopDown(IrpContext, Fcb, OriginalFcb)) != NULL ) {
DebugTrace(0, Dbg, "MarkFcb: %Z\n", &Fcb->FullFileName);
Fcb->FcbCondition = FcbCondition;
//
// We already know that FastIo is not possible since we are propagating
// a parent's bad/verify flag down the tree - IO to the children must
// take the long route for now.
//
Fcb->Header.IsFastIoPossible = FastIoIsNotPossible;
}
}
DebugTrace(-1, Dbg, "FatMarkFcbCondition -> VOID\n", 0);
return;
}
BOOLEAN
FatMarkDevForVerifyIfVcbMounted(
IN PVCB Vcb
)
/*++
Routine Description:
This routine checks to see if the specified Vcb is currently mounted on
the device or not. If it is, it sets the verify flag on the device, if
not then the state is noted in the Vcb.
Arguments:
Vcb - This is the volume to check.
Return Value:
TRUE if the device has been marked for verify here, FALSE otherwise.
--*/
{
BOOLEAN Marked = FALSE;
KIRQL SavedIrql;
IoAcquireVpbSpinLock( &SavedIrql );
if (Vcb->Vpb->RealDevice->Vpb == Vcb->Vpb) {
SetFlag( Vcb->Vpb->RealDevice->Flags, DO_VERIFY_VOLUME);
Marked = TRUE;
}
else {
//
// Flag this to avoid the VPB spinlock in future passes.
//
SetFlag( Vcb->VcbState, VCB_STATE_VPB_NOT_ON_DEVICE);
}
IoReleaseVpbSpinLock( SavedIrql );
return Marked;
}
VOID
FatVerifyVcb (
IN PIRP_CONTEXT IrpContext,
IN PVCB Vcb
)
/*++
Routine Description:
This routines verifies that the Vcb still denotes a valid Volume
If the Vcb is bad it raises an error condition.
Arguments:
Vcb - Supplies the Vcb being verified
Return Value:
None.
--*/
{
ULONG ChangeCount = 0;
BOOLEAN DevMarkedForVerify;
NTSTATUS Status = STATUS_SUCCESS;
IO_STATUS_BLOCK Iosb;
DebugTrace(+1, Dbg, "FatVerifyVcb, Vcb = %08lx\n", Vcb );
//
// If the media is removable and the verify volume flag in the
// device object is not set then we want to ping the device
// to see if it needs to be verified.
//
// Note that we only force this ping for create operations.
// For others we take a sporting chance. If in the end we
// have to physically access the disk, the right thing will happen.
//
DevMarkedForVerify = BooleanFlagOn(Vcb->Vpb->RealDevice->Flags, DO_VERIFY_VOLUME);
if (FlagOn(Vcb->VcbState, VCB_STATE_FLAG_REMOVABLE_MEDIA)) {
Status = FatPerformDevIoCtrl( IrpContext,
( Vcb->Vpb->RealDevice->DeviceType == FILE_DEVICE_CD_ROM ?
IOCTL_CDROM_CHECK_VERIFY :
IOCTL_DISK_CHECK_VERIFY ),
Vcb->TargetDeviceObject,
&ChangeCount,
sizeof(ULONG),
FALSE,
TRUE,
&Iosb );
if (Iosb.Information != sizeof(ULONG)) {
//
// Be safe about the count in case the driver didn't fill it in
//
ChangeCount = 0;
}
//
// There are four cases when we want to do a verify. These are the
// first three.
//
// 1. We are mounted, and the device has become empty
// 2. The device has returned verify required (=> DO_VERIFY_VOL flag is
// set, but could be due to hardware condition)
// 3. Media change count doesn't match the one in the Vcb
//
if (((Vcb->VcbCondition == VcbGood) &&
FatIsRawDevice( IrpContext, Status ))
||
(Status == STATUS_VERIFY_REQUIRED)
||
(NT_SUCCESS(Status) &&
(Vcb->ChangeCount != ChangeCount))) {
//
// If we are currently the volume on the device then it is our
// responsibility to set the verify flag. If we're not on the device,
// then we shouldn't touch the flag.
//
if (!FlagOn( Vcb->VcbState, VCB_STATE_VPB_NOT_ON_DEVICE) &&
!DevMarkedForVerify) {
DevMarkedForVerify = FatMarkDevForVerifyIfVcbMounted( Vcb);
}
}
}
//
// This is the 4th verify case.
//
// We ALWAYS force CREATE requests on unmounted volumes through the
// verify path. These requests could have been in limbo between
// IoCheckMountedVpb and us, when a verify/mount took place and caused
// a completely different fs/volume to be mounted. In this case the
// checks above may not have caught the condition, since we may already
// have verified (wrong volume) and decided that we have nothing to do.
// We want the requests to be re routed to the currently mounted volume,
// since they were directed at the 'drive', not our volume. So we take
// the verify path for synchronisation, and the request will eventually
// be bounced back to IO with STATUS_REPARSE by our verify handler.
//
if (!DevMarkedForVerify && (IrpContext->MajorFunction == IRP_MJ_CREATE)) {
PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation( IrpContext->OriginatingIrp);
if ((IrpSp->FileObject->RelatedFileObject == NULL) &&
(Vcb->VcbCondition == VcbNotMounted)) {
DevMarkedForVerify = TRUE;
}
}
//
// Raise any error condition otherwise.
//
if (!NT_SUCCESS( Status ) || DevMarkedForVerify) {
DebugTrace(0, Dbg, "The Vcb needs to be verified\n", 0);
IoSetHardErrorOrVerifyDevice( IrpContext->OriginatingIrp,
Vcb->Vpb->RealDevice );
FatNormalizeAndRaiseStatus( IrpContext, DevMarkedForVerify
? STATUS_VERIFY_REQUIRED
: Status );
}
//
// Check the operation is legal for current Vcb state.
//
FatQuickVerifyVcb( IrpContext, Vcb );
DebugTrace(-1, Dbg, "FatVerifyVcb -> VOID\n", 0);
}
VOID
FatVerifyFcb (
IN PIRP_CONTEXT IrpContext,
IN PFCB Fcb
)
/*++
Routine Description:
This routines verifies that the Fcb still denotes the same file.
If the Fcb is bad it raises a error condition.
Arguments:
Fcb - Supplies the Fcb being verified
Return Value:
None.
--*/
{
PFCB CurrentFcb;
DebugTrace(+1, Dbg, "FatVerifyFcb, Vcb = %08lx\n", Fcb );
//
// Always refuse operations on dismounted volumes.
//
if (FlagOn( Fcb->Vcb->VcbState, VCB_STATE_FLAG_VOLUME_DISMOUNTED )) {
FatRaiseStatus( IrpContext, STATUS_VOLUME_DISMOUNTED );
}
//
// If this is the Fcb of a deleted dirent or our parent is deleted,
// no-op this call with the hope that the caller will do the right thing.
// The only caller we really have to worry about is the AdvanceOnly
// callback for setting valid data length from Cc, this will happen after
// cleanup (and file deletion), just before the SCM is ripped down.
//
if (IsFileDeleted( IrpContext, Fcb ) ||
((NodeType(Fcb) != FAT_NTC_ROOT_DCB) &&
IsFileDeleted( IrpContext, Fcb->ParentDcb ))) {
return;
}
//
// If we are not in the process of doing a verify,
// first do a quick spot check on the Vcb.
//
if ( Fcb->Vcb->VerifyThread != KeGetCurrentThread() ) {
FatQuickVerifyVcb( IrpContext, Fcb->Vcb );
}
//
// Now based on the condition of the Fcb we'll either return
// immediately to the caller, raise a condition, or do some work
// to verify the Fcb.
//
switch (Fcb->FcbCondition) {
case FcbGood:
DebugTrace(0, Dbg, "The Fcb is good\n", 0);
break;
case FcbBad:
FatRaiseStatus( IrpContext, STATUS_FILE_INVALID );
break;
case FcbNeedsToBeVerified:
//
// We loop here checking our ancestors until we hit an Fcb which
// is either good or bad.
//
CurrentFcb = Fcb;
while (CurrentFcb->FcbCondition == FcbNeedsToBeVerified) {
FatDetermineAndMarkFcbCondition(IrpContext, CurrentFcb);
//
// If this Fcb didn't make it, or it was the Root Dcb, exit
// the loop now, else continue with out parent.
//
if ( (CurrentFcb->FcbCondition != FcbGood) ||
(NodeType(CurrentFcb) == FAT_NTC_ROOT_DCB) ) {
break;
}
CurrentFcb = CurrentFcb->ParentDcb;
}
//
// Now we can just look at ourselves to see how we did.
//
if (Fcb->FcbCondition != FcbGood) {
FatRaiseStatus( IrpContext, STATUS_FILE_INVALID );
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -