📄 verfysup.c
字号:
break;
default:
DebugDump("Invalid FcbCondition\n", 0, Fcb);
FatBugCheck( Fcb->FcbCondition, 0, 0 );
}
DebugTrace(-1, Dbg, "FatVerifyFcb -> VOID\n", 0);
return;
}
VOID
FatDeferredCleanVolume (
PVOID Parameter
)
/*++
Routine Description:
This is the routine that performs the actual FatMarkVolumeClean call.
It assures that the target volume still exists as there ia a race
condition between queueing the ExWorker item and volumes going away.
Arguments:
Parameter - Points to a clean volume packet that was allocated from pool
Return Value:
None.
--*/
{
PCLEAN_AND_DIRTY_VOLUME_PACKET Packet;
PLIST_ENTRY Links;
PVCB Vcb;
IRP_CONTEXT IrpContext;
BOOLEAN VcbExists = FALSE;
DebugTrace(+1, Dbg, "FatDeferredCleanVolume\n", 0);
Packet = (PCLEAN_AND_DIRTY_VOLUME_PACKET)Parameter;
Vcb = Packet->Vcb;
//
// Make us appear as a top level FSP request so that we will
// receive any errors from the operation.
//
IoSetTopLevelIrp( (PIRP)FSRTL_FSP_TOP_LEVEL_IRP );
//
// Dummy up and Irp Context so we can call our worker routines
//
RtlZeroMemory( &IrpContext, sizeof(IRP_CONTEXT));
SetFlag(IrpContext.Flags, IRP_CONTEXT_FLAG_WAIT);
//
// Acquire shared access to the global lock and make sure this volume
// still exists.
//
FatAcquireSharedGlobal( &IrpContext );
for (Links = FatData.VcbQueue.Flink;
Links != &FatData.VcbQueue;
Links = Links->Flink) {
PVCB ExistingVcb;
ExistingVcb = CONTAINING_RECORD(Links, VCB, VcbLinks);
if ( Vcb == ExistingVcb ) {
VcbExists = TRUE;
break;
}
}
//
// If the vcb is good then mark it clean. Ignore any problems.
//
if ( VcbExists &&
(Vcb->VcbCondition == VcbGood) &&
!FlagOn(Vcb->VcbState, VCB_STATE_FLAG_SHUTDOWN) ) {
try {
if (!FlagOn(Vcb->VcbState, VCB_STATE_FLAG_MOUNTED_DIRTY)) {
FatMarkVolume( &IrpContext, Vcb, VolumeClean );
}
//
// Check for a pathological race condition, and fix it.
//
if (FlagOn(Vcb->VcbState, VCB_STATE_FLAG_VOLUME_DIRTY)) {
FatMarkVolume( &IrpContext, Vcb, VolumeDirty );
} else {
//
// Unlock the volume if it is removable.
//
if (FlagOn(Vcb->VcbState, VCB_STATE_FLAG_REMOVABLE_MEDIA) &&
!FlagOn(Vcb->VcbState, VCB_STATE_FLAG_BOOT_OR_PAGING_FILE)) {
FatToggleMediaEjectDisable( &IrpContext, Vcb, FALSE );
}
}
} except( FsRtlIsNtstatusExpected(GetExceptionCode()) ?
EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH ) {
NOTHING;
}
}
//
// Release the global resource, unpin and repinned Bcbs and return.
//
FatReleaseGlobal( &IrpContext );
try {
FatUnpinRepinnedBcbs( &IrpContext );
} except( FsRtlIsNtstatusExpected(GetExceptionCode()) ?
EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH ) {
NOTHING;
}
IoSetTopLevelIrp( NULL );
//
// and finally free the packet.
//
ExFreePool( Packet );
return;
}
VOID
FatCleanVolumeDpc (
IN PKDPC Dpc,
IN PVOID DeferredContext,
IN PVOID SystemArgument1,
IN PVOID SystemArgument2
)
/*++
Routine Description:
This routine is dispatched 5 seconds after the last disk structure was
modified in a specific volume, and exqueues an execuative worker thread
to perform the actual task of marking the volume dirty.
Arguments:
DefferedContext - Contains the Vcb to process.
Return Value:
None.
--*/
{
PVCB Vcb;
PCLEAN_AND_DIRTY_VOLUME_PACKET Packet;
Vcb = (PVCB)DeferredContext;
//
// If there is still dirty data (highly unlikely), set the timer for a
// second in the future.
//
if (CcIsThereDirtyData(Vcb->Vpb)) {
LARGE_INTEGER TwoSecondsFromNow;
TwoSecondsFromNow.QuadPart = (LONG)-2*1000*1000*10;
KeSetTimer( &Vcb->CleanVolumeTimer,
TwoSecondsFromNow,
&Vcb->CleanVolumeDpc );
return;
}
//
// If we couldn't get pool, oh well....
//
Packet = ExAllocatePoolWithTag(NonPagedPool, sizeof(CLEAN_AND_DIRTY_VOLUME_PACKET), ' taF');
if ( Packet ) {
Packet->Vcb = Vcb;
Packet->Irp = NULL;
//
// Clear the dirty flag now since we cannot synchronize after this point.
//
ClearFlag( Packet->Vcb->VcbState, VCB_STATE_FLAG_VOLUME_DIRTY );
ExInitializeWorkItem( &Packet->Item, &FatDeferredCleanVolume, Packet );
ExQueueWorkItem( &Packet->Item, CriticalWorkQueue );
}
return;
}
VOID
FatMarkVolume (
IN PIRP_CONTEXT IrpContext,
IN PVCB Vcb,
IN FAT_VOLUME_STATE VolumeState
)
/*++
Routine Description:
This routine moves the physically marked volume state between the clean
and dirty states. For compatibility with Win9x, we manipulate both the
historical DOS (on==clean in index 1 of the FAT) and NT (on==dirty in
the CurrentHead field of the BPB) dirty bits.
Arguments:
Vcb - Supplies the Vcb being modified
VolumeState - Supplies the state the volume is transitioning to
Return Value:
None.
--*/
{
PCHAR Sector;
PBCB Bcb = NULL;
KEVENT Event;
PIRP Irp = NULL;
NTSTATUS Status;
BOOLEAN FsInfoUpdate = FALSE;
ULONG FsInfoOffset = 0;
ULONG ThisPass;
LARGE_INTEGER Offset;
BOOLEAN abort = FALSE;
DebugTrace(+1, Dbg, "FatMarkVolume, Vcb = %08lx\n", Vcb);
//
// We had best not be trying to scribble dirty/clean bits if the
// volume is write protected. The responsibility lies with the
// callers to make sure that operations that could cause a state
// change cannot happen. There are a few, though, that show it
// just doesn't make sense to force everyone to do the dinky
// check.
//
//
// If we were called for FAT12 or readonly media, return immediately.
//
if (FlagOn(Vcb->VcbState, VCB_STATE_FLAG_WRITE_PROTECTED) ||
FatIsFat12( Vcb )) {
return;
}
//
// We have two possible additional tasks to do to mark a volume
//
// Pass 0) Flip the dirty bit in the Bpb
// Pass 1) Rewrite the FsInfo sector for FAT32 if needed
//
// In most cases we can collapse these two either because the volume
// is either not FAT32 or the FsInfo sector is adjacent to the boot sector.
//
for (ThisPass = 0; ThisPass < 2; ThisPass++) {
//
// If this volume is being dirtied, or isn't FAT32, or if it is and
// we were able to perform the fast update, or the bpb lied to us
// about where the FsInfo went, we're done - no FsInfo to update in
// a seperate write.
//
if (ThisPass == 1 && (!FatIsFat32( Vcb ) ||
VolumeState != VolumeClean ||
FsInfoUpdate ||
Vcb->Bpb.FsInfoSector == 0)) {
break;
}
//
// Bail if we get an IO error.
//
try {
ULONG PinLength;
ULONG WriteLength;
//
// If the FAT table is 12-bit then our strategy is to pin the entire
// thing when any of it is modified. Here we're going to pin the
// first page, so in the 12-bit case we also want to pin the rest
// of the FAT table.
//
Offset.QuadPart = 0;
if (Vcb->AllocationSupport.FatIndexBitSize == 12) {
//
// But we only write back the first sector.
//
PinLength = FatReservedBytes(&Vcb->Bpb) + FatBytesPerFat(&Vcb->Bpb);
WriteLength = Vcb->Bpb.BytesPerSector;
} else {
WriteLength = PinLength = Vcb->Bpb.BytesPerSector;
//
// If this is a FAT32 volume going into the clean state,
// see about doing the FsInfo sector.
//
if (FatIsFat32( Vcb ) && VolumeState == VolumeClean) {
//
// If the FsInfo sector immediately follows the boot sector,
// we can do this in a single operation by rewriting both
// sectors at once.
//
if (Vcb->Bpb.FsInfoSector == 1) {
ASSERT( ThisPass == 0 );
FsInfoUpdate = TRUE;
FsInfoOffset = Vcb->Bpb.BytesPerSector;
WriteLength = PinLength = Vcb->Bpb.BytesPerSector * 2;
} else if (ThisPass == 1) {
//
// We are doing an explicit write to the FsInfo sector.
//
FsInfoUpdate = TRUE;
FsInfoOffset = 0;
Offset.QuadPart = Vcb->Bpb.BytesPerSector * Vcb->Bpb.FsInfoSector;
}
}
}
//
// Call Cc directly here so that we can avoid overhead and push this
// right down to the disk.
//
CcPinRead( Vcb->VirtualVolumeFile,
&Offset,
PinLength,
TRUE,
&Bcb,
(PVOID *)&Sector );
DbgDoit( IrpContext->PinCount += 1 )
//
// Set the Bpb on Pass 0 always
//
if (ThisPass == 0) {
PCHAR CurrentHead;
//
// Before we do anything, doublecheck that this still looks like a
// FAT bootsector. If it doesn't, something remarkable happened
// and we should avoid touching the volume.
//
// THIS IS TEMPORARY (but may last a while)
//
if (!FatIsBootSectorFat( (PPACKED_BOOT_SECTOR) Sector )) {
abort = TRUE;
leave;
}
if (FatIsFat32( Vcb )) {
CurrentHead = &((PPACKED_BOOT_SECTOR_EX) Sector)->CurrentHead;
} else {
CurrentHead = &((PPACKED_BOOT_SECTOR) Sector)->CurrentHead;
}
if (VolumeState == VolumeClean) {
ClearFlag( *CurrentHead, FAT_BOOT_SECTOR_DIRTY );
} else {
SetFlag( *CurrentHead, FAT_BOOT_SECTOR_DIRTY );
//
// In addition, if this request received an error that may indicate
// media corruption, have autochk perform a surface test.
//
if ( VolumeState == VolumeDirtyWithSurfaceTest ) {
SetFlag( *CurrentHead, FAT_BOOT_SECTOR_TEST_SURFACE );
}
}
}
//
// Update the FsInfo as appropriate.
//
if (FsInfoUpdate) {
PFSINFO_SECTOR FsInfoSector = (PFSINFO_SECTOR) ((PCHAR)Sector + FsInfoOffset);
//
// We just rewrite all of the spec'd fields. Note that we don't
// care to synchronize with the allocation package - this will be
// quickly taken care of by a re-dirtying of the volume if a change
// is racing with us. Remember that this is all a compatibility
// deference for Win9x FAT32 - NT will never look at this information.
//
FsInfoSector->SectorBeginSignature = FSINFO_SECTOR_BEGIN_SIGNATURE;
FsInfoSector->FsInfoSignature = FSINFO_SIGNATURE;
FsInfoSector->FreeClusterCount = Vcb->AllocationSupport.NumberOfFreeClusters;
FsInfoSector->NextFreeCluster = Vcb->ClusterHint;
FsInfoSector->SectorEndSignature = FSINFO_SECTOR_END_SIGNATURE;
}
//
// Initialize the event we're going to use
//
KeInitializeEvent( &Event, NotificationEvent, FALSE );
//
// Build the irp for the operation and also set the override flag.
// Note that we may be at APC level, so do this asyncrhonously and
// use an event for synchronization as normal request completion
// cannot occur at APC level.
//
Irp = IoBuildAsynchronousFsdRequest( IRP_MJ_WRITE,
Vcb->TargetDeviceObject,
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -