📄 fsctrl.c
字号:
//
UdfCompleteRequest( IrpContext, Irp, Status );
DebugTrace(( -1, Dbg, "UdfMountVolume -> %08x\n", Status ));
return Status;
}
//
// Local support routine
//
NTSTATUS
UdfVerifyVolume (
IN PIRP_CONTEXT IrpContext,
IN PIRP Irp
)
/*++
Routine Description:
This routine performs the verify volume operation. It is responsible for
either completing of enqueuing the input Irp.
Arguments:
Irp - Supplies the Irp to process
Return Value:
NTSTATUS - The return status for the operation
--*/
{
PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation( Irp );
PVPB Vpb = IrpSp->Parameters.VerifyVolume.Vpb;
PVCB Vcb = &((PVOLUME_DEVICE_OBJECT) IrpSp->Parameters.VerifyVolume.DeviceObject)->Vcb;
PPCB Pcb = NULL;
PNSR_ANCHOR AnchorVolumeDescriptor = NULL;
PNSR_PVD PrimaryVolumeDescriptor = NULL;
PNSR_LVOL LogicalVolumeDescriptor = NULL;
PNSR_FSD FileSetDescriptor = NULL;
ULONG MediaChangeCount = 0;
ULONG Index;
PFILE_OBJECT FileObjectToNotify = NULL;
BOOLEAN ReturnError;
BOOLEAN ReleaseVcb;
IO_STATUS_BLOCK Iosb;
WCHAR VolumeLabel[ MAXIMUM_VOLUME_LABEL_LENGTH / sizeof( WCHAR )];
USHORT VolumeLabelLength;
ULONG VolumeSerialNumber;
NTSTATUS Status;
PAGED_CODE();
//
// Check input.
//
ASSERT_IRP_CONTEXT( IrpContext );
//
// Check that we are talking to a Cdrom or Disk device. This request should
// always be waitable.
//
ASSERT( Vpb->RealDevice->DeviceType == FILE_DEVICE_CD_ROM ||
Vpb->RealDevice->DeviceType == FILE_DEVICE_DISK );
ASSERT_VCB( Vcb );
//
// Update the real device in the IrpContext from the Vpb. There was no available
// file object when the IrpContext was created.
//
IrpContext->RealDevice = Vpb->RealDevice;
//
// Acquire shared global access, the termination handler for the
// following try statement will free the access.
//
UdfAcquireUdfData( IrpContext );
UdfAcquireVcbExclusive( IrpContext, Vcb, FALSE );
ReleaseVcb = TRUE;
DebugTrace(( +1, Dbg, "UdfVerifyVolume, Vcb %08x\n", Vcb ));
try {
//
// Check if the real device still needs to be verified. If it doesn't
// then obviously someone beat us here and already did the work
// so complete the verify irp with success. Otherwise reenable
// the real device and get to work.
//
if (!FlagOn( Vpb->RealDevice->Flags, DO_VERIFY_VOLUME )) {
DebugTrace(( 0, Dbg, "UdfVerifyVolume, verify bit was cleared out ahead of us\n" ));
MediaChangeCount = Vcb->MediaChangeCount;
try_leave( Status = STATUS_SUCCESS );
}
//
// Verify that there is a disk here.
//
Status = UdfPerformDevIoCtrl( IrpContext,
( Vpb->RealDevice->DeviceType == FILE_DEVICE_CD_ROM ?
IOCTL_CDROM_CHECK_VERIFY :
IOCTL_DISK_CHECK_VERIFY ),
Vcb->TargetDeviceObject,
&MediaChangeCount,
sizeof(ULONG),
FALSE,
TRUE,
&Iosb );
if (!NT_SUCCESS( Status )) {
DebugTrace(( 0, Dbg, "UdfVerifyVolume, CHECK_VERIFY failed\n" ));
//
// If we will allow a raw mount then return WRONG_VOLUME to
// allow the volume to be mounted by raw.
//
if (FlagOn( IrpSp->Flags, SL_ALLOW_RAW_MOUNT )) {
DebugTrace(( 0, Dbg, "UdfVerifyVolume, ... allowing raw mount\n" ));
Status = STATUS_WRONG_VOLUME;
}
try_leave( Status );
}
if (Iosb.Information != sizeof(ULONG)) {
//
// Be safe about the count in case the driver didn't fill it in
//
MediaChangeCount = 0;
}
//
// Verify that the device actually saw a change. If the driver does not
// support the MCC, then we must verify the volume in any case.
//
if (MediaChangeCount == 0 || Vcb->MediaChangeCount != MediaChangeCount) {
//
// Now we need to navigate the disc to find the relavent decriptors. This is
// much the same as the mount process.
//
//
// Find the AVD.
//
Status = UdfFindAnchorVolumeDescriptor( IrpContext,
Vcb,
&AnchorVolumeDescriptor );
if (!NT_SUCCESS(Status)) {
DebugTrace(( 0, Dbg, "UdfVerifyVolume, No AVD visible\n" ));
try_leave( Status = STATUS_WRONG_VOLUME );
}
//
// Get the prevailing descriptors out of the VDS, building a fresh Pcb.
//
Status = UdfFindVolumeDescriptors( IrpContext,
Vcb,
&AnchorVolumeDescriptor->Main,
&Pcb,
&PrimaryVolumeDescriptor,
&LogicalVolumeDescriptor );
//
// Try the reserve sequence in case of error.
//
if (Status == STATUS_DISK_CORRUPT_ERROR) {
Status = UdfFindVolumeDescriptors( IrpContext,
Vcb,
&AnchorVolumeDescriptor->Reserve,
&Pcb,
&PrimaryVolumeDescriptor,
&LogicalVolumeDescriptor );
}
//
// If we're totally unable to find a VDS, give up.
//
if (!NT_SUCCESS(Status)) {
DebugTrace(( 0, Dbg, "UdfVerifyVolume, PVD/LVD/PD pickup failed\n" ));
try_leave( Status = STATUS_WRONG_VOLUME );
}
//
// Now go complete initialization of the Pcb so we can compare it.
//
Status = UdfCompletePcb( IrpContext,
Vcb,
Pcb );
if (!NT_SUCCESS(Status)) {
DebugTrace(( 0, Dbg, "UdfVerifyVolume, Pcb completion failed\n" ));
try_leave( Status = STATUS_WRONG_VOLUME );
}
//
// Now let's compare this new Pcb to the previous Vcb's Pcb to see if they
// appear to be equivalent.
//
if (!UdfEquivalentPcb( IrpContext,
Pcb,
Vcb->Pcb)) {
DebugTrace(( 0, Dbg, "UdfVerifyVolume, Pcbs are not equivalent\n" ));
try_leave( Status = STATUS_WRONG_VOLUME );
}
//
// At this point we know that the Vcb's Pcb is OK for mapping to find the fileset
// descriptor, so we can drop the new one we built for comparison purposes.
//
UdfDeletePcb( Pcb );
Pcb = NULL;
//
// Go pick up the fileset descriptor.
//
Status = UdfFindFileSetDescriptor( IrpContext,
Vcb,
&LogicalVolumeDescriptor->FSD,
&FileSetDescriptor );
if (!NT_SUCCESS(Status)) {
try_leave( Status = STATUS_WRONG_VOLUME );
}
//
// Now that everything is in place, build a volume label and serial number from these
// descriptors and perform the final check that this Vcb is (or is not) the right one
// for the media now in the drive.
//
UdfUpdateVolumeLabel( IrpContext,
VolumeLabel,
&VolumeLabelLength,
LogicalVolumeDescriptor->VolumeID,
sizeof( LogicalVolumeDescriptor->VolumeID ));
UdfUpdateVolumeSerialNumber( IrpContext,
&VolumeSerialNumber,
FileSetDescriptor );
if (Vcb->Vpb->SerialNumber != VolumeSerialNumber ||
Vcb->Vpb->VolumeLabelLength != VolumeLabelLength ||
RtlCompareMemory( Vcb->Vpb->VolumeLabel,
VolumeLabel,
VolumeLabelLength )) {
DebugTrace(( 0, Dbg, "UdfVerifyVolume, volume label/sn mismatch\n" ));
try_leave( Status = STATUS_WRONG_VOLUME );
}
}
//
// The volume is OK, clear the verify bit.
//
DebugTrace(( 0, Dbg, "UdfVerifyVolume, looks like the same volume\n" ));
Vcb->VcbCondition = VcbMounted;
ClearFlag( Vpb->RealDevice->Flags, DO_VERIFY_VOLUME );
//
// See if we will need to provide notification of the remount. This is the readonly
// filesystem's form of dismount/mount notification.
//
if (FlagOn( Vcb->VcbState, VCB_STATE_NOTIFY_REMOUNT )) {
ClearFlag( Vcb->VcbState, VCB_STATE_NOTIFY_REMOUNT );
FileObjectToNotify = Vcb->RootIndexFcb->FileObject;
ObReferenceObject( FileObjectToNotify );
}
} finally {
//
// If we did not raise an exception, update the current Vcb.
//
if (!AbnormalTermination()) {
//
// Update the media change count to note that we have verified the volume
// at this value
//
Vcb->MediaChangeCount = MediaChangeCount;
//
// Mark the Vcb as not mounted.
//
if (Status == STATUS_WRONG_VOLUME) {
Vcb->VcbCondition = VcbNotMounted;
//
// Now, if there are no user handles to the volume, try to spark
// teardown by purging the volume.
//
if (Vcb->VcbCleanup == 0) {
if (NT_SUCCESS( UdfPurgeVolume( IrpContext, Vcb, FALSE ))) {
ReleaseVcb = UdfCheckForDismount( IrpContext, Vcb, FALSE );
}
}
}
}
DebugTrace(( -1, Dbg, "UdfVerifyVolume -> %08x\n", Status ));
if (ReleaseVcb) {
UdfReleaseVcb( IrpContext, Vcb );
}
UdfReleaseUdfData( IrpContext );
//
// Delete the Pcb if built.
//
if (Pcb != NULL) {
UdfDeletePcb( Pcb );
}
UdfFreePool( &AnchorVolumeDescriptor );
UdfFreePool( &PrimaryVolumeDescriptor );
UdfFreePool( &LogicalVolumeDescriptor );
UdfFreePool( &FileSetDescriptor );
}
//
// Now send mount notification.
//
if (FileObjectToNotify) {
FsRtlNotifyVolumeEvent( FileObjectToNotify, FSRTL_VOLUME_MOUNT );
ObDereferenceObject( FileObjectToNotify );
}
//
// Complete the request if no exception.
//
UdfCompleteRequest( IrpContext, Irp, Status );
return Status;
}
//
// Local support routine
//
BOOLEAN
UdfIsRemount (
IN PIRP_CONTEXT IrpContext,
IN PVCB Vcb,
OUT PVCB *OldVcb
)
/*++
Routine Description:
This routine walks through the links of the Vcb chain in the global
data structure. The remount condition is met when the following
conditions are all met:
1 - The 32 serial for this VPB matches that in a previous
VPB.
2 - The volume label for this VPB matches that in the previous
VPB.
3 - The system pointer to the real device object in the current
VPB matches that in the same previous VPB.
4 - Finally the previous Vcb cannot be invalid or have a dismount
underway.
If a VPB is found which matches these conditions, then the address of
the Vcb for that VPB is returned via the pointer OldVcb.
Skip over the current Vcb.
Arguments:
Vcb - This is the Vcb we are checking for a remount.
OldVcb - A pointer to the address to store the address for the Vcb
for the volume if this is a remount. (This is a pointer to
a pointer)
Return Value:
BOOLEAN - TRUE if this is in fact a remount, FALSE otherwise.
--*/
{
PLIST_ENTRY Link;
PVPB Vpb = Vcb->Vpb;
PVPB OldVpb;
BOOLEAN Remount = FALSE;
PAGED_CODE();
//
// Check input.
//
ASSERT_IRP_CONTEXT( IrpContext );
ASSERT_VCB( Vcb );
DebugTrace(( +1, Dbg, "UdfIsRemount, Vcb %08x\n", Vcb ));
for (Link = UdfData.VcbQueue.Flink;
Link != &UdfData.VcbQueue;
Link = Link->Flink) {
*OldVcb = CONTAINING_RECORD( Link, VCB, VcbLinks );
//
// Skip ourselves.
//
if (Vcb == *OldVcb) { continue; }
//
// Look at the Vpb and state of the previous Vcb.
//
OldVpb = (*OldVcb)->Vpb;
if ((OldVpb != Vpb) &&
(OldVpb->RealDevice == Vpb->RealDevice) &&
((*OldVcb)->VcbCondition == VcbNotMounted)) {
//
// Go ahead and compare serial numbers and volume label.
//
if ((OldVpb->SerialNumber == Vpb->SerialNumber) &&
(Vpb->VolumeLabelLength == OldVpb->VolumeLabelLength) &&
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -