📄 fsctrl.c
字号:
ObReferenceObject( FileObjectToNotify );
}
try_leave( Status = STATUS_SUCCESS );
}
//
// This is a new mount. Go ahead and initialize the
// Vcb from the volume descriptor.
//
CdUpdateVcbFromVolDescriptor( IrpContext,
Vcb,
RawIsoVd );
//
// 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 );
}
//
// Now check the maximum transfer limits on the device in case we
// get raw reads on this volume.
//
Status = CdPerformDevIoCtrl( IrpContext,
IOCTL_SCSI_GET_CAPABILITIES,
DeviceObjectWeTalkTo,
&Capabilities,
sizeof( IO_SCSI_CAPABILITIES ),
FALSE,
TRUE,
NULL );
if (NT_SUCCESS(Status)) {
Vcb->MaximumTransferRawSectors = Capabilities.MaximumTransferLength / RAW_SECTOR_SIZE;
Vcb->MaximumPhysicalPages = Capabilities.MaximumPhysicalPages;
} else {
//
// This should never happen, but we can safely assume 64k and 16 pages.
//
Vcb->MaximumTransferRawSectors = (64 * 1024) / RAW_SECTOR_SIZE;
Vcb->MaximumPhysicalPages = 16;
}
//
// The new mount is complete. Remove the additional references on this
// Vcb and the device we are mounted on top of.
//
Vcb->VcbReference -= CDFS_RESIDUAL_REFERENCE;
ASSERT( Vcb->VcbReference == CDFS_RESIDUAL_REFERENCE );
ObDereferenceObject( Vcb->TargetDeviceObject );
CdUpdateVcbCondition( Vcb, VcbMounted);
CdReleaseVcb( IrpContext, Vcb );
Vcb = NULL;
Status = STATUS_SUCCESS;
} finally {
//
// Free the TOC buffer if not in the Vcb.
//
if (CdromToc != NULL) {
CdFreePool( &CdromToc );
}
//
// Free the sector buffer if allocated.
//
if (RawIsoVd != NULL) {
CdFreePool( &RawIsoVd );
}
//
// If we are not mounting the device, then set the verify bit again.
//
if ((AbnormalTermination() || (Status != STATUS_SUCCESS)) &&
SetDoVerifyOnFail) {
CdMarkRealDevForVerify( IrpContext->RealDevice);
}
//
// If we didn't complete the mount then cleanup any remaining structures.
//
if (Vpb != NULL) { Vpb->DeviceObject = NULL; }
if (Vcb != NULL) {
//
// Make sure there is no Vcb in the IrpContext since it could go away
//
IrpContext->Vcb = NULL;
Vcb->VcbReference -= CDFS_RESIDUAL_REFERENCE;
if (CdDismountVcb( IrpContext, Vcb )) {
CdReleaseVcb( IrpContext, Vcb );
}
} else if (VolDo != NULL) {
IoDeleteDevice( (PDEVICE_OBJECT) VolDo );
}
//
// Release the global resource.
//
CdReleaseCdData( IrpContext );
}
//
// Now send mount notification.
//
if (FileObjectToNotify) {
FsRtlNotifyVolumeEvent( FileObjectToNotify, FSRTL_VOLUME_MOUNT );
ObDereferenceObject( FileObjectToNotify );
}
//
// Complete the request if no exception.
//
CdCompleteRequest( IrpContext, Irp, Status );
return Status;
}
//
// Local support routine
//
NTSTATUS
CdVerifyVolume (
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;
PCHAR RawIsoVd = NULL;
PCDROM_TOC_LARGE CdromToc = NULL;
ULONG TocLength = 0;
ULONG TocTrackCount = 0;
ULONG TocDiskFlags = 0;
ULONG MediaChangeCount = Vcb->MediaChangeCount;
PFILE_OBJECT FileObjectToNotify = NULL;
BOOLEAN ReturnError;
BOOLEAN ReleaseVcb = FALSE;
IO_STATUS_BLOCK Iosb;
STRING AnsiLabel;
UNICODE_STRING UnicodeLabel;
WCHAR VolumeLabel[ VOLUME_ID_LENGTH ];
ULONG VolumeLabelLength;
ULONG Index;
NTSTATUS Status;
PAGED_CODE();
//
// We check that we are talking to a Cdrom device.
//
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;
//
// Acquire the global resource to synchronise against mounts and teardown,
// finally clause releases.
//
CdAcquireCdData( IrpContext );
try {
CdAcquireVcbExclusive( IrpContext, Vcb, FALSE );
ReleaseVcb = TRUE;
//
// Verify that there is a disk here.
//
Status = CdPerformDevIoCtrl( IrpContext,
IOCTL_CDROM_CHECK_VERIFY,
Vcb->TargetDeviceObject,
&MediaChangeCount,
sizeof(ULONG),
FALSE,
TRUE,
&Iosb );
if (!NT_SUCCESS( Status )) {
//
// 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 )) {
Status = STATUS_WRONG_VOLUME;
}
try_return( 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)) {
//
// Allocate a buffer to query the TOC.
//
CdromToc = FsRtlAllocatePoolWithTag( CdPagedPool,
sizeof( CDROM_TOC_LARGE ),
TAG_CDROM_TOC );
RtlZeroMemory( CdromToc, sizeof( CDROM_TOC_LARGE ));
//
// Let's query for the Toc now and handle any error we get from this operation.
//
Status = CdProcessToc( IrpContext,
Vcb->TargetDeviceObject,
CdromToc,
&TocLength,
&TocTrackCount,
&TocDiskFlags );
//
// If we failed to read the TOC, then give up now. Drives will fail
// a TOC read on, for example, erased CD-RW media.
//
if (Status != STATUS_SUCCESS) {
//
// For any errors other than no media and not ready, commute the
// status to ensure that the current VPB is kicked off the device
// below - there is probably blank media in the drive, since we got
// further than the check verify.
//
if (!CdIsRawDevice( IrpContext, Status )) {
Status = STATUS_WRONG_VOLUME;
}
try_return( Status );
//
// We got a TOC. Verify that it matches the previous Toc.
//
} else if ((Vcb->TocLength != TocLength) ||
(Vcb->TrackCount != TocTrackCount) ||
(Vcb->DiskFlags != TocDiskFlags) ||
!RtlEqualMemory( CdromToc,
Vcb->CdromToc,
TocLength )) {
try_return( Status = STATUS_WRONG_VOLUME );
}
//
// If the disk to verify is an audio disk then we already have a
// match. Otherwise we need to check the volume descriptor.
//
if (!FlagOn( Vcb->VcbState, VCB_STATE_AUDIO_DISK )) {
//
// Allocate a buffer for the sector buffer.
//
RawIsoVd = FsRtlAllocatePoolWithTag( CdNonPagedPool,
ROUND_TO_PAGES( 2 * SECTOR_SIZE ),
TAG_VOL_DESC );
//
// Read the primary volume descriptor for this volume. If we
// get an io error and this verify was a the result of DASD open,
// commute the Io error to STATUS_WRONG_VOLUME. Note that if we currently
// expect a music disk then this request should fail.
//
ReturnError = FALSE;
if (FlagOn( IrpSp->Flags, SL_ALLOW_RAW_MOUNT )) {
ReturnError = TRUE;
}
if (!CdFindPrimaryVd( IrpContext,
Vcb,
RawIsoVd,
Vcb->BlockFactor,
ReturnError,
TRUE )) {
//
// If the previous Vcb did not represent a raw disk
// then show this volume was dismounted.
//
try_return( Status = STATUS_WRONG_VOLUME );
}
else {
//
// Look for a supplementary VD.
//
// 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,
TRUE);
//
// Compare the serial numbers. If they don't match, set the
// status to wrong volume.
//
if (Vpb->SerialNumber != CdSerial32( RawIsoVd, SECTOR_SIZE )) {
try_return( Status = STATUS_WRONG_VOLUME );
}
//
// Verify the volume labels.
//
if (!FlagOn( Vcb->VcbState, VCB_STATE_JOLIET )) {
//
// Compute the length of the volume name
//
AnsiLabel.Buffer = CdRvdVolId( RawIsoVd, Vcb->VcbState );
AnsiLabel.MaximumLength = AnsiLabel.Length = VOLUME_ID_LENGTH;
UnicodeLabel.MaximumLength = VOLUME_ID_LENGTH * sizeof( WCHAR );
UnicodeLabel.Buffer = VolumeLabel;
//
// Convert this to unicode. If we get any error then use a name
// length of zero.
//
VolumeLabelLength = 0;
if (NT_SUCCESS( RtlOemStringToCountedUnicodeString( &UnicodeLabel,
&AnsiLabel,
FALSE ))) {
VolumeLabelLength = UnicodeLabel.Length;
}
//
// We need to convert from big-endian to little endian.
//
} else {
CdConvertBigToLittleEndian( IrpContext,
CdRvdVolId( RawIsoVd, Vcb->VcbState ),
VOLUME_ID_LENGTH,
(PCHAR) VolumeLabel );
VolumeLabelLength = VOLUME_ID_LENGTH;
}
//
// Strip the trailing spaces or zeroes from the name.
//
Index = VolumeLabelLength / sizeof( WCHAR );
while (Index > 0) {
if ((VolumeLabel[ Index - 1 ] != L'\0') &&
(VolumeLabel[ Index - 1 ] != L' ')) {
break;
}
Index -= 1;
}
//
// Now set the final length for the name.
//
VolumeLabelLength = (USHORT) (Index * sizeof( WCHAR ));
//
// Now check that the label matches.
//
if ((Vpb->VolumeLabelLength != VolumeLabelLength) ||
!RtlEqualMemory( Vpb->VolumeLabel,
VolumeLabel,
VolumeLabelLength )) {
try_return( Status = STATUS_WRONG_VOLUME );
}
}
}
}
//
// The volume is OK, clear the verify bit.
//
CdUpdateVcbCondition( Vcb, VcbMounted);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -