📄 fsctrl.c
字号:
ASSERT( Vpb->RealDevice->DeviceType == FILE_DEVICE_CD_ROM ||
Vpb->RealDevice->DeviceType == FILE_DEVICE_DISK );
ASSERT( FlagOn( IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT ));
DebugTrace(( +1, Dbg, "UdfMountVolume\n" ));
//
// 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;
//
// Check if we have disabled the mount process.
//
if (UdfDisable) {
UdfCompleteRequest( IrpContext, Irp, STATUS_UNRECOGNIZED_VOLUME );
DebugTrace(( 0, Dbg, "UdfMountVolume, disabled\n" ));
DebugTrace(( -1, Dbg, "UdfMountVolume -> STATUS_UNRECOGNIZED_VOLUME\n" ));
return STATUS_UNRECOGNIZED_VOLUME;
}
//
// Do a CheckVerify here to lift the MediaChange ticker from the driver
//
Status = UdfPerformDevIoCtrl( IrpContext,
( Vpb->RealDevice->DeviceType == FILE_DEVICE_CD_ROM ?
IOCTL_CDROM_CHECK_VERIFY :
IOCTL_DISK_CHECK_VERIFY ),
DeviceObjectWeTalkTo,
&MediaChangeCount,
sizeof(ULONG),
FALSE,
TRUE,
NULL );
if (!NT_SUCCESS( Status )) {
UdfCompleteRequest( IrpContext, Irp, Status );
DebugTrace(( 0, Dbg,
"UdfMountVolume, CHECK_VERIFY handed back status %08x (so don't continue)\n",
Status ));
DebugTrace(( -1, Dbg,
"UdfMountVolume -> %08x\n",
Status ));
return Status;
}
//
// Now let's make Jeff delirious and call to get the disk geometry. This
// will fix the case where the first change line is swallowed.
//
// This IOCTL does not have a generic STORAGE equivalent, so we must figure
// our which variant to pass down from the real underlying device object (as
// opposed to the top of the driver filter stack we will really be attaching
// on top of).
//
Status = UdfPerformDevIoCtrl( IrpContext,
( Vpb->RealDevice->DeviceType == FILE_DEVICE_CD_ROM ?
IOCTL_CDROM_GET_DRIVE_GEOMETRY :
IOCTL_DISK_GET_DRIVE_GEOMETRY ),
DeviceObjectWeTalkTo,
&DiskGeometry,
sizeof( DISK_GEOMETRY ),
FALSE,
TRUE,
NULL );
//
// If this call failed, we might be able to get away with a heuristic guess as to
// what the sector size is (per CDFS), but that is playing with fire. Nearly every
// failure here will be a permanent problem of some form.
//
if (!NT_SUCCESS( Status )) {
UdfCompleteRequest( IrpContext, Irp, Status );
DebugTrace(( 0, Dbg, "UdfMountVolume, GET_DRIVE_GEOMETRY failed\n" ));
DebugTrace(( -1, Dbg,
"UdfMountVolume -> %08x\n",
Status ));
return Status;
}
//
// Acquire the global resource to do mount operations.
//
UdfAcquireUdfData( IrpContext );
//
// Use a try-finally to facilitate cleanup.
//
try {
//
// Do a quick check to see if there any Vcb's which can be removed.
//
UdfScanForDismountedVcb( IrpContext );
//
// Make sure that the driver/drive is not screwing up underneath of us by
// feeding us garbage for the sector size.
//
if (DiskGeometry.BytesPerSector == 0 ||
(DiskGeometry.BytesPerSector & ~( 1 << UdfHighBit( DiskGeometry.BytesPerSector ))) != 0) {
DebugTrace(( 0, 0,
"UdfMountVolume, bad DiskGeometry (%08x) .BytesPerSector == %08x\n",
&DiskGeometry,
DiskGeometry.BytesPerSector ));
ASSERT( FALSE );
try_leave( Status = STATUS_DRIVER_INTERNAL_ERROR );
}
//
// Now go confirm that this volume may be a UDF image by looking for a
// valid ISO 13346 Volume Recognition Sequence.
//
if (!UdfRecognizeVolume( IrpContext,
DeviceObjectWeTalkTo,
DiskGeometry.BytesPerSector,
&BridgeMedia )) {
DebugTrace(( 0, Dbg, "UdfMountVolume, recognition failed so not mounting\n" ));
try_leave( Status = STATUS_UNRECOGNIZED_VOLUME );
}
//
// Create the DeviceObject for this mount attempt
//
Status = IoCreateDevice( UdfData.DriverObject,
sizeof( VOLUME_DEVICE_OBJECT ) - sizeof( DEVICE_OBJECT ),
NULL,
FILE_DEVICE_CD_ROM_FILE_SYSTEM,
0,
FALSE,
(PDEVICE_OBJECT *) &VolDo );
if (!NT_SUCCESS( Status )) {
DebugTrace(( 0, Dbg, "UdfMountVolume, couldn't get voldo! (%08x)\n", Status ));
try_leave( Status );
}
//
// Our alignment requirement is the larger of the processor alignment requirement
// already in the volume device object and that in the DeviceObjectWeTalkTo
//
if (DeviceObjectWeTalkTo->AlignmentRequirement > VolDo->DeviceObject.AlignmentRequirement) {
VolDo->DeviceObject.AlignmentRequirement = DeviceObjectWeTalkTo->AlignmentRequirement;
}
ClearFlag( VolDo->DeviceObject.Flags, DO_DEVICE_INITIALIZING );
//
// Initialize the overflow queue for the volume
//
VolDo->OverflowQueueCount = 0;
InitializeListHead( &VolDo->OverflowQueue );
VolDo->PostedRequestCount = 0;
KeInitializeSpinLock( &VolDo->OverflowQueueSpinLock );
//
// Now before we can initialize the Vcb we need to set up the
// device object field in the VPB to point to our new volume device
// object.
//
Vpb->DeviceObject = (PDEVICE_OBJECT) VolDo;
//
// Initialize the Vcb. This routine will raise on an allocation
// failure.
//
UdfInitializeVcb( IrpContext,
&VolDo->Vcb,
DeviceObjectWeTalkTo,
Vpb,
&DiskGeometry,
MediaChangeCount );
//
// We must initialize the stack size in our device object before
// the following reads, because the I/O system has not done it yet.
//
((PDEVICE_OBJECT) VolDo)->StackSize = (CCHAR) (DeviceObjectWeTalkTo->StackSize + 1);
//
// Pick up a local pointer to the new Vcb. Here is where we start
// thinking about cleanup of structures if the mount is failed.
//
Vcb = &VolDo->Vcb;
Vpb = NULL;
VolDo = NULL;
//
// Store the Vcb in the IrpContext as we didn't have one before.
//
IrpContext->Vcb = Vcb;
UdfAcquireVcbExclusive( IrpContext, Vcb, FALSE );
//
// Let's reference the Vpb to make sure we are the one to
// have the last dereference.
//
Vcb->Vpb->ReferenceCount += 1;
//
// Clear the verify bit for the start of mount.
//
ClearFlag( Vcb->Vpb->RealDevice->Flags, DO_VERIFY_VOLUME );
//
// Now find the multi-session bounds on this media.
//
UdfDetermineVolumeBounding( IrpContext,
Vcb,
&Vcb->BoundS,
&Vcb->BoundN );
//
// Now find the Anchor Volume Descriptor so we can discover the Volume Set
// Descriptor Sequence extent.
//
Status = UdfFindAnchorVolumeDescriptor( IrpContext,
Vcb,
&AnchorVolumeDescriptor );
if (!NT_SUCCESS(Status)) {
DebugTrace(( 0, Dbg, "UdfMountVolume, couldn't find anchor descriptors\n" ));
try_leave( Status );
}
//
// Now search for the prevailing copies of the PVD, LVD, and related PD in the
// extents indicated by the AVD.
//
Status = UdfFindVolumeDescriptors( IrpContext,
Vcb,
&AnchorVolumeDescriptor->Main,
&Pcb,
&PrimaryVolumeDescriptor,
&LogicalVolumeDescriptor );
//
// If we discovered invalid structures on the main extent, we may still
// be able to use the reserve extent. By definition the two extents
// must be logically equal, so just plow into it on any error.
//
if (!NT_SUCCESS( Status )) {
Status = UdfFindVolumeDescriptors( IrpContext,
Vcb,
&AnchorVolumeDescriptor->Reserve,
&Pcb,
&PrimaryVolumeDescriptor,
&LogicalVolumeDescriptor );
}
if (!NT_SUCCESS(Status)) {
DebugTrace(( 0, Dbg, "UdfMountVolume, couldn't find good VSD descriptors (PVD/LVD/PD)\n" ));
try_leave( Status );
}
//
// Now go complete initialization of the Pcb. After this point, we can perform
// physical partition mappings and know that the partition table is good.
//
Status = UdfCompletePcb( IrpContext,
Vcb,
Pcb );
if (!NT_SUCCESS(Status)) {
DebugTrace(( 0, Dbg, "UdfMountVolume, Pcb completion failed\n" ));
try_leave( Status );
}
Vcb->Pcb = Pcb;
Pcb = NULL;
//
// Set up all the support we need to do reads into the volume.
//
UdfUpdateVcbPhase0( IrpContext, Vcb );
//
// Now go get the fileset descriptor that will finally reveal the location
// of the root directory on this volume.
//
Status = UdfFindFileSetDescriptor( IrpContext,
Vcb,
&LogicalVolumeDescriptor->FSD,
&FileSetDescriptor );
if (!NT_SUCCESS(Status)) {
try_leave( NOTHING );
}
//
// Now that we have everything together, update the Vpb with identification
// of this volume.
//
UdfUpdateVolumeLabel( IrpContext,
Vcb->Vpb->VolumeLabel,
&Vcb->Vpb->VolumeLabelLength,
LogicalVolumeDescriptor->VolumeID,
sizeof( LogicalVolumeDescriptor->VolumeID ));
UdfUpdateVolumeSerialNumber( IrpContext,
&Vcb->Vpb->SerialNumber,
FileSetDescriptor );
//
// Check if this is a remount operation. If so then clean up
// the data structures passed in and created here.
//
if (UdfIsRemount( IrpContext, Vcb, &OldVcb )) {
//
// Link the old Vcb to point to the new device object that we
// should be talking to, dereferencing the previous.
//
ObDereferenceObject( OldVcb->TargetDeviceObject );
Vcb->Vpb->RealDevice->Vpb = OldVcb->Vpb;
OldVcb->Vpb->RealDevice = Vcb->Vpb->RealDevice;
OldVcb->TargetDeviceObject = DeviceObjectWeTalkTo;
OldVcb->VcbCondition = VcbMounted;
OldVcb->MediaChangeCount = Vcb->MediaChangeCount;
//
// Push the state of the method 2 bit across. In changing the device,
// we may now be on one with a different requirement.
//
ClearFlag( OldVcb->VcbState, VCB_STATE_METHOD_2_FIXUP );
SetFlag( OldVcb->VcbState, FlagOn( Vcb->VcbState, VCB_STATE_METHOD_2_FIXUP ));
//
// See if we will need to provide notification of the remount. This is the readonly
// filesystem's form of dismount/mount notification - we promise that whenever a
// volume is "dismounted", that a mount notification will occur when it is revalidated.
// Note that we do not send mount on normal remounts - that would duplicate the media
// arrival notification of the device driver.
//
if (FlagOn( OldVcb->VcbState, VCB_STATE_NOTIFY_REMOUNT )) {
ClearFlag( OldVcb->VcbState, VCB_STATE_NOTIFY_REMOUNT );
FileObjectToNotify = OldVcb->RootIndexFcb->FileObject;
ObReferenceObject( FileObjectToNotify );
}
DebugTrace(( 0, Dbg, "UdfMountVolume, remounted old Vcb %08x\n", OldVcb ));
try_leave( Status = STATUS_SUCCESS );
}
//
// Initialize the Vcb and associated structures from our volume descriptors
//
UdfUpdateVcbPhase1( IrpContext,
Vcb,
FileSetDescriptor );
//
// Drop an extra reference on the root dir file so we'll be able to send
// notification.
//
if (Vcb->RootIndexFcb) {
FileObjectToNotify = Vcb->RootIndexFcb->FileObject;
ObReferenceObject( FileObjectToNotify );
}
//
// The new mount is complete. Remove the additional references on this
// Vcb since, at this point, we have added the real references this volume
// will have during its lifetime. We also need to drop the additional
// reference on the device we mounted.
//
Vcb->VcbReference -= Vcb->VcbResidualReference;
ASSERT( Vcb->VcbReference == Vcb->VcbResidualReference );
ObDereferenceObject( Vcb->TargetDeviceObject );
Vcb->VcbCondition = VcbMounted;
UdfReleaseVcb( IrpContext, Vcb );
Vcb = NULL;
Status = STATUS_SUCCESS;
} finally {
DebugUnwind( "UdfMountVolume" );
//
// If we didn't complete the mount then cleanup any remaining structures.
//
if (Vpb != NULL) { Vpb->DeviceObject = NULL; }
if (Pcb != NULL) {
UdfDeletePcb( Pcb );
}
if (Vcb != NULL) {
//
// Make sure there is no Vcb in the IrpContext since it could go away
//
IrpContext->Vcb = NULL;
Vcb->VcbReference -= Vcb->VcbResidualReference;
if (UdfDismountVcb( IrpContext, Vcb )) {
UdfReleaseVcb( IrpContext, Vcb );
}
} else if (VolDo != NULL) {
IoDeleteDevice( (PDEVICE_OBJECT)VolDo );
Vpb->DeviceObject = NULL;
}
//
// Release the global resource.
//
UdfReleaseUdfData( IrpContext );
//
// Free any structures we may have been allocated
//
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.
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -