Merged FileSupport into Disk, improved granularity, more unit tests, code cleanup (#897)

* Merged FileSupport into Disk

* Improved code granularity

* Made classes previously directly writing to cout testable

* Added numerous unit tests

* Fixed minor issues uncovered by unit tests
 
* Fixed SonarCloud issues

* Replaced remaining proprietary data types (WORD/DWORD) except for files in hal/
This commit is contained in:
Uwe Seimet 2022-10-08 19:26:04 +02:00 committed by GitHub
parent 62e287c96d
commit ca23d9b7a3
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
106 changed files with 2951 additions and 1631 deletions

View File

@ -85,14 +85,16 @@ SRC_PROTOC = \
SRC_PROTOBUF = \
rascsi_interface.pb.cpp
SRC_RASCSI_CORE = \
scsi.cpp \
filepath.cpp \
fileio.cpp \
SRC_SHARED = \
rascsi_version.cpp \
rasutil.cpp \
command_util.cpp \
protobuf_util.cpp \
protobuf_serializer.cpp
SRC_RASCSI_CORE = \
bus.cpp \
filepath.cpp \
fileio.cpp
SRC_RASCSI_CORE += $(shell find ./rascsi -name '*.cpp')
SRC_RASCSI_CORE += $(shell find ./controllers -name '*.cpp')
SRC_RASCSI_CORE += $(shell find ./devices -name '*.cpp')
@ -102,22 +104,18 @@ SRC_RASCSI = rascsi.cpp
SRC_SCSIMON = \
scsimon.cpp \
scsi.cpp \
bus.cpp \
rascsi_version.cpp
SRC_SCSIMON += $(shell find ./monitor -name '*.cpp')
SRC_SCSIMON += $(shell find ./hal -name '*.cpp')
SRC_RASCTL = \
rasctl.cpp\
rascsi_version.cpp \
rasutil.cpp \
command_util.cpp \
protobuf_serializer.cpp
SRC_RASCTL += $(shell find ./rasctl -name '*.cpp')
SRC_RASCTL_CORE = $(shell find ./rasctl -name '*.cpp')
SRC_RASCTL = rasctl.cpp
SRC_RASDUMP = \
rasdump.cpp \
scsi.cpp \
bus.cpp \
filepath.cpp \
fileio.cpp \
rascsi_version.cpp
@ -134,10 +132,12 @@ vpath ./$(BINDIR)
OBJ_RASCSI_CORE := $(addprefix $(OBJDIR)/,$(notdir $(SRC_RASCSI_CORE:%.cpp=%.o)))
OBJ_RASCSI := $(addprefix $(OBJDIR)/,$(notdir $(SRC_RASCSI:%.cpp=%.o)))
OBJ_RASCTL_CORE := $(addprefix $(OBJDIR)/,$(notdir $(SRC_RASCTL_CORE:%.cpp=%.o)))
OBJ_RASCTL := $(addprefix $(OBJDIR)/,$(notdir $(SRC_RASCTL:%.cpp=%.o)))
OBJ_RASDUMP := $(addprefix $(OBJDIR)/,$(notdir $(SRC_RASDUMP:%.cpp=%.o)))
OBJ_SCSIMON := $(addprefix $(OBJDIR)/,$(notdir $(SRC_SCSIMON:%.cpp=%.o)))
OBJ_RASCSI_TEST := $(addprefix $(OBJDIR)/,$(notdir $(SRC_RASCSI_TEST:%.cpp=%.o)))
OBJ_SHARED := $(addprefix $(OBJDIR)/,$(notdir $(SRC_SHARED:%.cpp=%.o)))
OBJ_PROTOBUF := $(addprefix $(OBJDIR)/,$(notdir $(SRC_PROTOBUF:%.cpp=%.o)))
GEN_PROTOBUF := $(SRC_PROTOBUF) rascsi_interface.pb.h
@ -145,7 +145,7 @@ GEN_PROTOBUF := $(SRC_PROTOBUF) rascsi_interface.pb.h
# The following will include all of the auto-generated dependency files (*.d)
# if they exist. This will trigger a rebuild of a source file if a header changes
ALL_DEPS := $(patsubst %.o,%.d,$(OBJ_RASCSI_CORE) $(OBJ_RASCSI) $(OBJ_RASCTL) $(OBJ_SCSIMON) $(OBJ_RASCSI_TEST))
ALL_DEPS := $(patsubst %.o,%.d,$(OBJ_RASCSI_CORE) $(OBJ_RASCTL_CORE) $(OBJ_RASCSI) $(OBJ_RASCTL) $(OBJ_SCSIMON) $(OBJ_RASCSI_TEST))
-include $(ALL_DEPS)
$(OBJDIR) $(BINDIR):
@ -186,13 +186,13 @@ lcov: test
docs: $(DOC_DIR)/rascsi_man_page.txt $(DOC_DIR)/rasctl_man_page.txt $(DOC_DIR)/scsimon_man_page.txt
$(SRC_RASCSI_CORE): $(SRC_PROTOBUF)
$(SRC_SHARED): $(SRC_PROTOBUF)
$(BINDIR)/$(RASCSI): $(SRC_PROTOBUF) $(OBJ_RASCSI_CORE) $(OBJ_RASCSI) $(OBJ_PROTOBUF) | $(BINDIR)
$(CXX) $(CXXFLAGS) -o $@ $(OBJ_RASCSI_CORE) $(OBJ_RASCSI) $(OBJ_PROTOBUF) -lpthread -lpcap -lprotobuf -lstdc++fs
$(BINDIR)/$(RASCSI): $(SRC_PROTOBUF) $(OBJ_RASCSI_CORE) $(OBJ_RASCSI) $(OBJ_SHARED) $(OBJ_PROTOBUF) | $(BINDIR)
$(CXX) $(CXXFLAGS) -o $@ $(OBJ_RASCSI_CORE) $(OBJ_RASCSI) $(OBJ_SHARED) $(OBJ_PROTOBUF) -lpthread -lpcap -lprotobuf -lstdc++fs
$(BINDIR)/$(RASCTL): $(SRC_PROTOBUF) $(OBJ_RASCTL) $(OBJ_PROTOBUF) | $(BINDIR)
$(CXX) $(CXXFLAGS) -o $@ $(OBJ_RASCTL) $(OBJ_PROTOBUF) -lpthread -lprotobuf
$(BINDIR)/$(RASCTL): $(SRC_PROTOBUF) $(OBJ_RASCTL_CORE) $(OBJ_RASCTL) $(OBJ_SHARED) $(OBJ_PROTOBUF) | $(BINDIR)
$(CXX) $(CXXFLAGS) -o $@ $(OBJ_RASCTL_CORE) $(OBJ_RASCTL) $(OBJ_SHARED) $(OBJ_PROTOBUF) -lpthread -lprotobuf
$(BINDIR)/$(RASDUMP): $(OBJ_RASDUMP) | $(BINDIR)
$(CXX) $(CXXFLAGS) -o $@ $(OBJ_RASDUMP)
@ -200,8 +200,8 @@ $(BINDIR)/$(RASDUMP): $(OBJ_RASDUMP) | $(BINDIR)
$(BINDIR)/$(SCSIMON): $(OBJ_SCSIMON) | $(BINDIR)
$(CXX) $(CXXFLAGS) -o $@ $(OBJ_SCSIMON) -lpthread
$(BINDIR)/$(RASCSI_TEST): $(SRC_PROTOBUF) $(OBJ_RASCSI_CORE) $(OBJ_RASCSI_TEST) $(OBJ_PROTOBUF) | $(BINDIR)
$(CXX) $(CXXFLAGS) -o $@ $(OBJ_RASCSI_CORE) $(OBJ_RASCSI_TEST) $(OBJ_PROTOBUF) -lpthread -lpcap -lprotobuf -lstdc++fs -lgmock -lgtest
$(BINDIR)/$(RASCSI_TEST): $(SRC_PROTOBUF) $(OBJ_RASCSI_CORE) $(OBJ_RASCTL_CORE) $(OBJ_RASCSI_TEST) $(OBJ_RASCTL_TEST) $(OBJ_SHARED) $(OBJ_PROTOBUF) | $(BINDIR)
$(CXX) $(CXXFLAGS) -o $@ $(OBJ_RASCSI_CORE) $(OBJ_RASCTL_CORE) $(OBJ_RASCSI_TEST) $(OBJ_SHARED) $(OBJ_PROTOBUF) -lpthread -lpcap -lprotobuf -lstdc++fs -lgmock -lgtest
# Phony rules for building individual utilities

View File

@ -1,11 +1,10 @@
//---------------------------------------------------------------------------
//
// X68000 EMULATOR "XM6"
// X68000 EMULATOR "XM6"
//
// Copyright (C) 2001-2006 (ytanaka@ipc-tokai.or.jp)
// Copyright (C) 2014-2020 GIMONS
//
// [ SCSI Common Functionality ]
// Copyright (C) 2001-2006 (ytanaka@ipc-tokai.or.jp)
// Copyright (C) 2014-2020 GIMONS
// Copyright (C) 2022 Uwe Seimet
//
//---------------------------------------------------------------------------
@ -31,9 +30,9 @@ BUS::phase_t BUS::GetPhase()
}
// Get target phase from bus signal line
int mci = GetMSG() ? 0x04 : 0x00;
mci |= GetCD() ? 0x02 : 0x00;
mci |= GetIO() ? 0x01 : 0x00;
int mci = GetMSG() ? 0b100 : 0b000;
mci |= GetCD() ? 0b010 : 0b000;
mci |= GetIO() ? 0b001 : 0b000;
return GetPhase(mci);
}

View File

@ -59,7 +59,7 @@ public:
static const char* GetPhaseStrRaw(phase_t current_phase);
// Extract as specific pin field from a raw data capture
static inline DWORD GetPinRaw(DWORD raw_data, DWORD pin_num)
static inline uint32_t GetPinRaw(uint32_t raw_data, uint32_t pin_num)
{
return ((raw_data >> pin_num) & 1);
}

View File

@ -88,7 +88,7 @@ void AbstractController::ProcessPhase()
default:
LOGERROR("Cannot process phase %s", BUS::GetPhaseStrRaw(GetPhase()))
throw scsi_error_exception();
throw scsi_exception();
break;
}
}

View File

@ -11,6 +11,7 @@
#pragma once
#include "scsi.h"
#include "bus.h"
#include "phase_handler.h"
#include <unordered_set>

View File

@ -9,7 +9,6 @@
#include "devices/device_factory.h"
#include "devices/primary_device.h"
#include "devices/file_support.h"
#include "scsi_controller.h"
#include "controller_manager.h"
@ -20,15 +19,21 @@ bool ControllerManager::AttachToScsiController(int id, shared_ptr<PrimaryDevice>
auto controller = FindController(id);
if (controller == nullptr) {
controller = make_shared<ScsiController>(bus, id);
controllers[id] = controller;
if (controller->AddDevice(device)) {
controllers[id] = controller;
return true;
}
return false;
}
return controller->AddDevice(device);
}
void ControllerManager::DeleteController(shared_ptr<AbstractController> controller)
bool ControllerManager::DeleteController(shared_ptr<AbstractController> controller)
{
controllers.erase(controller->GetTargetId());
return controllers.erase(controller->GetTargetId()) == 1;
}
shared_ptr<AbstractController> ControllerManager::IdentifyController(int data) const
@ -53,7 +58,7 @@ unordered_set<shared_ptr<PrimaryDevice>> ControllerManager::GetAllDevices() cons
unordered_set<shared_ptr<PrimaryDevice>> devices;
for (const auto& [id, controller] : controllers) {
auto d = controller->GetDevices();
const auto& d = controller->GetDevices();
devices.insert(d.begin(), d.end());
}

View File

@ -36,7 +36,7 @@ public:
static const int DEVICE_MAX = 8;
bool AttachToScsiController(int, shared_ptr<PrimaryDevice>);
void DeleteController(shared_ptr<AbstractController>);
bool DeleteController(shared_ptr<AbstractController>);
shared_ptr<AbstractController> IdentifyController(int) const;
shared_ptr<AbstractController> FindController(int) const;
unordered_set<shared_ptr<PrimaryDevice>> GetAllDevices() const;

View File

@ -79,7 +79,7 @@ BUS::phase_t ScsiController::Process(int id)
try {
ProcessPhase();
}
catch(const scsi_error_exception&) {
catch(const scsi_exception&) {
// Any exception should have been handled during the phase processing
assert(false);
@ -198,8 +198,8 @@ void ScsiController::Command()
bus.SetCD(true);
bus.SetIO(false);
int actual_count = bus.CommandHandShake(GetBuffer().data());
int command_byte_count = GPIOBUS::GetCommandByteCount(GetBuffer()[0]);
const int actual_count = bus.CommandHandShake(GetBuffer().data());
const int command_byte_count = GPIOBUS::GetCommandByteCount(GetBuffer()[0]);
// If not able to receive all, move to the status phase
if (actual_count != command_byte_count) {
@ -267,10 +267,10 @@ void ScsiController::Execute()
if (!device->Dispatch(GetOpcode())) {
LOGTRACE("ID %d LUN %d received unsupported command: $%02X", GetTargetId(), lun, (int)GetOpcode())
throw scsi_error_exception(sense_key::ILLEGAL_REQUEST, asc::INVALID_COMMAND_OPERATION_CODE);
throw scsi_exception(sense_key::ILLEGAL_REQUEST, asc::INVALID_COMMAND_OPERATION_CODE);
}
}
catch(const scsi_error_exception& e) { //NOSONAR This exception is handled properly
catch(const scsi_exception& e) { //NOSONAR This exception is handled properly
Error(e.get_sense_key(), e.get_asc(), e.get_status());
// Fall through
@ -459,10 +459,9 @@ void ScsiController::Error(sense_key sense_key, asc asc, status status)
}
if (sense_key != sense_key::NO_SENSE || asc != asc::NO_ADDITIONAL_SENSE_INFORMATION) {
LOGDEBUG("Error status: Sense Key $%02X, ASC $%02X, ASCQ $%02X",
(int)sense_key << 16, (int)asc << 8, (int)asc & 0xff)
LOGDEBUG("Error status: Sense Key $%02X, ASC $%02X", (int)sense_key, (int)asc)
// Set Sense Key and ASC for a subsequent REQUEST SENSE
// Set Sense Key and ASC for a subsequent REQUEST SENSE
GetDeviceForLun(lun)->SetStatusCode(((int)sense_key << 16) | ((int)asc << 8));
}
@ -485,7 +484,7 @@ void ScsiController::Send()
// TODO The delay has to be taken from ctrl.unit[lun], but as there are currently no Daynaport drivers for
// LUNs other than 0 this work-around works.
if (int len = bus.SendHandShake(GetBuffer().data() + ctrl.offset, ctrl.length,
if (const int len = bus.SendHandShake(GetBuffer().data() + ctrl.offset, ctrl.length,
HasDeviceForLun(0) ? GetDeviceForLun(0)->GetSendDelay() : 0);
len != (int)ctrl.length) {
// If you cannot send all, move to status phase
@ -798,7 +797,7 @@ void ScsiController::FlushUnit()
try {
disk->ModeSelect(ctrl.cmd, GetBuffer(), GetOffset());
}
catch(const scsi_error_exception& e) {
catch(const scsi_exception& e) {
LOGWARN("Error occured while processing Mode Select command %02X\n", (int)GetOpcode())
Error(e.get_sense_key(), e.get_asc(), e.get_status());
return;
@ -841,7 +840,7 @@ bool ScsiController::XferIn(vector<BYTE>& buf)
try {
ctrl.length = (dynamic_pointer_cast<Disk>(GetDeviceForLun(lun)))->Read(ctrl.cmd, buf, ctrl.next);
}
catch(const scsi_error_exception&) {
catch(const scsi_exception&) {
// If there is an error, go to the status phase
return false;
}
@ -881,7 +880,7 @@ bool ScsiController::XferOutBlockOriented(bool cont)
try {
disk->ModeSelect(ctrl.cmd, GetBuffer(), GetOffset());
}
catch(const scsi_error_exception& e) {
catch(const scsi_exception& e) {
Error(e.get_sense_key(), e.get_asc(), e.get_status());
return false;
}
@ -919,7 +918,7 @@ bool ScsiController::XferOutBlockOriented(bool cont)
try {
disk->Write(ctrl.cmd, GetBuffer(), ctrl.next - 1);
}
catch(const scsi_error_exception& e) {
catch(const scsi_exception& e) {
Error(e.get_sense_key(), e.get_asc(), e.get_status());
// Write failed
@ -936,7 +935,7 @@ bool ScsiController::XferOutBlockOriented(bool cont)
try {
ctrl.length = disk->WriteCheck(ctrl.next - 1);
}
catch(const scsi_error_exception&) {
catch(const scsi_exception&) {
// Cannot write
return false;
}
@ -976,7 +975,7 @@ void ScsiController::ParseMessage()
{
int i = 0;
while (i < scsi.msc) {
BYTE message_type = scsi.msb[i];
const BYTE message_type = scsi.msb[i];
if (message_type == 0x06) {
LOGTRACE("Received ABORT message")
@ -1064,7 +1063,7 @@ int ScsiController::GetEffectiveLun() const
void ScsiController::Sleep()
{
if (uint32_t time = SysTimer::GetTimerLow() - execstart; time < MIN_EXEC_TIME) {
if (const uint32_t time = SysTimer::GetTimerLow() - execstart; time < MIN_EXEC_TIME) {
SysTimer::SleepUsec(MIN_EXEC_TIME - time);
}
execstart = 0;

View File

@ -7,12 +7,13 @@
// Copyright (C) 2014-2020 GIMONS
// Copyright (C) akuker
//
// Licensed under the BSD 3-Clause License.
// Licensed under the BSD 3-Clause License.
// See LICENSE file in the project root folder.
//
//---------------------------------------------------------------------------
#include "cd_track.h"
#include <cassert>
void CDTrack::Init(int track, uint32_t first, uint32_t last)
{

View File

@ -23,7 +23,7 @@ public:
CDTrack() = default;
~CDTrack() = default;
void Init(int track, DWORD first, DWORD last);
void Init(int track, uint32_t first, uint32_t last);
// Properties
void SetPath(bool cdda, const Filepath& path); // Set the path
@ -32,7 +32,7 @@ public:
uint32_t GetLast() const; // Get the last LBA
uint32_t GetBlocks() const; // Get the number of blocks
int GetTrackNo() const; // Get the track number
bool IsValid(DWORD lba) const; // Is this a valid LBA?
bool IsValid(uint32_t lba) const; // Is this a valid LBA?
bool IsAudio() const; // Is this an audio track?
private:

View File

@ -48,7 +48,7 @@ static void convert(char const *src, char const *dest,
return;
}
if (size_t ret = iconv(cd, &inbuf, &in, &outbuf, &out); ret == (size_t)-1) {
if (const size_t ret = iconv(cd, &inbuf, &in, &outbuf, &out); ret == (size_t)-1) {
return;
}
@ -166,7 +166,7 @@ void Human68k::namests_t::GetCopyFilename(BYTE* szFilename) const
if (i >= 8) {
// Transfer the extraneous part
for (i = 0; i < 10; i++) {
BYTE c = add[i];
const BYTE c = add[i];
if (c == '\0')
break;
*p++ = c;
@ -178,7 +178,7 @@ void Human68k::namests_t::GetCopyFilename(BYTE* szFilename) const
if (ext[0] != ' ' || ext[1] != ' ' || ext[2] != ' ') {
*p++ = '.';
for (i = 0; i < 3; i++) {
BYTE c = ext[i];
const BYTE c = ext[i];
if (c == ' ') {
// Check that the file extension continues after a space is detected
/// TODO: Should change this function to be compatible with 8+3 chars and TwentyOne
@ -226,7 +226,7 @@ CHostDrv::~CHostDrv()
// Initialization (device boot and load)
//
//---------------------------------------------------------------------------
void CHostDrv::Init(const TCHAR* szBase, DWORD nFlag)
void CHostDrv::Init(const TCHAR* szBase, uint32_t nFlag)
{
assert(szBase);
assert(strlen(szBase) < FILEPATH_MAX);
@ -253,7 +253,7 @@ void CHostDrv::Init(const TCHAR* szBase, DWORD nFlag)
TCHAR* pClear = nullptr;
TCHAR* p = m_szBase;
for (;;) {
TCHAR c = *p;
const TCHAR c = *p;
if (c == '\0')
break;
if (c == '/' || c == '\\') {
@ -301,7 +301,7 @@ BYTE CHostDrv::GetMediaByte() const
// Get drive status
//
//---------------------------------------------------------------------------
DWORD CHostDrv::GetStatus() const
uint32_t CHostDrv::GetStatus() const
{
return 0x40 | (m_bEnable ? (m_bWriteProtect ? 0x08 : 0) | 0x02 : 0);
}
@ -408,15 +408,15 @@ bool CHostDrv::GetVolumeCache(TCHAR* szLabel) const
return m_bVolumeCache;
}
DWORD CHostDrv::GetCapacity(Human68k::capacity_t* pCapacity)
uint32_t CHostDrv::GetCapacity(Human68k::capacity_t* pCapacity)
{
assert(pCapacity);
assert(m_bEnable);
DWORD nFree = 0x7FFF8000;
DWORD freearea;
DWORD clusters;
DWORD sectors;
const uint32_t nFree = 0x7FFF8000;
uint32_t freearea;
uint32_t clusters;
uint32_t sectors;
freearea = 0xFFFF;
clusters = 0xFFFF;
@ -428,9 +428,9 @@ DWORD CHostDrv::GetCapacity(Human68k::capacity_t* pCapacity)
assert(sectors <= 64);
// Update cache
m_capCache.freearea = (WORD)freearea;
m_capCache.clusters = (WORD)clusters;
m_capCache.sectors = (WORD)sectors;
m_capCache.freearea = (uint16_t)freearea;
m_capCache.clusters = (uint16_t)clusters;
m_capCache.sectors = (uint16_t)sectors;
m_capCache.bytes = 512;
// Transfer contents
@ -808,7 +808,7 @@ void CHostFilename::ConvertHuman(int nCount)
}
size_t nMax = 18; // Number of bytes for the base segment (base name and extension)
DWORD nOption = CFileSys::GetFileOption();
uint32_t nOption = CFileSys::GetFileOption();
if (nOption & WINDRV_OPT_CONVERT_LENGTH)
nMax = 8;
@ -817,7 +817,7 @@ void CHostFilename::ConvertHuman(int nCount)
BYTE* pNumber = nullptr;
if (nCount >= 0) {
pNumber = &szNumber[8];
for (DWORD i = 0; i < 5; i++) { // Max 5+1 digits (always leave the first 2 bytes of the base name)
for (uint32_t i = 0; i < 5; i++) { // Max 5+1 digits (always leave the first 2 bytes of the base name)
int n = nCount % 36;
nMax--;
pNumber--;
@ -1082,7 +1082,7 @@ bool CHostFilename::isReduce() const
/// Evaluate Human68k directory entry attribute
//
//---------------------------------------------------------------------------
int CHostFilename::CheckAttribute(DWORD nHumanAttribute) const
int CHostFilename::CheckAttribute(uint32_t nHumanAttribute) const
{
BYTE nAttribute = m_dirHuman.attr;
if ((nAttribute & (Human68k::AT_ARCHIVE | Human68k::AT_DIRECTORY | Human68k::AT_VOLUME)) == 0)
@ -1099,7 +1099,7 @@ int CHostFilename::CheckAttribute(DWORD nHumanAttribute) const
const BYTE* CHostFilename::SeparateExt(const BYTE* szHuman) // static
{
// Obtain the file name length
size_t nLength = strlen((const char*)szHuman);
const size_t nLength = strlen((const char*)szHuman);
const BYTE* pFirst = szHuman;
const BYTE* pLast = pFirst + nLength;
@ -1124,7 +1124,7 @@ const BYTE* CHostFilename::SeparateExt(const BYTE* szHuman) // static
//
//===========================================================================
DWORD CHostPath::g_nId; ///< Identifier creation counter
uint32_t CHostPath::g_nId; ///< Identifier creation counter
CHostPath::~CHostPath()
{
@ -1144,7 +1144,7 @@ CHostPath::ring_t* CHostPath::Alloc(size_t nLength) // static
{
assert(nLength < FILEPATH_MAX);
size_t n = offsetof(ring_t, f) + CHostFilename::Offset() + (nLength + 1) * sizeof(TCHAR);
const size_t n = offsetof(ring_t, f) + CHostFilename::Offset() + (nLength + 1) * sizeof(TCHAR);
auto p = (ring_t*)malloc(n);
assert(p);
@ -1295,8 +1295,8 @@ bool CHostPath::isSameHuman(const BYTE* szHuman) const
assert(szHuman);
// Calulate number of chars
size_t nLength = strlen((const char*)m_szHuman);
size_t n = strlen((const char*)szHuman);
const size_t nLength = strlen((const char*)m_szHuman);
const size_t n = strlen((const char*)szHuman);
// Check number of chars
if (nLength != n)
@ -1331,7 +1331,7 @@ bool CHostPath::isSameChild(const BYTE* szHuman) const
/// Make sure to lock from the top.
//
//---------------------------------------------------------------------------
const CHostFilename* CHostPath::FindFilename(const BYTE* szHuman, DWORD nHumanAttribute) const
const CHostFilename* CHostPath::FindFilename(const BYTE* szHuman, uint32_t nHumanAttribute) const
{
assert(szHuman);
@ -1368,7 +1368,7 @@ const CHostFilename* CHostPath::FindFilename(const BYTE* szHuman, DWORD nHumanAt
/// Make sure to lock from the top.
//
//---------------------------------------------------------------------------
const CHostFilename* CHostPath::FindFilenameWildcard(const BYTE* szHuman, DWORD nHumanAttribute, find_t* pFind) const
const CHostFilename* CHostPath::FindFilenameWildcard(const BYTE* szHuman, uint32_t nHumanAttribute, find_t* pFind) const
{
assert(szHuman);
assert(pFind);
@ -1386,7 +1386,7 @@ const CHostFilename* CHostPath::FindFilenameWildcard(const BYTE* szHuman, DWORD
p = pFind->pos;
} else {
// Find the start position in the directory entry contents
DWORD n = 0;
uint32_t n = 0;
for (;; p = (const ring_t*)p->r.Next()) {
if (p == (const ring_t*)&m_cRing) {
// Extrapolate from the count when the same entry isn't found (just in case)
@ -1547,7 +1547,7 @@ void CHostPath::Refresh()
// - No duplicated names in previous entries
// - No entity with the same name exists
if (pFilename->isReduce() || !pFilename->isCorrect()) { // Confirm that file name update is required
for (DWORD n = 0; n < XM6_HOST_FILENAME_PATTERN_MAX; n++) {
for (uint32_t n = 0; n < XM6_HOST_FILENAME_PATTERN_MAX; n++) {
// Confirm file name validity
if (pFilename->isCorrect()) {
// Confirm match with previous entry
@ -1583,14 +1583,14 @@ void CHostPath::Refresh()
nHumanAttribute |= Human68k::AT_READONLY;
pFilename->SetEntryAttribute(nHumanAttribute);
auto nHumanSize = (DWORD)sb.st_size;
auto nHumanSize = (uint32_t)sb.st_size;
pFilename->SetEntrySize(nHumanSize);
WORD nHumanDate = 0;
WORD nHumanTime = 0;
uint16_t nHumanDate = 0;
uint16_t nHumanTime = 0;
if (tm pt = {}; localtime_r(&sb.st_mtime, &pt) != nullptr) {
nHumanDate = (WORD)(((pt.tm_year - 80) << 9) | ((pt.tm_mon + 1) << 5) | pt.tm_mday);
nHumanTime = (WORD)((pt.tm_hour << 11) | (pt.tm_min << 5) | (pt.tm_sec >> 1));
nHumanDate = (uint16_t)(((pt.tm_year - 80) << 9) | ((pt.tm_mon + 1) << 5) | pt.tm_mday);
nHumanTime = (uint16_t)((pt.tm_hour << 11) | (pt.tm_min << 5) | (pt.tm_sec >> 1));
}
pFilename->SetEntryDate(nHumanDate);
pFilename->SetEntryTime(nHumanTime);
@ -1760,7 +1760,7 @@ void CHostEntry::CleanCache() const
/// Update the cache for the specified unit
//
//---------------------------------------------------------------------------
void CHostEntry::CleanCache(DWORD nUnit) const
void CHostEntry::CleanCache(uint32_t nUnit) const
{
assert(nUnit < DRIVE_MAX);
assert(m_pDrv[nUnit]);
@ -1773,7 +1773,7 @@ void CHostEntry::CleanCache(DWORD nUnit) const
/// Update the cache for the specified path
//
//---------------------------------------------------------------------------
void CHostEntry::CleanCache(DWORD nUnit, const BYTE* szHumanPath) const
void CHostEntry::CleanCache(uint32_t nUnit, const BYTE* szHumanPath) const
{
assert(szHumanPath);
assert(nUnit < DRIVE_MAX);
@ -1787,7 +1787,7 @@ void CHostEntry::CleanCache(DWORD nUnit, const BYTE* szHumanPath) const
/// Update all cache for the specified path and below
//
//---------------------------------------------------------------------------
void CHostEntry::CleanCacheChild(DWORD nUnit, const BYTE* szHumanPath) const
void CHostEntry::CleanCacheChild(uint32_t nUnit, const BYTE* szHumanPath) const
{
assert(szHumanPath);
assert(nUnit < DRIVE_MAX);
@ -1801,7 +1801,7 @@ void CHostEntry::CleanCacheChild(DWORD nUnit, const BYTE* szHumanPath) const
/// Delete cache for the specified path
//
//---------------------------------------------------------------------------
void CHostEntry::DeleteCache(DWORD nUnit, const BYTE* szHumanPath) const
void CHostEntry::DeleteCache(uint32_t nUnit, const BYTE* szHumanPath) const
{
assert(szHumanPath);
assert(nUnit < DRIVE_MAX);
@ -1815,7 +1815,7 @@ void CHostEntry::DeleteCache(DWORD nUnit, const BYTE* szHumanPath) const
/// Find host side names (path name + file name (can be abbreviated) + attribute)
//
//---------------------------------------------------------------------------
bool CHostEntry::Find(DWORD nUnit, CHostFiles* pFiles) const
bool CHostEntry::Find(uint32_t nUnit, CHostFiles* pFiles) const
{
assert(pFiles);
assert(nUnit < DRIVE_MAX);
@ -1829,7 +1829,7 @@ bool CHostEntry::Find(DWORD nUnit, CHostFiles* pFiles) const
/// Drive settings
//
//---------------------------------------------------------------------------
void CHostEntry::SetDrv(DWORD nUnit, CHostDrv* pDrv)
void CHostEntry::SetDrv(uint32_t nUnit, CHostDrv* pDrv)
{
assert(nUnit < DRIVE_MAX);
assert(m_pDrv[nUnit] == nullptr);
@ -1842,7 +1842,7 @@ void CHostEntry::SetDrv(DWORD nUnit, CHostDrv* pDrv)
/// Is it write-protected?
//
//---------------------------------------------------------------------------
bool CHostEntry::isWriteProtect(DWORD nUnit) const
bool CHostEntry::isWriteProtect(uint32_t nUnit) const
{
assert(nUnit < DRIVE_MAX);
assert(m_pDrv[nUnit]);
@ -1855,7 +1855,7 @@ bool CHostEntry::isWriteProtect(DWORD nUnit) const
/// Is it accessible?
//
//---------------------------------------------------------------------------
bool CHostEntry::isEnable(DWORD nUnit) const
bool CHostEntry::isEnable(uint32_t nUnit) const
{
assert(nUnit < DRIVE_MAX);
assert(m_pDrv[nUnit]);
@ -1868,7 +1868,7 @@ bool CHostEntry::isEnable(DWORD nUnit) const
/// Media check
//
//---------------------------------------------------------------------------
bool CHostEntry::isMediaOffline(DWORD nUnit) const
bool CHostEntry::isMediaOffline(uint32_t nUnit) const
{
assert(nUnit < DRIVE_MAX);
assert(m_pDrv[nUnit]);
@ -1881,7 +1881,7 @@ bool CHostEntry::isMediaOffline(DWORD nUnit) const
/// Get media byte
//
//---------------------------------------------------------------------------
BYTE CHostEntry::GetMediaByte(DWORD nUnit) const
BYTE CHostEntry::GetMediaByte(uint32_t nUnit) const
{
assert(nUnit < DRIVE_MAX);
assert(m_pDrv[nUnit]);
@ -1894,7 +1894,7 @@ BYTE CHostEntry::GetMediaByte(DWORD nUnit) const
/// Get drive status
//
//---------------------------------------------------------------------------
DWORD CHostEntry::GetStatus(DWORD nUnit) const
uint32_t CHostEntry::GetStatus(uint32_t nUnit) const
{
assert(nUnit < DRIVE_MAX);
assert(m_pDrv[nUnit]);
@ -1907,7 +1907,7 @@ DWORD CHostEntry::GetStatus(DWORD nUnit) const
/// Media change check
//
//---------------------------------------------------------------------------
bool CHostEntry::CheckMedia(DWORD nUnit) const
bool CHostEntry::CheckMedia(uint32_t nUnit) const
{
assert(nUnit < DRIVE_MAX);
assert(m_pDrv[nUnit]);
@ -1920,7 +1920,7 @@ bool CHostEntry::CheckMedia(DWORD nUnit) const
/// Eject
//
//---------------------------------------------------------------------------
void CHostEntry::Eject(DWORD nUnit) const
void CHostEntry::Eject(uint32_t nUnit) const
{
assert(nUnit < DRIVE_MAX);
assert(m_pDrv[nUnit]);
@ -1933,7 +1933,7 @@ void CHostEntry::Eject(DWORD nUnit) const
/// Get volume label
//
//---------------------------------------------------------------------------
void CHostEntry::GetVolume(DWORD nUnit, TCHAR* szLabel) const
void CHostEntry::GetVolume(uint32_t nUnit, TCHAR* szLabel) const
{
assert(nUnit < DRIVE_MAX);
assert(m_pDrv[nUnit]);
@ -1946,7 +1946,7 @@ void CHostEntry::GetVolume(DWORD nUnit, TCHAR* szLabel) const
/// Get volume label from cache
//
//---------------------------------------------------------------------------
bool CHostEntry::GetVolumeCache(DWORD nUnit, TCHAR* szLabel) const
bool CHostEntry::GetVolumeCache(uint32_t nUnit, TCHAR* szLabel) const
{
assert(nUnit < DRIVE_MAX);
assert(m_pDrv[nUnit]);
@ -1959,7 +1959,7 @@ bool CHostEntry::GetVolumeCache(DWORD nUnit, TCHAR* szLabel) const
/// Get capacity
//
//---------------------------------------------------------------------------
DWORD CHostEntry::GetCapacity(DWORD nUnit, Human68k::capacity_t* pCapacity) const
uint32_t CHostEntry::GetCapacity(uint32_t nUnit, Human68k::capacity_t* pCapacity) const
{
assert(nUnit < DRIVE_MAX);
assert(m_pDrv[nUnit]);
@ -1972,7 +1972,7 @@ DWORD CHostEntry::GetCapacity(DWORD nUnit, Human68k::capacity_t* pCapacity) cons
/// Get cluster size from cache
//
//---------------------------------------------------------------------------
bool CHostEntry::GetCapacityCache(DWORD nUnit, Human68k::capacity_t* pCapacity) const
bool CHostEntry::GetCapacityCache(uint32_t nUnit, Human68k::capacity_t* pCapacity) const
{
assert(nUnit < DRIVE_MAX);
assert(m_pDrv[nUnit]);
@ -2056,7 +2056,7 @@ void CHostFiles::SetPath(const Human68k::namests_t* pNamests)
/// Find file on the Human68k side and create data on the host side
//
//---------------------------------------------------------------------------
bool CHostFiles::Find(DWORD nUnit, const CHostEntry* pEntry)
bool CHostFiles::Find(uint32_t nUnit, const CHostEntry* pEntry)
{
assert(pEntry);
@ -2159,7 +2159,7 @@ void CHostFilesManager::Init()
assert(m_cRing.Prev() == &m_cRing);
// Allocate memory
for (DWORD i = 0; i < XM6_HOST_FILES_MAX; i++) {
for (uint32_t i = 0; i < XM6_HOST_FILES_MAX; i++) {
auto p = new ring_t();
p->r.Insert(&m_cRing);
}
@ -2180,7 +2180,7 @@ void CHostFilesManager::Clean()
}
}
CHostFiles* CHostFilesManager::Alloc(DWORD nKey)
CHostFiles* CHostFilesManager::Alloc(uint32_t nKey)
{
assert(nKey);
@ -2195,7 +2195,7 @@ CHostFiles* CHostFilesManager::Alloc(DWORD nKey)
return &p->f;
}
CHostFiles* CHostFilesManager::Search(DWORD nKey)
CHostFiles* CHostFilesManager::Search(uint32_t nKey)
{
// assert(nKey); // The search key may become 0 due to DPB damage
@ -2235,7 +2235,7 @@ void CHostFilesManager::Free(CHostFiles* pFiles)
/// Set file open mode
//
//---------------------------------------------------------------------------
bool CHostFcb::SetMode(DWORD nHumanMode)
bool CHostFcb::SetMode(uint32_t nHumanMode)
{
switch (nHumanMode & Human68k::OP_MASK) {
case Human68k::OP_READ:
@ -2279,7 +2279,7 @@ void CHostFcb::SetHumanPath(const BYTE* szHumanPath)
/// Return false if error is thrown.
//
//---------------------------------------------------------------------------
bool CHostFcb::Create(DWORD, bool bForce)
bool CHostFcb::Create(uint32_t, bool bForce)
{
assert((Human68k::AT_DIRECTORY | Human68k::AT_VOLUME) == 0);
assert(strlen(m_szFilename) > 0);
@ -2328,7 +2328,7 @@ bool CHostFcb::Open()
/// Return -1 if error is thrown.
//
//---------------------------------------------------------------------------
DWORD CHostFcb::Read(BYTE* pBuffer, DWORD nSize)
uint32_t CHostFcb::Read(BYTE* pBuffer, uint32_t nSize)
{
assert(pBuffer);
assert(m_pFile);
@ -2337,7 +2337,7 @@ DWORD CHostFcb::Read(BYTE* pBuffer, DWORD nSize)
if (ferror(m_pFile))
nResult = (size_t)-1;
return (DWORD)nResult;
return (uint32_t)nResult;
}
//---------------------------------------------------------------------------
@ -2348,7 +2348,7 @@ DWORD CHostFcb::Read(BYTE* pBuffer, DWORD nSize)
/// Return -1 if error is thrown.
//
//---------------------------------------------------------------------------
DWORD CHostFcb::Write(const BYTE* pBuffer, DWORD nSize)
uint32_t CHostFcb::Write(const BYTE* pBuffer, uint32_t nSize)
{
assert(pBuffer);
assert(m_pFile);
@ -2357,7 +2357,7 @@ DWORD CHostFcb::Write(const BYTE* pBuffer, DWORD nSize)
if (ferror(m_pFile))
nResult = (size_t)-1;
return (DWORD)nResult;
return (uint32_t)nResult;
}
//---------------------------------------------------------------------------
@ -2381,7 +2381,7 @@ bool CHostFcb::Truncate() const
/// Return -1 if error is thrown.
//
//---------------------------------------------------------------------------
DWORD CHostFcb::Seek(DWORD nOffset, Human68k::seek_t nHumanSeek)
uint32_t CHostFcb::Seek(uint32_t nOffset, Human68k::seek_t nHumanSeek)
{
assert(m_pFile);
@ -2399,9 +2399,9 @@ DWORD CHostFcb::Seek(DWORD nOffset, Human68k::seek_t nHumanSeek)
break;
}
if (fseek(m_pFile, nOffset, nSeek))
return (DWORD)-1;
return (uint32_t)-1;
return (DWORD)ftell(m_pFile);
return (uint32_t)ftell(m_pFile);
}
//---------------------------------------------------------------------------
@ -2411,7 +2411,7 @@ DWORD CHostFcb::Seek(DWORD nOffset, Human68k::seek_t nHumanSeek)
/// Return false if error is thrown.
//
//---------------------------------------------------------------------------
bool CHostFcb::TimeStamp(DWORD nHumanTime) const
bool CHostFcb::TimeStamp(uint32_t nHumanTime) const
{
assert(m_pFile || m_bFlag);
@ -2480,7 +2480,7 @@ void CHostFcbManager::Init()
assert(m_cRing.Prev() == &m_cRing);
// Memory allocation
for (DWORD i = 0; i < XM6_HOST_FCB_MAX; i++) {
for (uint32_t i = 0; i < XM6_HOST_FCB_MAX; i++) {
auto p = new ring_t;
assert(p);
p->r.Insert(&m_cRing);
@ -2501,7 +2501,7 @@ void CHostFcbManager::Clean() const
}
}
CHostFcb* CHostFcbManager::Alloc(DWORD nKey)
CHostFcb* CHostFcbManager::Alloc(uint32_t nKey)
{
assert(nKey);
@ -2523,7 +2523,7 @@ CHostFcb* CHostFcbManager::Alloc(DWORD nKey)
return &p->f;
}
CHostFcb* CHostFcbManager::Search(DWORD nKey)
CHostFcb* CHostFcbManager::Search(uint32_t nKey)
{
assert(nKey);
@ -2560,7 +2560,7 @@ void CHostFcbManager::Free(CHostFcb* pFcb)
//
//===========================================================================
DWORD CFileSys::g_nOption; // File name conversion flag
uint32_t CFileSys::g_nOption; // File name conversion flag
//---------------------------------------------------------------------------
//
@ -2607,7 +2607,7 @@ void CFileSys::Init()
m_cEntry.Init();
// Evaluate per-path setting validity
DWORD nDrives = m_nDrives;
uint32_t nDrives = m_nDrives;
if (nDrives == 0) {
// Use root directory instead of per-path settings
strcpy(m_szBase[0], "/");
@ -2616,8 +2616,8 @@ void CFileSys::Init()
}
// Register file system
DWORD nUnit = 0;
for (DWORD n = 0; n < nDrives; n++) {
uint32_t nUnit = 0;
for (uint32_t n = 0; n < nDrives; n++) {
// Don't register is base path do not exist
if (m_szBase[n][0] == '\0')
continue;
@ -2642,7 +2642,7 @@ void CFileSys::Init()
/// $40 - Device startup
//
//---------------------------------------------------------------------------
DWORD CFileSys::InitDevice(const Human68k::argument_t* pArgument)
uint32_t CFileSys::InitDevice(const Human68k::argument_t* pArgument)
{
InitOption(pArgument);
@ -2657,7 +2657,7 @@ DWORD CFileSys::InitDevice(const Human68k::argument_t* pArgument)
/// $41 - Directory check
//
//---------------------------------------------------------------------------
int CFileSys::CheckDir(DWORD nUnit, const Human68k::namests_t* pNamests) const
int CFileSys::CheckDir(uint32_t nUnit, const Human68k::namests_t* pNamests) const
{
assert(pNamests);
@ -2684,7 +2684,7 @@ int CFileSys::CheckDir(DWORD nUnit, const Human68k::namests_t* pNamests) const
/// $42 - Create directory
//
//---------------------------------------------------------------------------
int CFileSys::MakeDir(DWORD nUnit, const Human68k::namests_t* pNamests) const
int CFileSys::MakeDir(uint32_t nUnit, const Human68k::namests_t* pNamests) const
{
assert(pNamests);
@ -2726,7 +2726,7 @@ int CFileSys::MakeDir(DWORD nUnit, const Human68k::namests_t* pNamests) const
/// $43 - Delete directory
//
//---------------------------------------------------------------------------
int CFileSys::RemoveDir(DWORD nUnit, const Human68k::namests_t* pNamests) const
int CFileSys::RemoveDir(uint32_t nUnit, const Human68k::namests_t* pNamests) const
{
assert(pNamests);
@ -2776,7 +2776,7 @@ int CFileSys::RemoveDir(DWORD nUnit, const Human68k::namests_t* pNamests) const
/// $44 - Change file name
//
//---------------------------------------------------------------------------
int CFileSys::Rename(DWORD nUnit, const Human68k::namests_t* pNamests, const Human68k::namests_t* pNamestsNew) const
int CFileSys::Rename(uint32_t nUnit, const Human68k::namests_t* pNamests, const Human68k::namests_t* pNamestsNew) const
{
assert(pNamests);
@ -2834,7 +2834,7 @@ int CFileSys::Rename(DWORD nUnit, const Human68k::namests_t* pNamests, const Hum
/// $45 - Delete file
//
//---------------------------------------------------------------------------
int CFileSys::Delete(DWORD nUnit, const Human68k::namests_t* pNamests) const
int CFileSys::Delete(uint32_t nUnit, const Human68k::namests_t* pNamests) const
{
assert(pNamests);
@ -2874,7 +2874,7 @@ int CFileSys::Delete(DWORD nUnit, const Human68k::namests_t* pNamests) const
/// $46 - Get/set file attribute
//
//---------------------------------------------------------------------------
int CFileSys::Attribute(DWORD nUnit, const Human68k::namests_t* pNamests, DWORD nHumanAttribute) const
int CFileSys::Attribute(uint32_t nUnit, const Human68k::namests_t* pNamests, uint32_t nHumanAttribute) const
{
assert(pNamests);
@ -2908,7 +2908,7 @@ int CFileSys::Attribute(DWORD nUnit, const Human68k::namests_t* pNamests, DWORD
return FS_FATAL_WRITEPROTECT;
// Generate attribute
if (DWORD nAttribute = (nHumanAttribute & Human68k::AT_READONLY) | (f.GetAttribute() & ~Human68k::AT_READONLY);
if (uint32_t nAttribute = (nHumanAttribute & Human68k::AT_READONLY) | (f.GetAttribute() & ~Human68k::AT_READONLY);
f.GetAttribute() != nAttribute) {
struct stat sb;
if (stat(S2U(f.GetPath()), &sb))
@ -2939,7 +2939,7 @@ int CFileSys::Attribute(DWORD nUnit, const Human68k::namests_t* pNamests, DWORD
/// $47 - File search
//
//---------------------------------------------------------------------------
int CFileSys::Files(DWORD nUnit, DWORD nKey, const Human68k::namests_t* pNamests, Human68k::files_t* pFiles)
int CFileSys::Files(uint32_t nUnit, uint32_t nKey, const Human68k::namests_t* pNamests, Human68k::files_t* pFiles)
{
assert(pNamests);
assert(nKey);
@ -3025,7 +3025,7 @@ int CFileSys::Files(DWORD nUnit, DWORD nKey, const Human68k::namests_t* pNamests
/// $48 - Search next file
//
//---------------------------------------------------------------------------
int CFileSys::NFiles(DWORD nUnit, DWORD nKey, Human68k::files_t* pFiles)
int CFileSys::NFiles(uint32_t nUnit, uint32_t nKey, Human68k::files_t* pFiles)
{
assert(nKey);
assert(pFiles);
@ -3069,7 +3069,7 @@ int CFileSys::NFiles(DWORD nUnit, DWORD nKey, Human68k::files_t* pFiles)
/// $49 - Create new file
//
//---------------------------------------------------------------------------
int CFileSys::Create(DWORD nUnit, DWORD nKey, const Human68k::namests_t* pNamests, Human68k::fcb_t* pFcb, DWORD nHumanAttribute, bool bForce)
int CFileSys::Create(uint32_t nUnit, uint32_t nKey, const Human68k::namests_t* pNamests, Human68k::fcb_t* pFcb, uint32_t nHumanAttribute, bool bForce)
{
assert(pNamests);
assert(nKey);
@ -3114,7 +3114,7 @@ int CFileSys::Create(DWORD nUnit, DWORD nKey, const Human68k::namests_t* pNamest
pHostFcb->SetHumanPath(f.GetHumanPath());
// Set open mode
pFcb->mode = (WORD)((pFcb->mode & ~Human68k::OP_MASK) | Human68k::OP_FULL);
pFcb->mode = (uint16_t)((pFcb->mode & ~Human68k::OP_MASK) | Human68k::OP_FULL);
if (!pHostFcb->SetMode(pFcb->mode)) {
m_cFcb.Free(pHostFcb);
return FS_ILLEGALMOD;
@ -3137,7 +3137,7 @@ int CFileSys::Create(DWORD nUnit, DWORD nKey, const Human68k::namests_t* pNamest
/// $4A - File open
//
//---------------------------------------------------------------------------
int CFileSys::Open(DWORD nUnit, DWORD nKey, const Human68k::namests_t* pNamests, Human68k::fcb_t* pFcb)
int CFileSys::Open(uint32_t nUnit, uint32_t nKey, const Human68k::namests_t* pNamests, Human68k::fcb_t* pFcb)
{
assert(pNamests);
assert(nKey);
@ -3208,7 +3208,7 @@ int CFileSys::Open(DWORD nUnit, DWORD nKey, const Human68k::namests_t* pNamests,
/// $4B - File close
//
//---------------------------------------------------------------------------
int CFileSys::Close(DWORD nUnit, DWORD nKey, const Human68k::fcb_t* /* pFcb */)
int CFileSys::Close(uint32_t nUnit, uint32_t nKey, const Human68k::fcb_t* /* pFcb */)
{
assert(nKey);
@ -3246,7 +3246,7 @@ int CFileSys::Close(DWORD nUnit, DWORD nKey, const Human68k::fcb_t* /* pFcb */)
/// Clean exit when 0 bytes are read.
//
//---------------------------------------------------------------------------
int CFileSys::Read(DWORD nKey, Human68k::fcb_t* pFcb, BYTE* pBuffer, DWORD nSize)
int CFileSys::Read(uint32_t nKey, Human68k::fcb_t* pFcb, BYTE* pBuffer, uint32_t nSize)
{
assert(nKey);
assert(pFcb);
@ -3265,9 +3265,8 @@ int CFileSys::Read(DWORD nKey, Human68k::fcb_t* pFcb, BYTE* pBuffer, DWORD nSize
}
// Read
DWORD nResult;
nResult = pHostFcb->Read(pBuffer, nSize);
if (nResult == (DWORD)-1) {
const uint32_t nResult = pHostFcb->Read(pBuffer, nSize);
if (nResult == (uint32_t)-1) {
m_cFcb.Free(pHostFcb);
return FS_INVALIDFUNC; // TODO: Should return error code 10 (read error) as well here
}
@ -3286,7 +3285,7 @@ int CFileSys::Read(DWORD nKey, Human68k::fcb_t* pFcb, BYTE* pBuffer, DWORD nSize
/// Truncate file if 0 bytes are written.
//
//---------------------------------------------------------------------------
int CFileSys::Write(DWORD nKey, Human68k::fcb_t* pFcb, const BYTE* pBuffer, DWORD nSize)
int CFileSys::Write(uint32_t nKey, Human68k::fcb_t* pFcb, const BYTE* pBuffer, uint32_t nSize)
{
assert(nKey);
assert(pFcb);
@ -3298,7 +3297,7 @@ int CFileSys::Write(DWORD nKey, Human68k::fcb_t* pFcb, const BYTE* pBuffer, DWOR
if (pHostFcb == nullptr)
return FS_NOTOPENED;
DWORD nResult;
uint32_t nResult;
if (nSize == 0) {
// Truncate
if (!pHostFcb->Truncate()) {
@ -3319,7 +3318,7 @@ int CFileSys::Write(DWORD nKey, Human68k::fcb_t* pFcb, const BYTE* pBuffer, DWOR
// Write
nResult = pHostFcb->Write(pBuffer, nSize);
if (nResult == (DWORD)-1) {
if (nResult == (uint32_t)-1) {
m_cFcb.Free(pHostFcb);
return FS_CANTWRITE; /// TODO: Should return error code 11 (write error) as well here
}
@ -3344,7 +3343,7 @@ int CFileSys::Write(DWORD nKey, Human68k::fcb_t* pFcb, const BYTE* pBuffer, DWOR
/// $4E - File seek
//
//---------------------------------------------------------------------------
int CFileSys::Seek(DWORD nKey, Human68k::fcb_t* pFcb, DWORD nSeek, int nOffset)
int CFileSys::Seek(uint32_t nKey, Human68k::fcb_t* pFcb, uint32_t nSeek, int nOffset)
{
assert(pFcb);
@ -3354,14 +3353,14 @@ int CFileSys::Seek(DWORD nKey, Human68k::fcb_t* pFcb, DWORD nSeek, int nOffset)
return FS_NOTOPENED;
// Parameter check
if (nSeek > (DWORD)Human68k::seek_t::SK_END) {
if (nSeek > (uint32_t)Human68k::seek_t::SK_END) {
m_cFcb.Free(pHostFcb);
return FS_INVALIDPRM;
}
// File seek
DWORD nResult = pHostFcb->Seek(nOffset, (Human68k::seek_t)nSeek);
if (nResult == (DWORD)-1) {
uint32_t nResult = pHostFcb->Seek(nOffset, (Human68k::seek_t)nSeek);
if (nResult == (uint32_t)-1) {
m_cFcb.Free(pHostFcb);
return FS_CANTSEEK;
}
@ -3379,14 +3378,14 @@ int CFileSys::Seek(DWORD nKey, Human68k::fcb_t* pFcb, DWORD nSeek, int nOffset)
/// Throw error when the top 16 bits are $FFFF.
//
//---------------------------------------------------------------------------
DWORD CFileSys::TimeStamp(DWORD nUnit, DWORD nKey, Human68k::fcb_t* pFcb, DWORD nHumanTime)
uint32_t CFileSys::TimeStamp(uint32_t nUnit, uint32_t nKey, Human68k::fcb_t* pFcb, uint32_t nHumanTime)
{
assert(nKey);
assert(pFcb);
// Get only
if (nHumanTime == 0)
return ((DWORD)pFcb->date << 16) | pFcb->time;
return ((uint32_t)pFcb->date << 16) | pFcb->time;
// Unit check
if (nUnit >= CHostEntry::DRIVE_MAX)
@ -3413,8 +3412,8 @@ DWORD CFileSys::TimeStamp(DWORD nUnit, DWORD nKey, Human68k::fcb_t* pFcb, DWORD
m_cFcb.Free(pHostFcb);
return FS_INVALIDPRM;
}
pFcb->date = (WORD)(nHumanTime >> 16);
pFcb->time = (WORD)nHumanTime;
pFcb->date = (uint16_t)(nHumanTime >> 16);
pFcb->time = (uint16_t)nHumanTime;
// Update cache
m_cEntry.CleanCache(nUnit, pHostFcb->GetHumanPath());
@ -3427,7 +3426,7 @@ DWORD CFileSys::TimeStamp(DWORD nUnit, DWORD nKey, Human68k::fcb_t* pFcb, DWORD
/// $50 - Get capacity
//
//---------------------------------------------------------------------------
int CFileSys::GetCapacity(DWORD nUnit, Human68k::capacity_t* pCapacity) const
int CFileSys::GetCapacity(uint32_t nUnit, Human68k::capacity_t* pCapacity) const
{
assert(pCapacity);
@ -3451,7 +3450,7 @@ int CFileSys::GetCapacity(DWORD nUnit, Human68k::capacity_t* pCapacity) const
/// $51 - Inspect/control drive status
//
//---------------------------------------------------------------------------
int CFileSys::CtrlDrive(DWORD nUnit, Human68k::ctrldrive_t* pCtrlDrive) const
int CFileSys::CtrlDrive(uint32_t nUnit, Human68k::ctrldrive_t* pCtrlDrive) const
{
assert(pCtrlDrive);
@ -3494,7 +3493,7 @@ int CFileSys::CtrlDrive(DWORD nUnit, Human68k::ctrldrive_t* pCtrlDrive) const
/// Therefore, treat even a unit out of bounds as normal operation.
//
//---------------------------------------------------------------------------
int CFileSys::GetDPB(DWORD nUnit, Human68k::dpb_t* pDpb) const
int CFileSys::GetDPB(uint32_t nUnit, Human68k::dpb_t* pDpb) const
{
assert(pDpb);
@ -3528,8 +3527,8 @@ int CFileSys::GetDPB(DWORD nUnit, Human68k::dpb_t* pDpb) const
}
// Calculate number of shifts
DWORD nSize = 1;
DWORD nShift = 0;
uint32_t nSize = 1;
uint32_t nShift = 0;
for (;;) {
if (nSize >= cap.sectors)
break;
@ -3544,23 +3543,23 @@ int CFileSys::GetDPB(DWORD nUnit, Human68k::dpb_t* pDpb) const
// Cluster 1: FAT
// Cluster 2: Root directory
// Cluster 3: Data memory (pseudo-sector)
DWORD nFat = cap.sectors;
DWORD nRoot = cap.sectors * 2;
DWORD nData = cap.sectors * 3;
const uint32_t nFat = cap.sectors;
const uint32_t nRoot = cap.sectors * 2;
const uint32_t nData = cap.sectors * 3;
// Set DPB
pDpb->sector_size = cap.bytes; // Bytes per sector
pDpb->cluster_size =
(BYTE)(cap.sectors - 1); // Sectors per cluster - 1
pDpb->shift = (BYTE)nShift; // Number of cluster → sector shifts
pDpb->fat_sector = (WORD)nFat; // First FAT sector number
pDpb->fat_sector = (uint16_t)nFat; // First FAT sector number
pDpb->fat_max = 1; // Number of FAT memory spaces
pDpb->fat_size = (BYTE)cap.sectors; // Number of sectors controlled by FAT (excluding copies)
pDpb->file_max =
(WORD)(cap.sectors * cap.bytes / 0x20); // Number of files in the root directory
pDpb->data_sector = (WORD)nData; // First sector number of data memory
(uint16_t)(cap.sectors * cap.bytes / 0x20); // Number of files in the root directory
pDpb->data_sector = (uint16_t)nData; // First sector number of data memory
pDpb->cluster_max = cap.clusters; // Total number of clusters + 1
pDpb->root_sector = (WORD)nRoot; // First sector number of the root directory
pDpb->root_sector = (uint16_t)nRoot; // First sector number of the root directory
pDpb->media = media; // Media byte
return 0;
@ -3574,7 +3573,7 @@ int CFileSys::GetDPB(DWORD nUnit, Human68k::dpb_t* pDpb) const
/// Buffer size is hard coded to $200 byte.
//
//---------------------------------------------------------------------------
int CFileSys::DiskRead(DWORD nUnit, BYTE* pBuffer, DWORD nSector, DWORD nSize)
int CFileSys::DiskRead(uint32_t nUnit, BYTE* pBuffer, uint32_t nSector, uint32_t nSize)
{
assert(pBuffer);
@ -3611,7 +3610,7 @@ int CFileSys::DiskRead(DWORD nUnit, BYTE* pBuffer, DWORD nSector, DWORD nSize)
// Note that in lzdsys the sector number to read is calculated by the following formula:
// (dirent.cluster - 2) * (dpb.cluster_size + 1) + dpb.data_sector
/// @warning little endian only
dir->cluster = (WORD)(m_nHostSectorCount + 2); // Pseudo-sector number
dir->cluster = (uint16_t)(m_nHostSectorCount + 2); // Pseudo-sector number
m_nHostSectorBuffer[m_nHostSectorCount] = nSector; // Entity that points to the pseudo-sector
m_nHostSectorCount++;
m_nHostSectorCount %= XM6_HOST_PSEUDO_CLUSTER_MAX;
@ -3620,8 +3619,8 @@ int CFileSys::DiskRead(DWORD nUnit, BYTE* pBuffer, DWORD nSector, DWORD nSize)
}
// Calculate the sector number from the cluster number
DWORD n = nSector - (3 * cap.sectors);
DWORD nMod = 1;
uint32_t n = nSector - (3 * cap.sectors);
uint32_t nMod = 1;
if (cap.sectors) {
// Beware that cap.sectors becomes 0 when media does not exist
nMod = n % cap.sectors;
@ -3639,9 +3638,9 @@ int CFileSys::DiskRead(DWORD nUnit, BYTE* pBuffer, DWORD nSector, DWORD nSize)
if (!f.Open())
return FS_INVALIDPRM;
memset(pBuffer, 0, 0x200);
DWORD nResult = f.Read(pBuffer, 0x200);
uint32_t nResult = f.Read(pBuffer, 0x200);
f.Close();
if (nResult == (DWORD)-1)
if (nResult == (uint32_t)-1)
return FS_INVALIDPRM;
return 0;
@ -3656,7 +3655,7 @@ int CFileSys::DiskRead(DWORD nUnit, BYTE* pBuffer, DWORD nSector, DWORD nSize)
/// $54 - Write sector
//
//---------------------------------------------------------------------------
int CFileSys::DiskWrite(DWORD nUnit) const
int CFileSys::DiskWrite(uint32_t nUnit) const
{
// Unit check
if (nUnit >= CHostEntry::DRIVE_MAX)
@ -3682,7 +3681,7 @@ int CFileSys::DiskWrite(DWORD nUnit) const
/// $55 - IOCTRL
//
//---------------------------------------------------------------------------
int CFileSys::Ioctrl(DWORD nUnit, DWORD nFunction, Human68k::ioctrl_t* pIoctrl)
int CFileSys::Ioctrl(uint32_t nUnit, uint32_t nFunction, Human68k::ioctrl_t* pIoctrl)
{
assert(pIoctrl);
@ -3705,7 +3704,7 @@ int CFileSys::Ioctrl(DWORD nUnit, DWORD nFunction, Human68k::ioctrl_t* pIoctrl)
case 2:
switch (pIoctrl->param) {
case (DWORD)-1:
case (uint32_t)-1:
// Re-identify media
m_cEntry.isMediaOffline(nUnit);
return 0;
@ -3720,17 +3719,17 @@ int CFileSys::Ioctrl(DWORD nUnit, DWORD nFunction, Human68k::ioctrl_t* pIoctrl)
}
break;
case (DWORD)-1:
case (uint32_t)-1:
// Resident evaluation
memcpy(pIoctrl->buffer, "WindrvXM", 8);
return 0;
case (DWORD)-2:
case (uint32_t)-2:
// Set options
SetOption(pIoctrl->param);
return 0;
case (DWORD)-3:
case (uint32_t)-3:
// Get options
pIoctrl->param = GetOption();
return 0;
@ -3747,7 +3746,7 @@ int CFileSys::Ioctrl(DWORD nUnit, DWORD nFunction, Human68k::ioctrl_t* pIoctrl)
/// $56 - Flush
//
//---------------------------------------------------------------------------
int CFileSys::Flush(DWORD nUnit) const
int CFileSys::Flush(uint32_t nUnit) const
{
// Unit check
if (nUnit >= CHostEntry::DRIVE_MAX)
@ -3764,7 +3763,7 @@ int CFileSys::Flush(DWORD nUnit) const
/// $57 - Media change check
//
//---------------------------------------------------------------------------
int CFileSys::CheckMedia(DWORD nUnit) const
int CFileSys::CheckMedia(uint32_t nUnit) const
{
// Unit check
if (nUnit >= CHostEntry::DRIVE_MAX)
@ -3786,7 +3785,7 @@ int CFileSys::CheckMedia(DWORD nUnit) const
/// $58 - Lock
//
//---------------------------------------------------------------------------
int CFileSys::Lock(DWORD nUnit) const
int CFileSys::Lock(uint32_t nUnit) const
{
// Unit check
if (nUnit >= CHostEntry::DRIVE_MAX)
@ -3808,7 +3807,7 @@ int CFileSys::Lock(DWORD nUnit) const
/// Set options
//
//---------------------------------------------------------------------------
void CFileSys::SetOption(DWORD nOption)
void CFileSys::SetOption(uint32_t nOption)
{
// Clear cache when option settings change
if (m_nOption ^ nOption)
@ -3833,7 +3832,7 @@ void CFileSys::InitOption(const Human68k::argument_t* pArgument)
const BYTE* pp = pArgument->buf;
pp += strlen((const char*)pp) + 1;
DWORD nOption = m_nOptionDefault;
uint32_t nOption = m_nOptionDefault;
for (;;) {
assert(pp < pArgument->buf + sizeof(*pArgument));
const BYTE* p = pp;
@ -3841,7 +3840,7 @@ void CFileSys::InitOption(const Human68k::argument_t* pArgument)
if (c == '\0')
break;
DWORD nMode;
uint32_t nMode;
if (c == '+') {
nMode = 1;
} else if (c == '-') {
@ -3866,7 +3865,7 @@ void CFileSys::InitOption(const Human68k::argument_t* pArgument)
if (c == '\0')
break;
DWORD nBit = 0;
uint32_t nBit = 0;
switch (c) {
case 'A': case 'a': nBit = WINDRV_OPT_CONVERT_LENGTH; break;
case 'T': case 't': nBit = WINDRV_OPT_COMPARE_LENGTH; nMode ^= 1; break;
@ -3909,7 +3908,7 @@ void CFileSys::InitOption(const Human68k::argument_t* pArgument)
/// Get volume label
//
//---------------------------------------------------------------------------
bool CFileSys::FilesVolume(DWORD nUnit, Human68k::files_t* pFiles) const
bool CFileSys::FilesVolume(uint32_t nUnit, Human68k::files_t* pFiles) const
{
assert(pFiles);

View File

@ -116,41 +116,41 @@ namespace Human68k {
struct files_t {
BYTE fatr; ///< + 0 search attribute; read-only
// BYTE drive; ///< + 1 drive number; read-only
DWORD sector; ///< + 2 directory sector; DOS _FILES first address substitute
// WORD cluster; ///< + 6 directory cluster; details unknown (unused)
WORD offset; ///< + 8 directory entry; write-only
uint32_t sector; ///< + 2 directory sector; DOS _FILES first address substitute
// uint16_t cluster; ///< + 6 directory cluster; details unknown (unused)
uint16_t offset; ///< + 8 directory entry; write-only
// BYTE name[8]; ///< +10 working file name; write-only (unused)
// BYTE ext[3]; ///< +18 working extension; write-only (unused)
BYTE attr; ///< +21 file attribute; write-only
WORD time; ///< +22 last change time of day; write-only
WORD date; ///< +24 last change date; write-only
DWORD size; ///< +26 file size; write-only
uint16_t time; ///< +22 last change time of day; write-only
uint16_t date; ///< +24 last change date; write-only
uint32_t size; ///< +26 file size; write-only
BYTE full[23]; ///< +30 full name; write-only
};
struct fcb_t {
// BYTE pad00[6]; ///< + 0~+ 5 (unused)
DWORD fileptr; ///< + 6~+ 9 file pointer
uint32_t fileptr; ///< + 6~+ 9 file pointer
// BYTE pad01[4]; ///< +10~+13 (unused)
WORD mode; ///< +14~+15 open mode
uint16_t mode; ///< +14~+15 open mode
// BYTE pad02[16]; ///< +16~+31 (unused)
// DWORD zero; ///< +32~+35 zeros are written when opened (unused)
// uint32_t zero; ///< +32~+35 zeros are written when opened (unused)
// BYTE name[8]; ///< +36~+43 file name (PADDING 0x20) (unused)
// BYTE ext[3]; ///< +44~+46 extension (PADDING 0x20) (unused)
BYTE attr; ///< +47 file attribute
// BYTE add[10]; ///< +48~+57 file name addition (PADDING 0x00) (unused)
WORD time; ///< +58~+59 last change time of day
WORD date; ///< +60~+61 last change date
// WORD cluster; ///< +62~+63 cluster number (unused)
DWORD size; ///< +64~+67 file size
uint16_t time; ///< +58~+59 last change time of day
uint16_t date; ///< +60~+61 last change date
// uint16_t cluster; ///< +62~+63 cluster number (unused)
uint32_t size; ///< +64~+67 file size
// BYTE pad03[28]; ///< +68~+95 FAT cache (unused)
};
struct capacity_t {
WORD freearea; ///< + 0 Number of available clusters
WORD clusters; ///< + 2 Total number of clusters
WORD sectors; ///< + 4 Number of sectors per cluster
WORD bytes; ///< + 6 Number of bytes per sector
uint16_t freearea; ///< + 0 Number of available clusters
uint16_t clusters; ///< + 2 Total number of clusters
uint16_t sectors; ///< + 4 Number of sectors per cluster
uint16_t bytes; ///< + 6 Number of bytes per sector
};
struct ctrldrive_t {
@ -159,17 +159,17 @@ namespace Human68k {
};
struct dpb_t {
WORD sector_size; ///< + 0 Number of bytes in one sector
uint16_t sector_size; ///< + 0 Number of bytes in one sector
BYTE cluster_size; ///< + 2 Number sectors in one cluster -1
BYTE shift; ///< + 3 Number of cluster→sector shifts
WORD fat_sector; ///< + 4 FAT first sector number
uint16_t fat_sector; ///< + 4 FAT first sector number
BYTE fat_max; ///< + 6 FAT storage quantity
BYTE fat_size; ///< + 7 FAT controlled sector number (excluding duplicates)
WORD file_max; ///< + 8 Number of files in the root directory
WORD data_sector; ///< +10 First sector number of data storage
WORD cluster_max; ///< +12 Total number of clusters +1
WORD root_sector; ///< +14 First sector number of root directory
// DWORD driverentry; ///< +16 Device driver pointer (unused)
uint16_t file_max; ///< + 8 Number of files in the root directory
uint16_t data_sector; ///< +10 First sector number of data storage
uint16_t cluster_max; ///< +12 Total number of clusters +1
uint16_t root_sector; ///< +14 First sector number of root directory
// uint32_t driverentry; ///< +16 Device driver pointer (unused)
BYTE media; ///< +20 Media identifier
// BYTE flag; ///< +21 Flag used by DPB (unused)
};
@ -180,17 +180,17 @@ namespace Human68k {
BYTE ext[3]; ///< + 8 Extension (PADDING 0x20)
BYTE attr; ///< +11 File attribute
BYTE add[10]; ///< +12 File name addition (PADDING 0x00)
WORD time; ///< +22 Last change time of day
WORD date; ///< +24 Last change date
WORD cluster; ///< +26 Cluster number
DWORD size; ///< +28 File size
uint16_t time; ///< +22 Last change time of day
uint16_t date; ///< +24 Last change date
uint16_t cluster; ///< +26 Cluster number
uint32_t size; ///< +28 File size
};
/// IOCTRL parameter union
union ioctrl_t {
BYTE buffer[8]; ///< Access in byte units
DWORD param; ///< Parameter (First 4 bytes)
WORD media; ///< Media byte (First 2 bytes)
uint32_t param; ///< Parameter (First 4 bytes)
uint16_t media; ///< Media byte (First 2 bytes)
};
/// Command line parameter struct
@ -313,7 +313,7 @@ Normal is 0. Becomes 1 if attempting to mount in read-only mode.
Reserving the other values for future use.
Insurance against hard-to-detect devices such as homemade USB storage.
*/
static const DWORD FSFLAG_WRITE_PROTECT = 0x00000001; ///< Bit0: Force write protect
static const uint32_t FSFLAG_WRITE_PROTECT = 0x00000001; ///< Bit0: Force write protect
//===========================================================================
//
@ -429,17 +429,17 @@ public:
void SetEntryName(); ///< Set Human68k directory entry
void SetEntryAttribute(BYTE nHumanAttribute)
{ m_dirHuman.attr = nHumanAttribute; } ///< Set Human68k directory entry
void SetEntrySize(DWORD nHumanSize)
void SetEntrySize(uint32_t nHumanSize)
{ m_dirHuman.size = nHumanSize; } ///< Set Human68k directory entry
void SetEntryDate(WORD nHumanDate)
void SetEntryDate(uint16_t nHumanDate)
{ m_dirHuman.date = nHumanDate; } ///< Set Human68k directory entry
void SetEntryTime(WORD nHumanTime)
void SetEntryTime(uint16_t nHumanTime)
{ m_dirHuman.time = nHumanTime; } ///< Set Human68k directory entry
void SetEntryCluster(WORD nHumanCluster)
void SetEntryCluster(uint16_t nHumanCluster)
{ m_dirHuman.cluster = nHumanCluster; } ///< Set Human68k directory entry
const Human68k::dirent_t* GetEntry() const
{ return &m_dirHuman; } ///< Get Human68k directory entry
int CheckAttribute(DWORD nHumanAttribute) const; ///< Determine Human68k directory entry attributes
int CheckAttribute(uint32_t nHumanAttribute) const; ///< Determine Human68k directory entry attributes
bool isSameEntry(const Human68k::dirent_t* pdirHuman) const
{ assert(pdirHuman); return memcmp(&m_dirHuman, pdirHuman, sizeof(m_dirHuman)) == 0; }
///< Determine Human68k directory entry match
@ -491,8 +491,8 @@ class CHostPath: public CRing {
public:
/// Search buffer
struct find_t {
DWORD count; ///< Search execution count + 1 (When 0 the below value is invalid)
DWORD id; ///< Entry unique ID for the path of the next search
uint32_t count; ///< Search execution count + 1 (When 0 the below value is invalid)
uint32_t id; ///< Entry unique ID for the path of the next search
const ring_t* pos; ///< Position of the next search (When identical to unique ID)
Human68k::dirent_t entry; ///< Contents of the next seach entry
@ -511,9 +511,9 @@ public:
bool isSameHuman(const BYTE* szHuman) const; ///< Compare the name on the Human68k side
bool isSameChild(const BYTE* szHuman) const; ///< Compare the name on the Human68k side
const TCHAR* GetHost() const { return m_szHost; } ///< Obtain the name on the host side
const CHostFilename* FindFilename(const BYTE* szHuman, DWORD nHumanAttribute = Human68k::AT_ALL) const;
const CHostFilename* FindFilename(const BYTE* szHuman, uint32_t nHumanAttribute = Human68k::AT_ALL) const;
///< Find file name
const CHostFilename* FindFilenameWildcard(const BYTE* szHuman, DWORD nHumanAttribute, find_t* pFind) const;
const CHostFilename* FindFilenameWildcard(const BYTE* szHuman, uint32_t nHumanAttribute, find_t* pFind) const;
///< Find file name (with support for wildcards)
bool isRefresh() const; ///< Check that the file change has been done
void Refresh(); ///< Refresh file
@ -533,11 +533,11 @@ private:
CRing m_cRing; ///< For CHostFilename linking
time_t m_tBackup = 0; ///< For time stamp restoration
bool m_bRefresh = true; ///< Refresh flag
DWORD m_nId = 0; ///< Unique ID (When the value has changed, it means an update has been made)
uint32_t m_nId = 0; ///< Unique ID (When the value has changed, it means an update has been made)
BYTE m_szHuman[HUMAN68K_PATH_MAX]; ///< The internal Human68k name for the relevant entry
TCHAR m_szHost[FILEPATH_MAX]; ///< The host side name for the relevant entry
static DWORD g_nId; ///< Counter for the unique ID generation
static uint32_t g_nId; ///< Counter for the unique ID generation
};
//===========================================================================
@ -568,15 +568,15 @@ public:
void Init();
void SetKey(DWORD nKey) { m_nKey = nKey; } ///< Set search key
bool isSameKey(DWORD nKey) const { return m_nKey == nKey; } ///< Compare search key
void SetKey(uint32_t nKey) { m_nKey = nKey; } ///< Set search key
bool isSameKey(uint32_t nKey) const { return m_nKey == nKey; } ///< Compare search key
void SetPath(const Human68k::namests_t* pNamests); ///< Create path and file name internally
bool isRootPath() const { return m_szHumanPath[1] == '\0'; } ///< Check if root directory
void SetPathWildcard() { m_nHumanWildcard = 1; } ///< Enable file search using wildcards
void SetPathOnly() { m_nHumanWildcard = 0xFF; } ///< Enable only path names
bool isPathOnly() const { return m_nHumanWildcard == 0xFF; } ///< Check if set to only path names
void SetAttribute(DWORD nHumanAttribute) { m_nHumanAttribute = nHumanAttribute; } ///< Set search attribute
bool Find(DWORD nUnit, const class CHostEntry* pEntry); ///< Find files on the Human68k side, generating data on the host side
void SetAttribute(uint32_t nHumanAttribute) { m_nHumanAttribute = nHumanAttribute; } ///< Set search attribute
bool Find(uint32_t nUnit, const class CHostEntry* pEntry); ///< Find files on the Human68k side, generating data on the host side
const CHostFilename* Find(const CHostPath* pPath); ///< Find file name
void SetEntry(const CHostFilename* pFilename); ///< Store search results on the Human68k side
void SetResult(const TCHAR* szPath); ///< Set names on the host side
@ -587,18 +587,18 @@ public:
const Human68k::dirent_t* GetEntry() const { return &m_dirHuman; }///< Get Human68k directory entry
DWORD GetAttribute() const { return m_dirHuman.attr; } ///< Get Human68k attribute
WORD GetDate() const { return m_dirHuman.date; } ///< Get Human68k date
WORD GetTime() const { return m_dirHuman.time; } ///< Get Human68k time
DWORD GetSize() const { return m_dirHuman.size; } ///< Get Human68k file size
uint32_t GetAttribute() const { return m_dirHuman.attr; } ///< Get Human68k attribute
uint16_t GetDate() const { return m_dirHuman.date; } ///< Get Human68k date
uint16_t GetTime() const { return m_dirHuman.time; } ///< Get Human68k time
uint32_t GetSize() const { return m_dirHuman.size; } ///< Get Human68k file size
const BYTE* GetHumanFilename() const { return m_szHumanFilename; }///< Get Human68k file name
const BYTE* GetHumanResult() const { return m_szHumanResult; } ///< Get Human68k file name search results
const BYTE* GetHumanPath() const { return m_szHumanPath; } ///< Get Human68k path name
private:
DWORD m_nKey = 0; ///< FILES buffer address for Human68k; 0 is unused
DWORD m_nHumanWildcard = 0; ///< Human68k wildcard data
DWORD m_nHumanAttribute = 0; ///< Human68k search attribute
uint32_t m_nKey = 0; ///< FILES buffer address for Human68k; 0 is unused
uint32_t m_nHumanWildcard = 0; ///< Human68k wildcard data
uint32_t m_nHumanAttribute = 0; ///< Human68k search attribute
CHostPath::find_t m_findNext = {}; ///< Next search location data
Human68k::dirent_t m_dirHuman = {}; ///< Search results: Human68k file data
BYTE m_szHumanFilename[24] = {}; ///< Human68k file name
@ -620,8 +620,8 @@ public:
void Init(); ///< Initialization (when the driver is installed)
void Clean(); ///< Release (when starting up or resetting)
CHostFiles* Alloc(DWORD nKey);
CHostFiles* Search(DWORD nKey);
CHostFiles* Alloc(uint32_t nKey);
CHostFiles* Search(uint32_t nKey);
void Free(CHostFiles* pFiles);
private:
/// For memory management
@ -647,26 +647,26 @@ public:
void Init();
void SetKey(DWORD nKey) { m_nKey = nKey; } ///< Set search key
bool isSameKey(DWORD nKey) const { return m_nKey == nKey; } ///< Compare search key
void SetKey(uint32_t nKey) { m_nKey = nKey; } ///< Set search key
bool isSameKey(uint32_t nKey) const { return m_nKey == nKey; } ///< Compare search key
void SetUpdate() { m_bUpdate = true; } ///< Update
bool isUpdate() const { return m_bUpdate; } ///< Get update state
bool SetMode(DWORD nHumanMode); ///< Set file open mode
bool SetMode(uint32_t nHumanMode); ///< Set file open mode
void SetFilename(const TCHAR* szFilename); ///< Set file name
void SetHumanPath(const BYTE* szHumanPath); ///< Set Human68k path name
const BYTE* GetHumanPath() const { return m_szHumanPath; } ///< Get Human68k path name
bool Create(DWORD nHumanAttribute, bool bForce); ///< Create file
bool Create(uint32_t nHumanAttribute, bool bForce); ///< Create file
bool Open(); ///< Open file
DWORD Read(BYTE* pBuffer, DWORD nSize); ///< Read file
DWORD Write(const BYTE* pBuffer, DWORD nSize); ///< Write file
uint32_t Read(BYTE* pBuffer, uint32_t nSize); ///< Read file
uint32_t Write(const BYTE* pBuffer, uint32_t nSize); ///< Write file
bool Truncate() const; ///< Truncate file
DWORD Seek(DWORD nOffset, Human68k::seek_t nHumanSeek); ///< Seek file
bool TimeStamp(DWORD nHumanTime) const; ///< Set file time stamp
uint32_t Seek(uint32_t nOffset, Human68k::seek_t nHumanSeek); ///< Seek file
bool TimeStamp(uint32_t nHumanTime) const; ///< Set file time stamp
void Close(); ///< Close file
private:
DWORD m_nKey = 0; ///< Human68k FCB buffer address (0 if unused)
uint32_t m_nKey = 0; ///< Human68k FCB buffer address (0 if unused)
bool m_bUpdate = false; ///< Update flag
FILE* m_pFile = nullptr; ///< Host side file object
const char* m_pszMode = nullptr; ///< Host side file open mode
@ -688,8 +688,8 @@ public:
void Init(); ///< Initialization (when the driver is installed)
void Clean() const; ///< Release (when starting up or resetting)
CHostFcb* Alloc(DWORD nKey);
CHostFcb* Search(DWORD nKey);
CHostFcb* Alloc(uint32_t nKey);
CHostFcb* Search(uint32_t nKey);
void Free(CHostFcb* p);
private:
@ -717,20 +717,20 @@ public:
CHostDrv(CHostDrv&) = default;
CHostDrv& operator=(const CHostDrv&) = default;
void Init(const TCHAR* szBase, DWORD nFlag); ///< Initialization (device startup and load)
void Init(const TCHAR* szBase, uint32_t nFlag); ///< Initialization (device startup and load)
bool isWriteProtect() const { return m_bWriteProtect; }
bool isEnable() const { return m_bEnable; } ///< Is it accessible?
bool isMediaOffline() const;
BYTE GetMediaByte() const;
DWORD GetStatus() const;
uint32_t GetStatus() const;
void SetEnable(bool); ///< Set media status
bool CheckMedia(); ///< Check if media was changed
void Update(); ///< Update media status
void Eject();
void GetVolume(TCHAR* szLabel); ///< Get volume label
bool GetVolumeCache(TCHAR* szLabel) const; ///< Get volume label from cache
DWORD GetCapacity(Human68k::capacity_t* pCapacity);
uint32_t GetCapacity(Human68k::capacity_t* pCapacity);
bool GetCapacityCache(Human68k::capacity_t* pCapacity) const; ///< Get capacity from cache
// Cache operations
@ -756,7 +756,7 @@ private:
bool m_bWriteProtect = false; ///< TRUE if write-protected
bool m_bEnable = false; ///< TRUE if media is usable
DWORD m_nRing = 0; ///< Number of stored path names
uint32_t m_nRing = 0; ///< Number of stored path names
CRing m_cRing; ///< For attaching to CHostPath
Human68k::capacity_t m_capCache; ///< Sector data cache: if "sectors == 0" then not cached
bool m_bVolumeCache = false; ///< TRUE if the volume label has been read
@ -786,31 +786,31 @@ public:
// Cache operations
void CleanCache() const; ///< Update all cache
void CleanCache(DWORD nUnit) const; ///< Update cache for the specified unit
void CleanCache(DWORD nUnit, const BYTE* szHumanPath) const; ///< Update cache for the specified path
void CleanCacheChild(DWORD nUnit, const BYTE* szHumanPath) const; ///< Update cache below the specified path
void DeleteCache(DWORD nUnit, const BYTE* szHumanPath) const; ///< Delete cache for the specified path
bool Find(DWORD nUnit, CHostFiles* pFiles) const; ///< Find host side name (path + file name (can be abbreviated) + attribute)
void ShellNotify(DWORD nEvent, const TCHAR* szPath); ///< Notify status change in the host side file system
void CleanCache(uint32_t nUnit) const; ///< Update cache for the specified unit
void CleanCache(uint32_t nUnit, const BYTE* szHumanPath) const; ///< Update cache for the specified path
void CleanCacheChild(uint32_t nUnit, const BYTE* szHumanPath) const; ///< Update cache below the specified path
void DeleteCache(uint32_t nUnit, const BYTE* szHumanPath) const; ///< Delete cache for the specified path
bool Find(uint32_t nUnit, CHostFiles* pFiles) const; ///< Find host side name (path + file name (can be abbreviated) + attribute)
void ShellNotify(uint32_t nEvent, const TCHAR* szPath); ///< Notify status change in the host side file system
// Drive object operations
void SetDrv(DWORD nUnit, CHostDrv* pDrv);
bool isWriteProtect(DWORD nUnit) const;
bool isEnable(DWORD nUnit) const; ///< Is it accessible?
bool isMediaOffline(DWORD nUnit) const;
BYTE GetMediaByte(DWORD nUnit) const;
DWORD GetStatus(DWORD nUnit) const; ///< Get drive status
bool CheckMedia(DWORD nUnit) const; ///< Media change check
void Eject(DWORD nUnit) const;
void GetVolume(DWORD nUnit, TCHAR* szLabel) const; ///< Get volume label
bool GetVolumeCache(DWORD nUnit, TCHAR* szLabel) const; ///< Get volume label from cache
DWORD GetCapacity(DWORD nUnit, Human68k::capacity_t* pCapacity) const;
bool GetCapacityCache(DWORD nUnit, Human68k::capacity_t* pCapacity) const; ///< Get cluster size from cache
void SetDrv(uint32_t nUnit, CHostDrv* pDrv);
bool isWriteProtect(uint32_t nUnit) const;
bool isEnable(uint32_t nUnit) const; ///< Is it accessible?
bool isMediaOffline(uint32_t nUnit) const;
BYTE GetMediaByte(uint32_t nUnit) const;
uint32_t GetStatus(uint32_t nUnit) const; ///< Get drive status
bool CheckMedia(uint32_t nUnit) const; ///< Media change check
void Eject(uint32_t nUnit) const;
void GetVolume(uint32_t nUnit, TCHAR* szLabel) const; ///< Get volume label
bool GetVolumeCache(uint32_t nUnit, TCHAR* szLabel) const; ///< Get volume label from cache
uint32_t GetCapacity(uint32_t nUnit, Human68k::capacity_t* pCapacity) const;
bool GetCapacityCache(uint32_t nUnit, Human68k::capacity_t* pCapacity) const; ///< Get cluster size from cache
private:
CHostDrv* m_pDrv[DRIVE_MAX] = {}; ///< Host side drive object
DWORD m_nTimeout = 0; ///< Last time a timeout check was carried out
uint32_t m_nTimeout = 0; ///< Last time a timeout check was carried out
};
//===========================================================================
@ -854,71 +854,71 @@ public:
void Init(); ///< Initialization (device startup and load)
// Command handlers
DWORD InitDevice(const Human68k::argument_t* pArgument); ///< $40 - Device startup
int CheckDir(DWORD nUnit, const Human68k::namests_t* pNamests) const; ///< $41 - Directory check
int MakeDir(DWORD nUnit, const Human68k::namests_t* pNamests) const; ///< $42 - Create directory
int RemoveDir(DWORD nUnit, const Human68k::namests_t* pNamests) const; ///< $43 - Delete directory
int Rename(DWORD nUnit, const Human68k::namests_t* pNamests, const Human68k::namests_t* pNamestsNew) const;
uint32_t InitDevice(const Human68k::argument_t* pArgument); ///< $40 - Device startup
int CheckDir(uint32_t nUnit, const Human68k::namests_t* pNamests) const; ///< $41 - Directory check
int MakeDir(uint32_t nUnit, const Human68k::namests_t* pNamests) const; ///< $42 - Create directory
int RemoveDir(uint32_t nUnit, const Human68k::namests_t* pNamests) const; ///< $43 - Delete directory
int Rename(uint32_t nUnit, const Human68k::namests_t* pNamests, const Human68k::namests_t* pNamestsNew) const;
///< $44 - Change file name
int Delete(DWORD nUnit, const Human68k::namests_t* pNamests) const; ///< $45 - Delete file
int Attribute(DWORD nUnit, const Human68k::namests_t* pNamests, DWORD nHumanAttribute) const;
int Delete(uint32_t nUnit, const Human68k::namests_t* pNamests) const; ///< $45 - Delete file
int Attribute(uint32_t nUnit, const Human68k::namests_t* pNamests, uint32_t nHumanAttribute) const;
///< $46 - Get / set file attribute
int Files(DWORD nUnit, DWORD nKey, const Human68k::namests_t* pNamests, Human68k::files_t* pFiles);
int Files(uint32_t nUnit, uint32_t nKey, const Human68k::namests_t* pNamests, Human68k::files_t* pFiles);
///< $47 - Find file
int NFiles(DWORD nUnit, DWORD nKey, Human68k::files_t* pFiles); ///< $48 - Find next file
int Create(DWORD nUnit, DWORD nKey, const Human68k::namests_t* pNamests, Human68k::fcb_t* pFcb, DWORD nHumanAttribute, bool bForce);
int NFiles(uint32_t nUnit, uint32_t nKey, Human68k::files_t* pFiles); ///< $48 - Find next file
int Create(uint32_t nUnit, uint32_t nKey, const Human68k::namests_t* pNamests, Human68k::fcb_t* pFcb, uint32_t nHumanAttribute, bool bForce);
///< $49 - Create file
int Open(DWORD nUnit, DWORD nKey, const Human68k::namests_t* pNamests, Human68k::fcb_t* pFcb);
int Open(uint32_t nUnit, uint32_t nKey, const Human68k::namests_t* pNamests, Human68k::fcb_t* pFcb);
///< $4A - Open file
int Close(DWORD nUnit, DWORD nKey, const Human68k::fcb_t* pFcb); ///< $4B - Close file
int Read(DWORD nKey, Human68k::fcb_t* pFcb, BYTE* pAddress, DWORD nSize);
int Close(uint32_t nUnit, uint32_t nKey, const Human68k::fcb_t* pFcb); ///< $4B - Close file
int Read(uint32_t nKey, Human68k::fcb_t* pFcb, BYTE* pAddress, uint32_t nSize);
///< $4C - Read file
int Write(DWORD nKey, Human68k::fcb_t* pFcb, const BYTE* pAddress, DWORD nSize);
int Write(uint32_t nKey, Human68k::fcb_t* pFcb, const BYTE* pAddress, uint32_t nSize);
///< $4D - Write file
int Seek(DWORD nKey, Human68k::fcb_t* pFcb, DWORD nSeek, int nOffset); ///< $4E - Seek file
DWORD TimeStamp(DWORD nUnit, DWORD nKey, Human68k::fcb_t* pFcb, DWORD nHumanTime);
int Seek(uint32_t nKey, Human68k::fcb_t* pFcb, uint32_t nSeek, int nOffset); ///< $4E - Seek file
uint32_t TimeStamp(uint32_t nUnit, uint32_t nKey, Human68k::fcb_t* pFcb, uint32_t nHumanTime);
///< $4F - Get / set file timestamp
int GetCapacity(DWORD nUnit, Human68k::capacity_t* pCapacity) const; ///< $50 - Get capacity
int CtrlDrive(DWORD nUnit, Human68k::ctrldrive_t* pCtrlDrive) const; ///< $51 - Inspect / control drive status
int GetDPB(DWORD nUnit, Human68k::dpb_t* pDpb) const; ///< $52 - Get DPB
int DiskRead(DWORD nUnit, BYTE* pBuffer, DWORD nSector, DWORD nSize); ///< $53 - Read sectors
int DiskWrite(DWORD nUnit) const; ///< $54 - Write sectors
int Ioctrl(DWORD nUnit, DWORD nFunction, Human68k::ioctrl_t* pIoctrl); ///< $55 - IOCTRL
int Flush(DWORD nUnit) const; ///< $56 - Flush
int CheckMedia(DWORD nUnit) const; ///< $57 - Media change check
int Lock(DWORD nUnit) const; ///< $58 - Lock
int GetCapacity(uint32_t nUnit, Human68k::capacity_t* pCapacity) const; ///< $50 - Get capacity
int CtrlDrive(uint32_t nUnit, Human68k::ctrldrive_t* pCtrlDrive) const; ///< $51 - Inspect / control drive status
int GetDPB(uint32_t nUnit, Human68k::dpb_t* pDpb) const; ///< $52 - Get DPB
int DiskRead(uint32_t nUnit, BYTE* pBuffer, uint32_t nSector, uint32_t nSize); ///< $53 - Read sectors
int DiskWrite(uint32_t nUnit) const; ///< $54 - Write sectors
int Ioctrl(uint32_t nUnit, uint32_t nFunction, Human68k::ioctrl_t* pIoctrl); ///< $55 - IOCTRL
int Flush(uint32_t nUnit) const; ///< $56 - Flush
int CheckMedia(uint32_t nUnit) const; ///< $57 - Media change check
int Lock(uint32_t nUnit) const; ///< $58 - Lock
void SetOption(DWORD nOption); ///< Set option
DWORD GetOption() const { return m_nOption; } ///< Get option
DWORD GetDefault() const { return m_nOptionDefault; } ///< Get default options
static DWORD GetFileOption() { return g_nOption; } ///< Get file name change option
void SetOption(uint32_t nOption); ///< Set option
uint32_t GetOption() const { return m_nOption; } ///< Get option
uint32_t GetDefault() const { return m_nOptionDefault; } ///< Get default options
static uint32_t GetFileOption() { return g_nOption; } ///< Get file name change option
static const int DriveMax = CHostEntry::DRIVE_MAX; ///< Max number of drive candidates
private:
void InitOption(const Human68k::argument_t* pArgument);
bool FilesVolume(DWORD nUnit, Human68k::files_t* pFiles) const; ///< Get volume label
bool FilesVolume(uint32_t nUnit, Human68k::files_t* pFiles) const; ///< Get volume label
DWORD m_nUnits = 0; ///< Number of current drive objects (Changes for every resume)
uint32_t m_nUnits = 0; ///< Number of current drive objects (Changes for every resume)
DWORD m_nOption = 0; ///< Current runtime flag
DWORD m_nOptionDefault = 0; ///< Runtime flag at reset
uint32_t m_nOption = 0; ///< Current runtime flag
uint32_t m_nOptionDefault = 0; ///< Runtime flag at reset
DWORD m_nDrives = 0; ///< Number of candidates for base path status restoration (scan every time if 0)
uint32_t m_nDrives = 0; ///< Number of candidates for base path status restoration (scan every time if 0)
DWORD m_nKernel = 0; ///< Counter for kernel check
DWORD m_nKernelSearch = 0; ///< Initial address for NUL device
uint32_t m_nKernel = 0; ///< Counter for kernel check
uint32_t m_nKernelSearch = 0; ///< Initial address for NUL device
DWORD m_nHostSectorCount = 0; ///< Virtual sector identifier
uint32_t m_nHostSectorCount = 0; ///< Virtual sector identifier
CHostFilesManager m_cFiles; ///< File search memory
CHostFcbManager m_cFcb; ///< FCB operation memory
CHostEntry m_cEntry; ///< Drive object and directory entry
DWORD m_nHostSectorBuffer[XM6_HOST_PSEUDO_CLUSTER_MAX];
uint32_t m_nHostSectorBuffer[XM6_HOST_PSEUDO_CLUSTER_MAX];
///< Entity that the virtual sector points to
DWORD m_nFlag[DriveMax] = {}; ///< Candidate runtime flag for base path restoration
uint32_t m_nFlag[DriveMax] = {}; ///< Candidate runtime flag for base path restoration
TCHAR m_szBase[DriveMax][FILEPATH_MAX] = {}; ///< Candidate for base path restoration
static DWORD g_nOption; ///< File name change flag
static uint32_t g_nOption; ///< File name change flag
};

View File

@ -177,7 +177,7 @@ bool CTapDriver::Init(const unordered_map<string, string>& const_params)
LOGTRACE("Return code from ioctl was %d", ret)
int ip_fd = socket(PF_INET, SOCK_DGRAM, 0);
const int ip_fd = socket(PF_INET, SOCK_DGRAM, 0);
if (ip_fd < 0) {
LOGERROR("Can't open ip socket: %s", strerror(errno))
@ -185,7 +185,7 @@ bool CTapDriver::Init(const unordered_map<string, string>& const_params)
return false;
}
int br_socket_fd = socket(AF_LOCAL, SOCK_STREAM, 0);
const int br_socket_fd = socket(AF_LOCAL, SOCK_STREAM, 0);
if (br_socket_fd < 0) {
LOGERROR("Can't open bridge socket: %s", strerror(errno))
@ -260,7 +260,7 @@ bool CTapDriver::Init(const unordered_map<string, string>& const_params)
}
// long long is required for compatibility with 32 bit platforms
auto mask = (long long)(pow(2, 32) - (1 << (32 - m)));
const auto mask = (long long)(pow(2, 32) - (1 << (32 - m)));
netmask = to_string((mask >> 24) & 0xff) + '.' + to_string((mask >> 16) & 0xff) + '.' +
to_string((mask >> 8) & 0xff) + '.' + to_string(mask & 0xff);
@ -391,18 +391,18 @@ void CTapDriver::OpenDump(const Filepath& path) {
bool CTapDriver::Enable() const
{
int fd = socket(PF_INET, SOCK_DGRAM, 0);
const int fd = socket(PF_INET, SOCK_DGRAM, 0);
LOGDEBUG("%s: ip link set ras0 up", __PRETTY_FUNCTION__)
bool result = ip_link(fd, "ras0", true);
const bool result = ip_link(fd, "ras0", true);
close(fd);
return result;
}
bool CTapDriver::Disable() const
{
int fd = socket(PF_INET, SOCK_DGRAM, 0);
const int fd = socket(PF_INET, SOCK_DGRAM, 0);
LOGDEBUG("%s: ip link set ras0 down", __PRETTY_FUNCTION__)
bool result = ip_link(fd, "ras0", false);
const bool result = ip_link(fd, "ras0", false);
close(fd);
return result;
}
@ -452,7 +452,7 @@ uint32_t CTapDriver::Crc32(const BYTE *buf, int length) {
for (int i = 0; i < length; i++) {
crc ^= buf[i];
for (int j = 0; j < 8; j++) {
uint32_t mask = -((int)crc & 1);
const uint32_t mask = -((int)crc & 1);
crc = (crc >> 1) ^ (0xEDB88320 & mask);
}
}
@ -469,8 +469,8 @@ int CTapDriver::Receive(BYTE *buf)
}
// Receive
auto dwReceived = (DWORD)read(m_hTAP, buf, ETH_FRAME_LEN);
if (dwReceived == (DWORD)-1) {
auto dwReceived = (uint32_t)read(m_hTAP, buf, ETH_FRAME_LEN);
if (dwReceived == (uint32_t)-1) {
LOGWARN("%s Error occured while receiving a packet", __PRETTY_FUNCTION__)
return 0;
}
@ -480,7 +480,7 @@ int CTapDriver::Receive(BYTE *buf)
// We need to add the Frame Check Status (FCS) CRC back onto the end of the packet.
// The Linux network subsystem removes it, since most software apps shouldn't ever
// need it.
int crc = Crc32(buf, dwReceived);
const int crc = Crc32(buf, dwReceived);
buf[dwReceived + 0] = (BYTE)((crc >> 0) & 0xFF);
buf[dwReceived + 1] = (BYTE)((crc >> 8) & 0xFF);

View File

@ -23,20 +23,16 @@ using namespace std;
class CTapDriver
{
friend class SCSIDaynaPort;
friend class SCSIBR;
static constexpr const char *BRIDGE_NAME = "rascsi_bridge";
public:
CTapDriver() = default;
~CTapDriver();
CTapDriver(CTapDriver&) = default;
CTapDriver& operator=(const CTapDriver&) = default;
bool Init(const unordered_map<string, string>&);
public:
void OpenDump(const Filepath& path); // Capture packets
void GetMacAddr(BYTE *mac) const;
int Receive(BYTE *buf);

View File

@ -76,7 +76,7 @@ string Device::GetPaddedName() const
ostringstream os;
os << left << setfill(' ') << setw(8) << vendor << setw(16) << product << setw(4) << revision;
string name = os.str();
const string name = os.str();
assert(name.length() == 28);
return name;

View File

@ -56,12 +56,17 @@ DeviceFactory::DeviceFactory()
extension_mapping["hdr"] = SCRM;
extension_mapping["mos"] = SCMO;
extension_mapping["iso"] = SCCD;
device_mapping["bridge"] = SCBR;
device_mapping["daynaport"] = SCDP;
device_mapping["printer"] = SCLP;
device_mapping["services"] = SCHS;
}
string DeviceFactory::GetExtension(const string& filename) const
{
string ext;
if (size_t separator = filename.rfind('.'); separator != string::npos) {
if (const size_t separator = filename.rfind('.'); separator != string::npos) {
ext = filename.substr(separator + 1);
}
std::transform(ext.begin(), ext.end(), ext.begin(), [](unsigned char c){ return std::tolower(c); });
@ -74,17 +79,9 @@ PbDeviceType DeviceFactory::GetTypeForFile(const string& filename) const
if (const auto& it = extension_mapping.find(GetExtension(filename)); it != extension_mapping.end()) {
return it->second;
}
else if (filename == "bridge") {
return SCBR;
}
else if (filename == "daynaport") {
return SCDP;
}
else if (filename == "printer") {
return SCLP;
}
else if (filename == "services") {
return SCHS;
if (const auto& it = device_mapping.find(filename); it != device_mapping.end()) {
return it->second;
}
return UNDEFINED;
@ -105,7 +102,7 @@ shared_ptr<PrimaryDevice> DeviceFactory::CreateDevice(const ControllerManager& c
shared_ptr<PrimaryDevice> device;
switch (type) {
case SCHD: {
if (string ext = GetExtension(filename); ext == "hdn" || ext == "hdi" || ext == "nhd") {
if (const string ext = GetExtension(filename); ext == "hdn" || ext == "hdi" || ext == "nhd") {
device = make_shared<SCSIHD_NEC>(lun);
} else {
device = make_shared<SCSIHD>(lun, sector_sizes[SCHD], false,
@ -220,10 +217,10 @@ list<string> DeviceFactory::GetNetworkInterfaces() const
while (tmp) {
if (tmp->ifa_addr && tmp->ifa_addr->sa_family == AF_PACKET &&
strcmp(tmp->ifa_name, "lo") && strcmp(tmp->ifa_name, "rascsi_bridge")) {
int fd = socket(PF_INET, SOCK_DGRAM, IPPROTO_IP);
const int fd = socket(PF_INET, SOCK_DGRAM, IPPROTO_IP);
ifreq ifr = {};
strcpy(ifr.ifr_name, tmp->ifa_name);
strncpy(ifr.ifr_name, tmp->ifa_name, IFNAMSIZ); //NOSONAR Using strncpy is safe here
// Only list interfaces that are up
if (!ioctl(fd, SIOCGIFFLAGS, &ifr) && (ifr.ifr_flags & IFF_UP)) {
network_interfaces.emplace_back(tmp->ifa_name);

View File

@ -38,7 +38,7 @@ public:
const unordered_set<uint32_t>& GetSectorSizes(const string&) const;
const unordered_map<string, string>& GetDefaultParams(PbDeviceType type) const;
list<string> GetNetworkInterfaces() const;
unordered_map<string, PbDeviceType> GetExtensionMapping() const { return extension_mapping; }
const unordered_map<string, PbDeviceType>& GetExtensionMapping() const { return extension_mapping; }
private:
@ -50,6 +50,8 @@ private:
unordered_map<string, PbDeviceType> extension_mapping;
unordered_map<string, PbDeviceType> device_mapping;
unordered_set<uint32_t> empty_set;
unordered_map<string, string> empty_map;
};

View File

@ -14,9 +14,7 @@
//
//---------------------------------------------------------------------------
#include "os.h"
#include "fileio.h"
#include "file_support.h"
#include "rascsi_exceptions.h"
#include "dispatcher.h"
#include "scsi_command_util.h"
@ -25,6 +23,8 @@
using namespace scsi_defs;
using namespace scsi_command_util;
unordered_map<string, id_set> Disk::reserved_files;
Disk::Disk(const string& type, int lun) : ModePageDevice(type, lun)
{
dispatcher.Add(scsi_command::eCmdRezero, "Rezero", &Disk::Rezero);
@ -73,7 +73,7 @@ bool Disk::Dispatch(scsi_command cmd)
is_medium_changed = false;
throw scsi_error_exception(sense_key::UNIT_ATTENTION, asc::NOT_READY_TO_READY_CHANGE);
throw scsi_exception(sense_key::UNIT_ATTENTION, asc::NOT_READY_TO_READY_CHANGE);
}
// The superclass handles the less specific commands
@ -141,7 +141,7 @@ void Disk::FormatUnit()
// FMTDATA=1 is not supported (but OK if there is no DEFECT LIST)
if ((ctrl->cmd[1] & 0x10) != 0 && ctrl->cmd[4] != 0) {
throw scsi_error_exception(sense_key::ILLEGAL_REQUEST, asc::INVALID_FIELD_IN_CDB);
throw scsi_exception(sense_key::ILLEGAL_REQUEST, asc::INVALID_FIELD_IN_CDB);
}
EnterStatusPhase();
@ -187,7 +187,7 @@ void Disk::ReadWriteLong10()
{
// Transfer lengths other than 0 are not supported, which is compliant with the SCSI standard
if (GetInt16(ctrl->cmd, 7) != 0) {
throw scsi_error_exception(sense_key::ILLEGAL_REQUEST, asc::INVALID_FIELD_IN_CDB);
throw scsi_exception(sense_key::ILLEGAL_REQUEST, asc::INVALID_FIELD_IN_CDB);
}
ValidateBlockAddress(RW10);
@ -199,7 +199,7 @@ void Disk::ReadWriteLong16()
{
// Transfer lengths other than 0 are not supported, which is compliant with the SCSI standard
if (GetInt16(ctrl->cmd, 12) != 0) {
throw scsi_error_exception(sense_key::ILLEGAL_REQUEST, asc::INVALID_FIELD_IN_CDB);
throw scsi_exception(sense_key::ILLEGAL_REQUEST, asc::INVALID_FIELD_IN_CDB);
}
ValidateBlockAddress(RW16);
@ -271,8 +271,8 @@ void Disk::Verify16()
void Disk::StartStopUnit()
{
bool start = ctrl->cmd[4] & 0x01;
bool load = ctrl->cmd[4] & 0x02;
const bool start = ctrl->cmd[4] & 0x01;
const bool load = ctrl->cmd[4] & 0x02;
if (load) {
LOGTRACE(start ? "Loading medium" : "Ejecting medium")
@ -290,12 +290,12 @@ void Disk::StartStopUnit()
if (load) {
if (IsLocked()) {
// Cannot be ejected because it is locked
throw scsi_error_exception(sense_key::ILLEGAL_REQUEST, asc::LOAD_OR_EJECT_FAILED);
throw scsi_exception(sense_key::ILLEGAL_REQUEST, asc::LOAD_OR_EJECT_FAILED);
}
// Eject
if (!Eject(false)) {
throw scsi_error_exception();
throw scsi_exception();
}
}
}
@ -307,12 +307,12 @@ void Disk::SendDiagnostic()
{
// Do not support PF bit
if (ctrl->cmd[1] & 0x10) {
throw scsi_error_exception(sense_key::ILLEGAL_REQUEST, asc::INVALID_FIELD_IN_CDB);
throw scsi_exception(sense_key::ILLEGAL_REQUEST, asc::INVALID_FIELD_IN_CDB);
}
// Do not support parameter list
if ((ctrl->cmd[3] != 0) || (ctrl->cmd[4] != 0)) {
throw scsi_error_exception(sense_key::ILLEGAL_REQUEST, asc::INVALID_FIELD_IN_CDB);
throw scsi_exception(sense_key::ILLEGAL_REQUEST, asc::INVALID_FIELD_IN_CDB);
}
EnterStatusPhase();
@ -322,7 +322,7 @@ void Disk::PreventAllowMediumRemoval()
{
CheckReady();
bool lock = ctrl->cmd[4] & 0x01;
const bool lock = ctrl->cmd[4] & 0x01;
LOGTRACE(lock ? "Locking medium" : "Unlocking medium")
@ -340,7 +340,7 @@ void Disk::SynchronizeCache()
void Disk::ReadDefectData10()
{
size_t allocation_length = min((size_t)GetInt16(ctrl->cmd, 7), (size_t)4);
const size_t allocation_length = min((size_t)GetInt16(ctrl->cmd, 7), (size_t)4);
// The defect list is empty
fill_n(controller->GetBuffer().begin(), allocation_length, 0);
@ -361,15 +361,13 @@ void Disk::MediumChanged()
bool Disk::Eject(bool force)
{
bool status = super::Eject(force);
const bool status = super::Eject(force);
if (status) {
FlushCache();
cache.reset();
// The image file for this drive is not in use anymore
if (auto file_support = dynamic_cast<FileSupport *>(this); file_support) {
file_support->UnreserveFile();
}
UnreserveFile();
}
return status;
@ -378,7 +376,7 @@ bool Disk::Eject(bool force)
int Disk::ModeSense6(const vector<int>& cdb, vector<BYTE>& buf) const
{
// Get length, clear buffer
auto length = (int)min(buf.size(), (size_t)cdb[4]);
const auto length = (int)min(buf.size(), (size_t)cdb[4]);
fill_n(buf.begin(), length, 0);
// DEVICE SPECIFIC PARAMETER
@ -406,7 +404,7 @@ int Disk::ModeSense6(const vector<int>& cdb, vector<BYTE>& buf) const
size += super::AddModePages(cdb, buf, size, length - size);
if (size > 255) {
throw scsi_error_exception(sense_key::ILLEGAL_REQUEST, asc::INVALID_FIELD_IN_CDB);
throw scsi_exception(sense_key::ILLEGAL_REQUEST, asc::INVALID_FIELD_IN_CDB);
}
// Do not return more than ALLOCATION LENGTH bytes
@ -423,7 +421,7 @@ int Disk::ModeSense6(const vector<int>& cdb, vector<BYTE>& buf) const
int Disk::ModeSense10(const vector<int>& cdb, vector<BYTE>& buf) const
{
// Get length, clear buffer
auto length = (int)min(buf.size(), (size_t)GetInt16(cdb, 7));
const auto length = (int)min(buf.size(), (size_t)GetInt16(cdb, 7));
fill_n(buf.begin(), length, 0);
// DEVICE SPECIFIC PARAMETER
@ -467,7 +465,7 @@ int Disk::ModeSense10(const vector<int>& cdb, vector<BYTE>& buf) const
size += super::AddModePages(cdb, buf, size, length - size);
if (size > 65535) {
throw scsi_error_exception(sense_key::ILLEGAL_REQUEST, asc::INVALID_FIELD_IN_CDB);
throw scsi_exception(sense_key::ILLEGAL_REQUEST, asc::INVALID_FIELD_IN_CDB);
}
// Do not return more than ALLOCATION LENGTH bytes
@ -623,12 +621,12 @@ int Disk::Read(const vector<int>&, vector<BYTE>& buf, uint64_t block)
// Error if the total number of blocks is exceeded
if (block >= blocks) {
throw scsi_error_exception(sense_key::ILLEGAL_REQUEST, asc::INVALID_FIELD_IN_CDB);
throw scsi_exception(sense_key::ILLEGAL_REQUEST, asc::INVALID_FIELD_IN_CDB);
}
// leave it to the cache
if (!cache->ReadSector(buf, (uint32_t)block)) {
throw scsi_error_exception(sense_key::MEDIUM_ERROR, asc::READ_FAULT);
throw scsi_exception(sense_key::MEDIUM_ERROR, asc::READ_FAULT);
}
// Success
@ -641,12 +639,12 @@ int Disk::WriteCheck(uint64_t block)
// Error if the total number of blocks is exceeded
if (block >= blocks) {
throw scsi_error_exception(sense_key::ILLEGAL_REQUEST, asc::INVALID_FIELD_IN_CDB);
throw scsi_exception(sense_key::ILLEGAL_REQUEST, asc::INVALID_FIELD_IN_CDB);
}
// Error if write protected
if (IsProtected()) {
throw scsi_error_exception(sense_key::DATA_PROTECT, asc::WRITE_PROTECTED);
throw scsi_exception(sense_key::DATA_PROTECT, asc::WRITE_PROTECTED);
}
// Success
@ -660,22 +658,22 @@ void Disk::Write(const vector<int>&, const vector<BYTE>& buf, uint64_t block)
// Error if not ready
if (!IsReady()) {
throw scsi_error_exception(sense_key::NOT_READY);
throw scsi_exception(sense_key::NOT_READY);
}
// Error if the total number of blocks is exceeded
if (block >= blocks) {
throw scsi_error_exception(sense_key::ILLEGAL_REQUEST, asc::LBA_OUT_OF_RANGE);
throw scsi_exception(sense_key::ILLEGAL_REQUEST, asc::LBA_OUT_OF_RANGE);
}
// Error if write protected
if (IsProtected()) {
throw scsi_error_exception(sense_key::DATA_PROTECT, asc::WRITE_PROTECTED);
throw scsi_exception(sense_key::DATA_PROTECT, asc::WRITE_PROTECTED);
}
// Leave it to the cache
if (!cache->WriteSector(buf, (uint32_t)block)) {
throw scsi_error_exception(sense_key::MEDIUM_ERROR, asc::WRITE_FAULT);
throw scsi_exception(sense_key::MEDIUM_ERROR, asc::WRITE_FAULT);
}
}
@ -709,7 +707,7 @@ void Disk::ReadCapacity10()
CheckReady();
if (blocks == 0) {
throw scsi_error_exception(sense_key::ILLEGAL_REQUEST, asc::MEDIUM_NOT_PRESENT);
throw scsi_exception(sense_key::ILLEGAL_REQUEST, asc::MEDIUM_NOT_PRESENT);
}
vector<BYTE>& buf = controller->GetBuffer();
@ -737,7 +735,7 @@ void Disk::ReadCapacity16()
CheckReady();
if (blocks == 0) {
throw scsi_error_exception(sense_key::ILLEGAL_REQUEST, asc::MEDIUM_NOT_PRESENT);
throw scsi_exception(sense_key::ILLEGAL_REQUEST, asc::MEDIUM_NOT_PRESENT);
}
vector<BYTE>& buf = controller->GetBuffer();
@ -772,7 +770,7 @@ void Disk::ReadCapacity16_ReadLong16()
break;
default:
throw scsi_error_exception(sense_key::ILLEGAL_REQUEST, asc::INVALID_FIELD_IN_CDB);
throw scsi_exception(sense_key::ILLEGAL_REQUEST, asc::INVALID_FIELD_IN_CDB);
break;
}
}
@ -805,14 +803,12 @@ void Disk::Release()
void Disk::ValidateBlockAddress(access_mode mode) const
{
uint64_t block = mode == RW16 ? GetInt64(ctrl->cmd, 2) : GetInt32(ctrl->cmd, 2);
const uint64_t block = mode == RW16 ? GetInt64(ctrl->cmd, 2) : GetInt32(ctrl->cmd, 2);
uint64_t capacity = blocks;
if (block > capacity) {
LOGTRACE("%s", ("Capacity of " + to_string(capacity) + " block(s) exceeded: Trying to access block "
if (block > blocks) {
LOGTRACE("%s", ("Capacity of " + to_string(blocks) + " block(s) exceeded: Trying to access block "
+ to_string(block)).c_str())
throw scsi_error_exception(sense_key::ILLEGAL_REQUEST, asc::LBA_OUT_OF_RANGE);
throw scsi_exception(sense_key::ILLEGAL_REQUEST, asc::LBA_OUT_OF_RANGE);
}
}
@ -846,7 +842,7 @@ bool Disk::CheckAndGetStartAndCount(uint64_t& start, uint32_t& count, access_mod
if (uint64_t capacity = blocks; start > capacity || start + count > capacity) {
LOGTRACE("%s", ("Capacity of " + to_string(capacity) + " block(s) exceeded: Trying to access block "
+ to_string(start) + ", block count " + to_string(count)).c_str())
throw scsi_error_exception(sense_key::ILLEGAL_REQUEST, asc::LBA_OUT_OF_RANGE);
throw scsi_exception(sense_key::ILLEGAL_REQUEST, asc::LBA_OUT_OF_RANGE);
}
// Do not process 0 blocks
@ -909,3 +905,43 @@ bool Disk::SetConfiguredSectorSize(const DeviceFactory& device_factory, uint32_t
return true;
}
void Disk::ReserveFile(const Filepath& path, int id, int lun) const
{
reserved_files[path.GetPath()] = make_pair(id, lun);
}
void Disk::UnreserveFile() const
{
reserved_files.erase(diskpath.GetPath());
}
bool Disk::GetIdsForReservedFile(const Filepath& path, int& id, int& lun)
{
if (const auto& it = reserved_files.find(path.GetPath()); it != reserved_files.end()) {
id = it->second.first;
lun = it->second.second;
return true;
}
return false;
}
void Disk::UnreserveAll()
{
reserved_files.clear();
}
bool Disk::FileExists(const Filepath& filepath)
{
try {
// Disk::Open closes the file in case it exists
Open(filepath);
}
catch(const file_not_found_exception&) {
return false;
}
return true;
}

View File

@ -25,7 +25,11 @@
#include <string>
#include <unordered_set>
class Disk : public ModePageDevice, public ScsiBlockCommands
using namespace std;
using id_set = pair<int, int>;
class Disk : public ModePageDevice, private ScsiBlockCommands
{
enum access_mode { RW6, RW10, RW16, SEEK6, SEEK10 };
@ -45,6 +49,11 @@ class Disk : public ModePageDevice, public ScsiBlockCommands
bool is_medium_changed = false;
Filepath diskpath;
// The list of image files in use and the IDs and LUNs using these files
static unordered_map<string, id_set> reserved_files;
public:
Disk(const string&, int);
@ -67,6 +76,18 @@ public:
uint64_t GetBlockCount() const { return blocks; }
void FlushCache() override;
virtual void Open(const Filepath&);
void GetPath(Filepath& path) const { path = diskpath; }
void ReserveFile(const Filepath&, int, int) const;
void UnreserveFile() const;
static void UnreserveAll();
bool FileExists(const Filepath&);
static unordered_map<string, id_set> GetReservedFiles() { return reserved_files; }
static void SetReservedFiles(const unordered_map<string, id_set>& files_in_use) { reserved_files = files_in_use; }
static bool GetIdsForReservedFile(const Filepath&, int&, int&);
private:
using super = ModePageDevice;
@ -110,7 +131,6 @@ private:
protected:
virtual void Open(const Filepath&);
void SetUpCache(const Filepath&, off_t, bool = false);
void ResizeCache(const Filepath&, bool);
@ -127,4 +147,5 @@ protected:
void SetSectorSizeShiftCount(uint32_t count) { size_shift_count = count; }
uint32_t GetConfiguredSectorSize() const;
void SetBlockCount(uint64_t b) { blocks = b; }
void SetPath(const Filepath& path) { diskpath = path; }
};

View File

@ -16,6 +16,8 @@
#include "disk_track.h"
#include "disk_cache.h"
#include <cstdlib>
#include <cassert>
DiskCache::DiskCache(const Filepath& path, int size, uint32_t blocks, off_t imgoff)
: sec_size(size), sec_blocks(blocks), imgoffset(imgoff)

View File

@ -68,7 +68,7 @@ bool DiskTrack::Load(const Filepath& path)
offset += dt.imgoffset;
// Calculate length (data size of this track)
int length = dt.sectors << dt.size;
const int length = dt.sectors << dt.size;
// Allocate buffer memory
assert((dt.sectors > 0) && (dt.sectors <= 0x100));
@ -85,7 +85,7 @@ bool DiskTrack::Load(const Filepath& path)
}
// Reallocate if the buffer length is different
if (dt.length != (DWORD)length) {
if (dt.length != (uint32_t)length) {
free(dt.buffer);
if (posix_memalign((void **)&dt.buffer, 512, ((length + 511) / 512) * 512)) {
LOGWARN("%s posix_memalign failed", __PRETTY_FUNCTION__)
@ -167,7 +167,7 @@ bool DiskTrack::Save(const Filepath& path)
offset += dt.imgoffset;
// Calculate length per sector
int length = 1 << dt.size;
const int length = 1 << dt.size;
// Open file
Fileio fio;
@ -265,8 +265,8 @@ bool DiskTrack::WriteSector(const vector<BYTE>& buf, int sec)
}
// Calculate offset and length
int offset = sec << dt.size;
int length = 1 << dt.size;
const int offset = sec << dt.size;
const int length = 1 << dt.size;
// Compare
assert(dt.buffer);

View File

@ -16,6 +16,7 @@
#pragma once
#include "filepath.h"
#include <cstdlib>
#include <vector>
using namespace std;
@ -26,7 +27,7 @@ class DiskTrack
int track; // Track Number
int size; // Sector Size (8=256, 9=512, 10=1024, 11=2048, 12=4096)
int sectors; // Number of sectors(<0x100)
DWORD length; // Data buffer length
uint32_t length; // Data buffer length
BYTE *buffer; // Data buffer
bool init; // Is it initilized?
bool changed; // Changed flag

View File

@ -1,55 +0,0 @@
//---------------------------------------------------------------------------
//
// SCSI Target Emulator RaSCSI Reloaded
// for Raspberry Pi
//
// Copyright (C) 2021-2022 Uwe Seimet
//
//---------------------------------------------------------------------------
#include "rascsi_exceptions.h"
#include "file_support.h"
using namespace std;
unordered_map<string, id_set> FileSupport::reserved_files;
void FileSupport::ReserveFile(const Filepath& path, int id, int lun) const
{
reserved_files[path.GetPath()] = make_pair(id, lun);
}
void FileSupport::UnreserveFile() const
{
reserved_files.erase(diskpath.GetPath());
}
bool FileSupport::GetIdsForReservedFile(const Filepath& path, int& id, int& lun)
{
if (const auto& it = reserved_files.find(path.GetPath()); it != reserved_files.end()) {
id = it->second.first;
lun = it->second.second;
return true;
}
return false;
}
void FileSupport::UnreserveAll()
{
reserved_files.clear();
}
bool FileSupport::FileExists(const Filepath& filepath)
{
try {
// Disk::Open closes the file in case it exists
Open(filepath);
}
catch(const file_not_found_exception&) {
return false;
}
return true;
}

View File

@ -1,48 +0,0 @@
//---------------------------------------------------------------------------
//
// SCSI Target Emulator RaSCSI Reloaded
// for Raspberry Pi
//
// Copyright (C) 2021-2022 Uwe Seimet
//
// Devices inheriting from FileSupport support image files
//
//---------------------------------------------------------------------------
#pragma once
#include <unordered_map>
#include <string>
#include "filepath.h"
using namespace std;
using id_set = pair<int, int>;
class FileSupport
{
Filepath diskpath;
// The list of image files in use and the IDs and LUNs using these files
static unordered_map<string, id_set> reserved_files;
public:
FileSupport() = default;
virtual ~FileSupport() = default;
void GetPath(Filepath& path) const { path = diskpath; }
void SetPath(const Filepath& path) { diskpath = path; }
void ReserveFile(const Filepath&, int, int) const;
void UnreserveFile() const;
static void UnreserveAll();
bool FileExists(const Filepath&);
static unordered_map<string, id_set> GetReservedFiles() { return reserved_files; }
static void SetReservedFiles(const unordered_map<string, id_set>& files_in_use)
{ FileSupport::reserved_files = files_in_use; }
static bool GetIdsForReservedFile(const Filepath&, int&, int&);
virtual void Open(const Filepath&) = 0;
};

View File

@ -57,8 +57,8 @@ vector<byte> HostServices::InquiryInternal() const
void HostServices::StartStopUnit()
{
bool start = ctrl->cmd[4] & 0x01;
bool load = ctrl->cmd[4] & 0x02;
const bool start = ctrl->cmd[4] & 0x01;
const bool load = ctrl->cmd[4] & 0x02;
if (!start) {
// Flush any caches
@ -77,7 +77,7 @@ void HostServices::StartStopUnit()
controller->ScheduleShutdown(AbstractController::rascsi_shutdown_mode::RESTART_PI);
}
else {
throw scsi_error_exception(sense_key::ILLEGAL_REQUEST, asc::INVALID_FIELD_IN_CDB);
throw scsi_exception(sense_key::ILLEGAL_REQUEST, asc::INVALID_FIELD_IN_CDB);
}
EnterStatusPhase();
@ -87,10 +87,10 @@ int HostServices::ModeSense6(const vector<int>& cdb, vector<BYTE>& buf) const
{
// Block descriptors cannot be returned
if (!(cdb[1] & 0x08)) {
throw scsi_error_exception(sense_key::ILLEGAL_REQUEST, asc::INVALID_FIELD_IN_CDB);
throw scsi_exception(sense_key::ILLEGAL_REQUEST, asc::INVALID_FIELD_IN_CDB);
}
auto length = (int)min(buf.size(), (size_t)cdb[4]);
const auto length = (int)min(buf.size(), (size_t)cdb[4]);
fill_n(buf.begin(), length, 0);
// Basic Information
@ -98,7 +98,7 @@ int HostServices::ModeSense6(const vector<int>& cdb, vector<BYTE>& buf) const
size += super::AddModePages(cdb, buf, size, length - size);
if (size > 255) {
throw scsi_error_exception(sense_key::ILLEGAL_REQUEST, asc::INVALID_FIELD_IN_CDB);
throw scsi_exception(sense_key::ILLEGAL_REQUEST, asc::INVALID_FIELD_IN_CDB);
}
// Do not return more than ALLOCATION LENGTH bytes
@ -115,10 +115,10 @@ int HostServices::ModeSense10(const vector<int>& cdb, vector<BYTE>& buf) const
{
// Block descriptors cannot be returned
if (!(cdb[1] & 0x08)) {
throw scsi_error_exception(sense_key::ILLEGAL_REQUEST, asc::INVALID_FIELD_IN_CDB);
throw scsi_exception(sense_key::ILLEGAL_REQUEST, asc::INVALID_FIELD_IN_CDB);
}
auto length = (int)min(buf.size(), (size_t)GetInt16(cdb, 7));
const auto length = (int)min(buf.size(), (size_t)GetInt16(cdb, 7));
fill_n(buf.begin(), length, 0);
// Basic Information
@ -126,7 +126,7 @@ int HostServices::ModeSense10(const vector<int>& cdb, vector<BYTE>& buf) const
size += super::AddModePages(cdb, buf, size, length - size);
if (size > 65535) {
throw scsi_error_exception(sense_key::ILLEGAL_REQUEST, asc::INVALID_FIELD_IN_CDB);
throw scsi_exception(sense_key::ILLEGAL_REQUEST, asc::INVALID_FIELD_IN_CDB);
}
// Do not return more than ALLOCATION LENGTH bytes

View File

@ -29,7 +29,6 @@ public:
vector<byte> InquiryInternal() const override;
void TestUnitReady() override;
void StartStopUnit();
bool SupportsFile() const override { return false; }
@ -58,6 +57,7 @@ private:
const ControllerManager& controller_manager;
void StartStopUnit();
int ModeSense6(const vector<int>&, vector<BYTE>&) const override;
int ModeSense10(const vector<int>&, vector<BYTE>&) const override;

View File

@ -40,10 +40,10 @@ int ModePageDevice::AddModePages(const vector<int>& cdb, vector<BYTE>& buf, int
return 0;
}
bool changeable = (cdb[2] & 0xc0) == 0x40;
const bool changeable = (cdb[2] & 0xc0) == 0x40;
// Get page code (0x3f means all pages)
int page = cdb[2] & 0x3f;
const int page = cdb[2] & 0x3f;
LOGTRACE("%s Requesting mode page $%02X", __PRETTY_FUNCTION__, page)
@ -53,7 +53,7 @@ int ModePageDevice::AddModePages(const vector<int>& cdb, vector<BYTE>& buf, int
if (pages.empty()) {
LOGTRACE("%s Unsupported mode page $%02X", __PRETTY_FUNCTION__, page)
throw scsi_error_exception(sense_key::ILLEGAL_REQUEST, asc::INVALID_FIELD_IN_CDB);
throw scsi_exception(sense_key::ILLEGAL_REQUEST, asc::INVALID_FIELD_IN_CDB);
}
// Holds all mode page data
@ -63,7 +63,7 @@ int ModePageDevice::AddModePages(const vector<int>& cdb, vector<BYTE>& buf, int
for (auto const& [index, data] : pages) {
// The specification mandates that page 0 must be returned after all others
if (index) {
size_t off = result.size();
const size_t off = result.size();
// Page data
result.insert(result.end(), data.begin(), data.end());
@ -110,7 +110,7 @@ void ModePageDevice::ModeSense10()
void ModePageDevice::ModeSelect(const vector<int>&, const vector<BYTE>&, int) const
{
throw scsi_error_exception(sense_key::ILLEGAL_REQUEST, asc::INVALID_COMMAND_OPERATION_CODE);
throw scsi_exception(sense_key::ILLEGAL_REQUEST, asc::INVALID_COMMAND_OPERATION_CODE);
}
void ModePageDevice::ModeSelect6()
@ -132,7 +132,7 @@ int ModePageDevice::ModeSelectCheck(int length) const
// Error if save parameters are set for other types than SCHD, SCRM or SCMO
// TODO The assumption above is not correct, and this code should be located elsewhere
if (GetType() != "SCHD" && GetType() != "SCRM" && GetType() != "SCMO" && (ctrl->cmd[1] & 0x01)) {
throw scsi_error_exception(sense_key::ILLEGAL_REQUEST, asc::INVALID_FIELD_IN_CDB);
throw scsi_exception(sense_key::ILLEGAL_REQUEST, asc::INVALID_FIELD_IN_CDB);
}
return length;

View File

@ -59,12 +59,12 @@ void PrimaryDevice::Inquiry()
{
// EVPD and page code check
if ((ctrl->cmd[1] & 0x01) || ctrl->cmd[2]) {
throw scsi_error_exception(sense_key::ILLEGAL_REQUEST, asc::INVALID_FIELD_IN_CDB);
throw scsi_exception(sense_key::ILLEGAL_REQUEST, asc::INVALID_FIELD_IN_CDB);
}
vector<byte> buf = InquiryInternal();
size_t allocation_length = min(buf.size(), (size_t)GetInt16(ctrl->cmd, 3));
const size_t allocation_length = min(buf.size(), (size_t)GetInt16(ctrl->cmd, 3));
memcpy(controller->GetBuffer().data(), buf.data(), allocation_length);
ctrl->length = (uint32_t)allocation_length;
@ -84,10 +84,10 @@ void PrimaryDevice::ReportLuns()
{
// Only SELECT REPORT mode 0 is supported
if (ctrl->cmd[2]) {
throw scsi_error_exception(sense_key::ILLEGAL_REQUEST, asc::INVALID_FIELD_IN_CDB);
throw scsi_exception(sense_key::ILLEGAL_REQUEST, asc::INVALID_FIELD_IN_CDB);
}
uint32_t allocation_length = GetInt32(ctrl->cmd, 6);
const uint32_t allocation_length = GetInt32(ctrl->cmd, 6);
vector<BYTE>& buf = controller->GetBuffer();
fill_n(buf.begin(), min(buf.size(), (size_t)allocation_length), 0);
@ -129,7 +129,7 @@ void PrimaryDevice::RequestSense()
vector<byte> buf = controller->GetDeviceForLun(lun)->HandleRequestSense();
size_t allocation_length = min(buf.size(), (size_t)ctrl->cmd[4]);
const size_t allocation_length = min(buf.size(), (size_t)ctrl->cmd[4]);
memcpy(controller->GetBuffer().data(), buf.data(), allocation_length);
ctrl->length = (uint32_t)allocation_length;
@ -143,20 +143,20 @@ void PrimaryDevice::CheckReady()
if (IsReset()) {
SetReset(false);
LOGTRACE("%s Device in reset", __PRETTY_FUNCTION__)
throw scsi_error_exception(sense_key::UNIT_ATTENTION, asc::POWER_ON_OR_RESET);
throw scsi_exception(sense_key::UNIT_ATTENTION, asc::POWER_ON_OR_RESET);
}
// Not ready if it needs attention
if (IsAttn()) {
SetAttn(false);
LOGTRACE("%s Device in needs attention", __PRETTY_FUNCTION__)
throw scsi_error_exception(sense_key::UNIT_ATTENTION, asc::NOT_READY_TO_READY_CHANGE);
throw scsi_exception(sense_key::UNIT_ATTENTION, asc::NOT_READY_TO_READY_CHANGE);
}
// Return status if not ready
if (!IsReady()) {
LOGTRACE("%s Device not ready", __PRETTY_FUNCTION__)
throw scsi_error_exception(sense_key::NOT_READY, asc::MEDIUM_NOT_PRESENT);
throw scsi_exception(sense_key::NOT_READY, asc::MEDIUM_NOT_PRESENT);
}
// Initialization with no error
@ -180,7 +180,7 @@ vector<byte> PrimaryDevice::HandleInquiry(device_type type, scsi_level level, bo
buf[4] = (byte)0x1F;
// Padded vendor, product, revision
memcpy(&buf[8], GetPaddedName().c_str(), 28);
memcpy(&buf.data()[8], GetPaddedName().c_str(), 28);
return buf;
}
@ -189,7 +189,7 @@ vector<byte> PrimaryDevice::HandleRequestSense() const
{
// Return not ready only if there are no errors
if (!GetStatusCode() && !IsReady()) {
throw scsi_error_exception(sense_key::NOT_READY, asc::MEDIUM_NOT_PRESENT);
throw scsi_exception(sense_key::NOT_READY, asc::MEDIUM_NOT_PRESENT);
}
// Set 18 bytes including extended sense data

View File

@ -17,7 +17,7 @@
#include "dispatcher.h"
#include <string>
class PrimaryDevice: public ScsiPrimaryCommands, public Device
class PrimaryDevice: private ScsiPrimaryCommands, public Device
{
public:

View File

@ -20,7 +20,7 @@ void scsi_command_util::ModeSelect(const vector<int>& cdb, const vector<BYTE>& b
// PF
if (!(cdb[1] & 0x10)) {
// Vendor-specific parameters (SCSI-1) are not supported
throw scsi_error_exception(sense_key::ILLEGAL_REQUEST, asc::INVALID_FIELD_IN_PARAMETER_LIST);
throw scsi_exception(sense_key::ILLEGAL_REQUEST, asc::INVALID_FIELD_IN_PARAMETER_LIST);
}
bool has_valid_page_code = false;
@ -33,7 +33,7 @@ void scsi_command_util::ModeSelect(const vector<int>& cdb, const vector<BYTE>& b
buf[11] != (BYTE)sector_size) {
// See below for details
LOGWARN("In order to change the sector size use the -b option when launching rascsi")
throw scsi_error_exception(sense_key::ILLEGAL_REQUEST, asc::INVALID_FIELD_IN_PARAMETER_LIST);
throw scsi_exception(sense_key::ILLEGAL_REQUEST, asc::INVALID_FIELD_IN_PARAMETER_LIST);
}
offset += 12;
@ -52,7 +52,7 @@ void scsi_command_util::ModeSelect(const vector<int>& cdb, const vector<BYTE>& b
// With rascsi it is not possible to permanently (by formatting) change the sector size,
// because the size is an externally configurable setting only
LOGWARN("In order to change the sector size use the -b option when launching rascsi")
throw scsi_error_exception(sense_key::ILLEGAL_REQUEST, asc::INVALID_FIELD_IN_PARAMETER_LIST);
throw scsi_exception(sense_key::ILLEGAL_REQUEST, asc::INVALID_FIELD_IN_PARAMETER_LIST);
}
has_valid_page_code = true;
@ -68,7 +68,7 @@ void scsi_command_util::ModeSelect(const vector<int>& cdb, const vector<BYTE>& b
}
if (!has_valid_page_code) {
throw scsi_error_exception(sense_key::ILLEGAL_REQUEST, asc::INVALID_FIELD_IN_PARAMETER_LIST);
throw scsi_exception(sense_key::ILLEGAL_REQUEST, asc::INVALID_FIELD_IN_PARAMETER_LIST);
}
}

View File

@ -21,9 +21,6 @@
// following link:
// - https://github.com/akuker/RASCSI/wiki/Dayna-Port-SCSI-Link
//
// This does NOT include the file system functionality that is present
// in the Sharp X68000 host bridge.
//
// Note: This requires a DaynaPort SCSI Link driver.
//---------------------------------------------------------------------------
@ -133,12 +130,11 @@ vector<byte> SCSIDaynaPort::InquiryInternal() const
int SCSIDaynaPort::Read(const vector<int>& cdb, vector<BYTE>& buf, uint64_t)
{
int rx_packet_size = 0;
auto response = (scsi_resp_read_t*)buf.data();
const auto response = (scsi_resp_read_t*)buf.data();
int requested_length = cdb[4];
const int requested_length = cdb[4];
LOGTRACE("%s Read maximum length %d, (%04X)", __PRETTY_FUNCTION__, requested_length, requested_length)
// At host startup, it will send a READ(6) command with a length of 1. We should
// respond by going into the status mode with a code of 0x02
if (requested_length == 1) {
@ -207,8 +203,7 @@ int SCSIDaynaPort::Read(const vector<int>& cdb, vector<BYTE>& buf, uint64_t)
// If there are pending packets to be processed, we'll tell the host that the read
// length was 0.
if (!m_tap.PendingPackets())
{
if (!m_tap.PendingPackets()) {
response->length = 0;
response->flags = read_data_flags_t::e_no_more_data;
return DAYNAPORT_READ_HEADER_SZ;
@ -252,8 +247,8 @@ int SCSIDaynaPort::WriteCheck(uint64_t)
{
CheckReady();
if (!m_bTapEnable){
throw scsi_error_exception(sense_key::UNIT_ATTENTION, asc::MEDIUM_NOT_PRESENT);
if (!m_bTapEnable) {
throw scsi_exception(sense_key::UNIT_ATTENTION, asc::MEDIUM_NOT_PRESENT);
}
return 1;
@ -279,22 +274,20 @@ int SCSIDaynaPort::WriteCheck(uint64_t)
//---------------------------------------------------------------------------
bool SCSIDaynaPort::WriteBytes(const vector<int>& cdb, const vector<BYTE>& buf, uint64_t)
{
int data_format = cdb[5];
const int data_format = cdb[5];
int data_length = GetInt16(cdb, 3);
if (data_format == 0x00){
if (data_format == 0x00) {
m_tap.Send(buf.data(), data_length);
LOGTRACE("%s Transmitted %u bytes (00 format)", __PRETTY_FUNCTION__, data_length)
}
else if (data_format == 0x80){
else if (data_format == 0x80) {
// The data length is specified in the first 2 bytes of the payload
data_length=buf[1] + (buf[0] << 8);
data_length = buf[1] + (((int)buf[0] & 0xff) << 8);
m_tap.Send(&(buf.data()[4]), data_length);
LOGTRACE("%s Transmitted %u bytes (80 format)", __PRETTY_FUNCTION__, data_length)
}
else
{
// LOGWARN("%s Unknown data format %02X", __PRETTY_FUNCTION__, (unsigned int)command->format)
else {
LOGWARN("%s Unknown data format %02X", __PRETTY_FUNCTION__, data_format)
}
@ -321,45 +314,7 @@ int SCSIDaynaPort::RetrieveStats(const vector<int>& cdb, vector<BYTE>& buf) cons
{
memcpy(buf.data(), &m_scsi_link_stats, sizeof(m_scsi_link_stats));
return (int)min(sizeof(m_scsi_link_stats), (size_t)GetInt16(cdb, 4));
}
//---------------------------------------------------------------------------
//
// Enable or Disable the interface
//
// Command: 0e 00 00 00 00 XX (XX = 80 or 00)
// Function: Enable (80) / disable (00) Ethernet interface
// Type: No data transferred
// Notes: After issuing an Enable, the initiator should avoid sending
// any subsequent commands to the device for approximately 0.5
// seconds
//
//---------------------------------------------------------------------------
bool SCSIDaynaPort::EnableInterface(const vector<int>& cdb)
{
bool result;
if (cdb[5] & 0x80) {
result = m_tap.Enable();
if (result) {
LOGINFO("The DaynaPort interface has been ENABLED.")
}
else{
LOGWARN("Unable to enable the DaynaPort Interface")
}
m_tap.Flush();
}
else {
result = m_tap.Disable();
if (result) {
LOGINFO("The DaynaPort interface has been DISABLED.")
}
else{
LOGWARN("Unable to disable the DaynaPort Interface")
}
}
return result;
return (int)min(sizeof(m_scsi_link_stats), (size_t)GetInt16(cdb, 3));
}
void SCSIDaynaPort::TestUnitReady()
@ -371,14 +326,14 @@ void SCSIDaynaPort::TestUnitReady()
void SCSIDaynaPort::Read6()
{
// Get record number and block number
uint32_t record = GetInt24(ctrl->cmd, 1) & 0x1fffff;
const uint32_t record = GetInt24(ctrl->cmd, 1) & 0x1fffff;
ctrl->blocks=1;
// If any commands have a bogus control value, they were probably not
// generated by the DaynaPort driver so ignore them
if (ctrl->cmd[5] != 0xc0 && ctrl->cmd[5] != 0x80) {
LOGTRACE("%s Control value %d, (%04X), returning invalid CDB", __PRETTY_FUNCTION__, ctrl->cmd[5], ctrl->cmd[5])
throw scsi_error_exception(sense_key::ILLEGAL_REQUEST, asc::INVALID_FIELD_IN_CDB);
throw scsi_exception(sense_key::ILLEGAL_REQUEST, asc::INVALID_FIELD_IN_CDB);
}
LOGTRACE("%s READ(6) command record=%d blocks=%d", __PRETTY_FUNCTION__, record, ctrl->blocks)
@ -397,7 +352,7 @@ void SCSIDaynaPort::Write6()
// Ensure a sufficient buffer size (because it is not transfer for each block)
controller->AllocateBuffer(DAYNAPORT_BUFFER_SIZE);
int data_format = ctrl->cmd[5];
const int data_format = ctrl->cmd[5];
if (data_format == 0x00) {
ctrl->length = GetInt16(ctrl->cmd, 3);
@ -411,7 +366,7 @@ void SCSIDaynaPort::Write6()
LOGTRACE("%s length: $%04X (%d) format: $%02X", __PRETTY_FUNCTION__, ctrl->length, ctrl->length, data_format)
if (ctrl->length <= 0) {
throw scsi_error_exception();
throw scsi_exception();
}
// Set next block
@ -478,10 +433,12 @@ void SCSIDaynaPort::SetInterfaceMode()
case CMD_SCSILINK_ENABLE:
case CMD_SCSILINK_SET:
LOGWARN("%s Unsupported SetInterface command received: %02X", __PRETTY_FUNCTION__, ctrl->cmd[5])
throw scsi_exception();
break;
default:
LOGWARN("%s Unknown SetInterface command received: %02X", __PRETTY_FUNCTION__, ctrl->cmd[5])
throw scsi_exception();
break;
}
}
@ -492,16 +449,45 @@ void SCSIDaynaPort::SetMcastAddr()
if (ctrl->length == 0) {
LOGWARN("%s Not supported SetMcastAddr Command %02X", __PRETTY_FUNCTION__, ctrl->cmd[2])
throw scsi_error_exception();
throw scsi_exception();
}
EnterDataOutPhase();
}
//---------------------------------------------------------------------------
//
// Enable or Disable the interface
//
// Command: 0e 00 00 00 00 XX (XX = 80 or 00)
// Function: Enable (80) / disable (00) Ethernet interface
// Type: No data transferred
// Notes: After issuing an Enable, the initiator should avoid sending
// any subsequent commands to the device for approximately 0.5
// seconds
//
//---------------------------------------------------------------------------
void SCSIDaynaPort::EnableInterface()
{
if (!EnableInterface(ctrl->cmd)) {
throw scsi_error_exception();
if (ctrl->cmd[5] & 0x80) {
if (!m_tap.Enable()) {
LOGWARN("Unable to enable the DaynaPort Interface")
throw scsi_exception();
}
m_tap.Flush();
LOGINFO("The DaynaPort interface has been ENABLED")
}
else {
if (!m_tap.Disable()) {
LOGWARN("Unable to disable the DaynaPort Interface")
throw scsi_exception();
}
LOGINFO("The DaynaPort interface has been DISABLED")
}
EnterStatusPhase();

View File

@ -41,7 +41,7 @@
// DaynaPort SCSI Link
//
//===========================================================================
class SCSIDaynaPort final : public Disk
class SCSIDaynaPort : public Disk
{
public:
@ -58,7 +58,6 @@ public:
int WriteCheck(uint64_t block) override;
int RetrieveStats(const vector<int>&, vector<BYTE>&) const;
bool EnableInterface(const vector<int>&);
void TestUnitReady() override;
void Read6() override;
@ -88,9 +87,10 @@ public:
// The READ response has a header which consists of:
// 2 bytes - payload size
// 4 bytes - status flags
static const DWORD DAYNAPORT_READ_HEADER_SZ = 2 + 4;
static const uint32_t DAYNAPORT_READ_HEADER_SZ = 2 + 4;
private:
using super = Disk;
Dispatcher<SCSIDaynaPort> dispatcher;

View File

@ -107,13 +107,13 @@ void SCSIBR::TestUnitReady()
int SCSIBR::GetMessage10(const vector<int>& cdb, vector<BYTE>& buf)
{
// Type
int type = cdb[2];
const int type = cdb[2];
// Function number
int func = cdb[3];
const int func = cdb[3];
// Phase
int phase = cdb[9];
const int phase = cdb[9];
switch (type) {
case 1: // Ethernet
@ -195,16 +195,16 @@ int SCSIBR::GetMessage10(const vector<int>& cdb, vector<BYTE>& buf)
bool SCSIBR::WriteBytes(const vector<int>& cdb, vector<BYTE>& buf, uint64_t)
{
// Type
int type = cdb[2];
const int type = cdb[2];
// Function number
int func = cdb[3];
const int func = cdb[3];
// Phase
int phase = cdb[9];
const int phase = cdb[9];
// Get the number of lights
int len = GetInt24(cdb, 6);
const int len = GetInt24(cdb, 6);
switch (type) {
case 1: // Ethernet
@ -257,7 +257,7 @@ void SCSIBR::GetMessage10()
ctrl->length = GetMessage10(ctrl->cmd, controller->GetBuffer());
if (ctrl->length <= 0) {
throw scsi_error_exception();
throw scsi_exception();
}
// Set next block
@ -278,7 +278,7 @@ void SCSIBR::SendMessage10()
{
ctrl->length = GetInt24(ctrl->cmd, 6);
if (ctrl->length <= 0) {
throw scsi_error_exception();
throw scsi_exception();
}
// Ensure a sufficient buffer size (because it is not a transfer for each block)
@ -368,8 +368,8 @@ void SCSIBR::FS_InitDevice(vector<BYTE>& buf)
void SCSIBR::FS_CheckDir(vector<BYTE>& buf)
{
auto dp = (uint32_t*)buf.data();
uint32_t nUnit = ntohl(*dp);
int i = sizeof(uint32_t);
const uint32_t nUnit = ntohl(*dp);
const int i = sizeof(uint32_t);
const auto pNamests = (Human68k::namests_t*)&(buf.data()[i]);
@ -384,8 +384,8 @@ void SCSIBR::FS_CheckDir(vector<BYTE>& buf)
void SCSIBR::FS_MakeDir(vector<BYTE>& buf)
{
auto dp = (uint32_t*)buf.data();
uint32_t nUnit = ntohl(*dp);
int i = sizeof(uint32_t);
const uint32_t nUnit = ntohl(*dp);
const int i = sizeof(uint32_t);
const auto pNamests = (Human68k::namests_t*)&(buf.data()[i]);
@ -400,8 +400,8 @@ void SCSIBR::FS_MakeDir(vector<BYTE>& buf)
void SCSIBR::FS_RemoveDir(vector<BYTE>& buf)
{
auto dp = (uint32_t*)buf.data();
uint32_t nUnit = ntohl(*dp);
int i = sizeof(uint32_t);
const uint32_t nUnit = ntohl(*dp);
const int i = sizeof(uint32_t);
const auto pNamests = (Human68k::namests_t*)&(buf.data()[i]);
@ -416,7 +416,7 @@ void SCSIBR::FS_RemoveDir(vector<BYTE>& buf)
void SCSIBR::FS_Rename(vector<BYTE>& buf)
{
auto dp = (uint32_t*)buf.data();
uint32_t nUnit = ntohl(*dp);
const uint32_t nUnit = ntohl(*dp);
int i = sizeof(uint32_t);
const auto pNamests = (Human68k::namests_t*)&(buf.data()[i]);
@ -435,8 +435,8 @@ void SCSIBR::FS_Rename(vector<BYTE>& buf)
void SCSIBR::FS_Delete(vector<BYTE>& buf)
{
auto dp = (uint32_t*)buf.data();
uint32_t nUnit = ntohl(*dp);
int i = sizeof(uint32_t);
const uint32_t nUnit = ntohl(*dp);
const int i = sizeof(uint32_t);
const auto *pNamests = (Human68k::namests_t*)&(buf.data()[i]);
@ -451,7 +451,7 @@ void SCSIBR::FS_Delete(vector<BYTE>& buf)
void SCSIBR::FS_Attribute(vector<BYTE>& buf)
{
auto dp = (uint32_t*)buf.data();
uint32_t nUnit = ntohl(*dp);
const uint32_t nUnit = ntohl(*dp);
int i = sizeof(uint32_t);
const auto pNamests = (Human68k::namests_t*)&(buf.data()[i]);
@ -471,11 +471,11 @@ void SCSIBR::FS_Attribute(vector<BYTE>& buf)
void SCSIBR::FS_Files(vector<BYTE>& buf)
{
auto dp = (uint32_t*)buf.data();
uint32_t nUnit = ntohl(*dp);
const uint32_t nUnit = ntohl(*dp);
int i = sizeof(uint32_t);
dp = (uint32_t*)&(buf.data()[i]);
uint32_t nKey = ntohl(*dp);
const uint32_t nKey = ntohl(*dp);
i += sizeof(uint32_t);
const auto pNamests = (Human68k::namests_t*)&(buf.data()[i]);
@ -512,11 +512,11 @@ void SCSIBR::FS_Files(vector<BYTE>& buf)
void SCSIBR::FS_NFiles(vector<BYTE>& buf)
{
auto dp = (uint32_t*)buf.data();
uint32_t nUnit = ntohl(*dp);
const uint32_t nUnit = ntohl(*dp);
int i = sizeof(uint32_t);
dp = (uint32_t*)&(buf.data()[i]);
uint32_t nKey = ntohl(*dp);
const uint32_t nKey = ntohl(*dp);
i += sizeof(uint32_t);
auto files = (Human68k::files_t*)&(buf.data()[i]);
@ -550,11 +550,11 @@ void SCSIBR::FS_NFiles(vector<BYTE>& buf)
void SCSIBR::FS_Create(vector<BYTE>& buf)
{
auto dp = (uint32_t*)buf.data();
uint32_t nUnit = ntohl(*dp);
const uint32_t nUnit = ntohl(*dp);
int i = sizeof(uint32_t);
dp = (uint32_t*)&(buf.data()[i]);
uint32_t nKey = ntohl(*dp);
const uint32_t nKey = ntohl(*dp);
i += sizeof(uint32_t);
const auto pNamests = (Human68k::namests_t*)&(buf.data()[i]);
@ -564,11 +564,11 @@ void SCSIBR::FS_Create(vector<BYTE>& buf)
i += sizeof(Human68k::fcb_t);
dp = (uint32_t*)&(buf.data()[i]);
uint32_t nAttribute = ntohl(*dp);
const uint32_t nAttribute = ntohl(*dp);
i += sizeof(uint32_t);
auto bp = (int*)&(buf.data()[i]);
uint32_t bForce = ntohl(*bp);
const uint32_t bForce = ntohl(*bp);
pFcb->fileptr = ntohl(pFcb->fileptr);
pFcb->mode = ntohs(pFcb->mode);
@ -599,11 +599,11 @@ void SCSIBR::FS_Create(vector<BYTE>& buf)
void SCSIBR::FS_Open(vector<BYTE>& buf)
{
auto dp = (uint32_t*)buf.data();
uint32_t nUnit = ntohl(*dp);
const uint32_t nUnit = ntohl(*dp);
int i = sizeof(uint32_t);
dp = (uint32_t*)&(buf.data()[i]);
uint32_t nKey = ntohl(*dp);
const uint32_t nKey = ntohl(*dp);
i += sizeof(uint32_t);
const auto pNamests = (Human68k::namests_t*)&(buf.data()[i]);
@ -640,11 +640,11 @@ void SCSIBR::FS_Open(vector<BYTE>& buf)
void SCSIBR::FS_Close(vector<BYTE>& buf)
{
auto dp = (uint32_t*)buf.data();
uint32_t nUnit = ntohl(*dp);
const uint32_t nUnit = ntohl(*dp);
int i = sizeof(uint32_t);
dp = (uint32_t*)&(buf.data()[i]);
uint32_t nKey = ntohl(*dp);
const uint32_t nKey = ntohl(*dp);
i += sizeof(uint32_t);
auto pFcb = (Human68k::fcb_t*)&(buf.data()[i]);
@ -678,14 +678,14 @@ void SCSIBR::FS_Close(vector<BYTE>& buf)
void SCSIBR::FS_Read(vector<BYTE>& buf)
{
auto dp = (uint32_t*)buf.data();
uint32_t nKey = ntohl(*dp);
const uint32_t nKey = ntohl(*dp);
int i = sizeof(uint32_t);
auto pFcb = (Human68k::fcb_t*)&(buf.data()[i]);
i += sizeof(Human68k::fcb_t);
dp = (uint32_t*)&(buf.data()[i]);
uint32_t nSize = ntohl(*dp);
const uint32_t nSize = ntohl(*dp);
pFcb->fileptr = ntohl(pFcb->fileptr);
pFcb->mode = ntohs(pFcb->mode);
@ -718,14 +718,14 @@ void SCSIBR::FS_Read(vector<BYTE>& buf)
void SCSIBR::FS_Write(vector<BYTE>& buf)
{
auto dp = (uint32_t*)buf.data();
uint32_t nKey = ntohl(*dp);
const uint32_t nKey = ntohl(*dp);
int i = sizeof(uint32_t);
auto pFcb = (Human68k::fcb_t*)&(buf.data()[i]);
i += sizeof(Human68k::fcb_t);
dp = (uint32_t*)&(buf.data()[i]);
uint32_t nSize = ntohl(*dp);
const uint32_t nSize = ntohl(*dp);
pFcb->fileptr = ntohl(pFcb->fileptr);
pFcb->mode = ntohs(pFcb->mode);
@ -756,14 +756,14 @@ void SCSIBR::FS_Write(vector<BYTE>& buf)
void SCSIBR::FS_Seek(vector<BYTE>& buf)
{
auto dp = (uint32_t*)buf.data();
uint32_t nKey = ntohl(*dp);
const uint32_t nKey = ntohl(*dp);
int i = sizeof(uint32_t);
auto pFcb = (Human68k::fcb_t*)&(buf.data()[i]);
i += sizeof(Human68k::fcb_t);
dp = (uint32_t*)&(buf.data()[i]);
uint32_t nMode = ntohl(*dp);
const uint32_t nMode = ntohl(*dp);
i += sizeof(uint32_t);
auto ip = (const int*)&(buf.data()[i]);
@ -798,11 +798,11 @@ void SCSIBR::FS_Seek(vector<BYTE>& buf)
void SCSIBR::FS_TimeStamp(vector<BYTE>& buf)
{
auto dp = (uint32_t*)buf.data();
uint32_t nUnit = ntohl(*dp);
const uint32_t nUnit = ntohl(*dp);
int i = sizeof(uint32_t);
dp = (uint32_t*)&(buf.data()[i]);
uint32_t nKey = ntohl(*dp);
const uint32_t nKey = ntohl(*dp);
i += sizeof(uint32_t);
auto pFcb = (Human68k::fcb_t*)&(buf.data()[i]);
@ -840,7 +840,7 @@ void SCSIBR::FS_TimeStamp(vector<BYTE>& buf)
void SCSIBR::FS_GetCapacity(vector<BYTE>& buf)
{
auto dp = (uint32_t*)buf.data();
uint32_t nUnit = ntohl(*dp);
const uint32_t nUnit = ntohl(*dp);
Human68k::capacity_t cap;
fsresult = fs.GetCapacity(nUnit, &cap);
@ -862,8 +862,8 @@ void SCSIBR::FS_GetCapacity(vector<BYTE>& buf)
void SCSIBR::FS_CtrlDrive(vector<BYTE>& buf)
{
auto dp = (uint32_t*)buf.data();
uint32_t nUnit = ntohl(*dp);
int i = sizeof(uint32_t);
const uint32_t nUnit = ntohl(*dp);
const int i = sizeof(uint32_t);
auto pCtrlDrive = (Human68k::ctrldrive_t*)&(buf.data()[i]);
@ -881,7 +881,7 @@ void SCSIBR::FS_CtrlDrive(vector<BYTE>& buf)
void SCSIBR::FS_GetDPB(vector<BYTE>& buf)
{
auto dp = (uint32_t*)buf.data();
uint32_t nUnit = ntohl(*dp);
const uint32_t nUnit = ntohl(*dp);
Human68k::dpb_t dpb;
fsresult = fs.GetDPB(nUnit, &dpb);
@ -905,11 +905,11 @@ void SCSIBR::FS_GetDPB(vector<BYTE>& buf)
void SCSIBR::FS_DiskRead(vector<BYTE>& buf)
{
auto dp = (uint32_t*)buf.data();
uint32_t nUnit = ntohl(*dp);
const uint32_t nUnit = ntohl(*dp);
int i = sizeof(uint32_t);
dp = (uint32_t*)&(buf.data()[i]);
uint32_t nSector = ntohl(*dp);
const uint32_t nSector = ntohl(*dp);
i += sizeof(uint32_t);
dp = (uint32_t*)&(buf.data()[i]);
@ -927,7 +927,7 @@ void SCSIBR::FS_DiskRead(vector<BYTE>& buf)
void SCSIBR::FS_DiskWrite(vector<BYTE>& buf)
{
auto dp = (uint32_t*)buf.data();
uint32_t nUnit = ntohl(*dp);
const uint32_t nUnit = ntohl(*dp);
fsresult = fs.DiskWrite(nUnit);
}
@ -940,18 +940,18 @@ void SCSIBR::FS_DiskWrite(vector<BYTE>& buf)
void SCSIBR::FS_Ioctrl(vector<BYTE>& buf)
{
auto dp = (uint32_t*)buf.data();
uint32_t nUnit = ntohl(*dp);
const uint32_t nUnit = ntohl(*dp);
int i = sizeof(uint32_t);
dp = (uint32_t*)&(buf.data()[i]);
uint32_t nFunction = ntohl(*dp);
const uint32_t nFunction = ntohl(*dp);
i += sizeof(uint32_t);
auto pIoctrl = (Human68k::ioctrl_t*)&(buf.data()[i]);
switch (nFunction) {
case 2:
case (DWORD)-2:
case (uint32_t)-2:
pIoctrl->param = htonl(pIoctrl->param);
break;
default:
@ -965,7 +965,7 @@ void SCSIBR::FS_Ioctrl(vector<BYTE>& buf)
pIoctrl->media = htons(pIoctrl->media);
break;
case 1:
case (DWORD)-3:
case (uint32_t)-3:
pIoctrl->param = htonl(pIoctrl->param);
break;
default:
@ -986,7 +986,7 @@ void SCSIBR::FS_Ioctrl(vector<BYTE>& buf)
void SCSIBR::FS_Flush(vector<BYTE>& buf)
{
auto dp = (uint32_t*)buf.data();
uint32_t nUnit = ntohl(*dp);
const uint32_t nUnit = ntohl(*dp);
fsresult = fs.Flush(nUnit);
}
@ -999,7 +999,7 @@ void SCSIBR::FS_Flush(vector<BYTE>& buf)
void SCSIBR::FS_CheckMedia(vector<BYTE>& buf)
{
auto dp = (uint32_t*)buf.data();
uint32_t nUnit = ntohl(*dp);
const uint32_t nUnit = ntohl(*dp);
fsresult = fs.CheckMedia(nUnit);
}
@ -1012,7 +1012,7 @@ void SCSIBR::FS_CheckMedia(vector<BYTE>& buf)
void SCSIBR::FS_Lock(vector<BYTE>& buf)
{
auto dp = (uint32_t*)buf.data();
uint32_t nUnit = ntohl(*dp);
const uint32_t nUnit = ntohl(*dp);
fsresult = fs.Lock(nUnit);
}

View File

@ -26,7 +26,7 @@
using namespace std;
class SCSIBR final : public Disk
class SCSIBR : public Disk
{
static constexpr const array<BYTE, 6> bcast_addr = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
@ -99,9 +99,9 @@ private:
void FS_Lock(vector<BYTE>&); // $58 - get exclusive control
CFileSys fs; // File system accessor
DWORD fsresult = 0; // File system access result code
uint32_t fsresult = 0; // File system access result code
array<BYTE, 0x800> fsout; // File system access result buffer
DWORD fsoutlen = 0; // File system access result buffer size
uint32_t fsoutlen = 0; // File system access result buffer size
array<BYTE, 0x1000000> fsopt; // File system access buffer
DWORD fsoptlen = 0; // File system access buffer size
uint32_t fsoptlen = 0; // File system access buffer size
};

View File

@ -145,7 +145,7 @@ void SCSIPrinter::Print()
{
CheckReservation();
uint32_t length = GetInt24(ctrl->cmd, 2);
const uint32_t length = GetInt24(ctrl->cmd, 2);
LOGTRACE("Receiving %d byte(s) to be printed", length)
@ -153,7 +153,7 @@ void SCSIPrinter::Print()
LOGERROR("%s", ("Transfer buffer overflow: Buffer size is " + to_string(controller->GetBuffer().size()) +
" bytes, " + to_string(length) + " bytes expected").c_str())
throw scsi_error_exception(sense_key::ILLEGAL_REQUEST, asc::INVALID_FIELD_IN_CDB);
throw scsi_exception(sense_key::ILLEGAL_REQUEST, asc::INVALID_FIELD_IN_CDB);
}
ctrl->length = length;
@ -167,11 +167,11 @@ void SCSIPrinter::SynchronizeBuffer()
CheckReservation();
if (fd == -1) {
throw scsi_error_exception();
throw scsi_exception();
}
// Make the file readable for the lp user
fchmod(fd, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
fchmod(fd, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH); //NOSONAR Granting permissions to "others" is required here
struct stat st;
fstat(fd, &st);
@ -180,7 +180,7 @@ void SCSIPrinter::SynchronizeBuffer()
fd = -1;
string cmd = GetParam("cmd");
size_t file_position = cmd.find("%f");
const size_t file_position = cmd.find("%f");
assert(file_position != string::npos);
cmd.replace(file_position, 2, filename);
cmd = "sudo -u lp " + cmd;
@ -194,7 +194,7 @@ void SCSIPrinter::SynchronizeBuffer()
unlink(filename);
throw scsi_error_exception();
throw scsi_exception();
}
unlink(filename);
@ -217,7 +217,7 @@ void SCSIPrinter::StopPrint()
bool SCSIPrinter::WriteByteSequence(vector<BYTE>& buf, uint32_t length)
{
if (fd == -1) {
strcpy(filename, TMP_FILE_PATTERN);
strcpy(filename, TMP_FILE_PATTERN); //NOSONAR Using strcpy is safe here
fd = mkstemp(filename);
if (fd == -1) {
LOGERROR("Can't create printer output file '%s': %s", filename, strerror(errno))
@ -229,7 +229,7 @@ bool SCSIPrinter::WriteByteSequence(vector<BYTE>& buf, uint32_t length)
LOGTRACE("Appending %d byte(s) to printer output file '%s'", length, filename)
auto num_written = (uint32_t)write(fd, buf.data(), length);
const auto num_written = (uint32_t)write(fd, buf.data(), length);
return num_written == length;
}
@ -248,7 +248,7 @@ void SCSIPrinter::CheckReservation()
LOGTRACE("Unknown initiator tries to access reserved device ID %d, LUN %d", GetId(), GetLun())
}
throw scsi_error_exception(sense_key::ABORTED_COMMAND, asc::NO_ADDITIONAL_SENSE_INFORMATION,
throw scsi_exception(sense_key::ABORTED_COMMAND, asc::NO_ADDITIONAL_SENSE_INFORMATION,
status::RESERVATION_CONFLICT);
}

View File

@ -15,9 +15,9 @@
#include <string>
#include <unordered_map>
class SCSIPrinter final : public PrimaryDevice, public ScsiPrinterCommands //NOSONAR Custom destructor cannot be removed
class SCSIPrinter : public PrimaryDevice, ScsiPrinterCommands //NOSONAR Custom destructor cannot be removed
{
static constexpr const char *TMP_FILE_PATTERN = "/tmp/rascsi_sclp-XXXXXX";
static constexpr const char *TMP_FILE_PATTERN = "/tmp/rascsi_sclp-XXXXXX"; //NOSONAR Using /tmp is safe
static const int TMP_FILENAME_LENGTH = string_view(TMP_FILE_PATTERN).size();
static const int NOT_RESERVED = -2;

View File

@ -90,7 +90,7 @@ void SCSICD::Open(const Filepath& path)
assert(GetBlockCount() > 0);
super::Open(path);
FileSupport::SetPath(path);
SetPath(path);
SetUpCache(path, 0, rawfile);
@ -100,7 +100,7 @@ void SCSICD::Open(const Filepath& path)
}
}
void SCSICD::OpenCue(const Filepath& /*path*/) const
void SCSICD::OpenCue(const Filepath&) const
{
throw io_exception("Opening CUE CD-ROM files is not supported");
}
@ -114,7 +114,7 @@ void SCSICD::OpenIso(const Filepath& path)
}
// Get file size
off_t size = fio.GetFileSize();
const off_t size = fio.GetFileSize();
if (size < 0x800) {
fio.Close();
throw io_exception("ISO CD-ROM file size must be at least 2048 bytes");
@ -160,10 +160,10 @@ void SCSICD::OpenIso(const Filepath& path)
}
// Set the number of blocks
SetBlockCount((DWORD)(size / 0x930));
SetBlockCount((uint32_t)(size / 0x930));
} else {
// Set the number of blocks
SetBlockCount((DWORD)(size >> GetSectorSizeShiftCount()));
SetBlockCount((uint32_t)(size >> GetSectorSizeShiftCount()));
}
// Create only one data track
@ -197,7 +197,7 @@ void SCSICD::OpenPhysical(const Filepath& path)
size = (size / 512) * 512;
// Set the number of blocks
SetBlockCount((DWORD)(size >> GetSectorSizeShiftCount()));
SetBlockCount((uint32_t)(size >> GetSectorSizeShiftCount()));
// Create only one data track
assert(!tracks.size());
@ -275,11 +275,11 @@ int SCSICD::Read(const vector<int>& cdb, vector<BYTE>& buf, uint64_t block)
CheckReady();
// Search for the track
int index = SearchTrack((int)block);
const int index = SearchTrack((int)block);
// If invalid, out of range
if (index < 0) {
throw scsi_error_exception(sense_key::ILLEGAL_REQUEST, asc::LBA_OUT_OF_RANGE);
throw scsi_exception(sense_key::ILLEGAL_REQUEST, asc::LBA_OUT_OF_RANGE);
}
assert(tracks[index]);
@ -315,17 +315,17 @@ int SCSICD::ReadTocInternal(const vector<int>& cdb, vector<BYTE>& buf)
assert(tracks[0]);
// Get allocation length, clear buffer
int length = GetInt16(cdb, 7);
const int length = GetInt16(cdb, 7);
fill_n(buf.data(), length, 0);
// Get MSF Flag
bool msf = cdb[1] & 0x02;
const bool msf = cdb[1] & 0x02;
// Get and check the last track number
int last = tracks[tracks.size() - 1]->GetTrackNo();
const int last = tracks[tracks.size() - 1]->GetTrackNo();
// Except for AA
if (cdb[6] > last && cdb[6] != 0xaa) {
throw scsi_error_exception(sense_key::ILLEGAL_REQUEST, asc::INVALID_FIELD_IN_CDB);
throw scsi_exception(sense_key::ILLEGAL_REQUEST, asc::INVALID_FIELD_IN_CDB);
}
// Check start index
@ -358,12 +358,12 @@ int SCSICD::ReadTocInternal(const vector<int>& cdb, vector<BYTE>& buf)
}
// Otherwise, error
throw scsi_error_exception(sense_key::ILLEGAL_REQUEST, asc::INVALID_FIELD_IN_CDB);
throw scsi_exception(sense_key::ILLEGAL_REQUEST, asc::INVALID_FIELD_IN_CDB);
}
}
// Number of track descriptors returned this time (number of loops)
int loop = last - tracks[index]->GetTrackNo() + 1;
const int loop = last - tracks[index]->GetTrackNo() + 1;
assert(loop >= 1);
// Create header
@ -407,11 +407,11 @@ void SCSICD::GetEventStatusNotification()
{
if (!(ctrl->cmd[1] & 0x01)) {
// Asynchronous notification is optional and not supported by rascsi
throw scsi_error_exception(sense_key::ILLEGAL_REQUEST, asc::INVALID_FIELD_IN_CDB);
throw scsi_exception(sense_key::ILLEGAL_REQUEST, asc::INVALID_FIELD_IN_CDB);
}
LOGTRACE("Received request for event polling, which is currently not supported")
throw scsi_error_exception(sense_key::ILLEGAL_REQUEST, asc::INVALID_FIELD_IN_CDB);
throw scsi_exception(sense_key::ILLEGAL_REQUEST, asc::INVALID_FIELD_IN_CDB);
}
//---------------------------------------------------------------------------
@ -424,7 +424,7 @@ void SCSICD::LBAtoMSF(uint32_t lba, BYTE *msf) const
// 75 and 75*60 get the remainder
uint32_t m = lba / (75 * 60);
uint32_t s = lba % (75 * 60);
uint32_t f = s % 75;
const uint32_t f = s % 75;
s /= 75;
// The base point is M=0, S=2, F=0
@ -459,7 +459,7 @@ void SCSICD::ClearTrack()
// * Returns -1 if not found
//
//---------------------------------------------------------------------------
int SCSICD::SearchTrack(DWORD lba) const
int SCSICD::SearchTrack(uint32_t lba) const
{
// Track loop
for (size_t i = 0; i < tracks.size(); i++) {

View File

@ -10,20 +10,16 @@
// Licensed under the BSD 3-Clause License.
// See LICENSE file in the project root folder.
//
// [ SCSI CD-ROM ]
//
//---------------------------------------------------------------------------
#pragma once
#include "disk.h"
#include "filepath.h"
#include "cd_track.h"
#include "file_support.h"
#include "disk.h"
#include "interfaces/scsi_mmc_commands.h"
#include "interfaces/scsi_primary_commands.h"
class SCSICD : public Disk, public ScsiMmcCommands, public FileSupport
class SCSICD : public Disk, private ScsiMmcCommands
{
public:
@ -68,7 +64,7 @@ private:
// Track management
void ClearTrack(); // Clear the track
int SearchTrack(DWORD lba) const; // Track search
int SearchTrack(uint32_t lba) const; // Track search
vector<unique_ptr<CDTrack>> tracks; // Track opbject references
int dataindex = -1; // Current data track
int audioindex = -1; // Current audio track

View File

@ -40,13 +40,13 @@ void SCSIHD::FinalizeSetup(const Filepath &path, off_t size, off_t image_offset)
uint64_t capacity = GetBlockCount() * GetSectorSizeInBytes();
string unit;
// 10 GiB and more
if (capacity >= 1099511627776) {
capacity /= 1099511627776;
if (capacity >= 1'099'511'627'776) {
capacity /= 1'099'511'627'776;
unit = "GiB";
}
// 1 MiB and more
else if (capacity >= 1048576) {
capacity /= 1048576;
else if (capacity >= 1'048'576) {
capacity /= 1'048'576;
unit = "MiB";
}
else {
@ -62,8 +62,8 @@ void SCSIHD::FinalizeSetup(const Filepath &path, off_t size, off_t image_offset)
SetProtectable(true);
SetProtected(false);
Disk::Open(path);
FileSupport::SetPath(path);
super::Open(path);
SetPath(path);
SetUpCache(path, image_offset);
}
@ -84,7 +84,7 @@ void SCSIHD::Open(const Filepath& path)
// Sector size (default 512 bytes) and number of blocks
SetSectorSizeInBytes(GetConfiguredSectorSize() ? GetConfiguredSectorSize() : 512);
SetBlockCount((DWORD)(size >> GetSectorSizeShiftCount()));
SetBlockCount((uint32_t)(size >> GetSectorSizeShiftCount()));
// Effective size must be a multiple of the sector size
size = (size / GetSectorSizeInBytes()) * GetSectorSizeInBytes();

View File

@ -17,10 +17,9 @@
#pragma once
#include "disk.h"
#include "file_support.h"
#include "filepath.h"
class SCSIHD : public Disk, public FileSupport
class SCSIHD : public Disk
{
static constexpr const char *DEFAULT_PRODUCT = "SCSI HD";
@ -42,5 +41,7 @@ public:
private:
using super = Disk;
scsi_defs::scsi_level scsi_level;
};

View File

@ -7,7 +7,7 @@
// Copyright (C) 2014-2020 GIMONS
// Copyright (C) akuker
//
// Licensed under the BSD 3-Clause License.
// Licensed under the BSD 3-Clause License.
// See LICENSE file in the project root folder.
//
// [ SCSI NEC "Genuine" Hard Disk]

View File

@ -59,8 +59,8 @@ void SCSIMO::Open(const Filepath& path)
SetProtectable(true);
SetProtected(false);
Disk::Open(path);
FileSupport::SetPath(path);
super::Open(path);
SetPath(path);
SetUpCache(path, 0);

View File

@ -15,12 +15,11 @@
#pragma once
#include "disk.h"
#include "file_support.h"
#include "filepath.h"
using Geometry = pair<uint32_t, uint32_t>;
class SCSIMO : public Disk, public FileSupport
class SCSIMO : public Disk
{
public:
@ -40,6 +39,8 @@ protected:
private:
using super = Disk;
void AddOptionPage(map<int, vector<byte>>&, bool) const;
bool SetGeometryForCapacity(uint64_t);

View File

@ -11,6 +11,7 @@
#include "fileio.h"
#include <fcntl.h>
#include <unistd.h>
#include <cassert>
Fileio::~Fileio()
{
@ -30,7 +31,7 @@ bool Fileio::Open(const char *fname, OpenMode mode, bool directIO)
}
// Default mode
mode_t omode = directIO ? O_DIRECT : 0;
const mode_t omode = directIO ? O_DIRECT : 0;
switch (mode) {
case OpenMode::ReadOnly:
@ -111,10 +112,10 @@ off_t Fileio::GetFileSize() const
assert(handle >= 0);
// Get file position in 64bit
off_t cur = lseek(handle, 0, SEEK_CUR);
const off_t cur = lseek(handle, 0, SEEK_CUR);
// Get file size in64bitで
off_t end = lseek(handle, 0, SEEK_END);
const off_t end = lseek(handle, 0, SEEK_END);
// Return to start position
Seek(cur);

View File

@ -11,7 +11,7 @@
#pragma once
#include "filepath.h"
#include <sys/types.h>
#include <cstdlib>
class Fileio
{

View File

@ -8,11 +8,11 @@
//
//---------------------------------------------------------------------------
#include "os.h"
#include "filepath.h"
#include "config.h"
#include "fileio.h"
#include <libgen.h>
#include <cstdlib>
#include <cstring>
#include <cassert>
Filepath& Filepath::operator=(const Filepath& path)
{
@ -55,7 +55,7 @@ void Filepath::Split()
char *pDir = strdup(m_szPath);
const char *pDirName = dirname(pDir);
char *pBase = strdup(m_szPath);
char *pBaseName = basename(pBase);
const char *pBaseName = basename(pBase);
const char *pExtName = strrchr(pBaseName, '.');
// Transmit

View File

@ -32,7 +32,7 @@ BUS::phase_t GetPhase(const data_capture *sample)
}
// Get target phase from bus signal line
DWORD mci = GetMsg(sample) ? 0x04 : 0x00;
uint32_t mci = GetMsg(sample) ? 0x04 : 0x00;
mci |= GetCd(sample) ? 0x02 : 0x00;
mci |= GetIo(sample) ? 0x01 : 0x00;
return BUS::GetPhase(mci);

View File

@ -16,7 +16,7 @@
using data_capture_t = struct data_capture
{
DWORD data;
uint32_t data;
uint64_t timestamp;
};
@ -34,7 +34,7 @@ inline bool GetReq(const data_capture *sample) { return BUS::GetPinRaw(sample->d
inline bool GetDp(const data_capture *sample) { return BUS::GetPinRaw(sample->data, PIN_DP); }
inline BYTE GetData(const data_capture *sample)
{
DWORD data = sample->data;
uint32_t data = sample->data;
return (BYTE)((data >> (PIN_DT0 - 0)) & (1 << 0)) |
((data >> (PIN_DT1 - 1)) & (1 << 1)) |
((data >> (PIN_DT2 - 2)) & (1 << 2)) |

View File

@ -8,7 +8,6 @@
//
//---------------------------------------------------------------------------
#include <stdio.h>
#include <iostream>
#include <fstream>
#include "os.h"
@ -98,12 +97,12 @@ for (i = 0; i < coll.length; i++) {
)";
static void print_html_data(ofstream& html_fp, const data_capture *data_capture_array, DWORD capture_count)
static void print_html_data(ofstream& html_fp, const data_capture *data_capture_array, uint32_t capture_count)
{
const data_capture *data;
bool prev_data_valid = false;
bool curr_data_valid;
DWORD selected_id = 0;
uint32_t selected_id = 0;
BUS::phase_t prev_phase = BUS::phase_t::busfree;
bool close_row = false;
int data_space_count = 0;
@ -112,34 +111,26 @@ static void print_html_data(ofstream& html_fp, const data_capture *data_capture_
html_fp << "<table>" << endl;
for (DWORD idx = 0; idx < capture_count; idx++)
{
for (uint32_t idx = 0; idx < capture_count; idx++) {
data = &data_capture_array[idx];
curr_data_valid = GetAck(data) && GetReq(data);
BUS::phase_t phase = GetPhase(data);
if (phase == BUS::phase_t::selection && !GetBsy(data))
{
if (phase == BUS::phase_t::selection && !GetBsy(data)) {
selected_id = GetData(data);
}
if (prev_phase != phase)
{
if (close_row)
{
if (collapsible_div_active)
{
if (prev_phase != phase) {
if (close_row) {
if (collapsible_div_active) {
html_fp << "</code></div>";
}
else if (button_active)
{
else if (button_active) {
html_fp << "</code></button>";
}
html_fp << "</td>";
if (data_space_count < 1)
{
if (data_space_count < 1) {
html_fp << "<td>--</td>";
}
else
{
else {
html_fp << "<td>wc: " << std::dec << "(0x" << std::hex << data_space_count << ")</td>";
}
html_fp << "</tr>" << endl;
@ -152,33 +143,27 @@ static void print_html_data(ofstream& html_fp, const data_capture *data_capture_
html_fp << "<td>" << std::hex << selected_id << "</td>";
html_fp << "<td>";
}
if (curr_data_valid && !prev_data_valid)
{
if (data_space_count == 0)
{
if (curr_data_valid && !prev_data_valid) {
if (data_space_count == 0) {
button_active = true;
html_fp << "<button type=\"button\" class=\"collapsible\"><code>";
}
if ((data_space_count % 16) == 0)
{
if ((data_space_count % 16) == 0) {
html_fp << std::hex << data_space_count << ": ";
}
html_fp << fmt::format("{0:02X}", GetData(data));
data_space_count++;
if ((data_space_count % 4) == 0)
{
if ((data_space_count % 4) == 0) {
html_fp << " ";
}
if (data_space_count == 16)
{
if (data_space_count == 16) {
html_fp << "</code></button><div class=\"content\"><code>" << endl;
collapsible_div_active = true;
button_active = false;
}
if (((data_space_count % 16) == 0) && (data_space_count > 17))
{
if (((data_space_count % 16) == 0) && (data_space_count > 17)) {
html_fp << "<br>" << endl;
}
}
@ -187,9 +172,9 @@ static void print_html_data(ofstream& html_fp, const data_capture *data_capture_
}
}
void scsimon_generate_html(const char *filename, const data_capture *data_capture_array, DWORD capture_count)
void scsimon_generate_html(const char *filename, const data_capture *data_capture_array, uint32_t capture_count)
{
LOGINFO("Creating HTML report file (%s)", filename);
LOGINFO("Creating HTML report file (%s)", filename)
ofstream html_ofstream;

View File

@ -19,45 +19,39 @@ using namespace std;
const char timestamp_label[] = "\"timestamp\":\"0x";
const char data_label[] = "\"data\":\"0x";
DWORD scsimon_read_json(const char *json_filename, data_capture *data_capture_array, DWORD max_sz)
uint32_t scsimon_read_json(const char *json_filename, data_capture *data_capture_array, uint32_t max_sz)
{
char str_buf[1024];
FILE *fp = fopen(json_filename, "r");
DWORD sample_count = 0;
uint32_t sample_count = 0;
while (fgets(str_buf, sizeof(str_buf), fp))
{
while (fgets(str_buf, sizeof(str_buf), fp)) {
char timestamp[1024];
char data[1024];
uint64_t timestamp_uint;
uint32_t data_uint;
char *ptr;
const char *timestamp_str;
const char *data_str;
timestamp_str = strstr(str_buf, timestamp_label);
const char *timestamp_str = strstr(str_buf, timestamp_label);
if (!timestamp_str)
continue;
strncpy(timestamp, &timestamp_str[strlen(timestamp_label)], 16);
timestamp[16] = '\0';
timestamp_uint = strtoull(timestamp, &ptr, 16);
data_str = strstr(str_buf, data_label);
const char *data_str = strstr(str_buf, data_label);
if (!data_str)
continue;
strncpy(data, &data_str[strlen(data_label)], 8);
data[8] = '\0';
data_uint = strtoul(data, &ptr, 16);
// printf("Time: %016llX Data: %08X\n", timestamp_uint, data_uint);
data_capture_array[sample_count].timestamp = timestamp_uint;
data_capture_array[sample_count].data = data_uint;
sample_count++;
if (sample_count >= max_sz)
{
LOGWARN("File exceeds maximum buffer size. Some data may be missing.");
LOGWARN("Try re-running the tool with a larger buffer size");
if (sample_count >= max_sz) {
LOGWARN("File exceeds maximum buffer size. Some data may be missing.")
LOGWARN("Try re-running the tool with a larger buffer size")
break;
}
}
@ -74,17 +68,16 @@ DWORD scsimon_read_json(const char *json_filename, data_capture *data_capture_ar
// Generate JSON Output File
//
//---------------------------------------------------------------------------
void scsimon_generate_json(const char *filename, const data_capture *data_capture_array, DWORD capture_count)
void scsimon_generate_json(const char *filename, const data_capture *data_capture_array, uint32_t capture_count)
{
LOGTRACE("Creating JSON file (%s)", filename);
LOGTRACE("Creating JSON file (%s)", filename)
ofstream json_ofstream;
json_ofstream.open(filename, ios::out);
json_ofstream << "[" << endl;
DWORD i = 0;
while (i < capture_count)
{
uint32_t i = 0;
while (i < capture_count) {
json_ofstream << fmt::format("{{\"id\": \"{0:d}\", \"timestamp\":\"{1:#016x}\", \"data\":\"{2:#08x}\"}}", i, data_capture_array[i].timestamp, data_capture_array[i].data);
if (i != (capture_count - 1))

View File

@ -11,8 +11,8 @@
#include "data_sample.h"
DWORD scsimon_read_json(const char *json_filename, data_capture *data_capture_array, DWORD max_sz);
uint32_t scsimon_read_json(const char *json_filename, data_capture *data_capture_array, uint32_t max_sz);
void scsimon_generate_html(const char *filename, const data_capture *data_capture_array, DWORD capture_count);
void scsimon_generate_json(const char *filename, const data_capture *data_capture_array, DWORD capture_count);
void scsimon_generate_value_change_dump(const char *filename, const data_capture *data_capture_array, DWORD capture_count);
void scsimon_generate_html(const char *filename, const data_capture *data_capture_array, uint32_t capture_count);
void scsimon_generate_json(const char *filename, const data_capture *data_capture_array, uint32_t capture_count);
void scsimon_generate_value_change_dump(const char *filename, const data_capture *data_capture_array, uint32_t capture_count);

View File

@ -54,14 +54,14 @@ static BYTE prev_value[32] = {0xFF};
extern double ns_per_loop;
static BYTE get_pin_value(DWORD data, int pin)
static BYTE get_pin_value(uint32_t data, int pin)
{
return (data >> pin) & 1;
}
static BYTE get_data_field(DWORD data)
static BYTE get_data_field(uint32_t data)
{
DWORD data_out =
const uint32_t data_out =
((data >> (PIN_DT0 - 0)) & (1 << 7)) |
((data >> (PIN_DT1 - 1)) & (1 << 6)) |
((data >> (PIN_DT2 - 2)) & (1 << 5)) |
@ -74,31 +74,28 @@ static BYTE get_data_field(DWORD data)
return (BYTE)data_out;
}
static void vcd_output_if_changed_phase(ofstream& fp, DWORD data, int pin, char symbol)
static void vcd_output_if_changed_phase(ofstream& fp, uint32_t data, int pin, char symbol)
{
BUS::phase_t new_value = GPIOBUS::GetPhaseRaw(data);
if (prev_value[pin] != (int)new_value)
{
const BUS::phase_t new_value = GPIOBUS::GetPhaseRaw(data);
if (prev_value[pin] != (int)new_value) {
prev_value[pin] = (int)new_value;
fp << "s" << GPIOBUS::GetPhaseStrRaw(new_value) << " " << symbol << endl;
}
}
static void vcd_output_if_changed_bool(ofstream& fp, DWORD data, int pin, char symbol)
static void vcd_output_if_changed_bool(ofstream& fp, uint32_t data, int pin, char symbol)
{
BYTE new_value = get_pin_value(data, pin);
if (prev_value[pin] != new_value)
{
const BYTE new_value = get_pin_value(data, pin);
if (prev_value[pin] != new_value) {
prev_value[pin] = new_value;
fp << new_value << symbol << endl;
}
}
static void vcd_output_if_changed_byte(ofstream& fp, DWORD data, int pin, char symbol)
static void vcd_output_if_changed_byte(ofstream& fp, uint32_t data, int pin, char symbol)
{
BYTE new_value = get_data_field(data);
if (prev_value[pin] != new_value)
{
const BYTE new_value = get_data_field(data);
if (prev_value[pin] != new_value) {
prev_value[pin] = new_value;
fp << "b"
<< fmt::format("{0:b}", get_pin_value(data, PIN_DT7))
@ -113,9 +110,9 @@ static void vcd_output_if_changed_byte(ofstream& fp, DWORD data, int pin, char s
}
}
void scsimon_generate_value_change_dump(const char *filename, const data_capture *data_capture_array, DWORD capture_count)
void scsimon_generate_value_change_dump(const char *filename, const data_capture *data_capture_array, uint32_t capture_count)
{
LOGTRACE("Creating Value Change Dump file (%s)", filename);
LOGTRACE("Creating Value Change Dump file (%s)", filename)
ofstream vcd_ofstream;
vcd_ofstream.open(filename, ios::out);
@ -126,7 +123,7 @@ void scsimon_generate_value_change_dump(const char *filename, const data_capture
char timestamp[256];
strftime(timestamp, sizeof(timestamp), "%d-%m-%Y %H-%M-%S", timeinfo);
vcd_ofstream
vcd_ofstream
<< "$date" << endl
<< timestamp << endl
<< "$end" << endl
@ -167,9 +164,8 @@ void scsimon_generate_value_change_dump(const char *filename, const data_capture
<< "b00000000 " << SYMBOL_PIN_DAT << endl
<< "$end" << endl;
DWORD i = 0;
while (i < capture_count)
{
uint32_t i = 0;
while (i < capture_count) {
vcd_ofstream << "#" << (uint64_t)(data_capture_array[i].timestamp * ns_per_loop) << endl;
vcd_output_if_changed_bool(vcd_ofstream, data_capture_array[i].data, PIN_BSY, SYMBOL_PIN_BSY);
vcd_output_if_changed_bool(vcd_ofstream, data_capture_array[i].data, PIN_SEL, SYMBOL_PIN_SEL);

View File

@ -7,17 +7,11 @@
// Copyright (C) 2016-2020 GIMONS
// Copyright (C) 2020 akuker
//
// [ OS related definitions ]
//
//---------------------------------------------------------------------------
#pragma once
#include <cstdlib>
#include <cstring>
#include <cassert>
#include <cstdint>
using BYTE = unsigned char;
using WORD = uint16_t;
using DWORD = uint32_t;

View File

@ -11,7 +11,6 @@
#include "protobuf_serializer.h"
#include "rascsi_exceptions.h"
#include <unistd.h>
#include <sstream>
using namespace std;
using namespace rascsi_interface;
@ -45,10 +44,11 @@ void ProtobufSerializer::DeserializeMessage(int fd, google::protobuf::Message& m
// Read the header with the size of the protobuf data
vector<byte> header_buf(4);
if (ReadBytes(fd, header_buf) < header_buf.size()) {
return;
throw io_exception("Invalid protobuf message header");
}
size_t size = ((int)header_buf[3] << 24) + ((int)header_buf[2] << 16) + ((int)header_buf[1] << 8) + (int)header_buf[0];
const size_t size = ((int)header_buf[3] << 24) + ((int)header_buf[2] << 16)
+ ((int)header_buf[1] << 8) + (int)header_buf[0];
if (size <= 0) {
throw io_exception("Invalid protobuf message header");
}
@ -68,7 +68,7 @@ size_t ProtobufSerializer::ReadBytes(int fd, vector<byte>& buf) const
{
size_t offset = 0;
while (offset < buf.size()) {
ssize_t len = read(fd, &buf[offset], buf.size() - offset);
const ssize_t len = read(fd, &buf.data()[offset], buf.size() - offset);
if (len <= 0) {
return len;
}

View File

@ -0,0 +1,103 @@
//---------------------------------------------------------------------------
//
// SCSI Target Emulator RaSCSI Reloaded
// for Raspberry Pi
//
// Copyright (C) 2021-2022 Uwe Seimet
//
//---------------------------------------------------------------------------
#include "log.h"
#include "rascsi_interface.pb.h"
#include "protobuf_serializer.h"
#include "protobuf_util.h"
#include <sstream>
using namespace std;
using namespace rascsi_interface;
#define FPRT(fp, ...) fprintf(fp, __VA_ARGS__ )
static const char COMPONENT_SEPARATOR = ':';
static const char KEY_VALUE_SEPARATOR = '=';
void protobuf_util::ParseParameters(PbDeviceDefinition& device, const string& params)
{
if (params.empty()) {
return;
}
// Old style parameters, for backwards compatibility only.
// Only one of these parameters will be used by rascsi, depending on the device type.
if (params.find(KEY_VALUE_SEPARATOR) == string::npos) {
AddParam(device, "file", params);
if (params != "bridge" && params != "daynaport" && params != "printer" && params != "services") {
AddParam(device, "interfaces", params);
}
return;
}
stringstream ss(params);
string p;
while (getline(ss, p, COMPONENT_SEPARATOR)) {
if (!p.empty()) {
const size_t separator_pos = p.find(KEY_VALUE_SEPARATOR);
if (separator_pos != string::npos) {
AddParam(device, p.substr(0, separator_pos), string_view(p).substr(separator_pos + 1));
}
}
}
}
string protobuf_util::GetParam(const PbCommand& command, const string& key)
{
const auto& it = command.params().find(key);
return it != command.params().end() ? it->second : "";
}
string protobuf_util::GetParam(const PbDeviceDefinition& device, const string& key)
{
const auto& it = device.params().find(key);
return it != device.params().end() ? it->second : "";
}
void protobuf_util::AddParam(PbCommand& command, const string& key, string_view value)
{
if (!key.empty() && !value.empty()) {
auto& map = *command.mutable_params();
map[key] = value;
}
}
void protobuf_util::AddParam(PbDevice& device, const string& key, string_view value)
{
if (!key.empty() && !value.empty()) {
auto& map = *device.mutable_params();
map[key] = value;
}
}
void protobuf_util::AddParam(PbDeviceDefinition& device, const string& key, string_view value)
{
if (!key.empty() && !value.empty()) {
auto& map = *device.mutable_params();
map[key] = value;
}
}
void protobuf_util::SetPatternParams(PbCommand& command, string_view patterns)
{
string folder_pattern;
string file_pattern;
if (const size_t separator_pos = patterns.find(COMPONENT_SEPARATOR); separator_pos != string::npos) {
folder_pattern = patterns.substr(0, separator_pos);
file_pattern = patterns.substr(separator_pos + 1);
}
else {
file_pattern = patterns;
}
AddParam(command, "folder_pattern", folder_pattern);
AddParam(command, "file_pattern", file_pattern);
}

View File

@ -5,7 +5,7 @@
//
// Copyright (C) 2021-2022 Uwe Seimet
//
// Helper methods for serializing/deserializing protobuf messages
// Helper methods for setting up/evaluating protobuf messages
//
//---------------------------------------------------------------------------
@ -18,7 +18,7 @@
using namespace std;
using namespace rascsi_interface;
namespace command_util
namespace protobuf_util
{
void ParseParameters(PbDeviceDefinition&, const string&);
string GetParam(const PbCommand&, const string&);
@ -26,4 +26,5 @@ namespace command_util
void AddParam(PbCommand&, const string&, string_view);
void AddParam(PbDevice&, const string&, string_view);
void AddParam(PbDeviceDefinition&, const string&, string_view);
void SetPatternParams(PbCommand&, string_view);
}

View File

@ -15,13 +15,13 @@
#include "controllers/controller_manager.h"
#include "controllers/scsi_controller.h"
#include "devices/device_factory.h"
#include "devices/file_support.h"
#include "devices/disk.h"
#include "hal/gpiobus.h"
#include "hal/systimer.h"
#include "rascsi_version.h"
#include "rascsi_exceptions.h"
#include "protobuf_serializer.h"
#include "command_util.h"
#include "rascsi_version.h"
#include "protobuf_util.h"
#include "rascsi_interface.pb.h"
#include "rascsi/rascsi_executor.h"
#include "rascsi/rascsi_response.h"
@ -43,7 +43,7 @@ using namespace std;
using namespace spdlog;
using namespace rascsi_interface;
using namespace ras_util;
using namespace command_util;
using namespace protobuf_util;
//---------------------------------------------------------------------------
//
@ -61,7 +61,7 @@ static const char COMPONENT_SEPARATOR = ':';
static volatile bool active; // Processing flag
RascsiService service;
GPIOBUS bus;
string current_log_level; // Some versions of spdlog do not support get_log_level()
string current_log_level = "info"; // Some versions of spdlog do not support get_log_level()
string access_token;
DeviceFactory device_factory;
ControllerManager controller_manager(bus);
@ -72,28 +72,23 @@ const ProtobufSerializer serializer;
void Banner(int argc, char* argv[])
{
cout << "SCSI Target Emulator RaSCSI Reloaded version " << rascsi_get_version_string()
<< " (" << __DATE__ << ' ' << __TIME__ << ')' << endl;
cout << "Powered by XM6 TypeG Technology / ";
cout << "Copyright (C) 2016-2020 GIMONS" << endl;
cout << "Copyright (C) 2020-2022 Contributors to the RaSCSI Reloaded project" << endl;
cout << "Connect type: " << CONNECT_DESC << endl;
cout << Banner("Reloaded");
cout << "Connect type: " << CONNECT_DESC << '\n' << flush;
if ((argc > 1 && strcmp(argv[1], "-h") == 0) || (argc > 1 && strcmp(argv[1], "--help") == 0)){
cout << endl;
cout << "Usage: " << argv[0] << " [-idn[:m] FILE] ..." << endl << endl;
cout << " n is SCSI device ID (0-7)." << endl;
cout << " m is the optional logical unit (LUN) (0-31)." << endl;
cout << " FILE is a disk image file, \"daynaport\", \"bridge\", \"printer\" or \"services\"." << endl << endl;
cout << " Image type is detected based on file extension if no explicit type is specified." << endl;
cout << " hd1 : SCSI-1 HD image (Non-removable generic SCSI-1 HD image)" << endl;
cout << " hds : SCSI HD image (Non-removable generic SCSI HD image)" << endl;
cout << " hdr : SCSI HD image (Removable generic HD image)" << endl;
cout << " hdn : SCSI HD image (NEC GENUINE)" << endl;
cout << " hdi : SCSI HD image (Anex86 HD image)" << endl;
cout << " nhd : SCSI HD image (T98Next HD image)" << endl;
cout << " mos : SCSI MO image (MO image)" << endl;
cout << " iso : SCSI CD image (ISO 9660 image)" << endl;
cout << "\nUsage: " << argv[0] << " [-idn[:m] FILE] ...\n\n";
cout << " n is SCSI device ID (0-7).\n";
cout << " m is the optional logical unit (LUN) (0-31).\n";
cout << " FILE is a disk image file, \"daynaport\", \"bridge\", \"printer\" or \"services\".\n\n";
cout << " Image type is detected based on file extension if no explicit type is specified.\n";
cout << " hd1 : SCSI-1 HD image (Non-removable generic SCSI-1 HD image)\n";
cout << " hds : SCSI HD image (Non-removable generic SCSI HD image)\n";
cout << " hdr : SCSI HD image (Removable generic HD image)\n";
cout << " hdn : SCSI HD image (NEC GENUINE)\n";
cout << " hdi : SCSI HD image (Anex86 HD image)\n";
cout << " nhd : SCSI HD image (T98Next HD image)\n";
cout << " mos : SCSI MO image (MO image)\n";
cout << " iso : SCSI CD image (ISO 9660 image)\n" << flush;
exit(EXIT_SUCCESS);
}
@ -185,7 +180,7 @@ void TerminationHandler(int signum)
bool ProcessId(const string& id_spec, int& id, int& unit)
{
if (size_t separator_pos = id_spec.find(COMPONENT_SEPARATOR); separator_pos == string::npos) {
if (const size_t separator_pos = id_spec.find(COMPONENT_SEPARATOR); separator_pos == string::npos) {
if (!GetAsInt(id_spec, id) || id < 0 || id >= 8) {
cerr << optarg << ": Invalid device ID (0-7)" << endl;
return false;
@ -249,7 +244,7 @@ bool ParseArgument(int argc, char* argv[], int& port)
continue;
case 'F': {
if (string result = rascsi_image.SetDefaultFolder(optarg); !result.empty()) {
if (const string result = rascsi_image.SetDefaultFolder(optarg); !result.empty()) {
cerr << result << endl;
return false;
}
@ -365,7 +360,7 @@ bool ParseArgument(int argc, char* argv[], int& port)
const list<PbDevice>& devices = { server_info.devices_info().devices().begin(), server_info.devices_info().devices().end() };
const string device_list = ListDevices(devices);
LogDevices(device_list);
cout << device_list << endl;
cout << device_list << flush;
return true;
}
@ -388,8 +383,8 @@ static bool ExecuteCommand(const CommandContext& context, PbCommand& command)
switch(command.operation()) {
case LOG_LEVEL: {
string log_level = GetParam(command, "level");
if (bool status = executor.SetLogLevel(log_level); !status) {
const string log_level = GetParam(command, "level");
if (const bool status = executor.SetLogLevel(log_level); !status) {
context.ReturnLocalizedError(LocalizationKey::ERROR_LOG_LEVEL, log_level);
}
else {
@ -401,7 +396,7 @@ static bool ExecuteCommand(const CommandContext& context, PbCommand& command)
}
case DEFAULT_FOLDER: {
if (string status = rascsi_image.SetDefaultFolder(GetParam(command, "folder")); !status.empty()) {
if (const string status = rascsi_image.SetDefaultFolder(GetParam(command, "folder")); !status.empty()) {
context.ReturnStatus(false, status);
}
else {
@ -457,7 +452,7 @@ static bool ExecuteCommand(const CommandContext& context, PbCommand& command)
}
else {
auto image_file = make_unique<PbImageFile>();
bool status = rascsi_response.GetImageFile(*image_file.get(), rascsi_image.GetDefaultFolder(), filename);
const bool status = rascsi_response.GetImageFile(*image_file.get(), rascsi_image.GetDefaultFolder(), filename);
if (status) {
result.set_status(true);
result.set_allocated_image_file_info(image_file.get());
@ -505,7 +500,7 @@ static bool ExecuteCommand(const CommandContext& context, PbCommand& command)
default: {
// Wait until we become idle
timespec ts = { .tv_sec = 0, .tv_nsec = 500 * 1000 * 1000};
const timespec ts = { .tv_sec = 0, .tv_nsec = 500'000'000};
while (active) {
nanosleep(&ts, nullptr);
}
@ -537,10 +532,10 @@ int main(int argc, char* argv[])
}
}
executor.SetLogLevel("info");
executor.SetLogLevel(current_log_level);
// Create a thread-safe stdout logger to process the log messages
auto logger = stdout_color_mt("rascsi stdout logger");
const auto logger = stdout_color_mt("rascsi stdout logger");
if (!InitBus()) {
return EPERM;
@ -599,7 +594,7 @@ int main(int argc, char* argv[])
#else
bus.Acquire();
if (!bus.GetSEL()) {
timespec ts = { .tv_sec = 0, .tv_nsec = 0};
const timespec ts = { .tv_sec = 0, .tv_nsec = 0};
nanosleep(&ts, nullptr);
continue;
}
@ -608,8 +603,8 @@ int main(int argc, char* argv[])
// Wait until BSY is released as there is a possibility for the
// initiator to assert it while setting the ID (for up to 3 seconds)
if (bus.GetBSY()) {
uint32_t now = SysTimer::GetTimerLow();
while ((SysTimer::GetTimerLow() - now) < 3 * 1000 * 1000) {
const uint32_t now = SysTimer::GetTimerLow();
while ((SysTimer::GetTimerLow() - now) < 3'000'000) {
bus.Acquire();
if (!bus.GetBSY()) {
break;
@ -625,7 +620,7 @@ int main(int argc, char* argv[])
int initiator_id = -1;
// The initiator and target ID
BYTE id_data = bus.GetDAT();
const BYTE id_data = bus.GetDAT();
BUS::phase_t phase = BUS::phase_t::busfree;

View File

@ -15,10 +15,11 @@
using namespace std;
using namespace rascsi_interface;
void CommandContext::Cleanup() const
void CommandContext::Cleanup()
{
if (fd != -1) {
close(fd);
fd = -1;
}
}

View File

@ -32,7 +32,7 @@ public:
CommandContext(const std::string& s = "", int f = -1) : locale(s), fd(f) {}
~CommandContext() = default;
void Cleanup() const;
void Cleanup();
const ProtobufSerializer& GetSerializer() const { return serializer; }
int GetFd() const { return fd; }

View File

@ -13,13 +13,12 @@
#include "devices/device_factory.h"
#include "devices/primary_device.h"
#include "devices/disk.h"
#include "devices/file_support.h"
#include "rascsi_service.h"
#include "rascsi_response.h"
#include "rascsi_image.h"
#include "rascsi_exceptions.h"
#include "localizer.h"
#include "command_util.h"
#include "protobuf_util.h"
#include "command_context.h"
#include "rasutil.h"
#include "spdlog/spdlog.h"
@ -27,7 +26,7 @@
#include <sstream>
using namespace spdlog;
using namespace command_util;
using namespace protobuf_util;
using namespace ras_util;
bool RascsiExecutor::ProcessCmd(const CommandContext& context, const PbDeviceDefinition& pb_device,
@ -103,7 +102,7 @@ bool RascsiExecutor::ProcessCmd(const CommandContext& context, const PbCommand&
case RESERVE_IDS: {
const string ids = GetParam(command, "ids");
if (string error = SetReservedIds(ids); !error.empty()) {
if (const string error = SetReservedIds(ids); !error.empty()) {
return context.ReturnStatus(false, error);
}
@ -132,19 +131,19 @@ bool RascsiExecutor::ProcessCmd(const CommandContext& context, const PbCommand&
}
// Remember the list of reserved files, than run the dry run
const auto& reserved_files = FileSupport::GetReservedFiles();
const auto& reserved_files = Disk::GetReservedFiles();
for (const auto& device : command.devices()) {
if (!ProcessCmd(context, device, command, true)) {
// Dry run failed, restore the file list
FileSupport::SetReservedFiles(reserved_files);
Disk::SetReservedFiles(reserved_files);
return false;
}
}
// Restore the list of reserved files before proceeding
FileSupport::SetReservedFiles(reserved_files);
Disk::SetReservedFiles(reserved_files);
if (string result = ValidateLunSetup(command); !result.empty()) {
if (const string result = ValidateLunSetup(command); !result.empty()) {
return context.ReturnStatus(false, result);
}
@ -283,7 +282,7 @@ bool RascsiExecutor::Attach(const CommandContext& context, const PbDeviceDefinit
return context.ReturnLocalizedError(LocalizationKey::ERROR_RESERVED_ID, to_string(id));
}
string filename = GetParam(pb_device, "file");
const string filename = GetParam(pb_device, "file");
auto device = CreateDevice(context, type, lun, filename);
if (device == nullptr) {
@ -291,8 +290,8 @@ bool RascsiExecutor::Attach(const CommandContext& context, const PbDeviceDefinit
}
// If no filename was provided the medium is considered removed
auto file_support = dynamic_cast<FileSupport *>(device.get());
device->SetRemoved(file_support != nullptr ? filename.empty() : false);
auto disk = dynamic_pointer_cast<Disk>(device);
device->SetRemoved(disk != nullptr ? filename.empty() : false);
if (!SetProductData(context, pb_device, device)) {
return false;
@ -303,8 +302,8 @@ bool RascsiExecutor::Attach(const CommandContext& context, const PbDeviceDefinit
}
string full_path;
if (file_support != nullptr) {
// File check (type is HD, for removable media drives, CD and MO the medium (=file) may be inserted later
if (device->SupportsFile()) {
// Only with removable media drives, CD and MO the medium (=file) may be inserted later
if (!device->IsRemovable() && filename.empty()) {
return context.ReturnLocalizedError(LocalizationKey::ERROR_MISSING_FILENAME, PbDeviceType_Name(type));
}
@ -341,7 +340,7 @@ bool RascsiExecutor::Attach(const CommandContext& context, const PbDeviceDefinit
Filepath filepath;
filepath.SetPath(full_path.c_str());
file_support->ReserveFile(filepath, id, lun);
disk->ReserveFile(filepath, id, lun);
string msg = "Attached ";
if (device->IsReadOnly()) {
@ -367,7 +366,7 @@ bool RascsiExecutor::Insert(const CommandContext& context, const PbDeviceDefinit
return context.ReturnLocalizedError(LocalizationKey::ERROR_DEVICE_NAME_UPDATE);
}
string filename = GetParam(pb_device, "file");
const string filename = GetParam(pb_device, "file");
if (filename.empty()) {
return context.ReturnLocalizedError(LocalizationKey::ERROR_MISSING_FILENAME);
}
@ -390,7 +389,7 @@ bool RascsiExecutor::Insert(const CommandContext& context, const PbDeviceDefinit
Filepath filepath;
filepath.SetPath(full_path.c_str());
dynamic_pointer_cast<FileSupport>(device)->ReserveFile(filepath, device->GetId(), device->GetLun());
dynamic_pointer_cast<Disk>(device)->ReserveFile(filepath, device->GetId(), device->GetLun());
// Only non read-only devices support protect/unprotect.
// This operation must not be executed before Open() because Open() overrides some settings.
@ -407,31 +406,32 @@ bool RascsiExecutor::Insert(const CommandContext& context, const PbDeviceDefinit
bool RascsiExecutor::Detach(const CommandContext& context, shared_ptr<PrimaryDevice> device, bool dryRun) const
{
auto controller = controller_manager.FindController(device->GetId());
if (controller == nullptr) {
return context.ReturnLocalizedError(LocalizationKey::ERROR_DETACH);
}
// LUN 0 can only be detached if there is no other LUN anymore
if (!device->GetLun() && controller_manager.FindController(device->GetId())->GetLunCount() > 1) {
if (!device->GetLun() && controller->GetLunCount() > 1) {
return context.ReturnLocalizedError(LocalizationKey::ERROR_LUN0);
}
if (!dryRun) {
// Prepare log string before the device data are lost due to deletion
string s = "Detached " + device->GetType() + " device with ID " + to_string(device->GetId())
+ ", unit " + to_string(device->GetLun());
if (auto file_support = dynamic_pointer_cast<FileSupport>(device); file_support != nullptr) {
file_support->UnreserveFile();
}
auto controller = controller_manager.FindController(device->GetId());
if (controller == nullptr || !controller->DeleteDevice(device)) {
if (!controller->DeleteDevice(device)) {
return context.ReturnLocalizedError(LocalizationKey::ERROR_DETACH);
}
// If no LUN is left also delete the controller
if (!controller->GetLunCount()) {
controller_manager.DeleteController(controller);
if (!controller->GetLunCount() && !controller_manager.DeleteController(controller)) {
return context.ReturnLocalizedError(LocalizationKey::ERROR_DETACH);
}
LOGINFO("%s", s.c_str())
if (auto disk = dynamic_pointer_cast<Disk>(device); disk != nullptr) {
disk->UnreserveFile();
}
LOGINFO("%s", ("Detached " + device->GetType() + " device with ID " + to_string(device->GetId())
+ ", unit " + to_string(device->GetLun())).c_str())
}
return true;
@ -440,7 +440,7 @@ bool RascsiExecutor::Detach(const CommandContext& context, shared_ptr<PrimaryDev
void RascsiExecutor::DetachAll()
{
controller_manager.DeleteAllControllers();
FileSupport::UnreserveAll();
Disk::UnreserveAll();
LOGINFO("Detached all devices")
}
@ -511,7 +511,7 @@ string RascsiExecutor::SetReservedIds(string_view ids)
}
unordered_set<int> reserved;
for (string id_to_reserve : ids_to_reserve) {
for (const string& id_to_reserve : ids_to_reserve) {
int res_id;
if (!GetAsInt(id_to_reserve, res_id) || res_id > 7) {
return "Invalid ID " + id_to_reserve;
@ -549,8 +549,12 @@ string RascsiExecutor::SetReservedIds(string_view ids)
bool RascsiExecutor::ValidateImageFile(const CommandContext& context, shared_ptr<PrimaryDevice> device,
const string& filename, string& full_path) const
{
auto file_support = dynamic_pointer_cast<FileSupport>(device);
if (file_support == nullptr || filename.empty()) {
if (!device->SupportsFile()) {
return true;
}
auto disk = dynamic_pointer_cast<Disk>(device);
if (disk == nullptr || filename.empty()) {
return true;
}
@ -559,7 +563,7 @@ bool RascsiExecutor::ValidateImageFile(const CommandContext& context, shared_ptr
Filepath filepath;
filepath.SetPath(filename.c_str());
if (FileSupport::GetIdsForReservedFile(filepath, id, lun)) {
if (Disk::GetIdsForReservedFile(filepath, id, lun)) {
return context.ReturnLocalizedError(LocalizationKey::ERROR_IMAGE_IN_USE, filename,
to_string(id), to_string(lun));
}
@ -567,16 +571,16 @@ bool RascsiExecutor::ValidateImageFile(const CommandContext& context, shared_ptr
string initial_filename = filepath.GetPath();
try {
if (!file_support->FileExists(filepath)) {
if (!disk->FileExists(filepath)) {
// If the file does not exist search for it in the default image folder
filepath.SetPath((rascsi_image.GetDefaultFolder() + "/" + filename).c_str());
if (FileSupport::GetIdsForReservedFile(filepath, id, lun)) {
if (Disk::GetIdsForReservedFile(filepath, id, lun)) {
return context.ReturnLocalizedError(LocalizationKey::ERROR_IMAGE_IN_USE, filename,
to_string(id), to_string(lun));
}
file_support->Open(filepath);
disk->Open(filepath);
}
}
catch(const io_exception& e) {
@ -645,7 +649,7 @@ string RascsiExecutor::ValidateLunSetup(const PbCommand& command) const
}
// LUN 0 must exist for all devices
for (auto const& [id, lun]: luns) {
for (const auto& [id, lun]: luns) {
if (!(lun & 0x01)) {
return "LUN 0 is missing for device ID " + to_string(id);
}

View File

@ -12,8 +12,8 @@
#include "log.h"
#include "filepath.h"
#include "spdlog/spdlog.h"
#include "devices/file_support.h"
#include "command_util.h"
#include "devices/disk.h"
#include "protobuf_util.h"
#include "command_context.h"
#include "rascsi_image.h"
#include <string>
@ -26,7 +26,7 @@
using namespace std;
using namespace spdlog;
using namespace rascsi_interface;
using namespace command_util;
using namespace protobuf_util;
RascsiImage::RascsiImage()
{
@ -41,8 +41,8 @@ bool RascsiImage::CheckDepth(string_view filename) const
bool RascsiImage::CreateImageFolder(const CommandContext& context, const string& filename) const
{
if (size_t filename_start = filename.rfind('/'); filename_start != string::npos) {
string folder = filename.substr(0, filename_start);
if (const size_t filename_start = filename.rfind('/'); filename_start != string::npos) {
const string folder = filename.substr(0, filename_start);
// Checking for existence first prevents an error if the top-level folder is a softlink
if (struct stat st; stat(folder.c_str(), &st)) {
@ -105,7 +105,7 @@ bool RascsiImage::IsValidDstFilename(const string& filename) const
bool RascsiImage::CreateImage(const CommandContext& context, const PbCommand& command) const
{
string filename = GetParam(command, "file");
const string filename = GetParam(command, "file");
if (filename.empty()) {
return context.ReturnStatus(false, "Can't create image file: Missing image filename");
}
@ -114,7 +114,7 @@ bool RascsiImage::CreateImage(const CommandContext& context, const PbCommand& co
return context.ReturnStatus(false, ("Invalid folder hierarchy depth '" + filename + "'").c_str());
}
string full_filename = GetFullName(filename);
const string full_filename = GetFullName(filename);
if (!IsValidDstFilename(full_filename)) {
return context.ReturnStatus(false, "Can't create image file: '" + full_filename + "': File already exists");
}
@ -142,12 +142,12 @@ bool RascsiImage::CreateImage(const CommandContext& context, const PbCommand& co
return false;
}
string permission = GetParam(command, "read_only");
const string permission = GetParam(command, "read_only");
// Since rascsi is running as root ensure that others can access the file
int permissions = !strcasecmp(permission.c_str(), "true") ?
const int permissions = !strcasecmp(permission.c_str(), "true") ?
S_IRUSR | S_IRGRP | S_IROTH : S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH;
int image_fd = open(full_filename.c_str(), O_CREAT|O_WRONLY, permissions);
const int image_fd = open(full_filename.c_str(), O_CREAT|O_WRONLY, permissions);
if (image_fd == -1) {
return context.ReturnStatus(false, "Can't create image file '" + full_filename + "': " + string(strerror(errno)));
}
@ -178,7 +178,7 @@ bool RascsiImage::CreateImage(const CommandContext& context, const PbCommand& co
bool RascsiImage::DeleteImage(const CommandContext& context, const PbCommand& command) const
{
string filename = GetParam(command, "file");
const string filename = GetParam(command, "file");
if (filename.empty()) {
return context.ReturnStatus(false, "Missing image filename");
}
@ -187,13 +187,13 @@ bool RascsiImage::DeleteImage(const CommandContext& context, const PbCommand& co
return context.ReturnStatus(false, ("Invalid folder hierarchy depth '" + filename + "'").c_str());
}
string full_filename = GetFullName(filename);
const string full_filename = GetFullName(filename);
int id;
int unit;
Filepath filepath;
filepath.SetPath(full_filename.c_str());
if (FileSupport::GetIdsForReservedFile(filepath, id, unit)) {
if (Disk::GetIdsForReservedFile(filepath, id, unit)) {
return context.ReturnStatus(false, "Can't delete image file '" + full_filename +
"', it is currently being used by device ID " + to_string(id) + ", unit " + to_string(unit));
}
@ -273,17 +273,17 @@ bool RascsiImage::CopyImage(const CommandContext& context, const PbCommand& comm
return context.ReturnStatus();
}
int fd_src = open(from.c_str(), O_RDONLY, 0);
const int fd_src = open(from.c_str(), O_RDONLY, 0);
if (fd_src == -1) {
return context.ReturnStatus(false, "Can't open source image file '" + from + "': " + string(strerror(errno)));
}
string permission = GetParam(command, "read_only");
const string permission = GetParam(command, "read_only");
// Since rascsi is running as root ensure that others can access the file
int permissions = !strcasecmp(permission.c_str(), "true") ?
const int permissions = !strcasecmp(permission.c_str(), "true") ?
S_IRUSR | S_IRGRP | S_IROTH : S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH;
int fd_dst = open(to.c_str(), O_WRONLY | O_CREAT, permissions);
const int fd_dst = open(to.c_str(), O_WRONLY | O_CREAT, permissions);
if (fd_dst == -1) {
close(fd_src);
@ -334,9 +334,9 @@ bool RascsiImage::SetImagePermissions(const CommandContext& context, const PbCom
return context.ReturnStatus(false, "Can't modify image file '" + filename + "': Invalid name or type");
}
bool protect = command.operation() == PROTECT_IMAGE;
const bool protect = command.operation() == PROTECT_IMAGE;
if (int permissions = protect ? S_IRUSR | S_IRGRP | S_IROTH : S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH;
if (const int permissions = protect ? S_IRUSR | S_IRGRP | S_IROTH : S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH;
chmod(filename.c_str(), permissions) == -1) {
return context.ReturnStatus(false, "Can't " + string(protect ? "protect" : "unprotect") + " image file '" + filename + "': " +
strerror(errno));

View File

@ -8,16 +8,15 @@
//---------------------------------------------------------------------------
#include "controllers/controller_manager.h"
#include "devices/file_support.h"
#include "devices/disk.h"
#include "devices/device_factory.h"
#include "command_util.h"
#include "protobuf_util.h"
#include "rascsi_version.h"
#include "rascsi_interface.pb.h"
#include "rascsi_response.h"
using namespace rascsi_interface;
using namespace command_util;
using namespace protobuf_util;
unique_ptr<PbDeviceProperties> RascsiResponse::GetDeviceProperties(const Device& device) const
{
@ -29,7 +28,7 @@ unique_ptr<PbDeviceProperties> RascsiResponse::GetDeviceProperties(const Device&
properties->set_stoppable(device.IsStoppable());
properties->set_removable(device.IsRemovable());
properties->set_lockable(device.IsLockable());
properties->set_supports_file(dynamic_cast<const FileSupport *>(&device) != nullptr);
properties->set_supports_file(device.SupportsFile());
properties->set_supports_params(device.SupportsParams());
PbDeviceType t = UNDEFINED;
@ -53,7 +52,7 @@ void RascsiResponse::GetDeviceTypeProperties(PbDeviceTypesInfo& device_types_inf
{
auto type_properties = device_types_info.add_properties();
type_properties->set_type(type);
auto device = device_factory.CreateDevice(controller_manager, type, 0, "");
const auto device = device_factory.CreateDevice(controller_manager, type, 0, "");
type_properties->set_allocated_properties(GetDeviceProperties(*device).release());
} //NOSONAR The allocated memory is managed by protobuf
@ -101,10 +100,10 @@ void RascsiResponse::GetDevice(const Device& device, PbDevice& pb_device, const
pb_device.set_block_count(device.IsRemoved() ? 0: disk->GetBlockCount());
}
const auto file_support = dynamic_cast<const FileSupport *>(&device);
if (file_support) {
const auto disk = dynamic_cast<const Disk *>(&device);
if (disk != nullptr) {
Filepath filepath;
file_support->GetPath(filepath);
disk->GetPath(filepath);
auto image_file = make_unique<PbImageFile>().release();
GetImageFile(*image_file, default_folder, device.IsRemovable() && !device.IsReady() ? "" : filepath.GetPath());
pb_device.set_allocated_file(image_file);
@ -117,7 +116,7 @@ bool RascsiResponse::GetImageFile(PbImageFile& image_file, const string& default
image_file.set_name(filename);
image_file.set_type(device_factory.GetTypeForFile(filename));
string f = filename[0] == '/' ? filename : default_folder + "/" + filename;
const string f = filename[0] == '/' ? filename : default_folder + "/" + filename;
image_file.set_read_only(access(f.c_str(), W_OK));
@ -209,7 +208,7 @@ void RascsiResponse::GetAvailableImages(PbResult& result, PbServerInfo& server_i
unique_ptr<PbReservedIdsInfo> RascsiResponse::GetReservedIds(PbResult& result, const unordered_set<int>& ids) const
{
auto reserved_ids_info = make_unique<PbReservedIdsInfo>();
for (int id : ids) {
for (const int id : ids) {
reserved_ids_info->add_ids(id);
}
@ -533,14 +532,14 @@ string RascsiResponse::GetNextImageFile(const dirent *dir, const string& folder)
return "";
}
string filename = folder + "/" + dir->d_name;
const string filename = folder + "/" + dir->d_name;
struct stat st;
bool file_exists = !stat(filename.c_str(), &st);
const bool file_exists = !stat(filename.c_str(), &st);
if (dir->d_type == DT_REG && file_exists && !st.st_size) {
LOGWARN("File '%s' in image folder '%s' has a size of 0 bytes", dir->d_name, folder.c_str())
LOGWARN("File '%s' in image folder '%s' is empty", dir->d_name, folder.c_str())
return "";
}

View File

@ -77,7 +77,7 @@ void RascsiService::Execute() const
ras_util::FixCpu(2);
// Wait for the execution to start
timespec ts = { .tv_sec = 0, .tv_nsec = 1000};
const timespec ts = { .tv_sec = 0, .tv_nsec = 1000};
while (!running) {
nanosleep(&ts, nullptr);
}
@ -109,7 +109,7 @@ PbCommand RascsiService::ReadCommand(CommandContext& context) const
// Wait for connection
sockaddr client = {};
socklen_t socklen = sizeof(client);
int fd = accept(service_socket, &client, &socklen);
const int fd = accept(service_socket, &client, &socklen);
if (fd == -1) {
throw io_exception("accept() failed");
}
@ -118,7 +118,7 @@ PbCommand RascsiService::ReadCommand(CommandContext& context) const
// Read magic string
vector<byte> magic(6);
if (size_t bytes_read = context.GetSerializer().ReadBytes(fd, magic);
if (const size_t bytes_read = context.GetSerializer().ReadBytes(fd, magic);
bytes_read != magic.size() || memcmp(magic.data(), "RASCSI", magic.size())) {
throw io_exception("Invalid magic");
}

View File

@ -30,7 +30,7 @@ class file_not_found_exception : public io_exception
using io_exception::io_exception;
};
class scsi_error_exception final : public std::exception
class scsi_exception : public std::exception
{
scsi_defs::sense_key sense_key;
scsi_defs::asc asc;
@ -38,11 +38,11 @@ class scsi_error_exception final : public std::exception
public:
scsi_error_exception(scsi_defs::sense_key sense_key = scsi_defs::sense_key::ABORTED_COMMAND,
scsi_exception(scsi_defs::sense_key sense_key = scsi_defs::sense_key::ABORTED_COMMAND,
scsi_defs::asc asc = scsi_defs::asc::NO_ADDITIONAL_SENSE_INFORMATION,
scsi_defs::status status = scsi_defs::status::CHECK_CONDITION)
: sense_key(sense_key), asc(asc), status(status) {}
~scsi_error_exception() override = default;
~scsi_exception() override = default;
scsi_defs::sense_key get_sense_key() const { return sense_key; }
scsi_defs::asc get_asc() const { return asc; }

View File

@ -23,7 +23,7 @@ string rascsi_get_version_string()
{
stringstream s;
s << setw(2) << setfill('0') << rascsi_major_version << '.' << setw(2) << setfill('0') << rascsi_minor_version;
s << setw(2) << setfill('0') << rascsi_major_version << '.' << rascsi_minor_version;
if (rascsi_patch_version < 0) {
s << " --DEVELOPMENT BUILD--";

View File

@ -10,11 +10,11 @@
//
//---------------------------------------------------------------------------
#include <unistd.h>
#include "rascsi_version.h"
#include "command_util.h"
#include "protobuf_util.h"
#include "rasutil.h"
#include "rascsi_interface.pb.h"
#include "rasctl/rasctl_parser.h"
#include "rasctl/rasctl_commands.h"
#include <unistd.h>
#include <clocale>
@ -27,125 +27,45 @@ static const char COMPONENT_SEPARATOR = ':';
using namespace std;
using namespace rascsi_interface;
using namespace ras_util;
using namespace command_util;
using namespace protobuf_util;
PbOperation ParseOperation(const string& operation)
void Banner(int argc, char* argv[])
{
switch (tolower(operation[0])) {
case 'a':
return ATTACH;
if (argc < 2) {
cout << Banner("Controller");
case 'd':
return DETACH;
cout << "\nUsage: " << argv[0] << " -i ID [-u UNIT] [-c CMD] [-C FILE] [-t TYPE] [-b BLOCK_SIZE] [-n NAME] [-f FILE|PARAM] ";
cout << "[-F IMAGE_FOLDER] [-L LOG_LEVEL] [-h HOST] [-p PORT] [-r RESERVED_IDS] ";
cout << "[-C FILENAME:FILESIZE] [-d FILENAME] [-w FILENAME] [-R CURRENT_NAME:NEW_NAME] ";
cout << "[-x CURRENT_NAME:NEW_NAME] [-z LOCALE] ";
cout << "[-e] [-E FILENAME] [-D] [-I] [-l] [-m] [o] [-O] [-P] [-s] [-v] [-V] [-y] [-X]\n";
cout << " where ID := {0-7}\n";
cout << " UNIT := {0-31}, default is 0\n";
cout << " CMD := {attach|detach|insert|eject|protect|unprotect|show}\n";
cout << " TYPE := {schd|scrm|sccd|scmo|scbr|scdp} or convenience type {hd|rm|mo|cd|bridge|daynaport}\n";
cout << " BLOCK_SIZE := {512|1024|2048|4096) bytes per hard disk drive block\n";
cout << " NAME := name of device to attach (VENDOR:PRODUCT:REVISION)\n";
cout << " FILE|PARAM := image file path or device-specific parameter\n";
cout << " IMAGE_FOLDER := default location for image files, default is '~/images'\n";
cout << " HOST := rascsi host to connect to, default is 'localhost'\n";
cout << " PORT := rascsi port to connect to, default is 6868\n";
cout << " RESERVED_IDS := comma-separated list of IDs to reserve\n";
cout << " LOG_LEVEL := log level {trace|debug|info|warn|err|critical|off}, default is 'info'\n";
cout << " If CMD is 'attach' or 'insert' the FILE parameter is required.\n";
cout << "Usage: " << argv[0] << " -l\n";
cout << " Print device list.\n" << flush;
case 'i':
return INSERT;
case 'e':
return EJECT;
case 'p':
return PROTECT;
case 'u':
return UNPROTECT;
case 's':
return DEVICES_INFO;
default:
return NO_OPERATION;
exit(EXIT_SUCCESS);
}
}
PbDeviceType ParseType(const char *type)
{
string t = type;
transform(t.begin(), t.end(), t.begin(), ::toupper);
if (PbDeviceType parsed_type; PbDeviceType_Parse(t, &parsed_type)) {
return parsed_type;
}
// Parse convenience device types (shortcuts)
switch (tolower(type[0])) {
case 'c':
return SCCD;
case 'b':
return SCBR;
case 'd':
return SCDP;
case 'h':
return SCHD;
case 'm':
return SCMO;
case 'r':
return SCRM;
case 'l':
return SCLP;
case 's':
return SCHS;
default:
return UNDEFINED;
}
}
void SetPatternParams(PbCommand& command, string_view patterns)
{
string folder_pattern;
string file_pattern;
if (size_t separator_pos = patterns.find(COMPONENT_SEPARATOR); separator_pos != string::npos) {
folder_pattern = patterns.substr(0, separator_pos);
file_pattern = patterns.substr(separator_pos + 1);
}
else {
file_pattern = patterns;
}
AddParam(command, "folder_pattern", folder_pattern);
AddParam(command, "file_pattern", file_pattern);
}
int main(int argc, char* argv[])
{
GOOGLE_PROTOBUF_VERIFY_VERSION;
// Display help
if (argc < 2) {
cerr << "SCSI Target Emulator RaSCSI Controller" << endl;
cerr << "version " << rascsi_get_version_string() << " (" << __DATE__ << ", " << __TIME__ << ")" << endl;
cerr << "Usage: " << argv[0] << " -i ID [-u UNIT] [-c CMD] [-C FILE] [-t TYPE] [-b BLOCK_SIZE] [-n NAME] [-f FILE|PARAM] ";
cerr << "[-F IMAGE_FOLDER] [-L LOG_LEVEL] [-h HOST] [-p PORT] [-r RESERVED_IDS] ";
cerr << "[-C FILENAME:FILESIZE] [-d FILENAME] [-w FILENAME] [-R CURRENT_NAME:NEW_NAME] ";
cerr << "[-x CURRENT_NAME:NEW_NAME] [-z LOCALE] ";
cerr << "[-e] [-E FILENAME] [-D] [-I] [-l] [-L] [-m] [o] [-O] [-P] [-s] [-v] [-V] [-y] [-X]" << endl;
cerr << " where ID := {0-7}" << endl;
cerr << " UNIT := {0-31}, default is 0" << endl;
cerr << " CMD := {attach|detach|insert|eject|protect|unprotect|show}" << endl;
cerr << " TYPE := {schd|scrm|sccd|scmo|scbr|scdp} or convenience type {hd|rm|mo|cd|bridge|daynaport}" << endl;
cerr << " BLOCK_SIZE := {512|1024|2048|4096) bytes per hard disk drive block" << endl;
cerr << " NAME := name of device to attach (VENDOR:PRODUCT:REVISION)" << endl;
cerr << " FILE|PARAM := image file path or device-specific parameter" << endl;
cerr << " IMAGE_FOLDER := default location for image files, default is '~/images'" << endl;
cerr << " HOST := rascsi host to connect to, default is 'localhost'" << endl;
cerr << " PORT := rascsi port to connect to, default is 6868" << endl;
cerr << " RESERVED_IDS := comma-separated list of IDs to reserve" << endl;
cerr << " LOG_LEVEL := log level {trace|debug|info|warn|err|critical|off}, default is 'info'" << endl;
cerr << " If CMD is 'attach' or 'insert' the FILE parameter is required." << endl;
cerr << "Usage: " << argv[0] << " -l" << endl;
cerr << " Print device list." << endl;
exit(EXIT_SUCCESS);
}
Banner(argc, argv);
RasctlParser parser;
PbCommand command;
list<PbDeviceDefinition> devices;
PbDeviceDefinition* device = command.add_devices();
@ -205,7 +125,7 @@ int main(int argc, char* argv[])
break;
case 'c':
command.set_operation(ParseOperation(optarg));
command.set_operation(parser.ParseOperation(optarg));
if (command.operation() == NO_OPERATION) {
cerr << "Error: Unknown operation '" << optarg << "'" << endl;
exit(EXIT_FAILURE);
@ -276,7 +196,7 @@ int main(int argc, char* argv[])
break;
case 't':
device->set_type(ParseType(optarg));
device->set_type(parser.ParseType(optarg));
if (device->type() == UNDEFINED) {
cerr << "Error: Unknown device type '" << optarg << "'" << endl;
exit(EXIT_FAILURE);

View File

@ -9,7 +9,7 @@
#include "rascsi_exceptions.h"
#include "protobuf_serializer.h"
#include "command_util.h"
#include "protobuf_util.h"
#include "rasutil.h"
#include "rasctl_commands.h"
#include "rascsi_interface.pb.h"
@ -20,7 +20,7 @@
using namespace std;
using namespace rascsi_interface;
using namespace command_util;
using namespace protobuf_util;
// Separator for the INQUIRY name components
static const char COMPONENT_SEPARATOR = ':';
@ -115,36 +115,25 @@ void RasctlCommands::Execute(const string& log_level, const string& default_fold
void RasctlCommands::SendCommand()
{
if (!token.empty()) {
AddParam(command, "token", token);
}
AddParam(command, "token", token);
AddParam(command, "locale", locale);
if (!locale.empty()) {
AddParam(command, "locale", locale);
}
// Send command
int fd = -1;
try {
const hostent *host = gethostbyname(hostname.c_str());
if (!host) {
fd = socket(AF_INET, SOCK_STREAM, 0);
if (fd == -1) {
throw io_exception("Can't create socket: " + string(strerror(errno)));
}
sockaddr_in server_addr = {};
if (!ResolveHostName(hostname, &server_addr)) {
throw io_exception("Can't resolve hostname '" + hostname + "'");
}
fd = socket(AF_INET, SOCK_STREAM, 0);
if (fd < 0) {
throw io_exception("Can't create socket");
}
sockaddr_in server = {};
server.sin_family = AF_INET;
server.sin_port = htons((uint16_t)port);
server.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
memcpy(&server.sin_addr.s_addr, host->h_addr, host->h_length);
if (connect(fd, (struct sockaddr *)&server, sizeof(struct sockaddr_in)) < 0) {
throw io_exception("Can't connect to rascsi process on host '" + hostname + "', port "
+ to_string(port));
server_addr.sin_port = htons(uint16_t(port));
if (connect(fd, (sockaddr *)&server_addr, sizeof(server_addr)) < 0) {
throw io_exception("Can't connect to rascsi on host '" + hostname + "', port " + to_string(port)
+ ": " + strerror(errno));
}
if (write(fd, "RASCSI", 6) != 6) {
@ -156,11 +145,11 @@ void RasctlCommands::SendCommand()
catch(const io_exception& e) {
cerr << "Error: " << e.get_msg() << endl;
if (fd >= 0) {
if (fd != -1) {
close(fd);
}
exit(fd < 0 ? ENOTCONN : EXIT_FAILURE);
exit(fd == -1 ? ENOTCONN : EXIT_FAILURE);
}
// Receive result
@ -190,7 +179,7 @@ void RasctlCommands::CommandDevicesInfo()
{
SendCommand();
rasctl_display.DisplayDevices(result.devices_info());
cout << rasctl_display.DisplayDevicesInfo(result.devices_info()) << flush;
}
void RasctlCommands::CommandLogLevel(const string& log_level)
@ -209,7 +198,7 @@ void RasctlCommands::CommandReserveIds(const string& reserved_ids)
void RasctlCommands::CommandCreateImage(const string& image_params)
{
if (size_t separator_pos = image_params.find(COMPONENT_SEPARATOR); separator_pos != string::npos) {
if (const size_t separator_pos = image_params.find(COMPONENT_SEPARATOR); separator_pos != string::npos) {
AddParam(command, "file", string_view(image_params).substr(0, separator_pos));
AddParam(command, "size", string_view(image_params).substr(separator_pos + 1));
}
@ -232,7 +221,7 @@ void RasctlCommands::CommandDeleteImage(const string& filename)
void RasctlCommands::CommandRenameImage(const string& image_params)
{
if (size_t separator_pos = image_params.find(COMPONENT_SEPARATOR); separator_pos != string::npos) {
if (const size_t separator_pos = image_params.find(COMPONENT_SEPARATOR); separator_pos != string::npos) {
AddParam(command, "from", string_view(image_params).substr(0, separator_pos));
AddParam(command, "to", string_view(image_params).substr(separator_pos + 1));
}
@ -246,7 +235,7 @@ void RasctlCommands::CommandRenameImage(const string& image_params)
void RasctlCommands::CommandCopyImage(const string& image_params)
{
if (size_t separator_pos = image_params.find(COMPONENT_SEPARATOR); separator_pos != string::npos) {
if (const size_t separator_pos = image_params.find(COMPONENT_SEPARATOR); separator_pos != string::npos) {
AddParam(command, "from", string_view(image_params).substr(0, separator_pos));
AddParam(command, "to", string_view(image_params).substr(separator_pos + 1));
}
@ -270,22 +259,24 @@ void RasctlCommands::CommandDeviceInfo()
SendCommand();
for (const auto& device : result.devices_info().devices()) {
rasctl_display.DisplayDeviceInfo(device);
cout << rasctl_display.DisplayDeviceInfo(device);
}
cout << flush;
}
void RasctlCommands::CommandDeviceTypesInfo()
{
SendCommand();
rasctl_display.DisplayDeviceTypesInfo(result.device_types_info());
cout << rasctl_display.DisplayDeviceTypesInfo(result.device_types_info()) << flush;
}
void RasctlCommands::CommandVersionInfo()
{
SendCommand();
rasctl_display.DisplayVersionInfo(result.version_info());
cout << rasctl_display.DisplayVersionInfo(result.version_info()) << flush;
}
void RasctlCommands::CommandServerInfo()
@ -294,32 +285,34 @@ void RasctlCommands::CommandServerInfo()
PbServerInfo server_info = result.server_info();
rasctl_display.DisplayVersionInfo(server_info.version_info());
rasctl_display.DisplayLogLevelInfo(server_info.log_level_info());
rasctl_display.DisplayImageFiles(server_info.image_files_info());
rasctl_display.DisplayMappingInfo(server_info.mapping_info());
rasctl_display.DisplayNetworkInterfaces(server_info.network_interfaces_info());
rasctl_display.DisplayDeviceTypesInfo(server_info.device_types_info());
rasctl_display.DisplayReservedIdsInfo(server_info.reserved_ids_info());
rasctl_display.DisplayOperationInfo(server_info.operation_info());
cout << rasctl_display.DisplayVersionInfo(server_info.version_info());
cout << rasctl_display.DisplayLogLevelInfo(server_info.log_level_info());
cout << rasctl_display.DisplayImageFilesInfo(server_info.image_files_info());
cout << rasctl_display.DisplayMappingInfo(server_info.mapping_info());
cout << rasctl_display.DisplayNetworkInterfaces(server_info.network_interfaces_info());
cout << rasctl_display.DisplayDeviceTypesInfo(server_info.device_types_info());
cout << rasctl_display.DisplayReservedIdsInfo(server_info.reserved_ids_info());
cout << rasctl_display.DisplayOperationInfo(server_info.operation_info());
if (server_info.devices_info().devices_size()) {
list<PbDevice> sorted_devices = { server_info.devices_info().devices().begin(), server_info.devices_info().devices().end() };
sorted_devices.sort([](const auto& a, const auto& b) { return a.id() < b.id() || a.unit() < b.unit(); });
cout << "Attached devices:" << endl;
cout << "Attached devices:\n";
for (const auto& device : sorted_devices) {
rasctl_display.DisplayDeviceInfo(device);
cout << rasctl_display.DisplayDeviceInfo(device);
}
}
cout << flush;
}
void RasctlCommands::CommandDefaultImageFilesInfo()
{
SendCommand();
rasctl_display.DisplayImageFiles(result.image_files_info());
cout << rasctl_display.DisplayImageFilesInfo(result.image_files_info()) << flush;
}
void RasctlCommands::CommandImageFileInfo(const string& filename)
@ -328,40 +321,55 @@ void RasctlCommands::CommandImageFileInfo(const string& filename)
SendCommand();
rasctl_display.DisplayImageFile(result.image_file_info());
cout << rasctl_display.DisplayImageFile(result.image_file_info()) << flush;
}
void RasctlCommands::CommandNetworkInterfacesInfo()
{
SendCommand();
rasctl_display.DisplayNetworkInterfaces(result.network_interfaces_info());
cout << rasctl_display.DisplayNetworkInterfaces(result.network_interfaces_info()) << flush;
}
void RasctlCommands::CommandLogLevelInfo()
{
SendCommand();
rasctl_display.DisplayLogLevelInfo(result.log_level_info());
cout << rasctl_display.DisplayLogLevelInfo(result.log_level_info()) << flush;
}
void RasctlCommands::CommandReservedIdsInfo()
{
SendCommand();
rasctl_display.DisplayReservedIdsInfo(result.reserved_ids_info());
cout << rasctl_display.DisplayReservedIdsInfo(result.reserved_ids_info()) << flush;
}
void RasctlCommands::CommandMappingInfo()
{
SendCommand();
rasctl_display.DisplayMappingInfo(result.mapping_info());
cout << rasctl_display.DisplayMappingInfo(result.mapping_info()) << flush;
}
void RasctlCommands::CommandOperationInfo()
{
SendCommand();
rasctl_display.DisplayOperationInfo(result.operation_info());
cout << rasctl_display.DisplayOperationInfo(result.operation_info()) << flush;
}
bool RasctlCommands::ResolveHostName(const string& host, sockaddr_in *addr)
{
addrinfo hints = {};
hints.ai_family = AF_INET;
hints.ai_socktype = SOCK_STREAM;
if (addrinfo *result; !getaddrinfo(host.c_str(), nullptr, &hints, &result)) {
*addr = *(sockaddr_in *)(result->ai_addr);
freeaddrinfo(result);
return true;
}
return false;
}

View File

@ -3,7 +3,7 @@
// SCSI Target Emulator RaSCSI Reloaded
// for Raspberry Pi
//
// Copyright (C) 2021 Uwe Seimet
// Copyright (C) 2021-2022 Uwe Seimet
//
//---------------------------------------------------------------------------
@ -12,6 +12,7 @@
#include "protobuf_serializer.h"
#include "rascsi_interface.pb.h"
#include "rasctl_display.h"
#include <netdb.h>
#include <string>
using namespace rascsi_interface;
@ -49,6 +50,8 @@ private:
void CommandOperationInfo();
void SendCommand();
static bool ResolveHostName(const string&, sockaddr_in *);
ProtobufSerializer serializer;
PbCommand command;
string hostname;

View File

@ -10,274 +10,282 @@
#include "rascsi_interface.pb.h"
#include "rasutil.h"
#include "rasctl_display.h"
#include <iostream>
#include <sstream>
#include <list>
#include <iomanip>
using namespace std;
using namespace rascsi_interface;
using namespace ras_util;
void RasctlDisplay::DisplayDevices(const PbDevicesInfo& devices_info) const
string RasctlDisplay::DisplayDevicesInfo(const PbDevicesInfo& devices_info) const
{
ostringstream s;
const list<PbDevice>& devices = { devices_info.devices().begin(), devices_info.devices().end() };
cout << ListDevices(devices) << endl;
s << ListDevices(devices);
return s.str();
}
void RasctlDisplay::DisplayDeviceInfo(const PbDevice& pb_device) const
string RasctlDisplay::DisplayDeviceInfo(const PbDevice& pb_device) const
{
cout << " " << pb_device.id() << ":" << pb_device.unit() << " " << PbDeviceType_Name(pb_device.type())
ostringstream s;
s << " " << pb_device.id() << ":" << pb_device.unit() << " " << PbDeviceType_Name(pb_device.type())
<< " " << pb_device.vendor() << ":" << pb_device.product() << ":" << pb_device.revision();
if (pb_device.block_size()) {
cout << " " << pb_device.block_size() << " bytes per sector";
s << " " << pb_device.block_size() << " bytes per sector";
if (pb_device.block_count()) {
cout << " " << pb_device.block_size() * pb_device.block_count() << " bytes capacity";
s << " " << pb_device.block_size() * pb_device.block_count() << " bytes capacity";
}
}
if (pb_device.properties().supports_file() && !pb_device.file().name().empty()) {
cout << " " << pb_device.file().name();
s << " " << pb_device.file().name();
}
cout << " ";
s << " ";
bool hasProperty = false;
if (pb_device.properties().read_only()) {
cout << "read-only";
s << "read-only";
hasProperty = true;
}
if (pb_device.properties().protectable() && pb_device.status().protected_()) {
if (hasProperty) {
cout << ", ";
s << ", ";
}
cout << "protected";
s << "protected";
hasProperty = true;
}
if (pb_device.properties().stoppable() && pb_device.status().stopped()) {
if (hasProperty) {
cout << ", ";
s << ", ";
}
cout << "stopped";
s << "stopped";
hasProperty = true;
}
if (pb_device.properties().removable() && pb_device.status().removed()) {
if (hasProperty) {
cout << ", ";
s << ", ";
}
cout << "removed";
s << "removed";
hasProperty = true;
}
if (pb_device.properties().lockable() && pb_device.status().locked()) {
if (hasProperty) {
cout << ", ";
s << ", ";
}
cout << "locked";
s << "locked";
}
if (hasProperty) {
cout << " ";
s << " ";
}
// Creates a sorted map
map<string, string> params = { pb_device.params().begin(), pb_device.params().end() };
bool isFirst = true;
for (const auto& [key, value] : params) {
if (!isFirst) {
cout << ":";
}
isFirst = false;
cout << key << "=" << value;
}
DisplayParams(s, pb_device);
cout << endl;
s << '\n';
return s.str();
}
void RasctlDisplay::DisplayVersionInfo(const PbVersionInfo& version_info) const
string RasctlDisplay::DisplayVersionInfo(const PbVersionInfo& version_info) const
{
cout << "rascsi server version: " << version_info.major_version() << "." << version_info.minor_version();
ostringstream s;
s << "rascsi server version: " << setw(2) << setfill('0') << version_info.major_version() << "."
<< setw(2) << setfill('0') << version_info.minor_version();
if (version_info.patch_version() > 0) {
cout << "." << version_info.patch_version();
s << "." << version_info.patch_version();
}
else if (version_info.patch_version() < 0) {
cout << " (development version)";
s << " (development version)";
}
cout << endl;
s << '\n';
return s.str();
}
void RasctlDisplay::DisplayLogLevelInfo(const PbLogLevelInfo& log_level_info) const
string RasctlDisplay::DisplayLogLevelInfo(const PbLogLevelInfo& log_level_info) const
{
ostringstream s;
if (!log_level_info.log_levels_size()) {
cout << " No log level settings available" << endl;
s << " No log level settings available\n";
}
else {
cout << "rascsi log levels, sorted by severity:" << endl;
s << "rascsi log levels, sorted by severity:\n";
for (const auto& log_level : log_level_info.log_levels()) {
cout << " " << log_level << endl;
s << " " << log_level << '\n';
}
}
cout << "Current rascsi log level: " << log_level_info.current_log_level() << endl;
s << "Current rascsi log level: " << log_level_info.current_log_level() << '\n';
return s.str();
}
void RasctlDisplay::DisplayDeviceTypesInfo(const PbDeviceTypesInfo& device_types_info) const
string RasctlDisplay::DisplayDeviceTypesInfo(const PbDeviceTypesInfo& device_types_info) const
{
cout << "Supported device types and their properties:";
ostringstream s;
s << "Supported device types and their properties:";
for (const auto& device_type_info : device_types_info.properties()) {
cout << endl << " " << PbDeviceType_Name(device_type_info.type()) << " ";
s << "\n " << PbDeviceType_Name(device_type_info.type()) << " ";
const PbDeviceProperties& properties = device_type_info.properties();
if (properties.read_only() || properties.protectable() || properties.stoppable() || properties.lockable()) {
cout << "Properties: ";
bool has_property = false;
if (properties.read_only()) {
cout << "read-only";
has_property = true;
}
if (properties.protectable()) {
cout << (has_property ? ", " : "") << "protectable";
has_property = true;
}
if (properties.stoppable()) {
cout << (has_property ? ", " : "") << "stoppable";
has_property = true;
}
if (properties.removable()) {
cout << (has_property ? ", " : "") << "removable";
has_property = true;
}
if (properties.lockable()) {
cout << (has_property ? ", " : "") << "lockable";
}
cout << endl << " ";
}
DisplayAttributes(s, properties);
if (properties.supports_file()) {
cout << "Image file support" << endl << " ";
s << "Image file support\n ";
}
if (properties.supports_params()) {
cout << "Parameter support" << endl << " ";
s << "Parameter support\n ";
}
if (properties.supports_params() && properties.default_params_size()) {
// Creates a sorted map
map<string, string> params = { properties.default_params().begin(), properties.default_params().end() };
DisplayDefaultParameters(s, properties);
cout << "Default parameters: ";
bool isFirst = true;
for (const auto& [key, value] : params) {
if (!isFirst) {
cout << endl << " ";
}
cout << key << "=" << value;
isFirst = false;
}
}
if (properties.block_sizes_size()) {
// Creates a sorted set
set<uint32_t> block_sizes = { properties.block_sizes().begin(), properties.block_sizes().end() };
cout << "Configurable block sizes in bytes: ";
bool isFirst = true;
for (const auto& block_size : block_sizes) {
if (!isFirst) {
cout << ", ";
}
cout << block_size;
isFirst = false;
}
}
DisplayBlockSizes(s, properties);
}
return s.str();
}
void RasctlDisplay::DisplayReservedIdsInfo(const PbReservedIdsInfo& reserved_ids_info) const
string RasctlDisplay::DisplayReservedIdsInfo(const PbReservedIdsInfo& reserved_ids_info) const
{
ostringstream s;
if (reserved_ids_info.ids_size()) {
cout << "Reserved device IDs: ";
s << "Reserved device IDs: ";
for (int i = 0; i < reserved_ids_info.ids_size(); i++) {
if(i) {
cout << ", ";
s << ", ";
}
cout << reserved_ids_info.ids(i);
s << reserved_ids_info.ids(i);
}
cout <<endl;
s << '\n';
}
else {
s << "No reserved device IDs\n";
}
return s.str();
}
void RasctlDisplay::DisplayImageFile(const PbImageFile& image_file_info) const
string RasctlDisplay::DisplayImageFile(const PbImageFile& image_file_info) const
{
cout << image_file_info.name() << " " << image_file_info.size() << " bytes";
ostringstream s;
s << image_file_info.name() << " " << image_file_info.size() << " bytes";
if (image_file_info.read_only()) {
cout << " read-only";
s << " read-only";
}
if (image_file_info.type() != UNDEFINED) {
cout << " " << PbDeviceType_Name(image_file_info.type());
}
cout << endl;
if (image_file_info.type() != UNDEFINED) {
s << " " << PbDeviceType_Name(image_file_info.type());
}
s << '\n';
return s.str();
}
void RasctlDisplay::DisplayImageFiles(const PbImageFilesInfo& image_files_info) const
string RasctlDisplay::DisplayImageFilesInfo(const PbImageFilesInfo& image_files_info) const
{
cout << "Default image file folder: " << image_files_info.default_image_folder() << endl;
cout << "Supported folder depth: " << image_files_info.depth() << endl;
ostringstream s;
s << "Default image file folder: " << image_files_info.default_image_folder() << '\n';
s << "Supported folder depth: " << image_files_info.depth() << '\n';
if (image_files_info.image_files().empty()) {
cout << " No image files available" << endl;
s << " No image files available\n";
}
else {
list<PbImageFile> image_files = { image_files_info.image_files().begin(), image_files_info.image_files().end() };
image_files.sort([](const auto& a, const auto& b) { return a.name() < b.name(); });
cout << "Available image files:" << endl;
s << "Available image files:\n";
for (const auto& image_file : image_files) {
cout << " ";
DisplayImageFile(image_file);
s << " ";
s << DisplayImageFile(image_file);
}
}
return s.str();
}
void RasctlDisplay::DisplayNetworkInterfaces(const PbNetworkInterfacesInfo& network_interfaces_info) const
string RasctlDisplay::DisplayNetworkInterfaces(const PbNetworkInterfacesInfo& network_interfaces_info) const
{
// Creates a sorted list
const list<string> interfaces = { network_interfaces_info.name().begin(), network_interfaces_info.name().end() };
ostringstream s;
s << "Available (up) network interfaces:\n";
const list<string> sorted_interfaces = { network_interfaces_info.name().begin(), network_interfaces_info.name().end() };
cout << "Available (up) network interfaces:" << endl;
bool isFirst = true;
for (const auto& interface : interfaces) {
for (const auto& interface : sorted_interfaces) {
if (!isFirst) {
cout << ", ";
s << ", ";
}
else {
cout << " ";
s << " ";
}
isFirst = false;
cout << interface;
s << interface;
}
cout << endl;
s << '\n';
return s.str();
}
void RasctlDisplay::DisplayMappingInfo(const PbMappingInfo& mapping_info) const
string RasctlDisplay::DisplayMappingInfo(const PbMappingInfo& mapping_info) const
{
// Creates a sorted map
const map<string, PbDeviceType> mappings = { mapping_info.mapping().begin(), mapping_info.mapping().end() };
ostringstream s;
cout << "Supported image file extension to device type mappings:" << endl;
for (const auto& [extension, type] : mappings) {
cout << " " << extension << "->" << PbDeviceType_Name(type) << endl;
s << "Supported image file extension to device type mappings:\n";
const map<string, PbDeviceType, less<>> sorted_mappings = { mapping_info.mapping().begin(), mapping_info.mapping().end() };
for (const auto& [extension, type] : sorted_mappings) {
s << " " << extension << "->" << PbDeviceType_Name(type) << '\n';
}
return s.str();
}
void RasctlDisplay::DisplayOperationInfo(const PbOperationInfo& operation_info) const
string RasctlDisplay::DisplayOperationInfo(const PbOperationInfo& operation_info) const
{
const map<int, PbOperationMetaData> operations = { operation_info.operations().begin(), operation_info.operations().end() };
ostringstream s;
const map<int, PbOperationMetaData, less<>> operations = { operation_info.operations().begin(), operation_info.operations().end() };
// Copies result into a map sorted by operation name
const PbOperationMetaData *unknown_operation = new PbOperationMetaData();
map<string, PbOperationMetaData> sorted_operations;
auto unknown_operation = make_unique<PbOperationMetaData>();
map<string, PbOperationMetaData, less<>> sorted_operations;
for (const auto& [ordinal, meta_data] : operations) {
if (PbOperation_IsValid(static_cast<PbOperation>(ordinal))) {
sorted_operations[PbOperation_Name(static_cast<PbOperation>(ordinal))] = meta_data;
@ -289,46 +297,149 @@ void RasctlDisplay::DisplayOperationInfo(const PbOperationInfo& operation_info)
}
}
cout << "Operations supported by rascsi server and their parameters:" << endl;
s << "Operations supported by rascsi server and their parameters:\n";
for (const auto& [name, meta_data] : sorted_operations) {
if (!meta_data.server_side_name().empty()) {
cout << " " << name;
s << " " << name;
if (!meta_data.description().empty()) {
cout << " (" << meta_data.description() << ")";
s << " (" << meta_data.description() << ")";
}
cout << endl;
s << '\n';
list<PbOperationParameter> sorted_parameters = { meta_data.parameters().begin(), meta_data.parameters().end() };
sorted_parameters.sort([](const auto& a, const auto& b) { return a.name() < b.name(); });
for (const auto& parameter : sorted_parameters) {
cout << " " << parameter.name() << ": "
<< (parameter.is_mandatory() ? "mandatory" : "optional");
if (!parameter.description().empty()) {
cout << " (" << parameter.description() << ")";
}
cout << endl;
if (parameter.permitted_values_size()) {
cout << " Permitted values: ";
bool isFirst = true;
for (const auto& permitted_value : parameter.permitted_values()) {
if (!isFirst) {
cout << ", ";
}
isFirst = false;
cout << permitted_value;
}
cout << endl;
}
if (!parameter.default_value().empty()) {
cout << " Default value: " << parameter.default_value() << endl;
}
}
DisplayParameters(s, meta_data);
}
else {
cout << " " << name << " (Unknown server-side operation)" << endl;
s << " " << name << " (Unknown server-side operation)\n";
}
}
return s.str();
}
void RasctlDisplay::DisplayParams(ostringstream& s, const PbDevice& pb_device) const
{
const map<string, string, less<>> sorted_params = { pb_device.params().begin(), pb_device.params().end() };
bool isFirst = true;
for (const auto& [key, value] : sorted_params) {
if (!isFirst) {
s << ":";
}
isFirst = false;
s << key << "=" << value;
}
}
void RasctlDisplay::DisplayAttributes(ostringstream& s, const PbDeviceProperties& properties) const
{
if (properties.read_only() || properties.protectable() || properties.stoppable() || properties.lockable()) {
s << "Properties: ";
bool has_property = false;
if (properties.read_only()) {
s << "read-only";
has_property = true;
}
if (properties.protectable()) {
s << (has_property ? ", " : "") << "protectable";
has_property = true;
}
if (properties.stoppable()) {
s << (has_property ? ", " : "") << "stoppable";
has_property = true;
}
if (properties.removable()) {
s << (has_property ? ", " : "") << "removable";
has_property = true;
}
if (properties.lockable()) {
s << (has_property ? ", " : "") << "lockable";
}
s << "\n ";
}
}
void RasctlDisplay::DisplayDefaultParameters(ostringstream& s, const PbDeviceProperties& properties) const
{
if (properties.supports_params() && properties.default_params_size()) {
s << "Default parameters: ";
const map<string, string, less<>> sorted_params = { properties.default_params().begin(), properties.default_params().end() };
bool isFirst = true;
for (const auto& [key, value] : sorted_params) {
if (!isFirst) {
s << "\n ";
}
s << key << "=" << value;
isFirst = false;
}
}
}
void RasctlDisplay::DisplayBlockSizes(ostringstream& s, const PbDeviceProperties& properties) const
{
if (properties.block_sizes_size()) {
s << "Configurable block sizes in bytes: ";
const set<uint32_t> sorted_sizes = { properties.block_sizes().begin(), properties.block_sizes().end() };
bool isFirst = true;
for (const auto& size : sorted_sizes) {
if (!isFirst) {
s << ", ";
}
s << size;
isFirst = false;
}
}
}
void RasctlDisplay::DisplayParameters(ostringstream& s, const PbOperationMetaData& meta_data) const
{
list<PbOperationParameter> sorted_parameters = { meta_data.parameters().begin(), meta_data.parameters().end() };
sorted_parameters.sort([](const auto& a, const auto& b) { return a.name() < b.name(); });
for (const auto& parameter : sorted_parameters) {
s << " " << parameter.name() << ": "
<< (parameter.is_mandatory() ? "mandatory" : "optional");
if (!parameter.description().empty()) {
s << " (" << parameter.description() << ")";
}
s << '\n';
DisplayPermittedValues(s, parameter);
if (!parameter.default_value().empty()) {
s << " Default value: " << parameter.default_value() << '\n';
}
}
}
void RasctlDisplay::DisplayPermittedValues(ostringstream& s, const PbOperationParameter& parameter) const
{
if (parameter.permitted_values_size()) {
s << " Permitted values: ";
bool isFirst = true;
for (const auto& permitted_value : parameter.permitted_values()) {
if (!isFirst) {
s << ", ";
}
isFirst = false;
s << permitted_value;
}
s << '\n';
}
}

View File

@ -10,25 +10,37 @@
#pragma once
#include "rascsi_interface.pb.h"
#include <string>
#include <sstream>
using namespace std;
using namespace rascsi_interface;
class RasctlDisplay
{
friend class RasctlCommands;
public:
RasctlDisplay() = default;
~RasctlDisplay() = default;
void DisplayDevices(const PbDevicesInfo&) const;
void DisplayDeviceInfo(const PbDevice&) const;
void DisplayVersionInfo(const PbVersionInfo&) const;
void DisplayLogLevelInfo(const PbLogLevelInfo&) const;
void DisplayDeviceTypesInfo(const PbDeviceTypesInfo&) const;
void DisplayReservedIdsInfo(const PbReservedIdsInfo&) const;
void DisplayImageFile(const PbImageFile&) const;
void DisplayImageFiles(const PbImageFilesInfo&) const;
void DisplayNetworkInterfaces(const PbNetworkInterfacesInfo&) const;
void DisplayMappingInfo(const PbMappingInfo&) const;
void DisplayOperationInfo(const PbOperationInfo&) const;
string DisplayDevicesInfo(const PbDevicesInfo&) const;
string DisplayDeviceInfo(const PbDevice&) const;
string DisplayVersionInfo(const PbVersionInfo&) const;
string DisplayLogLevelInfo(const PbLogLevelInfo&) const;
string DisplayDeviceTypesInfo(const PbDeviceTypesInfo&) const;
string DisplayReservedIdsInfo(const PbReservedIdsInfo&) const;
string DisplayImageFile(const PbImageFile&) const;
string DisplayImageFilesInfo(const PbImageFilesInfo&) const;
string DisplayNetworkInterfaces(const PbNetworkInterfacesInfo&) const;
string DisplayMappingInfo(const PbMappingInfo&) const;
string DisplayOperationInfo(const PbOperationInfo&) const;
private:
void DisplayParams(ostringstream&, const PbDevice&) const;
void DisplayAttributes(ostringstream&, const PbDeviceProperties&) const;
void DisplayDefaultParameters(ostringstream&, const PbDeviceProperties&) const;
void DisplayBlockSizes(ostringstream&, const PbDeviceProperties&) const;
void DisplayParameters(ostringstream&, const PbOperationMetaData&) const;
void DisplayPermittedValues(ostringstream&, const PbOperationParameter&) const;
};

View File

@ -0,0 +1,31 @@
//---------------------------------------------------------------------------
//
// SCSI Target Emulator RaSCSI Reloaded
// for Raspberry Pi
//
// Copyright (C) 2022 Uwe Seimet
//
//---------------------------------------------------------------------------
#include "rasctl_parser.h"
PbOperation RasctlParser::ParseOperation(const string& operation) const
{
const auto& it = operations.find(tolower(operation[0]));
return it != operations.end() ? it->second : NO_OPERATION;
}
PbDeviceType RasctlParser::ParseType(const string& type) const
{
string t = type;
transform(t.begin(), t.end(), t.begin(), ::toupper);
if (PbDeviceType parsed_type; PbDeviceType_Parse(t, &parsed_type)) {
return parsed_type;
}
// Handle convenience device types (shortcuts)
const auto& it = device_types.find(tolower(type[0]));
return it != device_types.end() ? it->second : UNDEFINED;
}

View File

@ -0,0 +1,49 @@
//---------------------------------------------------------------------------
//
// SCSI Target Emulator RaSCSI Reloaded
// for Raspberry Pi
//
// Copyright (C) 2022 Uwe Seimet
//
//---------------------------------------------------------------------------
#include "rascsi_interface.pb.h"
#include <string>
#include <unordered_map>
using namespace std;
using namespace rascsi_interface;
class RasctlParser
{
public:
RasctlParser() = default;
~RasctlParser() = default;
PbOperation ParseOperation(const string&) const;
PbDeviceType ParseType(const string&) const;
private:
unordered_map<int, PbOperation> operations = {
{ 'a', ATTACH },
{ 'd', DETACH },
{ 'i', INSERT },
{ 'e', EJECT },
{ 'p', PROTECT },
{ 'u', UNPROTECT }
};
unordered_map<int, PbDeviceType> device_types = {
{ 'b', SCBR },
{ 'c', SCCD },
{ 'd', SCDP },
{ 'h', SCHD },
{ 'l', SCLP },
{ 'm', SCMO },
{ 'r', SCRM },
{ 's', SCHS }
};
};

View File

@ -217,7 +217,7 @@ bool ParseArgument(int argc, char* argv[])
bool WaitPhase(BUS::phase_t phase)
{
// Timeout (3000ms)
uint32_t now = SysTimer::GetTimerLow();
const uint32_t now = SysTimer::GetTimerLow();
while ((SysTimer::GetTimerLow() - now) < 3 * 1000 * 1000) {
bus.Acquire();
if (bus.GetREQ() && bus.GetPhase() == phase) {
@ -246,21 +246,17 @@ void BusFree()
//---------------------------------------------------------------------------
bool Selection(int id)
{
BYTE data;
int count;
// ID setting and SEL assert
data = 0;
data |= (1 << boardid);
BYTE data = 1 << boardid;
data |= (1 << id);
bus.SetDAT(data);
bus.SetSEL(true);
// wait for busy
count = 10000;
int count = 10000;
do {
// Wait 20 microseconds
timespec ts = { .tv_sec = 0, .tv_nsec = 20 * 1000};
const timespec ts = { .tv_sec = 0, .tv_nsec = 20 * 1000};
nanosleep(&ts, nullptr);
bus.Acquire();
if (bus.GetBSY()) {
@ -282,15 +278,13 @@ bool Selection(int id)
//---------------------------------------------------------------------------
bool Command(BYTE *buf, int length)
{
int count;
// Waiting for Phase
if (!WaitPhase(BUS::phase_t::command)) {
return false;
}
// Send Command
count = bus.SendHandShake(buf, length, BUS::SEND_NO_DELAY);
const int count = bus.SendHandShake(buf, length, BUS::SEND_NO_DELAY);
// Success if the transmission result is the same as the number
// of requests
@ -665,7 +659,7 @@ exit:
// READ10
//
//---------------------------------------------------------------------------
int Read10(int id, DWORD bstart, DWORD blength, DWORD length, BYTE *buf)
int Read10(int id, uint32_t bstart, uint32_t blength, uint32_t length, BYTE *buf)
{
array<BYTE, 256> cmd = {};
@ -728,7 +722,7 @@ exit:
// WRITE10
//
//---------------------------------------------------------------------------
int Write10(int id, DWORD bstart, DWORD blength, DWORD length, BYTE *buf)
int Write10(int id, uint32_t bstart, uint32_t blength, uint32_t length, BYTE *buf)
{
array<BYTE, 256> cmd = {};
@ -794,13 +788,12 @@ exit:
int main(int argc, char* argv[])
{
int i;
int count;
char str[32];
DWORD bsiz;
DWORD bnum;
DWORD duni;
DWORD dsiz;
DWORD dnum;
uint32_t bsiz;
uint32_t bnum;
uint32_t duni;
uint32_t dsiz;
uint32_t dnum;
Fileio fio;
Fileio::OpenMode omode;
off_t size;
@ -855,7 +848,7 @@ int main(int argc, char* argv[])
// Assert reset signal
bus.SetRST(true);
// Wait 1 ms
timespec ts = { .tv_sec = 0, .tv_nsec = 1000 * 1000};
const timespec ts = { .tv_sec = 0, .tv_nsec = 1000 * 1000};
nanosleep(&ts, nullptr);
bus.SetRST(false);
@ -864,7 +857,7 @@ int main(int argc, char* argv[])
printf("BOARD ID : %d\n", boardid);
// TEST UNIT READY
count = TestUnitReady(targetid);
int count = TestUnitReady(targetid);
if (count < 0) {
fprintf(stderr, "TEST UNIT READY ERROR %d\n", count);
goto cleanup_exit;

View File

@ -7,10 +7,9 @@
//
//---------------------------------------------------------------------------
#include <list>
#include <sstream>
#include "rascsi_interface.pb.h"
#include "rascsi_version.h"
#include "rasutil.h"
#include <sstream>
using namespace std;
using namespace rascsi_interface;
@ -35,16 +34,30 @@ bool ras_util::GetAsInt(const string& value, int& result)
return true;
}
string ras_util::Banner(const string& app)
{
ostringstream s;
s << "SCSI Target Emulator RaSCSI " << app << " version " << rascsi_get_version_string()
<< " (" << __DATE__ << ' ' << __TIME__ << ")\n";
s << "Powered by XM6 TypeG Technology / ";
s << "Copyright (C) 2016-2020 GIMONS\n";
s << "Copyright (C) 2020-2022 Contributors to the RaSCSI Reloaded project\n";
return s.str();
}
string ras_util::ListDevices(const list<PbDevice>& pb_devices)
{
if (pb_devices.empty()) {
return "No devices currently attached.";
return "No devices currently attached.\n";
}
ostringstream s;
s << "+----+-----+------+-------------------------------------" << endl
<< "| ID | LUN | TYPE | IMAGE FILE" << endl
<< "+----+-----+------+-------------------------------------" << endl;
s << "+----+-----+------+-------------------------------------\n"
<< "| ID | LUN | TYPE | IMAGE FILE\n"
<< "+----+-----+------+-------------------------------------\n";
list<PbDevice> devices = pb_devices;
devices.sort([](const auto& a, const auto& b) { return a.id() < b.id() || a.unit() < b.unit(); });
@ -76,10 +89,10 @@ string ras_util::ListDevices(const list<PbDevice>& pb_devices)
s << "| " << device.id() << " | " << device.unit() << " | " << PbDeviceType_Name(device.type()) << " | "
<< (filename.empty() ? "NO MEDIA" : filename)
<< (!device.status().removed() && (device.properties().read_only() || device.status().protected_()) ? " (READ-ONLY)" : "")
<< endl;
<< '\n';
}
s << "+----+-----+------+-------------------------------------";
s << "+----+-----+------+-------------------------------------\n";
return s.str();
}

View File

@ -15,10 +15,13 @@
#include <string>
#include "rascsi_interface.pb.h"
using namespace std;
namespace ras_util
{
bool GetAsInt(const std::string&, int&);
std::string ListDevices(const std::list<rascsi_interface::PbDevice>&);
bool GetAsInt(const string&, int&);
string Banner(const string&);
string ListDevices(const list<rascsi_interface::PbDevice>&);
void FixCpu(int);
}

View File

@ -33,6 +33,7 @@ namespace scsi_defs {
COMMUNICATIONS = 9
};
// TODO Use a mapping of enum to structure with command byte count and enum name
enum class scsi_command : int {
eCmdTestUnitReady = 0x00,
eCmdRezero = 0x01,

View File

@ -35,9 +35,9 @@ static const int _MAX_FNAME = 256;
static volatile bool running; // Running flag
GPIOBUS bus; // GPIO Bus
DWORD buff_size = 1000000;
uint32_t buff_size = 1000000;
data_capture *data_buffer;
DWORD data_idx = 0;
uint32_t data_idx = 0;
double ns_per_loop;
@ -94,8 +94,7 @@ void parse_arguments(int argc, char *argv[])
}
/* Process any remaining command line arguments (not options). */
if (optind < argc)
{
if (optind < argc) {
while (optind < argc)
strncpy(file_base_name, argv[optind++], sizeof(file_base_name)-1);
}
@ -147,12 +146,10 @@ void print_help_text(int, char *argv[])
//---------------------------------------------------------------------------
void Banner(int, char *[])
{
if (import_data)
{
if (import_data) {
LOGINFO("Reading input file: %s", input_file_name)
}
else
{
else {
LOGINFO("Reading live data from the GPIO pins")
LOGINFO(" Connection type : %s", CONNECT_DESC.c_str())
}
@ -172,16 +169,13 @@ void Banner(int, char *[])
bool Init()
{
// Interrupt handler settings
if (signal(SIGINT, KillHandler) == SIG_ERR)
{
if (signal(SIGINT, KillHandler) == SIG_ERR) {
return false;
}
if (signal(SIGHUP, KillHandler) == SIG_ERR)
{
if (signal(SIGHUP, KillHandler) == SIG_ERR) {
return false;
}
if (signal(SIGTERM, KillHandler) == SIG_ERR)
{
if (signal(SIGTERM, KillHandler) == SIG_ERR) {
return false;
}
@ -249,8 +243,8 @@ void FixCpu(int cpu)
#endif
#ifdef DEBUG
static DWORD high_bits = 0x0;
static DWORD low_bits = 0xFFFFFFFF;
static uint32_t high_bits = 0x0;
static uint32_t low_bits = 0xFFFFFFFF;
#endif
//---------------------------------------------------------------------------
@ -272,12 +266,12 @@ int main(int argc, char *argv[])
parse_arguments(argc, argv);
#ifdef DEBUG
DWORD prev_high = high_bits;
DWORD prev_low = low_bits;
uint32_t prev_high = high_bits;
uint32_t prev_low = low_bits;
#endif
ostringstream s;
DWORD prev_sample = 0xFFFFFFFF;
DWORD this_sample = 0;
uint32_t prev_sample = 0xFFFFFFFF;
uint32_t this_sample = 0;
timeval start_time;
timeval stop_time;
uint64_t loop_count = 0;
@ -312,8 +306,7 @@ int main(int argc, char *argv[])
// Initialize
int ret = 0;
if (!Init())
{
if (!Init()) {
ret = EPERM;
goto init_exit;
}

View File

@ -75,10 +75,10 @@ TEST(AbstractControllerTest, ProcessPhase)
controller.ProcessPhase();
controller.SetPhase(BUS::phase_t::reselection);
EXPECT_THROW(controller.ProcessPhase(), scsi_error_exception);
EXPECT_THROW(controller.ProcessPhase(), scsi_exception);
controller.SetPhase(BUS::phase_t::reserved);
EXPECT_THROW(controller.ProcessPhase(), scsi_error_exception);
EXPECT_THROW(controller.ProcessPhase(), scsi_exception);
}
TEST(AbstractControllerTest, DeviceLunLifeCycle)

View File

@ -0,0 +1,89 @@
//---------------------------------------------------------------------------
//
// SCSI Target Emulator RaSCSI Reloaded
// for Raspberry Pi
//
// Copyright (C) 2022 Uwe Seimet
//
//---------------------------------------------------------------------------
#include "mocks.h"
#include "bus.h"
TEST(BusTest, GetPhase)
{
EXPECT_EQ(BUS::phase_t::dataout, BUS::GetPhase(0b000));
EXPECT_EQ(BUS::phase_t::datain, BUS::GetPhase(0b001));
EXPECT_EQ(BUS::phase_t::command, BUS::GetPhase(0b010));
EXPECT_EQ(BUS::phase_t::status, BUS::GetPhase(0b011));
EXPECT_EQ(BUS::phase_t::reserved, BUS::GetPhase(0b100));
EXPECT_EQ(BUS::phase_t::reserved, BUS::GetPhase(0b101));
EXPECT_EQ(BUS::phase_t::msgout, BUS::GetPhase(0b110));
EXPECT_EQ(BUS::phase_t::msgin, BUS::GetPhase(0b111));
NiceMock<MockBus> bus;
EXPECT_EQ(BUS::phase_t::busfree, bus.GetPhase());
ON_CALL(bus, GetSEL()).WillByDefault(Return(true));
EXPECT_EQ(BUS::phase_t::selection, bus.GetPhase());
ON_CALL(bus, GetSEL()).WillByDefault(Return(false));
ON_CALL(bus, GetBSY()).WillByDefault(Return(true));
ON_CALL(bus, GetMSG()).WillByDefault(Return(false));
EXPECT_EQ(BUS::phase_t::dataout, bus.GetPhase());
ON_CALL(bus, GetMSG()).WillByDefault(Return(true));
EXPECT_EQ(BUS::phase_t::reserved, bus.GetPhase());
ON_CALL(bus, GetMSG()).WillByDefault(Return(false));
ON_CALL(bus, GetCD()).WillByDefault(Return(true));
EXPECT_EQ(BUS::phase_t::command, bus.GetPhase());
ON_CALL(bus, GetMSG()).WillByDefault(Return(true));
ON_CALL(bus, GetCD()).WillByDefault(Return(true));
EXPECT_EQ(BUS::phase_t::msgout, bus.GetPhase());
ON_CALL(bus, GetMSG()).WillByDefault(Return(false));
ON_CALL(bus, GetCD()).WillByDefault(Return(false));
ON_CALL(bus, GetIO()).WillByDefault(Return(true));
EXPECT_EQ(BUS::phase_t::datain, bus.GetPhase());
ON_CALL(bus, GetMSG()).WillByDefault(Return(true));
ON_CALL(bus, GetCD()).WillByDefault(Return(false));
ON_CALL(bus, GetIO()).WillByDefault(Return(true));
EXPECT_EQ(BUS::phase_t::reserved, bus.GetPhase());
ON_CALL(bus, GetMSG()).WillByDefault(Return(true));
ON_CALL(bus, GetCD()).WillByDefault(Return(true));
ON_CALL(bus, GetIO()).WillByDefault(Return(true));
EXPECT_EQ(BUS::phase_t::msgin, bus.GetPhase());
ON_CALL(bus, GetMSG()).WillByDefault(Return(false));
ON_CALL(bus, GetCD()).WillByDefault(Return(true));
ON_CALL(bus, GetIO()).WillByDefault(Return(true));
EXPECT_EQ(BUS::phase_t::status, bus.GetPhase());
}
TEST(BusTest, GetPhaseStrRaw)
{
EXPECT_STREQ("busfree", BUS::GetPhaseStrRaw(BUS::phase_t::busfree));
EXPECT_STREQ("arbitration", BUS::GetPhaseStrRaw(BUS::phase_t::arbitration));
EXPECT_STREQ("selection", BUS::GetPhaseStrRaw(BUS::phase_t::selection));
EXPECT_STREQ("reselection", BUS::GetPhaseStrRaw(BUS::phase_t::reselection));
EXPECT_STREQ("command", BUS::GetPhaseStrRaw(BUS::phase_t::command));
EXPECT_STREQ("datain", BUS::GetPhaseStrRaw(BUS::phase_t::datain));
EXPECT_STREQ("dataout", BUS::GetPhaseStrRaw(BUS::phase_t::dataout));
EXPECT_STREQ("status", BUS::GetPhaseStrRaw(BUS::phase_t::status));
EXPECT_STREQ("msgin", BUS::GetPhaseStrRaw(BUS::phase_t::msgin));
EXPECT_STREQ("msgout", BUS::GetPhaseStrRaw(BUS::phase_t::msgout));
EXPECT_STREQ("reserved", BUS::GetPhaseStrRaw(BUS::phase_t::reserved));
}
TEST(BusTest, GetPinRaw)
{
EXPECT_EQ(0, BUS::GetPinRaw(0, 0));
EXPECT_EQ(0, BUS::GetPinRaw(0, 7));
EXPECT_EQ(1, BUS::GetPinRaw(-1, 0));
EXPECT_EQ(1, BUS::GetPinRaw(-1, 7));
}

View File

@ -7,14 +7,48 @@
//
//---------------------------------------------------------------------------
#include "mocks.h"
#include <gmock/gmock.h>
#include "rascsi/command_context.h"
using namespace rascsi_interface;
TEST(CommandContext, GetSerializer)
{
CommandContext context("", -1);
// There is nothing more that can be tested
context.GetSerializer();
}
TEST(CommandContext, IsValid)
{
CommandContext context("", -1);
EXPECT_FALSE(context.IsValid());
context.SetFd(1);
EXPECT_TRUE(context.IsValid());
}
TEST(CommandContext, Cleanup)
{
CommandContext context("", 0);
EXPECT_EQ(0, context.GetFd());
context.Cleanup();
EXPECT_EQ(-1, context.GetFd());
}
TEST(CommandContext, ReturnLocalizedError)
{
MockCommandContext context;
CommandContext context("en_US", -1);
EXPECT_FALSE(context.ReturnLocalizedError(LocalizationKey::ERROR_LOG_LEVEL));
}
TEST(CommandContext, ReturnStatus)
{
CommandContext context("", -1);
EXPECT_TRUE(context.ReturnStatus(true, "status"));
EXPECT_FALSE(context.ReturnStatus(false, "status"));
}

View File

@ -21,8 +21,11 @@ TEST(ControllerManagerTest, LifeCycle)
ControllerManager controller_manager(bus);
DeviceFactory device_factory;
auto device = device_factory.CreateDevice(controller_manager, UNDEFINED, LUN1, "services");
controller_manager.AttachToScsiController(ID, device);
auto device = device_factory.CreateDevice(controller_manager, UNDEFINED, -1, "services");
EXPECT_FALSE(controller_manager.AttachToScsiController(ID, device));
device = device_factory.CreateDevice(controller_manager, UNDEFINED, LUN1, "services");
EXPECT_TRUE(controller_manager.AttachToScsiController(ID, device));
auto controller = controller_manager.FindController(ID);
EXPECT_NE(nullptr, controller);
EXPECT_EQ(1, controller->GetLunCount());
@ -33,9 +36,9 @@ TEST(ControllerManagerTest, LifeCycle)
EXPECT_EQ(nullptr, controller_manager.GetDeviceByIdAndLun(0, 0));
device = device_factory.CreateDevice(controller_manager, UNDEFINED, LUN2, "services");
controller_manager.AttachToScsiController(ID, device);
EXPECT_TRUE(controller_manager.AttachToScsiController(ID, device));
controller = controller_manager.FindController(ID);
controller_manager.DeleteController(controller);
EXPECT_TRUE(controller_manager.DeleteController(controller));
EXPECT_EQ(nullptr, controller_manager.FindController(ID));
controller_manager.DeleteAllControllers();
@ -52,7 +55,7 @@ TEST(ControllerManagerTest, ResetAllControllers)
DeviceFactory device_factory;
auto device = device_factory.CreateDevice(controller_manager, UNDEFINED, 0, "services");
controller_manager.AttachToScsiController(ID, device);
EXPECT_TRUE(controller_manager.AttachToScsiController(ID, device));
auto controller = controller_manager.FindController(ID);
EXPECT_NE(nullptr, controller);

View File

@ -22,10 +22,8 @@ TEST(DiskTest, Dispatch)
controller.AddDevice(disk);
controller.InitCmd(6);
disk->MediumChanged();
EXPECT_THROW(disk->Dispatch(scsi_command::eCmdTestUnitReady), scsi_error_exception);
EXPECT_THROW(disk->Dispatch(scsi_command::eCmdTestUnitReady), scsi_exception);
}
TEST(DiskTest, Rezero)
@ -35,7 +33,7 @@ TEST(DiskTest, Rezero)
controller.AddDevice(disk);
EXPECT_THROW(disk->Dispatch(scsi_command::eCmdRezero), scsi_error_exception)
EXPECT_THROW(disk->Dispatch(scsi_command::eCmdRezero), scsi_exception)
<< "REZERO must fail because drive is not ready";
disk->SetReady(true);
@ -54,7 +52,7 @@ TEST(DiskTest, FormatUnit)
vector<int>& cmd = controller.InitCmd(6);
EXPECT_THROW(disk->Dispatch(scsi_command::eCmdFormat), scsi_error_exception);
EXPECT_THROW(disk->Dispatch(scsi_command::eCmdFormat), scsi_exception);
disk->SetReady(true);
@ -64,7 +62,7 @@ TEST(DiskTest, FormatUnit)
cmd[1] = 0x10;
cmd[4] = 1;
EXPECT_THROW(disk->Dispatch(scsi_command::eCmdFormat), scsi_error_exception);
EXPECT_THROW(disk->Dispatch(scsi_command::eCmdFormat), scsi_exception);
}
TEST(DiskTest, ReassignBlocks)
@ -74,7 +72,7 @@ TEST(DiskTest, ReassignBlocks)
controller.AddDevice(disk);
EXPECT_THROW(disk->Dispatch(scsi_command::eCmdReassign), scsi_error_exception)
EXPECT_THROW(disk->Dispatch(scsi_command::eCmdReassign), scsi_exception)
<< "REASSIGN must fail because drive is not ready";
disk->SetReady(true);
@ -93,15 +91,15 @@ TEST(DiskTest, Seek)
vector<int>& cmd = controller.InitCmd(10);
EXPECT_THROW(disk->Dispatch(scsi_command::eCmdSeek6), scsi_error_exception)
EXPECT_THROW(disk->Dispatch(scsi_command::eCmdSeek6), scsi_exception)
<< "SEEK(6) must fail for a medium with 0 blocks";
EXPECT_THROW(disk->Dispatch(scsi_command::eCmdSeek10), scsi_error_exception)
EXPECT_THROW(disk->Dispatch(scsi_command::eCmdSeek10), scsi_exception)
<< "SEEK(10) must fail for a medium with 0 blocks";
disk->SetBlockCount(1);
EXPECT_THROW(disk->Dispatch(scsi_command::eCmdSeek6), scsi_error_exception)
EXPECT_THROW(disk->Dispatch(scsi_command::eCmdSeek6), scsi_exception)
<< "SEEK(6) must fail because drive is not ready";
EXPECT_THROW(disk->Dispatch(scsi_command::eCmdSeek10), scsi_error_exception)
EXPECT_THROW(disk->Dispatch(scsi_command::eCmdSeek10), scsi_exception)
<< "SEEK(10) must fail because drive is not ready";
disk->SetReady(true);
@ -129,23 +127,23 @@ TEST(DiskTest, ReadCapacity)
vector<int>& cmd = controller.InitCmd(16);
EXPECT_THROW(disk->Dispatch(scsi_command::eCmdReadCapacity16_ReadLong16), scsi_error_exception)
EXPECT_THROW(disk->Dispatch(scsi_command::eCmdReadCapacity16_ReadLong16), scsi_exception)
<< "Neithed READ CAPACITY(16) nor READ LONG(16)";
EXPECT_THROW(disk->Dispatch(scsi_command::eCmdReadCapacity10), scsi_error_exception)
EXPECT_THROW(disk->Dispatch(scsi_command::eCmdReadCapacity10), scsi_exception)
<< "READ CAPACITY(10) must fail because drive is not ready";
// READ CAPACITY(16), not READ LONG(16)
cmd[1] = 0x10;
EXPECT_THROW(disk->Dispatch(scsi_command::eCmdReadCapacity16_ReadLong16), scsi_error_exception)
EXPECT_THROW(disk->Dispatch(scsi_command::eCmdReadCapacity16_ReadLong16), scsi_exception)
<< "READ CAPACITY(16) must fail because drive is not ready";
cmd[1] = 0x00;
disk->SetReady(true);
EXPECT_THROW(disk->Dispatch(scsi_command::eCmdReadCapacity10), scsi_error_exception)
EXPECT_THROW(disk->Dispatch(scsi_command::eCmdReadCapacity10), scsi_exception)
<< "READ CAPACITY(10) must fail because the medium has no capacity";
// READ CAPACITY(16), not READ LONG(16)
cmd[1] = 0x10;
EXPECT_THROW(disk->Dispatch(scsi_command::eCmdReadCapacity16_ReadLong16), scsi_error_exception)
EXPECT_THROW(disk->Dispatch(scsi_command::eCmdReadCapacity16_ReadLong16), scsi_exception)
<< "READ CAPACITY(16) must fail because the medium has no capacity";
cmd[1] = 0x00;
@ -201,22 +199,22 @@ TEST(DiskTest, ReadWriteLong)
EXPECT_EQ(status::GOOD, controller.GetStatus());
cmd[2] = 1;
EXPECT_THROW(disk->Dispatch(scsi_command::eCmdReadLong10), scsi_error_exception)
EXPECT_THROW(disk->Dispatch(scsi_command::eCmdReadLong10), scsi_exception)
<< "READ LONG(10) must fail because the capacity is exceeded";
EXPECT_THROW(disk->Dispatch(scsi_command::eCmdWriteLong10), scsi_error_exception)
EXPECT_THROW(disk->Dispatch(scsi_command::eCmdWriteLong10), scsi_exception)
<< "WRITE LONG(10) must fail because the capacity is exceeded";
// READ LONG(16), not READ CAPACITY(16)
cmd[1] = 0x11;
EXPECT_THROW(disk->Dispatch(scsi_command::eCmdReadCapacity16_ReadLong16), scsi_error_exception)
EXPECT_THROW(disk->Dispatch(scsi_command::eCmdReadCapacity16_ReadLong16), scsi_exception)
<< "READ LONG(16) must fail because the capacity is exceeded";
EXPECT_THROW(disk->Dispatch(scsi_command::eCmdWriteLong16), scsi_error_exception)
EXPECT_THROW(disk->Dispatch(scsi_command::eCmdWriteLong16), scsi_exception)
<< "WRITE LONG(16) must fail because the capacity is exceeded";
cmd[2] = 0;
cmd[7] = 1;
EXPECT_THROW(disk->Dispatch(scsi_command::eCmdReadLong10), scsi_error_exception)
EXPECT_THROW(disk->Dispatch(scsi_command::eCmdReadLong10), scsi_exception)
<< "READ LONG(10) must fail because it currently only supports 0 bytes transfer length";
EXPECT_THROW(disk->Dispatch(scsi_command::eCmdWriteLong10), scsi_error_exception)
EXPECT_THROW(disk->Dispatch(scsi_command::eCmdWriteLong10), scsi_exception)
<< "WRITE LONG(10) must fail because it currently only supports 0 bytes transfer length";
cmd[7] = 0;
@ -233,25 +231,31 @@ TEST(DiskTest, ReadWriteLong)
cmd[13] = 1;
// READ LONG(16), not READ CAPACITY(16)
cmd[1] = 0x11;
EXPECT_THROW(disk->Dispatch(scsi_command::eCmdReadCapacity16_ReadLong16), scsi_error_exception)
EXPECT_THROW(disk->Dispatch(scsi_command::eCmdReadCapacity16_ReadLong16), scsi_exception)
<< "READ LONG(16) must fail because it currently only supports 0 bytes transfer length";
cmd[1] = 0x00;
EXPECT_THROW(disk->Dispatch(scsi_command::eCmdWriteLong16), scsi_error_exception)
EXPECT_THROW(disk->Dispatch(scsi_command::eCmdWriteLong16), scsi_exception)
<< "WRITE LONG(16) must fail because it currently only supports 0 bytes transfer length";
}
TEST(DiskTest, ReserveRelease)
TEST(DiskTest, Reserve)
{
MockAbstractController controller(0);
auto disk = make_shared<MockDisk>();
controller.AddDevice(disk);
controller.InitCmd(6);
EXPECT_CALL(controller, Status()).Times(1);
EXPECT_TRUE(disk->Dispatch(scsi_command::eCmdReserve6));
EXPECT_EQ(status::GOOD, controller.GetStatus());
}
TEST(DiskTest, Release)
{
MockAbstractController controller(0);
auto disk = make_shared<MockDisk>();
controller.AddDevice(disk);
EXPECT_CALL(controller, Status()).Times(1);
EXPECT_TRUE(disk->Dispatch(scsi_command::eCmdRelease6));
@ -272,16 +276,16 @@ TEST(DiskTest, SendDiagnostic)
EXPECT_EQ(status::GOOD, controller.GetStatus());
cmd[1] = 0x10;
EXPECT_THROW(disk->Dispatch(scsi_command::eCmdSendDiag), scsi_error_exception)
EXPECT_THROW(disk->Dispatch(scsi_command::eCmdSendDiag), scsi_exception)
<< "SEND DIAGNOSTIC must fail because PF bit is not supported";
cmd[1] = 0;
cmd[3] = 1;
EXPECT_THROW(disk->Dispatch(scsi_command::eCmdSendDiag), scsi_error_exception)
EXPECT_THROW(disk->Dispatch(scsi_command::eCmdSendDiag), scsi_exception)
<< "SEND DIAGNOSTIC must fail because parameter list is not supported";
cmd[3] = 0;
cmd[4] = 1;
EXPECT_THROW(disk->Dispatch(scsi_command::eCmdSendDiag), scsi_error_exception)
EXPECT_THROW(disk->Dispatch(scsi_command::eCmdSendDiag), scsi_exception)
<< "SEND DIAGNOSTIC must fail because parameter list is not supported";
}
@ -294,7 +298,7 @@ TEST(DiskTest, PreventAllowMediumRemoval)
vector<int>& cmd = controller.InitCmd(6);
EXPECT_THROW(disk->Dispatch(scsi_command::eCmdRemoval), scsi_error_exception)
EXPECT_THROW(disk->Dispatch(scsi_command::eCmdRemoval), scsi_exception)
<< "REMOVAL must fail because drive is not ready";
disk->SetReady(true);
@ -318,15 +322,11 @@ TEST(DiskTest, SynchronizeCache)
controller.AddDevice(disk);
controller.InitCmd(10);
EXPECT_CALL(*disk, FlushCache()).Times(1);
EXPECT_CALL(controller, Status()).Times(1);
EXPECT_TRUE(disk->Dispatch(scsi_command::eCmdSynchronizeCache10));
EXPECT_EQ(status::GOOD, controller.GetStatus());
controller.InitCmd(16);
EXPECT_CALL(*disk, FlushCache()).Times(1);
EXPECT_CALL(controller, Status()).Times(1);
EXPECT_TRUE(disk->Dispatch(scsi_command::eCmdSynchronizeCache16));
@ -410,3 +410,46 @@ TEST(DiskTest, BlockCount)
disk.SetBlockCount(0x1234567887654321);
EXPECT_EQ(0x1234567887654321, disk.GetBlockCount());
}
TEST(DiskTest, GetIdsForReservedFile)
{
const int ID = 1;
const int LUN = 2;
Filepath path;
path.SetPath("path");
MockDisk disk;
disk.SetPath(path);
Filepath result;
disk.GetPath(result);
EXPECT_STREQ("path", result.GetPath());
int id;
int lun;
EXPECT_FALSE(Disk::GetIdsForReservedFile(path, id, lun));
disk.ReserveFile(path, ID, LUN);
EXPECT_TRUE(Disk::GetIdsForReservedFile(path, id, lun));
EXPECT_EQ(ID, id);
EXPECT_EQ(LUN, lun);
disk.UnreserveFile();
EXPECT_FALSE(Disk::GetIdsForReservedFile(path, id, lun));
}
TEST(DiskTest, UnreserveAll)
{
const int ID = 2;
const int LUN = 31;
Filepath path;
path.SetPath("path");
MockDisk disk;
disk.ReserveFile(path, ID, LUN);
Disk::UnreserveAll();
int id;
int lun;
EXPECT_FALSE(Disk::GetIdsForReservedFile(path, id, lun));
}

View File

@ -1,61 +0,0 @@
//---------------------------------------------------------------------------
//
// SCSI Target Emulator RaSCSI Reloaded
// for Raspberry Pi
//
// Copyright (C) 2022 Uwe Seimet
//
//---------------------------------------------------------------------------
#include "mocks.h"
#include "devices/file_support.h"
class TestFileSupport : public FileSupport
{
void Open(const Filepath&) final {
// Do nothing when running unit tests
}
};
TEST(FileSupportTest, Reserve)
{
const int ID = 1;
const int LUN = 2;
Filepath path;
path.SetPath("path");
TestFileSupport file_support;
file_support.SetPath(path);
Filepath result;
file_support.GetPath(result);
EXPECT_STREQ("path", result.GetPath());
int id;
int lun;
EXPECT_FALSE(FileSupport::GetIdsForReservedFile(path, id, lun));
file_support.ReserveFile(path, ID, LUN);
EXPECT_TRUE(FileSupport::GetIdsForReservedFile(path, id, lun));
EXPECT_EQ(ID, id);
EXPECT_EQ(LUN, lun);
file_support.UnreserveFile();
EXPECT_FALSE(FileSupport::GetIdsForReservedFile(path, id, lun));
}
TEST(FileSupportTest, UnreserveAll)
{
const int ID = 2;
const int LUN = 31;
Filepath path;
path.SetPath("path");
TestFileSupport file_support;
file_support.ReserveFile(path, ID, LUN);
FileSupport::UnreserveAll();
int id;
int lun;
EXPECT_FALSE(FileSupport::GetIdsForReservedFile(path, id, lun));
}

View File

@ -0,0 +1,149 @@
//---------------------------------------------------------------------------
//
// SCSI Target Emulator RaSCSI Reloaded
// for Raspberry Pi
//
// Copyright (C) 2022 Uwe Seimet
//
//---------------------------------------------------------------------------
#include "mocks.h"
#include "rascsi_exceptions.h"
#include "controllers/controller_manager.h"
#include "devices/host_services.h"
using namespace std;
TEST(HostServicesTest, TestUnitReady)
{
NiceMock<MockAbstractController> controller(0);
auto services = CreateDevice(SCHS, controller);
EXPECT_CALL(controller, Status()).Times(1);
EXPECT_TRUE(services->Dispatch(scsi_command::eCmdTestUnitReady)) << "TEST UNIT READY must never fail";
EXPECT_EQ(status::GOOD, controller.GetStatus());
}
TEST(HostServicesTest, Inquiry)
{
TestInquiry(SCHS, device_type::PROCESSOR, scsi_level::SPC_3, scsi_level::SCSI_2,
"RaSCSI Host Services ", 0x1f, false);
}
TEST(HostServicesTest, StartStopUnit)
{
NiceMock<MockAbstractController> controller(0);
auto services = CreateDevice(SCHS, controller);
vector<int>& cmd = controller.InitCmd(6);
// STOP
EXPECT_CALL(controller, ScheduleShutdown(AbstractController::rascsi_shutdown_mode::STOP_RASCSI)).Times(1);
EXPECT_CALL(controller, Status()).Times(1);
EXPECT_TRUE(services->Dispatch(scsi_command::eCmdStartStop));
EXPECT_EQ(status::GOOD, controller.GetStatus());
// LOAD
cmd[4] = 0x02;
EXPECT_CALL(controller, ScheduleShutdown(AbstractController::rascsi_shutdown_mode::STOP_PI)).Times(1);
EXPECT_CALL(controller, Status()).Times(1);
EXPECT_TRUE(services->Dispatch(scsi_command::eCmdStartStop));
EXPECT_EQ(status::GOOD, controller.GetStatus());
// UNLOAD
cmd[4] = 0x03;
EXPECT_CALL(controller, ScheduleShutdown(AbstractController::rascsi_shutdown_mode::RESTART_PI)).Times(1);
EXPECT_CALL(controller, Status()).Times(1);
EXPECT_TRUE(services->Dispatch(scsi_command::eCmdStartStop));
EXPECT_EQ(status::GOOD, controller.GetStatus());
// START
cmd[4] = 0x01;
EXPECT_THROW(services->Dispatch(scsi_command::eCmdStartStop), scsi_exception);
}
TEST(HostServicesTest, ModeSense6)
{
NiceMock<MockAbstractController> controller(0);
auto services = CreateDevice(SCHS, controller);
vector<int>& cmd = controller.InitCmd(6);
EXPECT_THROW(services->Dispatch(scsi_command::eCmdModeSense6), scsi_exception)
<< "Unsupported mode page was returned";
cmd[2] = 0x20;
EXPECT_THROW(services->Dispatch(scsi_command::eCmdModeSense6), scsi_exception)
<< "Block descriptors are not supported";
cmd[1] = 0x08;
// ALLOCATION LENGTH
cmd[4] = 255;
EXPECT_CALL(controller, DataIn()).Times(1);
EXPECT_TRUE(services->Dispatch(scsi_command::eCmdModeSense6));
vector<BYTE>& buffer = controller.GetBuffer();
// Major version 1
EXPECT_EQ(0x01, buffer[6]);
// Minor version 0
EXPECT_EQ(0x00, buffer[7]);
// Year
EXPECT_NE(0x00, buffer[9]);
// Day
EXPECT_NE(0x00, buffer[10]);
// ALLOCATION LENGTH
cmd[4] = 2;
EXPECT_CALL(controller, DataIn()).Times(1);
EXPECT_TRUE(services->Dispatch(scsi_command::eCmdModeSense6));
buffer = controller.GetBuffer();
EXPECT_EQ(0x02, buffer[0]);
}
TEST(HostServicesTest, ModeSense10)
{
NiceMock<MockAbstractController> controller(0);
auto services = CreateDevice(SCHS, controller);
vector<int>& cmd = controller.InitCmd(10);
EXPECT_THROW(services->Dispatch(scsi_command::eCmdModeSense10), scsi_exception)
<< "Unsupported mode page was returned";
cmd[2] = 0x20;
EXPECT_THROW(services->Dispatch(scsi_command::eCmdModeSense10), scsi_exception)
<< "Block descriptors are not supported";
cmd[1] = 0x08;
// ALLOCATION LENGTH
cmd[8] = 255;
EXPECT_CALL(controller, DataIn()).Times(1);
EXPECT_TRUE(services->Dispatch(scsi_command::eCmdModeSense10));
vector<BYTE>& buffer = controller.GetBuffer();
// Major version 1
EXPECT_EQ(0x01, buffer[10]);
// Minor version 0
EXPECT_EQ(0x00, buffer[11]);
// Year
EXPECT_NE(0x00, buffer[13]);
// Day
EXPECT_NE(0x00, buffer[14]);
// ALLOCATION LENGTH
cmd[8] = 2;
EXPECT_CALL(controller, DataIn()).Times(1);
EXPECT_TRUE(services->Dispatch(scsi_command::eCmdModeSense10));
buffer = controller.GetBuffer();
EXPECT_EQ(0x02, buffer[1]);
}
TEST(HostServicesTest, SetUpModePages)
{
MockBus bus;
ControllerManager controller_manager(bus);
MockHostServices services(0, controller_manager);
map<int, vector<byte>> mode_pages;
services.SetUpModePages(mode_pages, 0x3f, false);
EXPECT_EQ(1, mode_pages.size()) << "Unexpected number of mode pages";
EXPECT_EQ(10, mode_pages[32].size());
}

View File

@ -11,6 +11,7 @@
#include <gmock/gmock.h>
#include "test_shared.h"
#include "controllers/scsi_controller.h"
#include "devices/primary_device.h"
#include "devices/scsihd.h"
@ -20,7 +21,9 @@
#include "devices/host_services.h"
#include "rascsi/command_context.h"
class MockBus final : public BUS //NOSONAR Having many fields/methods cannot be avoided
using namespace testing;
class MockBus : public BUS //NOSONAR Having many fields/methods cannot be avoided
{
public:
@ -78,8 +81,12 @@ public:
using PhaseHandler::PhaseHandler;
};
class MockAbstractController final : public AbstractController //NOSONAR Having many fields/methods cannot be avoided
class MockAbstractController : public AbstractController //NOSONAR Having many fields/methods cannot be avoided
{
friend shared_ptr<PrimaryDevice> CreateDevice(rascsi_interface::PbDeviceType, AbstractController&, int);
friend void TestInquiry(rascsi_interface::PbDeviceType, scsi_defs::device_type, scsi_defs::scsi_level,
scsi_defs::scsi_level, const std::string&, int, bool);
FRIEND_TEST(AbstractControllerTest, Reset);
FRIEND_TEST(AbstractControllerTest, ProcessPhase);
FRIEND_TEST(AbstractControllerTest, DeviceLunLifeCycle);
@ -93,6 +100,10 @@ class MockAbstractController final : public AbstractController //NOSONAR Having
FRIEND_TEST(PrimaryDeviceTest, RequestSense);
FRIEND_TEST(PrimaryDeviceTest, ReportLuns);
FRIEND_TEST(PrimaryDeviceTest, UnknownCommand);
FRIEND_TEST(ModePageDeviceTest, ModeSense6);
FRIEND_TEST(ModePageDeviceTest, ModeSense10);
FRIEND_TEST(ModePageDeviceTest, ModeSelect6);
FRIEND_TEST(ModePageDeviceTest, ModeSelect10);
FRIEND_TEST(DiskTest, Dispatch);
FRIEND_TEST(DiskTest, Rezero);
FRIEND_TEST(DiskTest, FormatUnit);
@ -100,7 +111,8 @@ class MockAbstractController final : public AbstractController //NOSONAR Having
FRIEND_TEST(DiskTest, Seek);
FRIEND_TEST(DiskTest, ReadCapacity);
FRIEND_TEST(DiskTest, ReadWriteLong);
FRIEND_TEST(DiskTest, ReserveRelease);
FRIEND_TEST(DiskTest, Reserve);
FRIEND_TEST(DiskTest, Release);
FRIEND_TEST(DiskTest, SendDiagnostic);
FRIEND_TEST(DiskTest, PreventAllowMediumRemoval);
FRIEND_TEST(DiskTest, SynchronizeCache);
@ -128,10 +140,12 @@ public:
}
~MockAbstractController() override = default;
vector<int>& InitCmd(int size) { return AbstractController::InitCmd(size); } //NOSONAR Hides function on purpose
MockBus bus;
};
class MockScsiController final : public ScsiController
class MockScsiController : public ScsiController
{
FRIEND_TEST(ScsiControllerTest, RequestSense);
FRIEND_TEST(PrimaryDeviceTest, RequestSense);
@ -150,7 +164,7 @@ public:
MockBus bus;
};
class MockDevice final : public Device
class MockDevice : public Device
{
FRIEND_TEST(DeviceTest, Params);
FRIEND_TEST(DeviceTest, StatusCode);
@ -167,7 +181,7 @@ public:
~MockDevice() override = default;
};
class MockPrimaryDevice final : public PrimaryDevice
class MockPrimaryDevice : public PrimaryDevice
{
FRIEND_TEST(PrimaryDeviceTest, PhaseChange);
FRIEND_TEST(PrimaryDeviceTest, TestUnitReady);
@ -185,17 +199,19 @@ public:
~MockPrimaryDevice() override = default;
};
class MockModePageDevice final : public ModePageDevice
class MockModePageDevice : public ModePageDevice
{
FRIEND_TEST(ModePagesTest, ModePageDevice_AddModePages);
FRIEND_TEST(ModePageDeviceTest, AddModePages);
explicit MockModePageDevice(int lun) : ModePageDevice("test", lun) {}
~MockModePageDevice() override = default;
public:
MOCK_METHOD(vector<byte>, InquiryInternal, (), (const));
MOCK_METHOD(int, ModeSense6, (const vector<int>&, vector<BYTE>&), (const override));
MOCK_METHOD(int, ModeSense10, (const vector<int>&, vector<BYTE>&), (const override));
explicit MockModePageDevice() : ModePageDevice("test", 0) {}
~MockModePageDevice() override = default;
void SetUpModePages(map<int, vector<byte>>& pages, int page, bool) const override {
// Return dummy data for other pages than page 0
if (page) {
@ -205,7 +221,7 @@ class MockModePageDevice final : public ModePageDevice
}
};
class MockDisk final : public Disk
class MockDisk : public Disk
{
FRIEND_TEST(DiskTest, Rezero);
FRIEND_TEST(DiskTest, FormatUnit);
@ -220,6 +236,7 @@ class MockDisk final : public Disk
FRIEND_TEST(DiskTest, ReadDefectData);
FRIEND_TEST(DiskTest, SectorSize);
FRIEND_TEST(DiskTest, BlockCount);
FRIEND_TEST(DiskTest, GetIdsForReservedFile);
public:
@ -230,41 +247,39 @@ public:
~MockDisk() override = default;
};
class MockSCSIHD final : public SCSIHD
class MockSCSIHD : public SCSIHD
{
FRIEND_TEST(DiskTest, ConfiguredSectorSize);
FRIEND_TEST(ModePagesTest, SCSIHD_SetUpModePages);
FRIEND_TEST(ScsiHdTest, SetUpModePages);
FRIEND_TEST(RascsiExecutorTest, SetSectorSize);
using SCSIHD::SCSIHD;
};
class MockSCSIHD_NEC final : public SCSIHD_NEC //NOSONAR Ignore inheritance hierarchy depth in unit tests
class MockSCSIHD_NEC : public SCSIHD_NEC //NOSONAR Ignore inheritance hierarchy depth in unit tests
{
FRIEND_TEST(ModePagesTest, SCSIHD_NEC_SetUpModePages);
MOCK_METHOD(void, FlushCache, (), (override));
FRIEND_TEST(ScsiHdNecTest, SetUpModePages);
using SCSIHD_NEC::SCSIHD_NEC;
};
class MockSCSICD final : public SCSICD
class MockSCSICD : public SCSICD
{
FRIEND_TEST(ModePagesTest, SCSICD_SetUpModePages);
FRIEND_TEST(ScsiCdTest, SetUpModePages);
using SCSICD::SCSICD;
};
class MockSCSIMO final : public SCSIMO
class MockSCSIMO : public SCSIMO
{
FRIEND_TEST(ModePagesTest, SCSIMO_SetUpModePages);
FRIEND_TEST(ScsiMoTest, SetUpModePages);
using SCSIMO::SCSIMO;
};
class MockHostServices final : public HostServices
class MockHostServices : public HostServices
{
FRIEND_TEST(ModePagesTest, HostServices_SetUpModePages);
FRIEND_TEST(HostServicesTest, SetUpModePages);
using HostServices::HostServices;
};

View File

@ -0,0 +1,100 @@
//---------------------------------------------------------------------------
//
// SCSI Target Emulator RaSCSI Reloaded
// for Raspberry Pi
//
// Copyright (C) 2022 Uwe Seimet
//
//---------------------------------------------------------------------------
#include "mocks.h"
#include "rascsi_exceptions.h"
#include "devices/mode_page_device.h"
using namespace std;
TEST(ModePageDeviceTest, AddModePages)
{
vector<int> cdb(6);
vector<BYTE> buf(512);
MockModePageDevice device;
cdb[2] = 0x3f;
EXPECT_EQ(0, device.AddModePages(cdb, buf, 0, -1)) << "Negative maximum length must be rejected";
EXPECT_EQ(0, device.AddModePages(cdb, buf, 0, 0)) << "Allocation length 0 must be rejected";
EXPECT_EQ(1, device.AddModePages(cdb, buf, 0, 1)) << "Allocation length 1 must be rejected";
cdb[2] = 0x00;
EXPECT_THROW(device.AddModePages(cdb, buf, 0, 12), scsi_exception)
<< "Data were returned for non-existing mode page 0";
}
TEST(ModePageDeviceTest, ModeSense6)
{
MockAbstractController controller(0);
auto device = make_shared<NiceMock<MockModePageDevice>>();
controller.AddDevice(device);
controller.InitCmd(6);
EXPECT_CALL(controller, DataIn()).Times(1);
EXPECT_TRUE(device->Dispatch(scsi_command::eCmdModeSense6));
}
TEST(ModePageDeviceTest, ModeSense10)
{
MockAbstractController controller(0);
auto device = make_shared<NiceMock<MockModePageDevice>>();
controller.AddDevice(device);
controller.InitCmd(10);
EXPECT_CALL(controller, DataIn()).Times(1);
EXPECT_TRUE(device->Dispatch(scsi_command::eCmdModeSense10));
}
TEST(ModePageDeviceTest, ModeSelect)
{
MockModePageDevice device;
vector<int> cmd;
vector<BYTE> buf;
EXPECT_THROW(device.ModeSelect(cmd, buf, 0), scsi_exception) << "Unexpected MODE SELECT default implementation";
}
TEST(ModePageDeviceTest, ModeSelect6)
{
MockAbstractController controller(0);
auto device = make_shared<MockModePageDevice>();
controller.AddDevice(device);
vector<int>& cmd = controller.InitCmd(6);
EXPECT_CALL(controller, DataOut()).Times(1);
EXPECT_TRUE(device->Dispatch(scsi_command::eCmdModeSelect6));
cmd[1] = 0x01;
EXPECT_THROW(device->Dispatch(scsi_command::eCmdModeSelect6), scsi_exception)
<< "Saving parameters is not supported for most device types";
}
TEST(ModePageDeviceTest, ModeSelect10)
{
MockAbstractController controller(0);
auto device = make_shared<MockModePageDevice>();
controller.AddDevice(device);
vector<int>& cmd = controller.InitCmd(10);
EXPECT_CALL(controller, DataOut()).Times(1);
EXPECT_TRUE(device->Dispatch(scsi_command::eCmdModeSelect10));
cmd[1] = 0x01;
EXPECT_THROW(device->Dispatch(scsi_command::eCmdModeSelect10), scsi_exception)
<< "Saving parameters is not supported for most device types";
}

View File

@ -1,147 +0,0 @@
//---------------------------------------------------------------------------
//
// SCSI Target Emulator RaSCSI Reloaded
// for Raspberry Pi
//
// Copyright (C) 2022 Uwe Seimet
//
//---------------------------------------------------------------------------
#include "mocks.h"
#include "spdlog/spdlog.h"
#include "rascsi_exceptions.h"
#include "controllers/controller_manager.h"
#include "devices/scsi_command_util.h"
#include "devices/scsihd.h"
#include "devices/scsihd_nec.h"
#include "devices/scsicd.h"
#include "devices/scsimo.h"
#include "devices/host_services.h"
using namespace std;
TEST(ModePagesTest, ModePageDevice_AddModePages)
{
vector<int> cdb(6);
vector<BYTE> buf(512);
MockModePageDevice device(0);
cdb[2] = 0x3f;
EXPECT_EQ(0, device.AddModePages(cdb, buf, 0, -1)) << "Negative maximum length must be rejected";
EXPECT_EQ(0, device.AddModePages(cdb, buf, 0, 0)) << "Allocation length 0 must be rejected";
EXPECT_EQ(1, device.AddModePages(cdb, buf, 0, 1)) << "Allocation length 1 must be rejected";
cdb[2] = 0x00;
EXPECT_THROW(device.AddModePages(cdb, buf, 0, 12), scsi_error_exception) << "Data for non-existing mode page 0 were returned";
}
TEST(ModePagesTest, SCSIHD_SetUpModePages)
{
map<int, vector<byte>> mode_pages;
const unordered_set<uint32_t> sector_sizes;
MockSCSIHD device(0, sector_sizes, false);
device.SetUpModePages(mode_pages, 0x3f, false);
EXPECT_EQ(5, mode_pages.size()) << "Unexpected number of mode pages";
EXPECT_EQ(12, mode_pages[1].size());
EXPECT_EQ(24, mode_pages[3].size());
EXPECT_EQ(24, mode_pages[4].size());
EXPECT_EQ(12, mode_pages[8].size());
EXPECT_EQ(30, mode_pages[48].size());
}
TEST(ModePagesTest, SCSIHD_NEC_SetUpModePages)
{
map<int, vector<byte>> mode_pages;
MockSCSIHD_NEC device(0);
device.SetUpModePages(mode_pages, 0x3f, false);
EXPECT_EQ(5, mode_pages.size()) << "Unexpected number of mode pages";
EXPECT_EQ(8, mode_pages[1].size());
EXPECT_EQ(24, mode_pages[3].size());
EXPECT_EQ(20, mode_pages[4].size());
EXPECT_EQ(12, mode_pages[8].size());
EXPECT_EQ(30, mode_pages[48].size());
}
TEST(ModePagesTest, SCSICD_SetUpModePages)
{
map<int, vector<byte>> mode_pages;
const unordered_set<uint32_t> sector_sizes;
MockSCSICD device(0, sector_sizes);
device.SetUpModePages(mode_pages, 0x3f, false);
EXPECT_EQ(7, mode_pages.size()) << "Unexpected number of mode pages";
EXPECT_EQ(12, mode_pages[1].size());
EXPECT_EQ(24, mode_pages[3].size());
EXPECT_EQ(24, mode_pages[4].size());
EXPECT_EQ(12, mode_pages[8].size());
EXPECT_EQ(8, mode_pages[13].size());
EXPECT_EQ(16, mode_pages[14].size());
EXPECT_EQ(30, mode_pages[48].size());
}
TEST(ModePagesTest, SCSIMO_SetUpModePages)
{
map<int, vector<byte>> mode_pages;
const unordered_set<uint32_t> sector_sizes;
MockSCSIMO device(0, sector_sizes);
device.SetUpModePages(mode_pages, 0x3f, false);
EXPECT_EQ(6, mode_pages.size()) << "Unexpected number of mode pages";
EXPECT_EQ(12, mode_pages[1].size());
EXPECT_EQ(24, mode_pages[3].size());
EXPECT_EQ(24, mode_pages[4].size());
EXPECT_EQ(4, mode_pages[6].size());
EXPECT_EQ(12, mode_pages[8].size());
EXPECT_EQ(12, mode_pages[32].size());
}
TEST(ModePagesTest, HostServices_SetUpModePages)
{
MockBus bus;
ControllerManager controller_manager(bus);
MockHostServices device(0, controller_manager);
map<int, vector<byte>> mode_pages;
device.SetUpModePages(mode_pages, 0x3f, false);
EXPECT_EQ(1, mode_pages.size()) << "Unexpected number of mode pages";
EXPECT_EQ(10, mode_pages[32].size());
}
TEST(ModePagesTest, ModeSelect)
{
const int LENGTH = 12;
vector<int> cdb(16);
vector<BYTE> buf(255);
// PF (vendor-specific parameter format)
cdb[1] = 0x00;
EXPECT_THROW(scsi_command_util::ModeSelect(cdb, buf, LENGTH, 0), scsi_error_exception)
<< "Vendor-specific parameters are not supported";
// PF (standard parameter format)
cdb[1] = 0x10;
// Request 512 bytes per sector
buf[9] = 0x00;
buf[10] = 0x02;
buf[11] = 0x00;
EXPECT_THROW(scsi_command_util::ModeSelect(cdb, buf, LENGTH, 256), scsi_error_exception)
<< "Requested sector size does not match current sector size";
// Page 0
buf[LENGTH] = 0x00;
EXPECT_THROW(scsi_command_util::ModeSelect(cdb, buf, LENGTH + 2, 512), scsi_error_exception)
<< "Unsupported page 0 was not rejected";
// Page 3 (Format Device Page)
buf[LENGTH] = 0x03;
EXPECT_THROW(scsi_command_util::ModeSelect(cdb, buf, LENGTH + 2, 512), scsi_error_exception)
<< "Requested sector size does not match current sector size";
// Match the requested to the current sector size
buf[LENGTH + 12] = 0x02;
scsi_command_util::ModeSelect(cdb, buf, LENGTH + 2, 512);
}

View File

@ -16,25 +16,81 @@ TEST(PhaseHandlerTest, Phases)
handler.SetPhase(BUS::phase_t::selection);
EXPECT_TRUE(handler.IsSelection());
EXPECT_FALSE(handler.IsBusFree());
EXPECT_FALSE(handler.IsCommand());
EXPECT_FALSE(handler.IsStatus());
EXPECT_FALSE(handler.IsDataIn());
EXPECT_FALSE(handler.IsDataOut());
EXPECT_FALSE(handler.IsMsgIn());
EXPECT_FALSE(handler.IsMsgOut());
handler.SetPhase(BUS::phase_t::busfree);
EXPECT_TRUE(handler.IsBusFree());
EXPECT_FALSE(handler.IsSelection());
EXPECT_FALSE(handler.IsCommand());
EXPECT_FALSE(handler.IsStatus());
EXPECT_FALSE(handler.IsDataIn());
EXPECT_FALSE(handler.IsDataOut());
EXPECT_FALSE(handler.IsMsgIn());
EXPECT_FALSE(handler.IsMsgOut());
handler.SetPhase(BUS::phase_t::command);
EXPECT_TRUE(handler.IsCommand());
EXPECT_FALSE(handler.IsBusFree());
EXPECT_FALSE(handler.IsSelection());
EXPECT_FALSE(handler.IsStatus());
EXPECT_FALSE(handler.IsDataIn());
EXPECT_FALSE(handler.IsDataOut());
EXPECT_FALSE(handler.IsMsgIn());
EXPECT_FALSE(handler.IsMsgOut());
handler.SetPhase(BUS::phase_t::status);
EXPECT_TRUE(handler.IsStatus());
EXPECT_FALSE(handler.IsBusFree());
EXPECT_FALSE(handler.IsSelection());
EXPECT_FALSE(handler.IsCommand());
EXPECT_FALSE(handler.IsDataIn());
EXPECT_FALSE(handler.IsDataOut());
EXPECT_FALSE(handler.IsMsgIn());
EXPECT_FALSE(handler.IsMsgOut());
handler.SetPhase(BUS::phase_t::datain);
EXPECT_TRUE(handler.IsDataIn());
EXPECT_FALSE(handler.IsBusFree());
EXPECT_FALSE(handler.IsSelection());
EXPECT_FALSE(handler.IsCommand());
EXPECT_FALSE(handler.IsStatus());
EXPECT_FALSE(handler.IsDataOut());
EXPECT_FALSE(handler.IsMsgIn());
EXPECT_FALSE(handler.IsMsgOut());
handler.SetPhase(BUS::phase_t::dataout);
EXPECT_TRUE(handler.IsDataOut());
EXPECT_FALSE(handler.IsBusFree());
EXPECT_FALSE(handler.IsSelection());
EXPECT_FALSE(handler.IsCommand());
EXPECT_FALSE(handler.IsStatus());
EXPECT_FALSE(handler.IsDataIn());
EXPECT_FALSE(handler.IsMsgIn());
EXPECT_FALSE(handler.IsMsgOut());
handler.SetPhase(BUS::phase_t::msgin);
EXPECT_TRUE(handler.IsMsgIn());
EXPECT_FALSE(handler.IsBusFree());
EXPECT_FALSE(handler.IsSelection());
EXPECT_FALSE(handler.IsCommand());
EXPECT_FALSE(handler.IsStatus());
EXPECT_FALSE(handler.IsDataIn());
EXPECT_FALSE(handler.IsDataOut());
EXPECT_FALSE(handler.IsMsgOut());
handler.SetPhase(BUS::phase_t::msgout);
EXPECT_TRUE(handler.IsMsgOut());
EXPECT_FALSE(handler.IsBusFree());
EXPECT_FALSE(handler.IsSelection());
EXPECT_FALSE(handler.IsCommand());
EXPECT_FALSE(handler.IsStatus());
EXPECT_FALSE(handler.IsDataIn());
EXPECT_FALSE(handler.IsDataOut());
EXPECT_FALSE(handler.IsMsgIn());
}

View File

@ -56,25 +56,25 @@ TEST(PrimaryDeviceTest, TestUnitReady)
device->SetAttn(true);
device->SetReady(false);
EXPECT_CALL(controller, DataIn()).Times(0);
EXPECT_THROW(device->Dispatch(scsi_command::eCmdTestUnitReady), scsi_error_exception);
EXPECT_THROW(device->Dispatch(scsi_command::eCmdTestUnitReady), scsi_exception);
device->SetReset(false);
EXPECT_CALL(controller, DataIn()).Times(0);
EXPECT_THROW(device->Dispatch(scsi_command::eCmdTestUnitReady), scsi_error_exception);
EXPECT_THROW(device->Dispatch(scsi_command::eCmdTestUnitReady), scsi_exception);
device->SetReset(true);
device->SetAttn(false);
EXPECT_CALL(controller, DataIn()).Times(0);
EXPECT_THROW(device->Dispatch(scsi_command::eCmdTestUnitReady), scsi_error_exception);
EXPECT_THROW(device->Dispatch(scsi_command::eCmdTestUnitReady), scsi_exception);
device->SetReset(false);
device->SetAttn(true);
EXPECT_CALL(controller, DataIn()).Times(0);
EXPECT_THROW(device->Dispatch(scsi_command::eCmdTestUnitReady), scsi_error_exception);
EXPECT_THROW(device->Dispatch(scsi_command::eCmdTestUnitReady), scsi_exception);
device->SetAttn(false);
EXPECT_CALL(controller, DataIn()).Times(0);
EXPECT_THROW(device->Dispatch(scsi_command::eCmdTestUnitReady), scsi_error_exception);
EXPECT_THROW(device->Dispatch(scsi_command::eCmdTestUnitReady), scsi_exception);
device->SetReady(true);
EXPECT_CALL(controller, Status()).Times(1);
@ -84,7 +84,7 @@ TEST(PrimaryDeviceTest, TestUnitReady)
TEST(PrimaryDeviceTest, Inquiry)
{
MockAbstractController controller(0);
NiceMock<MockAbstractController> controller(0);
auto device = make_shared<MockPrimaryDevice>(0);
device->SetController(&controller);
@ -126,11 +126,11 @@ TEST(PrimaryDeviceTest, Inquiry)
cmd[1] = 0x01;
EXPECT_CALL(controller, DataIn()).Times(0);
EXPECT_THROW(device->Dispatch(scsi_command::eCmdInquiry), scsi_error_exception) << "EVPD bit is not supported";
EXPECT_THROW(device->Dispatch(scsi_command::eCmdInquiry), scsi_exception) << "EVPD bit is not supported";
cmd[2] = 0x01;
EXPECT_CALL(controller, DataIn()).Times(0);
EXPECT_THROW(device->Dispatch(scsi_command::eCmdInquiry), scsi_error_exception) << "PAGE CODE field is not supported";
EXPECT_THROW(device->Dispatch(scsi_command::eCmdInquiry), scsi_exception) << "PAGE CODE field is not supported";
cmd[1] = 0x00;
cmd[2] = 0x00;
@ -145,7 +145,7 @@ TEST(PrimaryDeviceTest, Inquiry)
TEST(PrimaryDeviceTest, RequestSense)
{
MockAbstractController controller(0);
NiceMock<MockAbstractController> controller(0);
auto device = make_shared<MockPrimaryDevice>(0);
controller.AddDevice(device);
@ -155,7 +155,7 @@ TEST(PrimaryDeviceTest, RequestSense)
cmd[4] = 255;
device->SetReady(false);
EXPECT_THROW(device->Dispatch(scsi_command::eCmdRequestSense), scsi_error_exception);
EXPECT_THROW(device->Dispatch(scsi_command::eCmdRequestSense), scsi_exception);
device->SetReady(true);
EXPECT_CALL(controller, DataIn()).Times(1);
@ -206,7 +206,7 @@ TEST(PrimaryDeviceTest, ReportLuns)
EXPECT_EQ(LUN2, buffer[23]) << "Wrong LUN2 number";
cmd[2] = 0x01;
EXPECT_THROW(device1->Dispatch(scsi_command::eCmdReportLuns), scsi_error_exception) << "Only SELECT REPORT mode 0 is supported";
EXPECT_THROW(device1->Dispatch(scsi_command::eCmdReportLuns), scsi_exception) << "Only SELECT REPORT mode 0 is supported";
}
TEST(PrimaryDeviceTest, UnknownCommand)
@ -216,7 +216,6 @@ TEST(PrimaryDeviceTest, UnknownCommand)
controller.AddDevice(device);
controller.InitCmd(1);
EXPECT_FALSE(device->Dispatch((scsi_command)0xFF));
}

View File

@ -16,12 +16,50 @@ using namespace rascsi_interface;
TEST(ProtobufSerializerTest, SerializeMessage)
{
PbResult message;
PbResult result;
ProtobufSerializer serializer;
int fd = open("/dev/null", O_WRONLY);
ASSERT_NE(-1, fd);
serializer.SerializeMessage(fd, message);
int fd = open("/dev/zero", O_RDONLY);
EXPECT_NE(-1, fd);
EXPECT_THROW(serializer.DeserializeMessage(fd, result), io_exception) << "Writing the message header must fail";
close(fd);
fd = open("/dev/null", O_WRONLY);
EXPECT_NE(-1, fd);
serializer.SerializeMessage(fd, result);
EXPECT_THROW(serializer.SerializeMessage(-1, result), io_exception) << "Writing a message must fail";
close(fd);
}
TEST(ProtobufSerializerTest, DeserializeMessage)
{
PbResult result;
ProtobufSerializer serializer;
vector<byte> buf(1);
int fd = open("/dev/null", O_RDONLY);
EXPECT_NE(-1, fd);
EXPECT_THROW(serializer.DeserializeMessage(fd, result), io_exception) << "Reading the message header must fail";
close(fd);
fd = open("/dev/zero", O_RDONLY);
EXPECT_NE(-1, fd);
EXPECT_THROW(serializer.DeserializeMessage(fd, result), io_exception) << "Reading a message must fail";
close(fd);
}
TEST(ProtobufSerializerTest, ReadBytes)
{
ProtobufSerializer serializer;
vector<byte> buf(1);
int fd = open("/dev/null", O_RDONLY);
EXPECT_NE(-1, fd);
EXPECT_EQ(0, serializer.ReadBytes(fd, buf));
close(fd);
fd = open("/dev/zero", O_RDONLY);
EXPECT_NE(-1, fd);
EXPECT_EQ(1, serializer.ReadBytes(fd, buf));
close(fd);
EXPECT_THROW(serializer.SerializeMessage(-1, message), io_exception);
}

View File

@ -9,10 +9,10 @@
#include "mocks.h"
#include "rascsi_interface.pb.h"
#include "command_util.h"
#include "protobuf_util.h"
using namespace rascsi_interface;
using namespace command_util;
using namespace protobuf_util;
void TestSpecialDevice(const string& name)
{
@ -59,3 +59,26 @@ TEST(CommandUtil, ParseParameters)
TestSpecialDevice("printer");
TestSpecialDevice("services");
}
TEST(CommandUtil, SetPatternParams)
{
PbCommand command1;
SetPatternParams(command1, "file");
EXPECT_EQ("", GetParam(command1, "folder_pattern"));
EXPECT_EQ("file", GetParam(command1, "file_pattern"));
PbCommand command2;
SetPatternParams(command2, ":file");
EXPECT_EQ("", GetParam(command2, "folder_pattern"));
EXPECT_EQ("file", GetParam(command2, "file_pattern"));
PbCommand command3;
SetPatternParams(command3, "folder:");
EXPECT_EQ("folder", GetParam(command3, "folder_pattern"));
EXPECT_EQ("", GetParam(command3, "file_pattern"));
PbCommand command4;
SetPatternParams(command4, "folder:file");
EXPECT_EQ("folder", GetParam(command4, "folder_pattern"));
EXPECT_EQ("file", GetParam(command4, "file_pattern"));
}

View File

@ -35,36 +35,36 @@ TEST(RascsiExceptionsTest, FileNotFoundException)
TEST(RascsiExceptionsTest, ScsiErrorException)
{
try {
throw scsi_error_exception();
throw scsi_exception();
}
catch(const scsi_error_exception& e) {
catch(const scsi_exception& e) {
EXPECT_EQ(sense_key::ABORTED_COMMAND, e.get_sense_key());
EXPECT_EQ(asc::NO_ADDITIONAL_SENSE_INFORMATION, e.get_asc());
EXPECT_EQ(status::CHECK_CONDITION, e.get_status());
}
try {
throw scsi_error_exception(sense_key::UNIT_ATTENTION);
throw scsi_exception(sense_key::UNIT_ATTENTION);
}
catch(const scsi_error_exception& e) {
catch(const scsi_exception& e) {
EXPECT_EQ(sense_key::UNIT_ATTENTION, e.get_sense_key());
EXPECT_EQ(asc::NO_ADDITIONAL_SENSE_INFORMATION, e.get_asc());
EXPECT_EQ(status::CHECK_CONDITION, e.get_status());
}
try {
throw scsi_error_exception(sense_key::UNIT_ATTENTION, asc::LBA_OUT_OF_RANGE);
throw scsi_exception(sense_key::UNIT_ATTENTION, asc::LBA_OUT_OF_RANGE);
}
catch(const scsi_error_exception& e) {
catch(const scsi_exception& e) {
EXPECT_EQ(sense_key::UNIT_ATTENTION, e.get_sense_key());
EXPECT_EQ(asc::LBA_OUT_OF_RANGE, e.get_asc());
EXPECT_EQ(status::CHECK_CONDITION, e.get_status());
}
try {
throw scsi_error_exception(sense_key::UNIT_ATTENTION, asc::LBA_OUT_OF_RANGE, status::BUSY);
throw scsi_exception(sense_key::UNIT_ATTENTION, asc::LBA_OUT_OF_RANGE, status::BUSY);
}
catch(const scsi_error_exception& e) {
catch(const scsi_exception& e) {
EXPECT_EQ(sense_key::UNIT_ATTENTION, e.get_sense_key());
EXPECT_EQ(asc::LBA_OUT_OF_RANGE, e.get_asc());
EXPECT_EQ(status::BUSY, e.get_status());

View File

@ -8,7 +8,7 @@
//---------------------------------------------------------------------------
#include "mocks.h"
#include "command_util.h"
#include "protobuf_util.h"
#include "controllers/controller_manager.h"
#include "devices/device_factory.h"
#include "rascsi/command_context.h"
@ -17,7 +17,7 @@
#include "rascsi/rascsi_executor.h"
using namespace rascsi_interface;
using namespace command_util;
using namespace protobuf_util;
TEST(RascsiExecutorTest, ProcessCmd)
{

View File

@ -0,0 +1,288 @@
//---------------------------------------------------------------------------
//
// SCSI Target Emulator RaSCSI Reloaded
// for Raspberry Pi
//
// Copyright (C) 2022 Uwe Seimet
//
// These tests only test key aspects of the expected output, because the output may change over time.
//
//---------------------------------------------------------------------------
#include <gtest/gtest.h>
#include "rasctl/rasctl_display.h"
TEST(RasctlDisplayTest, DisplayDevicesInfo)
{
RasctlDisplay display;
PbDevicesInfo info;
EXPECT_FALSE(display.DisplayDevicesInfo(info).empty());
}
TEST(RasctlDisplayTest, DisplayDeviceInfo)
{
RasctlDisplay display;
PbDevice device;
EXPECT_FALSE(display.DisplayDeviceInfo(device).empty());
device.mutable_properties()->set_supports_file(true);
device.mutable_properties()->set_read_only(true);
device.mutable_properties()->set_protectable(true);
device.mutable_status()->set_protected_(true);
device.mutable_properties()->set_stoppable(true);
device.mutable_status()->set_stopped(true);
device.mutable_properties()->set_removable(true);
device.mutable_status()->set_removed(true);
device.mutable_properties()->set_lockable(true);
device.mutable_status()->set_locked(true);
EXPECT_FALSE(display.DisplayDeviceInfo(device).empty());
device.set_block_size(1234);
string s = display.DisplayDeviceInfo(device);
EXPECT_FALSE(s.empty());
EXPECT_NE(string::npos, s.find("1234"));
device.set_block_count(4321);
s = display.DisplayDeviceInfo(device);
EXPECT_FALSE(s.empty());
EXPECT_NE(string::npos, s.find(to_string(1234 *4321)));
device.mutable_properties()->set_supports_file(true);
auto file = make_unique<PbImageFile>();
file->set_name("filename");
device.set_allocated_file(file.release());
s = display.DisplayDeviceInfo(device); //NOSONAR The allocated memory is managed by protobuf
EXPECT_FALSE(s.empty());
EXPECT_NE(string::npos, s.find("filename"));
device.mutable_properties()->set_supports_params(true);
(*device.mutable_params())["key1"] = "value1";
s = display.DisplayDeviceInfo(device);
EXPECT_FALSE(s.empty());
EXPECT_NE(string::npos, s.find("key1=value1"));
(*device.mutable_params())["key2"] = "value2";
s = display.DisplayDeviceInfo(device);
EXPECT_FALSE(s.empty());
EXPECT_NE(string::npos, s.find("key1=value1"));
EXPECT_NE(string::npos, s.find("key2=value2"));
}
TEST(RasctlDisplayTest, DisplayVersionInfo)
{
RasctlDisplay display;
PbVersionInfo info;
info.set_major_version(1);
info.set_minor_version(2);
info.set_patch_version(3);
string s = display.DisplayVersionInfo(info);
EXPECT_FALSE(s.empty());
EXPECT_EQ(string::npos, s.find("development version"));
EXPECT_NE(string::npos, s.find("01.02.3"));
info.set_patch_version(-1);
s = display.DisplayVersionInfo(info);
EXPECT_FALSE(s.empty());
EXPECT_NE(string::npos, s.find("development version"));
EXPECT_NE(string::npos, s.find("01.02"));
}
TEST(RasctlDisplayTest, DisplayLogLevelInfo)
{
RasctlDisplay display;
PbLogLevelInfo info;
string s = display.DisplayLogLevelInfo(info);
EXPECT_FALSE(s.empty());
info.add_log_levels("test");
s = display.DisplayLogLevelInfo(info);
EXPECT_FALSE(s.empty());
EXPECT_NE(string::npos, s.find("test"));
}
TEST(RasctlDisplayTest, DisplayDeviceTypesInfo)
{
RasctlDisplay display;
PbDeviceTypesInfo info;
// Start with 2 instead of 1. 1 was the removed SASI drive type.
int ordinal = 2;
while (PbDeviceType_IsValid(ordinal)) {
PbDeviceType type = UNDEFINED;
PbDeviceType_Parse(PbDeviceType_Name((PbDeviceType)ordinal), &type);
auto type_properties = info.add_properties();
type_properties->set_type(type);
if (type == SCHD) {
type_properties->mutable_properties()->set_supports_file(true);
type_properties->mutable_properties()->add_block_sizes(512);
type_properties->mutable_properties()->add_block_sizes(1024);
}
if (type == SCMO) {
type_properties->mutable_properties()->set_supports_file(true);
type_properties->mutable_properties()->set_read_only(true);
type_properties->mutable_properties()->set_protectable(true);
type_properties->mutable_properties()->set_stoppable(true);
type_properties->mutable_properties()->set_removable(true);
type_properties->mutable_properties()->set_lockable(true);
}
if (type == SCLP) {
type_properties->mutable_properties()->set_supports_params(true);
(*type_properties->mutable_properties()->mutable_default_params())["key1"] = "value1";
(*type_properties->mutable_properties()->mutable_default_params())["key2"] = "value2";
}
ordinal++;
}
const string s = display.DisplayDeviceTypesInfo(info);
EXPECT_FALSE(s.empty());
EXPECT_NE(string::npos, s.find("key1=value1"));
EXPECT_NE(string::npos, s.find("key2=value2"));
}
TEST(RasctlDisplayTest, DisplayReservedIdsInfo)
{
RasctlDisplay display;
PbReservedIdsInfo info;
string s = display.DisplayReservedIdsInfo(info);
EXPECT_FALSE(s.empty());
info.mutable_ids()->Add(5);
s = display.DisplayReservedIdsInfo(info);
EXPECT_FALSE(s.empty());
EXPECT_NE(string::npos, s.find("5"));
info.mutable_ids()->Add(6);
s = display.DisplayReservedIdsInfo(info);
EXPECT_FALSE(s.empty());
EXPECT_NE(string::npos, s.find("5, 6"));
}
TEST(RasctlDisplayTest, DisplayNetworkInterfacesInfo)
{
RasctlDisplay display;
PbNetworkInterfacesInfo info;
string s = display.DisplayNetworkInterfaces(info);
EXPECT_FALSE(s.empty());
info.mutable_name()->Add("eth0");
s = display.DisplayNetworkInterfaces(info);
EXPECT_FALSE(s.empty());
EXPECT_NE(string::npos, s.find("eth0"));
info.mutable_name()->Add("wlan0");
s = display.DisplayNetworkInterfaces(info);
EXPECT_FALSE(s.empty());
EXPECT_NE(string::npos, s.find("eth0, wlan0"));
}
TEST(RasctlDisplayTest, DisplayImageFile)
{
RasctlDisplay display;
PbImageFile file;
string s = display.DisplayImageFile(file);
EXPECT_FALSE(s.empty());
file.set_name("filename");
s = display.DisplayImageFile(file);
EXPECT_FALSE(s.empty());
EXPECT_NE(string::npos, s.find("filename"));
EXPECT_EQ(string::npos, s.find("read-only"));
EXPECT_EQ(string::npos, s.find("SCHD"));
file.set_read_only(true);
s = display.DisplayImageFile(file);
EXPECT_FALSE(s.empty());
EXPECT_NE(string::npos, s.find("filename"));
EXPECT_NE(string::npos, s.find("read-only"));
EXPECT_EQ(string::npos, s.find("SCHD"));
file.set_type(SCHD);
s = display.DisplayImageFile(file);
EXPECT_FALSE(s.empty());
EXPECT_NE(string::npos, s.find("SCHD"));
}
TEST(RasctlDisplayTest, DisplayImageFilesInfo)
{
RasctlDisplay display;
PbImageFilesInfo info;
string s = display.DisplayImageFilesInfo(info);
EXPECT_FALSE(display.DisplayImageFilesInfo(info).empty());
EXPECT_EQ(string::npos, s.find("filename"));
PbImageFile *file = info.add_image_files();
file->set_name("filename");
s = display.DisplayImageFilesInfo(info);
EXPECT_FALSE(s.empty());
EXPECT_NE(string::npos, s.find("filename"));
}
TEST(RasctlDisplayTest, DisplayMappingInfo)
{
RasctlDisplay display;
PbMappingInfo info;
string s = display.DisplayMappingInfo(info);
EXPECT_FALSE(s.empty());
EXPECT_EQ(string::npos, s.find("key->SCHD"));
(*info.mutable_mapping())["key"] = SCHD;
s = display.DisplayMappingInfo(info);
EXPECT_FALSE(s.empty());
EXPECT_NE(string::npos, s.find("key->SCHD"));
}
TEST(RasctlDisplayTest, DisplayOperationInfo)
{
RasctlDisplay display;
PbOperationInfo info;
string s = display.DisplayOperationInfo(info);
EXPECT_FALSE(s.empty());
PbOperationMetaData meta_data;
PbOperationParameter *param1 = meta_data.add_parameters();
param1->set_name("default_key1");
param1->set_default_value("default_value1");
PbOperationParameter *param2 = meta_data.add_parameters();
param2->set_name("default_key2");
param2->set_default_value("default_value2");
param2->set_description("description2");
PbOperationParameter *param3 = meta_data.add_parameters();
param3->set_name("default_key3");
param3->set_default_value("default_value3");
param3->set_description("description3");
param3->add_permitted_values("permitted_value3_1");
param3->add_permitted_values("permitted_value3_2");
(*info.mutable_operations())[0] = meta_data;
s = display.DisplayOperationInfo(info);
EXPECT_FALSE(s.empty());
EXPECT_NE(string::npos, s.find(PbOperation_Name(NO_OPERATION)));
meta_data.set_server_side_name("name");
meta_data.set_description("description");
(*info.mutable_operations())[0] = meta_data;
s = display.DisplayOperationInfo(info);
EXPECT_FALSE(s.empty());
EXPECT_NE(string::npos, s.find("default_key1"));
EXPECT_NE(string::npos, s.find("default_value1"));
EXPECT_NE(string::npos, s.find("default_key2"));
EXPECT_NE(string::npos, s.find("default_value2"));
EXPECT_NE(string::npos, s.find("description2"));
EXPECT_NE(string::npos, s.find("description3"));
EXPECT_NE(string::npos, s.find("permitted_value3_1"));
EXPECT_NE(string::npos, s.find("permitted_value3_2"));
}

View File

@ -0,0 +1,55 @@
//---------------------------------------------------------------------------
//
// SCSI Target Emulator RaSCSI Reloaded
// for Raspberry Pi
//
// Copyright (C) 2022 Uwe Seimet
//
//---------------------------------------------------------------------------
#include <gtest/gtest.h>
#include "rasctl/rasctl_parser.h"
TEST(RasctlParserTest, ParseOperation)
{
RasctlParser parser;
EXPECT_EQ(ATTACH, parser.ParseOperation("A"));
EXPECT_EQ(ATTACH, parser.ParseOperation("a"));
EXPECT_EQ(DETACH, parser.ParseOperation("d"));
EXPECT_EQ(INSERT, parser.ParseOperation("i"));
EXPECT_EQ(EJECT, parser.ParseOperation("e"));
EXPECT_EQ(PROTECT, parser.ParseOperation("p"));
EXPECT_EQ(UNPROTECT, parser.ParseOperation("u"));
EXPECT_EQ(NO_OPERATION, parser.ParseOperation(""));
EXPECT_EQ(NO_OPERATION, parser.ParseOperation("xyz"));
}
TEST(RasctlParserTest, ParseType)
{
RasctlParser parser;
EXPECT_EQ(SCBR, parser.ParseType("SCBR"));
EXPECT_EQ(SCBR, parser.ParseType("scbr"));
EXPECT_EQ(SCCD, parser.ParseType("sccd"));
EXPECT_EQ(SCDP, parser.ParseType("scdp"));
EXPECT_EQ(SCHD, parser.ParseType("schd"));
EXPECT_EQ(SCLP, parser.ParseType("sclp"));
EXPECT_EQ(SCMO, parser.ParseType("scmo"));
EXPECT_EQ(SCRM, parser.ParseType("scrm"));
EXPECT_EQ(SCHS, parser.ParseType("schs"));
EXPECT_EQ(SCBR, parser.ParseType("B"));
EXPECT_EQ(SCBR, parser.ParseType("b"));
EXPECT_EQ(SCCD, parser.ParseType("c"));
EXPECT_EQ(SCDP, parser.ParseType("d"));
EXPECT_EQ(SCHD, parser.ParseType("h"));
EXPECT_EQ(SCLP, parser.ParseType("l"));
EXPECT_EQ(SCMO, parser.ParseType("m"));
EXPECT_EQ(SCRM, parser.ParseType("r"));
EXPECT_EQ(SCHS, parser.ParseType("s"));
EXPECT_EQ(UNDEFINED, parser.ParseType(""));
EXPECT_EQ(UNDEFINED, parser.ParseType("xyz"));
}

View File

@ -25,3 +25,33 @@ TEST(RasUtilTest, GetAsInt)
EXPECT_TRUE(GetAsInt("1234", result));
EXPECT_EQ(1234, result);
}
TEST(RasUtilTest, Banner)
{
EXPECT_FALSE(Banner("Test").empty());
}
TEST(RasUtilTest, ListDevices)
{
list<PbDevice> devices;
EXPECT_FALSE(ListDevices(devices).empty());
PbDevice device;
device.set_type(SCHD);
devices.push_back(device);
device.set_type(SCBR);
devices.push_back(device);
device.set_type(SCDP);
devices.push_back(device);
device.set_type(SCHS);
devices.push_back(device);
device.set_type(SCLP);
devices.push_back(device);
const string device_list = ListDevices(devices);
EXPECT_FALSE(device_list.empty());
EXPECT_NE(string::npos, device_list.find("X68000 HOST BRIDGE"));
EXPECT_NE(string::npos, device_list.find("DaynaPort SCSI/Link"));
EXPECT_NE(string::npos, device_list.find("Host Services"));
EXPECT_NE(string::npos, device_list.find("SCSI Printer"));
}

View File

@ -8,10 +8,47 @@
//---------------------------------------------------------------------------
#include "mocks.h"
#include "rascsi_exceptions.h"
#include "devices/scsi_command_util.h"
using namespace scsi_command_util;
TEST(ScsiCommandUtilTest, ModeSelect)
{
const int LENGTH = 12;
vector<int> cdb(16);
vector<BYTE> buf(255);
// PF (vendor-specific parameter format)
cdb[1] = 0x00;
EXPECT_THROW(ModeSelect(cdb, buf, LENGTH, 0), scsi_exception)
<< "Vendor-specific parameters are not supported";
// PF (standard parameter format)
cdb[1] = 0x10;
// Request 512 bytes per sector
buf[9] = 0x00;
buf[10] = 0x02;
buf[11] = 0x00;
EXPECT_THROW(ModeSelect(cdb, buf, LENGTH, 256), scsi_exception)
<< "Requested sector size does not match current sector size";
// Page 0
buf[LENGTH] = 0x00;
EXPECT_THROW(ModeSelect(cdb, buf, LENGTH + 2, 512), scsi_exception)
<< "Unsupported page 0 was not rejected";
// Page 3 (Format Device Page)
buf[LENGTH] = 0x03;
EXPECT_THROW(ModeSelect(cdb, buf, LENGTH + 2, 512), scsi_exception)
<< "Requested sector size does not match current sector size";
// Match the requested to the current sector size
buf[LENGTH + 12] = 0x02;
ModeSelect(cdb, buf, LENGTH + 2, 512);
}
TEST(ScsiCommandUtilTest, EnrichFormatPage)
{
const int SECTOR_SIZE = 512;

View File

@ -0,0 +1,125 @@
//---------------------------------------------------------------------------
//
// SCSI Target Emulator RaSCSI Reloaded
// for Raspberry Pi
//
// Copyright (C) 2022 Uwe Seimet
//
//---------------------------------------------------------------------------
#include "mocks.h"
#include "rascsi_exceptions.h"
#include "devices/scsi_daynaport.h"
TEST(ScsiDaynaportTest, Inquiry)
{
TestInquiry(SCDP, device_type::PROCESSOR, scsi_level::SCSI_2, scsi_level::SCSI_2,
"Dayna SCSI/Link 1.4a", 0x20, false);
}
TEST(ScsiDaynaportTest, Dispatch)
{
NiceMock<MockAbstractController> controller(0);
auto daynaport = CreateDevice(SCDP, controller);
EXPECT_FALSE(daynaport->Dispatch(scsi_command::eCmdModeSense6))
<< "Non-DaynaPort commands inherited from Disk must not be supported";
EXPECT_FALSE(daynaport->Dispatch(scsi_command::eCmdModeSelect6))
<< "Non-DaynaPort commands inherited from Disk must not be supported";
EXPECT_FALSE(daynaport->Dispatch(scsi_command::eCmdModeSense10))
<< "Non-DaynaPort commands inherited from Disk must not be supported";
EXPECT_FALSE(daynaport->Dispatch(scsi_command::eCmdModeSelect10))
<< "Non-DaynaPort commands inherited from Disk must not be supported";
}
TEST(ScsiDaynaportTest, TestUnitReady)
{
NiceMock<MockAbstractController> controller(0);
auto daynaport = CreateDevice(SCDP, controller);
EXPECT_CALL(controller, Status()).Times(1);
EXPECT_TRUE(daynaport->Dispatch(scsi_command::eCmdTestUnitReady)) << "TEST UNIT READY must never fail";
EXPECT_EQ(status::GOOD, controller.GetStatus());
}
TEST(ScsiDaynaportTest, TestRetrieveStats)
{
NiceMock<MockAbstractController> controller(0);
auto daynaport = CreateDevice(SCDP, controller);
vector<int>& cmd = controller.InitCmd(6);
// ALLOCATION LENGTH
cmd[4] = 255;
EXPECT_CALL(controller, DataIn()).Times(1);
EXPECT_TRUE(daynaport->Dispatch(scsi_command::eCmdRetrieveStats));
}
TEST(ScsiDaynaportTest, SetInterfaceMode)
{
NiceMock<MockAbstractController> controller(0);
auto daynaport = CreateDevice(SCDP, controller);
vector<int>& cmd = controller.InitCmd(6);
// Unknown interface command
EXPECT_THROW(daynaport->Dispatch(scsi_command::eCmdSetIfaceMode), scsi_exception);
// Not implemented, do nothing
cmd[5] = SCSIDaynaPort::CMD_SCSILINK_SETMODE;
EXPECT_CALL(controller, Status()).Times(1);
EXPECT_TRUE(daynaport->Dispatch(scsi_command::eCmdSetIfaceMode));
EXPECT_EQ(status::GOOD, controller.GetStatus());
cmd[5] = SCSIDaynaPort::CMD_SCSILINK_SETMAC;
EXPECT_CALL(controller, DataOut()).Times(1);
EXPECT_TRUE(daynaport->Dispatch(scsi_command::eCmdSetIfaceMode));
// Not implemented
cmd[5] = SCSIDaynaPort::CMD_SCSILINK_STATS;
EXPECT_THROW(daynaport->Dispatch(scsi_command::eCmdSetIfaceMode), scsi_exception);
// Not implemented
cmd[5] = SCSIDaynaPort::CMD_SCSILINK_ENABLE;
EXPECT_THROW(daynaport->Dispatch(scsi_command::eCmdSetIfaceMode), scsi_exception);
// Not implemented
cmd[5] = SCSIDaynaPort::CMD_SCSILINK_SET;
EXPECT_THROW(daynaport->Dispatch(scsi_command::eCmdSetIfaceMode), scsi_exception);
}
TEST(ScsiDaynaportTest, SetMcastAddr)
{
NiceMock<MockAbstractController> controller(0);
auto daynaport = CreateDevice(SCDP, controller);
vector<int>& cmd = controller.InitCmd(6);
EXPECT_THROW(daynaport->Dispatch(scsi_command::eCmdSetMcastAddr), scsi_exception) << "Length of 0 is not supported";
cmd[4] = 1;
EXPECT_CALL(controller, DataOut()).Times(1);
EXPECT_TRUE(daynaport->Dispatch(scsi_command::eCmdSetMcastAddr));
}
TEST(ScsiDaynaportTest, EnableInterface)
{
NiceMock<MockAbstractController> controller(0);
auto daynaport = CreateDevice(SCDP, controller);
vector<int>& cmd = controller.InitCmd(6);
// Enable
EXPECT_THROW(daynaport->Dispatch(scsi_command::eCmdEnableInterface), scsi_exception);
// Disable
cmd[5] = 0x80;
EXPECT_THROW(daynaport->Dispatch(scsi_command::eCmdEnableInterface), scsi_exception);
}
TEST(ScsiDaynaportTest, GetSendDelay)
{
SCSIDaynaPort daynaport(0);
EXPECT_EQ(6, daynaport.GetSendDelay());
}

View File

@ -0,0 +1,16 @@
//---------------------------------------------------------------------------
//
// SCSI Target Emulator RaSCSI Reloaded
// for Raspberry Pi
//
// Copyright (C) 2022 Uwe Seimet
//
//---------------------------------------------------------------------------
#include "mocks.h"
TEST(ScsiHostBridgeTest, Inquiry)
{
TestInquiry(SCBR, device_type::COMMUNICATIONS, scsi_level::SCSI_2, scsi_level::SCSI_2,
"RaSCSI RASCSI BRIDGE ", 0x27, false);
}

View File

@ -0,0 +1,72 @@
//---------------------------------------------------------------------------
//
// SCSI Target Emulator RaSCSI Reloaded
// for Raspberry Pi
//
// Copyright (C) 2022 Uwe Seimet
//
//---------------------------------------------------------------------------
#include "mocks.h"
#include "rascsi_exceptions.h"
#include "controllers/controller_manager.h"
#include "devices/scsi_printer.h"
using namespace std;
TEST(ScsiPrinterTest, TestUnitReady)
{
NiceMock<MockAbstractController> controller(0);
auto printer = CreateDevice(SCLP, controller);
EXPECT_CALL(controller, Status()).Times(1);
EXPECT_TRUE(printer->Dispatch(scsi_command::eCmdTestUnitReady));
EXPECT_EQ(status::GOOD, controller.GetStatus());
}
TEST(ScsiPrinterTest, Inquiry)
{
TestInquiry(SCLP, device_type::PRINTER, scsi_level::SCSI_2, scsi_level::SCSI_2,
"RaSCSI SCSI PRINTER ", 0x1f, false);
}
TEST(ScsiPrinterTest, ReserveUnit)
{
NiceMock<MockAbstractController> controller(0);
auto printer = CreateDevice(SCLP, controller);
EXPECT_CALL(controller, Status()).Times(1);
EXPECT_TRUE(printer->Dispatch(scsi_command::eCmdReserve6));
EXPECT_EQ(status::GOOD, controller.GetStatus());
}
TEST(ScsiPrinterTest, ReleaseUnit)
{
NiceMock<MockAbstractController> controller(0);
auto printer = CreateDevice(SCLP, controller);
EXPECT_CALL(controller, Status()).Times(1);
EXPECT_TRUE(printer->Dispatch(scsi_command::eCmdRelease6));
EXPECT_EQ(status::GOOD, controller.GetStatus());
}
TEST(ScsiPrinterTest, SendDiagnostic)
{
NiceMock<MockAbstractController> controller(0);
auto printer = CreateDevice(SCLP, controller);
EXPECT_CALL(controller, Status()).Times(1);
EXPECT_TRUE(printer->Dispatch(scsi_command::eCmdSendDiag));
EXPECT_EQ(status::GOOD, controller.GetStatus());
}
TEST(ScsiPrinterTest, StopPrint)
{
NiceMock<MockAbstractController> controller(0);
auto printer = CreateDevice(SCLP, controller);
EXPECT_CALL(controller, Status()).Times(1);
EXPECT_TRUE(printer->Dispatch(scsi_command::eCmdStartStop));
EXPECT_EQ(status::GOOD, controller.GetStatus());
}

Some files were not shown because too many files have changed in this diff Show More