📄 fsctrl.c
字号:
PUCHAR Buffer;
ObDereferenceObject( OldVcb->TargetDeviceObject );
IoAcquireVpbSpinLock( &SavedIrql );
NewVcb->Vpb->RealDevice->Vpb = OldVcb->Vpb;
OldVcb->Vpb->RealDevice = NewVcb->Vpb->RealDevice;
OldVcb->TargetDeviceObject = DeviceObjectWeTalkTo;
CdUpdateVcbCondition( OldVcb, VcbMounted);
CdUpdateMediaChangeCount( OldVcb, NewVcb->MediaChangeCount);
ClearFlag( OldVcb->VcbState, VCB_STATE_VPB_NOT_ON_DEVICE);
Buffer = OldVcb->SectorCacheBuffer = NewVcb->SectorCacheBuffer;
NewVcb->SectorCacheBuffer = NULL;
if (NULL != Buffer) {
for (Index = 0; Index < CD_SEC_CACHE_CHUNKS; Index++) {
OldVcb->SecCacheChunks[ Index].Buffer = Buffer;
OldVcb->SecCacheChunks[ Index].BaseLbn = -1;
Buffer += CD_SEC_CHUNK_BLOCKS * SECTOR_SIZE;
}
}
IoReleaseVpbSpinLock( SavedIrql );
}
//
// Local support routine
//
NTSTATUS
CdMountVolume (
IN PIRP_CONTEXT IrpContext,
IN PIRP Irp
)
/*++
Routine Description:
This routine performs the mount volume operation. It is responsible for
either completing of enqueuing the input Irp.
Its job is to verify that the volume denoted in the IRP is a Cdrom volume,
and create the VCB and root DCB structures. The algorithm it
uses is essentially as follows:
1. Create a new Vcb Structure, and initialize it enough to do I/O
through the on-disk volume descriptors.
2. Read the disk and check if it is a Cdrom volume.
3. If it is not a Cdrom volume then delete the Vcb and
complete the IRP back with an appropriate status.
4. Check if the volume was previously mounted and if it was then do a
remount operation. This involves deleting the VCB, hook in the
old VCB, and complete the IRP.
5. Otherwise create a Vcb and root DCB for each valid volume descriptor.
Arguments:
Irp - Supplies the Irp to process
Return Value:
NTSTATUS - The return status for the operation
--*/
{
NTSTATUS Status;
PVOLUME_DEVICE_OBJECT VolDo = NULL;
PVCB Vcb = NULL;
PVCB OldVcb;
UCHAR StackSize;
BOOLEAN FoundPvd = FALSE;
BOOLEAN SetDoVerifyOnFail;
PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation( Irp );
PDEVICE_OBJECT DeviceObjectWeTalkTo = IrpSp->Parameters.MountVolume.DeviceObject;
PVPB Vpb = IrpSp->Parameters.MountVolume.Vpb;
PFILE_OBJECT FileObjectToNotify = NULL;
ULONG BlockFactor;
DISK_GEOMETRY DiskGeometry;
IO_SCSI_CAPABILITIES Capabilities;
IO_STATUS_BLOCK Iosb;
PCHAR RawIsoVd = NULL;
PCDROM_TOC_LARGE CdromToc = NULL;
ULONG TocLength = 0;
ULONG TocTrackCount = 0;
ULONG TocDiskFlags = 0;
ULONG MediaChangeCount = 0;
PAGED_CODE();
//
// Check that we are talking to a Cdrom device. This request should
// always be waitable.
//
ASSERT( Vpb->RealDevice->DeviceType == FILE_DEVICE_CD_ROM );
ASSERT( FlagOn( IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT ));
//
// 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;
SetDoVerifyOnFail = CdRealDevNeedsVerify( IrpContext->RealDevice);
//
// Check if we have disabled the mount process.
//
if (CdDisable) {
CdCompleteRequest( IrpContext, Irp, STATUS_UNRECOGNIZED_VOLUME );
return STATUS_UNRECOGNIZED_VOLUME;
}
//
// Do a CheckVerify here to lift the MediaChange ticker from the driver
//
Status = CdPerformDevIoCtrl( IrpContext,
IOCTL_CDROM_CHECK_VERIFY,
DeviceObjectWeTalkTo,
&MediaChangeCount,
sizeof(ULONG),
FALSE,
TRUE,
&Iosb );
if (!NT_SUCCESS( Status )) {
CdCompleteRequest( IrpContext, Irp, Status );
return Status;
}
if (Iosb.Information != sizeof(ULONG)) {
//
// Be safe about the count in case the driver didn't fill it in
//
MediaChangeCount = 0;
}
//
// 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.
//
Status = CdPerformDevIoCtrl( IrpContext,
IOCTL_CDROM_GET_DRIVE_GEOMETRY,
DeviceObjectWeTalkTo,
&DiskGeometry,
sizeof( DISK_GEOMETRY ),
FALSE,
TRUE,
NULL );
//
// Return insufficient sources to our caller.
//
if (Status == STATUS_INSUFFICIENT_RESOURCES) {
CdCompleteRequest( IrpContext, Irp, Status );
return Status;
}
//
// Now check the block factor for addressing the volume descriptors.
// If the call for the disk geometry failed then assume there is one
// block per sector.
//
BlockFactor = 1;
if (NT_SUCCESS( Status ) &&
(DiskGeometry.BytesPerSector != 0) &&
(DiskGeometry.BytesPerSector < SECTOR_SIZE)) {
BlockFactor = SECTOR_SIZE / DiskGeometry.BytesPerSector;
}
//
// Acquire the global resource to do mount operations.
//
CdAcquireCdData( IrpContext );
//
// Use a try-finally to facilitate cleanup.
//
try {
//
// Allocate a buffer to query the TOC.
//
CdromToc = FsRtlAllocatePoolWithTag( CdPagedPool,
sizeof( CDROM_TOC_LARGE ),
TAG_CDROM_TOC );
RtlZeroMemory( CdromToc, sizeof( CDROM_TOC_LARGE ));
//
// Do a quick check to see if there any Vcb's which can be removed.
//
CdScanForDismountedVcb( IrpContext );
//
// Get our device object and alignment requirement.
//
Status = IoCreateDevice( CdData.DriverObject,
sizeof( VOLUME_DEVICE_OBJECT ) - sizeof( DEVICE_OBJECT ),
NULL,
FILE_DEVICE_CD_ROM_FILE_SYSTEM,
0,
FALSE,
(PDEVICE_OBJECT *) &VolDo );
if (!NT_SUCCESS( 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;
}
//
// 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);
StackSize = ((PDEVICE_OBJECT) VolDo)->StackSize;
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 );
//
// Let's query for the Toc now and handle any error we get from this operation.
//
Status = CdProcessToc( IrpContext,
DeviceObjectWeTalkTo,
CdromToc,
&TocLength,
&TocTrackCount,
&TocDiskFlags );
//
// If we failed to read the TOC, then bail out. Probably blank media.
//
if (Status != STATUS_SUCCESS) {
try_leave( Status );
}
//
// 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.
//
CdInitializeVcb( IrpContext,
&VolDo->Vcb,
DeviceObjectWeTalkTo,
Vpb,
CdromToc,
TocLength,
TocTrackCount,
TocDiskFlags,
BlockFactor,
MediaChangeCount );
//
// Show that we initialized the Vcb and can cleanup with the Vcb.
//
Vcb = &VolDo->Vcb;
VolDo = NULL;
Vpb = NULL;
CdromToc = NULL;
//
// Store the Vcb in the IrpContext as we didn't have one before.
//
IrpContext->Vcb = Vcb;
CdAcquireVcbExclusive( 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.
//
CdMarkRealDevVerifyOk( Vcb->Vpb->RealDevice);
if (!FlagOn( Vcb->VcbState, VCB_STATE_AUDIO_DISK)) {
//
// Allocate a buffer to read in the volume descriptors. We allocate a full
// page to make sure we don't hit any alignment problems.
//
RawIsoVd = FsRtlAllocatePoolWithTag( CdNonPagedPool,
ROUND_TO_PAGES( SECTOR_SIZE ),
TAG_VOL_DESC );
//
// Try to find the primary volume descriptor.
//
FoundPvd = CdFindPrimaryVd( IrpContext,
Vcb,
RawIsoVd,
BlockFactor,
TRUE,
FALSE );
if (!FoundPvd) {
//
// We failed to find a valid VD in the data track, but there were also
// audio tracks on this disc, so we'll try to mount it as an audio CD.
// Since we're always last in the mount order, we won't be preventing
// any other FS from trying to mount the data track. However if the
// data track was at the start of the disc, then we abort, to avoid
// having to filter it from our synthesised directory listing later. We
// already filtered off any data track at the end.
//
if (!(TocDiskFlags & CDROM_DISK_AUDIO_TRACK) ||
BooleanFlagOn( Vcb->CdromToc->TrackData[0].Control, TOC_DATA_TRACK)) {
try_leave( Status = STATUS_UNRECOGNIZED_VOLUME);
}
SetFlag( Vcb->VcbState, VCB_STATE_AUDIO_DISK | VCB_STATE_CDXA );
CdFreePool( &RawIsoVd );
RawIsoVd = NULL;
}
}
//
// Look and see if there is a secondary volume descriptor we want to
// use.
//
if (FoundPvd) {
//
// Store the primary volume descriptor in the second half of
// RawIsoVd. Then if our search for a secondary fails we can
// recover this immediately.
//
RtlCopyMemory( Add2Ptr( RawIsoVd, SECTOR_SIZE, PVOID ),
RawIsoVd,
SECTOR_SIZE );
//
// We have the initial volume descriptor. Locate a secondary
// volume descriptor if present.
//
CdFindActiveVolDescriptor( IrpContext,
Vcb,
RawIsoVd,
FALSE);
}
//
// Allocate a block cache to speed directory operations. We can't
// use the cache if there is any chance the volume has link blocks
// in the data area (i.e. was packet written and then finalized to
// Joliet/9660). So we simply only allow the cache to operate on
// media with a single track - since we're really targetting pressed
// installation media here. We can't be more precise, since D/CD-ROM
// drives don't support READ_TRACK_INFO, which is the only way for
// certain to know whether or not a track was packet written.
//
if (!FlagOn( Vcb->VcbState, VCB_STATE_AUDIO_DISK) &&
((Vcb->CdromToc->LastTrack - Vcb->CdromToc->FirstTrack) == 0)) {
ULONG Index;
PUCHAR Buffer;
Buffer =
Vcb->SectorCacheBuffer = FsRtlAllocatePool( CdPagedPool,
CD_SEC_CACHE_CHUNKS *
CD_SEC_CHUNK_BLOCKS *
SECTOR_SIZE);
for (Index = 0; Index < CD_SEC_CACHE_CHUNKS; Index++) {
Vcb->SecCacheChunks[ Index].Buffer = Buffer;
Vcb->SecCacheChunks[ Index].BaseLbn = -1;
Buffer += CD_SEC_CHUNK_BLOCKS * SECTOR_SIZE;
}
Vcb->SectorCacheIrp = IoAllocateIrp( StackSize, FALSE);
IoInitializeIrp( Vcb->SectorCacheIrp,
IoSizeOfIrp( StackSize),
(CCHAR)StackSize);
KeInitializeEvent( &Vcb->SectorCacheEvent, SynchronizationEvent, FALSE);
ExInitializeResourceLite( &Vcb->SectorCacheResource);
}
//
// Check if this is a remount operation. If so then clean up
// the data structures passed in and created here.
//
if (CdIsRemount( IrpContext, Vcb, &OldVcb )) {
KIRQL SavedIrql;
ASSERT( NULL != OldVcb->SwapVpb );
//
// Link the old Vcb to point to the new device object that we
// should be talking to, dereferencing the previous. Call a
// nonpaged routine to do this since we take the Vpb spinlock.
//
CdReMountOldVcb( IrpContext,
OldVcb,
Vcb,
DeviceObjectWeTalkTo);
//
// 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;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -