150 lines
4.0 KiB
C++
150 lines
4.0 KiB
C++
|
#include <windows.h>
|
||
|
#include <stddef.h> // for offsetof
|
||
|
#include <winioctl.h>
|
||
|
#include <strsafe.h>
|
||
|
|
||
|
typedef struct {
|
||
|
USHORT Length;
|
||
|
UCHAR ScsiStatus;
|
||
|
UCHAR PathId;
|
||
|
UCHAR TargetId;
|
||
|
UCHAR Lun;
|
||
|
UCHAR CdbLength;
|
||
|
UCHAR SenseInfoLength;
|
||
|
UCHAR DataIn;
|
||
|
ULONG DataTransferLength;
|
||
|
ULONG TimeOutValue;
|
||
|
PVOID DataBuffer;
|
||
|
ULONG SenseInfoOffset;
|
||
|
UCHAR Cdb[16];
|
||
|
} SCSI_PASS_THROUGH_DIRECT, *PSCSI_PASS_THROUGH_DIRECT;
|
||
|
|
||
|
|
||
|
typedef struct {
|
||
|
SCSI_PASS_THROUGH_DIRECT spt;
|
||
|
ULONG Filler;
|
||
|
UCHAR ucSenseBuf[32];
|
||
|
} SCSI_PASS_THROUGH_DIRECT_WITH_BUFFER, *PSCSI_PASS_THROUGH_DIRECT_WITH_BUFFER;
|
||
|
|
||
|
|
||
|
|
||
|
#define IOCTL_SCSI_BASE 0x00000004
|
||
|
|
||
|
/*
|
||
|
* constants for DataIn member of SCSI_PASS_THROUGH* structures
|
||
|
*/
|
||
|
#define SCSI_IOCTL_DATA_OUT 0
|
||
|
#define SCSI_IOCTL_DATA_IN 1
|
||
|
#define SCSI_IOCTL_DATA_UNSPECIFIED 2
|
||
|
|
||
|
/*
|
||
|
* Standard IOCTL define
|
||
|
*/
|
||
|
#define CTL_CODE( DevType, Function, Method, Access ) ( \
|
||
|
((DevType) << 16) | ((Access) << 14) | ((Function) << 2) | (Method) \
|
||
|
)
|
||
|
|
||
|
#define IOCTL_SCSI_PASS_THROUGH CTL_CODE( IOCTL_SCSI_BASE, 0x0401, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS )
|
||
|
#define IOCTL_SCSI_MINIPORT CTL_CODE( IOCTL_SCSI_BASE, 0x0402, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS )
|
||
|
#define IOCTL_SCSI_GET_INQUIRY_DATA CTL_CODE( IOCTL_SCSI_BASE, 0x0403, METHOD_BUFFERED, FILE_ANY_ACCESS)
|
||
|
#define IOCTL_SCSI_GET_CAPABILITIES CTL_CODE( IOCTL_SCSI_BASE, 0x0404, METHOD_BUFFERED, FILE_ANY_ACCESS)
|
||
|
#define IOCTL_SCSI_PASS_THROUGH_DIRECT CTL_CODE( IOCTL_SCSI_BASE, 0x0405, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS )
|
||
|
#define IOCTL_SCSI_GET_ADDRESS CTL_CODE( IOCTL_SCSI_BASE, 0x0406, METHOD_BUFFERED, FILE_ANY_ACCESS
|
||
|
|
||
|
static bool scsi_inquiry(HANDLE deviceHandle, UCHAR page, UCHAR *inqbuf, size_t &buf_len)
|
||
|
{
|
||
|
char buf[2048] = {0};
|
||
|
BOOL status;
|
||
|
PSCSI_PASS_THROUGH_DIRECT_WITH_BUFFER pswb;
|
||
|
|
||
|
DWORD length=0, returned=0;
|
||
|
|
||
|
/*
|
||
|
* Get the drive inquiry data
|
||
|
*/
|
||
|
ZeroMemory( &buf, 2048 );
|
||
|
ZeroMemory( inqbuf, buf_len );
|
||
|
pswb = (PSCSI_PASS_THROUGH_DIRECT_WITH_BUFFER)buf;
|
||
|
pswb->spt.Length = sizeof(SCSI_PASS_THROUGH_DIRECT);
|
||
|
pswb->spt.CdbLength = 6;
|
||
|
pswb->spt.SenseInfoLength = 32;
|
||
|
pswb->spt.DataIn = SCSI_IOCTL_DATA_IN;
|
||
|
pswb->spt.DataTransferLength = buf_len;
|
||
|
pswb->spt.TimeOutValue = 2;
|
||
|
pswb->spt.DataBuffer = inqbuf;
|
||
|
pswb->spt.SenseInfoOffset = offsetof(SCSI_PASS_THROUGH_DIRECT_WITH_BUFFER,ucSenseBuf);
|
||
|
pswb->spt.Cdb[0] = 0x12;
|
||
|
pswb->spt.Cdb[1] = 0x1;
|
||
|
pswb->spt.Cdb[2] = page;
|
||
|
pswb->spt.Cdb[4] = (UCHAR)buf_len;
|
||
|
|
||
|
length = sizeof(SCSI_PASS_THROUGH_DIRECT_WITH_BUFFER);
|
||
|
status = DeviceIoControl( deviceHandle,
|
||
|
IOCTL_SCSI_PASS_THROUGH_DIRECT,
|
||
|
pswb,
|
||
|
length,
|
||
|
pswb,
|
||
|
length,
|
||
|
&returned,
|
||
|
NULL );
|
||
|
|
||
|
|
||
|
if (status && returned >3)
|
||
|
{
|
||
|
buf_len=returned;
|
||
|
return true;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
buf_len=0;
|
||
|
return false;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
static bool AddPagetoXML(HANDLE dev, char *&dest, size_t &destlen, UCHAR page)
|
||
|
{
|
||
|
UCHAR buf[256] = {0};
|
||
|
size_t buflen=255;
|
||
|
if (scsi_inquiry(dev, page, buf, buflen))
|
||
|
{
|
||
|
size_t len = buf[3];
|
||
|
StringCchCopyNExA(dest, destlen, (char *)buf+4, len, &dest, &destlen, 0);
|
||
|
return true;
|
||
|
}
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
static bool BuildXML(HANDLE dev, char *xml, size_t xmllen)
|
||
|
{
|
||
|
*xml=0;
|
||
|
UCHAR pages[255] = {0};
|
||
|
size_t pageslen=255;
|
||
|
if (scsi_inquiry(dev, 0xc0, pages, pageslen) && pageslen>3)
|
||
|
{
|
||
|
unsigned char numPages=pages[3];
|
||
|
if (numPages+4 <= 255)
|
||
|
{
|
||
|
for (int i=0;i<numPages;i++)
|
||
|
{
|
||
|
if (!AddPagetoXML(dev, xml, xmllen, pages[i+4]))
|
||
|
return false;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
bool ParseSysInfoXML(wchar_t drive_letter, char * xml, int xmllen)
|
||
|
{
|
||
|
wchar_t fn[MAX_PATH] = {0};
|
||
|
StringCchPrintf(fn, MAX_PATH, L"\\\\.\\%c:", drive_letter);
|
||
|
HANDLE hfile = CreateFileW(fn, GENERIC_WRITE|GENERIC_READ, FILE_SHARE_READ|FILE_SHARE_WRITE, 0, OPEN_EXISTING, 0, 0);
|
||
|
if (hfile != INVALID_HANDLE_VALUE)
|
||
|
{
|
||
|
bool ret = BuildXML(hfile, xml, xmllen);
|
||
|
CloseHandle(hfile);
|
||
|
return ret;
|
||
|
}
|
||
|
return false;
|
||
|
}
|