📄 scsicmd.cpp
字号:
#pragma warning(disable:4005)
#include <stddef.h>
#include <Windows.h>
#include "scsicmd.h"
namespace NT{
#include <ntddk.h>
#include <devioctl.h>
#include <ntdddisk.h>
#include <ntddscsi.h>
#include <scsi.h>
}
#include <memory>
using namespace std;
#define SENSEBUFSIZE 32
#define DATABUFSIZE 0xFC
#pragma pack(push,4)
typedef struct _SCSI_PASS_THROUGH_WITH_BUFFERS {
NT::SCSI_PASS_THROUGH spt;
ULONG Filler; // realign buffers to double word boundary
UCHAR ucSenseBuf[SENSEBUFSIZE];
UCHAR ucDataBuf[DATABUFSIZE];
} SCSI_PASS_THROUGH_WITH_BUFFERS, *PSCSI_PASS_THROUGH_WITH_BUFFERS;
typedef struct _SCSI_PASS_THROUGH_DIRECT_WITH_BUFFER {
NT::SCSI_PASS_THROUGH_DIRECT sptd;
ULONG Filler; // realign buffer to double word boundary
UCHAR ucSenseBuf[SENSEBUFSIZE];
} SCSI_PASS_THROUGH_DIRECT_WITH_BUFFER, *PSCSI_PASS_THROUGH_DIRECT_WITH_BUFFER;
#pragma pack(pop)
bool GetCapacity(wstring const&Device,DWORD&Sectors,DWORD&BytesPerSector){
bool success=false;Sectors=BytesPerSector=0;
HANDLE const hDrive=CreateFileW(Device.c_str(),GENERIC_READ|GENERIC_WRITE,FILE_SHARE_READ|FILE_SHARE_WRITE,NULL,OPEN_EXISTING,0,NULL);
DWORD returned;
SCSI_PASS_THROUGH_WITH_BUFFERS sptwb;
NT::CDB&Cdb=(NT::CDB&)sptwb.spt.Cdb;
memset(&sptwb,0,sizeof(SCSI_PASS_THROUGH_WITH_BUFFERS));
sptwb.spt.Length = sizeof(NT::SCSI_PASS_THROUGH);
//sptwb.spt.PathId = 0;
//sptwb.spt.TargetId = 0;
//sptwb.spt.Lun = 0;
sptwb.spt.CdbLength = CDB10GENERIC_LENGTH;
sptwb.spt.SenseInfoLength = SENSEBUFSIZE;
sptwb.spt.DataIn = SCSI_IOCTL_DATA_IN;
sptwb.spt.DataTransferLength = DATABUFSIZE;
sptwb.spt.TimeOutValue = 10;
sptwb.spt.DataBufferOffset =offsetof(SCSI_PASS_THROUGH_WITH_BUFFERS,ucDataBuf);
sptwb.spt.SenseInfoOffset =offsetof(SCSI_PASS_THROUGH_WITH_BUFFERS,ucSenseBuf);
sptwb.spt.Cdb[0] = SCSIOP_READ_CAPACITY;
DWORD length=offsetof(SCSI_PASS_THROUGH_WITH_BUFFERS,ucDataBuf)+sptwb.spt.DataTransferLength;
BOOL status=DeviceIoControl(hDrive,IOCTL_SCSI_PASS_THROUGH,&sptwb,sizeof(NT::SCSI_PASS_THROUGH),&sptwb,length,&returned,NULL);
if(status&&!sptwb.spt.ScsiStatus){
if((sptwb.spt.DataTransferLength>7)&&(returned==sptwb.spt.DataTransferLength+sptwb.spt.DataBufferOffset)){
union{
DWORD u;
BYTE by[4];
}tmp;
tmp.by[3]=sptwb.ucDataBuf[0];
tmp.by[2]=sptwb.ucDataBuf[1];
tmp.by[1]=sptwb.ucDataBuf[2];
tmp.by[0]=sptwb.ucDataBuf[3];
if(++tmp.u){
Sectors=tmp.u;
tmp.by[3]=sptwb.ucDataBuf[4];
tmp.by[2]=sptwb.ucDataBuf[5];
tmp.by[1]=sptwb.ucDataBuf[6];
tmp.by[0]=sptwb.ucDataBuf[7];
BytesPerSector=tmp.u;
success=true;
}
}
}
CloseHandle(hDrive);
return success;
}
BOOL SCSICommand(HANDLE const hDevice,UCHAR&ScsiStatus,
UCHAR*const ucSenseBuf,UCHAR&SenseSize,
UCHAR*const ucDataBuf,DWORD&DataSize,
NT::CDB const&Cdb,BYTE const CdbLength,UCHAR const DataIn){
if(CdbLength>sizeof(((NT::SCSI_PASS_THROUGH_DIRECT*)NULL)->Cdb))
return FALSE;
DWORD const Align=4;
DWORD const tmpSenseSize=SenseSize<SENSEBUFSIZE?SENSEBUFSIZE:SenseSize;
auto_ptr<char>const tmpptr
(new char[sizeof(SCSI_PASS_THROUGH_DIRECT_WITH_BUFFER)+tmpSenseSize-SENSEBUFSIZE+Align]);
SCSI_PASS_THROUGH_DIRECT_WITH_BUFFER*const
psptdwb=(SCSI_PASS_THROUGH_DIRECT_WITH_BUFFER*)(DWORD(tmpptr.get()+Align-1)/Align*Align);
DWORD const sptdwbSize=sizeof(SCSI_PASS_THROUGH_DIRECT_WITH_BUFFER)+tmpSenseSize-SENSEBUFSIZE;
memset(psptdwb,0,sptdwbSize);
psptdwb->sptd.Length = sizeof(NT::SCSI_PASS_THROUGH_DIRECT);
psptdwb->sptd.CdbLength = CdbLength;
psptdwb->sptd.SenseInfoLength = ucSenseBuf?tmpSenseSize:0;
psptdwb->sptd.DataIn = DataIn;
psptdwb->sptd.DataTransferLength = DataSize;
psptdwb->sptd.TimeOutValue = 10;
psptdwb->sptd.DataBuffer = ucDataBuf;
psptdwb->sptd.SenseInfoOffset =offsetof(SCSI_PASS_THROUGH_DIRECT_WITH_BUFFER,ucSenseBuf);
memcpy(psptdwb->sptd.Cdb,&Cdb,CdbLength);
DWORD returned;
BOOL const Status=DeviceIoControl(hDevice,IOCTL_SCSI_PASS_THROUGH_DIRECT,
psptdwb,sizeof(NT::SCSI_PASS_THROUGH_DIRECT),
psptdwb,sptdwbSize,&returned,NULL);
if(!Status)
return FALSE;
if(returned<sizeof(NT::SCSI_PASS_THROUGH_DIRECT))
return FALSE;
if(sizeof(SCSI_PASS_THROUGH_DIRECT_WITH_BUFFER)-SENSEBUFSIZE+psptdwb->sptd.SenseInfoLength!=returned)
return FALSE;
ScsiStatus=psptdwb->sptd.ScsiStatus;
SenseSize=psptdwb->sptd.SenseInfoLength;
if(ucSenseBuf&&SenseSize)
memcpy(ucSenseBuf,psptdwb->ucSenseBuf,SenseSize);
DataSize=psptdwb->sptd.DataTransferLength;
return TRUE;
}
bool ModeSenseCheck(UCHAR const**const PageData,BOOL const Status,UCHAR const ScsiStatus,
UCHAR const PageCode,UCHAR const CdbLength,UCHAR const PageSize,
UCHAR*const DataBuf,DWORD const DataSize){
if((!Status)||(ScsiStatus))
return false;
if((CdbLength!=CDB6GENERIC_LENGTH)&&(CdbLength!=CDB10GENERIC_LENGTH))
return false;
DWORD const HeadSize=(CdbLength==CDB6GENERIC_LENGTH)?4:8;
if(DataSize<HeadSize)
return false;
WORD ModeDataLength,BlockLength;
if(CdbLength==CDB6GENERIC_LENGTH){
ModeDataLength=DataBuf[0]+1;
BlockLength=DataBuf[3];
}else{
union{
WORD w;
BYTE b[2];
}tmp;
tmp.b[1]=DataBuf[0];
tmp.b[0]=DataBuf[1];
ModeDataLength=tmp.w+2;
tmp.b[1]=DataBuf[6];
tmp.b[0]=DataBuf[7];
BlockLength=tmp.w;
}
if(ModeDataLength!=DataSize)
return false;
if((BlockLength&7)||(PageSize+BlockLength+HeadSize)>DataSize)
return false;
if(PageCode!=DataBuf[HeadSize+BlockLength])
return false;
if(PageSize!=DataBuf[HeadSize+BlockLength+1]+2)
return false;
if(PageData)
*PageData=DataBuf+HeadSize+BlockLength;
return true;
}
bool RigidDisk(HANDLE const hDrive,UCHAR const CdbLength,DWORD&Cylinders,DWORD&Heads,DWORD&Sectors,DWORD&SectorSize){
if((CdbLength!=CDB6GENERIC_LENGTH)&&(CdbLength!=CDB10GENERIC_LENGTH))
return false;
NT::CDB Cdb;
UCHAR DataBuf[DATABUFSIZE],SenseBuf[SENSEBUFSIZE];
UCHAR SenseSize=sizeof(SenseBuf),ScsiStatus;
DWORD DataSize=sizeof(DataBuf);
UCHAR const*PageData;
union{
DWORD u;
WORD w[2];
BYTE by[4];
}tmp;
memset(&Cdb,0,sizeof(Cdb));
if(CdbLength==CDB10GENERIC_LENGTH){
Cdb.MODE_SENSE10.OperationCode = SCSIOP_MODE_SENSE10;
Cdb.MODE_SENSE10.PageCode=MODE_PAGE_RIGID_GEOMETRY;
tmp.w[0]=sizeof(DataBuf);
Cdb.MODE_SENSE10.AllocationLength[0] = tmp.by[1];
Cdb.MODE_SENSE10.AllocationLength[1] = tmp.by[0];
}else{
Cdb.MODE_SENSE.OperationCode = SCSIOP_MODE_SENSE;
Cdb.MODE_SENSE.PageCode=MODE_PAGE_RIGID_GEOMETRY;
Cdb.MODE_SENSE.AllocationLength = sizeof(DataBuf);
}
BOOL Status=SCSICommand(hDrive,ScsiStatus,
SenseBuf,SenseSize,DataBuf,DataSize,Cdb,CdbLength,SCSI_IOCTL_DATA_IN);
if(ModeSenseCheck(&PageData,Status,ScsiStatus,Cdb.MODE_SENSE.PageCode,CdbLength,24,DataBuf,DataSize)){
tmp.by[3]=0;
tmp.by[2]=PageData[2];
tmp.by[1]=PageData[3];
tmp.by[0]=PageData[4];
Cylinders=tmp.u;
Heads=PageData[5];
SenseSize=sizeof(SenseBuf);
DataSize=sizeof(DataBuf);
memset(&Cdb,0,sizeof(Cdb));
if(CdbLength==CDB10GENERIC_LENGTH){
Cdb.MODE_SENSE10.OperationCode = SCSIOP_MODE_SENSE10;
Cdb.MODE_SENSE10.PageCode=MODE_PAGE_FORMAT_DEVICE;
tmp.w[0]=sizeof(DataBuf);
Cdb.MODE_SENSE10.AllocationLength[0] = tmp.by[1];
Cdb.MODE_SENSE10.AllocationLength[1] = tmp.by[0];
}else{
Cdb.MODE_SENSE.OperationCode = SCSIOP_MODE_SENSE;
Cdb.MODE_SENSE.PageCode=MODE_PAGE_FORMAT_DEVICE;
Cdb.MODE_SENSE.AllocationLength = sizeof(DataBuf);
}
Status=SCSICommand(hDrive,ScsiStatus,
SenseBuf,SenseSize,DataBuf,DataSize,Cdb,CdbLength,SCSI_IOCTL_DATA_IN);
if(ModeSenseCheck(&PageData,Status,ScsiStatus,Cdb.MODE_SENSE.PageCode,CdbLength,24,DataBuf,DataSize)){
tmp.by[3]=tmp.by[2]=0;
tmp.by[1]=PageData[10];
tmp.by[0]=PageData[11];
Sectors=tmp.u;
tmp.by[1]=PageData[12];
tmp.by[0]=PageData[13];
SectorSize=tmp.u;
return true;
}
}
return false;
}
bool FlexibleDisk(HANDLE const hDrive,UCHAR const CdbLength,DWORD&Cylinders,DWORD&Heads,DWORD&Sectors,DWORD&SectorSize){
if((CdbLength!=CDB6GENERIC_LENGTH)&&(CdbLength!=CDB10GENERIC_LENGTH))
return false;
NT::CDB Cdb;
UCHAR DataBuf[DATABUFSIZE],SenseBuf[SENSEBUFSIZE];
UCHAR SenseSize=sizeof(SenseBuf),ScsiStatus;
DWORD DataSize=sizeof(DataBuf);
UCHAR const*PageData;
union{
DWORD u;
WORD w[2];
BYTE by[4];
}tmp;
memset(&Cdb,0,sizeof(Cdb));
if(CdbLength==CDB10GENERIC_LENGTH){
Cdb.MODE_SENSE10.OperationCode = SCSIOP_MODE_SENSE10;
Cdb.MODE_SENSE10.PageCode=MODE_PAGE_FLEXIBILE;
tmp.w[0]=sizeof(DataBuf);
Cdb.MODE_SENSE10.AllocationLength[0] = tmp.by[1];
Cdb.MODE_SENSE10.AllocationLength[1] = tmp.by[0];
}else{
Cdb.MODE_SENSE.OperationCode = SCSIOP_MODE_SENSE;
Cdb.MODE_SENSE.PageCode=MODE_PAGE_FLEXIBILE;
Cdb.MODE_SENSE.AllocationLength = sizeof(DataBuf);
}
BOOL const Status=SCSICommand(hDrive,ScsiStatus,
SenseBuf,SenseSize,DataBuf,DataSize,Cdb,CdbLength,SCSI_IOCTL_DATA_IN);
if(ModeSenseCheck(&PageData,Status,ScsiStatus,Cdb.MODE_SENSE.PageCode,CdbLength,32,DataBuf,DataSize)){
Heads=PageData[4];
Sectors=PageData[5];
tmp.by[3]=tmp.by[2]=0;
tmp.by[1]=PageData[6];
tmp.by[0]=PageData[7];
SectorSize=tmp.u;
tmp.by[1]=PageData[8];
tmp.by[0]=PageData[9];
Cylinders=tmp.u;
return true;
}
return false;
}
bool GetGeometry(wstring const&Device,DWORD&Cylinders,DWORD&Heads,DWORD&Sectors,DWORD&SectorSize){
Cylinders=Heads=Sectors=SectorSize=0;
HANDLE const hDrive=CreateFileW(Device.c_str(),GENERIC_READ|GENERIC_WRITE,FILE_SHARE_READ|FILE_SHARE_WRITE,NULL,OPEN_EXISTING,0,NULL);
bool res;
if(!RigidDisk(hDrive,CDB10GENERIC_LENGTH,Cylinders,Heads,Sectors,SectorSize))
if(!RigidDisk(hDrive,CDB6GENERIC_LENGTH,Cylinders,Heads,Sectors,SectorSize))
if(!FlexibleDisk(hDrive,CDB10GENERIC_LENGTH,Cylinders,Heads,Sectors,SectorSize))
res=FlexibleDisk(hDrive,CDB6GENERIC_LENGTH,Cylinders,Heads,Sectors,SectorSize);
CloseHandle(hDrive);
return res;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -