⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 ioctl.c

📁 The CD ROM driver is used with Classpnp.sys to provide access to CD ROMs and DVD ROMs. It supports P
💻 C
📖 第 1 页 / 共 5 页
字号:
/*--

Copyright (C) Microsoft Corporation, 1999 - 1999

Module Name:

    ioctl.c

Abstract:

    The CDROM class driver tranlates IRPs to SRBs with embedded CDBs
    and sends them to its devices through the port driver.

Environment:

    kernel mode only

Notes:

    SCSI Tape, CDRom and Disk class drivers share common routines
    that can be found in the CLASS directory (..\ntos\dd\class).

Revision History:

--*/

#include "stddef.h"
#include "string.h"

#include "ntddk.h"

#include "ntddcdvd.h"
#include "classpnp.h"

#include "initguid.h"
#include "ntddstor.h"
#include "cdrom.h"

#include "ioctl.tmh"

#if DBG
    PUCHAR READ_DVD_STRUCTURE_FORMAT_STRINGS[DvdMaxDescriptor+1] = {
        "Physical",
        "Copyright",
        "DiskKey",
        "BCA",
        "Manufacturer",
        "Unknown"
    };
#endif // DBG

#define DEFAULT_CDROM_SECTORS_PER_TRACK 32
#define DEFAULT_TRACKS_PER_CYLINDER     64



NTSTATUS
CdRomDeviceControlDispatch(
    IN PDEVICE_OBJECT DeviceObject,
    IN PIRP Irp
    )
/*++

Routine Description:

    This is the NT device control handler for CDROMs.

Arguments:

    DeviceObject - for this CDROM

    Irp - IO Request packet

Return Value:

    NTSTATUS

--*/
{
    PFUNCTIONAL_DEVICE_EXTENSION  fdoExtension = DeviceObject->DeviceExtension;
    PCOMMON_DEVICE_EXTENSION commonExtension = DeviceObject->DeviceExtension;

    PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation(Irp);
    PIO_STACK_LOCATION nextStack;
    PCDROM_DATA        cdData = (PCDROM_DATA)(commonExtension->DriverData);

    BOOLEAN            use6Byte = TEST_FLAG(cdData->XAFlags, XA_USE_6_BYTE);
    SCSI_REQUEST_BLOCK srb = {0};
    PCDB cdb = (PCDB)srb.Cdb;
    PVOID outputBuffer;
    ULONG bytesTransferred = 0;
    NTSTATUS status;
    NTSTATUS status2;
    KIRQL    irql;

    ULONG ioctlCode;
    ULONG baseCode;
    ULONG functionCode;

RetryControl:

    //
    // Zero the SRB on stack.
    //

    RtlZeroMemory(&srb, sizeof(SCSI_REQUEST_BLOCK));

    Irp->IoStatus.Information = 0;

    //
    // if this is a class driver ioctl then we need to change the base code
    // to IOCTL_CDROM_BASE so that the switch statement can handle it.
    //
    // WARNING - currently the scsi class ioctl function codes are between
    // 0x200 & 0x300.  this routine depends on that fact
    //

    ioctlCode = irpStack->Parameters.DeviceIoControl.IoControlCode;
    baseCode = ioctlCode >> 16;
    functionCode = (ioctlCode & (~0xffffc003)) >> 2;

    TraceLog((CdromDebugTrace,
                "CdRomDeviceControl: Ioctl Code = %lx, Base Code = %lx,"
                " Function Code = %lx\n",
                ioctlCode,
                baseCode,
                functionCode
              ));

    if((functionCode >= 0x200) && (functionCode <= 0x300)) {

        ioctlCode = (ioctlCode & 0x0000ffff) | CTL_CODE(IOCTL_CDROM_BASE, 0, 0, 0);

        TraceLog((CdromDebugTrace,
                    "CdRomDeviceControl: Class Code - new ioctl code is %lx\n",
                    ioctlCode));

        irpStack->Parameters.DeviceIoControl.IoControlCode = ioctlCode;

    }

    switch (ioctlCode) {

    case IOCTL_STORAGE_GET_MEDIA_TYPES_EX: {

        PGET_MEDIA_TYPES  mediaTypes = Irp->AssociatedIrp.SystemBuffer;
        PDEVICE_MEDIA_INFO mediaInfo = &mediaTypes->MediaInfo[0];
        ULONG sizeNeeded;

        sizeNeeded = sizeof(GET_MEDIA_TYPES);

        //
        // IsMmc is static...
        //

        if (cdData->Mmc.IsMmc) {
            sizeNeeded += sizeof(DEVICE_MEDIA_INFO) * 1; // return two media types
        }

        //
        // Ensure that buffer is large enough.
        //

        if (irpStack->Parameters.DeviceIoControl.OutputBufferLength <
            sizeNeeded) {

            //
            // Buffer too small.
            //

            Irp->IoStatus.Information = sizeNeeded;
            status = STATUS_BUFFER_TOO_SMALL;
            break;
        }

        RtlZeroMemory(Irp->AssociatedIrp.SystemBuffer, sizeNeeded);

        //
        // ISSUE-2000/5/11-henrygab - need to update GET_MEDIA_TYPES_EX
        //

        mediaTypes->DeviceType = CdRomGetDeviceType(DeviceObject);

        mediaTypes->MediaInfoCount = 1;
        mediaInfo->DeviceSpecific.RemovableDiskInfo.MediaType = CD_ROM;
        mediaInfo->DeviceSpecific.RemovableDiskInfo.NumberMediaSides = 1;
        mediaInfo->DeviceSpecific.RemovableDiskInfo.MediaCharacteristics = MEDIA_READ_ONLY;
        mediaInfo->DeviceSpecific.RemovableDiskInfo.Cylinders.QuadPart = fdoExtension->DiskGeometry.Cylinders.QuadPart;
        mediaInfo->DeviceSpecific.RemovableDiskInfo.TracksPerCylinder = fdoExtension->DiskGeometry.TracksPerCylinder;
        mediaInfo->DeviceSpecific.RemovableDiskInfo.SectorsPerTrack = fdoExtension->DiskGeometry.SectorsPerTrack;
        mediaInfo->DeviceSpecific.RemovableDiskInfo.BytesPerSector = fdoExtension->DiskGeometry.BytesPerSector;

        if (cdData->Mmc.IsMmc) {

            //
            // also report a removable disk
            //
            mediaTypes->MediaInfoCount += 1;

            mediaInfo++;
            mediaInfo->DeviceSpecific.RemovableDiskInfo.MediaType = RemovableMedia;
            mediaInfo->DeviceSpecific.RemovableDiskInfo.NumberMediaSides = 1;
            mediaInfo->DeviceSpecific.RemovableDiskInfo.MediaCharacteristics = MEDIA_READ_WRITE;
            mediaInfo->DeviceSpecific.RemovableDiskInfo.Cylinders.QuadPart = fdoExtension->DiskGeometry.Cylinders.QuadPart;
            mediaInfo->DeviceSpecific.RemovableDiskInfo.TracksPerCylinder = fdoExtension->DiskGeometry.TracksPerCylinder;
            mediaInfo->DeviceSpecific.RemovableDiskInfo.SectorsPerTrack = fdoExtension->DiskGeometry.SectorsPerTrack;
            mediaInfo->DeviceSpecific.RemovableDiskInfo.BytesPerSector = fdoExtension->DiskGeometry.BytesPerSector;
            mediaInfo--;

        }

        //
        // Status will either be success, if media is present, or no media.
        // It would be optimal to base from density code and medium type, but not all devices
        // have values for these fields.
        //

        //
        // Send a TUR to determine if media is present.
        //

        srb.CdbLength = 6;
        cdb = (PCDB)srb.Cdb;
        cdb->CDB6GENERIC.OperationCode = SCSIOP_TEST_UNIT_READY;

        //
        // Set timeout value.
        //

        srb.TimeOutValue = fdoExtension->TimeOutValue;

        status = ClassSendSrbSynchronous(DeviceObject,
                                         &srb,
                                         NULL,
                                         0,
                                         FALSE);


        TraceLog((CdromDebugWarning,
                   "CdRomDeviceControl: GET_MEDIA_TYPES status of TUR - %lx\n",
                   status));

        if (NT_SUCCESS(status)) {

            //
            // set the disk's media as current if we can write to it.
            //

            if (cdData->Mmc.IsMmc && cdData->Mmc.WriteAllowed) {

                mediaInfo++;
                SET_FLAG(mediaInfo->DeviceSpecific.RemovableDiskInfo.MediaCharacteristics,
                         MEDIA_CURRENTLY_MOUNTED);
                mediaInfo--;


            } else {

                SET_FLAG(mediaInfo->DeviceSpecific.RemovableDiskInfo.MediaCharacteristics,
                         MEDIA_CURRENTLY_MOUNTED);

            }

        }

        Irp->IoStatus.Information = sizeNeeded;
        status = STATUS_SUCCESS;
        break;
    }


    case IOCTL_CDROM_RAW_READ: {

        LARGE_INTEGER  startingOffset = {0};
        ULONGLONG      transferBytes;
        ULONGLONG      endOffset;
        ULONGLONG      mdlBytes;
        ULONG          startingSector;
        RAW_READ_INFO rawReadInfo;

        //
        // Ensure that XA reads are supported.
        //
        if (TEST_FLAG(cdData->XAFlags, XA_NOT_SUPPORTED)) {
            TraceLog((CdromDebugWarning,
                        "CdRomDeviceControl: XA Reads not supported. Flags (%x)\n",
                        cdData->XAFlags));
            status = STATUS_INVALID_DEVICE_REQUEST;
            break;
        }

        //
        // Check that ending sector is on disc and buffers are there and of
        // correct size.
        //

        if (!irpStack->Parameters.DeviceIoControl.Type3InputBuffer){
            /*
             *  This is a call from user space.  This is the only time that we need to validate parameters.
             *  Validate the input and get the input buffer into Type3InputBuffer
             *  so the rest of the code will be uniform.
             */
            if (Irp->AssociatedIrp.SystemBuffer){
                irpStack->Parameters.DeviceIoControl.Type3InputBuffer = Irp->AssociatedIrp.SystemBuffer;
                if (irpStack->Parameters.DeviceIoControl.InputBufferLength < sizeof(RAW_READ_INFO)){
                    status = STATUS_BUFFER_TOO_SMALL;
                    break;
                }
            }
            else {
                status = STATUS_INVALID_PARAMETER;
                break;
            }
        }

        /*
         *  Since this ioctl is METHOD_OUT_DIRECT, we need to copy away the input buffer before interpreting it.
         *  This prevents a malicious app from messing with the input buffer while we are interpreting it.
         */
        rawReadInfo = *(PRAW_READ_INFO)irpStack->Parameters.DeviceIoControl.Type3InputBuffer;

        startingOffset.QuadPart = rawReadInfo.DiskOffset.QuadPart;
        startingSector = (ULONG)(rawReadInfo.DiskOffset.QuadPart >> fdoExtension->SectorShift);
        transferBytes = (ULONGLONG)rawReadInfo.SectorCount * RAW_SECTOR_SIZE;

        endOffset = (ULONGLONG)rawReadInfo.SectorCount * COOKED_SECTOR_SIZE;
        endOffset += startingOffset.QuadPart;

        //
        // check for overflows....
        //
        if (rawReadInfo.SectorCount == 0) {
            TraceLog((CdromDebugWarning,
                        "CdRomDeviceControl: Invalid I/O parameters for XA "
                        "Read (zero sectors requested)\n"));
            status = STATUS_INVALID_PARAMETER;
            break;
        }
        if (transferBytes < (ULONGLONG)(rawReadInfo.SectorCount)) {
            TraceLog((CdromDebugWarning,
                        "CdRomDeviceControl: Invalid I/O parameters for XA "
                        "Read (TransferBytes Overflow)\n"));
            status = STATUS_INVALID_PARAMETER;
            break;
        }
        if (endOffset < (ULONGLONG)startingOffset.QuadPart) {
            TraceLog((CdromDebugWarning,
                        "CdRomDeviceControl: Invalid I/O parameters for XA "
                        "Read (EndingOffset Overflow)\n"));
            status = STATUS_INVALID_PARAMETER;
            break;
        }
        if (irpStack->Parameters.DeviceIoControl.OutputBufferLength <
            transferBytes) {
            TraceLog((CdromDebugWarning,
                        "CdRomDeviceControl: Invalid I/O parameters for XA "
                        "Read (Bad buffer size)\n"));
            status = STATUS_INVALID_PARAMETER;
            break;
        }
        if (endOffset > (ULONGLONG)commonExtension->PartitionLength.QuadPart) {
            TraceLog((CdromDebugWarning,
                        "CdRomDeviceControl: Invalid I/O parameters for XA "
                        "Read (Request Out of Bounds)\n"));
            status = STATUS_INVALID_PARAMETER;
            break;
        }

        //
        // cannot validate the MdlAddress, since it is not included in any
        // other location per the DDK and file system calls.
        //

        //
        // validate the mdl describes at least the number of bytes
        // requested from us.
        //

        mdlBytes = (ULONGLONG)MmGetMdlByteCount(Irp->MdlAddress);
        if (mdlBytes < transferBytes) {
            TraceLog((CdromDebugWarning,
                        "CdRomDeviceControl: Invalid MDL %s, Irp %p\n",
                        "size (5)", Irp));
            status = STATUS_INVALID_PARAMETER;
            break;
        }

        //
        // check the buffer for alignment
        // This is important for x86 as some busses (ie ATAPI)
        // require word-aligned buffers.
        //

        if ( ((ULONG_PTR)MmGetMdlVirtualAddress(Irp->MdlAddress)) &
             fdoExtension->AdapterDescriptor->AlignmentMask
            )
        {
            TraceLog((CdromDebugWarning,
                      "CdRomDeviceControl: Invalid I/O parameters for "

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -