Windows上的物理驱动器上的SCSI读取(10)

时间:2017-01-04 03:58:57

标签: c winapi

我尝试向Windows 7计算机上的物理驱动器发出SCSI Read(10)命令。以下是我正在使用的代码段。它失败了,错误代码为87。

void scsi_read() 
{

 const UCHAR cdb[10] = { 0x28, 0, 0, 0, 0, 0, 0, 0, 512, 0 };
 UCHAR buf[512];
 BYTE senseBuf[196];
 const int SENSE_LENGTH = 196;
 LPCSTR fname = "\\\\.\\E:";
 HANDLE fh; 
 DWORD ioctl_bytes;
 DWORD err = 0;

 SCSI_PASS_THROUGH s = {0};
 memcpy(s.Cdb, cdb, sizeof(cdb));
 s.CdbLength = 10;
 s.DataIn = SCSI_IOCTL_DATA_IN;
 s.TimeOutValue = 30;
 s.Length = sizeof(SCSI_PASS_THROUGH);  
 s.ScsiStatus         = 0x00;
 s.SenseInfoOffset =  senseBuf;
 s.SenseInfoLength  = SENSE_LENGTH;
 s.DataBufferOffset = buf;
 s.DataTransferLength = 512;

 fh = CreateFile("\\\\.\\E:", GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL,  OPEN_EXISTING, 0, NULL);
 if(fh == INVALID_HANDLE_VALUE) {
    printf("Could not open %s file, error %d\n", fname, GetLastError());
    return (FALSE);
 }

 int ret = DeviceIoControl(fh,IOCTL_SCSI_PASS_THROUGH, &s,sizeof(s), //scsiPassThrough.sizeof,
                                &s,
                                sizeof(s),
                                &ioctl_bytes,
                                NULL);

 printf("ret %d",(int)ret);                                    
 if (ret==1) {
    printf("OK");
 }
 else {

    err = GetLastError();
    printf("Last error code %u\n", err);
    printf("Return size %d\n", ioctl_bytes);
    printf("Sense data\n");
    int i=0;
    for (i = 0; i < 20; i++) {
        printf("\t%x", senseBuf[i]);
    }
    printf("\n");
 }
 CloseHandle(fh);
}

错误:在输出中打印十六进制转储

Code Output

1 个答案:

答案 0 :(得分:1)

您收到错误代码87 - ERROR_INVALID_PARAMETER,因为代码完全错误。

例如:

const UCHAR cdb[10] = { 0x28, 0, 0, 0, 0, 0, 0, 0, 512, 0 };

但是512> 255MAXUCHAR)你在这里没有编译器警告吗?

warning C4305: 'initializing': truncation from 'int' to 'const UCHAR'

看看这一行!

s.DataBufferOffset = buf;

来自SCSI_PASS_THROUGH结构:

  

DataBufferOffset

     

包含从此结构的开头到数据的偏移量   缓冲。偏移必须遵守数据对齐要求   设备

所以偏移到缓冲区,而不是指针到缓冲区

使用这个正确的代码需要像这样:

struct MY_DATA : SCSI_PASS_THROUGH 
{
    UCHAR buf[512];
} s;

s.DataBufferOffset = FIELD_OFFSET(MY_DATA, buf);

但最好SCSI_PASS_THROUGH_DIRECTIOCTL_SCSI_PASS_THROUGH_DIRECT

一起使用{{3}}

你硬编码扇区大小(512),当需要在运行时获取它。以及如何初始化CDB?!?根本不清楚你尝试做什么。

工作代码示例(抱歉,但c++代替c

#define _NTSCSI_USER_MODE_
#include <scsi.h>
#include <ntddscsi.h>

BOOL scsi_read(HANDLE fh, PVOID buf, DWORD cb, ULONGLONG LogicalBlock, ULONG TransferBlocks)
{
    SCSI_PASS_THROUGH_DIRECT s = { 
        sizeof(SCSI_PASS_THROUGH_DIRECT), 0, 0, 0, 0, 0, 0, SCSI_IOCTL_DATA_IN, cb, 30, buf
    };

    union {
        PUCHAR Cdb;
        CDB::_CDB10* Cdb10;
        CDB::_CDB16* Cdb16;
    };

    Cdb = s.Cdb;

    if (MAXULONG < LogicalBlock || MAXUSHORT < TransferBlocks)
    {
        s.CdbLength = sizeof(CDB::_CDB16);
        Cdb16->OperationCode = SCSIOP_READ16;
        *(ULONGLONG*)Cdb16->LogicalBlock = _byteswap_uint64(LogicalBlock);
        *(ULONG*)Cdb16->TransferLength = _byteswap_ulong(TransferBlocks);
    }
    else
    {
        s.CdbLength = sizeof(CDB::_CDB10);
        Cdb10->OperationCode = SCSIOP_READ;
        *(ULONG*)&Cdb10->LogicalBlockByte0 = _byteswap_ulong((ULONG)LogicalBlock);
        *(USHORT*)&Cdb10->TransferBlocksMsb = _byteswap_ushort((USHORT)TransferBlocks);
    }

    DWORD ioctl_bytes;

    return DeviceIoControl(fh, IOCTL_SCSI_PASS_THROUGH_DIRECT, &s, sizeof(s), &s, sizeof(s), &ioctl_bytes, NULL);
}

BOOL test_scsi_read(PCWSTR fname) 
{
    BOOL fOk = FALSE;

    HANDLE fh = CreateFileW(fname, GENERIC_READ | GENERIC_WRITE, 
        FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL);

    if (fh != INVALID_HANDLE_VALUE) 
    {
        DWORD ioctl_bytes;

        DISK_GEOMETRY_EX dg;

        if (DeviceIoControl(fh, IOCTL_DISK_GET_DRIVE_GEOMETRY_EX, NULL, 0, &dg, sizeof(dg), &ioctl_bytes, 0))
        {
            // 16 sectors for example
            ULONG cb = 16 * dg.Geometry.BytesPerSector;

            if (PVOID buf = new CHAR[cb])
            {
                // read first 16 sectors
                fOk = scsi_read(fh, buf, cb, 0, 16);

                if (ULONGLONG LogicalBlock = dg.DiskSize.QuadPart / dg.Geometry.BytesPerSector)
                {
                    // read last sector
                    fOk = scsi_read(fh, buf, dg.Geometry.BytesPerSector, LogicalBlock - 1, 1);
                }

                delete buf;
            }
        }

        CloseHandle(fh);
    }

    return fOk;
}
    test_scsi_read(L"\\\\?\\e:");