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
106 changed files with 2951 additions and 1631 deletions

View File

@@ -85,14 +85,16 @@ SRC_PROTOC = \
SRC_PROTOBUF = \ SRC_PROTOBUF = \
rascsi_interface.pb.cpp rascsi_interface.pb.cpp
SRC_RASCSI_CORE = \ SRC_SHARED = \
scsi.cpp \
filepath.cpp \
fileio.cpp \
rascsi_version.cpp \ rascsi_version.cpp \
rasutil.cpp \ rasutil.cpp \
command_util.cpp \ protobuf_util.cpp \
protobuf_serializer.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 ./rascsi -name '*.cpp')
SRC_RASCSI_CORE += $(shell find ./controllers -name '*.cpp') SRC_RASCSI_CORE += $(shell find ./controllers -name '*.cpp')
SRC_RASCSI_CORE += $(shell find ./devices -name '*.cpp') SRC_RASCSI_CORE += $(shell find ./devices -name '*.cpp')
@@ -102,22 +104,18 @@ SRC_RASCSI = rascsi.cpp
SRC_SCSIMON = \ SRC_SCSIMON = \
scsimon.cpp \ scsimon.cpp \
scsi.cpp \ bus.cpp \
rascsi_version.cpp rascsi_version.cpp
SRC_SCSIMON += $(shell find ./monitor -name '*.cpp') SRC_SCSIMON += $(shell find ./monitor -name '*.cpp')
SRC_SCSIMON += $(shell find ./hal -name '*.cpp') SRC_SCSIMON += $(shell find ./hal -name '*.cpp')
SRC_RASCTL = \ SRC_RASCTL_CORE = $(shell find ./rasctl -name '*.cpp')
rasctl.cpp\
rascsi_version.cpp \ SRC_RASCTL = rasctl.cpp
rasutil.cpp \
command_util.cpp \
protobuf_serializer.cpp
SRC_RASCTL += $(shell find ./rasctl -name '*.cpp')
SRC_RASDUMP = \ SRC_RASDUMP = \
rasdump.cpp \ rasdump.cpp \
scsi.cpp \ bus.cpp \
filepath.cpp \ filepath.cpp \
fileio.cpp \ fileio.cpp \
rascsi_version.cpp rascsi_version.cpp
@@ -134,10 +132,12 @@ vpath ./$(BINDIR)
OBJ_RASCSI_CORE := $(addprefix $(OBJDIR)/,$(notdir $(SRC_RASCSI_CORE:%.cpp=%.o))) OBJ_RASCSI_CORE := $(addprefix $(OBJDIR)/,$(notdir $(SRC_RASCSI_CORE:%.cpp=%.o)))
OBJ_RASCSI := $(addprefix $(OBJDIR)/,$(notdir $(SRC_RASCSI:%.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_RASCTL := $(addprefix $(OBJDIR)/,$(notdir $(SRC_RASCTL:%.cpp=%.o)))
OBJ_RASDUMP := $(addprefix $(OBJDIR)/,$(notdir $(SRC_RASDUMP:%.cpp=%.o))) OBJ_RASDUMP := $(addprefix $(OBJDIR)/,$(notdir $(SRC_RASDUMP:%.cpp=%.o)))
OBJ_SCSIMON := $(addprefix $(OBJDIR)/,$(notdir $(SRC_SCSIMON:%.cpp=%.o))) OBJ_SCSIMON := $(addprefix $(OBJDIR)/,$(notdir $(SRC_SCSIMON:%.cpp=%.o)))
OBJ_RASCSI_TEST := $(addprefix $(OBJDIR)/,$(notdir $(SRC_RASCSI_TEST:%.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))) OBJ_PROTOBUF := $(addprefix $(OBJDIR)/,$(notdir $(SRC_PROTOBUF:%.cpp=%.o)))
GEN_PROTOBUF := $(SRC_PROTOBUF) rascsi_interface.pb.h 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) # 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 # 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) -include $(ALL_DEPS)
$(OBJDIR) $(BINDIR): $(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 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) $(BINDIR)/$(RASCSI): $(SRC_PROTOBUF) $(OBJ_RASCSI_CORE) $(OBJ_RASCSI) $(OBJ_SHARED) $(OBJ_PROTOBUF) | $(BINDIR)
$(CXX) $(CXXFLAGS) -o $@ $(OBJ_RASCSI_CORE) $(OBJ_RASCSI) $(OBJ_PROTOBUF) -lpthread -lpcap -lprotobuf -lstdc++fs $(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) $(BINDIR)/$(RASCTL): $(SRC_PROTOBUF) $(OBJ_RASCTL_CORE) $(OBJ_RASCTL) $(OBJ_SHARED) $(OBJ_PROTOBUF) | $(BINDIR)
$(CXX) $(CXXFLAGS) -o $@ $(OBJ_RASCTL) $(OBJ_PROTOBUF) -lpthread -lprotobuf $(CXX) $(CXXFLAGS) -o $@ $(OBJ_RASCTL_CORE) $(OBJ_RASCTL) $(OBJ_SHARED) $(OBJ_PROTOBUF) -lpthread -lprotobuf
$(BINDIR)/$(RASDUMP): $(OBJ_RASDUMP) | $(BINDIR) $(BINDIR)/$(RASDUMP): $(OBJ_RASDUMP) | $(BINDIR)
$(CXX) $(CXXFLAGS) -o $@ $(OBJ_RASDUMP) $(CXX) $(CXXFLAGS) -o $@ $(OBJ_RASDUMP)
@@ -200,8 +200,8 @@ $(BINDIR)/$(RASDUMP): $(OBJ_RASDUMP) | $(BINDIR)
$(BINDIR)/$(SCSIMON): $(OBJ_SCSIMON) | $(BINDIR) $(BINDIR)/$(SCSIMON): $(OBJ_SCSIMON) | $(BINDIR)
$(CXX) $(CXXFLAGS) -o $@ $(OBJ_SCSIMON) -lpthread $(CXX) $(CXXFLAGS) -o $@ $(OBJ_SCSIMON) -lpthread
$(BINDIR)/$(RASCSI_TEST): $(SRC_PROTOBUF) $(OBJ_RASCSI_CORE) $(OBJ_RASCSI_TEST) $(OBJ_PROTOBUF) | $(BINDIR) $(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_RASCSI_TEST) $(OBJ_PROTOBUF) -lpthread -lpcap -lprotobuf -lstdc++fs -lgmock -lgtest $(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 # 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) 2001-2006 (ytanaka@ipc-tokai.or.jp)
// Copyright (C) 2014-2020 GIMONS // Copyright (C) 2014-2020 GIMONS
// // Copyright (C) 2022 Uwe Seimet
// [ SCSI Common Functionality ]
// //
//--------------------------------------------------------------------------- //---------------------------------------------------------------------------
@@ -31,9 +30,9 @@ BUS::phase_t BUS::GetPhase()
} }
// Get target phase from bus signal line // Get target phase from bus signal line
int mci = GetMSG() ? 0x04 : 0x00; int mci = GetMSG() ? 0b100 : 0b000;
mci |= GetCD() ? 0x02 : 0x00; mci |= GetCD() ? 0b010 : 0b000;
mci |= GetIO() ? 0x01 : 0x00; mci |= GetIO() ? 0b001 : 0b000;
return GetPhase(mci); return GetPhase(mci);
} }

View File

@@ -59,7 +59,7 @@ public:
static const char* GetPhaseStrRaw(phase_t current_phase); static const char* GetPhaseStrRaw(phase_t current_phase);
// Extract as specific pin field from a raw data capture // 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); return ((raw_data >> pin_num) & 1);
} }

View File

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

View File

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

View File

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

View File

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

View File

@@ -79,7 +79,7 @@ BUS::phase_t ScsiController::Process(int id)
try { try {
ProcessPhase(); ProcessPhase();
} }
catch(const scsi_error_exception&) { catch(const scsi_exception&) {
// Any exception should have been handled during the phase processing // Any exception should have been handled during the phase processing
assert(false); assert(false);
@@ -198,8 +198,8 @@ void ScsiController::Command()
bus.SetCD(true); bus.SetCD(true);
bus.SetIO(false); bus.SetIO(false);
int actual_count = bus.CommandHandShake(GetBuffer().data()); const int actual_count = bus.CommandHandShake(GetBuffer().data());
int command_byte_count = GPIOBUS::GetCommandByteCount(GetBuffer()[0]); const int command_byte_count = GPIOBUS::GetCommandByteCount(GetBuffer()[0]);
// If not able to receive all, move to the status phase // If not able to receive all, move to the status phase
if (actual_count != command_byte_count) { if (actual_count != command_byte_count) {
@@ -267,10 +267,10 @@ void ScsiController::Execute()
if (!device->Dispatch(GetOpcode())) { if (!device->Dispatch(GetOpcode())) {
LOGTRACE("ID %d LUN %d received unsupported command: $%02X", GetTargetId(), lun, (int)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()); Error(e.get_sense_key(), e.get_asc(), e.get_status());
// Fall through // 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) { if (sense_key != sense_key::NO_SENSE || asc != asc::NO_ADDITIONAL_SENSE_INFORMATION) {
LOGDEBUG("Error status: Sense Key $%02X, ASC $%02X, ASCQ $%02X", LOGDEBUG("Error status: Sense Key $%02X, ASC $%02X", (int)sense_key, (int)asc)
(int)sense_key << 16, (int)asc << 8, (int)asc & 0xff)
// 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)); 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 // 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. // 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); HasDeviceForLun(0) ? GetDeviceForLun(0)->GetSendDelay() : 0);
len != (int)ctrl.length) { len != (int)ctrl.length) {
// If you cannot send all, move to status phase // If you cannot send all, move to status phase
@@ -798,7 +797,7 @@ void ScsiController::FlushUnit()
try { try {
disk->ModeSelect(ctrl.cmd, GetBuffer(), GetOffset()); 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()) LOGWARN("Error occured while processing Mode Select command %02X\n", (int)GetOpcode())
Error(e.get_sense_key(), e.get_asc(), e.get_status()); Error(e.get_sense_key(), e.get_asc(), e.get_status());
return; return;
@@ -841,7 +840,7 @@ bool ScsiController::XferIn(vector<BYTE>& buf)
try { try {
ctrl.length = (dynamic_pointer_cast<Disk>(GetDeviceForLun(lun)))->Read(ctrl.cmd, buf, ctrl.next); 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 // If there is an error, go to the status phase
return false; return false;
} }
@@ -881,7 +880,7 @@ bool ScsiController::XferOutBlockOriented(bool cont)
try { try {
disk->ModeSelect(ctrl.cmd, GetBuffer(), GetOffset()); 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()); Error(e.get_sense_key(), e.get_asc(), e.get_status());
return false; return false;
} }
@@ -919,7 +918,7 @@ bool ScsiController::XferOutBlockOriented(bool cont)
try { try {
disk->Write(ctrl.cmd, GetBuffer(), ctrl.next - 1); 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()); Error(e.get_sense_key(), e.get_asc(), e.get_status());
// Write failed // Write failed
@@ -936,7 +935,7 @@ bool ScsiController::XferOutBlockOriented(bool cont)
try { try {
ctrl.length = disk->WriteCheck(ctrl.next - 1); ctrl.length = disk->WriteCheck(ctrl.next - 1);
} }
catch(const scsi_error_exception&) { catch(const scsi_exception&) {
// Cannot write // Cannot write
return false; return false;
} }
@@ -976,7 +975,7 @@ void ScsiController::ParseMessage()
{ {
int i = 0; int i = 0;
while (i < scsi.msc) { while (i < scsi.msc) {
BYTE message_type = scsi.msb[i]; const BYTE message_type = scsi.msb[i];
if (message_type == 0x06) { if (message_type == 0x06) {
LOGTRACE("Received ABORT message") LOGTRACE("Received ABORT message")
@@ -1064,7 +1063,7 @@ int ScsiController::GetEffectiveLun() const
void ScsiController::Sleep() 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); SysTimer::SleepUsec(MIN_EXEC_TIME - time);
} }
execstart = 0; execstart = 0;

View File

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

View File

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

View File

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

View File

@@ -116,41 +116,41 @@ namespace Human68k {
struct files_t { struct files_t {
BYTE fatr; ///< + 0 search attribute; read-only BYTE fatr; ///< + 0 search attribute; read-only
// BYTE drive; ///< + 1 drive number; read-only // BYTE drive; ///< + 1 drive number; read-only
DWORD sector; ///< + 2 directory sector; DOS _FILES first address substitute uint32_t sector; ///< + 2 directory sector; DOS _FILES first address substitute
// WORD cluster; ///< + 6 directory cluster; details unknown (unused) // uint16_t cluster; ///< + 6 directory cluster; details unknown (unused)
WORD offset; ///< + 8 directory entry; write-only uint16_t offset; ///< + 8 directory entry; write-only
// BYTE name[8]; ///< +10 working file name; write-only (unused) // BYTE name[8]; ///< +10 working file name; write-only (unused)
// BYTE ext[3]; ///< +18 working extension; write-only (unused) // BYTE ext[3]; ///< +18 working extension; write-only (unused)
BYTE attr; ///< +21 file attribute; write-only BYTE attr; ///< +21 file attribute; write-only
WORD time; ///< +22 last change time of day; write-only uint16_t time; ///< +22 last change time of day; write-only
WORD date; ///< +24 last change date; write-only uint16_t date; ///< +24 last change date; write-only
DWORD size; ///< +26 file size; write-only uint32_t size; ///< +26 file size; write-only
BYTE full[23]; ///< +30 full name; write-only BYTE full[23]; ///< +30 full name; write-only
}; };
struct fcb_t { struct fcb_t {
// BYTE pad00[6]; ///< + 0~+ 5 (unused) // 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) // 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) // 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 name[8]; ///< +36~+43 file name (PADDING 0x20) (unused)
// BYTE ext[3]; ///< +44~+46 extension (PADDING 0x20) (unused) // BYTE ext[3]; ///< +44~+46 extension (PADDING 0x20) (unused)
BYTE attr; ///< +47 file attribute BYTE attr; ///< +47 file attribute
// BYTE add[10]; ///< +48~+57 file name addition (PADDING 0x00) (unused) // BYTE add[10]; ///< +48~+57 file name addition (PADDING 0x00) (unused)
WORD time; ///< +58~+59 last change time of day uint16_t time; ///< +58~+59 last change time of day
WORD date; ///< +60~+61 last change date uint16_t date; ///< +60~+61 last change date
// WORD cluster; ///< +62~+63 cluster number (unused) // uint16_t cluster; ///< +62~+63 cluster number (unused)
DWORD size; ///< +64~+67 file size uint32_t size; ///< +64~+67 file size
// BYTE pad03[28]; ///< +68~+95 FAT cache (unused) // BYTE pad03[28]; ///< +68~+95 FAT cache (unused)
}; };
struct capacity_t { struct capacity_t {
WORD freearea; ///< + 0 Number of available clusters uint16_t freearea; ///< + 0 Number of available clusters
WORD clusters; ///< + 2 Total number of clusters uint16_t clusters; ///< + 2 Total number of clusters
WORD sectors; ///< + 4 Number of sectors per cluster uint16_t sectors; ///< + 4 Number of sectors per cluster
WORD bytes; ///< + 6 Number of bytes per sector uint16_t bytes; ///< + 6 Number of bytes per sector
}; };
struct ctrldrive_t { struct ctrldrive_t {
@@ -159,17 +159,17 @@ namespace Human68k {
}; };
struct dpb_t { 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 cluster_size; ///< + 2 Number sectors in one cluster -1
BYTE shift; ///< + 3 Number of cluster→sector shifts 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_max; ///< + 6 FAT storage quantity
BYTE fat_size; ///< + 7 FAT controlled sector number (excluding duplicates) BYTE fat_size; ///< + 7 FAT controlled sector number (excluding duplicates)
WORD file_max; ///< + 8 Number of files in the root directory uint16_t file_max; ///< + 8 Number of files in the root directory
WORD data_sector; ///< +10 First sector number of data storage uint16_t data_sector; ///< +10 First sector number of data storage
WORD cluster_max; ///< +12 Total number of clusters +1 uint16_t cluster_max; ///< +12 Total number of clusters +1
WORD root_sector; ///< +14 First sector number of root directory uint16_t root_sector; ///< +14 First sector number of root directory
// DWORD driverentry; ///< +16 Device driver pointer (unused) // uint32_t driverentry; ///< +16 Device driver pointer (unused)
BYTE media; ///< +20 Media identifier BYTE media; ///< +20 Media identifier
// BYTE flag; ///< +21 Flag used by DPB (unused) // BYTE flag; ///< +21 Flag used by DPB (unused)
}; };
@@ -180,17 +180,17 @@ namespace Human68k {
BYTE ext[3]; ///< + 8 Extension (PADDING 0x20) BYTE ext[3]; ///< + 8 Extension (PADDING 0x20)
BYTE attr; ///< +11 File attribute BYTE attr; ///< +11 File attribute
BYTE add[10]; ///< +12 File name addition (PADDING 0x00) BYTE add[10]; ///< +12 File name addition (PADDING 0x00)
WORD time; ///< +22 Last change time of day uint16_t time; ///< +22 Last change time of day
WORD date; ///< +24 Last change date uint16_t date; ///< +24 Last change date
WORD cluster; ///< +26 Cluster number uint16_t cluster; ///< +26 Cluster number
DWORD size; ///< +28 File size uint32_t size; ///< +28 File size
}; };
/// IOCTRL parameter union /// IOCTRL parameter union
union ioctrl_t { union ioctrl_t {
BYTE buffer[8]; ///< Access in byte units BYTE buffer[8]; ///< Access in byte units
DWORD param; ///< Parameter (First 4 bytes) uint32_t param; ///< Parameter (First 4 bytes)
WORD media; ///< Media byte (First 2 bytes) uint16_t media; ///< Media byte (First 2 bytes)
}; };
/// Command line parameter struct /// 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. Reserving the other values for future use.
Insurance against hard-to-detect devices such as homemade USB storage. 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 SetEntryName(); ///< Set Human68k directory entry
void SetEntryAttribute(BYTE nHumanAttribute) void SetEntryAttribute(BYTE nHumanAttribute)
{ m_dirHuman.attr = nHumanAttribute; } ///< Set Human68k directory entry { 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 { 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 { 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 { 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 { m_dirHuman.cluster = nHumanCluster; } ///< Set Human68k directory entry
const Human68k::dirent_t* GetEntry() const const Human68k::dirent_t* GetEntry() const
{ return &m_dirHuman; } ///< Get Human68k directory entry { 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 bool isSameEntry(const Human68k::dirent_t* pdirHuman) const
{ assert(pdirHuman); return memcmp(&m_dirHuman, pdirHuman, sizeof(m_dirHuman)) == 0; } { assert(pdirHuman); return memcmp(&m_dirHuman, pdirHuman, sizeof(m_dirHuman)) == 0; }
///< Determine Human68k directory entry match ///< Determine Human68k directory entry match
@@ -491,8 +491,8 @@ class CHostPath: public CRing {
public: public:
/// Search buffer /// Search buffer
struct find_t { struct find_t {
DWORD count; ///< Search execution count + 1 (When 0 the below value is invalid) uint32_t 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 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) const ring_t* pos; ///< Position of the next search (When identical to unique ID)
Human68k::dirent_t entry; ///< Contents of the next seach entry 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 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 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 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 ///< 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) ///< Find file name (with support for wildcards)
bool isRefresh() const; ///< Check that the file change has been done bool isRefresh() const; ///< Check that the file change has been done
void Refresh(); ///< Refresh file void Refresh(); ///< Refresh file
@@ -533,11 +533,11 @@ private:
CRing m_cRing; ///< For CHostFilename linking CRing m_cRing; ///< For CHostFilename linking
time_t m_tBackup = 0; ///< For time stamp restoration time_t m_tBackup = 0; ///< For time stamp restoration
bool m_bRefresh = true; ///< Refresh flag 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 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 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 Init();
void SetKey(DWORD nKey) { m_nKey = nKey; } ///< Set search key void SetKey(uint32_t nKey) { m_nKey = nKey; } ///< Set search key
bool isSameKey(DWORD nKey) const { return m_nKey == nKey; } ///< Compare 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 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 bool isRootPath() const { return m_szHumanPath[1] == '\0'; } ///< Check if root directory
void SetPathWildcard() { m_nHumanWildcard = 1; } ///< Enable file search using wildcards void SetPathWildcard() { m_nHumanWildcard = 1; } ///< Enable file search using wildcards
void SetPathOnly() { m_nHumanWildcard = 0xFF; } ///< Enable only path names void SetPathOnly() { m_nHumanWildcard = 0xFF; } ///< Enable only path names
bool isPathOnly() const { return m_nHumanWildcard == 0xFF; } ///< Check if set to 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 void SetAttribute(uint32_t 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 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 const CHostFilename* Find(const CHostPath* pPath); ///< Find file name
void SetEntry(const CHostFilename* pFilename); ///< Store search results on the Human68k side void SetEntry(const CHostFilename* pFilename); ///< Store search results on the Human68k side
void SetResult(const TCHAR* szPath); ///< Set names on the host 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 const Human68k::dirent_t* GetEntry() const { return &m_dirHuman; }///< Get Human68k directory entry
DWORD GetAttribute() const { return m_dirHuman.attr; } ///< Get Human68k attribute uint32_t GetAttribute() const { return m_dirHuman.attr; } ///< Get Human68k attribute
WORD GetDate() const { return m_dirHuman.date; } ///< Get Human68k date uint16_t GetDate() const { return m_dirHuman.date; } ///< Get Human68k date
WORD GetTime() const { return m_dirHuman.time; } ///< Get Human68k time uint16_t GetTime() const { return m_dirHuman.time; } ///< Get Human68k time
DWORD GetSize() const { return m_dirHuman.size; } ///< Get Human68k file size 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* GetHumanFilename() const { return m_szHumanFilename; }///< Get Human68k file name
const BYTE* GetHumanResult() const { return m_szHumanResult; } ///< Get Human68k file name search results const BYTE* GetHumanResult() const { return m_szHumanResult; } ///< Get Human68k file name search results
const BYTE* GetHumanPath() const { return m_szHumanPath; } ///< Get Human68k path name const BYTE* GetHumanPath() const { return m_szHumanPath; } ///< Get Human68k path name
private: private:
DWORD m_nKey = 0; ///< FILES buffer address for Human68k; 0 is unused uint32_t m_nKey = 0; ///< FILES buffer address for Human68k; 0 is unused
DWORD m_nHumanWildcard = 0; ///< Human68k wildcard data uint32_t m_nHumanWildcard = 0; ///< Human68k wildcard data
DWORD m_nHumanAttribute = 0; ///< Human68k search attribute uint32_t m_nHumanAttribute = 0; ///< Human68k search attribute
CHostPath::find_t m_findNext = {}; ///< Next search location data CHostPath::find_t m_findNext = {}; ///< Next search location data
Human68k::dirent_t m_dirHuman = {}; ///< Search results: Human68k file data Human68k::dirent_t m_dirHuman = {}; ///< Search results: Human68k file data
BYTE m_szHumanFilename[24] = {}; ///< Human68k file name BYTE m_szHumanFilename[24] = {}; ///< Human68k file name
@@ -620,8 +620,8 @@ public:
void Init(); ///< Initialization (when the driver is installed) void Init(); ///< Initialization (when the driver is installed)
void Clean(); ///< Release (when starting up or resetting) void Clean(); ///< Release (when starting up or resetting)
CHostFiles* Alloc(DWORD nKey); CHostFiles* Alloc(uint32_t nKey);
CHostFiles* Search(DWORD nKey); CHostFiles* Search(uint32_t nKey);
void Free(CHostFiles* pFiles); void Free(CHostFiles* pFiles);
private: private:
/// For memory management /// For memory management
@@ -647,26 +647,26 @@ public:
void Init(); void Init();
void SetKey(DWORD nKey) { m_nKey = nKey; } ///< Set search key void SetKey(uint32_t nKey) { m_nKey = nKey; } ///< Set search key
bool isSameKey(DWORD nKey) const { return m_nKey == nKey; } ///< Compare search key bool isSameKey(uint32_t nKey) const { return m_nKey == nKey; } ///< Compare search key
void SetUpdate() { m_bUpdate = true; } ///< Update void SetUpdate() { m_bUpdate = true; } ///< Update
bool isUpdate() const { return m_bUpdate; } ///< Get update state 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 SetFilename(const TCHAR* szFilename); ///< Set file name
void SetHumanPath(const BYTE* szHumanPath); ///< Set Human68k path name void SetHumanPath(const BYTE* szHumanPath); ///< Set Human68k path name
const BYTE* GetHumanPath() const { return m_szHumanPath; } ///< Get 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 bool Open(); ///< Open file
DWORD Read(BYTE* pBuffer, DWORD nSize); ///< Read file uint32_t Read(BYTE* pBuffer, uint32_t nSize); ///< Read file
DWORD Write(const BYTE* pBuffer, DWORD nSize); ///< Write file uint32_t Write(const BYTE* pBuffer, uint32_t nSize); ///< Write file
bool Truncate() const; ///< Truncate file bool Truncate() const; ///< Truncate file
DWORD Seek(DWORD nOffset, Human68k::seek_t nHumanSeek); ///< Seek file uint32_t Seek(uint32_t nOffset, Human68k::seek_t nHumanSeek); ///< Seek file
bool TimeStamp(DWORD nHumanTime) const; ///< Set file time stamp bool TimeStamp(uint32_t nHumanTime) const; ///< Set file time stamp
void Close(); ///< Close file void Close(); ///< Close file
private: 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 bool m_bUpdate = false; ///< Update flag
FILE* m_pFile = nullptr; ///< Host side file object FILE* m_pFile = nullptr; ///< Host side file object
const char* m_pszMode = nullptr; ///< Host side file open mode const char* m_pszMode = nullptr; ///< Host side file open mode
@@ -688,8 +688,8 @@ public:
void Init(); ///< Initialization (when the driver is installed) void Init(); ///< Initialization (when the driver is installed)
void Clean() const; ///< Release (when starting up or resetting) void Clean() const; ///< Release (when starting up or resetting)
CHostFcb* Alloc(DWORD nKey); CHostFcb* Alloc(uint32_t nKey);
CHostFcb* Search(DWORD nKey); CHostFcb* Search(uint32_t nKey);
void Free(CHostFcb* p); void Free(CHostFcb* p);
private: private:
@@ -717,20 +717,20 @@ public:
CHostDrv(CHostDrv&) = default; CHostDrv(CHostDrv&) = default;
CHostDrv& operator=(const 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 isWriteProtect() const { return m_bWriteProtect; }
bool isEnable() const { return m_bEnable; } ///< Is it accessible? bool isEnable() const { return m_bEnable; } ///< Is it accessible?
bool isMediaOffline() const; bool isMediaOffline() const;
BYTE GetMediaByte() const; BYTE GetMediaByte() const;
DWORD GetStatus() const; uint32_t GetStatus() const;
void SetEnable(bool); ///< Set media status void SetEnable(bool); ///< Set media status
bool CheckMedia(); ///< Check if media was changed bool CheckMedia(); ///< Check if media was changed
void Update(); ///< Update media status void Update(); ///< Update media status
void Eject(); void Eject();
void GetVolume(TCHAR* szLabel); ///< Get volume label void GetVolume(TCHAR* szLabel); ///< Get volume label
bool GetVolumeCache(TCHAR* szLabel) const; ///< Get volume label from cache 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 bool GetCapacityCache(Human68k::capacity_t* pCapacity) const; ///< Get capacity from cache
// Cache operations // Cache operations
@@ -756,7 +756,7 @@ private:
bool m_bWriteProtect = false; ///< TRUE if write-protected bool m_bWriteProtect = false; ///< TRUE if write-protected
bool m_bEnable = false; ///< TRUE if media is usable 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 CRing m_cRing; ///< For attaching to CHostPath
Human68k::capacity_t m_capCache; ///< Sector data cache: if "sectors == 0" then not cached 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 bool m_bVolumeCache = false; ///< TRUE if the volume label has been read
@@ -786,31 +786,31 @@ public:
// Cache operations // Cache operations
void CleanCache() const; ///< Update all cache void CleanCache() const; ///< Update all cache
void CleanCache(DWORD nUnit) const; ///< Update cache for the specified unit void CleanCache(uint32_t nUnit) const; ///< Update cache for the specified unit
void CleanCache(DWORD nUnit, const BYTE* szHumanPath) const; ///< Update cache for the specified path void CleanCache(uint32_t 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 CleanCacheChild(uint32_t 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 void DeleteCache(uint32_t 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) bool Find(uint32_t 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 ShellNotify(uint32_t nEvent, const TCHAR* szPath); ///< Notify status change in the host side file system
// Drive object operations // Drive object operations
void SetDrv(DWORD nUnit, CHostDrv* pDrv); void SetDrv(uint32_t nUnit, CHostDrv* pDrv);
bool isWriteProtect(DWORD nUnit) const; bool isWriteProtect(uint32_t nUnit) const;
bool isEnable(DWORD nUnit) const; ///< Is it accessible? bool isEnable(uint32_t nUnit) const; ///< Is it accessible?
bool isMediaOffline(DWORD nUnit) const; bool isMediaOffline(uint32_t nUnit) const;
BYTE GetMediaByte(DWORD nUnit) const; BYTE GetMediaByte(uint32_t nUnit) const;
DWORD GetStatus(DWORD nUnit) const; ///< Get drive status uint32_t GetStatus(uint32_t nUnit) const; ///< Get drive status
bool CheckMedia(DWORD nUnit) const; ///< Media change check bool CheckMedia(uint32_t nUnit) const; ///< Media change check
void Eject(DWORD nUnit) const; void Eject(uint32_t nUnit) const;
void GetVolume(DWORD nUnit, TCHAR* szLabel) const; ///< Get volume label void GetVolume(uint32_t nUnit, TCHAR* szLabel) const; ///< Get volume label
bool GetVolumeCache(DWORD nUnit, TCHAR* szLabel) const; ///< Get volume label from cache bool GetVolumeCache(uint32_t nUnit, TCHAR* szLabel) const; ///< Get volume label from cache
DWORD GetCapacity(DWORD nUnit, Human68k::capacity_t* pCapacity) const; uint32_t GetCapacity(uint32_t nUnit, Human68k::capacity_t* pCapacity) const;
bool GetCapacityCache(DWORD nUnit, Human68k::capacity_t* pCapacity) const; ///< Get cluster size from cache bool GetCapacityCache(uint32_t nUnit, Human68k::capacity_t* pCapacity) const; ///< Get cluster size from cache
private: private:
CHostDrv* m_pDrv[DRIVE_MAX] = {}; ///< Host side drive object 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) void Init(); ///< Initialization (device startup and load)
// Command handlers // Command handlers
DWORD InitDevice(const Human68k::argument_t* pArgument); ///< $40 - Device startup uint32_t InitDevice(const Human68k::argument_t* pArgument); ///< $40 - Device startup
int CheckDir(DWORD nUnit, const Human68k::namests_t* pNamests) const; ///< $41 - Directory check int CheckDir(uint32_t nUnit, const Human68k::namests_t* pNamests) const; ///< $41 - Directory check
int MakeDir(DWORD nUnit, const Human68k::namests_t* pNamests) const; ///< $42 - Create directory int MakeDir(uint32_t nUnit, const Human68k::namests_t* pNamests) const; ///< $42 - Create directory
int RemoveDir(DWORD nUnit, const Human68k::namests_t* pNamests) const; ///< $43 - Delete directory int RemoveDir(uint32_t 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; int Rename(uint32_t nUnit, const Human68k::namests_t* pNamests, const Human68k::namests_t* pNamestsNew) const;
///< $44 - Change file name ///< $44 - Change file name
int Delete(DWORD nUnit, const Human68k::namests_t* pNamests) const; ///< $45 - Delete file int Delete(uint32_t nUnit, const Human68k::namests_t* pNamests) const; ///< $45 - Delete file
int Attribute(DWORD nUnit, const Human68k::namests_t* pNamests, DWORD nHumanAttribute) const; int Attribute(uint32_t nUnit, const Human68k::namests_t* pNamests, uint32_t nHumanAttribute) const;
///< $46 - Get / set file attribute ///< $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 ///< $47 - Find file
int NFiles(DWORD nUnit, DWORD nKey, Human68k::files_t* pFiles); ///< $48 - Find next file int NFiles(uint32_t nUnit, uint32_t 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 Create(uint32_t nUnit, uint32_t nKey, const Human68k::namests_t* pNamests, Human68k::fcb_t* pFcb, uint32_t nHumanAttribute, bool bForce);
///< $49 - Create file ///< $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 ///< $4A - Open file
int Close(DWORD nUnit, DWORD nKey, const Human68k::fcb_t* pFcb); ///< $4B - Close file int Close(uint32_t nUnit, uint32_t nKey, const Human68k::fcb_t* pFcb); ///< $4B - Close file
int Read(DWORD nKey, Human68k::fcb_t* pFcb, BYTE* pAddress, DWORD nSize); int Read(uint32_t nKey, Human68k::fcb_t* pFcb, BYTE* pAddress, uint32_t nSize);
///< $4C - Read file ///< $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 ///< $4D - Write file
int Seek(DWORD nKey, Human68k::fcb_t* pFcb, DWORD nSeek, int nOffset); ///< $4E - Seek file int Seek(uint32_t nKey, Human68k::fcb_t* pFcb, uint32_t nSeek, int nOffset); ///< $4E - Seek file
DWORD TimeStamp(DWORD nUnit, DWORD nKey, Human68k::fcb_t* pFcb, DWORD nHumanTime); uint32_t TimeStamp(uint32_t nUnit, uint32_t nKey, Human68k::fcb_t* pFcb, uint32_t nHumanTime);
///< $4F - Get / set file timestamp ///< $4F - Get / set file timestamp
int GetCapacity(DWORD nUnit, Human68k::capacity_t* pCapacity) const; ///< $50 - Get capacity int GetCapacity(uint32_t nUnit, Human68k::capacity_t* pCapacity) const; ///< $50 - Get capacity
int CtrlDrive(DWORD nUnit, Human68k::ctrldrive_t* pCtrlDrive) const; ///< $51 - Inspect / control drive status int CtrlDrive(uint32_t nUnit, Human68k::ctrldrive_t* pCtrlDrive) const; ///< $51 - Inspect / control drive status
int GetDPB(DWORD nUnit, Human68k::dpb_t* pDpb) const; ///< $52 - Get DPB int GetDPB(uint32_t nUnit, Human68k::dpb_t* pDpb) const; ///< $52 - Get DPB
int DiskRead(DWORD nUnit, BYTE* pBuffer, DWORD nSector, DWORD nSize); ///< $53 - Read sectors int DiskRead(uint32_t nUnit, BYTE* pBuffer, uint32_t nSector, uint32_t nSize); ///< $53 - Read sectors
int DiskWrite(DWORD nUnit) const; ///< $54 - Write sectors int DiskWrite(uint32_t nUnit) const; ///< $54 - Write sectors
int Ioctrl(DWORD nUnit, DWORD nFunction, Human68k::ioctrl_t* pIoctrl); ///< $55 - IOCTRL int Ioctrl(uint32_t nUnit, uint32_t nFunction, Human68k::ioctrl_t* pIoctrl); ///< $55 - IOCTRL
int Flush(DWORD nUnit) const; ///< $56 - Flush int Flush(uint32_t nUnit) const; ///< $56 - Flush
int CheckMedia(DWORD nUnit) const; ///< $57 - Media change check int CheckMedia(uint32_t nUnit) const; ///< $57 - Media change check
int Lock(DWORD nUnit) const; ///< $58 - Lock int Lock(uint32_t nUnit) const; ///< $58 - Lock
void SetOption(DWORD nOption); ///< Set option void SetOption(uint32_t nOption); ///< Set option
DWORD GetOption() const { return m_nOption; } ///< Get option uint32_t GetOption() const { return m_nOption; } ///< Get option
DWORD GetDefault() const { return m_nOptionDefault; } ///< Get default options uint32_t GetDefault() const { return m_nOptionDefault; } ///< Get default options
static DWORD GetFileOption() { return g_nOption; } ///< Get file name change option static uint32_t GetFileOption() { return g_nOption; } ///< Get file name change option
static const int DriveMax = CHostEntry::DRIVE_MAX; ///< Max number of drive candidates static const int DriveMax = CHostEntry::DRIVE_MAX; ///< Max number of drive candidates
private: private:
void InitOption(const Human68k::argument_t* pArgument); 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 uint32_t m_nOption = 0; ///< Current runtime flag
DWORD m_nOptionDefault = 0; ///< Runtime flag at reset 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 uint32_t m_nKernel = 0; ///< Counter for kernel check
DWORD m_nKernelSearch = 0; ///< Initial address for NUL device 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 CHostFilesManager m_cFiles; ///< File search memory
CHostFcbManager m_cFcb; ///< FCB operation memory CHostFcbManager m_cFcb; ///< FCB operation memory
CHostEntry m_cEntry; ///< Drive object and directory entry 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 ///< 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 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) 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) { if (ip_fd < 0) {
LOGERROR("Can't open ip socket: %s", strerror(errno)) 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; 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) { if (br_socket_fd < 0) {
LOGERROR("Can't open bridge socket: %s", strerror(errno)) 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 // 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) + '.' + netmask = to_string((mask >> 24) & 0xff) + '.' + to_string((mask >> 16) & 0xff) + '.' +
to_string((mask >> 8) & 0xff) + '.' + to_string(mask & 0xff); to_string((mask >> 8) & 0xff) + '.' + to_string(mask & 0xff);
@@ -391,18 +391,18 @@ void CTapDriver::OpenDump(const Filepath& path) {
bool CTapDriver::Enable() const 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__) 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); close(fd);
return result; return result;
} }
bool CTapDriver::Disable() const 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__) 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); close(fd);
return result; return result;
} }
@@ -452,7 +452,7 @@ uint32_t CTapDriver::Crc32(const BYTE *buf, int length) {
for (int i = 0; i < length; i++) { for (int i = 0; i < length; i++) {
crc ^= buf[i]; crc ^= buf[i];
for (int j = 0; j < 8; j++) { 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); crc = (crc >> 1) ^ (0xEDB88320 & mask);
} }
} }
@@ -469,8 +469,8 @@ int CTapDriver::Receive(BYTE *buf)
} }
// Receive // Receive
auto dwReceived = (DWORD)read(m_hTAP, buf, ETH_FRAME_LEN); auto dwReceived = (uint32_t)read(m_hTAP, buf, ETH_FRAME_LEN);
if (dwReceived == (DWORD)-1) { if (dwReceived == (uint32_t)-1) {
LOGWARN("%s Error occured while receiving a packet", __PRETTY_FUNCTION__) LOGWARN("%s Error occured while receiving a packet", __PRETTY_FUNCTION__)
return 0; 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. // 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 // The Linux network subsystem removes it, since most software apps shouldn't ever
// need it. // need it.
int crc = Crc32(buf, dwReceived); const int crc = Crc32(buf, dwReceived);
buf[dwReceived + 0] = (BYTE)((crc >> 0) & 0xFF); buf[dwReceived + 0] = (BYTE)((crc >> 0) & 0xFF);
buf[dwReceived + 1] = (BYTE)((crc >> 8) & 0xFF); buf[dwReceived + 1] = (BYTE)((crc >> 8) & 0xFF);

View File

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

View File

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

View File

@@ -56,12 +56,17 @@ DeviceFactory::DeviceFactory()
extension_mapping["hdr"] = SCRM; extension_mapping["hdr"] = SCRM;
extension_mapping["mos"] = SCMO; extension_mapping["mos"] = SCMO;
extension_mapping["iso"] = SCCD; 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 DeviceFactory::GetExtension(const string& filename) const
{ {
string ext; 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); ext = filename.substr(separator + 1);
} }
std::transform(ext.begin(), ext.end(), ext.begin(), [](unsigned char c){ return std::tolower(c); }); 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()) { if (const auto& it = extension_mapping.find(GetExtension(filename)); it != extension_mapping.end()) {
return it->second; return it->second;
} }
else if (filename == "bridge") {
return SCBR; if (const auto& it = device_mapping.find(filename); it != device_mapping.end()) {
} return it->second;
else if (filename == "daynaport") {
return SCDP;
}
else if (filename == "printer") {
return SCLP;
}
else if (filename == "services") {
return SCHS;
} }
return UNDEFINED; return UNDEFINED;
@@ -105,7 +102,7 @@ shared_ptr<PrimaryDevice> DeviceFactory::CreateDevice(const ControllerManager& c
shared_ptr<PrimaryDevice> device; shared_ptr<PrimaryDevice> device;
switch (type) { switch (type) {
case SCHD: { 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); device = make_shared<SCSIHD_NEC>(lun);
} else { } else {
device = make_shared<SCSIHD>(lun, sector_sizes[SCHD], false, device = make_shared<SCSIHD>(lun, sector_sizes[SCHD], false,
@@ -220,10 +217,10 @@ list<string> DeviceFactory::GetNetworkInterfaces() const
while (tmp) { while (tmp) {
if (tmp->ifa_addr && tmp->ifa_addr->sa_family == AF_PACKET && if (tmp->ifa_addr && tmp->ifa_addr->sa_family == AF_PACKET &&
strcmp(tmp->ifa_name, "lo") && strcmp(tmp->ifa_name, "rascsi_bridge")) { 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 = {}; 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 // Only list interfaces that are up
if (!ioctl(fd, SIOCGIFFLAGS, &ifr) && (ifr.ifr_flags & IFF_UP)) { if (!ioctl(fd, SIOCGIFFLAGS, &ifr) && (ifr.ifr_flags & IFF_UP)) {
network_interfaces.emplace_back(tmp->ifa_name); 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_set<uint32_t>& GetSectorSizes(const string&) const;
const unordered_map<string, string>& GetDefaultParams(PbDeviceType type) const; const unordered_map<string, string>& GetDefaultParams(PbDeviceType type) const;
list<string> GetNetworkInterfaces() 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: private:
@@ -50,6 +50,8 @@ private:
unordered_map<string, PbDeviceType> extension_mapping; unordered_map<string, PbDeviceType> extension_mapping;
unordered_map<string, PbDeviceType> device_mapping;
unordered_set<uint32_t> empty_set; unordered_set<uint32_t> empty_set;
unordered_map<string, string> empty_map; unordered_map<string, string> empty_map;
}; };

View File

@@ -14,9 +14,7 @@
// //
//--------------------------------------------------------------------------- //---------------------------------------------------------------------------
#include "os.h"
#include "fileio.h" #include "fileio.h"
#include "file_support.h"
#include "rascsi_exceptions.h" #include "rascsi_exceptions.h"
#include "dispatcher.h" #include "dispatcher.h"
#include "scsi_command_util.h" #include "scsi_command_util.h"
@@ -25,6 +23,8 @@
using namespace scsi_defs; using namespace scsi_defs;
using namespace scsi_command_util; using namespace scsi_command_util;
unordered_map<string, id_set> Disk::reserved_files;
Disk::Disk(const string& type, int lun) : ModePageDevice(type, lun) Disk::Disk(const string& type, int lun) : ModePageDevice(type, lun)
{ {
dispatcher.Add(scsi_command::eCmdRezero, "Rezero", &Disk::Rezero); dispatcher.Add(scsi_command::eCmdRezero, "Rezero", &Disk::Rezero);
@@ -73,7 +73,7 @@ bool Disk::Dispatch(scsi_command cmd)
is_medium_changed = false; 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 // 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) // FMTDATA=1 is not supported (but OK if there is no DEFECT LIST)
if ((ctrl->cmd[1] & 0x10) != 0 && ctrl->cmd[4] != 0) { 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(); EnterStatusPhase();
@@ -187,7 +187,7 @@ void Disk::ReadWriteLong10()
{ {
// Transfer lengths other than 0 are not supported, which is compliant with the SCSI standard // Transfer lengths other than 0 are not supported, which is compliant with the SCSI standard
if (GetInt16(ctrl->cmd, 7) != 0) { 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); ValidateBlockAddress(RW10);
@@ -199,7 +199,7 @@ void Disk::ReadWriteLong16()
{ {
// Transfer lengths other than 0 are not supported, which is compliant with the SCSI standard // Transfer lengths other than 0 are not supported, which is compliant with the SCSI standard
if (GetInt16(ctrl->cmd, 12) != 0) { 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); ValidateBlockAddress(RW16);
@@ -271,8 +271,8 @@ void Disk::Verify16()
void Disk::StartStopUnit() void Disk::StartStopUnit()
{ {
bool start = ctrl->cmd[4] & 0x01; const bool start = ctrl->cmd[4] & 0x01;
bool load = ctrl->cmd[4] & 0x02; const bool load = ctrl->cmd[4] & 0x02;
if (load) { if (load) {
LOGTRACE(start ? "Loading medium" : "Ejecting medium") LOGTRACE(start ? "Loading medium" : "Ejecting medium")
@@ -290,12 +290,12 @@ void Disk::StartStopUnit()
if (load) { if (load) {
if (IsLocked()) { if (IsLocked()) {
// Cannot be ejected because it is locked // 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 // Eject
if (!Eject(false)) { if (!Eject(false)) {
throw scsi_error_exception(); throw scsi_exception();
} }
} }
} }
@@ -307,12 +307,12 @@ void Disk::SendDiagnostic()
{ {
// Do not support PF bit // Do not support PF bit
if (ctrl->cmd[1] & 0x10) { 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 // Do not support parameter list
if ((ctrl->cmd[3] != 0) || (ctrl->cmd[4] != 0)) { 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(); EnterStatusPhase();
@@ -322,7 +322,7 @@ void Disk::PreventAllowMediumRemoval()
{ {
CheckReady(); CheckReady();
bool lock = ctrl->cmd[4] & 0x01; const bool lock = ctrl->cmd[4] & 0x01;
LOGTRACE(lock ? "Locking medium" : "Unlocking medium") LOGTRACE(lock ? "Locking medium" : "Unlocking medium")
@@ -340,7 +340,7 @@ void Disk::SynchronizeCache()
void Disk::ReadDefectData10() 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 // The defect list is empty
fill_n(controller->GetBuffer().begin(), allocation_length, 0); fill_n(controller->GetBuffer().begin(), allocation_length, 0);
@@ -361,15 +361,13 @@ void Disk::MediumChanged()
bool Disk::Eject(bool force) bool Disk::Eject(bool force)
{ {
bool status = super::Eject(force); const bool status = super::Eject(force);
if (status) { if (status) {
FlushCache(); FlushCache();
cache.reset(); cache.reset();
// The image file for this drive is not in use anymore // The image file for this drive is not in use anymore
if (auto file_support = dynamic_cast<FileSupport *>(this); file_support) { UnreserveFile();
file_support->UnreserveFile();
}
} }
return status; return status;
@@ -378,7 +376,7 @@ bool Disk::Eject(bool force)
int Disk::ModeSense6(const vector<int>& cdb, vector<BYTE>& buf) const int Disk::ModeSense6(const vector<int>& cdb, vector<BYTE>& buf) const
{ {
// Get length, clear buffer // 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); fill_n(buf.begin(), length, 0);
// DEVICE SPECIFIC PARAMETER // 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); size += super::AddModePages(cdb, buf, size, length - size);
if (size > 255) { 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 // 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 int Disk::ModeSense10(const vector<int>& cdb, vector<BYTE>& buf) const
{ {
// Get length, clear buffer // 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); fill_n(buf.begin(), length, 0);
// DEVICE SPECIFIC PARAMETER // 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); size += super::AddModePages(cdb, buf, size, length - size);
if (size > 65535) { 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 // 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 // Error if the total number of blocks is exceeded
if (block >= blocks) { 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 // leave it to the cache
if (!cache->ReadSector(buf, (uint32_t)block)) { 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 // Success
@@ -641,12 +639,12 @@ int Disk::WriteCheck(uint64_t block)
// Error if the total number of blocks is exceeded // Error if the total number of blocks is exceeded
if (block >= blocks) { 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 // Error if write protected
if (IsProtected()) { if (IsProtected()) {
throw scsi_error_exception(sense_key::DATA_PROTECT, asc::WRITE_PROTECTED); throw scsi_exception(sense_key::DATA_PROTECT, asc::WRITE_PROTECTED);
} }
// Success // Success
@@ -660,22 +658,22 @@ void Disk::Write(const vector<int>&, const vector<BYTE>& buf, uint64_t block)
// Error if not ready // Error if not ready
if (!IsReady()) { 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 // Error if the total number of blocks is exceeded
if (block >= blocks) { 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 // Error if write protected
if (IsProtected()) { 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 // Leave it to the cache
if (!cache->WriteSector(buf, (uint32_t)block)) { 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(); CheckReady();
if (blocks == 0) { 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(); vector<BYTE>& buf = controller->GetBuffer();
@@ -737,7 +735,7 @@ void Disk::ReadCapacity16()
CheckReady(); CheckReady();
if (blocks == 0) { 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(); vector<BYTE>& buf = controller->GetBuffer();
@@ -772,7 +770,7 @@ void Disk::ReadCapacity16_ReadLong16()
break; break;
default: 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; break;
} }
} }
@@ -805,14 +803,12 @@ void Disk::Release()
void Disk::ValidateBlockAddress(access_mode mode) const 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 > blocks) {
LOGTRACE("%s", ("Capacity of " + to_string(blocks) + " block(s) exceeded: Trying to access block "
if (block > capacity) {
LOGTRACE("%s", ("Capacity of " + to_string(capacity) + " block(s) exceeded: Trying to access block "
+ to_string(block)).c_str()) + 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) { if (uint64_t capacity = blocks; start > capacity || start + count > capacity) {
LOGTRACE("%s", ("Capacity of " + to_string(capacity) + " block(s) exceeded: Trying to access block " LOGTRACE("%s", ("Capacity of " + to_string(capacity) + " block(s) exceeded: Trying to access block "
+ to_string(start) + ", block count " + to_string(count)).c_str()) + 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 // Do not process 0 blocks
@@ -909,3 +905,43 @@ bool Disk::SetConfiguredSectorSize(const DeviceFactory& device_factory, uint32_t
return true; 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 <string>
#include <unordered_set> #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 }; enum access_mode { RW6, RW10, RW16, SEEK6, SEEK10 };
@@ -45,6 +49,11 @@ class Disk : public ModePageDevice, public ScsiBlockCommands
bool is_medium_changed = false; 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: public:
Disk(const string&, int); Disk(const string&, int);
@@ -67,6 +76,18 @@ public:
uint64_t GetBlockCount() const { return blocks; } uint64_t GetBlockCount() const { return blocks; }
void FlushCache() override; 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: private:
using super = ModePageDevice; using super = ModePageDevice;
@@ -110,7 +131,6 @@ private:
protected: protected:
virtual void Open(const Filepath&);
void SetUpCache(const Filepath&, off_t, bool = false); void SetUpCache(const Filepath&, off_t, bool = false);
void ResizeCache(const Filepath&, bool); void ResizeCache(const Filepath&, bool);
@@ -127,4 +147,5 @@ protected:
void SetSectorSizeShiftCount(uint32_t count) { size_shift_count = count; } void SetSectorSizeShiftCount(uint32_t count) { size_shift_count = count; }
uint32_t GetConfiguredSectorSize() const; uint32_t GetConfiguredSectorSize() const;
void SetBlockCount(uint64_t b) { blocks = b; } 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_track.h"
#include "disk_cache.h" #include "disk_cache.h"
#include <cstdlib>
#include <cassert>
DiskCache::DiskCache(const Filepath& path, int size, uint32_t blocks, off_t imgoff) DiskCache::DiskCache(const Filepath& path, int size, uint32_t blocks, off_t imgoff)
: sec_size(size), sec_blocks(blocks), imgoffset(imgoff) : sec_size(size), sec_blocks(blocks), imgoffset(imgoff)

View File

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

View File

@@ -16,6 +16,7 @@
#pragma once #pragma once
#include "filepath.h" #include "filepath.h"
#include <cstdlib>
#include <vector> #include <vector>
using namespace std; using namespace std;
@@ -26,7 +27,7 @@ class DiskTrack
int track; // Track Number int track; // Track Number
int size; // Sector Size (8=256, 9=512, 10=1024, 11=2048, 12=4096) int size; // Sector Size (8=256, 9=512, 10=1024, 11=2048, 12=4096)
int sectors; // Number of sectors(<0x100) int sectors; // Number of sectors(<0x100)
DWORD length; // Data buffer length uint32_t length; // Data buffer length
BYTE *buffer; // Data buffer BYTE *buffer; // Data buffer
bool init; // Is it initilized? bool init; // Is it initilized?
bool changed; // Changed flag 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() void HostServices::StartStopUnit()
{ {
bool start = ctrl->cmd[4] & 0x01; const bool start = ctrl->cmd[4] & 0x01;
bool load = ctrl->cmd[4] & 0x02; const bool load = ctrl->cmd[4] & 0x02;
if (!start) { if (!start) {
// Flush any caches // Flush any caches
@@ -77,7 +77,7 @@ void HostServices::StartStopUnit()
controller->ScheduleShutdown(AbstractController::rascsi_shutdown_mode::RESTART_PI); controller->ScheduleShutdown(AbstractController::rascsi_shutdown_mode::RESTART_PI);
} }
else { 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(); EnterStatusPhase();
@@ -87,10 +87,10 @@ int HostServices::ModeSense6(const vector<int>& cdb, vector<BYTE>& buf) const
{ {
// Block descriptors cannot be returned // Block descriptors cannot be returned
if (!(cdb[1] & 0x08)) { 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); fill_n(buf.begin(), length, 0);
// Basic Information // 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); size += super::AddModePages(cdb, buf, size, length - size);
if (size > 255) { 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 // 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 // Block descriptors cannot be returned
if (!(cdb[1] & 0x08)) { 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); fill_n(buf.begin(), length, 0);
// Basic Information // 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); size += super::AddModePages(cdb, buf, size, length - size);
if (size > 65535) { 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 // Do not return more than ALLOCATION LENGTH bytes

View File

@@ -29,7 +29,6 @@ public:
vector<byte> InquiryInternal() const override; vector<byte> InquiryInternal() const override;
void TestUnitReady() override; void TestUnitReady() override;
void StartStopUnit();
bool SupportsFile() const override { return false; } bool SupportsFile() const override { return false; }
@@ -58,6 +57,7 @@ private:
const ControllerManager& controller_manager; const ControllerManager& controller_manager;
void StartStopUnit();
int ModeSense6(const vector<int>&, vector<BYTE>&) const override; int ModeSense6(const vector<int>&, vector<BYTE>&) const override;
int ModeSense10(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; return 0;
} }
bool changeable = (cdb[2] & 0xc0) == 0x40; const bool changeable = (cdb[2] & 0xc0) == 0x40;
// Get page code (0x3f means all pages) // 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) 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()) { if (pages.empty()) {
LOGTRACE("%s Unsupported mode page $%02X", __PRETTY_FUNCTION__, page) 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 // 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) { for (auto const& [index, data] : pages) {
// The specification mandates that page 0 must be returned after all others // The specification mandates that page 0 must be returned after all others
if (index) { if (index) {
size_t off = result.size(); const size_t off = result.size();
// Page data // Page data
result.insert(result.end(), data.begin(), data.end()); 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 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() 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 // 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 // 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)) { 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; return length;

View File

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

View File

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

View File

@@ -20,7 +20,7 @@ void scsi_command_util::ModeSelect(const vector<int>& cdb, const vector<BYTE>& b
// PF // PF
if (!(cdb[1] & 0x10)) { if (!(cdb[1] & 0x10)) {
// Vendor-specific parameters (SCSI-1) are not supported // 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; 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) { buf[11] != (BYTE)sector_size) {
// See below for details // See below for details
LOGWARN("In order to change the sector size use the -b option when launching rascsi") 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; 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, // With rascsi it is not possible to permanently (by formatting) change the sector size,
// because the size is an externally configurable setting only // because the size is an externally configurable setting only
LOGWARN("In order to change the sector size use the -b option when launching rascsi") 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; 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) { 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: // following link:
// - https://github.com/akuker/RASCSI/wiki/Dayna-Port-SCSI-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. // 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 SCSIDaynaPort::Read(const vector<int>& cdb, vector<BYTE>& buf, uint64_t)
{ {
int rx_packet_size = 0; 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) 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 // 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 // respond by going into the status mode with a code of 0x02
if (requested_length == 1) { 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 // If there are pending packets to be processed, we'll tell the host that the read
// length was 0. // length was 0.
if (!m_tap.PendingPackets()) if (!m_tap.PendingPackets()) {
{
response->length = 0; response->length = 0;
response->flags = read_data_flags_t::e_no_more_data; response->flags = read_data_flags_t::e_no_more_data;
return DAYNAPORT_READ_HEADER_SZ; return DAYNAPORT_READ_HEADER_SZ;
@@ -252,8 +247,8 @@ int SCSIDaynaPort::WriteCheck(uint64_t)
{ {
CheckReady(); CheckReady();
if (!m_bTapEnable){ if (!m_bTapEnable) {
throw scsi_error_exception(sense_key::UNIT_ATTENTION, asc::MEDIUM_NOT_PRESENT); throw scsi_exception(sense_key::UNIT_ATTENTION, asc::MEDIUM_NOT_PRESENT);
} }
return 1; return 1;
@@ -279,22 +274,20 @@ int SCSIDaynaPort::WriteCheck(uint64_t)
//--------------------------------------------------------------------------- //---------------------------------------------------------------------------
bool SCSIDaynaPort::WriteBytes(const vector<int>& cdb, const vector<BYTE>& buf, 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); int data_length = GetInt16(cdb, 3);
if (data_format == 0x00){ if (data_format == 0x00) {
m_tap.Send(buf.data(), data_length); m_tap.Send(buf.data(), data_length);
LOGTRACE("%s Transmitted %u bytes (00 format)", __PRETTY_FUNCTION__, 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 // 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); m_tap.Send(&(buf.data()[4]), data_length);
LOGTRACE("%s Transmitted %u bytes (80 format)", __PRETTY_FUNCTION__, data_length) LOGTRACE("%s Transmitted %u bytes (80 format)", __PRETTY_FUNCTION__, data_length)
} }
else else {
{
// LOGWARN("%s Unknown data format %02X", __PRETTY_FUNCTION__, (unsigned int)command->format)
LOGWARN("%s Unknown data format %02X", __PRETTY_FUNCTION__, data_format) 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)); 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)); return (int)min(sizeof(m_scsi_link_stats), (size_t)GetInt16(cdb, 3));
}
//---------------------------------------------------------------------------
//
// 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;
} }
void SCSIDaynaPort::TestUnitReady() void SCSIDaynaPort::TestUnitReady()
@@ -371,14 +326,14 @@ void SCSIDaynaPort::TestUnitReady()
void SCSIDaynaPort::Read6() void SCSIDaynaPort::Read6()
{ {
// Get record number and block number // 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; ctrl->blocks=1;
// If any commands have a bogus control value, they were probably not // If any commands have a bogus control value, they were probably not
// generated by the DaynaPort driver so ignore them // generated by the DaynaPort driver so ignore them
if (ctrl->cmd[5] != 0xc0 && ctrl->cmd[5] != 0x80) { 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]) 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) 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) // Ensure a sufficient buffer size (because it is not transfer for each block)
controller->AllocateBuffer(DAYNAPORT_BUFFER_SIZE); controller->AllocateBuffer(DAYNAPORT_BUFFER_SIZE);
int data_format = ctrl->cmd[5]; const int data_format = ctrl->cmd[5];
if (data_format == 0x00) { if (data_format == 0x00) {
ctrl->length = GetInt16(ctrl->cmd, 3); 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) LOGTRACE("%s length: $%04X (%d) format: $%02X", __PRETTY_FUNCTION__, ctrl->length, ctrl->length, data_format)
if (ctrl->length <= 0) { if (ctrl->length <= 0) {
throw scsi_error_exception(); throw scsi_exception();
} }
// Set next block // Set next block
@@ -478,10 +433,12 @@ void SCSIDaynaPort::SetInterfaceMode()
case CMD_SCSILINK_ENABLE: case CMD_SCSILINK_ENABLE:
case CMD_SCSILINK_SET: case CMD_SCSILINK_SET:
LOGWARN("%s Unsupported SetInterface command received: %02X", __PRETTY_FUNCTION__, ctrl->cmd[5]) LOGWARN("%s Unsupported SetInterface command received: %02X", __PRETTY_FUNCTION__, ctrl->cmd[5])
throw scsi_exception();
break; break;
default: default:
LOGWARN("%s Unknown SetInterface command received: %02X", __PRETTY_FUNCTION__, ctrl->cmd[5]) LOGWARN("%s Unknown SetInterface command received: %02X", __PRETTY_FUNCTION__, ctrl->cmd[5])
throw scsi_exception();
break; break;
} }
} }
@@ -492,16 +449,45 @@ void SCSIDaynaPort::SetMcastAddr()
if (ctrl->length == 0) { if (ctrl->length == 0) {
LOGWARN("%s Not supported SetMcastAddr Command %02X", __PRETTY_FUNCTION__, ctrl->cmd[2]) LOGWARN("%s Not supported SetMcastAddr Command %02X", __PRETTY_FUNCTION__, ctrl->cmd[2])
throw scsi_error_exception(); throw scsi_exception();
} }
EnterDataOutPhase(); 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() void SCSIDaynaPort::EnableInterface()
{ {
if (!EnableInterface(ctrl->cmd)) { if (ctrl->cmd[5] & 0x80) {
throw scsi_error_exception(); 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(); EnterStatusPhase();

View File

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

View File

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

View File

@@ -26,7 +26,7 @@
using namespace std; 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 }; 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 void FS_Lock(vector<BYTE>&); // $58 - get exclusive control
CFileSys fs; // File system accessor 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 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 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(); 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) 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()) + LOGERROR("%s", ("Transfer buffer overflow: Buffer size is " + to_string(controller->GetBuffer().size()) +
" bytes, " + to_string(length) + " bytes expected").c_str()) " 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; ctrl->length = length;
@@ -167,11 +167,11 @@ void SCSIPrinter::SynchronizeBuffer()
CheckReservation(); CheckReservation();
if (fd == -1) { if (fd == -1) {
throw scsi_error_exception(); throw scsi_exception();
} }
// Make the file readable for the lp user // 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; struct stat st;
fstat(fd, &st); fstat(fd, &st);
@@ -180,7 +180,7 @@ void SCSIPrinter::SynchronizeBuffer()
fd = -1; fd = -1;
string cmd = GetParam("cmd"); string cmd = GetParam("cmd");
size_t file_position = cmd.find("%f"); const size_t file_position = cmd.find("%f");
assert(file_position != string::npos); assert(file_position != string::npos);
cmd.replace(file_position, 2, filename); cmd.replace(file_position, 2, filename);
cmd = "sudo -u lp " + cmd; cmd = "sudo -u lp " + cmd;
@@ -194,7 +194,7 @@ void SCSIPrinter::SynchronizeBuffer()
unlink(filename); unlink(filename);
throw scsi_error_exception(); throw scsi_exception();
} }
unlink(filename); unlink(filename);
@@ -217,7 +217,7 @@ void SCSIPrinter::StopPrint()
bool SCSIPrinter::WriteByteSequence(vector<BYTE>& buf, uint32_t length) bool SCSIPrinter::WriteByteSequence(vector<BYTE>& buf, uint32_t length)
{ {
if (fd == -1) { if (fd == -1) {
strcpy(filename, TMP_FILE_PATTERN); strcpy(filename, TMP_FILE_PATTERN); //NOSONAR Using strcpy is safe here
fd = mkstemp(filename); fd = mkstemp(filename);
if (fd == -1) { if (fd == -1) {
LOGERROR("Can't create printer output file '%s': %s", filename, strerror(errno)) 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) 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; 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()) 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); status::RESERVATION_CONFLICT);
} }

View File

@@ -15,9 +15,9 @@
#include <string> #include <string>
#include <unordered_map> #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 TMP_FILENAME_LENGTH = string_view(TMP_FILE_PATTERN).size();
static const int NOT_RESERVED = -2; static const int NOT_RESERVED = -2;

View File

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

View File

@@ -10,20 +10,16 @@
// Licensed under the BSD 3-Clause License. // Licensed under the BSD 3-Clause License.
// See LICENSE file in the project root folder. // See LICENSE file in the project root folder.
// //
// [ SCSI CD-ROM ]
//
//--------------------------------------------------------------------------- //---------------------------------------------------------------------------
#pragma once #pragma once
#include "disk.h"
#include "filepath.h" #include "filepath.h"
#include "cd_track.h" #include "cd_track.h"
#include "file_support.h" #include "disk.h"
#include "interfaces/scsi_mmc_commands.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: public:
@@ -68,7 +64,7 @@ private:
// Track management // Track management
void ClearTrack(); // Clear the track 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 vector<unique_ptr<CDTrack>> tracks; // Track opbject references
int dataindex = -1; // Current data track int dataindex = -1; // Current data track
int audioindex = -1; // Current audio 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(); uint64_t capacity = GetBlockCount() * GetSectorSizeInBytes();
string unit; string unit;
// 10 GiB and more // 10 GiB and more
if (capacity >= 1099511627776) { if (capacity >= 1'099'511'627'776) {
capacity /= 1099511627776; capacity /= 1'099'511'627'776;
unit = "GiB"; unit = "GiB";
} }
// 1 MiB and more // 1 MiB and more
else if (capacity >= 1048576) { else if (capacity >= 1'048'576) {
capacity /= 1048576; capacity /= 1'048'576;
unit = "MiB"; unit = "MiB";
} }
else { else {
@@ -62,8 +62,8 @@ void SCSIHD::FinalizeSetup(const Filepath &path, off_t size, off_t image_offset)
SetProtectable(true); SetProtectable(true);
SetProtected(false); SetProtected(false);
Disk::Open(path); super::Open(path);
FileSupport::SetPath(path); SetPath(path);
SetUpCache(path, image_offset); SetUpCache(path, image_offset);
} }
@@ -84,7 +84,7 @@ void SCSIHD::Open(const Filepath& path)
// Sector size (default 512 bytes) and number of blocks // Sector size (default 512 bytes) and number of blocks
SetSectorSizeInBytes(GetConfiguredSectorSize() ? GetConfiguredSectorSize() : 512); SetSectorSizeInBytes(GetConfiguredSectorSize() ? GetConfiguredSectorSize() : 512);
SetBlockCount((DWORD)(size >> GetSectorSizeShiftCount())); SetBlockCount((uint32_t)(size >> GetSectorSizeShiftCount()));
// Effective size must be a multiple of the sector size // Effective size must be a multiple of the sector size
size = (size / GetSectorSizeInBytes()) * GetSectorSizeInBytes(); size = (size / GetSectorSizeInBytes()) * GetSectorSizeInBytes();

View File

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

View File

@@ -7,7 +7,7 @@
// Copyright (C) 2014-2020 GIMONS // Copyright (C) 2014-2020 GIMONS
// Copyright (C) akuker // 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. // See LICENSE file in the project root folder.
// //
// [ SCSI NEC "Genuine" Hard Disk] // [ SCSI NEC "Genuine" Hard Disk]

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -8,7 +8,6 @@
// //
//--------------------------------------------------------------------------- //---------------------------------------------------------------------------
#include <stdio.h>
#include <iostream> #include <iostream>
#include <fstream> #include <fstream>
#include "os.h" #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; const data_capture *data;
bool prev_data_valid = false; bool prev_data_valid = false;
bool curr_data_valid; bool curr_data_valid;
DWORD selected_id = 0; uint32_t selected_id = 0;
BUS::phase_t prev_phase = BUS::phase_t::busfree; BUS::phase_t prev_phase = BUS::phase_t::busfree;
bool close_row = false; bool close_row = false;
int data_space_count = 0; 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; 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]; data = &data_capture_array[idx];
curr_data_valid = GetAck(data) && GetReq(data); curr_data_valid = GetAck(data) && GetReq(data);
BUS::phase_t phase = GetPhase(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); selected_id = GetData(data);
} }
if (prev_phase != phase) if (prev_phase != phase) {
{ if (close_row) {
if (close_row) if (collapsible_div_active) {
{
if (collapsible_div_active)
{
html_fp << "</code></div>"; html_fp << "</code></div>";
} }
else if (button_active) else if (button_active) {
{
html_fp << "</code></button>"; html_fp << "</code></button>";
} }
html_fp << "</td>"; html_fp << "</td>";
if (data_space_count < 1) if (data_space_count < 1) {
{
html_fp << "<td>--</td>"; html_fp << "<td>--</td>";
} }
else else {
{
html_fp << "<td>wc: " << std::dec << "(0x" << std::hex << data_space_count << ")</td>"; html_fp << "<td>wc: " << std::dec << "(0x" << std::hex << data_space_count << ")</td>";
} }
html_fp << "</tr>" << endl; 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>" << std::hex << selected_id << "</td>";
html_fp << "<td>"; html_fp << "<td>";
} }
if (curr_data_valid && !prev_data_valid) if (curr_data_valid && !prev_data_valid) {
{ if (data_space_count == 0) {
if (data_space_count == 0)
{
button_active = true; button_active = true;
html_fp << "<button type=\"button\" class=\"collapsible\"><code>"; 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 << std::hex << data_space_count << ": ";
} }
html_fp << fmt::format("{0:02X}", GetData(data)); html_fp << fmt::format("{0:02X}", GetData(data));
data_space_count++; data_space_count++;
if ((data_space_count % 4) == 0) if ((data_space_count % 4) == 0) {
{
html_fp << " "; html_fp << " ";
} }
if (data_space_count == 16) if (data_space_count == 16) {
{
html_fp << "</code></button><div class=\"content\"><code>" << endl; html_fp << "</code></button><div class=\"content\"><code>" << endl;
collapsible_div_active = true; collapsible_div_active = true;
button_active = false; 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; 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; ofstream html_ofstream;

View File

@@ -19,45 +19,39 @@ using namespace std;
const char timestamp_label[] = "\"timestamp\":\"0x"; const char timestamp_label[] = "\"timestamp\":\"0x";
const char data_label[] = "\"data\":\"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]; char str_buf[1024];
FILE *fp = fopen(json_filename, "r"); 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 timestamp[1024];
char data[1024]; char data[1024];
uint64_t timestamp_uint; uint64_t timestamp_uint;
uint32_t data_uint; uint32_t data_uint;
char *ptr; char *ptr;
const char *timestamp_str; const char *timestamp_str = strstr(str_buf, timestamp_label);
const char *data_str;
timestamp_str = strstr(str_buf, timestamp_label);
if (!timestamp_str) if (!timestamp_str)
continue; continue;
strncpy(timestamp, &timestamp_str[strlen(timestamp_label)], 16); strncpy(timestamp, &timestamp_str[strlen(timestamp_label)], 16);
timestamp[16] = '\0'; timestamp[16] = '\0';
timestamp_uint = strtoull(timestamp, &ptr, 16); 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) if (!data_str)
continue; continue;
strncpy(data, &data_str[strlen(data_label)], 8); strncpy(data, &data_str[strlen(data_label)], 8);
data[8] = '\0'; data[8] = '\0';
data_uint = strtoul(data, &ptr, 16); 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].timestamp = timestamp_uint;
data_capture_array[sample_count].data = data_uint; data_capture_array[sample_count].data = data_uint;
sample_count++; sample_count++;
if (sample_count >= max_sz) if (sample_count >= max_sz) {
{ LOGWARN("File exceeds maximum buffer size. Some data may be missing.")
LOGWARN("File exceeds maximum buffer size. Some data may be missing."); LOGWARN("Try re-running the tool with a larger buffer size")
LOGWARN("Try re-running the tool with a larger buffer size");
break; break;
} }
} }
@@ -74,17 +68,16 @@ DWORD scsimon_read_json(const char *json_filename, data_capture *data_capture_ar
// Generate JSON Output File // 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; ofstream json_ofstream;
json_ofstream.open(filename, ios::out); json_ofstream.open(filename, ios::out);
json_ofstream << "[" << endl; json_ofstream << "[" << endl;
DWORD i = 0; uint32_t i = 0;
while (i < capture_count) 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); 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)) if (i != (capture_count - 1))

View File

@@ -11,8 +11,8 @@
#include "data_sample.h" #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_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, DWORD 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, DWORD 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; 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; 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_DT0 - 0)) & (1 << 7)) |
((data >> (PIN_DT1 - 1)) & (1 << 6)) | ((data >> (PIN_DT1 - 1)) & (1 << 6)) |
((data >> (PIN_DT2 - 2)) & (1 << 5)) | ((data >> (PIN_DT2 - 2)) & (1 << 5)) |
@@ -74,31 +74,28 @@ static BYTE get_data_field(DWORD data)
return (BYTE)data_out; 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); const BUS::phase_t new_value = GPIOBUS::GetPhaseRaw(data);
if (prev_value[pin] != (int)new_value) if (prev_value[pin] != (int)new_value) {
{
prev_value[pin] = (int)new_value; prev_value[pin] = (int)new_value;
fp << "s" << GPIOBUS::GetPhaseStrRaw(new_value) << " " << symbol << endl; 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); const BYTE new_value = get_pin_value(data, pin);
if (prev_value[pin] != new_value) if (prev_value[pin] != new_value) {
{
prev_value[pin] = new_value; prev_value[pin] = new_value;
fp << new_value << symbol << endl; 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); const BYTE new_value = get_data_field(data);
if (prev_value[pin] != new_value) if (prev_value[pin] != new_value) {
{
prev_value[pin] = new_value; prev_value[pin] = new_value;
fp << "b" fp << "b"
<< fmt::format("{0:b}", get_pin_value(data, PIN_DT7)) << 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; ofstream vcd_ofstream;
vcd_ofstream.open(filename, ios::out); 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]; char timestamp[256];
strftime(timestamp, sizeof(timestamp), "%d-%m-%Y %H-%M-%S", timeinfo); strftime(timestamp, sizeof(timestamp), "%d-%m-%Y %H-%M-%S", timeinfo);
vcd_ofstream vcd_ofstream
<< "$date" << endl << "$date" << endl
<< timestamp << endl << timestamp << endl
<< "$end" << endl << "$end" << endl
@@ -167,9 +164,8 @@ void scsimon_generate_value_change_dump(const char *filename, const data_capture
<< "b00000000 " << SYMBOL_PIN_DAT << endl << "b00000000 " << SYMBOL_PIN_DAT << endl
<< "$end" << endl; << "$end" << endl;
DWORD i = 0; uint32_t i = 0;
while (i < capture_count) while (i < capture_count) {
{
vcd_ofstream << "#" << (uint64_t)(data_capture_array[i].timestamp * ns_per_loop) << endl; 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_BSY, SYMBOL_PIN_BSY);
vcd_output_if_changed_bool(vcd_ofstream, data_capture_array[i].data, PIN_SEL, SYMBOL_PIN_SEL); 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) 2016-2020 GIMONS
// Copyright (C) 2020 akuker // Copyright (C) 2020 akuker
// //
// [ OS related definitions ]
//
//--------------------------------------------------------------------------- //---------------------------------------------------------------------------
#pragma once #pragma once
#include <cstdlib>
#include <cstring>
#include <cassert>
#include <cstdint> #include <cstdint>
using BYTE = unsigned char; using BYTE = unsigned char;
using WORD = uint16_t;
using DWORD = uint32_t; using DWORD = uint32_t;

View File

@@ -11,7 +11,6 @@
#include "protobuf_serializer.h" #include "protobuf_serializer.h"
#include "rascsi_exceptions.h" #include "rascsi_exceptions.h"
#include <unistd.h> #include <unistd.h>
#include <sstream>
using namespace std; using namespace std;
using namespace rascsi_interface; 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 // Read the header with the size of the protobuf data
vector<byte> header_buf(4); vector<byte> header_buf(4);
if (ReadBytes(fd, header_buf) < header_buf.size()) { 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) { if (size <= 0) {
throw io_exception("Invalid protobuf message header"); 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; size_t offset = 0;
while (offset < buf.size()) { 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) { if (len <= 0) {
return len; 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 // 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 std;
using namespace rascsi_interface; using namespace rascsi_interface;
namespace command_util namespace protobuf_util
{ {
void ParseParameters(PbDeviceDefinition&, const string&); void ParseParameters(PbDeviceDefinition&, const string&);
string GetParam(const PbCommand&, const string&); string GetParam(const PbCommand&, const string&);
@@ -26,4 +26,5 @@ namespace command_util
void AddParam(PbCommand&, const string&, string_view); void AddParam(PbCommand&, const string&, string_view);
void AddParam(PbDevice&, const string&, string_view); void AddParam(PbDevice&, const string&, string_view);
void AddParam(PbDeviceDefinition&, 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/controller_manager.h"
#include "controllers/scsi_controller.h" #include "controllers/scsi_controller.h"
#include "devices/device_factory.h" #include "devices/device_factory.h"
#include "devices/file_support.h" #include "devices/disk.h"
#include "hal/gpiobus.h" #include "hal/gpiobus.h"
#include "hal/systimer.h" #include "hal/systimer.h"
#include "rascsi_version.h"
#include "rascsi_exceptions.h" #include "rascsi_exceptions.h"
#include "protobuf_serializer.h" #include "protobuf_serializer.h"
#include "command_util.h" #include "protobuf_util.h"
#include "rascsi_version.h"
#include "rascsi_interface.pb.h" #include "rascsi_interface.pb.h"
#include "rascsi/rascsi_executor.h" #include "rascsi/rascsi_executor.h"
#include "rascsi/rascsi_response.h" #include "rascsi/rascsi_response.h"
@@ -43,7 +43,7 @@ using namespace std;
using namespace spdlog; using namespace spdlog;
using namespace rascsi_interface; using namespace rascsi_interface;
using namespace ras_util; 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 static volatile bool active; // Processing flag
RascsiService service; RascsiService service;
GPIOBUS bus; 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; string access_token;
DeviceFactory device_factory; DeviceFactory device_factory;
ControllerManager controller_manager(bus); ControllerManager controller_manager(bus);
@@ -72,28 +72,23 @@ const ProtobufSerializer serializer;
void Banner(int argc, char* argv[]) void Banner(int argc, char* argv[])
{ {
cout << "SCSI Target Emulator RaSCSI Reloaded version " << rascsi_get_version_string() cout << Banner("Reloaded");
<< " (" << __DATE__ << ' ' << __TIME__ << ')' << endl; cout << "Connect type: " << CONNECT_DESC << '\n' << flush;
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;
if ((argc > 1 && strcmp(argv[1], "-h") == 0) || (argc > 1 && strcmp(argv[1], "--help") == 0)){ if ((argc > 1 && strcmp(argv[1], "-h") == 0) || (argc > 1 && strcmp(argv[1], "--help") == 0)){
cout << endl; cout << "\nUsage: " << argv[0] << " [-idn[:m] FILE] ...\n\n";
cout << "Usage: " << argv[0] << " [-idn[:m] FILE] ..." << endl << endl; cout << " n is SCSI device ID (0-7).\n";
cout << " n is SCSI device ID (0-7)." << endl; cout << " m is the optional logical unit (LUN) (0-31).\n";
cout << " m is the optional logical unit (LUN) (0-31)." << endl; cout << " FILE is a disk image file, \"daynaport\", \"bridge\", \"printer\" or \"services\".\n\n";
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.\n";
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)\n";
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)\n";
cout << " hds : SCSI HD image (Non-removable generic SCSI HD image)" << endl; cout << " hdr : SCSI HD image (Removable generic HD image)\n";
cout << " hdr : SCSI HD image (Removable generic HD image)" << endl; cout << " hdn : SCSI HD image (NEC GENUINE)\n";
cout << " hdn : SCSI HD image (NEC GENUINE)" << endl; cout << " hdi : SCSI HD image (Anex86 HD image)\n";
cout << " hdi : SCSI HD image (Anex86 HD image)" << endl; cout << " nhd : SCSI HD image (T98Next HD image)\n";
cout << " nhd : SCSI HD image (T98Next HD image)" << endl; cout << " mos : SCSI MO image (MO image)\n";
cout << " mos : SCSI MO image (MO image)" << endl; cout << " iso : SCSI CD image (ISO 9660 image)\n" << flush;
cout << " iso : SCSI CD image (ISO 9660 image)" << endl;
exit(EXIT_SUCCESS); exit(EXIT_SUCCESS);
} }
@@ -185,7 +180,7 @@ void TerminationHandler(int signum)
bool ProcessId(const string& id_spec, int& id, int& unit) 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) { if (!GetAsInt(id_spec, id) || id < 0 || id >= 8) {
cerr << optarg << ": Invalid device ID (0-7)" << endl; cerr << optarg << ": Invalid device ID (0-7)" << endl;
return false; return false;
@@ -249,7 +244,7 @@ bool ParseArgument(int argc, char* argv[], int& port)
continue; continue;
case 'F': { case 'F': {
if (string result = rascsi_image.SetDefaultFolder(optarg); !result.empty()) { if (const string result = rascsi_image.SetDefaultFolder(optarg); !result.empty()) {
cerr << result << endl; cerr << result << endl;
return false; 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 list<PbDevice>& devices = { server_info.devices_info().devices().begin(), server_info.devices_info().devices().end() };
const string device_list = ListDevices(devices); const string device_list = ListDevices(devices);
LogDevices(device_list); LogDevices(device_list);
cout << device_list << endl; cout << device_list << flush;
return true; return true;
} }
@@ -388,8 +383,8 @@ static bool ExecuteCommand(const CommandContext& context, PbCommand& command)
switch(command.operation()) { switch(command.operation()) {
case LOG_LEVEL: { case LOG_LEVEL: {
string log_level = GetParam(command, "level"); const string log_level = GetParam(command, "level");
if (bool status = executor.SetLogLevel(log_level); !status) { if (const bool status = executor.SetLogLevel(log_level); !status) {
context.ReturnLocalizedError(LocalizationKey::ERROR_LOG_LEVEL, log_level); context.ReturnLocalizedError(LocalizationKey::ERROR_LOG_LEVEL, log_level);
} }
else { else {
@@ -401,7 +396,7 @@ static bool ExecuteCommand(const CommandContext& context, PbCommand& command)
} }
case DEFAULT_FOLDER: { 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); context.ReturnStatus(false, status);
} }
else { else {
@@ -457,7 +452,7 @@ static bool ExecuteCommand(const CommandContext& context, PbCommand& command)
} }
else { else {
auto image_file = make_unique<PbImageFile>(); 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) { if (status) {
result.set_status(true); result.set_status(true);
result.set_allocated_image_file_info(image_file.get()); result.set_allocated_image_file_info(image_file.get());
@@ -505,7 +500,7 @@ static bool ExecuteCommand(const CommandContext& context, PbCommand& command)
default: { default: {
// Wait until we become idle // 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) { while (active) {
nanosleep(&ts, nullptr); 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 // 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()) { if (!InitBus()) {
return EPERM; return EPERM;
@@ -599,7 +594,7 @@ int main(int argc, char* argv[])
#else #else
bus.Acquire(); bus.Acquire();
if (!bus.GetSEL()) { if (!bus.GetSEL()) {
timespec ts = { .tv_sec = 0, .tv_nsec = 0}; const timespec ts = { .tv_sec = 0, .tv_nsec = 0};
nanosleep(&ts, nullptr); nanosleep(&ts, nullptr);
continue; continue;
} }
@@ -608,8 +603,8 @@ int main(int argc, char* argv[])
// Wait until BSY is released as there is a possibility for the // 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) // initiator to assert it while setting the ID (for up to 3 seconds)
if (bus.GetBSY()) { if (bus.GetBSY()) {
uint32_t now = SysTimer::GetTimerLow(); const uint32_t now = SysTimer::GetTimerLow();
while ((SysTimer::GetTimerLow() - now) < 3 * 1000 * 1000) { while ((SysTimer::GetTimerLow() - now) < 3'000'000) {
bus.Acquire(); bus.Acquire();
if (!bus.GetBSY()) { if (!bus.GetBSY()) {
break; break;
@@ -625,7 +620,7 @@ int main(int argc, char* argv[])
int initiator_id = -1; int initiator_id = -1;
// The initiator and target ID // The initiator and target ID
BYTE id_data = bus.GetDAT(); const BYTE id_data = bus.GetDAT();
BUS::phase_t phase = BUS::phase_t::busfree; BUS::phase_t phase = BUS::phase_t::busfree;

View File

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

View File

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

View File

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

View File

@@ -12,8 +12,8 @@
#include "log.h" #include "log.h"
#include "filepath.h" #include "filepath.h"
#include "spdlog/spdlog.h" #include "spdlog/spdlog.h"
#include "devices/file_support.h" #include "devices/disk.h"
#include "command_util.h" #include "protobuf_util.h"
#include "command_context.h" #include "command_context.h"
#include "rascsi_image.h" #include "rascsi_image.h"
#include <string> #include <string>
@@ -26,7 +26,7 @@
using namespace std; using namespace std;
using namespace spdlog; using namespace spdlog;
using namespace rascsi_interface; using namespace rascsi_interface;
using namespace command_util; using namespace protobuf_util;
RascsiImage::RascsiImage() RascsiImage::RascsiImage()
{ {
@@ -41,8 +41,8 @@ bool RascsiImage::CheckDepth(string_view filename) const
bool RascsiImage::CreateImageFolder(const CommandContext& context, const string& filename) const bool RascsiImage::CreateImageFolder(const CommandContext& context, const string& filename) const
{ {
if (size_t filename_start = filename.rfind('/'); filename_start != string::npos) { if (const size_t filename_start = filename.rfind('/'); filename_start != string::npos) {
string folder = filename.substr(0, filename_start); const string folder = filename.substr(0, filename_start);
// Checking for existence first prevents an error if the top-level folder is a softlink // Checking for existence first prevents an error if the top-level folder is a softlink
if (struct stat st; stat(folder.c_str(), &st)) { 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 bool RascsiImage::CreateImage(const CommandContext& context, const PbCommand& command) const
{ {
string filename = GetParam(command, "file"); const string filename = GetParam(command, "file");
if (filename.empty()) { if (filename.empty()) {
return context.ReturnStatus(false, "Can't create image file: Missing image filename"); 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()); 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)) { if (!IsValidDstFilename(full_filename)) {
return context.ReturnStatus(false, "Can't create image file: '" + full_filename + "': File already exists"); 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; 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 // 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; 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) { if (image_fd == -1) {
return context.ReturnStatus(false, "Can't create image file '" + full_filename + "': " + string(strerror(errno))); 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 bool RascsiImage::DeleteImage(const CommandContext& context, const PbCommand& command) const
{ {
string filename = GetParam(command, "file"); const string filename = GetParam(command, "file");
if (filename.empty()) { if (filename.empty()) {
return context.ReturnStatus(false, "Missing image filename"); 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()); 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 id;
int unit; int unit;
Filepath filepath; Filepath filepath;
filepath.SetPath(full_filename.c_str()); 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 + 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)); "', 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(); 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) { if (fd_src == -1) {
return context.ReturnStatus(false, "Can't open source image file '" + from + "': " + string(strerror(errno))); 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 // 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; 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) { if (fd_dst == -1) {
close(fd_src); 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"); 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) { chmod(filename.c_str(), permissions) == -1) {
return context.ReturnStatus(false, "Can't " + string(protect ? "protect" : "unprotect") + " image file '" + filename + "': " + return context.ReturnStatus(false, "Can't " + string(protect ? "protect" : "unprotect") + " image file '" + filename + "': " +
strerror(errno)); strerror(errno));

View File

@@ -8,16 +8,15 @@
//--------------------------------------------------------------------------- //---------------------------------------------------------------------------
#include "controllers/controller_manager.h" #include "controllers/controller_manager.h"
#include "devices/file_support.h"
#include "devices/disk.h" #include "devices/disk.h"
#include "devices/device_factory.h" #include "devices/device_factory.h"
#include "command_util.h" #include "protobuf_util.h"
#include "rascsi_version.h" #include "rascsi_version.h"
#include "rascsi_interface.pb.h" #include "rascsi_interface.pb.h"
#include "rascsi_response.h" #include "rascsi_response.h"
using namespace rascsi_interface; using namespace rascsi_interface;
using namespace command_util; using namespace protobuf_util;
unique_ptr<PbDeviceProperties> RascsiResponse::GetDeviceProperties(const Device& device) const 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_stoppable(device.IsStoppable());
properties->set_removable(device.IsRemovable()); properties->set_removable(device.IsRemovable());
properties->set_lockable(device.IsLockable()); 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()); properties->set_supports_params(device.SupportsParams());
PbDeviceType t = UNDEFINED; PbDeviceType t = UNDEFINED;
@@ -53,7 +52,7 @@ void RascsiResponse::GetDeviceTypeProperties(PbDeviceTypesInfo& device_types_inf
{ {
auto type_properties = device_types_info.add_properties(); auto type_properties = device_types_info.add_properties();
type_properties->set_type(type); 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()); type_properties->set_allocated_properties(GetDeviceProperties(*device).release());
} //NOSONAR The allocated memory is managed by protobuf } //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()); pb_device.set_block_count(device.IsRemoved() ? 0: disk->GetBlockCount());
} }
const auto file_support = dynamic_cast<const FileSupport *>(&device); const auto disk = dynamic_cast<const Disk *>(&device);
if (file_support) { if (disk != nullptr) {
Filepath filepath; Filepath filepath;
file_support->GetPath(filepath); disk->GetPath(filepath);
auto image_file = make_unique<PbImageFile>().release(); auto image_file = make_unique<PbImageFile>().release();
GetImageFile(*image_file, default_folder, device.IsRemovable() && !device.IsReady() ? "" : filepath.GetPath()); GetImageFile(*image_file, default_folder, device.IsRemovable() && !device.IsReady() ? "" : filepath.GetPath());
pb_device.set_allocated_file(image_file); 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_name(filename);
image_file.set_type(device_factory.GetTypeForFile(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)); 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 unique_ptr<PbReservedIdsInfo> RascsiResponse::GetReservedIds(PbResult& result, const unordered_set<int>& ids) const
{ {
auto reserved_ids_info = make_unique<PbReservedIdsInfo>(); auto reserved_ids_info = make_unique<PbReservedIdsInfo>();
for (int id : ids) { for (const int id : ids) {
reserved_ids_info->add_ids(id); reserved_ids_info->add_ids(id);
} }
@@ -533,14 +532,14 @@ string RascsiResponse::GetNextImageFile(const dirent *dir, const string& folder)
return ""; return "";
} }
string filename = folder + "/" + dir->d_name; const string filename = folder + "/" + dir->d_name;
struct stat st; 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) { 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 ""; return "";
} }

View File

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

View File

@@ -30,7 +30,7 @@ class file_not_found_exception : public io_exception
using io_exception::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::sense_key sense_key;
scsi_defs::asc asc; scsi_defs::asc asc;
@@ -38,11 +38,11 @@ class scsi_error_exception final : public std::exception
public: 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::asc asc = scsi_defs::asc::NO_ADDITIONAL_SENSE_INFORMATION,
scsi_defs::status status = scsi_defs::status::CHECK_CONDITION) scsi_defs::status status = scsi_defs::status::CHECK_CONDITION)
: sense_key(sense_key), asc(asc), status(status) {} : 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::sense_key get_sense_key() const { return sense_key; }
scsi_defs::asc get_asc() const { return asc; } scsi_defs::asc get_asc() const { return asc; }

View File

@@ -23,7 +23,7 @@ string rascsi_get_version_string()
{ {
stringstream s; 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) { if (rascsi_patch_version < 0) {
s << " --DEVELOPMENT BUILD--"; s << " --DEVELOPMENT BUILD--";

View File

@@ -10,11 +10,11 @@
// //
//--------------------------------------------------------------------------- //---------------------------------------------------------------------------
#include <unistd.h>
#include "rascsi_version.h" #include "rascsi_version.h"
#include "command_util.h" #include "protobuf_util.h"
#include "rasutil.h" #include "rasutil.h"
#include "rascsi_interface.pb.h" #include "rascsi_interface.pb.h"
#include "rasctl/rasctl_parser.h"
#include "rasctl/rasctl_commands.h" #include "rasctl/rasctl_commands.h"
#include <unistd.h> #include <unistd.h>
#include <clocale> #include <clocale>
@@ -27,125 +27,45 @@ static const char COMPONENT_SEPARATOR = ':';
using namespace std; using namespace std;
using namespace rascsi_interface; using namespace rascsi_interface;
using namespace ras_util; 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])) { if (argc < 2) {
case 'a': cout << Banner("Controller");
return ATTACH;
case 'd': cout << "\nUsage: " << argv[0] << " -i ID [-u UNIT] [-c CMD] [-C FILE] [-t TYPE] [-b BLOCK_SIZE] [-n NAME] [-f FILE|PARAM] ";
return DETACH; 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': exit(EXIT_SUCCESS);
return INSERT;
case 'e':
return EJECT;
case 'p':
return PROTECT;
case 'u':
return UNPROTECT;
case 's':
return DEVICES_INFO;
default:
return NO_OPERATION;
} }
} }
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[]) int main(int argc, char* argv[])
{ {
GOOGLE_PROTOBUF_VERIFY_VERSION; GOOGLE_PROTOBUF_VERIFY_VERSION;
// Display help Banner(argc, argv);
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);
}
RasctlParser parser;
PbCommand command; PbCommand command;
list<PbDeviceDefinition> devices; list<PbDeviceDefinition> devices;
PbDeviceDefinition* device = command.add_devices(); PbDeviceDefinition* device = command.add_devices();
@@ -205,7 +125,7 @@ int main(int argc, char* argv[])
break; break;
case 'c': case 'c':
command.set_operation(ParseOperation(optarg)); command.set_operation(parser.ParseOperation(optarg));
if (command.operation() == NO_OPERATION) { if (command.operation() == NO_OPERATION) {
cerr << "Error: Unknown operation '" << optarg << "'" << endl; cerr << "Error: Unknown operation '" << optarg << "'" << endl;
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
@@ -276,7 +196,7 @@ int main(int argc, char* argv[])
break; break;
case 't': case 't':
device->set_type(ParseType(optarg)); device->set_type(parser.ParseType(optarg));
if (device->type() == UNDEFINED) { if (device->type() == UNDEFINED) {
cerr << "Error: Unknown device type '" << optarg << "'" << endl; cerr << "Error: Unknown device type '" << optarg << "'" << endl;
exit(EXIT_FAILURE); exit(EXIT_FAILURE);

View File

@@ -9,7 +9,7 @@
#include "rascsi_exceptions.h" #include "rascsi_exceptions.h"
#include "protobuf_serializer.h" #include "protobuf_serializer.h"
#include "command_util.h" #include "protobuf_util.h"
#include "rasutil.h" #include "rasutil.h"
#include "rasctl_commands.h" #include "rasctl_commands.h"
#include "rascsi_interface.pb.h" #include "rascsi_interface.pb.h"
@@ -20,7 +20,7 @@
using namespace std; using namespace std;
using namespace rascsi_interface; using namespace rascsi_interface;
using namespace command_util; using namespace protobuf_util;
// Separator for the INQUIRY name components // Separator for the INQUIRY name components
static const char COMPONENT_SEPARATOR = ':'; static const char COMPONENT_SEPARATOR = ':';
@@ -115,36 +115,25 @@ void RasctlCommands::Execute(const string& log_level, const string& default_fold
void RasctlCommands::SendCommand() 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; int fd = -1;
try { try {
const hostent *host = gethostbyname(hostname.c_str()); fd = socket(AF_INET, SOCK_STREAM, 0);
if (!host) { 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 + "'"); throw io_exception("Can't resolve hostname '" + hostname + "'");
} }
fd = socket(AF_INET, SOCK_STREAM, 0); server_addr.sin_port = htons(uint16_t(port));
if (fd < 0) { if (connect(fd, (sockaddr *)&server_addr, sizeof(server_addr)) < 0) {
throw io_exception("Can't create socket"); throw io_exception("Can't connect to rascsi on host '" + hostname + "', port " + to_string(port)
} + ": " + strerror(errno));
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));
} }
if (write(fd, "RASCSI", 6) != 6) { if (write(fd, "RASCSI", 6) != 6) {
@@ -156,11 +145,11 @@ void RasctlCommands::SendCommand()
catch(const io_exception& e) { catch(const io_exception& e) {
cerr << "Error: " << e.get_msg() << endl; cerr << "Error: " << e.get_msg() << endl;
if (fd >= 0) { if (fd != -1) {
close(fd); close(fd);
} }
exit(fd < 0 ? ENOTCONN : EXIT_FAILURE); exit(fd == -1 ? ENOTCONN : EXIT_FAILURE);
} }
// Receive result // Receive result
@@ -190,7 +179,7 @@ void RasctlCommands::CommandDevicesInfo()
{ {
SendCommand(); SendCommand();
rasctl_display.DisplayDevices(result.devices_info()); cout << rasctl_display.DisplayDevicesInfo(result.devices_info()) << flush;
} }
void RasctlCommands::CommandLogLevel(const string& log_level) 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) 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, "file", string_view(image_params).substr(0, separator_pos));
AddParam(command, "size", string_view(image_params).substr(separator_pos + 1)); 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) 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, "from", string_view(image_params).substr(0, separator_pos));
AddParam(command, "to", string_view(image_params).substr(separator_pos + 1)); 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) 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, "from", string_view(image_params).substr(0, separator_pos));
AddParam(command, "to", string_view(image_params).substr(separator_pos + 1)); AddParam(command, "to", string_view(image_params).substr(separator_pos + 1));
} }
@@ -270,22 +259,24 @@ void RasctlCommands::CommandDeviceInfo()
SendCommand(); SendCommand();
for (const auto& device : result.devices_info().devices()) { for (const auto& device : result.devices_info().devices()) {
rasctl_display.DisplayDeviceInfo(device); cout << rasctl_display.DisplayDeviceInfo(device);
} }
cout << flush;
} }
void RasctlCommands::CommandDeviceTypesInfo() void RasctlCommands::CommandDeviceTypesInfo()
{ {
SendCommand(); SendCommand();
rasctl_display.DisplayDeviceTypesInfo(result.device_types_info()); cout << rasctl_display.DisplayDeviceTypesInfo(result.device_types_info()) << flush;
} }
void RasctlCommands::CommandVersionInfo() void RasctlCommands::CommandVersionInfo()
{ {
SendCommand(); SendCommand();
rasctl_display.DisplayVersionInfo(result.version_info()); cout << rasctl_display.DisplayVersionInfo(result.version_info()) << flush;
} }
void RasctlCommands::CommandServerInfo() void RasctlCommands::CommandServerInfo()
@@ -294,32 +285,34 @@ void RasctlCommands::CommandServerInfo()
PbServerInfo server_info = result.server_info(); PbServerInfo server_info = result.server_info();
rasctl_display.DisplayVersionInfo(server_info.version_info()); cout << rasctl_display.DisplayVersionInfo(server_info.version_info());
rasctl_display.DisplayLogLevelInfo(server_info.log_level_info()); cout << rasctl_display.DisplayLogLevelInfo(server_info.log_level_info());
rasctl_display.DisplayImageFiles(server_info.image_files_info()); cout << rasctl_display.DisplayImageFilesInfo(server_info.image_files_info());
rasctl_display.DisplayMappingInfo(server_info.mapping_info()); cout << rasctl_display.DisplayMappingInfo(server_info.mapping_info());
rasctl_display.DisplayNetworkInterfaces(server_info.network_interfaces_info()); cout << rasctl_display.DisplayNetworkInterfaces(server_info.network_interfaces_info());
rasctl_display.DisplayDeviceTypesInfo(server_info.device_types_info()); cout << rasctl_display.DisplayDeviceTypesInfo(server_info.device_types_info());
rasctl_display.DisplayReservedIdsInfo(server_info.reserved_ids_info()); cout << rasctl_display.DisplayReservedIdsInfo(server_info.reserved_ids_info());
rasctl_display.DisplayOperationInfo(server_info.operation_info()); cout << rasctl_display.DisplayOperationInfo(server_info.operation_info());
if (server_info.devices_info().devices_size()) { if (server_info.devices_info().devices_size()) {
list<PbDevice> sorted_devices = { server_info.devices_info().devices().begin(), server_info.devices_info().devices().end() }; 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(); }); 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) { for (const auto& device : sorted_devices) {
rasctl_display.DisplayDeviceInfo(device); cout << rasctl_display.DisplayDeviceInfo(device);
} }
} }
cout << flush;
} }
void RasctlCommands::CommandDefaultImageFilesInfo() void RasctlCommands::CommandDefaultImageFilesInfo()
{ {
SendCommand(); SendCommand();
rasctl_display.DisplayImageFiles(result.image_files_info()); cout << rasctl_display.DisplayImageFilesInfo(result.image_files_info()) << flush;
} }
void RasctlCommands::CommandImageFileInfo(const string& filename) void RasctlCommands::CommandImageFileInfo(const string& filename)
@@ -328,40 +321,55 @@ void RasctlCommands::CommandImageFileInfo(const string& filename)
SendCommand(); SendCommand();
rasctl_display.DisplayImageFile(result.image_file_info()); cout << rasctl_display.DisplayImageFile(result.image_file_info()) << flush;
} }
void RasctlCommands::CommandNetworkInterfacesInfo() void RasctlCommands::CommandNetworkInterfacesInfo()
{ {
SendCommand(); SendCommand();
rasctl_display.DisplayNetworkInterfaces(result.network_interfaces_info()); cout << rasctl_display.DisplayNetworkInterfaces(result.network_interfaces_info()) << flush;
} }
void RasctlCommands::CommandLogLevelInfo() void RasctlCommands::CommandLogLevelInfo()
{ {
SendCommand(); SendCommand();
rasctl_display.DisplayLogLevelInfo(result.log_level_info()); cout << rasctl_display.DisplayLogLevelInfo(result.log_level_info()) << flush;
} }
void RasctlCommands::CommandReservedIdsInfo() void RasctlCommands::CommandReservedIdsInfo()
{ {
SendCommand(); SendCommand();
rasctl_display.DisplayReservedIdsInfo(result.reserved_ids_info()); cout << rasctl_display.DisplayReservedIdsInfo(result.reserved_ids_info()) << flush;
} }
void RasctlCommands::CommandMappingInfo() void RasctlCommands::CommandMappingInfo()
{ {
SendCommand(); SendCommand();
rasctl_display.DisplayMappingInfo(result.mapping_info()); cout << rasctl_display.DisplayMappingInfo(result.mapping_info()) << flush;
} }
void RasctlCommands::CommandOperationInfo() void RasctlCommands::CommandOperationInfo()
{ {
SendCommand(); 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 // SCSI Target Emulator RaSCSI Reloaded
// for Raspberry Pi // for Raspberry Pi
// //
// Copyright (C) 2021 Uwe Seimet // Copyright (C) 2021-2022 Uwe Seimet
// //
//--------------------------------------------------------------------------- //---------------------------------------------------------------------------
@@ -12,6 +12,7 @@
#include "protobuf_serializer.h" #include "protobuf_serializer.h"
#include "rascsi_interface.pb.h" #include "rascsi_interface.pb.h"
#include "rasctl_display.h" #include "rasctl_display.h"
#include <netdb.h>
#include <string> #include <string>
using namespace rascsi_interface; using namespace rascsi_interface;
@@ -49,6 +50,8 @@ private:
void CommandOperationInfo(); void CommandOperationInfo();
void SendCommand(); void SendCommand();
static bool ResolveHostName(const string&, sockaddr_in *);
ProtobufSerializer serializer; ProtobufSerializer serializer;
PbCommand command; PbCommand command;
string hostname; string hostname;

View File

@@ -10,274 +10,282 @@
#include "rascsi_interface.pb.h" #include "rascsi_interface.pb.h"
#include "rasutil.h" #include "rasutil.h"
#include "rasctl_display.h" #include "rasctl_display.h"
#include <iostream> #include <sstream>
#include <list> #include <list>
#include <iomanip>
using namespace std; using namespace std;
using namespace rascsi_interface; using namespace rascsi_interface;
using namespace ras_util; 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() }; 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(); << " " << pb_device.vendor() << ":" << pb_device.product() << ":" << pb_device.revision();
if (pb_device.block_size()) { 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()) { 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()) { 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; bool hasProperty = false;
if (pb_device.properties().read_only()) { if (pb_device.properties().read_only()) {
cout << "read-only"; s << "read-only";
hasProperty = true; hasProperty = true;
} }
if (pb_device.properties().protectable() && pb_device.status().protected_()) { if (pb_device.properties().protectable() && pb_device.status().protected_()) {
if (hasProperty) { if (hasProperty) {
cout << ", "; s << ", ";
} }
cout << "protected"; s << "protected";
hasProperty = true; hasProperty = true;
} }
if (pb_device.properties().stoppable() && pb_device.status().stopped()) { if (pb_device.properties().stoppable() && pb_device.status().stopped()) {
if (hasProperty) { if (hasProperty) {
cout << ", "; s << ", ";
} }
cout << "stopped"; s << "stopped";
hasProperty = true; hasProperty = true;
} }
if (pb_device.properties().removable() && pb_device.status().removed()) { if (pb_device.properties().removable() && pb_device.status().removed()) {
if (hasProperty) { if (hasProperty) {
cout << ", "; s << ", ";
} }
cout << "removed"; s << "removed";
hasProperty = true; hasProperty = true;
} }
if (pb_device.properties().lockable() && pb_device.status().locked()) { if (pb_device.properties().lockable() && pb_device.status().locked()) {
if (hasProperty) { if (hasProperty) {
cout << ", "; s << ", ";
} }
cout << "locked"; s << "locked";
} }
if (hasProperty) { if (hasProperty) {
cout << " "; s << " ";
} }
// Creates a sorted map DisplayParams(s, pb_device);
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;
}
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) { if (version_info.patch_version() > 0) {
cout << "." << version_info.patch_version(); s << "." << version_info.patch_version();
} }
else if (version_info.patch_version() < 0) { 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()) { if (!log_level_info.log_levels_size()) {
cout << " No log level settings available" << endl; s << " No log level settings available\n";
} }
else { 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()) { 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()) { 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(); const PbDeviceProperties& properties = device_type_info.properties();
if (properties.read_only() || properties.protectable() || properties.stoppable() || properties.lockable()) { DisplayAttributes(s, properties);
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 << " ";
}
if (properties.supports_file()) { if (properties.supports_file()) {
cout << "Image file support" << endl << " "; s << "Image file support\n ";
} }
if (properties.supports_params()) { if (properties.supports_params()) {
cout << "Parameter support" << endl << " "; s << "Parameter support\n ";
} }
if (properties.supports_params() && properties.default_params_size()) { DisplayDefaultParameters(s, properties);
// Creates a sorted map
map<string, string> params = { properties.default_params().begin(), properties.default_params().end() };
cout << "Default parameters: "; DisplayBlockSizes(s, properties);
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;
}
}
} }
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()) { 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++) { for (int i = 0; i < reserved_ids_info.ids_size(); i++) {
if(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()) { 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; ostringstream s;
cout << "Supported folder depth: " << image_files_info.depth() << endl;
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()) { if (image_files_info.image_files().empty()) {
cout << " No image files available" << endl; s << " No image files available\n";
} }
else { else {
list<PbImageFile> image_files = { image_files_info.image_files().begin(), image_files_info.image_files().end() }; 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(); }); 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) { for (const auto& image_file : image_files) {
cout << " "; s << " ";
DisplayImageFile(image_file);
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 ostringstream s;
const list<string> interfaces = { network_interfaces_info.name().begin(), network_interfaces_info.name().end() };
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; bool isFirst = true;
for (const auto& interface : interfaces) { for (const auto& interface : sorted_interfaces) {
if (!isFirst) { if (!isFirst) {
cout << ", "; s << ", ";
} }
else { else {
cout << " "; s << " ";
} }
isFirst = false; 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 ostringstream s;
const map<string, PbDeviceType> mappings = { mapping_info.mapping().begin(), mapping_info.mapping().end() };
cout << "Supported image file extension to device type mappings:" << endl; s << "Supported image file extension to device type mappings:\n";
for (const auto& [extension, type] : mappings) {
cout << " " << extension << "->" << PbDeviceType_Name(type) << endl; 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 // Copies result into a map sorted by operation name
const PbOperationMetaData *unknown_operation = new PbOperationMetaData(); auto unknown_operation = make_unique<PbOperationMetaData>();
map<string, PbOperationMetaData> sorted_operations; map<string, PbOperationMetaData, less<>> sorted_operations;
for (const auto& [ordinal, meta_data] : operations) { for (const auto& [ordinal, meta_data] : operations) {
if (PbOperation_IsValid(static_cast<PbOperation>(ordinal))) { if (PbOperation_IsValid(static_cast<PbOperation>(ordinal))) {
sorted_operations[PbOperation_Name(static_cast<PbOperation>(ordinal))] = meta_data; 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) { for (const auto& [name, meta_data] : sorted_operations) {
if (!meta_data.server_side_name().empty()) { if (!meta_data.server_side_name().empty()) {
cout << " " << name; s << " " << name;
if (!meta_data.description().empty()) { 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() }; DisplayParameters(s, meta_data);
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;
}
}
} }
else { 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 #pragma once
#include "rascsi_interface.pb.h" #include "rascsi_interface.pb.h"
#include <string>
#include <sstream>
using namespace std;
using namespace rascsi_interface; using namespace rascsi_interface;
class RasctlDisplay class RasctlDisplay
{ {
friend class RasctlCommands; public:
RasctlDisplay() = default; RasctlDisplay() = default;
~RasctlDisplay() = default; ~RasctlDisplay() = default;
void DisplayDevices(const PbDevicesInfo&) const; string DisplayDevicesInfo(const PbDevicesInfo&) const;
void DisplayDeviceInfo(const PbDevice&) const; string DisplayDeviceInfo(const PbDevice&) const;
void DisplayVersionInfo(const PbVersionInfo&) const; string DisplayVersionInfo(const PbVersionInfo&) const;
void DisplayLogLevelInfo(const PbLogLevelInfo&) const; string DisplayLogLevelInfo(const PbLogLevelInfo&) const;
void DisplayDeviceTypesInfo(const PbDeviceTypesInfo&) const; string DisplayDeviceTypesInfo(const PbDeviceTypesInfo&) const;
void DisplayReservedIdsInfo(const PbReservedIdsInfo&) const; string DisplayReservedIdsInfo(const PbReservedIdsInfo&) const;
void DisplayImageFile(const PbImageFile&) const; string DisplayImageFile(const PbImageFile&) const;
void DisplayImageFiles(const PbImageFilesInfo&) const; string DisplayImageFilesInfo(const PbImageFilesInfo&) const;
void DisplayNetworkInterfaces(const PbNetworkInterfacesInfo&) const; string DisplayNetworkInterfaces(const PbNetworkInterfacesInfo&) const;
void DisplayMappingInfo(const PbMappingInfo&) const; string DisplayMappingInfo(const PbMappingInfo&) const;
void DisplayOperationInfo(const PbOperationInfo&) 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) bool WaitPhase(BUS::phase_t phase)
{ {
// Timeout (3000ms) // Timeout (3000ms)
uint32_t now = SysTimer::GetTimerLow(); const uint32_t now = SysTimer::GetTimerLow();
while ((SysTimer::GetTimerLow() - now) < 3 * 1000 * 1000) { while ((SysTimer::GetTimerLow() - now) < 3 * 1000 * 1000) {
bus.Acquire(); bus.Acquire();
if (bus.GetREQ() && bus.GetPhase() == phase) { if (bus.GetREQ() && bus.GetPhase() == phase) {
@@ -246,21 +246,17 @@ void BusFree()
//--------------------------------------------------------------------------- //---------------------------------------------------------------------------
bool Selection(int id) bool Selection(int id)
{ {
BYTE data;
int count;
// ID setting and SEL assert // ID setting and SEL assert
data = 0; BYTE data = 1 << boardid;
data |= (1 << boardid);
data |= (1 << id); data |= (1 << id);
bus.SetDAT(data); bus.SetDAT(data);
bus.SetSEL(true); bus.SetSEL(true);
// wait for busy // wait for busy
count = 10000; int count = 10000;
do { do {
// Wait 20 microseconds // 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); nanosleep(&ts, nullptr);
bus.Acquire(); bus.Acquire();
if (bus.GetBSY()) { if (bus.GetBSY()) {
@@ -282,15 +278,13 @@ bool Selection(int id)
//--------------------------------------------------------------------------- //---------------------------------------------------------------------------
bool Command(BYTE *buf, int length) bool Command(BYTE *buf, int length)
{ {
int count;
// Waiting for Phase // Waiting for Phase
if (!WaitPhase(BUS::phase_t::command)) { if (!WaitPhase(BUS::phase_t::command)) {
return false; return false;
} }
// Send Command // 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 // Success if the transmission result is the same as the number
// of requests // of requests
@@ -665,7 +659,7 @@ exit:
// READ10 // 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 = {}; array<BYTE, 256> cmd = {};
@@ -728,7 +722,7 @@ exit:
// WRITE10 // 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 = {}; array<BYTE, 256> cmd = {};
@@ -794,13 +788,12 @@ exit:
int main(int argc, char* argv[]) int main(int argc, char* argv[])
{ {
int i; int i;
int count;
char str[32]; char str[32];
DWORD bsiz; uint32_t bsiz;
DWORD bnum; uint32_t bnum;
DWORD duni; uint32_t duni;
DWORD dsiz; uint32_t dsiz;
DWORD dnum; uint32_t dnum;
Fileio fio; Fileio fio;
Fileio::OpenMode omode; Fileio::OpenMode omode;
off_t size; off_t size;
@@ -855,7 +848,7 @@ int main(int argc, char* argv[])
// Assert reset signal // Assert reset signal
bus.SetRST(true); bus.SetRST(true);
// Wait 1 ms // 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); nanosleep(&ts, nullptr);
bus.SetRST(false); bus.SetRST(false);
@@ -864,7 +857,7 @@ int main(int argc, char* argv[])
printf("BOARD ID : %d\n", boardid); printf("BOARD ID : %d\n", boardid);
// TEST UNIT READY // TEST UNIT READY
count = TestUnitReady(targetid); int count = TestUnitReady(targetid);
if (count < 0) { if (count < 0) {
fprintf(stderr, "TEST UNIT READY ERROR %d\n", count); fprintf(stderr, "TEST UNIT READY ERROR %d\n", count);
goto cleanup_exit; goto cleanup_exit;

View File

@@ -7,10 +7,9 @@
// //
//--------------------------------------------------------------------------- //---------------------------------------------------------------------------
#include <list> #include "rascsi_version.h"
#include <sstream>
#include "rascsi_interface.pb.h"
#include "rasutil.h" #include "rasutil.h"
#include <sstream>
using namespace std; using namespace std;
using namespace rascsi_interface; using namespace rascsi_interface;
@@ -35,16 +34,30 @@ bool ras_util::GetAsInt(const string& value, int& result)
return true; 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) string ras_util::ListDevices(const list<PbDevice>& pb_devices)
{ {
if (pb_devices.empty()) { if (pb_devices.empty()) {
return "No devices currently attached."; return "No devices currently attached.\n";
} }
ostringstream s; ostringstream s;
s << "+----+-----+------+-------------------------------------" << endl s << "+----+-----+------+-------------------------------------\n"
<< "| ID | LUN | TYPE | IMAGE FILE" << endl << "| ID | LUN | TYPE | IMAGE FILE\n"
<< "+----+-----+------+-------------------------------------" << endl; << "+----+-----+------+-------------------------------------\n";
list<PbDevice> devices = pb_devices; list<PbDevice> devices = pb_devices;
devices.sort([](const auto& a, const auto& b) { return a.id() < b.id() || a.unit() < b.unit(); }); 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()) << " | " s << "| " << device.id() << " | " << device.unit() << " | " << PbDeviceType_Name(device.type()) << " | "
<< (filename.empty() ? "NO MEDIA" : filename) << (filename.empty() ? "NO MEDIA" : filename)
<< (!device.status().removed() && (device.properties().read_only() || device.status().protected_()) ? " (READ-ONLY)" : "") << (!device.status().removed() && (device.properties().read_only() || device.status().protected_()) ? " (READ-ONLY)" : "")
<< endl; << '\n';
} }
s << "+----+-----+------+-------------------------------------"; s << "+----+-----+------+-------------------------------------\n";
return s.str(); return s.str();
} }

View File

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

View File

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

View File

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

View File

@@ -75,10 +75,10 @@ TEST(AbstractControllerTest, ProcessPhase)
controller.ProcessPhase(); controller.ProcessPhase();
controller.SetPhase(BUS::phase_t::reselection); 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); controller.SetPhase(BUS::phase_t::reserved);
EXPECT_THROW(controller.ProcessPhase(), scsi_error_exception); EXPECT_THROW(controller.ProcessPhase(), scsi_exception);
} }
TEST(AbstractControllerTest, DeviceLunLifeCycle) 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" #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) TEST(CommandContext, ReturnLocalizedError)
{ {
MockCommandContext context; CommandContext context("en_US", -1);
EXPECT_FALSE(context.ReturnLocalizedError(LocalizationKey::ERROR_LOG_LEVEL)); 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); ControllerManager controller_manager(bus);
DeviceFactory device_factory; DeviceFactory device_factory;
auto device = device_factory.CreateDevice(controller_manager, UNDEFINED, LUN1, "services"); auto device = device_factory.CreateDevice(controller_manager, UNDEFINED, -1, "services");
controller_manager.AttachToScsiController(ID, device); 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); auto controller = controller_manager.FindController(ID);
EXPECT_NE(nullptr, controller); EXPECT_NE(nullptr, controller);
EXPECT_EQ(1, controller->GetLunCount()); EXPECT_EQ(1, controller->GetLunCount());
@@ -33,9 +36,9 @@ TEST(ControllerManagerTest, LifeCycle)
EXPECT_EQ(nullptr, controller_manager.GetDeviceByIdAndLun(0, 0)); EXPECT_EQ(nullptr, controller_manager.GetDeviceByIdAndLun(0, 0));
device = device_factory.CreateDevice(controller_manager, UNDEFINED, LUN2, "services"); 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 = controller_manager.FindController(ID);
controller_manager.DeleteController(controller); EXPECT_TRUE(controller_manager.DeleteController(controller));
EXPECT_EQ(nullptr, controller_manager.FindController(ID)); EXPECT_EQ(nullptr, controller_manager.FindController(ID));
controller_manager.DeleteAllControllers(); controller_manager.DeleteAllControllers();
@@ -52,7 +55,7 @@ TEST(ControllerManagerTest, ResetAllControllers)
DeviceFactory device_factory; DeviceFactory device_factory;
auto device = device_factory.CreateDevice(controller_manager, UNDEFINED, 0, "services"); 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); auto controller = controller_manager.FindController(ID);
EXPECT_NE(nullptr, controller); EXPECT_NE(nullptr, controller);

View File

@@ -22,10 +22,8 @@ TEST(DiskTest, Dispatch)
controller.AddDevice(disk); controller.AddDevice(disk);
controller.InitCmd(6);
disk->MediumChanged(); disk->MediumChanged();
EXPECT_THROW(disk->Dispatch(scsi_command::eCmdTestUnitReady), scsi_error_exception); EXPECT_THROW(disk->Dispatch(scsi_command::eCmdTestUnitReady), scsi_exception);
} }
TEST(DiskTest, Rezero) TEST(DiskTest, Rezero)
@@ -35,7 +33,7 @@ TEST(DiskTest, Rezero)
controller.AddDevice(disk); 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"; << "REZERO must fail because drive is not ready";
disk->SetReady(true); disk->SetReady(true);
@@ -54,7 +52,7 @@ TEST(DiskTest, FormatUnit)
vector<int>& cmd = controller.InitCmd(6); 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); disk->SetReady(true);
@@ -64,7 +62,7 @@ TEST(DiskTest, FormatUnit)
cmd[1] = 0x10; cmd[1] = 0x10;
cmd[4] = 1; 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) TEST(DiskTest, ReassignBlocks)
@@ -74,7 +72,7 @@ TEST(DiskTest, ReassignBlocks)
controller.AddDevice(disk); 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"; << "REASSIGN must fail because drive is not ready";
disk->SetReady(true); disk->SetReady(true);
@@ -93,15 +91,15 @@ TEST(DiskTest, Seek)
vector<int>& cmd = controller.InitCmd(10); 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"; << "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"; << "SEEK(10) must fail for a medium with 0 blocks";
disk->SetBlockCount(1); 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"; << "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"; << "SEEK(10) must fail because drive is not ready";
disk->SetReady(true); disk->SetReady(true);
@@ -129,23 +127,23 @@ TEST(DiskTest, ReadCapacity)
vector<int>& cmd = controller.InitCmd(16); 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)"; << "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(10) must fail because drive is not ready";
// READ CAPACITY(16), not READ LONG(16) // READ CAPACITY(16), not READ LONG(16)
cmd[1] = 0x10; 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"; << "READ CAPACITY(16) must fail because drive is not ready";
cmd[1] = 0x00; cmd[1] = 0x00;
disk->SetReady(true); 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(10) must fail because the medium has no capacity";
// READ CAPACITY(16), not READ LONG(16) // READ CAPACITY(16), not READ LONG(16)
cmd[1] = 0x10; 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"; << "READ CAPACITY(16) must fail because the medium has no capacity";
cmd[1] = 0x00; cmd[1] = 0x00;
@@ -201,22 +199,22 @@ TEST(DiskTest, ReadWriteLong)
EXPECT_EQ(status::GOOD, controller.GetStatus()); EXPECT_EQ(status::GOOD, controller.GetStatus());
cmd[2] = 1; 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"; << "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"; << "WRITE LONG(10) must fail because the capacity is exceeded";
// READ LONG(16), not READ CAPACITY(16) // READ LONG(16), not READ CAPACITY(16)
cmd[1] = 0x11; 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"; << "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"; << "WRITE LONG(16) must fail because the capacity is exceeded";
cmd[2] = 0; cmd[2] = 0;
cmd[7] = 1; 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"; << "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"; << "WRITE LONG(10) must fail because it currently only supports 0 bytes transfer length";
cmd[7] = 0; cmd[7] = 0;
@@ -233,25 +231,31 @@ TEST(DiskTest, ReadWriteLong)
cmd[13] = 1; cmd[13] = 1;
// READ LONG(16), not READ CAPACITY(16) // READ LONG(16), not READ CAPACITY(16)
cmd[1] = 0x11; 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"; << "READ LONG(16) must fail because it currently only supports 0 bytes transfer length";
cmd[1] = 0x00; 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"; << "WRITE LONG(16) must fail because it currently only supports 0 bytes transfer length";
} }
TEST(DiskTest, ReserveRelease) TEST(DiskTest, Reserve)
{ {
MockAbstractController controller(0); MockAbstractController controller(0);
auto disk = make_shared<MockDisk>(); auto disk = make_shared<MockDisk>();
controller.AddDevice(disk); controller.AddDevice(disk);
controller.InitCmd(6);
EXPECT_CALL(controller, Status()).Times(1); EXPECT_CALL(controller, Status()).Times(1);
EXPECT_TRUE(disk->Dispatch(scsi_command::eCmdReserve6)); EXPECT_TRUE(disk->Dispatch(scsi_command::eCmdReserve6));
EXPECT_EQ(status::GOOD, controller.GetStatus()); 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_CALL(controller, Status()).Times(1);
EXPECT_TRUE(disk->Dispatch(scsi_command::eCmdRelease6)); EXPECT_TRUE(disk->Dispatch(scsi_command::eCmdRelease6));
@@ -272,16 +276,16 @@ TEST(DiskTest, SendDiagnostic)
EXPECT_EQ(status::GOOD, controller.GetStatus()); EXPECT_EQ(status::GOOD, controller.GetStatus());
cmd[1] = 0x10; 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"; << "SEND DIAGNOSTIC must fail because PF bit is not supported";
cmd[1] = 0; cmd[1] = 0;
cmd[3] = 1; 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"; << "SEND DIAGNOSTIC must fail because parameter list is not supported";
cmd[3] = 0; cmd[3] = 0;
cmd[4] = 1; 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"; << "SEND DIAGNOSTIC must fail because parameter list is not supported";
} }
@@ -294,7 +298,7 @@ TEST(DiskTest, PreventAllowMediumRemoval)
vector<int>& cmd = controller.InitCmd(6); 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"; << "REMOVAL must fail because drive is not ready";
disk->SetReady(true); disk->SetReady(true);
@@ -318,15 +322,11 @@ TEST(DiskTest, SynchronizeCache)
controller.AddDevice(disk); controller.AddDevice(disk);
controller.InitCmd(10);
EXPECT_CALL(*disk, FlushCache()).Times(1); EXPECT_CALL(*disk, FlushCache()).Times(1);
EXPECT_CALL(controller, Status()).Times(1); EXPECT_CALL(controller, Status()).Times(1);
EXPECT_TRUE(disk->Dispatch(scsi_command::eCmdSynchronizeCache10)); EXPECT_TRUE(disk->Dispatch(scsi_command::eCmdSynchronizeCache10));
EXPECT_EQ(status::GOOD, controller.GetStatus()); EXPECT_EQ(status::GOOD, controller.GetStatus());
controller.InitCmd(16);
EXPECT_CALL(*disk, FlushCache()).Times(1); EXPECT_CALL(*disk, FlushCache()).Times(1);
EXPECT_CALL(controller, Status()).Times(1); EXPECT_CALL(controller, Status()).Times(1);
EXPECT_TRUE(disk->Dispatch(scsi_command::eCmdSynchronizeCache16)); EXPECT_TRUE(disk->Dispatch(scsi_command::eCmdSynchronizeCache16));
@@ -410,3 +410,46 @@ TEST(DiskTest, BlockCount)
disk.SetBlockCount(0x1234567887654321); disk.SetBlockCount(0x1234567887654321);
EXPECT_EQ(0x1234567887654321, disk.GetBlockCount()); 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 <gmock/gmock.h>
#include "test_shared.h"
#include "controllers/scsi_controller.h" #include "controllers/scsi_controller.h"
#include "devices/primary_device.h" #include "devices/primary_device.h"
#include "devices/scsihd.h" #include "devices/scsihd.h"
@@ -20,7 +21,9 @@
#include "devices/host_services.h" #include "devices/host_services.h"
#include "rascsi/command_context.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: public:
@@ -78,8 +81,12 @@ public:
using PhaseHandler::PhaseHandler; 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, Reset);
FRIEND_TEST(AbstractControllerTest, ProcessPhase); FRIEND_TEST(AbstractControllerTest, ProcessPhase);
FRIEND_TEST(AbstractControllerTest, DeviceLunLifeCycle); FRIEND_TEST(AbstractControllerTest, DeviceLunLifeCycle);
@@ -93,6 +100,10 @@ class MockAbstractController final : public AbstractController //NOSONAR Having
FRIEND_TEST(PrimaryDeviceTest, RequestSense); FRIEND_TEST(PrimaryDeviceTest, RequestSense);
FRIEND_TEST(PrimaryDeviceTest, ReportLuns); FRIEND_TEST(PrimaryDeviceTest, ReportLuns);
FRIEND_TEST(PrimaryDeviceTest, UnknownCommand); 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, Dispatch);
FRIEND_TEST(DiskTest, Rezero); FRIEND_TEST(DiskTest, Rezero);
FRIEND_TEST(DiskTest, FormatUnit); FRIEND_TEST(DiskTest, FormatUnit);
@@ -100,7 +111,8 @@ class MockAbstractController final : public AbstractController //NOSONAR Having
FRIEND_TEST(DiskTest, Seek); FRIEND_TEST(DiskTest, Seek);
FRIEND_TEST(DiskTest, ReadCapacity); FRIEND_TEST(DiskTest, ReadCapacity);
FRIEND_TEST(DiskTest, ReadWriteLong); FRIEND_TEST(DiskTest, ReadWriteLong);
FRIEND_TEST(DiskTest, ReserveRelease); FRIEND_TEST(DiskTest, Reserve);
FRIEND_TEST(DiskTest, Release);
FRIEND_TEST(DiskTest, SendDiagnostic); FRIEND_TEST(DiskTest, SendDiagnostic);
FRIEND_TEST(DiskTest, PreventAllowMediumRemoval); FRIEND_TEST(DiskTest, PreventAllowMediumRemoval);
FRIEND_TEST(DiskTest, SynchronizeCache); FRIEND_TEST(DiskTest, SynchronizeCache);
@@ -128,10 +140,12 @@ public:
} }
~MockAbstractController() override = default; ~MockAbstractController() override = default;
vector<int>& InitCmd(int size) { return AbstractController::InitCmd(size); } //NOSONAR Hides function on purpose
MockBus bus; MockBus bus;
}; };
class MockScsiController final : public ScsiController class MockScsiController : public ScsiController
{ {
FRIEND_TEST(ScsiControllerTest, RequestSense); FRIEND_TEST(ScsiControllerTest, RequestSense);
FRIEND_TEST(PrimaryDeviceTest, RequestSense); FRIEND_TEST(PrimaryDeviceTest, RequestSense);
@@ -150,7 +164,7 @@ public:
MockBus bus; MockBus bus;
}; };
class MockDevice final : public Device class MockDevice : public Device
{ {
FRIEND_TEST(DeviceTest, Params); FRIEND_TEST(DeviceTest, Params);
FRIEND_TEST(DeviceTest, StatusCode); FRIEND_TEST(DeviceTest, StatusCode);
@@ -167,7 +181,7 @@ public:
~MockDevice() override = default; ~MockDevice() override = default;
}; };
class MockPrimaryDevice final : public PrimaryDevice class MockPrimaryDevice : public PrimaryDevice
{ {
FRIEND_TEST(PrimaryDeviceTest, PhaseChange); FRIEND_TEST(PrimaryDeviceTest, PhaseChange);
FRIEND_TEST(PrimaryDeviceTest, TestUnitReady); FRIEND_TEST(PrimaryDeviceTest, TestUnitReady);
@@ -185,17 +199,19 @@ public:
~MockPrimaryDevice() override = default; ~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) {} public:
~MockModePageDevice() override = default;
MOCK_METHOD(vector<byte>, InquiryInternal, (), (const)); MOCK_METHOD(vector<byte>, InquiryInternal, (), (const));
MOCK_METHOD(int, ModeSense6, (const vector<int>&, vector<BYTE>&), (const override)); MOCK_METHOD(int, ModeSense6, (const vector<int>&, vector<BYTE>&), (const override));
MOCK_METHOD(int, ModeSense10, (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 { void SetUpModePages(map<int, vector<byte>>& pages, int page, bool) const override {
// Return dummy data for other pages than page 0 // Return dummy data for other pages than page 0
if (page) { 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, Rezero);
FRIEND_TEST(DiskTest, FormatUnit); FRIEND_TEST(DiskTest, FormatUnit);
@@ -220,6 +236,7 @@ class MockDisk final : public Disk
FRIEND_TEST(DiskTest, ReadDefectData); FRIEND_TEST(DiskTest, ReadDefectData);
FRIEND_TEST(DiskTest, SectorSize); FRIEND_TEST(DiskTest, SectorSize);
FRIEND_TEST(DiskTest, BlockCount); FRIEND_TEST(DiskTest, BlockCount);
FRIEND_TEST(DiskTest, GetIdsForReservedFile);
public: public:
@@ -230,41 +247,39 @@ public:
~MockDisk() override = default; ~MockDisk() override = default;
}; };
class MockSCSIHD final : public SCSIHD class MockSCSIHD : public SCSIHD
{ {
FRIEND_TEST(DiskTest, ConfiguredSectorSize); FRIEND_TEST(DiskTest, ConfiguredSectorSize);
FRIEND_TEST(ModePagesTest, SCSIHD_SetUpModePages); FRIEND_TEST(ScsiHdTest, SetUpModePages);
FRIEND_TEST(RascsiExecutorTest, SetSectorSize); FRIEND_TEST(RascsiExecutorTest, SetSectorSize);
using SCSIHD::SCSIHD; 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); FRIEND_TEST(ScsiHdNecTest, SetUpModePages);
MOCK_METHOD(void, FlushCache, (), (override));
using SCSIHD_NEC::SCSIHD_NEC; 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; using SCSICD::SCSICD;
}; };
class MockSCSIMO final : public SCSIMO class MockSCSIMO : public SCSIMO
{ {
FRIEND_TEST(ModePagesTest, SCSIMO_SetUpModePages); FRIEND_TEST(ScsiMoTest, SetUpModePages);
using SCSIMO::SCSIMO; using SCSIMO::SCSIMO;
}; };
class MockHostServices final : public HostServices class MockHostServices : public HostServices
{ {
FRIEND_TEST(ModePagesTest, HostServices_SetUpModePages); FRIEND_TEST(HostServicesTest, SetUpModePages);
using HostServices::HostServices; 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); handler.SetPhase(BUS::phase_t::selection);
EXPECT_TRUE(handler.IsSelection()); 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); handler.SetPhase(BUS::phase_t::busfree);
EXPECT_TRUE(handler.IsBusFree()); 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); handler.SetPhase(BUS::phase_t::command);
EXPECT_TRUE(handler.IsCommand()); 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); handler.SetPhase(BUS::phase_t::status);
EXPECT_TRUE(handler.IsStatus()); 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); handler.SetPhase(BUS::phase_t::datain);
EXPECT_TRUE(handler.IsDataIn()); 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); handler.SetPhase(BUS::phase_t::dataout);
EXPECT_TRUE(handler.IsDataOut()); 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); handler.SetPhase(BUS::phase_t::msgin);
EXPECT_TRUE(handler.IsMsgIn()); 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); handler.SetPhase(BUS::phase_t::msgout);
EXPECT_TRUE(handler.IsMsgOut()); 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->SetAttn(true);
device->SetReady(false); device->SetReady(false);
EXPECT_CALL(controller, DataIn()).Times(0); 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->SetReset(false);
EXPECT_CALL(controller, DataIn()).Times(0); 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->SetReset(true);
device->SetAttn(false); device->SetAttn(false);
EXPECT_CALL(controller, DataIn()).Times(0); 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->SetReset(false);
device->SetAttn(true); device->SetAttn(true);
EXPECT_CALL(controller, DataIn()).Times(0); 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); device->SetAttn(false);
EXPECT_CALL(controller, DataIn()).Times(0); 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); device->SetReady(true);
EXPECT_CALL(controller, Status()).Times(1); EXPECT_CALL(controller, Status()).Times(1);
@@ -84,7 +84,7 @@ TEST(PrimaryDeviceTest, TestUnitReady)
TEST(PrimaryDeviceTest, Inquiry) TEST(PrimaryDeviceTest, Inquiry)
{ {
MockAbstractController controller(0); NiceMock<MockAbstractController> controller(0);
auto device = make_shared<MockPrimaryDevice>(0); auto device = make_shared<MockPrimaryDevice>(0);
device->SetController(&controller); device->SetController(&controller);
@@ -126,11 +126,11 @@ TEST(PrimaryDeviceTest, Inquiry)
cmd[1] = 0x01; cmd[1] = 0x01;
EXPECT_CALL(controller, DataIn()).Times(0); 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; cmd[2] = 0x01;
EXPECT_CALL(controller, DataIn()).Times(0); 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[1] = 0x00;
cmd[2] = 0x00; cmd[2] = 0x00;
@@ -145,7 +145,7 @@ TEST(PrimaryDeviceTest, Inquiry)
TEST(PrimaryDeviceTest, RequestSense) TEST(PrimaryDeviceTest, RequestSense)
{ {
MockAbstractController controller(0); NiceMock<MockAbstractController> controller(0);
auto device = make_shared<MockPrimaryDevice>(0); auto device = make_shared<MockPrimaryDevice>(0);
controller.AddDevice(device); controller.AddDevice(device);
@@ -155,7 +155,7 @@ TEST(PrimaryDeviceTest, RequestSense)
cmd[4] = 255; cmd[4] = 255;
device->SetReady(false); 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); device->SetReady(true);
EXPECT_CALL(controller, DataIn()).Times(1); EXPECT_CALL(controller, DataIn()).Times(1);
@@ -206,7 +206,7 @@ TEST(PrimaryDeviceTest, ReportLuns)
EXPECT_EQ(LUN2, buffer[23]) << "Wrong LUN2 number"; EXPECT_EQ(LUN2, buffer[23]) << "Wrong LUN2 number";
cmd[2] = 0x01; 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) TEST(PrimaryDeviceTest, UnknownCommand)
@@ -216,7 +216,6 @@ TEST(PrimaryDeviceTest, UnknownCommand)
controller.AddDevice(device); controller.AddDevice(device);
controller.InitCmd(1);
EXPECT_FALSE(device->Dispatch((scsi_command)0xFF)); EXPECT_FALSE(device->Dispatch((scsi_command)0xFF));
} }

View File

@@ -16,12 +16,50 @@ using namespace rascsi_interface;
TEST(ProtobufSerializerTest, SerializeMessage) TEST(ProtobufSerializerTest, SerializeMessage)
{ {
PbResult message; PbResult result;
ProtobufSerializer serializer; ProtobufSerializer serializer;
int fd = open("/dev/null", O_WRONLY); int fd = open("/dev/zero", O_RDONLY);
ASSERT_NE(-1, fd); EXPECT_NE(-1, fd);
serializer.SerializeMessage(fd, message); 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); close(fd);
EXPECT_THROW(serializer.SerializeMessage(-1, message), io_exception);
} }

View File

@@ -9,10 +9,10 @@
#include "mocks.h" #include "mocks.h"
#include "rascsi_interface.pb.h" #include "rascsi_interface.pb.h"
#include "command_util.h" #include "protobuf_util.h"
using namespace rascsi_interface; using namespace rascsi_interface;
using namespace command_util; using namespace protobuf_util;
void TestSpecialDevice(const string& name) void TestSpecialDevice(const string& name)
{ {
@@ -59,3 +59,26 @@ TEST(CommandUtil, ParseParameters)
TestSpecialDevice("printer"); TestSpecialDevice("printer");
TestSpecialDevice("services"); 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) TEST(RascsiExceptionsTest, ScsiErrorException)
{ {
try { 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(sense_key::ABORTED_COMMAND, e.get_sense_key());
EXPECT_EQ(asc::NO_ADDITIONAL_SENSE_INFORMATION, e.get_asc()); EXPECT_EQ(asc::NO_ADDITIONAL_SENSE_INFORMATION, e.get_asc());
EXPECT_EQ(status::CHECK_CONDITION, e.get_status()); EXPECT_EQ(status::CHECK_CONDITION, e.get_status());
} }
try { 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(sense_key::UNIT_ATTENTION, e.get_sense_key());
EXPECT_EQ(asc::NO_ADDITIONAL_SENSE_INFORMATION, e.get_asc()); EXPECT_EQ(asc::NO_ADDITIONAL_SENSE_INFORMATION, e.get_asc());
EXPECT_EQ(status::CHECK_CONDITION, e.get_status()); EXPECT_EQ(status::CHECK_CONDITION, e.get_status());
} }
try { 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(sense_key::UNIT_ATTENTION, e.get_sense_key());
EXPECT_EQ(asc::LBA_OUT_OF_RANGE, e.get_asc()); EXPECT_EQ(asc::LBA_OUT_OF_RANGE, e.get_asc());
EXPECT_EQ(status::CHECK_CONDITION, e.get_status()); EXPECT_EQ(status::CHECK_CONDITION, e.get_status());
} }
try { 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(sense_key::UNIT_ATTENTION, e.get_sense_key());
EXPECT_EQ(asc::LBA_OUT_OF_RANGE, e.get_asc()); EXPECT_EQ(asc::LBA_OUT_OF_RANGE, e.get_asc());
EXPECT_EQ(status::BUSY, e.get_status()); EXPECT_EQ(status::BUSY, e.get_status());

View File

@@ -8,7 +8,7 @@
//--------------------------------------------------------------------------- //---------------------------------------------------------------------------
#include "mocks.h" #include "mocks.h"
#include "command_util.h" #include "protobuf_util.h"
#include "controllers/controller_manager.h" #include "controllers/controller_manager.h"
#include "devices/device_factory.h" #include "devices/device_factory.h"
#include "rascsi/command_context.h" #include "rascsi/command_context.h"
@@ -17,7 +17,7 @@
#include "rascsi/rascsi_executor.h" #include "rascsi/rascsi_executor.h"
using namespace rascsi_interface; using namespace rascsi_interface;
using namespace command_util; using namespace protobuf_util;
TEST(RascsiExecutorTest, ProcessCmd) 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_TRUE(GetAsInt("1234", result));
EXPECT_EQ(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 "mocks.h"
#include "rascsi_exceptions.h"
#include "devices/scsi_command_util.h" #include "devices/scsi_command_util.h"
using namespace scsi_command_util; 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) TEST(ScsiCommandUtilTest, EnrichFormatPage)
{ {
const int SECTOR_SIZE = 512; 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