📄 disk.c
字号:
controlCode = IOCTL_SCSI_MINIPORT_ENABLE_DISABLE_AUTOSAVE;
break;
case SAVE_ATTRIBUTE_VALUES:
controlCode = IOCTL_SCSI_MINIPORT_SAVE_ATTRIBUTE_VALUES;
break;
case EXECUTE_OFFLINE_DIAGS:
controlCode = IOCTL_SCSI_MINIPORT_EXECUTE_OFFLINE_DIAGS;
default:
status = STATUS_INVALID_PARAMETER;
break;
}
} else {
status = STATUS_INVALID_PARAMETER;
}
if (controlCode == 0) {
status = STATUS_INVALID_PARAMETER;
break;
}
length += (sizeof(SENDCMDOUTPARAMS) > sizeof(SENDCMDINPARAMS)) ? sizeof(SENDCMDOUTPARAMS) : sizeof(SENDCMDINPARAMS);;
srbControl = ExAllocatePool(NonPagedPool,
sizeof(SRB_IO_CONTROL) + length);
if (!srbControl) {
status = STATUS_INSUFFICIENT_RESOURCES;
break;
}
//
// fill in srbControl fields
//
srbControl->HeaderLength = sizeof(SRB_IO_CONTROL);
RtlMoveMemory (srbControl->Signature, "SCSIDISK", 8);
srbControl->Timeout = deviceExtension->TimeOutValue;
srbControl->Length = length;
//
// Point to the 'buffer' portion of the SRB_CONTROL
//
buffer = (ULONG_PTR)srbControl + srbControl->HeaderLength;
//
// Ensure correct target is set in the cmd parameters.
//
cmdInParameters->bDriveNumber = deviceExtension->TargetId;
//
// Copy the IOCTL parameters to the srb control buffer area.
//
RtlMoveMemory((PVOID)buffer, Irp->AssociatedIrp.SystemBuffer, sizeof(SENDCMDINPARAMS) - 1);
srbControl->ControlCode = controlCode;
irp2 = IoBuildDeviceIoControlRequest(IOCTL_SCSI_MINIPORT,
deviceExtension->PortDeviceObject,
srbControl,
sizeof(SRB_IO_CONTROL) + sizeof(SENDCMDINPARAMS) - 1,
srbControl,
sizeof(SRB_IO_CONTROL) + length,
FALSE,
&event,
&ioStatus);
if (irp2 == NULL) {
status = STATUS_INSUFFICIENT_RESOURCES;
break;
}
//
// Call the port driver with the request and wait for it to complete.
//
status = IoCallDriver(deviceExtension->PortDeviceObject, irp2);
if (status == STATUS_PENDING) {
KeWaitForSingleObject(&event, Suspended, KernelMode, FALSE, NULL);
status = ioStatus.Status;
}
//
// Copy the data received into the output buffer. Since the status buffer
// contains error information also, always perform this copy. IO will will
// either pass this back to the app, or zero it, in case of error.
//
buffer = (ULONG_PTR)srbControl + srbControl->HeaderLength;
//
// Update the return buffer size based on the sub-command.
//
if (cmdInParameters->irDriveRegs.bFeaturesReg == RETURN_SMART_STATUS) {
length = sizeof(SENDCMDOUTPARAMS) - 1 + sizeof(IDEREGS);
} else {
length = sizeof(SENDCMDOUTPARAMS) - 1;
}
RtlMoveMemory ( Irp->AssociatedIrp.SystemBuffer, (PVOID)buffer, length);
Irp->IoStatus.Information = length;
ExFreePool(srbControl);
break;
}
case IOCTL_DISK_GET_DRIVE_GEOMETRY:
if ( irpStack->Parameters.DeviceIoControl.OutputBufferLength <
sizeof( DISK_GEOMETRY ) ) {
status = STATUS_INFO_LENGTH_MISMATCH;
break;
}
if (DeviceObject->Characteristics & FILE_REMOVABLE_MEDIA) {
//
// Issue ReadCapacity to update device extension
// with information for current media.
//
status = ScsiClassReadDriveCapacity(deviceExtension->PhysicalDevice);
if (!NT_SUCCESS(status)) {
//
// Note the drive is not ready.
//
diskData->DriveNotReady = TRUE;
break;
}
//
// Note the drive is now ready.
//
diskData->DriveNotReady = FALSE;
}
//
// Copy drive geometry information from device extension.
//
RtlMoveMemory(Irp->AssociatedIrp.SystemBuffer,
deviceExtension->DiskGeometry,
sizeof(DISK_GEOMETRY));
status = STATUS_SUCCESS;
Irp->IoStatus.Information = sizeof(DISK_GEOMETRY);
break;
case IOCTL_DISK_VERIFY:
{
PVERIFY_INFORMATION verifyInfo = Irp->AssociatedIrp.SystemBuffer;
LARGE_INTEGER byteOffset;
ULONG sectorOffset;
USHORT sectorCount;
//
// Validate buffer length.
//
if (irpStack->Parameters.DeviceIoControl.InputBufferLength <
sizeof(VERIFY_INFORMATION)) {
status = STATUS_INFO_LENGTH_MISMATCH;
break;
}
//
// Verify sectors
//
srb->CdbLength = 10;
cdb->CDB10.OperationCode = SCSIOP_VERIFY;
//
// Add disk offset to starting sector.
//
byteOffset.QuadPart = deviceExtension->StartingOffset.QuadPart +
verifyInfo->StartingOffset.QuadPart;
//
// Convert byte offset to sector offset.
//
sectorOffset = (ULONG)(byteOffset.QuadPart >> deviceExtension->SectorShift);
//
// Convert ULONG byte count to USHORT sector count.
//
sectorCount = (USHORT)(verifyInfo->Length >> deviceExtension->SectorShift);
//
// Move little endian values into CDB in big endian format.
//
cdb->CDB10.LogicalBlockByte0 = ((PFOUR_BYTE)§orOffset)->Byte3;
cdb->CDB10.LogicalBlockByte1 = ((PFOUR_BYTE)§orOffset)->Byte2;
cdb->CDB10.LogicalBlockByte2 = ((PFOUR_BYTE)§orOffset)->Byte1;
cdb->CDB10.LogicalBlockByte3 = ((PFOUR_BYTE)§orOffset)->Byte0;
cdb->CDB10.TransferBlocksMsb = ((PFOUR_BYTE)§orCount)->Byte1;
cdb->CDB10.TransferBlocksLsb = ((PFOUR_BYTE)§orCount)->Byte0;
//
// The verify command is used by the NT FORMAT utility and
// requests are sent down for 5% of the volume size. The
// request timeout value is calculated based on the number of
// sectors verified.
//
srb->TimeOutValue = ((sectorCount + 0x7F) >> 7) *
deviceExtension->TimeOutValue;
status = ScsiClassSendSrbAsynchronous(DeviceObject,
srb,
Irp,
NULL,
0,
FALSE);
return(status);
}
case IOCTL_DISK_GET_PARTITION_INFO:
//
// Return the information about the partition specified by the device
// object. Note that no information is ever returned about the size
// or partition type of the physical disk, as this doesn't make any
// sense.
//
if (irpStack->Parameters.DeviceIoControl.OutputBufferLength <
sizeof(PARTITION_INFORMATION)) {
status = STATUS_INFO_LENGTH_MISMATCH;
}
#if 0 // HACK: ReactOS partition numbers must be wrong
else if (diskData->PartitionNumber == 0) {
//
// Paritition zero is not a partition so this is not a
// reasonable request.
//
status = STATUS_INVALID_DEVICE_REQUEST;
}
#endif
else {
PPARTITION_INFORMATION outputBuffer;
//
// Update the geometry in case it has changed.
//
status = UpdateRemovableGeometry (DeviceObject, Irp);
if (!NT_SUCCESS(status)) {
//
// Note the drive is not ready.
//
diskData->DriveNotReady = TRUE;
break;
}
//
// Note the drive is now ready.
//
diskData->DriveNotReady = FALSE;
// HACK: ReactOS partition numbers must be wrong (>0 part)
if (diskData->PartitionType == 0 && (diskData->PartitionNumber > 0)) {
status = STATUS_INVALID_DEVICE_REQUEST;
break;
}
outputBuffer =
(PPARTITION_INFORMATION)Irp->AssociatedIrp.SystemBuffer;
outputBuffer->PartitionType = diskData->PartitionType;
outputBuffer->StartingOffset = deviceExtension->StartingOffset;
outputBuffer->PartitionLength.QuadPart = (diskData->PartitionNumber) ?
deviceExtension->PartitionLength.QuadPart : 2305843009213693951LL; // HACK
outputBuffer->HiddenSectors = diskData->HiddenSectors;
outputBuffer->PartitionNumber = diskData->PartitionNumber;
outputBuffer->BootIndicator = diskData->BootIndicator;
outputBuffer->RewritePartition = FALSE;
outputBuffer->RecognizedPartition =
IsRecognizedPartition(diskData->PartitionType);
status = STATUS_SUCCESS;
Irp->IoStatus.Information = sizeof(PARTITION_INFORMATION);
}
break;
case IOCTL_DISK_SET_PARTITION_INFO:
if (diskData->PartitionNumber == 0) {
status = STATUS_UNSUCCESSFUL;
} else {
PSET_PARTITION_INFORMATION inputBuffer =
(PSET_PARTITION_INFORMATION)Irp->AssociatedIrp.SystemBuffer;
//
// Validate buffer length.
//
if (irpStack->Parameters.DeviceIoControl.InputBufferLength <
sizeof(SET_PARTITION_INFORMATION)) {
status = STATUS_INFO_LENGTH_MISMATCH;
break;
}
//
// The HAL routines IoGet- and IoSetPartitionInformation were
// developed before support of dynamic partitioning and therefore
// don't distinguish between partition ordinal (that is the order
// of a partition on a disk) and the partition number. (The
// partition number is assigned to a partition to identify it to
// the system.) Use partition ordinals for these legacy calls.
//
status = IoSetPartitionInformation(
deviceExtension->PhysicalDevice,
deviceExtension->DiskGeometry->BytesPerSector,
diskData->PartitionOrdinal,
inputBuffer->PartitionType);
if (NT_SUCCESS(status)) {
diskData->PartitionType = inputBuffer->PartitionType;
}
}
break;
case IOCTL_DISK_GET_DRIVE_LAYOUT:
//
// Return the partition layout for the physical drive. Note that
// the layout is returned for the actual physical drive, regardless
// of which partition was specified for the request.
//
if (irpStack->Parameters.DeviceIoControl.OutputBufferLength <
sizeof(DRIVE_LAYOUT_INFORMATION)) {
status = STATUS_INFO_LENGTH_MISMATCH;
} else {
PDRIVE_LAYOUT_INFORMATION partitionList;
PDEVICE_EXTENSION physicalExtension = deviceExtension;
PPARTITION_INFORMATION partitionEntry;
PDISK_DATA diskData;
ULONG tempSize;
ULONG i;
//
// Read partition information.
//
status = IoReadPartitionTable(deviceExtension->PhysicalDevice,
deviceExtension->DiskGeometry->BytesPerSector,
FALSE,
&partitionList);
if (!NT_SUCCESS(status)) {
break;
}
//
// The disk layout has been returned in the partitionList
// buffer. Determine its size and, if the data will fit
// into the intermediatery buffer, return it.
//
tempSize = FIELD_OFFSET(DRIVE_LAYOUT_INFORMATION,PartitionEntry[0]);
tempSize += partitionList->PartitionCount *
sizeof(PARTITION_INFORMATION);
if (tempSize >
irpStack->Parameters.DeviceIoControl.OutputBufferLength) {
status = STATUS_BUFFER_TOO_SMALL;
ExFreePool(partitionList);
break;
}
//
// Walk partition list to associate partition numbers with
// partition entries.
//
for (i = 0; i < partitionList->PartitionCount; i++) {
//
// Walk partition chain anchored at physical disk extension.
//
deviceExtension = physicalExtension;
diskData = (PDISK_DATA)(deviceExtension + 1);
do {
deviceExtension = diskData->NextPartition;
//
// Check if this is the last partition in the chain.
//
if (!deviceExtension) {
break;
}
//
// Get the partition device extension from disk data.
//
diskData = (PDISK_DATA)(deviceExtension + 1);
//
/
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -