Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

how to make virtual disk read only

92 views
Skip to first unread message

sa_sa_Jerry

unread,
Apr 19, 2008, 10:09:20 PM4/19/08
to
I have been writing the virtual disk driver. This driver is based on toaster
sample.
I download from the internet. Maybe it's name is "VDBUS" source code,
written by Primoz Beltram.

User can mount the disk image file such as raw dd image file,
then it will appear the Disk Managerment MMC interface.
It works fine, but i don't how to make it read-only.


//This is caret physical device object.
// Set DeviceType
WdfDeviceInitSetDeviceType(DeviceInit, FILE_DEVICE_DISK);
WdfDeviceInitSetExclusive(DeviceInit, TRUE);
WdfDeviceInitSetIoType(DeviceInit, WdfDeviceIoDirect);
WdfDeviceInitSetCharacteristics(DeviceInit,
FILE_DEVICE_SECURE_OPEN
//| FILE_READ_ONLY_DEVICE
/*| FILE_REMOVABLE_MEDIA*/
| FILE_CHARACTERISTIC_PNP_DEVICE, TRUE);

WdfDeviceInitSetDeviceClass(DeviceInit, &GUID_DEVCLASS_DISKDRIVE);

// Provide DeviceID, HardwareIDs, CompatibleIDs and InstanceId
ntStatus = WdfPdoInitAssignDeviceID(DeviceInit, &deviceID);
ntStatus = WdfPdoInitAddHardwareID(DeviceInit, &hardwareID);
ntStatus = WdfPdoInitAddCompatibleID(DeviceInit, &compatibleID);
ntStatus = RtlUnicodeStringPrintf(&buffer, L"VDBusDisk%02d", SerialNo);
ntStatus = WdfPdoInitAssignInstanceID(DeviceInit, &buffer);
ntStatus = RtlUnicodeStringPrintf(&buffer, L"VDBUS Disk %02d", SerialNo);
ntStatus = WdfPdoInitAddDeviceText(DeviceInit, &buffer, &deviceLocation,
0x409);
WdfPdoInitSetDefaultLocale(DeviceInit, 0x409);

// Initialize WDF_PDO_EVENT_CALLBACKS structure to fill the
// dispatch table for a bus driver's event callbacks. We use
// this callback to provide a fake I/O port resource.
WDF_PDO_EVENT_CALLBACKS_INIT(&pdoCallbacks);
WdfPdoInitSetEventCallbacks(DeviceInit, &pdoCallbacks);
// Mark a PDO as raw.
WdfPdoInitAssignRawDevice(DeviceInit, &GUID_DEVCLASS_DISKDRIVE);

// Initialize the attributes to specify the size of PDO device extension.
// All the state information private to the PDO will be tracked here.
WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&pdo_Attributes, PDO_DEVICE_DATA);
pdo_Attributes.SynchronizationScope =
WdfSynchronizationScopeInheritFromParent;
pdo_Attributes.ExecutionLevel = WdfExecutionLevelInheritFromParent;

ntStatus = WdfDeviceCreate(&DeviceInit, &pdo_Attributes, &hChild);

WDF_IO_QUEUE_CONFIG_INIT_DEFAULT_QUEUE(&queueConfig,
WdfIoQueueDispatchParallel);
queueConfig.PowerManaged = WdfFalse;
queueConfig.AllowZeroLengthRequests = TRUE;
queueConfig.EvtIoDeviceControl = BusPDO_EvtIoDeviceControl;
queueConfig.EvtIoDefault = BusPDO_EvtIoDefault;
queueConfig.EvtIoRead = BusPDO_EvtIoRead;
queueConfig.EvtIoWrite = BusPDO_EvtIoWrite;
//DEL queueConfig.EvtIoInternalDeviceControl =
BusPDO_EvtIoInternalDeviceControl;
queueConfig.EvtIoStop = BusPDO_EvtIoStop;
queueConfig.EvtIoResume = BusPDO_EvtIoResume;
queueConfig.EvtIoCanceledOnQueue = BusPDO_EvtIoCanceledOnQueue;

// Set POWER properties for the child device.
WDF_DEVICE_POWER_CAPABILITIES_INIT(&powerCaps);
powerCaps.DeviceWake = PowerDeviceD1;
powerCaps.DeviceState[PowerSystemWorking] = PowerDeviceD0;
powerCaps.DeviceState[PowerSystemSleeping1] = PowerDeviceD3;
powerCaps.DeviceState[PowerSystemSleeping2] = PowerDeviceD3;
powerCaps.DeviceState[PowerSystemSleeping3] = PowerDeviceD3;
powerCaps.DeviceState[PowerSystemHibernate] = PowerDeviceD3;
powerCaps.DeviceState[PowerSystemShutdown] = PowerDeviceD3;
WdfDeviceSetPowerCapabilities(hChild, &powerCaps);
ntStatus = WdfDeviceCreateDeviceInterface(hChild, &GUID_DEVCLASS_DISKDRIVE,
NULL);
//////////////////////////////////////////////////////////////////////////////////////////////
// this code is handle the default request for SCSI request
VOID
BusPDO_EvtIoDefault(IN WDFQUEUE hQueue, IN WDFREQUEST hRequest)
{
WDF_REQUEST_PARAMETERS sReqParams;

PAGED_CODE ();

WDF_REQUEST_PARAMETERS_INIT(&sReqParams);
WdfRequestGetParameters(hRequest, &sReqParams);

switch (sReqParams.Type)
{
case WdfRequestTypeDeviceControlInternal: // IRP_MJ_SCSI

// Handle IRP_MJ_SCSI request.
BusPDO_InternalSCSI(hQueue, hRequest);
break;

default:

tst_TRC_m(tst_DBG_MAIN_d, (tst_TRC_PARAMS_d,
"Unknown EvtIoDefault(0x%x,0x%x).",
sReqParams.Type, sReqParams.MinorFunction));

WdfRequestComplete(hRequest, STATUS_INVALID_DEVICE_REQUEST);
break;
};

};
// then the internal scsi request handler
//============================================================================//
VOID
BusPDO_InternalSCSI(IN WDFQUEUE hQueue, IN WDFREQUEST hRequest)
{
WDF_REQUEST_PARAMETERS sReqParams;
PSCSI_REQUEST_BLOCK pSrb;
ULONG ulIoctl;

PAGED_CODE();

tst_FUNCIN_m();

tst_INP_ASSERT_m(NULL != hQueue, __LINE__, 0, 0, 0);
tst_INP_ASSERT_m(NULL != hRequest, __LINE__, 0, 0, 0);

WDF_REQUEST_PARAMETERS_INIT(&sReqParams);
WdfRequestGetParameters(hRequest, &sReqParams);
pSrb = (PSCSI_REQUEST_BLOCK) sReqParams.Parameters.Others.Arg1;
ulIoctl = sReqParams.Parameters.Others.IoControlCode;

//Dump all SRB members.
tst_TRC_m(tst_DBG_SRB_d, (tst_TRC_PARAMS_d,
"Dump SRB. Len=%d Function=0x%x SrbStatus=0x%x ScsiStatus=0x%x
PathId=%d TargetId=%d Lun=%d "
"QueueTag=0x%x QueueAction=0x%x QueueSortKey=0x%x TimeOutValue=%d
SrbFlags=0x%x"
"DataTransferLength=%d DataBuffer=0x%x SenseInfoBufferLength=%d
SenseInfoBuffer=0x%x "
"OriginalRequest=0x%x SrbExtension=0x%x NextSrb=0x%x CdbLength=%d
Cdb[0]=0x%x",
pSrb->Length, pSrb->Function, pSrb->SrbStatus, pSrb->ScsiStatus,
pSrb->PathId, pSrb->TargetId, pSrb->Lun,
pSrb->QueueTag, pSrb->QueueAction, pSrb->QueueSortKey,
pSrb->TimeOutValue, pSrb->SrbFlags,
pSrb->DataTransferLength, pSrb->DataBuffer,
pSrb->SenseInfoBufferLength, pSrb->SenseInfoBuffer,
pSrb->OriginalRequest, pSrb->SrbExtension, pSrb->NextSrb,
pSrb->CdbLength, pSrb->Cdb[0]));

switch (ulIoctl)
{
case IOCTL_SCSI_EXECUTE_NONE:
switch (pSrb->Function)
{
case SRB_FUNCTION_CLAIM_DEVICE:
WdfRequestComplete(hRequest, STATUS_SUCCESS);
break;
case SRB_FUNCTION_EXECUTE_SCSI:
//Really?
BusPDO_ScsiRequest(hQueue, hRequest, pSrb);
break;
default:
pSrb->SrbStatus = SRB_STATUS_INVALID_REQUEST;
WdfRequestComplete(hRequest,
STATUS_INVALID_DEVICE_REQUEST);
break;
};
break;
case IOCTL_SCSI_EXECUTE_IN:
pSrb->SrbStatus = SRB_STATUS_INVALID_REQUEST;
WdfRequestComplete(hRequest, STATUS_INVALID_DEVICE_REQUEST);
break;
case IOCTL_SCSI_EXECUTE_OUT:
pSrb->SrbStatus = SRB_STATUS_INVALID_REQUEST;
WdfRequestComplete(hRequest, STATUS_INVALID_DEVICE_REQUEST);
break;

default: // It is IRP_MJ_SCSI.

BusPDO_ScsiRequest(hQueue, hRequest, pSrb);
break;
};

tst_FUNCOUT_m();
};
//--------------------------------------------------------------------
VOID
BusPDO_ScsiRequest(IN WDFQUEUE hQueue, IN WDFREQUEST hRequest,
IN PSCSI_REQUEST_BLOCK pSrb)
{
PCDB pCdb;
PSRB_IO_CONTROL pSio;

PAGED_CODE();

switch (pSrb->Function)
{
case SRB_FUNCTION_EXECUTE_SCSI:

pCdb = (PCDB) pSrb->Cdb;
switch (pCdb->CDB6GENERIC.OperationCode)
{
case SCSIOP_READ_CAPACITY:
BusPDO_SrbReadCapacity(hQueue, hRequest, pSrb);
break;

case SCSIOP_READ:
BusPDO_SrbRead(hQueue, hRequest, pSrb);
break;

case SCSIOP_WRITE:
BusPDO_SrbWrite(hQueue, hRequest, pSrb);
break;

// If i refuse this request, Windows will not make the Virtual Disk Device
available.
/*case SCSIOP_WRITE:
tst_TRC_m(tst_DBG_MAIN_d, (tst_TRC_PARAMS_d,
"-- UNIMPLEMENTED. SCSIOP_WRITE CDB(%d,0x%x).",
pSrb->CdbLength, pCdb->CDB6GENERIC.OperationCode));

pSrb->ScsiStatus = SRB_STATUS_BAD_FUNCTION;
pSrb->SrbStatus = SRB_STATUS_BAD_FUNCTION;

WdfRequestComplete(hRequest, STATUS_MEDIA_WRITE_PROTECTED);
break;*/

case SCSIOP_MODE_SENSE:
BusPDO_SrbModeSense(hQueue, hRequest, pSrb);
break;

case SCSIOP_TEST_UNIT_READY:
BusPDO_SrbTestUnitReady(hQueue, hRequest, pSrb);
break;

case SCSIOP_VERIFY:
BusPDO_SrbVerify(hQueue, hRequest, pSrb);
break;

case SCSIOP_MEDIUM_REMOVAL:
BusPDO_SrbMediumRemoval(hQueue, hRequest, pSrb);
break;

case SCSIOP_LOAD_UNLOAD:
BusPDO_SrbLoadUnload(hQueue, hRequest, pSrb);
break;

default: // Unknown SRB operation code.
myTraceMessage(tst_DBG_MAIN_d, (tst_TRC_PARAMS_d,
"UNIMPLEMENTED. SRB_FUNCTION_EXECUTE_SCSI
CDB(%d,0x%x).",
pSrb->CdbLength, pCdb->CDB6GENERIC.OperationCode));

pSrb->ScsiStatus = SRB_STATUS_ERROR;
pSrb->SrbStatus = SRB_STATUS_ERROR;

WdfRequestComplete(hRequest,
STATUS_INVALID_DEVICE_REQUEST);
break;
};
break;

case SRB_FUNCTION_IO_CONTROL:

pSio = (PSRB_IO_CONTROL) pSrb->DataBuffer;

myTraceMessage(tst_DBG_MAIN_d, (tst_TRC_PARAMS_d,
"UNIMPLEMENTED. SRB_FUNCTION_IO_CONTROL SIO(%d,0x%x,%d).",
pSrb->DataTransferLength, pSio->ControlCode, pSio->Length));
// This way comes in some SMART disk IOCTLs
// e.g. IOCTL_SCSI_MINIPORT_IDENTIFY send from
DiskPerformSmartCommand (disk.c).

// Success request.
// pSio->ReturnCode = STATUS_SUCCESS;
// pSRB->SrbStatus = SRB_STATUS_SUCCESS;
// *pulLen = pSio->Length;

//TODO IOCTL_SCSI_MINIPORT_IDENTIFY:
// UNIMPLEMENTED. SRB_FUNCTION_IO_CONTROL
SIO(572,0x1b0501,544)
pSrb->ScsiStatus = SRB_STATUS_ERROR;
pSrb->SrbStatus = SRB_STATUS_INVALID_REQUEST;
WdfRequestComplete(hRequest, STATUS_INVALID_DEVICE_REQUEST);
break;

case SRB_FUNCTION_FLUSH:
// Success request.
pSrb->SrbStatus = SRB_STATUS_SUCCESS;
WdfRequestComplete(hRequest, STATUS_SUCCESS);
break;

case SRB_FUNCTION_SHUTDOWN:
// Success request.
pSrb->SrbStatus = SRB_STATUS_SUCCESS;
WdfRequestComplete(hRequest, STATUS_SUCCESS);
break;

default: // Unknown SRB function.

pSrb->ScsiStatus = SRB_STATUS_ERROR;
pSrb->SrbStatus = SRB_STATUS_INVALID_REQUEST;

WdfRequestComplete(hRequest, STATUS_INVALID_DEVICE_REQUEST);
break;
};

};

I can't refuse SCSIOP_WRITE request. it will make mount image failed.
Dose someone can give me some cure? I can't post all the code on here, due
to the size limitation.
So if someone can help me to fix this problem, i could share with my code.

Thank u!


Don Burn

unread,
Apr 20, 2008, 6:51:19 AM4/20/08
to
Return STATUS_MEDIA_WRITE_PROTECTED from IOCTL_DISK_IS_WRITABLE


--
Don Burn (MVP, Windows DDK)
Windows 2k/XP/2k3 Filesystem and Driver Consulting
Website: http://www.windrvr.com
Blog: http://msmvps.com/blogs/WinDrvr
Remove StopSpam to reply

"sa_sa_Jerry" <sa_sa...@hotmail.com> wrote in message
news:OZhyMuoo...@TK2MSFTNGP04.phx.gbl...

0 new messages