mirror of
https://github.com/fadden/ciderpress.git
synced 2024-12-24 17:29:22 +00:00
aa3145856c
Focusing on the diskimg library this time, which deals with a lot of filesystem structures that have specific widths. This is still a bit lax in places, e.g. using "long" for lengths. Should either specify a bit width or use di_off_t. Also, added "override" keyword where appropriate. Also, bumped library version to 5.0.0.
138 lines
4.7 KiB
C++
138 lines
4.7 KiB
C++
/*
|
|
* CiderPress
|
|
* Copyright (C) 2007 by faddenSoft, LLC. All Rights Reserved.
|
|
* See the file LICENSE for distribution terms.
|
|
*/
|
|
/*
|
|
* Implementation of some SPTI functions.
|
|
*/
|
|
#include "StdAfx.h"
|
|
#ifdef _WIN32
|
|
|
|
#include "DiskImgPriv.h"
|
|
#include "SCSIDefs.h"
|
|
#include "CP_ntddscsi.h"
|
|
#include "SPTI.h"
|
|
|
|
|
|
/*
|
|
* Get the capacity of the device.
|
|
*
|
|
* Returns the LBA of the last valid block and the device's block size.
|
|
*/
|
|
/*static*/ DIError SPTI::GetDeviceCapacity(HANDLE handle, uint32_t* pLastBlock,
|
|
uint32_t* pBlockSize)
|
|
{
|
|
SCSI_PASS_THROUGH_DIRECT sptd;
|
|
uint32_t lba, blockLen;
|
|
CDB_ReadCapacityData dataBuf;
|
|
DWORD cb;
|
|
BOOL status;
|
|
|
|
assert(sizeof(dataBuf) == 8); // READ CAPACITY returns two longs
|
|
|
|
memset(&sptd, 0, sizeof(sptd));
|
|
sptd.Length = sizeof(sptd);
|
|
sptd.PathId = 0; // SCSI card ID filled in by ioctl
|
|
sptd.TargetId = 0; // SCSI target ID filled in by ioctl
|
|
sptd.Lun = 0; // SCSI lun ID filled in by ioctl
|
|
sptd.CdbLength = 10; // CDB size is 10 for READ CAPACITY
|
|
sptd.SenseInfoLength = 0; // don't return any sense data
|
|
sptd.DataIn = SCSI_IOCTL_DATA_IN; // will be data from drive
|
|
sptd.DataTransferLength = sizeof(dataBuf);
|
|
sptd.TimeOutValue = 10; // SCSI timeout value, in seconds
|
|
sptd.DataBuffer = (PVOID) &dataBuf;
|
|
sptd.SenseInfoOffset = 0; // offset to request-sense buffer
|
|
|
|
CDB10* pCdb = (CDB10*) &sptd.Cdb;
|
|
pCdb->operationCode = kScsiOpReadCapacity;
|
|
// rest of CDB is zero
|
|
|
|
status = ::DeviceIoControl(handle, IOCTL_SCSI_PASS_THROUGH_DIRECT,
|
|
&sptd, sizeof(sptd), NULL, 0, &cb, NULL);
|
|
|
|
if (!status) {
|
|
DWORD lastError = ::GetLastError();
|
|
LOGE("DeviceIoControl(SCSI READ CAPACITY) failed, err=%ld",
|
|
::GetLastError());
|
|
if (lastError == ERROR_IO_DEVICE) // no disc in drive
|
|
return kDIErrDeviceNotReady;
|
|
else
|
|
return kDIErrSPTIFailure;
|
|
}
|
|
|
|
lba = (uint32_t) dataBuf.logicalBlockAddr0 << 24 |
|
|
(uint32_t) dataBuf.logicalBlockAddr1 << 16 |
|
|
(uint32_t) dataBuf.logicalBlockAddr2 << 8 |
|
|
(uint32_t) dataBuf.logicalBlockAddr3;
|
|
blockLen = (uint32_t) dataBuf.bytesPerBlock0 << 24 |
|
|
(uint32_t) dataBuf.bytesPerBlock1 << 16 |
|
|
(uint32_t) dataBuf.bytesPerBlock2 << 8 |
|
|
(uint32_t) dataBuf.bytesPerBlock3;
|
|
|
|
*pLastBlock = lba;
|
|
*pBlockSize = blockLen;
|
|
|
|
return kDIErrNone;
|
|
}
|
|
|
|
|
|
/*
|
|
* Read one or more blocks from the specified SCSI device.
|
|
*
|
|
* "buf" must be able to hold (numBlocks * blockSize) bytes.
|
|
*/
|
|
/*static*/ DIError SPTI::ReadBlocks(HANDLE handle, long startBlock,
|
|
short numBlocks, long blockSize, void* buf)
|
|
{
|
|
SCSI_PASS_THROUGH_DIRECT sptd;
|
|
DWORD cb;
|
|
BOOL status;
|
|
|
|
assert(startBlock >= 0);
|
|
assert(numBlocks > 0);
|
|
assert(buf != NULL);
|
|
|
|
LOGD(" SPTI phys read block (%ld) %d", startBlock, numBlocks);
|
|
|
|
memset(&sptd, 0, sizeof(sptd));
|
|
sptd.Length = sizeof(sptd); // size of struct (+ request-sense buffer)
|
|
sptd.ScsiStatus = 0;
|
|
sptd.PathId = 0; // SCSI card ID filled in by ioctl
|
|
sptd.TargetId = 0; // SCSI target ID filled in by ioctl
|
|
sptd.Lun = 0; // SCSI lun ID filled in by ioctl
|
|
sptd.CdbLength = 10; // CDB size is 10 for READ CAPACITY
|
|
sptd.SenseInfoLength = 0; // don't return any sense data
|
|
sptd.DataIn = SCSI_IOCTL_DATA_IN; // will be data from drive
|
|
sptd.DataTransferLength = blockSize * numBlocks;
|
|
sptd.TimeOutValue = 10; // SCSI timeout value (in seconds)
|
|
sptd.DataBuffer = (PVOID) buf;
|
|
sptd.SenseInfoOffset = 0; // offset from start of struct to request-sense
|
|
|
|
CDB10* pCdb = (CDB10*) &sptd.Cdb;
|
|
pCdb->operationCode = kScsiOpRead;
|
|
pCdb->logicalBlockAddr0 = (uint8_t) (startBlock >> 24); // MSB
|
|
pCdb->logicalBlockAddr1 = (uint8_t) (startBlock >> 16);
|
|
pCdb->logicalBlockAddr2 = (uint8_t) (startBlock >> 8);
|
|
pCdb->logicalBlockAddr3 = (uint8_t) startBlock; // LSB
|
|
pCdb->transferLength0 = (uint8_t) (numBlocks >> 8); // MSB
|
|
pCdb->transferLength1 = (uint8_t) numBlocks; // LSB
|
|
|
|
status = ::DeviceIoControl(handle, IOCTL_SCSI_PASS_THROUGH_DIRECT,
|
|
&sptd, sizeof(sptd), NULL, 0, &cb, NULL);
|
|
|
|
if (!status) {
|
|
LOGE("DeviceIoControl(SCSI READ(10)) failed, err=%ld",
|
|
::GetLastError());
|
|
return kDIErrReadFailed; // close enough
|
|
}
|
|
if (sptd.ScsiStatus != 0) {
|
|
LOGE("SCSI READ(10) failed, status=%d", sptd.ScsiStatus);
|
|
return kDIErrReadFailed;
|
|
}
|
|
|
|
return kDIErrNone;
|
|
}
|
|
|
|
#endif /*_WIN32*/
|