status = STATUS_NOT_IMPLEMENTED;
COMPLETE_REQUEST( Irp, status, 0 );
ASSERTMSG("BUG: we should never get here", 0);
break;
} // switch
В качестве проверки, если мы получили пакет с другим кодом, то возвратим ошибочный статус.
Обработка запросов на запись или чтение , также реализуется в одной процедуре, т.к. отличия в действиях заключаются в направлении копирования данных: из буфера в образ диска или наоборот. Для выполнения запроса, требуется, чтобы виртуальный диск находился в состоянии WORKING:
if ( devExt->DevState != WORKING )
{// Устройство не готово или удалено, отменить любые запросы
DBGPRINT( DBG_COMP_READ, DBG_LEVEL_WARN, ("Device not ready\n" ) );
status = STATUS_INVALID_DEVICE_STATE;
COMPLETE_REQUEST( Irp, status, information );}
Далее требуется проверить, что переданные параметры(начальное смещение Parameters.Read.ByteOffset и количество байт Parameters.Read.Length) не выходят за границы нашего диска, чтобы обеспечить корректность операции чтения/записи. Дополнительно количество байт должно быть кратно размеру сектора на диске:
if (RtlLargeIntegerGreaterThan(
RtlLargeIntegerAdd(
irpStack->Parameters.Read.ByteOffset,
RtlConvertUlongToLargeInteger(irpStack->Parameters.Read.Length)),
RtlConvertUlongToLargeInteger(devExt->DiskRegInfo.DiskSize)) ||
(irpStack->Parameters.Read.Length & (devExt->DiskGeometry.BytesPerSector - 1)))
{DBGPRINT( DBG_COMP_READ, DBG_LEVEL_ERROR,
("Error invalid parameter\n"
"ByteOffset: %x\n"
"Length: %d\n"
"Operation: %x\n",
irpStack->Parameters.Read.Length,
irpStack->MajorFunction));
status = STATUS_INVALID_PARAMETER;
COMPLETE_REQUEST( Irp, status, information );
IoReleaseRemoveLock(&devExt->RemoveLock, Irp);
return status;}
Если какой-либо из параметров не верен, то статус обработки запроса будет равен STATUS_INVALID_PARAMETER (неверные параметры).
Драйвер использует прямой метод передачи буфера данных, нам передается MDL список для буфера пользователя в параметре Irp->MdlAddress, который мы отображаем в адресное пространство ядра с помощью функции MmGetSystemAddressForMdlSafe:
ASSERT ( Irp->MdlAddress != NULL );
currentAddress = MmGetSystemAddressForMdlSafe(Irp->MdlAddress,NormalPagePriority);
if ( currentAddress == NULL )
{status = STATUS_INSUFFICIENT_RESOURCES;
DBGPRINT( DBG_COMP_READ, DBG_LEVEL_ERROR, ("Unable to get the system-space virtual address\n" ) );
Когда адрес получен адрес буфера (currentAddress), можно произвести копирование данных с помощью функции RtlMoveMemory
information = irpStack->Parameters.Read.Length;
switch (irpStack->MajorFunction)
{case IRP_MJ_READ:
RtlMoveMemory(
currentAddress,
devExt->DiskImage + irpStack->Parameters.Read.ByteOffset.LowPart,
irpStack->Parameters.Read.Length);
case IRP_MJ_WRITE:
currentAddress, irpStack->Parameters.Read.Length);
default:
information = 0;
break;}
status = STATUS_SUCCESS;
При этом поле information содержит количество байт, которые были записаны/прочитаны.
3.4.3 Обработка расширенных запросов
Поскольку наш драйвер обращается с виртуальным диском, при следующих запросах выполнять каких-либо действий не требуется, просто сообщить, что запрос успешно обработан. Это запросы:
case IOCTL_DISK_IS_WRITABLE://проверка можно ли на диск записывать данные
{DBGPRINT( DBG_COMP_IOCTL, DBG_LEVEL_INFO, ("IOCTL_DISK_IS_WRITABLE \n" ) );
case IOCTL_MOUNTMGR_QUERY_POINTS: // сообщить о символической ссылке для тома
{DBGPRINT( DBG_COMP_IOCTL, DBG_LEVEL_INFO, ("IOCTL_MOUNTMGR_QUERY_POINTS\n" ) );
status = STATUS_INVALID_DEVICE_REQUEST;
case IOCTL_DISK_FORMAT_TRACKS: //Форматировать дорожки
{DBGPRINT( DBG_COMP_IOCTL, DBG_LEVEL_INFO, ("IOCTL_DISK_FORMAT_TRACKS\n" ) );
status = STATUS_SUCCESS ;
case IOCTL_DISK_MEDIA_REMOVAL: //блокировать извлечение носителя
{DBGPRINT( DBG_COMP_IOCTL, DBG_LEVEL_INFO, ("IOCTL_DISK_MEDIA_REMOVAL\n" ) );
case IOCTL_DISK_VERIFY: //провреить данные
{PVERIFY_INFORMATION verifyInformation;
DBGPRINT( DBG_COMP_IOCTL, DBG_LEVEL_INFO, ("IOCTL_DISK_VERIFY\n" ) );
case IOCTL_DISK_CHECK_VERIFY:// проверить, сменился ли носитель
{DBGPRINT( DBG_COMP_IOCTL, DBG_LEVEL_INFO, ("IOCTL_DISK_CHECK_VERIFY\n" ) );
Запрос IOCTL_DISK_GET_PARTITION_INFO, требует сообщить информацию о разделах на диске. На рамдиске имеется один раздел. Результатом обработки запроса будет структура PARTITION_INFORMATION
typedef struct _PARTITION_INFORMATION
{LARGE_INTEGER StartingOffset; //смещение, с которого начинается раздел
LARGE_INTEGER PartitionLength;//размер раздела
DWORD HiddenSectors; //скрытых секторов
DWORD PartitionNumber; //порядковый номер раздела
BYTE PartitionType; //тип раздела
BOOLEAN BootIndicator; //TRUE - раздел является загрузочным
BOOLEAN RecognizedPartition; //распознан ли раздел
BOOLEAN RewritePartition; //TRUE - изменились параметры раздела}
Тип раздела PartitionType для виртуального диска может быть PARTITION_FAT_12 или PARTITION_FAT_16(он определяется при инициализации и хранится в расширении драйвера). Остальные поля заполняются следующим образом:
case IOCTL_DISK_GET_PARTITION_INFO:
{DBGPRINT( DBG_COMP_IOCTL, DBG_LEVEL_INFO, ("IOCTL_DISK_GET_PARTITION_INFO \n" ) );
if (irpStack->Parameters.DeviceIoControl.OutputBufferLength <sizeof(PARTITION_INFORMATION))
{DBGPRINT( DBG_COMP_IOCTL, DBG_LEVEL_INFO, ("Output buffer too small... \n" ) );
status = STATUS_BUFFER_TOO_SMALL; // Нужен буфер больше
information = sizeof(PARTITION_INFORMATION);}
else
{PPARTITION_INFORMATION outputBuffer;
outputBuffer = ( PPARTITION_INFORMATION )Irp->AssociatedIrp.SystemBuffer;
outputBuffer->PartitionType = (UCHAR)devExt->DiskRegInfo.PartitionType;
outputBuffer->BootIndicator = FALSE;
outputBuffer->RecognizedPartition = FALSE
outputBuffer->RewritePartition = FALSE;
outputBuffer->StartingOffset = RtlConvertUlongToLargeInteger(0);
outputBuffer->PartitionLength = RtlConvertUlongToLargeInteger(devExt->DiskRegInfo.DiskSize);
outputBuffer->HiddenSectors = (ULONG) (1L);
outputBuffer->PartitionNumber = (ULONG) (1L);
information = sizeof( PARTITION_INFORMATION );}
Запросы IOCTL_DISK_GET_MEDIA_TYPES, IOCTL_DISK_GET_DRIVE _GEOMETRY нужны для поучения информации о геометрии диска, для этого надо заполнить структуру DISK_GEOMETRY описанную в разделе 2.7.:
typedef struct _DISK_GEOMETRY {
LARGE_INTEGER Cylinders; //количество цилиндров
MEDIA_TYPE MediaType; //тип носителя
ULONG TracksPerCylinder; //количество дорожек на цилиндр
ULONG SectorsPerTrack; //количество секторов на дорожку
ULONG BytesPerSector; //размер сектора в байтах
} DISK_GEOMETRY, *PDISK_GEOMETRY;
Все остальные параметры заранее рассчитаны и определены при инициализации, и нужно только эту структуру скопировать из расширения устройства:
PDISK_GEOMETRY outputBuffer;
outputBuffer = ( PDISK_GEOMETRY ) Irp->AssociatedIrp.SystemBuffer;
RtlCopyMemory( outputBuffer, &(devExt->DiskGeometry), sizeof(DISK_GEOMETRY) );
DBGPRINT(DBG_COMP_IOCTL,DBG_LEVEL_INFO,("IOCTL_DISK_GET_DRIVE_GEOMETRY-OK!\n"));
information = sizeof( DISK_GEOMETRY );
3.4.4 Обработка запросов Plug and Play
При запуске устройства мы получаем IRP пакет с кодом IRP_MN_START_DEVICE:
case IRP_MN_START_DEVICE:
{KeInitializeEvent( &event, NotificationEvent, FALSE);
IoCopyCurrentIrpStackLocationToNext( Irp );
IoSetCompletionRoutine( Irp, (PIO_COMPLETION_ROUTINE) RamDskIoCompletionRoutine,
(PVOID) &event, TRUE, TRUE, TRUE );
status = IoCallDriver( devExt->LowerDeviceObject, Irp );
if (status == STATUS_PENDING)
{KeWaitForSingleObject( &event, Executive, KernelMode, FALSE, NULL);}
if ( NT_SUCCESS(status) )
Страницы: 1, 2, 3, 4, 5, 6