mirror of
https://github.com/akuker/RASCSI.git
synced 2025-04-16 12:37:06 +00:00
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:
parent
62e287c96d
commit
ca23d9b7a3
@ -85,14 +85,16 @@ SRC_PROTOC = \
|
||||
SRC_PROTOBUF = \
|
||||
rascsi_interface.pb.cpp
|
||||
|
||||
SRC_RASCSI_CORE = \
|
||||
scsi.cpp \
|
||||
filepath.cpp \
|
||||
fileio.cpp \
|
||||
SRC_SHARED = \
|
||||
rascsi_version.cpp \
|
||||
rasutil.cpp \
|
||||
command_util.cpp \
|
||||
protobuf_util.cpp \
|
||||
protobuf_serializer.cpp
|
||||
|
||||
SRC_RASCSI_CORE = \
|
||||
bus.cpp \
|
||||
filepath.cpp \
|
||||
fileio.cpp
|
||||
SRC_RASCSI_CORE += $(shell find ./rascsi -name '*.cpp')
|
||||
SRC_RASCSI_CORE += $(shell find ./controllers -name '*.cpp')
|
||||
SRC_RASCSI_CORE += $(shell find ./devices -name '*.cpp')
|
||||
@ -102,22 +104,18 @@ SRC_RASCSI = rascsi.cpp
|
||||
|
||||
SRC_SCSIMON = \
|
||||
scsimon.cpp \
|
||||
scsi.cpp \
|
||||
bus.cpp \
|
||||
rascsi_version.cpp
|
||||
SRC_SCSIMON += $(shell find ./monitor -name '*.cpp')
|
||||
SRC_SCSIMON += $(shell find ./hal -name '*.cpp')
|
||||
|
||||
SRC_RASCTL = \
|
||||
rasctl.cpp\
|
||||
rascsi_version.cpp \
|
||||
rasutil.cpp \
|
||||
command_util.cpp \
|
||||
protobuf_serializer.cpp
|
||||
SRC_RASCTL += $(shell find ./rasctl -name '*.cpp')
|
||||
SRC_RASCTL_CORE = $(shell find ./rasctl -name '*.cpp')
|
||||
|
||||
SRC_RASCTL = rasctl.cpp
|
||||
|
||||
SRC_RASDUMP = \
|
||||
rasdump.cpp \
|
||||
scsi.cpp \
|
||||
bus.cpp \
|
||||
filepath.cpp \
|
||||
fileio.cpp \
|
||||
rascsi_version.cpp
|
||||
@ -134,10 +132,12 @@ vpath ./$(BINDIR)
|
||||
|
||||
OBJ_RASCSI_CORE := $(addprefix $(OBJDIR)/,$(notdir $(SRC_RASCSI_CORE:%.cpp=%.o)))
|
||||
OBJ_RASCSI := $(addprefix $(OBJDIR)/,$(notdir $(SRC_RASCSI:%.cpp=%.o)))
|
||||
OBJ_RASCTL_CORE := $(addprefix $(OBJDIR)/,$(notdir $(SRC_RASCTL_CORE:%.cpp=%.o)))
|
||||
OBJ_RASCTL := $(addprefix $(OBJDIR)/,$(notdir $(SRC_RASCTL:%.cpp=%.o)))
|
||||
OBJ_RASDUMP := $(addprefix $(OBJDIR)/,$(notdir $(SRC_RASDUMP:%.cpp=%.o)))
|
||||
OBJ_SCSIMON := $(addprefix $(OBJDIR)/,$(notdir $(SRC_SCSIMON:%.cpp=%.o)))
|
||||
OBJ_RASCSI_TEST := $(addprefix $(OBJDIR)/,$(notdir $(SRC_RASCSI_TEST:%.cpp=%.o)))
|
||||
OBJ_SHARED := $(addprefix $(OBJDIR)/,$(notdir $(SRC_SHARED:%.cpp=%.o)))
|
||||
OBJ_PROTOBUF := $(addprefix $(OBJDIR)/,$(notdir $(SRC_PROTOBUF:%.cpp=%.o)))
|
||||
|
||||
GEN_PROTOBUF := $(SRC_PROTOBUF) rascsi_interface.pb.h
|
||||
@ -145,7 +145,7 @@ GEN_PROTOBUF := $(SRC_PROTOBUF) rascsi_interface.pb.h
|
||||
|
||||
# The following will include all of the auto-generated dependency files (*.d)
|
||||
# if they exist. This will trigger a rebuild of a source file if a header changes
|
||||
ALL_DEPS := $(patsubst %.o,%.d,$(OBJ_RASCSI_CORE) $(OBJ_RASCSI) $(OBJ_RASCTL) $(OBJ_SCSIMON) $(OBJ_RASCSI_TEST))
|
||||
ALL_DEPS := $(patsubst %.o,%.d,$(OBJ_RASCSI_CORE) $(OBJ_RASCTL_CORE) $(OBJ_RASCSI) $(OBJ_RASCTL) $(OBJ_SCSIMON) $(OBJ_RASCSI_TEST))
|
||||
-include $(ALL_DEPS)
|
||||
|
||||
$(OBJDIR) $(BINDIR):
|
||||
@ -186,13 +186,13 @@ lcov: test
|
||||
|
||||
docs: $(DOC_DIR)/rascsi_man_page.txt $(DOC_DIR)/rasctl_man_page.txt $(DOC_DIR)/scsimon_man_page.txt
|
||||
|
||||
$(SRC_RASCSI_CORE): $(SRC_PROTOBUF)
|
||||
$(SRC_SHARED): $(SRC_PROTOBUF)
|
||||
|
||||
$(BINDIR)/$(RASCSI): $(SRC_PROTOBUF) $(OBJ_RASCSI_CORE) $(OBJ_RASCSI) $(OBJ_PROTOBUF) | $(BINDIR)
|
||||
$(CXX) $(CXXFLAGS) -o $@ $(OBJ_RASCSI_CORE) $(OBJ_RASCSI) $(OBJ_PROTOBUF) -lpthread -lpcap -lprotobuf -lstdc++fs
|
||||
$(BINDIR)/$(RASCSI): $(SRC_PROTOBUF) $(OBJ_RASCSI_CORE) $(OBJ_RASCSI) $(OBJ_SHARED) $(OBJ_PROTOBUF) | $(BINDIR)
|
||||
$(CXX) $(CXXFLAGS) -o $@ $(OBJ_RASCSI_CORE) $(OBJ_RASCSI) $(OBJ_SHARED) $(OBJ_PROTOBUF) -lpthread -lpcap -lprotobuf -lstdc++fs
|
||||
|
||||
$(BINDIR)/$(RASCTL): $(SRC_PROTOBUF) $(OBJ_RASCTL) $(OBJ_PROTOBUF) | $(BINDIR)
|
||||
$(CXX) $(CXXFLAGS) -o $@ $(OBJ_RASCTL) $(OBJ_PROTOBUF) -lpthread -lprotobuf
|
||||
$(BINDIR)/$(RASCTL): $(SRC_PROTOBUF) $(OBJ_RASCTL_CORE) $(OBJ_RASCTL) $(OBJ_SHARED) $(OBJ_PROTOBUF) | $(BINDIR)
|
||||
$(CXX) $(CXXFLAGS) -o $@ $(OBJ_RASCTL_CORE) $(OBJ_RASCTL) $(OBJ_SHARED) $(OBJ_PROTOBUF) -lpthread -lprotobuf
|
||||
|
||||
$(BINDIR)/$(RASDUMP): $(OBJ_RASDUMP) | $(BINDIR)
|
||||
$(CXX) $(CXXFLAGS) -o $@ $(OBJ_RASDUMP)
|
||||
@ -200,8 +200,8 @@ $(BINDIR)/$(RASDUMP): $(OBJ_RASDUMP) | $(BINDIR)
|
||||
$(BINDIR)/$(SCSIMON): $(OBJ_SCSIMON) | $(BINDIR)
|
||||
$(CXX) $(CXXFLAGS) -o $@ $(OBJ_SCSIMON) -lpthread
|
||||
|
||||
$(BINDIR)/$(RASCSI_TEST): $(SRC_PROTOBUF) $(OBJ_RASCSI_CORE) $(OBJ_RASCSI_TEST) $(OBJ_PROTOBUF) | $(BINDIR)
|
||||
$(CXX) $(CXXFLAGS) -o $@ $(OBJ_RASCSI_CORE) $(OBJ_RASCSI_TEST) $(OBJ_PROTOBUF) -lpthread -lpcap -lprotobuf -lstdc++fs -lgmock -lgtest
|
||||
$(BINDIR)/$(RASCSI_TEST): $(SRC_PROTOBUF) $(OBJ_RASCSI_CORE) $(OBJ_RASCTL_CORE) $(OBJ_RASCSI_TEST) $(OBJ_RASCTL_TEST) $(OBJ_SHARED) $(OBJ_PROTOBUF) | $(BINDIR)
|
||||
$(CXX) $(CXXFLAGS) -o $@ $(OBJ_RASCSI_CORE) $(OBJ_RASCTL_CORE) $(OBJ_RASCSI_TEST) $(OBJ_SHARED) $(OBJ_PROTOBUF) -lpthread -lpcap -lprotobuf -lstdc++fs -lgmock -lgtest
|
||||
|
||||
|
||||
# Phony rules for building individual utilities
|
||||
|
@ -1,11 +1,10 @@
|
||||
//---------------------------------------------------------------------------
|
||||
//
|
||||
// X68000 EMULATOR "XM6"
|
||||
// X68000 EMULATOR "XM6"
|
||||
//
|
||||
// Copyright (C) 2001-2006 PI.(ytanaka@ipc-tokai.or.jp)
|
||||
// Copyright (C) 2014-2020 GIMONS
|
||||
//
|
||||
// [ SCSI Common Functionality ]
|
||||
// Copyright (C) 2001-2006 PI.(ytanaka@ipc-tokai.or.jp)
|
||||
// Copyright (C) 2014-2020 GIMONS
|
||||
// Copyright (C) 2022 Uwe Seimet
|
||||
//
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
@ -31,9 +30,9 @@ BUS::phase_t BUS::GetPhase()
|
||||
}
|
||||
|
||||
// Get target phase from bus signal line
|
||||
int mci = GetMSG() ? 0x04 : 0x00;
|
||||
mci |= GetCD() ? 0x02 : 0x00;
|
||||
mci |= GetIO() ? 0x01 : 0x00;
|
||||
int mci = GetMSG() ? 0b100 : 0b000;
|
||||
mci |= GetCD() ? 0b010 : 0b000;
|
||||
mci |= GetIO() ? 0b001 : 0b000;
|
||||
return GetPhase(mci);
|
||||
}
|
||||
|
@ -59,7 +59,7 @@ public:
|
||||
static const char* GetPhaseStrRaw(phase_t current_phase);
|
||||
|
||||
// Extract as specific pin field from a raw data capture
|
||||
static inline DWORD GetPinRaw(DWORD raw_data, DWORD pin_num)
|
||||
static inline uint32_t GetPinRaw(uint32_t raw_data, uint32_t pin_num)
|
||||
{
|
||||
return ((raw_data >> pin_num) & 1);
|
||||
}
|
||||
|
@ -88,7 +88,7 @@ void AbstractController::ProcessPhase()
|
||||
|
||||
default:
|
||||
LOGERROR("Cannot process phase %s", BUS::GetPhaseStrRaw(GetPhase()))
|
||||
throw scsi_error_exception();
|
||||
throw scsi_exception();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -11,6 +11,7 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "scsi.h"
|
||||
#include "bus.h"
|
||||
#include "phase_handler.h"
|
||||
#include <unordered_set>
|
||||
|
@ -9,7 +9,6 @@
|
||||
|
||||
#include "devices/device_factory.h"
|
||||
#include "devices/primary_device.h"
|
||||
#include "devices/file_support.h"
|
||||
#include "scsi_controller.h"
|
||||
#include "controller_manager.h"
|
||||
|
||||
@ -20,15 +19,21 @@ bool ControllerManager::AttachToScsiController(int id, shared_ptr<PrimaryDevice>
|
||||
auto controller = FindController(id);
|
||||
if (controller == nullptr) {
|
||||
controller = make_shared<ScsiController>(bus, id);
|
||||
controllers[id] = controller;
|
||||
if (controller->AddDevice(device)) {
|
||||
controllers[id] = controller;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
return controller->AddDevice(device);
|
||||
}
|
||||
|
||||
void ControllerManager::DeleteController(shared_ptr<AbstractController> controller)
|
||||
bool ControllerManager::DeleteController(shared_ptr<AbstractController> controller)
|
||||
{
|
||||
controllers.erase(controller->GetTargetId());
|
||||
return controllers.erase(controller->GetTargetId()) == 1;
|
||||
}
|
||||
|
||||
shared_ptr<AbstractController> ControllerManager::IdentifyController(int data) const
|
||||
@ -53,7 +58,7 @@ unordered_set<shared_ptr<PrimaryDevice>> ControllerManager::GetAllDevices() cons
|
||||
unordered_set<shared_ptr<PrimaryDevice>> devices;
|
||||
|
||||
for (const auto& [id, controller] : controllers) {
|
||||
auto d = controller->GetDevices();
|
||||
const auto& d = controller->GetDevices();
|
||||
devices.insert(d.begin(), d.end());
|
||||
}
|
||||
|
||||
|
@ -36,7 +36,7 @@ public:
|
||||
static const int DEVICE_MAX = 8;
|
||||
|
||||
bool AttachToScsiController(int, shared_ptr<PrimaryDevice>);
|
||||
void DeleteController(shared_ptr<AbstractController>);
|
||||
bool DeleteController(shared_ptr<AbstractController>);
|
||||
shared_ptr<AbstractController> IdentifyController(int) const;
|
||||
shared_ptr<AbstractController> FindController(int) const;
|
||||
unordered_set<shared_ptr<PrimaryDevice>> GetAllDevices() const;
|
||||
|
@ -79,7 +79,7 @@ BUS::phase_t ScsiController::Process(int id)
|
||||
try {
|
||||
ProcessPhase();
|
||||
}
|
||||
catch(const scsi_error_exception&) {
|
||||
catch(const scsi_exception&) {
|
||||
// Any exception should have been handled during the phase processing
|
||||
assert(false);
|
||||
|
||||
@ -198,8 +198,8 @@ void ScsiController::Command()
|
||||
bus.SetCD(true);
|
||||
bus.SetIO(false);
|
||||
|
||||
int actual_count = bus.CommandHandShake(GetBuffer().data());
|
||||
int command_byte_count = GPIOBUS::GetCommandByteCount(GetBuffer()[0]);
|
||||
const int actual_count = bus.CommandHandShake(GetBuffer().data());
|
||||
const int command_byte_count = GPIOBUS::GetCommandByteCount(GetBuffer()[0]);
|
||||
|
||||
// If not able to receive all, move to the status phase
|
||||
if (actual_count != command_byte_count) {
|
||||
@ -267,10 +267,10 @@ void ScsiController::Execute()
|
||||
if (!device->Dispatch(GetOpcode())) {
|
||||
LOGTRACE("ID %d LUN %d received unsupported command: $%02X", GetTargetId(), lun, (int)GetOpcode())
|
||||
|
||||
throw scsi_error_exception(sense_key::ILLEGAL_REQUEST, asc::INVALID_COMMAND_OPERATION_CODE);
|
||||
throw scsi_exception(sense_key::ILLEGAL_REQUEST, asc::INVALID_COMMAND_OPERATION_CODE);
|
||||
}
|
||||
}
|
||||
catch(const scsi_error_exception& e) { //NOSONAR This exception is handled properly
|
||||
catch(const scsi_exception& e) { //NOSONAR This exception is handled properly
|
||||
Error(e.get_sense_key(), e.get_asc(), e.get_status());
|
||||
|
||||
// Fall through
|
||||
@ -459,10 +459,9 @@ void ScsiController::Error(sense_key sense_key, asc asc, status status)
|
||||
}
|
||||
|
||||
if (sense_key != sense_key::NO_SENSE || asc != asc::NO_ADDITIONAL_SENSE_INFORMATION) {
|
||||
LOGDEBUG("Error status: Sense Key $%02X, ASC $%02X, ASCQ $%02X",
|
||||
(int)sense_key << 16, (int)asc << 8, (int)asc & 0xff)
|
||||
LOGDEBUG("Error status: Sense Key $%02X, ASC $%02X", (int)sense_key, (int)asc)
|
||||
|
||||
// Set Sense Key and ASC for a subsequent REQUEST SENSE
|
||||
// Set Sense Key and ASC for a subsequent REQUEST SENSE
|
||||
GetDeviceForLun(lun)->SetStatusCode(((int)sense_key << 16) | ((int)asc << 8));
|
||||
}
|
||||
|
||||
@ -485,7 +484,7 @@ void ScsiController::Send()
|
||||
|
||||
// TODO The delay has to be taken from ctrl.unit[lun], but as there are currently no Daynaport drivers for
|
||||
// LUNs other than 0 this work-around works.
|
||||
if (int len = bus.SendHandShake(GetBuffer().data() + ctrl.offset, ctrl.length,
|
||||
if (const int len = bus.SendHandShake(GetBuffer().data() + ctrl.offset, ctrl.length,
|
||||
HasDeviceForLun(0) ? GetDeviceForLun(0)->GetSendDelay() : 0);
|
||||
len != (int)ctrl.length) {
|
||||
// If you cannot send all, move to status phase
|
||||
@ -798,7 +797,7 @@ void ScsiController::FlushUnit()
|
||||
try {
|
||||
disk->ModeSelect(ctrl.cmd, GetBuffer(), GetOffset());
|
||||
}
|
||||
catch(const scsi_error_exception& e) {
|
||||
catch(const scsi_exception& e) {
|
||||
LOGWARN("Error occured while processing Mode Select command %02X\n", (int)GetOpcode())
|
||||
Error(e.get_sense_key(), e.get_asc(), e.get_status());
|
||||
return;
|
||||
@ -841,7 +840,7 @@ bool ScsiController::XferIn(vector<BYTE>& buf)
|
||||
try {
|
||||
ctrl.length = (dynamic_pointer_cast<Disk>(GetDeviceForLun(lun)))->Read(ctrl.cmd, buf, ctrl.next);
|
||||
}
|
||||
catch(const scsi_error_exception&) {
|
||||
catch(const scsi_exception&) {
|
||||
// If there is an error, go to the status phase
|
||||
return false;
|
||||
}
|
||||
@ -881,7 +880,7 @@ bool ScsiController::XferOutBlockOriented(bool cont)
|
||||
try {
|
||||
disk->ModeSelect(ctrl.cmd, GetBuffer(), GetOffset());
|
||||
}
|
||||
catch(const scsi_error_exception& e) {
|
||||
catch(const scsi_exception& e) {
|
||||
Error(e.get_sense_key(), e.get_asc(), e.get_status());
|
||||
return false;
|
||||
}
|
||||
@ -919,7 +918,7 @@ bool ScsiController::XferOutBlockOriented(bool cont)
|
||||
try {
|
||||
disk->Write(ctrl.cmd, GetBuffer(), ctrl.next - 1);
|
||||
}
|
||||
catch(const scsi_error_exception& e) {
|
||||
catch(const scsi_exception& e) {
|
||||
Error(e.get_sense_key(), e.get_asc(), e.get_status());
|
||||
|
||||
// Write failed
|
||||
@ -936,7 +935,7 @@ bool ScsiController::XferOutBlockOriented(bool cont)
|
||||
try {
|
||||
ctrl.length = disk->WriteCheck(ctrl.next - 1);
|
||||
}
|
||||
catch(const scsi_error_exception&) {
|
||||
catch(const scsi_exception&) {
|
||||
// Cannot write
|
||||
return false;
|
||||
}
|
||||
@ -976,7 +975,7 @@ void ScsiController::ParseMessage()
|
||||
{
|
||||
int i = 0;
|
||||
while (i < scsi.msc) {
|
||||
BYTE message_type = scsi.msb[i];
|
||||
const BYTE message_type = scsi.msb[i];
|
||||
|
||||
if (message_type == 0x06) {
|
||||
LOGTRACE("Received ABORT message")
|
||||
@ -1064,7 +1063,7 @@ int ScsiController::GetEffectiveLun() const
|
||||
|
||||
void ScsiController::Sleep()
|
||||
{
|
||||
if (uint32_t time = SysTimer::GetTimerLow() - execstart; time < MIN_EXEC_TIME) {
|
||||
if (const uint32_t time = SysTimer::GetTimerLow() - execstart; time < MIN_EXEC_TIME) {
|
||||
SysTimer::SleepUsec(MIN_EXEC_TIME - time);
|
||||
}
|
||||
execstart = 0;
|
||||
|
@ -7,12 +7,13 @@
|
||||
// Copyright (C) 2014-2020 GIMONS
|
||||
// Copyright (C) akuker
|
||||
//
|
||||
// Licensed under the BSD 3-Clause License.
|
||||
// Licensed under the BSD 3-Clause License.
|
||||
// See LICENSE file in the project root folder.
|
||||
//
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
#include "cd_track.h"
|
||||
#include <cassert>
|
||||
|
||||
void CDTrack::Init(int track, uint32_t first, uint32_t last)
|
||||
{
|
||||
|
@ -23,7 +23,7 @@ public:
|
||||
CDTrack() = default;
|
||||
~CDTrack() = default;
|
||||
|
||||
void Init(int track, DWORD first, DWORD last);
|
||||
void Init(int track, uint32_t first, uint32_t last);
|
||||
|
||||
// Properties
|
||||
void SetPath(bool cdda, const Filepath& path); // Set the path
|
||||
@ -32,7 +32,7 @@ public:
|
||||
uint32_t GetLast() const; // Get the last LBA
|
||||
uint32_t GetBlocks() const; // Get the number of blocks
|
||||
int GetTrackNo() const; // Get the track number
|
||||
bool IsValid(DWORD lba) const; // Is this a valid LBA?
|
||||
bool IsValid(uint32_t lba) const; // Is this a valid LBA?
|
||||
bool IsAudio() const; // Is this an audio track?
|
||||
|
||||
private:
|
||||
|
@ -48,7 +48,7 @@ static void convert(char const *src, char const *dest,
|
||||
return;
|
||||
}
|
||||
|
||||
if (size_t ret = iconv(cd, &inbuf, &in, &outbuf, &out); ret == (size_t)-1) {
|
||||
if (const size_t ret = iconv(cd, &inbuf, &in, &outbuf, &out); ret == (size_t)-1) {
|
||||
return;
|
||||
}
|
||||
|
||||
@ -166,7 +166,7 @@ void Human68k::namests_t::GetCopyFilename(BYTE* szFilename) const
|
||||
if (i >= 8) {
|
||||
// Transfer the extraneous part
|
||||
for (i = 0; i < 10; i++) {
|
||||
BYTE c = add[i];
|
||||
const BYTE c = add[i];
|
||||
if (c == '\0')
|
||||
break;
|
||||
*p++ = c;
|
||||
@ -178,7 +178,7 @@ void Human68k::namests_t::GetCopyFilename(BYTE* szFilename) const
|
||||
if (ext[0] != ' ' || ext[1] != ' ' || ext[2] != ' ') {
|
||||
*p++ = '.';
|
||||
for (i = 0; i < 3; i++) {
|
||||
BYTE c = ext[i];
|
||||
const BYTE c = ext[i];
|
||||
if (c == ' ') {
|
||||
// Check that the file extension continues after a space is detected
|
||||
/// TODO: Should change this function to be compatible with 8+3 chars and TwentyOne
|
||||
@ -226,7 +226,7 @@ CHostDrv::~CHostDrv()
|
||||
// Initialization (device boot and load)
|
||||
//
|
||||
//---------------------------------------------------------------------------
|
||||
void CHostDrv::Init(const TCHAR* szBase, DWORD nFlag)
|
||||
void CHostDrv::Init(const TCHAR* szBase, uint32_t nFlag)
|
||||
{
|
||||
assert(szBase);
|
||||
assert(strlen(szBase) < FILEPATH_MAX);
|
||||
@ -253,7 +253,7 @@ void CHostDrv::Init(const TCHAR* szBase, DWORD nFlag)
|
||||
TCHAR* pClear = nullptr;
|
||||
TCHAR* p = m_szBase;
|
||||
for (;;) {
|
||||
TCHAR c = *p;
|
||||
const TCHAR c = *p;
|
||||
if (c == '\0')
|
||||
break;
|
||||
if (c == '/' || c == '\\') {
|
||||
@ -301,7 +301,7 @@ BYTE CHostDrv::GetMediaByte() const
|
||||
// Get drive status
|
||||
//
|
||||
//---------------------------------------------------------------------------
|
||||
DWORD CHostDrv::GetStatus() const
|
||||
uint32_t CHostDrv::GetStatus() const
|
||||
{
|
||||
return 0x40 | (m_bEnable ? (m_bWriteProtect ? 0x08 : 0) | 0x02 : 0);
|
||||
}
|
||||
@ -408,15 +408,15 @@ bool CHostDrv::GetVolumeCache(TCHAR* szLabel) const
|
||||
return m_bVolumeCache;
|
||||
}
|
||||
|
||||
DWORD CHostDrv::GetCapacity(Human68k::capacity_t* pCapacity)
|
||||
uint32_t CHostDrv::GetCapacity(Human68k::capacity_t* pCapacity)
|
||||
{
|
||||
assert(pCapacity);
|
||||
assert(m_bEnable);
|
||||
|
||||
DWORD nFree = 0x7FFF8000;
|
||||
DWORD freearea;
|
||||
DWORD clusters;
|
||||
DWORD sectors;
|
||||
const uint32_t nFree = 0x7FFF8000;
|
||||
uint32_t freearea;
|
||||
uint32_t clusters;
|
||||
uint32_t sectors;
|
||||
|
||||
freearea = 0xFFFF;
|
||||
clusters = 0xFFFF;
|
||||
@ -428,9 +428,9 @@ DWORD CHostDrv::GetCapacity(Human68k::capacity_t* pCapacity)
|
||||
assert(sectors <= 64);
|
||||
|
||||
// Update cache
|
||||
m_capCache.freearea = (WORD)freearea;
|
||||
m_capCache.clusters = (WORD)clusters;
|
||||
m_capCache.sectors = (WORD)sectors;
|
||||
m_capCache.freearea = (uint16_t)freearea;
|
||||
m_capCache.clusters = (uint16_t)clusters;
|
||||
m_capCache.sectors = (uint16_t)sectors;
|
||||
m_capCache.bytes = 512;
|
||||
|
||||
// Transfer contents
|
||||
@ -808,7 +808,7 @@ void CHostFilename::ConvertHuman(int nCount)
|
||||
}
|
||||
|
||||
size_t nMax = 18; // Number of bytes for the base segment (base name and extension)
|
||||
DWORD nOption = CFileSys::GetFileOption();
|
||||
uint32_t nOption = CFileSys::GetFileOption();
|
||||
if (nOption & WINDRV_OPT_CONVERT_LENGTH)
|
||||
nMax = 8;
|
||||
|
||||
@ -817,7 +817,7 @@ void CHostFilename::ConvertHuman(int nCount)
|
||||
BYTE* pNumber = nullptr;
|
||||
if (nCount >= 0) {
|
||||
pNumber = &szNumber[8];
|
||||
for (DWORD i = 0; i < 5; i++) { // Max 5+1 digits (always leave the first 2 bytes of the base name)
|
||||
for (uint32_t i = 0; i < 5; i++) { // Max 5+1 digits (always leave the first 2 bytes of the base name)
|
||||
int n = nCount % 36;
|
||||
nMax--;
|
||||
pNumber--;
|
||||
@ -1082,7 +1082,7 @@ bool CHostFilename::isReduce() const
|
||||
/// Evaluate Human68k directory entry attribute
|
||||
//
|
||||
//---------------------------------------------------------------------------
|
||||
int CHostFilename::CheckAttribute(DWORD nHumanAttribute) const
|
||||
int CHostFilename::CheckAttribute(uint32_t nHumanAttribute) const
|
||||
{
|
||||
BYTE nAttribute = m_dirHuman.attr;
|
||||
if ((nAttribute & (Human68k::AT_ARCHIVE | Human68k::AT_DIRECTORY | Human68k::AT_VOLUME)) == 0)
|
||||
@ -1099,7 +1099,7 @@ int CHostFilename::CheckAttribute(DWORD nHumanAttribute) const
|
||||
const BYTE* CHostFilename::SeparateExt(const BYTE* szHuman) // static
|
||||
{
|
||||
// Obtain the file name length
|
||||
size_t nLength = strlen((const char*)szHuman);
|
||||
const size_t nLength = strlen((const char*)szHuman);
|
||||
const BYTE* pFirst = szHuman;
|
||||
const BYTE* pLast = pFirst + nLength;
|
||||
|
||||
@ -1124,7 +1124,7 @@ const BYTE* CHostFilename::SeparateExt(const BYTE* szHuman) // static
|
||||
//
|
||||
//===========================================================================
|
||||
|
||||
DWORD CHostPath::g_nId; ///< Identifier creation counter
|
||||
uint32_t CHostPath::g_nId; ///< Identifier creation counter
|
||||
|
||||
CHostPath::~CHostPath()
|
||||
{
|
||||
@ -1144,7 +1144,7 @@ CHostPath::ring_t* CHostPath::Alloc(size_t nLength) // static
|
||||
{
|
||||
assert(nLength < FILEPATH_MAX);
|
||||
|
||||
size_t n = offsetof(ring_t, f) + CHostFilename::Offset() + (nLength + 1) * sizeof(TCHAR);
|
||||
const size_t n = offsetof(ring_t, f) + CHostFilename::Offset() + (nLength + 1) * sizeof(TCHAR);
|
||||
auto p = (ring_t*)malloc(n);
|
||||
assert(p);
|
||||
|
||||
@ -1295,8 +1295,8 @@ bool CHostPath::isSameHuman(const BYTE* szHuman) const
|
||||
assert(szHuman);
|
||||
|
||||
// Calulate number of chars
|
||||
size_t nLength = strlen((const char*)m_szHuman);
|
||||
size_t n = strlen((const char*)szHuman);
|
||||
const size_t nLength = strlen((const char*)m_szHuman);
|
||||
const size_t n = strlen((const char*)szHuman);
|
||||
|
||||
// Check number of chars
|
||||
if (nLength != n)
|
||||
@ -1331,7 +1331,7 @@ bool CHostPath::isSameChild(const BYTE* szHuman) const
|
||||
/// Make sure to lock from the top.
|
||||
//
|
||||
//---------------------------------------------------------------------------
|
||||
const CHostFilename* CHostPath::FindFilename(const BYTE* szHuman, DWORD nHumanAttribute) const
|
||||
const CHostFilename* CHostPath::FindFilename(const BYTE* szHuman, uint32_t nHumanAttribute) const
|
||||
{
|
||||
assert(szHuman);
|
||||
|
||||
@ -1368,7 +1368,7 @@ const CHostFilename* CHostPath::FindFilename(const BYTE* szHuman, DWORD nHumanAt
|
||||
/// Make sure to lock from the top.
|
||||
//
|
||||
//---------------------------------------------------------------------------
|
||||
const CHostFilename* CHostPath::FindFilenameWildcard(const BYTE* szHuman, DWORD nHumanAttribute, find_t* pFind) const
|
||||
const CHostFilename* CHostPath::FindFilenameWildcard(const BYTE* szHuman, uint32_t nHumanAttribute, find_t* pFind) const
|
||||
{
|
||||
assert(szHuman);
|
||||
assert(pFind);
|
||||
@ -1386,7 +1386,7 @@ const CHostFilename* CHostPath::FindFilenameWildcard(const BYTE* szHuman, DWORD
|
||||
p = pFind->pos;
|
||||
} else {
|
||||
// Find the start position in the directory entry contents
|
||||
DWORD n = 0;
|
||||
uint32_t n = 0;
|
||||
for (;; p = (const ring_t*)p->r.Next()) {
|
||||
if (p == (const ring_t*)&m_cRing) {
|
||||
// Extrapolate from the count when the same entry isn't found (just in case)
|
||||
@ -1547,7 +1547,7 @@ void CHostPath::Refresh()
|
||||
// - No duplicated names in previous entries
|
||||
// - No entity with the same name exists
|
||||
if (pFilename->isReduce() || !pFilename->isCorrect()) { // Confirm that file name update is required
|
||||
for (DWORD n = 0; n < XM6_HOST_FILENAME_PATTERN_MAX; n++) {
|
||||
for (uint32_t n = 0; n < XM6_HOST_FILENAME_PATTERN_MAX; n++) {
|
||||
// Confirm file name validity
|
||||
if (pFilename->isCorrect()) {
|
||||
// Confirm match with previous entry
|
||||
@ -1583,14 +1583,14 @@ void CHostPath::Refresh()
|
||||
nHumanAttribute |= Human68k::AT_READONLY;
|
||||
pFilename->SetEntryAttribute(nHumanAttribute);
|
||||
|
||||
auto nHumanSize = (DWORD)sb.st_size;
|
||||
auto nHumanSize = (uint32_t)sb.st_size;
|
||||
pFilename->SetEntrySize(nHumanSize);
|
||||
|
||||
WORD nHumanDate = 0;
|
||||
WORD nHumanTime = 0;
|
||||
uint16_t nHumanDate = 0;
|
||||
uint16_t nHumanTime = 0;
|
||||
if (tm pt = {}; localtime_r(&sb.st_mtime, &pt) != nullptr) {
|
||||
nHumanDate = (WORD)(((pt.tm_year - 80) << 9) | ((pt.tm_mon + 1) << 5) | pt.tm_mday);
|
||||
nHumanTime = (WORD)((pt.tm_hour << 11) | (pt.tm_min << 5) | (pt.tm_sec >> 1));
|
||||
nHumanDate = (uint16_t)(((pt.tm_year - 80) << 9) | ((pt.tm_mon + 1) << 5) | pt.tm_mday);
|
||||
nHumanTime = (uint16_t)((pt.tm_hour << 11) | (pt.tm_min << 5) | (pt.tm_sec >> 1));
|
||||
}
|
||||
pFilename->SetEntryDate(nHumanDate);
|
||||
pFilename->SetEntryTime(nHumanTime);
|
||||
@ -1760,7 +1760,7 @@ void CHostEntry::CleanCache() const
|
||||
/// Update the cache for the specified unit
|
||||
//
|
||||
//---------------------------------------------------------------------------
|
||||
void CHostEntry::CleanCache(DWORD nUnit) const
|
||||
void CHostEntry::CleanCache(uint32_t nUnit) const
|
||||
{
|
||||
assert(nUnit < DRIVE_MAX);
|
||||
assert(m_pDrv[nUnit]);
|
||||
@ -1773,7 +1773,7 @@ void CHostEntry::CleanCache(DWORD nUnit) const
|
||||
/// Update the cache for the specified path
|
||||
//
|
||||
//---------------------------------------------------------------------------
|
||||
void CHostEntry::CleanCache(DWORD nUnit, const BYTE* szHumanPath) const
|
||||
void CHostEntry::CleanCache(uint32_t nUnit, const BYTE* szHumanPath) const
|
||||
{
|
||||
assert(szHumanPath);
|
||||
assert(nUnit < DRIVE_MAX);
|
||||
@ -1787,7 +1787,7 @@ void CHostEntry::CleanCache(DWORD nUnit, const BYTE* szHumanPath) const
|
||||
/// Update all cache for the specified path and below
|
||||
//
|
||||
//---------------------------------------------------------------------------
|
||||
void CHostEntry::CleanCacheChild(DWORD nUnit, const BYTE* szHumanPath) const
|
||||
void CHostEntry::CleanCacheChild(uint32_t nUnit, const BYTE* szHumanPath) const
|
||||
{
|
||||
assert(szHumanPath);
|
||||
assert(nUnit < DRIVE_MAX);
|
||||
@ -1801,7 +1801,7 @@ void CHostEntry::CleanCacheChild(DWORD nUnit, const BYTE* szHumanPath) const
|
||||
/// Delete cache for the specified path
|
||||
//
|
||||
//---------------------------------------------------------------------------
|
||||
void CHostEntry::DeleteCache(DWORD nUnit, const BYTE* szHumanPath) const
|
||||
void CHostEntry::DeleteCache(uint32_t nUnit, const BYTE* szHumanPath) const
|
||||
{
|
||||
assert(szHumanPath);
|
||||
assert(nUnit < DRIVE_MAX);
|
||||
@ -1815,7 +1815,7 @@ void CHostEntry::DeleteCache(DWORD nUnit, const BYTE* szHumanPath) const
|
||||
/// Find host side names (path name + file name (can be abbreviated) + attribute)
|
||||
//
|
||||
//---------------------------------------------------------------------------
|
||||
bool CHostEntry::Find(DWORD nUnit, CHostFiles* pFiles) const
|
||||
bool CHostEntry::Find(uint32_t nUnit, CHostFiles* pFiles) const
|
||||
{
|
||||
assert(pFiles);
|
||||
assert(nUnit < DRIVE_MAX);
|
||||
@ -1829,7 +1829,7 @@ bool CHostEntry::Find(DWORD nUnit, CHostFiles* pFiles) const
|
||||
/// Drive settings
|
||||
//
|
||||
//---------------------------------------------------------------------------
|
||||
void CHostEntry::SetDrv(DWORD nUnit, CHostDrv* pDrv)
|
||||
void CHostEntry::SetDrv(uint32_t nUnit, CHostDrv* pDrv)
|
||||
{
|
||||
assert(nUnit < DRIVE_MAX);
|
||||
assert(m_pDrv[nUnit] == nullptr);
|
||||
@ -1842,7 +1842,7 @@ void CHostEntry::SetDrv(DWORD nUnit, CHostDrv* pDrv)
|
||||
/// Is it write-protected?
|
||||
//
|
||||
//---------------------------------------------------------------------------
|
||||
bool CHostEntry::isWriteProtect(DWORD nUnit) const
|
||||
bool CHostEntry::isWriteProtect(uint32_t nUnit) const
|
||||
{
|
||||
assert(nUnit < DRIVE_MAX);
|
||||
assert(m_pDrv[nUnit]);
|
||||
@ -1855,7 +1855,7 @@ bool CHostEntry::isWriteProtect(DWORD nUnit) const
|
||||
/// Is it accessible?
|
||||
//
|
||||
//---------------------------------------------------------------------------
|
||||
bool CHostEntry::isEnable(DWORD nUnit) const
|
||||
bool CHostEntry::isEnable(uint32_t nUnit) const
|
||||
{
|
||||
assert(nUnit < DRIVE_MAX);
|
||||
assert(m_pDrv[nUnit]);
|
||||
@ -1868,7 +1868,7 @@ bool CHostEntry::isEnable(DWORD nUnit) const
|
||||
/// Media check
|
||||
//
|
||||
//---------------------------------------------------------------------------
|
||||
bool CHostEntry::isMediaOffline(DWORD nUnit) const
|
||||
bool CHostEntry::isMediaOffline(uint32_t nUnit) const
|
||||
{
|
||||
assert(nUnit < DRIVE_MAX);
|
||||
assert(m_pDrv[nUnit]);
|
||||
@ -1881,7 +1881,7 @@ bool CHostEntry::isMediaOffline(DWORD nUnit) const
|
||||
/// Get media byte
|
||||
//
|
||||
//---------------------------------------------------------------------------
|
||||
BYTE CHostEntry::GetMediaByte(DWORD nUnit) const
|
||||
BYTE CHostEntry::GetMediaByte(uint32_t nUnit) const
|
||||
{
|
||||
assert(nUnit < DRIVE_MAX);
|
||||
assert(m_pDrv[nUnit]);
|
||||
@ -1894,7 +1894,7 @@ BYTE CHostEntry::GetMediaByte(DWORD nUnit) const
|
||||
/// Get drive status
|
||||
//
|
||||
//---------------------------------------------------------------------------
|
||||
DWORD CHostEntry::GetStatus(DWORD nUnit) const
|
||||
uint32_t CHostEntry::GetStatus(uint32_t nUnit) const
|
||||
{
|
||||
assert(nUnit < DRIVE_MAX);
|
||||
assert(m_pDrv[nUnit]);
|
||||
@ -1907,7 +1907,7 @@ DWORD CHostEntry::GetStatus(DWORD nUnit) const
|
||||
/// Media change check
|
||||
//
|
||||
//---------------------------------------------------------------------------
|
||||
bool CHostEntry::CheckMedia(DWORD nUnit) const
|
||||
bool CHostEntry::CheckMedia(uint32_t nUnit) const
|
||||
{
|
||||
assert(nUnit < DRIVE_MAX);
|
||||
assert(m_pDrv[nUnit]);
|
||||
@ -1920,7 +1920,7 @@ bool CHostEntry::CheckMedia(DWORD nUnit) const
|
||||
/// Eject
|
||||
//
|
||||
//---------------------------------------------------------------------------
|
||||
void CHostEntry::Eject(DWORD nUnit) const
|
||||
void CHostEntry::Eject(uint32_t nUnit) const
|
||||
{
|
||||
assert(nUnit < DRIVE_MAX);
|
||||
assert(m_pDrv[nUnit]);
|
||||
@ -1933,7 +1933,7 @@ void CHostEntry::Eject(DWORD nUnit) const
|
||||
/// Get volume label
|
||||
//
|
||||
//---------------------------------------------------------------------------
|
||||
void CHostEntry::GetVolume(DWORD nUnit, TCHAR* szLabel) const
|
||||
void CHostEntry::GetVolume(uint32_t nUnit, TCHAR* szLabel) const
|
||||
{
|
||||
assert(nUnit < DRIVE_MAX);
|
||||
assert(m_pDrv[nUnit]);
|
||||
@ -1946,7 +1946,7 @@ void CHostEntry::GetVolume(DWORD nUnit, TCHAR* szLabel) const
|
||||
/// Get volume label from cache
|
||||
//
|
||||
//---------------------------------------------------------------------------
|
||||
bool CHostEntry::GetVolumeCache(DWORD nUnit, TCHAR* szLabel) const
|
||||
bool CHostEntry::GetVolumeCache(uint32_t nUnit, TCHAR* szLabel) const
|
||||
{
|
||||
assert(nUnit < DRIVE_MAX);
|
||||
assert(m_pDrv[nUnit]);
|
||||
@ -1959,7 +1959,7 @@ bool CHostEntry::GetVolumeCache(DWORD nUnit, TCHAR* szLabel) const
|
||||
/// Get capacity
|
||||
//
|
||||
//---------------------------------------------------------------------------
|
||||
DWORD CHostEntry::GetCapacity(DWORD nUnit, Human68k::capacity_t* pCapacity) const
|
||||
uint32_t CHostEntry::GetCapacity(uint32_t nUnit, Human68k::capacity_t* pCapacity) const
|
||||
{
|
||||
assert(nUnit < DRIVE_MAX);
|
||||
assert(m_pDrv[nUnit]);
|
||||
@ -1972,7 +1972,7 @@ DWORD CHostEntry::GetCapacity(DWORD nUnit, Human68k::capacity_t* pCapacity) cons
|
||||
/// Get cluster size from cache
|
||||
//
|
||||
//---------------------------------------------------------------------------
|
||||
bool CHostEntry::GetCapacityCache(DWORD nUnit, Human68k::capacity_t* pCapacity) const
|
||||
bool CHostEntry::GetCapacityCache(uint32_t nUnit, Human68k::capacity_t* pCapacity) const
|
||||
{
|
||||
assert(nUnit < DRIVE_MAX);
|
||||
assert(m_pDrv[nUnit]);
|
||||
@ -2056,7 +2056,7 @@ void CHostFiles::SetPath(const Human68k::namests_t* pNamests)
|
||||
/// Find file on the Human68k side and create data on the host side
|
||||
//
|
||||
//---------------------------------------------------------------------------
|
||||
bool CHostFiles::Find(DWORD nUnit, const CHostEntry* pEntry)
|
||||
bool CHostFiles::Find(uint32_t nUnit, const CHostEntry* pEntry)
|
||||
{
|
||||
assert(pEntry);
|
||||
|
||||
@ -2159,7 +2159,7 @@ void CHostFilesManager::Init()
|
||||
assert(m_cRing.Prev() == &m_cRing);
|
||||
|
||||
// Allocate memory
|
||||
for (DWORD i = 0; i < XM6_HOST_FILES_MAX; i++) {
|
||||
for (uint32_t i = 0; i < XM6_HOST_FILES_MAX; i++) {
|
||||
auto p = new ring_t();
|
||||
p->r.Insert(&m_cRing);
|
||||
}
|
||||
@ -2180,7 +2180,7 @@ void CHostFilesManager::Clean()
|
||||
}
|
||||
}
|
||||
|
||||
CHostFiles* CHostFilesManager::Alloc(DWORD nKey)
|
||||
CHostFiles* CHostFilesManager::Alloc(uint32_t nKey)
|
||||
{
|
||||
assert(nKey);
|
||||
|
||||
@ -2195,7 +2195,7 @@ CHostFiles* CHostFilesManager::Alloc(DWORD nKey)
|
||||
return &p->f;
|
||||
}
|
||||
|
||||
CHostFiles* CHostFilesManager::Search(DWORD nKey)
|
||||
CHostFiles* CHostFilesManager::Search(uint32_t nKey)
|
||||
{
|
||||
// assert(nKey); // The search key may become 0 due to DPB damage
|
||||
|
||||
@ -2235,7 +2235,7 @@ void CHostFilesManager::Free(CHostFiles* pFiles)
|
||||
/// Set file open mode
|
||||
//
|
||||
//---------------------------------------------------------------------------
|
||||
bool CHostFcb::SetMode(DWORD nHumanMode)
|
||||
bool CHostFcb::SetMode(uint32_t nHumanMode)
|
||||
{
|
||||
switch (nHumanMode & Human68k::OP_MASK) {
|
||||
case Human68k::OP_READ:
|
||||
@ -2279,7 +2279,7 @@ void CHostFcb::SetHumanPath(const BYTE* szHumanPath)
|
||||
/// Return false if error is thrown.
|
||||
//
|
||||
//---------------------------------------------------------------------------
|
||||
bool CHostFcb::Create(DWORD, bool bForce)
|
||||
bool CHostFcb::Create(uint32_t, bool bForce)
|
||||
{
|
||||
assert((Human68k::AT_DIRECTORY | Human68k::AT_VOLUME) == 0);
|
||||
assert(strlen(m_szFilename) > 0);
|
||||
@ -2328,7 +2328,7 @@ bool CHostFcb::Open()
|
||||
/// Return -1 if error is thrown.
|
||||
//
|
||||
//---------------------------------------------------------------------------
|
||||
DWORD CHostFcb::Read(BYTE* pBuffer, DWORD nSize)
|
||||
uint32_t CHostFcb::Read(BYTE* pBuffer, uint32_t nSize)
|
||||
{
|
||||
assert(pBuffer);
|
||||
assert(m_pFile);
|
||||
@ -2337,7 +2337,7 @@ DWORD CHostFcb::Read(BYTE* pBuffer, DWORD nSize)
|
||||
if (ferror(m_pFile))
|
||||
nResult = (size_t)-1;
|
||||
|
||||
return (DWORD)nResult;
|
||||
return (uint32_t)nResult;
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
@ -2348,7 +2348,7 @@ DWORD CHostFcb::Read(BYTE* pBuffer, DWORD nSize)
|
||||
/// Return -1 if error is thrown.
|
||||
//
|
||||
//---------------------------------------------------------------------------
|
||||
DWORD CHostFcb::Write(const BYTE* pBuffer, DWORD nSize)
|
||||
uint32_t CHostFcb::Write(const BYTE* pBuffer, uint32_t nSize)
|
||||
{
|
||||
assert(pBuffer);
|
||||
assert(m_pFile);
|
||||
@ -2357,7 +2357,7 @@ DWORD CHostFcb::Write(const BYTE* pBuffer, DWORD nSize)
|
||||
if (ferror(m_pFile))
|
||||
nResult = (size_t)-1;
|
||||
|
||||
return (DWORD)nResult;
|
||||
return (uint32_t)nResult;
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
@ -2381,7 +2381,7 @@ bool CHostFcb::Truncate() const
|
||||
/// Return -1 if error is thrown.
|
||||
//
|
||||
//---------------------------------------------------------------------------
|
||||
DWORD CHostFcb::Seek(DWORD nOffset, Human68k::seek_t nHumanSeek)
|
||||
uint32_t CHostFcb::Seek(uint32_t nOffset, Human68k::seek_t nHumanSeek)
|
||||
{
|
||||
assert(m_pFile);
|
||||
|
||||
@ -2399,9 +2399,9 @@ DWORD CHostFcb::Seek(DWORD nOffset, Human68k::seek_t nHumanSeek)
|
||||
break;
|
||||
}
|
||||
if (fseek(m_pFile, nOffset, nSeek))
|
||||
return (DWORD)-1;
|
||||
return (uint32_t)-1;
|
||||
|
||||
return (DWORD)ftell(m_pFile);
|
||||
return (uint32_t)ftell(m_pFile);
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
@ -2411,7 +2411,7 @@ DWORD CHostFcb::Seek(DWORD nOffset, Human68k::seek_t nHumanSeek)
|
||||
/// Return false if error is thrown.
|
||||
//
|
||||
//---------------------------------------------------------------------------
|
||||
bool CHostFcb::TimeStamp(DWORD nHumanTime) const
|
||||
bool CHostFcb::TimeStamp(uint32_t nHumanTime) const
|
||||
{
|
||||
assert(m_pFile || m_bFlag);
|
||||
|
||||
@ -2480,7 +2480,7 @@ void CHostFcbManager::Init()
|
||||
assert(m_cRing.Prev() == &m_cRing);
|
||||
|
||||
// Memory allocation
|
||||
for (DWORD i = 0; i < XM6_HOST_FCB_MAX; i++) {
|
||||
for (uint32_t i = 0; i < XM6_HOST_FCB_MAX; i++) {
|
||||
auto p = new ring_t;
|
||||
assert(p);
|
||||
p->r.Insert(&m_cRing);
|
||||
@ -2501,7 +2501,7 @@ void CHostFcbManager::Clean() const
|
||||
}
|
||||
}
|
||||
|
||||
CHostFcb* CHostFcbManager::Alloc(DWORD nKey)
|
||||
CHostFcb* CHostFcbManager::Alloc(uint32_t nKey)
|
||||
{
|
||||
assert(nKey);
|
||||
|
||||
@ -2523,7 +2523,7 @@ CHostFcb* CHostFcbManager::Alloc(DWORD nKey)
|
||||
return &p->f;
|
||||
}
|
||||
|
||||
CHostFcb* CHostFcbManager::Search(DWORD nKey)
|
||||
CHostFcb* CHostFcbManager::Search(uint32_t nKey)
|
||||
{
|
||||
assert(nKey);
|
||||
|
||||
@ -2560,7 +2560,7 @@ void CHostFcbManager::Free(CHostFcb* pFcb)
|
||||
//
|
||||
//===========================================================================
|
||||
|
||||
DWORD CFileSys::g_nOption; // File name conversion flag
|
||||
uint32_t CFileSys::g_nOption; // File name conversion flag
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
//
|
||||
@ -2607,7 +2607,7 @@ void CFileSys::Init()
|
||||
m_cEntry.Init();
|
||||
|
||||
// Evaluate per-path setting validity
|
||||
DWORD nDrives = m_nDrives;
|
||||
uint32_t nDrives = m_nDrives;
|
||||
if (nDrives == 0) {
|
||||
// Use root directory instead of per-path settings
|
||||
strcpy(m_szBase[0], "/");
|
||||
@ -2616,8 +2616,8 @@ void CFileSys::Init()
|
||||
}
|
||||
|
||||
// Register file system
|
||||
DWORD nUnit = 0;
|
||||
for (DWORD n = 0; n < nDrives; n++) {
|
||||
uint32_t nUnit = 0;
|
||||
for (uint32_t n = 0; n < nDrives; n++) {
|
||||
// Don't register is base path do not exist
|
||||
if (m_szBase[n][0] == '\0')
|
||||
continue;
|
||||
@ -2642,7 +2642,7 @@ void CFileSys::Init()
|
||||
/// $40 - Device startup
|
||||
//
|
||||
//---------------------------------------------------------------------------
|
||||
DWORD CFileSys::InitDevice(const Human68k::argument_t* pArgument)
|
||||
uint32_t CFileSys::InitDevice(const Human68k::argument_t* pArgument)
|
||||
{
|
||||
InitOption(pArgument);
|
||||
|
||||
@ -2657,7 +2657,7 @@ DWORD CFileSys::InitDevice(const Human68k::argument_t* pArgument)
|
||||
/// $41 - Directory check
|
||||
//
|
||||
//---------------------------------------------------------------------------
|
||||
int CFileSys::CheckDir(DWORD nUnit, const Human68k::namests_t* pNamests) const
|
||||
int CFileSys::CheckDir(uint32_t nUnit, const Human68k::namests_t* pNamests) const
|
||||
{
|
||||
assert(pNamests);
|
||||
|
||||
@ -2684,7 +2684,7 @@ int CFileSys::CheckDir(DWORD nUnit, const Human68k::namests_t* pNamests) const
|
||||
/// $42 - Create directory
|
||||
//
|
||||
//---------------------------------------------------------------------------
|
||||
int CFileSys::MakeDir(DWORD nUnit, const Human68k::namests_t* pNamests) const
|
||||
int CFileSys::MakeDir(uint32_t nUnit, const Human68k::namests_t* pNamests) const
|
||||
{
|
||||
assert(pNamests);
|
||||
|
||||
@ -2726,7 +2726,7 @@ int CFileSys::MakeDir(DWORD nUnit, const Human68k::namests_t* pNamests) const
|
||||
/// $43 - Delete directory
|
||||
//
|
||||
//---------------------------------------------------------------------------
|
||||
int CFileSys::RemoveDir(DWORD nUnit, const Human68k::namests_t* pNamests) const
|
||||
int CFileSys::RemoveDir(uint32_t nUnit, const Human68k::namests_t* pNamests) const
|
||||
{
|
||||
assert(pNamests);
|
||||
|
||||
@ -2776,7 +2776,7 @@ int CFileSys::RemoveDir(DWORD nUnit, const Human68k::namests_t* pNamests) const
|
||||
/// $44 - Change file name
|
||||
//
|
||||
//---------------------------------------------------------------------------
|
||||
int CFileSys::Rename(DWORD nUnit, const Human68k::namests_t* pNamests, const Human68k::namests_t* pNamestsNew) const
|
||||
int CFileSys::Rename(uint32_t nUnit, const Human68k::namests_t* pNamests, const Human68k::namests_t* pNamestsNew) const
|
||||
{
|
||||
assert(pNamests);
|
||||
|
||||
@ -2834,7 +2834,7 @@ int CFileSys::Rename(DWORD nUnit, const Human68k::namests_t* pNamests, const Hum
|
||||
/// $45 - Delete file
|
||||
//
|
||||
//---------------------------------------------------------------------------
|
||||
int CFileSys::Delete(DWORD nUnit, const Human68k::namests_t* pNamests) const
|
||||
int CFileSys::Delete(uint32_t nUnit, const Human68k::namests_t* pNamests) const
|
||||
{
|
||||
assert(pNamests);
|
||||
|
||||
@ -2874,7 +2874,7 @@ int CFileSys::Delete(DWORD nUnit, const Human68k::namests_t* pNamests) const
|
||||
/// $46 - Get/set file attribute
|
||||
//
|
||||
//---------------------------------------------------------------------------
|
||||
int CFileSys::Attribute(DWORD nUnit, const Human68k::namests_t* pNamests, DWORD nHumanAttribute) const
|
||||
int CFileSys::Attribute(uint32_t nUnit, const Human68k::namests_t* pNamests, uint32_t nHumanAttribute) const
|
||||
{
|
||||
assert(pNamests);
|
||||
|
||||
@ -2908,7 +2908,7 @@ int CFileSys::Attribute(DWORD nUnit, const Human68k::namests_t* pNamests, DWORD
|
||||
return FS_FATAL_WRITEPROTECT;
|
||||
|
||||
// Generate attribute
|
||||
if (DWORD nAttribute = (nHumanAttribute & Human68k::AT_READONLY) | (f.GetAttribute() & ~Human68k::AT_READONLY);
|
||||
if (uint32_t nAttribute = (nHumanAttribute & Human68k::AT_READONLY) | (f.GetAttribute() & ~Human68k::AT_READONLY);
|
||||
f.GetAttribute() != nAttribute) {
|
||||
struct stat sb;
|
||||
if (stat(S2U(f.GetPath()), &sb))
|
||||
@ -2939,7 +2939,7 @@ int CFileSys::Attribute(DWORD nUnit, const Human68k::namests_t* pNamests, DWORD
|
||||
/// $47 - File search
|
||||
//
|
||||
//---------------------------------------------------------------------------
|
||||
int CFileSys::Files(DWORD nUnit, DWORD nKey, const Human68k::namests_t* pNamests, Human68k::files_t* pFiles)
|
||||
int CFileSys::Files(uint32_t nUnit, uint32_t nKey, const Human68k::namests_t* pNamests, Human68k::files_t* pFiles)
|
||||
{
|
||||
assert(pNamests);
|
||||
assert(nKey);
|
||||
@ -3025,7 +3025,7 @@ int CFileSys::Files(DWORD nUnit, DWORD nKey, const Human68k::namests_t* pNamests
|
||||
/// $48 - Search next file
|
||||
//
|
||||
//---------------------------------------------------------------------------
|
||||
int CFileSys::NFiles(DWORD nUnit, DWORD nKey, Human68k::files_t* pFiles)
|
||||
int CFileSys::NFiles(uint32_t nUnit, uint32_t nKey, Human68k::files_t* pFiles)
|
||||
{
|
||||
assert(nKey);
|
||||
assert(pFiles);
|
||||
@ -3069,7 +3069,7 @@ int CFileSys::NFiles(DWORD nUnit, DWORD nKey, Human68k::files_t* pFiles)
|
||||
/// $49 - Create new file
|
||||
//
|
||||
//---------------------------------------------------------------------------
|
||||
int CFileSys::Create(DWORD nUnit, DWORD nKey, const Human68k::namests_t* pNamests, Human68k::fcb_t* pFcb, DWORD nHumanAttribute, bool bForce)
|
||||
int CFileSys::Create(uint32_t nUnit, uint32_t nKey, const Human68k::namests_t* pNamests, Human68k::fcb_t* pFcb, uint32_t nHumanAttribute, bool bForce)
|
||||
{
|
||||
assert(pNamests);
|
||||
assert(nKey);
|
||||
@ -3114,7 +3114,7 @@ int CFileSys::Create(DWORD nUnit, DWORD nKey, const Human68k::namests_t* pNamest
|
||||
pHostFcb->SetHumanPath(f.GetHumanPath());
|
||||
|
||||
// Set open mode
|
||||
pFcb->mode = (WORD)((pFcb->mode & ~Human68k::OP_MASK) | Human68k::OP_FULL);
|
||||
pFcb->mode = (uint16_t)((pFcb->mode & ~Human68k::OP_MASK) | Human68k::OP_FULL);
|
||||
if (!pHostFcb->SetMode(pFcb->mode)) {
|
||||
m_cFcb.Free(pHostFcb);
|
||||
return FS_ILLEGALMOD;
|
||||
@ -3137,7 +3137,7 @@ int CFileSys::Create(DWORD nUnit, DWORD nKey, const Human68k::namests_t* pNamest
|
||||
/// $4A - File open
|
||||
//
|
||||
//---------------------------------------------------------------------------
|
||||
int CFileSys::Open(DWORD nUnit, DWORD nKey, const Human68k::namests_t* pNamests, Human68k::fcb_t* pFcb)
|
||||
int CFileSys::Open(uint32_t nUnit, uint32_t nKey, const Human68k::namests_t* pNamests, Human68k::fcb_t* pFcb)
|
||||
{
|
||||
assert(pNamests);
|
||||
assert(nKey);
|
||||
@ -3208,7 +3208,7 @@ int CFileSys::Open(DWORD nUnit, DWORD nKey, const Human68k::namests_t* pNamests,
|
||||
/// $4B - File close
|
||||
//
|
||||
//---------------------------------------------------------------------------
|
||||
int CFileSys::Close(DWORD nUnit, DWORD nKey, const Human68k::fcb_t* /* pFcb */)
|
||||
int CFileSys::Close(uint32_t nUnit, uint32_t nKey, const Human68k::fcb_t* /* pFcb */)
|
||||
{
|
||||
assert(nKey);
|
||||
|
||||
@ -3246,7 +3246,7 @@ int CFileSys::Close(DWORD nUnit, DWORD nKey, const Human68k::fcb_t* /* pFcb */)
|
||||
/// Clean exit when 0 bytes are read.
|
||||
//
|
||||
//---------------------------------------------------------------------------
|
||||
int CFileSys::Read(DWORD nKey, Human68k::fcb_t* pFcb, BYTE* pBuffer, DWORD nSize)
|
||||
int CFileSys::Read(uint32_t nKey, Human68k::fcb_t* pFcb, BYTE* pBuffer, uint32_t nSize)
|
||||
{
|
||||
assert(nKey);
|
||||
assert(pFcb);
|
||||
@ -3265,9 +3265,8 @@ int CFileSys::Read(DWORD nKey, Human68k::fcb_t* pFcb, BYTE* pBuffer, DWORD nSize
|
||||
}
|
||||
|
||||
// Read
|
||||
DWORD nResult;
|
||||
nResult = pHostFcb->Read(pBuffer, nSize);
|
||||
if (nResult == (DWORD)-1) {
|
||||
const uint32_t nResult = pHostFcb->Read(pBuffer, nSize);
|
||||
if (nResult == (uint32_t)-1) {
|
||||
m_cFcb.Free(pHostFcb);
|
||||
return FS_INVALIDFUNC; // TODO: Should return error code 10 (read error) as well here
|
||||
}
|
||||
@ -3286,7 +3285,7 @@ int CFileSys::Read(DWORD nKey, Human68k::fcb_t* pFcb, BYTE* pBuffer, DWORD nSize
|
||||
/// Truncate file if 0 bytes are written.
|
||||
//
|
||||
//---------------------------------------------------------------------------
|
||||
int CFileSys::Write(DWORD nKey, Human68k::fcb_t* pFcb, const BYTE* pBuffer, DWORD nSize)
|
||||
int CFileSys::Write(uint32_t nKey, Human68k::fcb_t* pFcb, const BYTE* pBuffer, uint32_t nSize)
|
||||
{
|
||||
assert(nKey);
|
||||
assert(pFcb);
|
||||
@ -3298,7 +3297,7 @@ int CFileSys::Write(DWORD nKey, Human68k::fcb_t* pFcb, const BYTE* pBuffer, DWOR
|
||||
if (pHostFcb == nullptr)
|
||||
return FS_NOTOPENED;
|
||||
|
||||
DWORD nResult;
|
||||
uint32_t nResult;
|
||||
if (nSize == 0) {
|
||||
// Truncate
|
||||
if (!pHostFcb->Truncate()) {
|
||||
@ -3319,7 +3318,7 @@ int CFileSys::Write(DWORD nKey, Human68k::fcb_t* pFcb, const BYTE* pBuffer, DWOR
|
||||
|
||||
// Write
|
||||
nResult = pHostFcb->Write(pBuffer, nSize);
|
||||
if (nResult == (DWORD)-1) {
|
||||
if (nResult == (uint32_t)-1) {
|
||||
m_cFcb.Free(pHostFcb);
|
||||
return FS_CANTWRITE; /// TODO: Should return error code 11 (write error) as well here
|
||||
}
|
||||
@ -3344,7 +3343,7 @@ int CFileSys::Write(DWORD nKey, Human68k::fcb_t* pFcb, const BYTE* pBuffer, DWOR
|
||||
/// $4E - File seek
|
||||
//
|
||||
//---------------------------------------------------------------------------
|
||||
int CFileSys::Seek(DWORD nKey, Human68k::fcb_t* pFcb, DWORD nSeek, int nOffset)
|
||||
int CFileSys::Seek(uint32_t nKey, Human68k::fcb_t* pFcb, uint32_t nSeek, int nOffset)
|
||||
{
|
||||
assert(pFcb);
|
||||
|
||||
@ -3354,14 +3353,14 @@ int CFileSys::Seek(DWORD nKey, Human68k::fcb_t* pFcb, DWORD nSeek, int nOffset)
|
||||
return FS_NOTOPENED;
|
||||
|
||||
// Parameter check
|
||||
if (nSeek > (DWORD)Human68k::seek_t::SK_END) {
|
||||
if (nSeek > (uint32_t)Human68k::seek_t::SK_END) {
|
||||
m_cFcb.Free(pHostFcb);
|
||||
return FS_INVALIDPRM;
|
||||
}
|
||||
|
||||
// File seek
|
||||
DWORD nResult = pHostFcb->Seek(nOffset, (Human68k::seek_t)nSeek);
|
||||
if (nResult == (DWORD)-1) {
|
||||
uint32_t nResult = pHostFcb->Seek(nOffset, (Human68k::seek_t)nSeek);
|
||||
if (nResult == (uint32_t)-1) {
|
||||
m_cFcb.Free(pHostFcb);
|
||||
return FS_CANTSEEK;
|
||||
}
|
||||
@ -3379,14 +3378,14 @@ int CFileSys::Seek(DWORD nKey, Human68k::fcb_t* pFcb, DWORD nSeek, int nOffset)
|
||||
/// Throw error when the top 16 bits are $FFFF.
|
||||
//
|
||||
//---------------------------------------------------------------------------
|
||||
DWORD CFileSys::TimeStamp(DWORD nUnit, DWORD nKey, Human68k::fcb_t* pFcb, DWORD nHumanTime)
|
||||
uint32_t CFileSys::TimeStamp(uint32_t nUnit, uint32_t nKey, Human68k::fcb_t* pFcb, uint32_t nHumanTime)
|
||||
{
|
||||
assert(nKey);
|
||||
assert(pFcb);
|
||||
|
||||
// Get only
|
||||
if (nHumanTime == 0)
|
||||
return ((DWORD)pFcb->date << 16) | pFcb->time;
|
||||
return ((uint32_t)pFcb->date << 16) | pFcb->time;
|
||||
|
||||
// Unit check
|
||||
if (nUnit >= CHostEntry::DRIVE_MAX)
|
||||
@ -3413,8 +3412,8 @@ DWORD CFileSys::TimeStamp(DWORD nUnit, DWORD nKey, Human68k::fcb_t* pFcb, DWORD
|
||||
m_cFcb.Free(pHostFcb);
|
||||
return FS_INVALIDPRM;
|
||||
}
|
||||
pFcb->date = (WORD)(nHumanTime >> 16);
|
||||
pFcb->time = (WORD)nHumanTime;
|
||||
pFcb->date = (uint16_t)(nHumanTime >> 16);
|
||||
pFcb->time = (uint16_t)nHumanTime;
|
||||
|
||||
// Update cache
|
||||
m_cEntry.CleanCache(nUnit, pHostFcb->GetHumanPath());
|
||||
@ -3427,7 +3426,7 @@ DWORD CFileSys::TimeStamp(DWORD nUnit, DWORD nKey, Human68k::fcb_t* pFcb, DWORD
|
||||
/// $50 - Get capacity
|
||||
//
|
||||
//---------------------------------------------------------------------------
|
||||
int CFileSys::GetCapacity(DWORD nUnit, Human68k::capacity_t* pCapacity) const
|
||||
int CFileSys::GetCapacity(uint32_t nUnit, Human68k::capacity_t* pCapacity) const
|
||||
{
|
||||
assert(pCapacity);
|
||||
|
||||
@ -3451,7 +3450,7 @@ int CFileSys::GetCapacity(DWORD nUnit, Human68k::capacity_t* pCapacity) const
|
||||
/// $51 - Inspect/control drive status
|
||||
//
|
||||
//---------------------------------------------------------------------------
|
||||
int CFileSys::CtrlDrive(DWORD nUnit, Human68k::ctrldrive_t* pCtrlDrive) const
|
||||
int CFileSys::CtrlDrive(uint32_t nUnit, Human68k::ctrldrive_t* pCtrlDrive) const
|
||||
{
|
||||
assert(pCtrlDrive);
|
||||
|
||||
@ -3494,7 +3493,7 @@ int CFileSys::CtrlDrive(DWORD nUnit, Human68k::ctrldrive_t* pCtrlDrive) const
|
||||
/// Therefore, treat even a unit out of bounds as normal operation.
|
||||
//
|
||||
//---------------------------------------------------------------------------
|
||||
int CFileSys::GetDPB(DWORD nUnit, Human68k::dpb_t* pDpb) const
|
||||
int CFileSys::GetDPB(uint32_t nUnit, Human68k::dpb_t* pDpb) const
|
||||
{
|
||||
assert(pDpb);
|
||||
|
||||
@ -3528,8 +3527,8 @@ int CFileSys::GetDPB(DWORD nUnit, Human68k::dpb_t* pDpb) const
|
||||
}
|
||||
|
||||
// Calculate number of shifts
|
||||
DWORD nSize = 1;
|
||||
DWORD nShift = 0;
|
||||
uint32_t nSize = 1;
|
||||
uint32_t nShift = 0;
|
||||
for (;;) {
|
||||
if (nSize >= cap.sectors)
|
||||
break;
|
||||
@ -3544,23 +3543,23 @@ int CFileSys::GetDPB(DWORD nUnit, Human68k::dpb_t* pDpb) const
|
||||
// Cluster 1: FAT
|
||||
// Cluster 2: Root directory
|
||||
// Cluster 3: Data memory (pseudo-sector)
|
||||
DWORD nFat = cap.sectors;
|
||||
DWORD nRoot = cap.sectors * 2;
|
||||
DWORD nData = cap.sectors * 3;
|
||||
const uint32_t nFat = cap.sectors;
|
||||
const uint32_t nRoot = cap.sectors * 2;
|
||||
const uint32_t nData = cap.sectors * 3;
|
||||
|
||||
// Set DPB
|
||||
pDpb->sector_size = cap.bytes; // Bytes per sector
|
||||
pDpb->cluster_size =
|
||||
(BYTE)(cap.sectors - 1); // Sectors per cluster - 1
|
||||
pDpb->shift = (BYTE)nShift; // Number of cluster → sector shifts
|
||||
pDpb->fat_sector = (WORD)nFat; // First FAT sector number
|
||||
pDpb->fat_sector = (uint16_t)nFat; // First FAT sector number
|
||||
pDpb->fat_max = 1; // Number of FAT memory spaces
|
||||
pDpb->fat_size = (BYTE)cap.sectors; // Number of sectors controlled by FAT (excluding copies)
|
||||
pDpb->file_max =
|
||||
(WORD)(cap.sectors * cap.bytes / 0x20); // Number of files in the root directory
|
||||
pDpb->data_sector = (WORD)nData; // First sector number of data memory
|
||||
(uint16_t)(cap.sectors * cap.bytes / 0x20); // Number of files in the root directory
|
||||
pDpb->data_sector = (uint16_t)nData; // First sector number of data memory
|
||||
pDpb->cluster_max = cap.clusters; // Total number of clusters + 1
|
||||
pDpb->root_sector = (WORD)nRoot; // First sector number of the root directory
|
||||
pDpb->root_sector = (uint16_t)nRoot; // First sector number of the root directory
|
||||
pDpb->media = media; // Media byte
|
||||
|
||||
return 0;
|
||||
@ -3574,7 +3573,7 @@ int CFileSys::GetDPB(DWORD nUnit, Human68k::dpb_t* pDpb) const
|
||||
/// Buffer size is hard coded to $200 byte.
|
||||
//
|
||||
//---------------------------------------------------------------------------
|
||||
int CFileSys::DiskRead(DWORD nUnit, BYTE* pBuffer, DWORD nSector, DWORD nSize)
|
||||
int CFileSys::DiskRead(uint32_t nUnit, BYTE* pBuffer, uint32_t nSector, uint32_t nSize)
|
||||
{
|
||||
assert(pBuffer);
|
||||
|
||||
@ -3611,7 +3610,7 @@ int CFileSys::DiskRead(DWORD nUnit, BYTE* pBuffer, DWORD nSector, DWORD nSize)
|
||||
// Note that in lzdsys the sector number to read is calculated by the following formula:
|
||||
// (dirent.cluster - 2) * (dpb.cluster_size + 1) + dpb.data_sector
|
||||
/// @warning little endian only
|
||||
dir->cluster = (WORD)(m_nHostSectorCount + 2); // Pseudo-sector number
|
||||
dir->cluster = (uint16_t)(m_nHostSectorCount + 2); // Pseudo-sector number
|
||||
m_nHostSectorBuffer[m_nHostSectorCount] = nSector; // Entity that points to the pseudo-sector
|
||||
m_nHostSectorCount++;
|
||||
m_nHostSectorCount %= XM6_HOST_PSEUDO_CLUSTER_MAX;
|
||||
@ -3620,8 +3619,8 @@ int CFileSys::DiskRead(DWORD nUnit, BYTE* pBuffer, DWORD nSector, DWORD nSize)
|
||||
}
|
||||
|
||||
// Calculate the sector number from the cluster number
|
||||
DWORD n = nSector - (3 * cap.sectors);
|
||||
DWORD nMod = 1;
|
||||
uint32_t n = nSector - (3 * cap.sectors);
|
||||
uint32_t nMod = 1;
|
||||
if (cap.sectors) {
|
||||
// Beware that cap.sectors becomes 0 when media does not exist
|
||||
nMod = n % cap.sectors;
|
||||
@ -3639,9 +3638,9 @@ int CFileSys::DiskRead(DWORD nUnit, BYTE* pBuffer, DWORD nSector, DWORD nSize)
|
||||
if (!f.Open())
|
||||
return FS_INVALIDPRM;
|
||||
memset(pBuffer, 0, 0x200);
|
||||
DWORD nResult = f.Read(pBuffer, 0x200);
|
||||
uint32_t nResult = f.Read(pBuffer, 0x200);
|
||||
f.Close();
|
||||
if (nResult == (DWORD)-1)
|
||||
if (nResult == (uint32_t)-1)
|
||||
return FS_INVALIDPRM;
|
||||
|
||||
return 0;
|
||||
@ -3656,7 +3655,7 @@ int CFileSys::DiskRead(DWORD nUnit, BYTE* pBuffer, DWORD nSector, DWORD nSize)
|
||||
/// $54 - Write sector
|
||||
//
|
||||
//---------------------------------------------------------------------------
|
||||
int CFileSys::DiskWrite(DWORD nUnit) const
|
||||
int CFileSys::DiskWrite(uint32_t nUnit) const
|
||||
{
|
||||
// Unit check
|
||||
if (nUnit >= CHostEntry::DRIVE_MAX)
|
||||
@ -3682,7 +3681,7 @@ int CFileSys::DiskWrite(DWORD nUnit) const
|
||||
/// $55 - IOCTRL
|
||||
//
|
||||
//---------------------------------------------------------------------------
|
||||
int CFileSys::Ioctrl(DWORD nUnit, DWORD nFunction, Human68k::ioctrl_t* pIoctrl)
|
||||
int CFileSys::Ioctrl(uint32_t nUnit, uint32_t nFunction, Human68k::ioctrl_t* pIoctrl)
|
||||
{
|
||||
assert(pIoctrl);
|
||||
|
||||
@ -3705,7 +3704,7 @@ int CFileSys::Ioctrl(DWORD nUnit, DWORD nFunction, Human68k::ioctrl_t* pIoctrl)
|
||||
|
||||
case 2:
|
||||
switch (pIoctrl->param) {
|
||||
case (DWORD)-1:
|
||||
case (uint32_t)-1:
|
||||
// Re-identify media
|
||||
m_cEntry.isMediaOffline(nUnit);
|
||||
return 0;
|
||||
@ -3720,17 +3719,17 @@ int CFileSys::Ioctrl(DWORD nUnit, DWORD nFunction, Human68k::ioctrl_t* pIoctrl)
|
||||
}
|
||||
break;
|
||||
|
||||
case (DWORD)-1:
|
||||
case (uint32_t)-1:
|
||||
// Resident evaluation
|
||||
memcpy(pIoctrl->buffer, "WindrvXM", 8);
|
||||
return 0;
|
||||
|
||||
case (DWORD)-2:
|
||||
case (uint32_t)-2:
|
||||
// Set options
|
||||
SetOption(pIoctrl->param);
|
||||
return 0;
|
||||
|
||||
case (DWORD)-3:
|
||||
case (uint32_t)-3:
|
||||
// Get options
|
||||
pIoctrl->param = GetOption();
|
||||
return 0;
|
||||
@ -3747,7 +3746,7 @@ int CFileSys::Ioctrl(DWORD nUnit, DWORD nFunction, Human68k::ioctrl_t* pIoctrl)
|
||||
/// $56 - Flush
|
||||
//
|
||||
//---------------------------------------------------------------------------
|
||||
int CFileSys::Flush(DWORD nUnit) const
|
||||
int CFileSys::Flush(uint32_t nUnit) const
|
||||
{
|
||||
// Unit check
|
||||
if (nUnit >= CHostEntry::DRIVE_MAX)
|
||||
@ -3764,7 +3763,7 @@ int CFileSys::Flush(DWORD nUnit) const
|
||||
/// $57 - Media change check
|
||||
//
|
||||
//---------------------------------------------------------------------------
|
||||
int CFileSys::CheckMedia(DWORD nUnit) const
|
||||
int CFileSys::CheckMedia(uint32_t nUnit) const
|
||||
{
|
||||
// Unit check
|
||||
if (nUnit >= CHostEntry::DRIVE_MAX)
|
||||
@ -3786,7 +3785,7 @@ int CFileSys::CheckMedia(DWORD nUnit) const
|
||||
/// $58 - Lock
|
||||
//
|
||||
//---------------------------------------------------------------------------
|
||||
int CFileSys::Lock(DWORD nUnit) const
|
||||
int CFileSys::Lock(uint32_t nUnit) const
|
||||
{
|
||||
// Unit check
|
||||
if (nUnit >= CHostEntry::DRIVE_MAX)
|
||||
@ -3808,7 +3807,7 @@ int CFileSys::Lock(DWORD nUnit) const
|
||||
/// Set options
|
||||
//
|
||||
//---------------------------------------------------------------------------
|
||||
void CFileSys::SetOption(DWORD nOption)
|
||||
void CFileSys::SetOption(uint32_t nOption)
|
||||
{
|
||||
// Clear cache when option settings change
|
||||
if (m_nOption ^ nOption)
|
||||
@ -3833,7 +3832,7 @@ void CFileSys::InitOption(const Human68k::argument_t* pArgument)
|
||||
const BYTE* pp = pArgument->buf;
|
||||
pp += strlen((const char*)pp) + 1;
|
||||
|
||||
DWORD nOption = m_nOptionDefault;
|
||||
uint32_t nOption = m_nOptionDefault;
|
||||
for (;;) {
|
||||
assert(pp < pArgument->buf + sizeof(*pArgument));
|
||||
const BYTE* p = pp;
|
||||
@ -3841,7 +3840,7 @@ void CFileSys::InitOption(const Human68k::argument_t* pArgument)
|
||||
if (c == '\0')
|
||||
break;
|
||||
|
||||
DWORD nMode;
|
||||
uint32_t nMode;
|
||||
if (c == '+') {
|
||||
nMode = 1;
|
||||
} else if (c == '-') {
|
||||
@ -3866,7 +3865,7 @@ void CFileSys::InitOption(const Human68k::argument_t* pArgument)
|
||||
if (c == '\0')
|
||||
break;
|
||||
|
||||
DWORD nBit = 0;
|
||||
uint32_t nBit = 0;
|
||||
switch (c) {
|
||||
case 'A': case 'a': nBit = WINDRV_OPT_CONVERT_LENGTH; break;
|
||||
case 'T': case 't': nBit = WINDRV_OPT_COMPARE_LENGTH; nMode ^= 1; break;
|
||||
@ -3909,7 +3908,7 @@ void CFileSys::InitOption(const Human68k::argument_t* pArgument)
|
||||
/// Get volume label
|
||||
//
|
||||
//---------------------------------------------------------------------------
|
||||
bool CFileSys::FilesVolume(DWORD nUnit, Human68k::files_t* pFiles) const
|
||||
bool CFileSys::FilesVolume(uint32_t nUnit, Human68k::files_t* pFiles) const
|
||||
{
|
||||
assert(pFiles);
|
||||
|
||||
|
@ -116,41 +116,41 @@ namespace Human68k {
|
||||
struct files_t {
|
||||
BYTE fatr; ///< + 0 search attribute; read-only
|
||||
// BYTE drive; ///< + 1 drive number; read-only
|
||||
DWORD sector; ///< + 2 directory sector; DOS _FILES first address substitute
|
||||
// WORD cluster; ///< + 6 directory cluster; details unknown (unused)
|
||||
WORD offset; ///< + 8 directory entry; write-only
|
||||
uint32_t sector; ///< + 2 directory sector; DOS _FILES first address substitute
|
||||
// uint16_t cluster; ///< + 6 directory cluster; details unknown (unused)
|
||||
uint16_t offset; ///< + 8 directory entry; write-only
|
||||
// BYTE name[8]; ///< +10 working file name; write-only (unused)
|
||||
// BYTE ext[3]; ///< +18 working extension; write-only (unused)
|
||||
BYTE attr; ///< +21 file attribute; write-only
|
||||
WORD time; ///< +22 last change time of day; write-only
|
||||
WORD date; ///< +24 last change date; write-only
|
||||
DWORD size; ///< +26 file size; write-only
|
||||
uint16_t time; ///< +22 last change time of day; write-only
|
||||
uint16_t date; ///< +24 last change date; write-only
|
||||
uint32_t size; ///< +26 file size; write-only
|
||||
BYTE full[23]; ///< +30 full name; write-only
|
||||
};
|
||||
|
||||
struct fcb_t {
|
||||
// BYTE pad00[6]; ///< + 0~+ 5 (unused)
|
||||
DWORD fileptr; ///< + 6~+ 9 file pointer
|
||||
uint32_t fileptr; ///< + 6~+ 9 file pointer
|
||||
// BYTE pad01[4]; ///< +10~+13 (unused)
|
||||
WORD mode; ///< +14~+15 open mode
|
||||
uint16_t mode; ///< +14~+15 open mode
|
||||
// BYTE pad02[16]; ///< +16~+31 (unused)
|
||||
// DWORD zero; ///< +32~+35 zeros are written when opened (unused)
|
||||
// uint32_t zero; ///< +32~+35 zeros are written when opened (unused)
|
||||
// BYTE name[8]; ///< +36~+43 file name (PADDING 0x20) (unused)
|
||||
// BYTE ext[3]; ///< +44~+46 extension (PADDING 0x20) (unused)
|
||||
BYTE attr; ///< +47 file attribute
|
||||
// BYTE add[10]; ///< +48~+57 file name addition (PADDING 0x00) (unused)
|
||||
WORD time; ///< +58~+59 last change time of day
|
||||
WORD date; ///< +60~+61 last change date
|
||||
// WORD cluster; ///< +62~+63 cluster number (unused)
|
||||
DWORD size; ///< +64~+67 file size
|
||||
uint16_t time; ///< +58~+59 last change time of day
|
||||
uint16_t date; ///< +60~+61 last change date
|
||||
// uint16_t cluster; ///< +62~+63 cluster number (unused)
|
||||
uint32_t size; ///< +64~+67 file size
|
||||
// BYTE pad03[28]; ///< +68~+95 FAT cache (unused)
|
||||
};
|
||||
|
||||
struct capacity_t {
|
||||
WORD freearea; ///< + 0 Number of available clusters
|
||||
WORD clusters; ///< + 2 Total number of clusters
|
||||
WORD sectors; ///< + 4 Number of sectors per cluster
|
||||
WORD bytes; ///< + 6 Number of bytes per sector
|
||||
uint16_t freearea; ///< + 0 Number of available clusters
|
||||
uint16_t clusters; ///< + 2 Total number of clusters
|
||||
uint16_t sectors; ///< + 4 Number of sectors per cluster
|
||||
uint16_t bytes; ///< + 6 Number of bytes per sector
|
||||
};
|
||||
|
||||
struct ctrldrive_t {
|
||||
@ -159,17 +159,17 @@ namespace Human68k {
|
||||
};
|
||||
|
||||
struct dpb_t {
|
||||
WORD sector_size; ///< + 0 Number of bytes in one sector
|
||||
uint16_t sector_size; ///< + 0 Number of bytes in one sector
|
||||
BYTE cluster_size; ///< + 2 Number sectors in one cluster -1
|
||||
BYTE shift; ///< + 3 Number of cluster→sector shifts
|
||||
WORD fat_sector; ///< + 4 FAT first sector number
|
||||
uint16_t fat_sector; ///< + 4 FAT first sector number
|
||||
BYTE fat_max; ///< + 6 FAT storage quantity
|
||||
BYTE fat_size; ///< + 7 FAT controlled sector number (excluding duplicates)
|
||||
WORD file_max; ///< + 8 Number of files in the root directory
|
||||
WORD data_sector; ///< +10 First sector number of data storage
|
||||
WORD cluster_max; ///< +12 Total number of clusters +1
|
||||
WORD root_sector; ///< +14 First sector number of root directory
|
||||
// DWORD driverentry; ///< +16 Device driver pointer (unused)
|
||||
uint16_t file_max; ///< + 8 Number of files in the root directory
|
||||
uint16_t data_sector; ///< +10 First sector number of data storage
|
||||
uint16_t cluster_max; ///< +12 Total number of clusters +1
|
||||
uint16_t root_sector; ///< +14 First sector number of root directory
|
||||
// uint32_t driverentry; ///< +16 Device driver pointer (unused)
|
||||
BYTE media; ///< +20 Media identifier
|
||||
// BYTE flag; ///< +21 Flag used by DPB (unused)
|
||||
};
|
||||
@ -180,17 +180,17 @@ namespace Human68k {
|
||||
BYTE ext[3]; ///< + 8 Extension (PADDING 0x20)
|
||||
BYTE attr; ///< +11 File attribute
|
||||
BYTE add[10]; ///< +12 File name addition (PADDING 0x00)
|
||||
WORD time; ///< +22 Last change time of day
|
||||
WORD date; ///< +24 Last change date
|
||||
WORD cluster; ///< +26 Cluster number
|
||||
DWORD size; ///< +28 File size
|
||||
uint16_t time; ///< +22 Last change time of day
|
||||
uint16_t date; ///< +24 Last change date
|
||||
uint16_t cluster; ///< +26 Cluster number
|
||||
uint32_t size; ///< +28 File size
|
||||
};
|
||||
|
||||
/// IOCTRL parameter union
|
||||
union ioctrl_t {
|
||||
BYTE buffer[8]; ///< Access in byte units
|
||||
DWORD param; ///< Parameter (First 4 bytes)
|
||||
WORD media; ///< Media byte (First 2 bytes)
|
||||
uint32_t param; ///< Parameter (First 4 bytes)
|
||||
uint16_t media; ///< Media byte (First 2 bytes)
|
||||
};
|
||||
|
||||
/// Command line parameter struct
|
||||
@ -313,7 +313,7 @@ Normal is 0. Becomes 1 if attempting to mount in read-only mode.
|
||||
Reserving the other values for future use.
|
||||
Insurance against hard-to-detect devices such as homemade USB storage.
|
||||
*/
|
||||
static const DWORD FSFLAG_WRITE_PROTECT = 0x00000001; ///< Bit0: Force write protect
|
||||
static const uint32_t FSFLAG_WRITE_PROTECT = 0x00000001; ///< Bit0: Force write protect
|
||||
|
||||
//===========================================================================
|
||||
//
|
||||
@ -429,17 +429,17 @@ public:
|
||||
void SetEntryName(); ///< Set Human68k directory entry
|
||||
void SetEntryAttribute(BYTE nHumanAttribute)
|
||||
{ m_dirHuman.attr = nHumanAttribute; } ///< Set Human68k directory entry
|
||||
void SetEntrySize(DWORD nHumanSize)
|
||||
void SetEntrySize(uint32_t nHumanSize)
|
||||
{ m_dirHuman.size = nHumanSize; } ///< Set Human68k directory entry
|
||||
void SetEntryDate(WORD nHumanDate)
|
||||
void SetEntryDate(uint16_t nHumanDate)
|
||||
{ m_dirHuman.date = nHumanDate; } ///< Set Human68k directory entry
|
||||
void SetEntryTime(WORD nHumanTime)
|
||||
void SetEntryTime(uint16_t nHumanTime)
|
||||
{ m_dirHuman.time = nHumanTime; } ///< Set Human68k directory entry
|
||||
void SetEntryCluster(WORD nHumanCluster)
|
||||
void SetEntryCluster(uint16_t nHumanCluster)
|
||||
{ m_dirHuman.cluster = nHumanCluster; } ///< Set Human68k directory entry
|
||||
const Human68k::dirent_t* GetEntry() const
|
||||
{ return &m_dirHuman; } ///< Get Human68k directory entry
|
||||
int CheckAttribute(DWORD nHumanAttribute) const; ///< Determine Human68k directory entry attributes
|
||||
int CheckAttribute(uint32_t nHumanAttribute) const; ///< Determine Human68k directory entry attributes
|
||||
bool isSameEntry(const Human68k::dirent_t* pdirHuman) const
|
||||
{ assert(pdirHuman); return memcmp(&m_dirHuman, pdirHuman, sizeof(m_dirHuman)) == 0; }
|
||||
///< Determine Human68k directory entry match
|
||||
@ -491,8 +491,8 @@ class CHostPath: public CRing {
|
||||
public:
|
||||
/// Search buffer
|
||||
struct find_t {
|
||||
DWORD count; ///< Search execution count + 1 (When 0 the below value is invalid)
|
||||
DWORD id; ///< Entry unique ID for the path of the next search
|
||||
uint32_t count; ///< Search execution count + 1 (When 0 the below value is invalid)
|
||||
uint32_t id; ///< Entry unique ID for the path of the next search
|
||||
const ring_t* pos; ///< Position of the next search (When identical to unique ID)
|
||||
Human68k::dirent_t entry; ///< Contents of the next seach entry
|
||||
|
||||
@ -511,9 +511,9 @@ public:
|
||||
bool isSameHuman(const BYTE* szHuman) const; ///< Compare the name on the Human68k side
|
||||
bool isSameChild(const BYTE* szHuman) const; ///< Compare the name on the Human68k side
|
||||
const TCHAR* GetHost() const { return m_szHost; } ///< Obtain the name on the host side
|
||||
const CHostFilename* FindFilename(const BYTE* szHuman, DWORD nHumanAttribute = Human68k::AT_ALL) const;
|
||||
const CHostFilename* FindFilename(const BYTE* szHuman, uint32_t nHumanAttribute = Human68k::AT_ALL) const;
|
||||
///< Find file name
|
||||
const CHostFilename* FindFilenameWildcard(const BYTE* szHuman, DWORD nHumanAttribute, find_t* pFind) const;
|
||||
const CHostFilename* FindFilenameWildcard(const BYTE* szHuman, uint32_t nHumanAttribute, find_t* pFind) const;
|
||||
///< Find file name (with support for wildcards)
|
||||
bool isRefresh() const; ///< Check that the file change has been done
|
||||
void Refresh(); ///< Refresh file
|
||||
@ -533,11 +533,11 @@ private:
|
||||
CRing m_cRing; ///< For CHostFilename linking
|
||||
time_t m_tBackup = 0; ///< For time stamp restoration
|
||||
bool m_bRefresh = true; ///< Refresh flag
|
||||
DWORD m_nId = 0; ///< Unique ID (When the value has changed, it means an update has been made)
|
||||
uint32_t m_nId = 0; ///< Unique ID (When the value has changed, it means an update has been made)
|
||||
BYTE m_szHuman[HUMAN68K_PATH_MAX]; ///< The internal Human68k name for the relevant entry
|
||||
TCHAR m_szHost[FILEPATH_MAX]; ///< The host side name for the relevant entry
|
||||
|
||||
static DWORD g_nId; ///< Counter for the unique ID generation
|
||||
static uint32_t g_nId; ///< Counter for the unique ID generation
|
||||
};
|
||||
|
||||
//===========================================================================
|
||||
@ -568,15 +568,15 @@ public:
|
||||
|
||||
void Init();
|
||||
|
||||
void SetKey(DWORD nKey) { m_nKey = nKey; } ///< Set search key
|
||||
bool isSameKey(DWORD nKey) const { return m_nKey == nKey; } ///< Compare search key
|
||||
void SetKey(uint32_t nKey) { m_nKey = nKey; } ///< Set search key
|
||||
bool isSameKey(uint32_t nKey) const { return m_nKey == nKey; } ///< Compare search key
|
||||
void SetPath(const Human68k::namests_t* pNamests); ///< Create path and file name internally
|
||||
bool isRootPath() const { return m_szHumanPath[1] == '\0'; } ///< Check if root directory
|
||||
void SetPathWildcard() { m_nHumanWildcard = 1; } ///< Enable file search using wildcards
|
||||
void SetPathOnly() { m_nHumanWildcard = 0xFF; } ///< Enable only path names
|
||||
bool isPathOnly() const { return m_nHumanWildcard == 0xFF; } ///< Check if set to only path names
|
||||
void SetAttribute(DWORD nHumanAttribute) { m_nHumanAttribute = nHumanAttribute; } ///< Set search attribute
|
||||
bool Find(DWORD nUnit, const class CHostEntry* pEntry); ///< Find files on the Human68k side, generating data on the host side
|
||||
void SetAttribute(uint32_t nHumanAttribute) { m_nHumanAttribute = nHumanAttribute; } ///< Set search attribute
|
||||
bool Find(uint32_t nUnit, const class CHostEntry* pEntry); ///< Find files on the Human68k side, generating data on the host side
|
||||
const CHostFilename* Find(const CHostPath* pPath); ///< Find file name
|
||||
void SetEntry(const CHostFilename* pFilename); ///< Store search results on the Human68k side
|
||||
void SetResult(const TCHAR* szPath); ///< Set names on the host side
|
||||
@ -587,18 +587,18 @@ public:
|
||||
|
||||
const Human68k::dirent_t* GetEntry() const { return &m_dirHuman; }///< Get Human68k directory entry
|
||||
|
||||
DWORD GetAttribute() const { return m_dirHuman.attr; } ///< Get Human68k attribute
|
||||
WORD GetDate() const { return m_dirHuman.date; } ///< Get Human68k date
|
||||
WORD GetTime() const { return m_dirHuman.time; } ///< Get Human68k time
|
||||
DWORD GetSize() const { return m_dirHuman.size; } ///< Get Human68k file size
|
||||
uint32_t GetAttribute() const { return m_dirHuman.attr; } ///< Get Human68k attribute
|
||||
uint16_t GetDate() const { return m_dirHuman.date; } ///< Get Human68k date
|
||||
uint16_t GetTime() const { return m_dirHuman.time; } ///< Get Human68k time
|
||||
uint32_t GetSize() const { return m_dirHuman.size; } ///< Get Human68k file size
|
||||
const BYTE* GetHumanFilename() const { return m_szHumanFilename; }///< Get Human68k file name
|
||||
const BYTE* GetHumanResult() const { return m_szHumanResult; } ///< Get Human68k file name search results
|
||||
const BYTE* GetHumanPath() const { return m_szHumanPath; } ///< Get Human68k path name
|
||||
|
||||
private:
|
||||
DWORD m_nKey = 0; ///< FILES buffer address for Human68k; 0 is unused
|
||||
DWORD m_nHumanWildcard = 0; ///< Human68k wildcard data
|
||||
DWORD m_nHumanAttribute = 0; ///< Human68k search attribute
|
||||
uint32_t m_nKey = 0; ///< FILES buffer address for Human68k; 0 is unused
|
||||
uint32_t m_nHumanWildcard = 0; ///< Human68k wildcard data
|
||||
uint32_t m_nHumanAttribute = 0; ///< Human68k search attribute
|
||||
CHostPath::find_t m_findNext = {}; ///< Next search location data
|
||||
Human68k::dirent_t m_dirHuman = {}; ///< Search results: Human68k file data
|
||||
BYTE m_szHumanFilename[24] = {}; ///< Human68k file name
|
||||
@ -620,8 +620,8 @@ public:
|
||||
void Init(); ///< Initialization (when the driver is installed)
|
||||
void Clean(); ///< Release (when starting up or resetting)
|
||||
|
||||
CHostFiles* Alloc(DWORD nKey);
|
||||
CHostFiles* Search(DWORD nKey);
|
||||
CHostFiles* Alloc(uint32_t nKey);
|
||||
CHostFiles* Search(uint32_t nKey);
|
||||
void Free(CHostFiles* pFiles);
|
||||
private:
|
||||
/// For memory management
|
||||
@ -647,26 +647,26 @@ public:
|
||||
|
||||
void Init();
|
||||
|
||||
void SetKey(DWORD nKey) { m_nKey = nKey; } ///< Set search key
|
||||
bool isSameKey(DWORD nKey) const { return m_nKey == nKey; } ///< Compare search key
|
||||
void SetKey(uint32_t nKey) { m_nKey = nKey; } ///< Set search key
|
||||
bool isSameKey(uint32_t nKey) const { return m_nKey == nKey; } ///< Compare search key
|
||||
void SetUpdate() { m_bUpdate = true; } ///< Update
|
||||
bool isUpdate() const { return m_bUpdate; } ///< Get update state
|
||||
bool SetMode(DWORD nHumanMode); ///< Set file open mode
|
||||
bool SetMode(uint32_t nHumanMode); ///< Set file open mode
|
||||
void SetFilename(const TCHAR* szFilename); ///< Set file name
|
||||
void SetHumanPath(const BYTE* szHumanPath); ///< Set Human68k path name
|
||||
const BYTE* GetHumanPath() const { return m_szHumanPath; } ///< Get Human68k path name
|
||||
|
||||
bool Create(DWORD nHumanAttribute, bool bForce); ///< Create file
|
||||
bool Create(uint32_t nHumanAttribute, bool bForce); ///< Create file
|
||||
bool Open(); ///< Open file
|
||||
DWORD Read(BYTE* pBuffer, DWORD nSize); ///< Read file
|
||||
DWORD Write(const BYTE* pBuffer, DWORD nSize); ///< Write file
|
||||
uint32_t Read(BYTE* pBuffer, uint32_t nSize); ///< Read file
|
||||
uint32_t Write(const BYTE* pBuffer, uint32_t nSize); ///< Write file
|
||||
bool Truncate() const; ///< Truncate file
|
||||
DWORD Seek(DWORD nOffset, Human68k::seek_t nHumanSeek); ///< Seek file
|
||||
bool TimeStamp(DWORD nHumanTime) const; ///< Set file time stamp
|
||||
uint32_t Seek(uint32_t nOffset, Human68k::seek_t nHumanSeek); ///< Seek file
|
||||
bool TimeStamp(uint32_t nHumanTime) const; ///< Set file time stamp
|
||||
void Close(); ///< Close file
|
||||
|
||||
private:
|
||||
DWORD m_nKey = 0; ///< Human68k FCB buffer address (0 if unused)
|
||||
uint32_t m_nKey = 0; ///< Human68k FCB buffer address (0 if unused)
|
||||
bool m_bUpdate = false; ///< Update flag
|
||||
FILE* m_pFile = nullptr; ///< Host side file object
|
||||
const char* m_pszMode = nullptr; ///< Host side file open mode
|
||||
@ -688,8 +688,8 @@ public:
|
||||
void Init(); ///< Initialization (when the driver is installed)
|
||||
void Clean() const; ///< Release (when starting up or resetting)
|
||||
|
||||
CHostFcb* Alloc(DWORD nKey);
|
||||
CHostFcb* Search(DWORD nKey);
|
||||
CHostFcb* Alloc(uint32_t nKey);
|
||||
CHostFcb* Search(uint32_t nKey);
|
||||
void Free(CHostFcb* p);
|
||||
|
||||
private:
|
||||
@ -717,20 +717,20 @@ public:
|
||||
CHostDrv(CHostDrv&) = default;
|
||||
CHostDrv& operator=(const CHostDrv&) = default;
|
||||
|
||||
void Init(const TCHAR* szBase, DWORD nFlag); ///< Initialization (device startup and load)
|
||||
void Init(const TCHAR* szBase, uint32_t nFlag); ///< Initialization (device startup and load)
|
||||
|
||||
bool isWriteProtect() const { return m_bWriteProtect; }
|
||||
bool isEnable() const { return m_bEnable; } ///< Is it accessible?
|
||||
bool isMediaOffline() const;
|
||||
BYTE GetMediaByte() const;
|
||||
DWORD GetStatus() const;
|
||||
uint32_t GetStatus() const;
|
||||
void SetEnable(bool); ///< Set media status
|
||||
bool CheckMedia(); ///< Check if media was changed
|
||||
void Update(); ///< Update media status
|
||||
void Eject();
|
||||
void GetVolume(TCHAR* szLabel); ///< Get volume label
|
||||
bool GetVolumeCache(TCHAR* szLabel) const; ///< Get volume label from cache
|
||||
DWORD GetCapacity(Human68k::capacity_t* pCapacity);
|
||||
uint32_t GetCapacity(Human68k::capacity_t* pCapacity);
|
||||
bool GetCapacityCache(Human68k::capacity_t* pCapacity) const; ///< Get capacity from cache
|
||||
|
||||
// Cache operations
|
||||
@ -756,7 +756,7 @@ private:
|
||||
|
||||
bool m_bWriteProtect = false; ///< TRUE if write-protected
|
||||
bool m_bEnable = false; ///< TRUE if media is usable
|
||||
DWORD m_nRing = 0; ///< Number of stored path names
|
||||
uint32_t m_nRing = 0; ///< Number of stored path names
|
||||
CRing m_cRing; ///< For attaching to CHostPath
|
||||
Human68k::capacity_t m_capCache; ///< Sector data cache: if "sectors == 0" then not cached
|
||||
bool m_bVolumeCache = false; ///< TRUE if the volume label has been read
|
||||
@ -786,31 +786,31 @@ public:
|
||||
|
||||
// Cache operations
|
||||
void CleanCache() const; ///< Update all cache
|
||||
void CleanCache(DWORD nUnit) const; ///< Update cache for the specified unit
|
||||
void CleanCache(DWORD nUnit, const BYTE* szHumanPath) const; ///< Update cache for the specified path
|
||||
void CleanCacheChild(DWORD nUnit, const BYTE* szHumanPath) const; ///< Update cache below the specified path
|
||||
void DeleteCache(DWORD nUnit, const BYTE* szHumanPath) const; ///< Delete cache for the specified path
|
||||
bool Find(DWORD nUnit, CHostFiles* pFiles) const; ///< Find host side name (path + file name (can be abbreviated) + attribute)
|
||||
void ShellNotify(DWORD nEvent, const TCHAR* szPath); ///< Notify status change in the host side file system
|
||||
void CleanCache(uint32_t nUnit) const; ///< Update cache for the specified unit
|
||||
void CleanCache(uint32_t nUnit, const BYTE* szHumanPath) const; ///< Update cache for the specified path
|
||||
void CleanCacheChild(uint32_t nUnit, const BYTE* szHumanPath) const; ///< Update cache below the specified path
|
||||
void DeleteCache(uint32_t nUnit, const BYTE* szHumanPath) const; ///< Delete cache for the specified path
|
||||
bool Find(uint32_t nUnit, CHostFiles* pFiles) const; ///< Find host side name (path + file name (can be abbreviated) + attribute)
|
||||
void ShellNotify(uint32_t nEvent, const TCHAR* szPath); ///< Notify status change in the host side file system
|
||||
|
||||
// Drive object operations
|
||||
void SetDrv(DWORD nUnit, CHostDrv* pDrv);
|
||||
bool isWriteProtect(DWORD nUnit) const;
|
||||
bool isEnable(DWORD nUnit) const; ///< Is it accessible?
|
||||
bool isMediaOffline(DWORD nUnit) const;
|
||||
BYTE GetMediaByte(DWORD nUnit) const;
|
||||
DWORD GetStatus(DWORD nUnit) const; ///< Get drive status
|
||||
bool CheckMedia(DWORD nUnit) const; ///< Media change check
|
||||
void Eject(DWORD nUnit) const;
|
||||
void GetVolume(DWORD nUnit, TCHAR* szLabel) const; ///< Get volume label
|
||||
bool GetVolumeCache(DWORD nUnit, TCHAR* szLabel) const; ///< Get volume label from cache
|
||||
DWORD GetCapacity(DWORD nUnit, Human68k::capacity_t* pCapacity) const;
|
||||
bool GetCapacityCache(DWORD nUnit, Human68k::capacity_t* pCapacity) const; ///< Get cluster size from cache
|
||||
void SetDrv(uint32_t nUnit, CHostDrv* pDrv);
|
||||
bool isWriteProtect(uint32_t nUnit) const;
|
||||
bool isEnable(uint32_t nUnit) const; ///< Is it accessible?
|
||||
bool isMediaOffline(uint32_t nUnit) const;
|
||||
BYTE GetMediaByte(uint32_t nUnit) const;
|
||||
uint32_t GetStatus(uint32_t nUnit) const; ///< Get drive status
|
||||
bool CheckMedia(uint32_t nUnit) const; ///< Media change check
|
||||
void Eject(uint32_t nUnit) const;
|
||||
void GetVolume(uint32_t nUnit, TCHAR* szLabel) const; ///< Get volume label
|
||||
bool GetVolumeCache(uint32_t nUnit, TCHAR* szLabel) const; ///< Get volume label from cache
|
||||
uint32_t GetCapacity(uint32_t nUnit, Human68k::capacity_t* pCapacity) const;
|
||||
bool GetCapacityCache(uint32_t nUnit, Human68k::capacity_t* pCapacity) const; ///< Get cluster size from cache
|
||||
|
||||
private:
|
||||
|
||||
CHostDrv* m_pDrv[DRIVE_MAX] = {}; ///< Host side drive object
|
||||
DWORD m_nTimeout = 0; ///< Last time a timeout check was carried out
|
||||
uint32_t m_nTimeout = 0; ///< Last time a timeout check was carried out
|
||||
};
|
||||
|
||||
//===========================================================================
|
||||
@ -854,71 +854,71 @@ public:
|
||||
void Init(); ///< Initialization (device startup and load)
|
||||
|
||||
// Command handlers
|
||||
DWORD InitDevice(const Human68k::argument_t* pArgument); ///< $40 - Device startup
|
||||
int CheckDir(DWORD nUnit, const Human68k::namests_t* pNamests) const; ///< $41 - Directory check
|
||||
int MakeDir(DWORD nUnit, const Human68k::namests_t* pNamests) const; ///< $42 - Create directory
|
||||
int RemoveDir(DWORD nUnit, const Human68k::namests_t* pNamests) const; ///< $43 - Delete directory
|
||||
int Rename(DWORD nUnit, const Human68k::namests_t* pNamests, const Human68k::namests_t* pNamestsNew) const;
|
||||
uint32_t InitDevice(const Human68k::argument_t* pArgument); ///< $40 - Device startup
|
||||
int CheckDir(uint32_t nUnit, const Human68k::namests_t* pNamests) const; ///< $41 - Directory check
|
||||
int MakeDir(uint32_t nUnit, const Human68k::namests_t* pNamests) const; ///< $42 - Create directory
|
||||
int RemoveDir(uint32_t nUnit, const Human68k::namests_t* pNamests) const; ///< $43 - Delete directory
|
||||
int Rename(uint32_t nUnit, const Human68k::namests_t* pNamests, const Human68k::namests_t* pNamestsNew) const;
|
||||
///< $44 - Change file name
|
||||
int Delete(DWORD nUnit, const Human68k::namests_t* pNamests) const; ///< $45 - Delete file
|
||||
int Attribute(DWORD nUnit, const Human68k::namests_t* pNamests, DWORD nHumanAttribute) const;
|
||||
int Delete(uint32_t nUnit, const Human68k::namests_t* pNamests) const; ///< $45 - Delete file
|
||||
int Attribute(uint32_t nUnit, const Human68k::namests_t* pNamests, uint32_t nHumanAttribute) const;
|
||||
///< $46 - Get / set file attribute
|
||||
int Files(DWORD nUnit, DWORD nKey, const Human68k::namests_t* pNamests, Human68k::files_t* pFiles);
|
||||
int Files(uint32_t nUnit, uint32_t nKey, const Human68k::namests_t* pNamests, Human68k::files_t* pFiles);
|
||||
///< $47 - Find file
|
||||
int NFiles(DWORD nUnit, DWORD nKey, Human68k::files_t* pFiles); ///< $48 - Find next file
|
||||
int Create(DWORD nUnit, DWORD nKey, const Human68k::namests_t* pNamests, Human68k::fcb_t* pFcb, DWORD nHumanAttribute, bool bForce);
|
||||
int NFiles(uint32_t nUnit, uint32_t nKey, Human68k::files_t* pFiles); ///< $48 - Find next file
|
||||
int Create(uint32_t nUnit, uint32_t nKey, const Human68k::namests_t* pNamests, Human68k::fcb_t* pFcb, uint32_t nHumanAttribute, bool bForce);
|
||||
///< $49 - Create file
|
||||
int Open(DWORD nUnit, DWORD nKey, const Human68k::namests_t* pNamests, Human68k::fcb_t* pFcb);
|
||||
int Open(uint32_t nUnit, uint32_t nKey, const Human68k::namests_t* pNamests, Human68k::fcb_t* pFcb);
|
||||
///< $4A - Open file
|
||||
int Close(DWORD nUnit, DWORD nKey, const Human68k::fcb_t* pFcb); ///< $4B - Close file
|
||||
int Read(DWORD nKey, Human68k::fcb_t* pFcb, BYTE* pAddress, DWORD nSize);
|
||||
int Close(uint32_t nUnit, uint32_t nKey, const Human68k::fcb_t* pFcb); ///< $4B - Close file
|
||||
int Read(uint32_t nKey, Human68k::fcb_t* pFcb, BYTE* pAddress, uint32_t nSize);
|
||||
///< $4C - Read file
|
||||
int Write(DWORD nKey, Human68k::fcb_t* pFcb, const BYTE* pAddress, DWORD nSize);
|
||||
int Write(uint32_t nKey, Human68k::fcb_t* pFcb, const BYTE* pAddress, uint32_t nSize);
|
||||
///< $4D - Write file
|
||||
int Seek(DWORD nKey, Human68k::fcb_t* pFcb, DWORD nSeek, int nOffset); ///< $4E - Seek file
|
||||
DWORD TimeStamp(DWORD nUnit, DWORD nKey, Human68k::fcb_t* pFcb, DWORD nHumanTime);
|
||||
int Seek(uint32_t nKey, Human68k::fcb_t* pFcb, uint32_t nSeek, int nOffset); ///< $4E - Seek file
|
||||
uint32_t TimeStamp(uint32_t nUnit, uint32_t nKey, Human68k::fcb_t* pFcb, uint32_t nHumanTime);
|
||||
///< $4F - Get / set file timestamp
|
||||
int GetCapacity(DWORD nUnit, Human68k::capacity_t* pCapacity) const; ///< $50 - Get capacity
|
||||
int CtrlDrive(DWORD nUnit, Human68k::ctrldrive_t* pCtrlDrive) const; ///< $51 - Inspect / control drive status
|
||||
int GetDPB(DWORD nUnit, Human68k::dpb_t* pDpb) const; ///< $52 - Get DPB
|
||||
int DiskRead(DWORD nUnit, BYTE* pBuffer, DWORD nSector, DWORD nSize); ///< $53 - Read sectors
|
||||
int DiskWrite(DWORD nUnit) const; ///< $54 - Write sectors
|
||||
int Ioctrl(DWORD nUnit, DWORD nFunction, Human68k::ioctrl_t* pIoctrl); ///< $55 - IOCTRL
|
||||
int Flush(DWORD nUnit) const; ///< $56 - Flush
|
||||
int CheckMedia(DWORD nUnit) const; ///< $57 - Media change check
|
||||
int Lock(DWORD nUnit) const; ///< $58 - Lock
|
||||
int GetCapacity(uint32_t nUnit, Human68k::capacity_t* pCapacity) const; ///< $50 - Get capacity
|
||||
int CtrlDrive(uint32_t nUnit, Human68k::ctrldrive_t* pCtrlDrive) const; ///< $51 - Inspect / control drive status
|
||||
int GetDPB(uint32_t nUnit, Human68k::dpb_t* pDpb) const; ///< $52 - Get DPB
|
||||
int DiskRead(uint32_t nUnit, BYTE* pBuffer, uint32_t nSector, uint32_t nSize); ///< $53 - Read sectors
|
||||
int DiskWrite(uint32_t nUnit) const; ///< $54 - Write sectors
|
||||
int Ioctrl(uint32_t nUnit, uint32_t nFunction, Human68k::ioctrl_t* pIoctrl); ///< $55 - IOCTRL
|
||||
int Flush(uint32_t nUnit) const; ///< $56 - Flush
|
||||
int CheckMedia(uint32_t nUnit) const; ///< $57 - Media change check
|
||||
int Lock(uint32_t nUnit) const; ///< $58 - Lock
|
||||
|
||||
void SetOption(DWORD nOption); ///< Set option
|
||||
DWORD GetOption() const { return m_nOption; } ///< Get option
|
||||
DWORD GetDefault() const { return m_nOptionDefault; } ///< Get default options
|
||||
static DWORD GetFileOption() { return g_nOption; } ///< Get file name change option
|
||||
void SetOption(uint32_t nOption); ///< Set option
|
||||
uint32_t GetOption() const { return m_nOption; } ///< Get option
|
||||
uint32_t GetDefault() const { return m_nOptionDefault; } ///< Get default options
|
||||
static uint32_t GetFileOption() { return g_nOption; } ///< Get file name change option
|
||||
|
||||
static const int DriveMax = CHostEntry::DRIVE_MAX; ///< Max number of drive candidates
|
||||
|
||||
private:
|
||||
void InitOption(const Human68k::argument_t* pArgument);
|
||||
bool FilesVolume(DWORD nUnit, Human68k::files_t* pFiles) const; ///< Get volume label
|
||||
bool FilesVolume(uint32_t nUnit, Human68k::files_t* pFiles) const; ///< Get volume label
|
||||
|
||||
DWORD m_nUnits = 0; ///< Number of current drive objects (Changes for every resume)
|
||||
uint32_t m_nUnits = 0; ///< Number of current drive objects (Changes for every resume)
|
||||
|
||||
DWORD m_nOption = 0; ///< Current runtime flag
|
||||
DWORD m_nOptionDefault = 0; ///< Runtime flag at reset
|
||||
uint32_t m_nOption = 0; ///< Current runtime flag
|
||||
uint32_t m_nOptionDefault = 0; ///< Runtime flag at reset
|
||||
|
||||
DWORD m_nDrives = 0; ///< Number of candidates for base path status restoration (scan every time if 0)
|
||||
uint32_t m_nDrives = 0; ///< Number of candidates for base path status restoration (scan every time if 0)
|
||||
|
||||
DWORD m_nKernel = 0; ///< Counter for kernel check
|
||||
DWORD m_nKernelSearch = 0; ///< Initial address for NUL device
|
||||
uint32_t m_nKernel = 0; ///< Counter for kernel check
|
||||
uint32_t m_nKernelSearch = 0; ///< Initial address for NUL device
|
||||
|
||||
DWORD m_nHostSectorCount = 0; ///< Virtual sector identifier
|
||||
uint32_t m_nHostSectorCount = 0; ///< Virtual sector identifier
|
||||
|
||||
CHostFilesManager m_cFiles; ///< File search memory
|
||||
CHostFcbManager m_cFcb; ///< FCB operation memory
|
||||
CHostEntry m_cEntry; ///< Drive object and directory entry
|
||||
|
||||
DWORD m_nHostSectorBuffer[XM6_HOST_PSEUDO_CLUSTER_MAX];
|
||||
uint32_t m_nHostSectorBuffer[XM6_HOST_PSEUDO_CLUSTER_MAX];
|
||||
///< Entity that the virtual sector points to
|
||||
|
||||
DWORD m_nFlag[DriveMax] = {}; ///< Candidate runtime flag for base path restoration
|
||||
uint32_t m_nFlag[DriveMax] = {}; ///< Candidate runtime flag for base path restoration
|
||||
TCHAR m_szBase[DriveMax][FILEPATH_MAX] = {}; ///< Candidate for base path restoration
|
||||
static DWORD g_nOption; ///< File name change flag
|
||||
static uint32_t g_nOption; ///< File name change flag
|
||||
};
|
||||
|
@ -177,7 +177,7 @@ bool CTapDriver::Init(const unordered_map<string, string>& const_params)
|
||||
|
||||
LOGTRACE("Return code from ioctl was %d", ret)
|
||||
|
||||
int ip_fd = socket(PF_INET, SOCK_DGRAM, 0);
|
||||
const int ip_fd = socket(PF_INET, SOCK_DGRAM, 0);
|
||||
if (ip_fd < 0) {
|
||||
LOGERROR("Can't open ip socket: %s", strerror(errno))
|
||||
|
||||
@ -185,7 +185,7 @@ bool CTapDriver::Init(const unordered_map<string, string>& const_params)
|
||||
return false;
|
||||
}
|
||||
|
||||
int br_socket_fd = socket(AF_LOCAL, SOCK_STREAM, 0);
|
||||
const int br_socket_fd = socket(AF_LOCAL, SOCK_STREAM, 0);
|
||||
if (br_socket_fd < 0) {
|
||||
LOGERROR("Can't open bridge socket: %s", strerror(errno))
|
||||
|
||||
@ -260,7 +260,7 @@ bool CTapDriver::Init(const unordered_map<string, string>& const_params)
|
||||
}
|
||||
|
||||
// long long is required for compatibility with 32 bit platforms
|
||||
auto mask = (long long)(pow(2, 32) - (1 << (32 - m)));
|
||||
const auto mask = (long long)(pow(2, 32) - (1 << (32 - m)));
|
||||
netmask = to_string((mask >> 24) & 0xff) + '.' + to_string((mask >> 16) & 0xff) + '.' +
|
||||
to_string((mask >> 8) & 0xff) + '.' + to_string(mask & 0xff);
|
||||
|
||||
@ -391,18 +391,18 @@ void CTapDriver::OpenDump(const Filepath& path) {
|
||||
|
||||
bool CTapDriver::Enable() const
|
||||
{
|
||||
int fd = socket(PF_INET, SOCK_DGRAM, 0);
|
||||
const int fd = socket(PF_INET, SOCK_DGRAM, 0);
|
||||
LOGDEBUG("%s: ip link set ras0 up", __PRETTY_FUNCTION__)
|
||||
bool result = ip_link(fd, "ras0", true);
|
||||
const bool result = ip_link(fd, "ras0", true);
|
||||
close(fd);
|
||||
return result;
|
||||
}
|
||||
|
||||
bool CTapDriver::Disable() const
|
||||
{
|
||||
int fd = socket(PF_INET, SOCK_DGRAM, 0);
|
||||
const int fd = socket(PF_INET, SOCK_DGRAM, 0);
|
||||
LOGDEBUG("%s: ip link set ras0 down", __PRETTY_FUNCTION__)
|
||||
bool result = ip_link(fd, "ras0", false);
|
||||
const bool result = ip_link(fd, "ras0", false);
|
||||
close(fd);
|
||||
return result;
|
||||
}
|
||||
@ -452,7 +452,7 @@ uint32_t CTapDriver::Crc32(const BYTE *buf, int length) {
|
||||
for (int i = 0; i < length; i++) {
|
||||
crc ^= buf[i];
|
||||
for (int j = 0; j < 8; j++) {
|
||||
uint32_t mask = -((int)crc & 1);
|
||||
const uint32_t mask = -((int)crc & 1);
|
||||
crc = (crc >> 1) ^ (0xEDB88320 & mask);
|
||||
}
|
||||
}
|
||||
@ -469,8 +469,8 @@ int CTapDriver::Receive(BYTE *buf)
|
||||
}
|
||||
|
||||
// Receive
|
||||
auto dwReceived = (DWORD)read(m_hTAP, buf, ETH_FRAME_LEN);
|
||||
if (dwReceived == (DWORD)-1) {
|
||||
auto dwReceived = (uint32_t)read(m_hTAP, buf, ETH_FRAME_LEN);
|
||||
if (dwReceived == (uint32_t)-1) {
|
||||
LOGWARN("%s Error occured while receiving a packet", __PRETTY_FUNCTION__)
|
||||
return 0;
|
||||
}
|
||||
@ -480,7 +480,7 @@ int CTapDriver::Receive(BYTE *buf)
|
||||
// We need to add the Frame Check Status (FCS) CRC back onto the end of the packet.
|
||||
// The Linux network subsystem removes it, since most software apps shouldn't ever
|
||||
// need it.
|
||||
int crc = Crc32(buf, dwReceived);
|
||||
const int crc = Crc32(buf, dwReceived);
|
||||
|
||||
buf[dwReceived + 0] = (BYTE)((crc >> 0) & 0xFF);
|
||||
buf[dwReceived + 1] = (BYTE)((crc >> 8) & 0xFF);
|
||||
|
@ -23,20 +23,16 @@ using namespace std;
|
||||
|
||||
class CTapDriver
|
||||
{
|
||||
friend class SCSIDaynaPort;
|
||||
friend class SCSIBR;
|
||||
|
||||
static constexpr const char *BRIDGE_NAME = "rascsi_bridge";
|
||||
|
||||
public:
|
||||
|
||||
CTapDriver() = default;
|
||||
~CTapDriver();
|
||||
CTapDriver(CTapDriver&) = default;
|
||||
CTapDriver& operator=(const CTapDriver&) = default;
|
||||
|
||||
bool Init(const unordered_map<string, string>&);
|
||||
|
||||
public:
|
||||
|
||||
void OpenDump(const Filepath& path); // Capture packets
|
||||
void GetMacAddr(BYTE *mac) const;
|
||||
int Receive(BYTE *buf);
|
||||
|
@ -76,7 +76,7 @@ string Device::GetPaddedName() const
|
||||
ostringstream os;
|
||||
os << left << setfill(' ') << setw(8) << vendor << setw(16) << product << setw(4) << revision;
|
||||
|
||||
string name = os.str();
|
||||
const string name = os.str();
|
||||
assert(name.length() == 28);
|
||||
|
||||
return name;
|
||||
|
@ -56,12 +56,17 @@ DeviceFactory::DeviceFactory()
|
||||
extension_mapping["hdr"] = SCRM;
|
||||
extension_mapping["mos"] = SCMO;
|
||||
extension_mapping["iso"] = SCCD;
|
||||
|
||||
device_mapping["bridge"] = SCBR;
|
||||
device_mapping["daynaport"] = SCDP;
|
||||
device_mapping["printer"] = SCLP;
|
||||
device_mapping["services"] = SCHS;
|
||||
}
|
||||
|
||||
string DeviceFactory::GetExtension(const string& filename) const
|
||||
{
|
||||
string ext;
|
||||
if (size_t separator = filename.rfind('.'); separator != string::npos) {
|
||||
if (const size_t separator = filename.rfind('.'); separator != string::npos) {
|
||||
ext = filename.substr(separator + 1);
|
||||
}
|
||||
std::transform(ext.begin(), ext.end(), ext.begin(), [](unsigned char c){ return std::tolower(c); });
|
||||
@ -74,17 +79,9 @@ PbDeviceType DeviceFactory::GetTypeForFile(const string& filename) const
|
||||
if (const auto& it = extension_mapping.find(GetExtension(filename)); it != extension_mapping.end()) {
|
||||
return it->second;
|
||||
}
|
||||
else if (filename == "bridge") {
|
||||
return SCBR;
|
||||
}
|
||||
else if (filename == "daynaport") {
|
||||
return SCDP;
|
||||
}
|
||||
else if (filename == "printer") {
|
||||
return SCLP;
|
||||
}
|
||||
else if (filename == "services") {
|
||||
return SCHS;
|
||||
|
||||
if (const auto& it = device_mapping.find(filename); it != device_mapping.end()) {
|
||||
return it->second;
|
||||
}
|
||||
|
||||
return UNDEFINED;
|
||||
@ -105,7 +102,7 @@ shared_ptr<PrimaryDevice> DeviceFactory::CreateDevice(const ControllerManager& c
|
||||
shared_ptr<PrimaryDevice> device;
|
||||
switch (type) {
|
||||
case SCHD: {
|
||||
if (string ext = GetExtension(filename); ext == "hdn" || ext == "hdi" || ext == "nhd") {
|
||||
if (const string ext = GetExtension(filename); ext == "hdn" || ext == "hdi" || ext == "nhd") {
|
||||
device = make_shared<SCSIHD_NEC>(lun);
|
||||
} else {
|
||||
device = make_shared<SCSIHD>(lun, sector_sizes[SCHD], false,
|
||||
@ -220,10 +217,10 @@ list<string> DeviceFactory::GetNetworkInterfaces() const
|
||||
while (tmp) {
|
||||
if (tmp->ifa_addr && tmp->ifa_addr->sa_family == AF_PACKET &&
|
||||
strcmp(tmp->ifa_name, "lo") && strcmp(tmp->ifa_name, "rascsi_bridge")) {
|
||||
int fd = socket(PF_INET, SOCK_DGRAM, IPPROTO_IP);
|
||||
const int fd = socket(PF_INET, SOCK_DGRAM, IPPROTO_IP);
|
||||
|
||||
ifreq ifr = {};
|
||||
strcpy(ifr.ifr_name, tmp->ifa_name);
|
||||
strncpy(ifr.ifr_name, tmp->ifa_name, IFNAMSIZ); //NOSONAR Using strncpy is safe here
|
||||
// Only list interfaces that are up
|
||||
if (!ioctl(fd, SIOCGIFFLAGS, &ifr) && (ifr.ifr_flags & IFF_UP)) {
|
||||
network_interfaces.emplace_back(tmp->ifa_name);
|
||||
|
@ -38,7 +38,7 @@ public:
|
||||
const unordered_set<uint32_t>& GetSectorSizes(const string&) const;
|
||||
const unordered_map<string, string>& GetDefaultParams(PbDeviceType type) const;
|
||||
list<string> GetNetworkInterfaces() const;
|
||||
unordered_map<string, PbDeviceType> GetExtensionMapping() const { return extension_mapping; }
|
||||
const unordered_map<string, PbDeviceType>& GetExtensionMapping() const { return extension_mapping; }
|
||||
|
||||
private:
|
||||
|
||||
@ -50,6 +50,8 @@ private:
|
||||
|
||||
unordered_map<string, PbDeviceType> extension_mapping;
|
||||
|
||||
unordered_map<string, PbDeviceType> device_mapping;
|
||||
|
||||
unordered_set<uint32_t> empty_set;
|
||||
unordered_map<string, string> empty_map;
|
||||
};
|
||||
|
@ -14,9 +14,7 @@
|
||||
//
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
#include "os.h"
|
||||
#include "fileio.h"
|
||||
#include "file_support.h"
|
||||
#include "rascsi_exceptions.h"
|
||||
#include "dispatcher.h"
|
||||
#include "scsi_command_util.h"
|
||||
@ -25,6 +23,8 @@
|
||||
using namespace scsi_defs;
|
||||
using namespace scsi_command_util;
|
||||
|
||||
unordered_map<string, id_set> Disk::reserved_files;
|
||||
|
||||
Disk::Disk(const string& type, int lun) : ModePageDevice(type, lun)
|
||||
{
|
||||
dispatcher.Add(scsi_command::eCmdRezero, "Rezero", &Disk::Rezero);
|
||||
@ -73,7 +73,7 @@ bool Disk::Dispatch(scsi_command cmd)
|
||||
|
||||
is_medium_changed = false;
|
||||
|
||||
throw scsi_error_exception(sense_key::UNIT_ATTENTION, asc::NOT_READY_TO_READY_CHANGE);
|
||||
throw scsi_exception(sense_key::UNIT_ATTENTION, asc::NOT_READY_TO_READY_CHANGE);
|
||||
}
|
||||
|
||||
// The superclass handles the less specific commands
|
||||
@ -141,7 +141,7 @@ void Disk::FormatUnit()
|
||||
|
||||
// FMTDATA=1 is not supported (but OK if there is no DEFECT LIST)
|
||||
if ((ctrl->cmd[1] & 0x10) != 0 && ctrl->cmd[4] != 0) {
|
||||
throw scsi_error_exception(sense_key::ILLEGAL_REQUEST, asc::INVALID_FIELD_IN_CDB);
|
||||
throw scsi_exception(sense_key::ILLEGAL_REQUEST, asc::INVALID_FIELD_IN_CDB);
|
||||
}
|
||||
|
||||
EnterStatusPhase();
|
||||
@ -187,7 +187,7 @@ void Disk::ReadWriteLong10()
|
||||
{
|
||||
// Transfer lengths other than 0 are not supported, which is compliant with the SCSI standard
|
||||
if (GetInt16(ctrl->cmd, 7) != 0) {
|
||||
throw scsi_error_exception(sense_key::ILLEGAL_REQUEST, asc::INVALID_FIELD_IN_CDB);
|
||||
throw scsi_exception(sense_key::ILLEGAL_REQUEST, asc::INVALID_FIELD_IN_CDB);
|
||||
}
|
||||
|
||||
ValidateBlockAddress(RW10);
|
||||
@ -199,7 +199,7 @@ void Disk::ReadWriteLong16()
|
||||
{
|
||||
// Transfer lengths other than 0 are not supported, which is compliant with the SCSI standard
|
||||
if (GetInt16(ctrl->cmd, 12) != 0) {
|
||||
throw scsi_error_exception(sense_key::ILLEGAL_REQUEST, asc::INVALID_FIELD_IN_CDB);
|
||||
throw scsi_exception(sense_key::ILLEGAL_REQUEST, asc::INVALID_FIELD_IN_CDB);
|
||||
}
|
||||
|
||||
ValidateBlockAddress(RW16);
|
||||
@ -271,8 +271,8 @@ void Disk::Verify16()
|
||||
|
||||
void Disk::StartStopUnit()
|
||||
{
|
||||
bool start = ctrl->cmd[4] & 0x01;
|
||||
bool load = ctrl->cmd[4] & 0x02;
|
||||
const bool start = ctrl->cmd[4] & 0x01;
|
||||
const bool load = ctrl->cmd[4] & 0x02;
|
||||
|
||||
if (load) {
|
||||
LOGTRACE(start ? "Loading medium" : "Ejecting medium")
|
||||
@ -290,12 +290,12 @@ void Disk::StartStopUnit()
|
||||
if (load) {
|
||||
if (IsLocked()) {
|
||||
// Cannot be ejected because it is locked
|
||||
throw scsi_error_exception(sense_key::ILLEGAL_REQUEST, asc::LOAD_OR_EJECT_FAILED);
|
||||
throw scsi_exception(sense_key::ILLEGAL_REQUEST, asc::LOAD_OR_EJECT_FAILED);
|
||||
}
|
||||
|
||||
// Eject
|
||||
if (!Eject(false)) {
|
||||
throw scsi_error_exception();
|
||||
throw scsi_exception();
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -307,12 +307,12 @@ void Disk::SendDiagnostic()
|
||||
{
|
||||
// Do not support PF bit
|
||||
if (ctrl->cmd[1] & 0x10) {
|
||||
throw scsi_error_exception(sense_key::ILLEGAL_REQUEST, asc::INVALID_FIELD_IN_CDB);
|
||||
throw scsi_exception(sense_key::ILLEGAL_REQUEST, asc::INVALID_FIELD_IN_CDB);
|
||||
}
|
||||
|
||||
// Do not support parameter list
|
||||
if ((ctrl->cmd[3] != 0) || (ctrl->cmd[4] != 0)) {
|
||||
throw scsi_error_exception(sense_key::ILLEGAL_REQUEST, asc::INVALID_FIELD_IN_CDB);
|
||||
throw scsi_exception(sense_key::ILLEGAL_REQUEST, asc::INVALID_FIELD_IN_CDB);
|
||||
}
|
||||
|
||||
EnterStatusPhase();
|
||||
@ -322,7 +322,7 @@ void Disk::PreventAllowMediumRemoval()
|
||||
{
|
||||
CheckReady();
|
||||
|
||||
bool lock = ctrl->cmd[4] & 0x01;
|
||||
const bool lock = ctrl->cmd[4] & 0x01;
|
||||
|
||||
LOGTRACE(lock ? "Locking medium" : "Unlocking medium")
|
||||
|
||||
@ -340,7 +340,7 @@ void Disk::SynchronizeCache()
|
||||
|
||||
void Disk::ReadDefectData10()
|
||||
{
|
||||
size_t allocation_length = min((size_t)GetInt16(ctrl->cmd, 7), (size_t)4);
|
||||
const size_t allocation_length = min((size_t)GetInt16(ctrl->cmd, 7), (size_t)4);
|
||||
|
||||
// The defect list is empty
|
||||
fill_n(controller->GetBuffer().begin(), allocation_length, 0);
|
||||
@ -361,15 +361,13 @@ void Disk::MediumChanged()
|
||||
|
||||
bool Disk::Eject(bool force)
|
||||
{
|
||||
bool status = super::Eject(force);
|
||||
const bool status = super::Eject(force);
|
||||
if (status) {
|
||||
FlushCache();
|
||||
cache.reset();
|
||||
|
||||
// The image file for this drive is not in use anymore
|
||||
if (auto file_support = dynamic_cast<FileSupport *>(this); file_support) {
|
||||
file_support->UnreserveFile();
|
||||
}
|
||||
UnreserveFile();
|
||||
}
|
||||
|
||||
return status;
|
||||
@ -378,7 +376,7 @@ bool Disk::Eject(bool force)
|
||||
int Disk::ModeSense6(const vector<int>& cdb, vector<BYTE>& buf) const
|
||||
{
|
||||
// Get length, clear buffer
|
||||
auto length = (int)min(buf.size(), (size_t)cdb[4]);
|
||||
const auto length = (int)min(buf.size(), (size_t)cdb[4]);
|
||||
fill_n(buf.begin(), length, 0);
|
||||
|
||||
// DEVICE SPECIFIC PARAMETER
|
||||
@ -406,7 +404,7 @@ int Disk::ModeSense6(const vector<int>& cdb, vector<BYTE>& buf) const
|
||||
|
||||
size += super::AddModePages(cdb, buf, size, length - size);
|
||||
if (size > 255) {
|
||||
throw scsi_error_exception(sense_key::ILLEGAL_REQUEST, asc::INVALID_FIELD_IN_CDB);
|
||||
throw scsi_exception(sense_key::ILLEGAL_REQUEST, asc::INVALID_FIELD_IN_CDB);
|
||||
}
|
||||
|
||||
// Do not return more than ALLOCATION LENGTH bytes
|
||||
@ -423,7 +421,7 @@ int Disk::ModeSense6(const vector<int>& cdb, vector<BYTE>& buf) const
|
||||
int Disk::ModeSense10(const vector<int>& cdb, vector<BYTE>& buf) const
|
||||
{
|
||||
// Get length, clear buffer
|
||||
auto length = (int)min(buf.size(), (size_t)GetInt16(cdb, 7));
|
||||
const auto length = (int)min(buf.size(), (size_t)GetInt16(cdb, 7));
|
||||
fill_n(buf.begin(), length, 0);
|
||||
|
||||
// DEVICE SPECIFIC PARAMETER
|
||||
@ -467,7 +465,7 @@ int Disk::ModeSense10(const vector<int>& cdb, vector<BYTE>& buf) const
|
||||
|
||||
size += super::AddModePages(cdb, buf, size, length - size);
|
||||
if (size > 65535) {
|
||||
throw scsi_error_exception(sense_key::ILLEGAL_REQUEST, asc::INVALID_FIELD_IN_CDB);
|
||||
throw scsi_exception(sense_key::ILLEGAL_REQUEST, asc::INVALID_FIELD_IN_CDB);
|
||||
}
|
||||
|
||||
// Do not return more than ALLOCATION LENGTH bytes
|
||||
@ -623,12 +621,12 @@ int Disk::Read(const vector<int>&, vector<BYTE>& buf, uint64_t block)
|
||||
|
||||
// Error if the total number of blocks is exceeded
|
||||
if (block >= blocks) {
|
||||
throw scsi_error_exception(sense_key::ILLEGAL_REQUEST, asc::INVALID_FIELD_IN_CDB);
|
||||
throw scsi_exception(sense_key::ILLEGAL_REQUEST, asc::INVALID_FIELD_IN_CDB);
|
||||
}
|
||||
|
||||
// leave it to the cache
|
||||
if (!cache->ReadSector(buf, (uint32_t)block)) {
|
||||
throw scsi_error_exception(sense_key::MEDIUM_ERROR, asc::READ_FAULT);
|
||||
throw scsi_exception(sense_key::MEDIUM_ERROR, asc::READ_FAULT);
|
||||
}
|
||||
|
||||
// Success
|
||||
@ -641,12 +639,12 @@ int Disk::WriteCheck(uint64_t block)
|
||||
|
||||
// Error if the total number of blocks is exceeded
|
||||
if (block >= blocks) {
|
||||
throw scsi_error_exception(sense_key::ILLEGAL_REQUEST, asc::INVALID_FIELD_IN_CDB);
|
||||
throw scsi_exception(sense_key::ILLEGAL_REQUEST, asc::INVALID_FIELD_IN_CDB);
|
||||
}
|
||||
|
||||
// Error if write protected
|
||||
if (IsProtected()) {
|
||||
throw scsi_error_exception(sense_key::DATA_PROTECT, asc::WRITE_PROTECTED);
|
||||
throw scsi_exception(sense_key::DATA_PROTECT, asc::WRITE_PROTECTED);
|
||||
}
|
||||
|
||||
// Success
|
||||
@ -660,22 +658,22 @@ void Disk::Write(const vector<int>&, const vector<BYTE>& buf, uint64_t block)
|
||||
|
||||
// Error if not ready
|
||||
if (!IsReady()) {
|
||||
throw scsi_error_exception(sense_key::NOT_READY);
|
||||
throw scsi_exception(sense_key::NOT_READY);
|
||||
}
|
||||
|
||||
// Error if the total number of blocks is exceeded
|
||||
if (block >= blocks) {
|
||||
throw scsi_error_exception(sense_key::ILLEGAL_REQUEST, asc::LBA_OUT_OF_RANGE);
|
||||
throw scsi_exception(sense_key::ILLEGAL_REQUEST, asc::LBA_OUT_OF_RANGE);
|
||||
}
|
||||
|
||||
// Error if write protected
|
||||
if (IsProtected()) {
|
||||
throw scsi_error_exception(sense_key::DATA_PROTECT, asc::WRITE_PROTECTED);
|
||||
throw scsi_exception(sense_key::DATA_PROTECT, asc::WRITE_PROTECTED);
|
||||
}
|
||||
|
||||
// Leave it to the cache
|
||||
if (!cache->WriteSector(buf, (uint32_t)block)) {
|
||||
throw scsi_error_exception(sense_key::MEDIUM_ERROR, asc::WRITE_FAULT);
|
||||
throw scsi_exception(sense_key::MEDIUM_ERROR, asc::WRITE_FAULT);
|
||||
}
|
||||
}
|
||||
|
||||
@ -709,7 +707,7 @@ void Disk::ReadCapacity10()
|
||||
CheckReady();
|
||||
|
||||
if (blocks == 0) {
|
||||
throw scsi_error_exception(sense_key::ILLEGAL_REQUEST, asc::MEDIUM_NOT_PRESENT);
|
||||
throw scsi_exception(sense_key::ILLEGAL_REQUEST, asc::MEDIUM_NOT_PRESENT);
|
||||
}
|
||||
|
||||
vector<BYTE>& buf = controller->GetBuffer();
|
||||
@ -737,7 +735,7 @@ void Disk::ReadCapacity16()
|
||||
CheckReady();
|
||||
|
||||
if (blocks == 0) {
|
||||
throw scsi_error_exception(sense_key::ILLEGAL_REQUEST, asc::MEDIUM_NOT_PRESENT);
|
||||
throw scsi_exception(sense_key::ILLEGAL_REQUEST, asc::MEDIUM_NOT_PRESENT);
|
||||
}
|
||||
|
||||
vector<BYTE>& buf = controller->GetBuffer();
|
||||
@ -772,7 +770,7 @@ void Disk::ReadCapacity16_ReadLong16()
|
||||
break;
|
||||
|
||||
default:
|
||||
throw scsi_error_exception(sense_key::ILLEGAL_REQUEST, asc::INVALID_FIELD_IN_CDB);
|
||||
throw scsi_exception(sense_key::ILLEGAL_REQUEST, asc::INVALID_FIELD_IN_CDB);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -805,14 +803,12 @@ void Disk::Release()
|
||||
|
||||
void Disk::ValidateBlockAddress(access_mode mode) const
|
||||
{
|
||||
uint64_t block = mode == RW16 ? GetInt64(ctrl->cmd, 2) : GetInt32(ctrl->cmd, 2);
|
||||
const uint64_t block = mode == RW16 ? GetInt64(ctrl->cmd, 2) : GetInt32(ctrl->cmd, 2);
|
||||
|
||||
uint64_t capacity = blocks;
|
||||
|
||||
if (block > capacity) {
|
||||
LOGTRACE("%s", ("Capacity of " + to_string(capacity) + " block(s) exceeded: Trying to access block "
|
||||
if (block > blocks) {
|
||||
LOGTRACE("%s", ("Capacity of " + to_string(blocks) + " block(s) exceeded: Trying to access block "
|
||||
+ to_string(block)).c_str())
|
||||
throw scsi_error_exception(sense_key::ILLEGAL_REQUEST, asc::LBA_OUT_OF_RANGE);
|
||||
throw scsi_exception(sense_key::ILLEGAL_REQUEST, asc::LBA_OUT_OF_RANGE);
|
||||
}
|
||||
}
|
||||
|
||||
@ -846,7 +842,7 @@ bool Disk::CheckAndGetStartAndCount(uint64_t& start, uint32_t& count, access_mod
|
||||
if (uint64_t capacity = blocks; start > capacity || start + count > capacity) {
|
||||
LOGTRACE("%s", ("Capacity of " + to_string(capacity) + " block(s) exceeded: Trying to access block "
|
||||
+ to_string(start) + ", block count " + to_string(count)).c_str())
|
||||
throw scsi_error_exception(sense_key::ILLEGAL_REQUEST, asc::LBA_OUT_OF_RANGE);
|
||||
throw scsi_exception(sense_key::ILLEGAL_REQUEST, asc::LBA_OUT_OF_RANGE);
|
||||
}
|
||||
|
||||
// Do not process 0 blocks
|
||||
@ -909,3 +905,43 @@ bool Disk::SetConfiguredSectorSize(const DeviceFactory& device_factory, uint32_t
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void Disk::ReserveFile(const Filepath& path, int id, int lun) const
|
||||
{
|
||||
reserved_files[path.GetPath()] = make_pair(id, lun);
|
||||
}
|
||||
|
||||
void Disk::UnreserveFile() const
|
||||
{
|
||||
reserved_files.erase(diskpath.GetPath());
|
||||
}
|
||||
|
||||
bool Disk::GetIdsForReservedFile(const Filepath& path, int& id, int& lun)
|
||||
{
|
||||
if (const auto& it = reserved_files.find(path.GetPath()); it != reserved_files.end()) {
|
||||
id = it->second.first;
|
||||
lun = it->second.second;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void Disk::UnreserveAll()
|
||||
{
|
||||
reserved_files.clear();
|
||||
}
|
||||
|
||||
bool Disk::FileExists(const Filepath& filepath)
|
||||
{
|
||||
try {
|
||||
// Disk::Open closes the file in case it exists
|
||||
Open(filepath);
|
||||
}
|
||||
catch(const file_not_found_exception&) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
@ -25,7 +25,11 @@
|
||||
#include <string>
|
||||
#include <unordered_set>
|
||||
|
||||
class Disk : public ModePageDevice, public ScsiBlockCommands
|
||||
using namespace std;
|
||||
|
||||
using id_set = pair<int, int>;
|
||||
|
||||
class Disk : public ModePageDevice, private ScsiBlockCommands
|
||||
{
|
||||
enum access_mode { RW6, RW10, RW16, SEEK6, SEEK10 };
|
||||
|
||||
@ -45,6 +49,11 @@ class Disk : public ModePageDevice, public ScsiBlockCommands
|
||||
|
||||
bool is_medium_changed = false;
|
||||
|
||||
Filepath diskpath;
|
||||
|
||||
// The list of image files in use and the IDs and LUNs using these files
|
||||
static unordered_map<string, id_set> reserved_files;
|
||||
|
||||
public:
|
||||
|
||||
Disk(const string&, int);
|
||||
@ -67,6 +76,18 @@ public:
|
||||
uint64_t GetBlockCount() const { return blocks; }
|
||||
void FlushCache() override;
|
||||
|
||||
virtual void Open(const Filepath&);
|
||||
void GetPath(Filepath& path) const { path = diskpath; }
|
||||
|
||||
void ReserveFile(const Filepath&, int, int) const;
|
||||
void UnreserveFile() const;
|
||||
static void UnreserveAll();
|
||||
bool FileExists(const Filepath&);
|
||||
|
||||
static unordered_map<string, id_set> GetReservedFiles() { return reserved_files; }
|
||||
static void SetReservedFiles(const unordered_map<string, id_set>& files_in_use) { reserved_files = files_in_use; }
|
||||
static bool GetIdsForReservedFile(const Filepath&, int&, int&);
|
||||
|
||||
private:
|
||||
|
||||
using super = ModePageDevice;
|
||||
@ -110,7 +131,6 @@ private:
|
||||
|
||||
protected:
|
||||
|
||||
virtual void Open(const Filepath&);
|
||||
void SetUpCache(const Filepath&, off_t, bool = false);
|
||||
void ResizeCache(const Filepath&, bool);
|
||||
|
||||
@ -127,4 +147,5 @@ protected:
|
||||
void SetSectorSizeShiftCount(uint32_t count) { size_shift_count = count; }
|
||||
uint32_t GetConfiguredSectorSize() const;
|
||||
void SetBlockCount(uint64_t b) { blocks = b; }
|
||||
void SetPath(const Filepath& path) { diskpath = path; }
|
||||
};
|
||||
|
@ -16,6 +16,8 @@
|
||||
|
||||
#include "disk_track.h"
|
||||
#include "disk_cache.h"
|
||||
#include <cstdlib>
|
||||
#include <cassert>
|
||||
|
||||
DiskCache::DiskCache(const Filepath& path, int size, uint32_t blocks, off_t imgoff)
|
||||
: sec_size(size), sec_blocks(blocks), imgoffset(imgoff)
|
||||
|
@ -68,7 +68,7 @@ bool DiskTrack::Load(const Filepath& path)
|
||||
offset += dt.imgoffset;
|
||||
|
||||
// Calculate length (data size of this track)
|
||||
int length = dt.sectors << dt.size;
|
||||
const int length = dt.sectors << dt.size;
|
||||
|
||||
// Allocate buffer memory
|
||||
assert((dt.sectors > 0) && (dt.sectors <= 0x100));
|
||||
@ -85,7 +85,7 @@ bool DiskTrack::Load(const Filepath& path)
|
||||
}
|
||||
|
||||
// Reallocate if the buffer length is different
|
||||
if (dt.length != (DWORD)length) {
|
||||
if (dt.length != (uint32_t)length) {
|
||||
free(dt.buffer);
|
||||
if (posix_memalign((void **)&dt.buffer, 512, ((length + 511) / 512) * 512)) {
|
||||
LOGWARN("%s posix_memalign failed", __PRETTY_FUNCTION__)
|
||||
@ -167,7 +167,7 @@ bool DiskTrack::Save(const Filepath& path)
|
||||
offset += dt.imgoffset;
|
||||
|
||||
// Calculate length per sector
|
||||
int length = 1 << dt.size;
|
||||
const int length = 1 << dt.size;
|
||||
|
||||
// Open file
|
||||
Fileio fio;
|
||||
@ -265,8 +265,8 @@ bool DiskTrack::WriteSector(const vector<BYTE>& buf, int sec)
|
||||
}
|
||||
|
||||
// Calculate offset and length
|
||||
int offset = sec << dt.size;
|
||||
int length = 1 << dt.size;
|
||||
const int offset = sec << dt.size;
|
||||
const int length = 1 << dt.size;
|
||||
|
||||
// Compare
|
||||
assert(dt.buffer);
|
||||
|
@ -16,6 +16,7 @@
|
||||
#pragma once
|
||||
|
||||
#include "filepath.h"
|
||||
#include <cstdlib>
|
||||
#include <vector>
|
||||
|
||||
using namespace std;
|
||||
@ -26,7 +27,7 @@ class DiskTrack
|
||||
int track; // Track Number
|
||||
int size; // Sector Size (8=256, 9=512, 10=1024, 11=2048, 12=4096)
|
||||
int sectors; // Number of sectors(<0x100)
|
||||
DWORD length; // Data buffer length
|
||||
uint32_t length; // Data buffer length
|
||||
BYTE *buffer; // Data buffer
|
||||
bool init; // Is it initilized?
|
||||
bool changed; // Changed flag
|
||||
|
@ -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;
|
||||
}
|
@ -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;
|
||||
};
|
@ -57,8 +57,8 @@ vector<byte> HostServices::InquiryInternal() const
|
||||
|
||||
void HostServices::StartStopUnit()
|
||||
{
|
||||
bool start = ctrl->cmd[4] & 0x01;
|
||||
bool load = ctrl->cmd[4] & 0x02;
|
||||
const bool start = ctrl->cmd[4] & 0x01;
|
||||
const bool load = ctrl->cmd[4] & 0x02;
|
||||
|
||||
if (!start) {
|
||||
// Flush any caches
|
||||
@ -77,7 +77,7 @@ void HostServices::StartStopUnit()
|
||||
controller->ScheduleShutdown(AbstractController::rascsi_shutdown_mode::RESTART_PI);
|
||||
}
|
||||
else {
|
||||
throw scsi_error_exception(sense_key::ILLEGAL_REQUEST, asc::INVALID_FIELD_IN_CDB);
|
||||
throw scsi_exception(sense_key::ILLEGAL_REQUEST, asc::INVALID_FIELD_IN_CDB);
|
||||
}
|
||||
|
||||
EnterStatusPhase();
|
||||
@ -87,10 +87,10 @@ int HostServices::ModeSense6(const vector<int>& cdb, vector<BYTE>& buf) const
|
||||
{
|
||||
// Block descriptors cannot be returned
|
||||
if (!(cdb[1] & 0x08)) {
|
||||
throw scsi_error_exception(sense_key::ILLEGAL_REQUEST, asc::INVALID_FIELD_IN_CDB);
|
||||
throw scsi_exception(sense_key::ILLEGAL_REQUEST, asc::INVALID_FIELD_IN_CDB);
|
||||
}
|
||||
|
||||
auto length = (int)min(buf.size(), (size_t)cdb[4]);
|
||||
const auto length = (int)min(buf.size(), (size_t)cdb[4]);
|
||||
fill_n(buf.begin(), length, 0);
|
||||
|
||||
// Basic Information
|
||||
@ -98,7 +98,7 @@ int HostServices::ModeSense6(const vector<int>& cdb, vector<BYTE>& buf) const
|
||||
|
||||
size += super::AddModePages(cdb, buf, size, length - size);
|
||||
if (size > 255) {
|
||||
throw scsi_error_exception(sense_key::ILLEGAL_REQUEST, asc::INVALID_FIELD_IN_CDB);
|
||||
throw scsi_exception(sense_key::ILLEGAL_REQUEST, asc::INVALID_FIELD_IN_CDB);
|
||||
}
|
||||
|
||||
// Do not return more than ALLOCATION LENGTH bytes
|
||||
@ -115,10 +115,10 @@ int HostServices::ModeSense10(const vector<int>& cdb, vector<BYTE>& buf) const
|
||||
{
|
||||
// Block descriptors cannot be returned
|
||||
if (!(cdb[1] & 0x08)) {
|
||||
throw scsi_error_exception(sense_key::ILLEGAL_REQUEST, asc::INVALID_FIELD_IN_CDB);
|
||||
throw scsi_exception(sense_key::ILLEGAL_REQUEST, asc::INVALID_FIELD_IN_CDB);
|
||||
}
|
||||
|
||||
auto length = (int)min(buf.size(), (size_t)GetInt16(cdb, 7));
|
||||
const auto length = (int)min(buf.size(), (size_t)GetInt16(cdb, 7));
|
||||
fill_n(buf.begin(), length, 0);
|
||||
|
||||
// Basic Information
|
||||
@ -126,7 +126,7 @@ int HostServices::ModeSense10(const vector<int>& cdb, vector<BYTE>& buf) const
|
||||
|
||||
size += super::AddModePages(cdb, buf, size, length - size);
|
||||
if (size > 65535) {
|
||||
throw scsi_error_exception(sense_key::ILLEGAL_REQUEST, asc::INVALID_FIELD_IN_CDB);
|
||||
throw scsi_exception(sense_key::ILLEGAL_REQUEST, asc::INVALID_FIELD_IN_CDB);
|
||||
}
|
||||
|
||||
// Do not return more than ALLOCATION LENGTH bytes
|
||||
|
@ -29,7 +29,6 @@ public:
|
||||
|
||||
vector<byte> InquiryInternal() const override;
|
||||
void TestUnitReady() override;
|
||||
void StartStopUnit();
|
||||
|
||||
bool SupportsFile() const override { return false; }
|
||||
|
||||
@ -58,6 +57,7 @@ private:
|
||||
|
||||
const ControllerManager& controller_manager;
|
||||
|
||||
void StartStopUnit();
|
||||
int ModeSense6(const vector<int>&, vector<BYTE>&) const override;
|
||||
int ModeSense10(const vector<int>&, vector<BYTE>&) const override;
|
||||
|
||||
|
@ -40,10 +40,10 @@ int ModePageDevice::AddModePages(const vector<int>& cdb, vector<BYTE>& buf, int
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool changeable = (cdb[2] & 0xc0) == 0x40;
|
||||
const bool changeable = (cdb[2] & 0xc0) == 0x40;
|
||||
|
||||
// Get page code (0x3f means all pages)
|
||||
int page = cdb[2] & 0x3f;
|
||||
const int page = cdb[2] & 0x3f;
|
||||
|
||||
LOGTRACE("%s Requesting mode page $%02X", __PRETTY_FUNCTION__, page)
|
||||
|
||||
@ -53,7 +53,7 @@ int ModePageDevice::AddModePages(const vector<int>& cdb, vector<BYTE>& buf, int
|
||||
|
||||
if (pages.empty()) {
|
||||
LOGTRACE("%s Unsupported mode page $%02X", __PRETTY_FUNCTION__, page)
|
||||
throw scsi_error_exception(sense_key::ILLEGAL_REQUEST, asc::INVALID_FIELD_IN_CDB);
|
||||
throw scsi_exception(sense_key::ILLEGAL_REQUEST, asc::INVALID_FIELD_IN_CDB);
|
||||
}
|
||||
|
||||
// Holds all mode page data
|
||||
@ -63,7 +63,7 @@ int ModePageDevice::AddModePages(const vector<int>& cdb, vector<BYTE>& buf, int
|
||||
for (auto const& [index, data] : pages) {
|
||||
// The specification mandates that page 0 must be returned after all others
|
||||
if (index) {
|
||||
size_t off = result.size();
|
||||
const size_t off = result.size();
|
||||
|
||||
// Page data
|
||||
result.insert(result.end(), data.begin(), data.end());
|
||||
@ -110,7 +110,7 @@ void ModePageDevice::ModeSense10()
|
||||
|
||||
void ModePageDevice::ModeSelect(const vector<int>&, const vector<BYTE>&, int) const
|
||||
{
|
||||
throw scsi_error_exception(sense_key::ILLEGAL_REQUEST, asc::INVALID_COMMAND_OPERATION_CODE);
|
||||
throw scsi_exception(sense_key::ILLEGAL_REQUEST, asc::INVALID_COMMAND_OPERATION_CODE);
|
||||
}
|
||||
|
||||
void ModePageDevice::ModeSelect6()
|
||||
@ -132,7 +132,7 @@ int ModePageDevice::ModeSelectCheck(int length) const
|
||||
// Error if save parameters are set for other types than SCHD, SCRM or SCMO
|
||||
// TODO The assumption above is not correct, and this code should be located elsewhere
|
||||
if (GetType() != "SCHD" && GetType() != "SCRM" && GetType() != "SCMO" && (ctrl->cmd[1] & 0x01)) {
|
||||
throw scsi_error_exception(sense_key::ILLEGAL_REQUEST, asc::INVALID_FIELD_IN_CDB);
|
||||
throw scsi_exception(sense_key::ILLEGAL_REQUEST, asc::INVALID_FIELD_IN_CDB);
|
||||
}
|
||||
|
||||
return length;
|
||||
|
@ -59,12 +59,12 @@ void PrimaryDevice::Inquiry()
|
||||
{
|
||||
// EVPD and page code check
|
||||
if ((ctrl->cmd[1] & 0x01) || ctrl->cmd[2]) {
|
||||
throw scsi_error_exception(sense_key::ILLEGAL_REQUEST, asc::INVALID_FIELD_IN_CDB);
|
||||
throw scsi_exception(sense_key::ILLEGAL_REQUEST, asc::INVALID_FIELD_IN_CDB);
|
||||
}
|
||||
|
||||
vector<byte> buf = InquiryInternal();
|
||||
|
||||
size_t allocation_length = min(buf.size(), (size_t)GetInt16(ctrl->cmd, 3));
|
||||
const size_t allocation_length = min(buf.size(), (size_t)GetInt16(ctrl->cmd, 3));
|
||||
|
||||
memcpy(controller->GetBuffer().data(), buf.data(), allocation_length);
|
||||
ctrl->length = (uint32_t)allocation_length;
|
||||
@ -84,10 +84,10 @@ void PrimaryDevice::ReportLuns()
|
||||
{
|
||||
// Only SELECT REPORT mode 0 is supported
|
||||
if (ctrl->cmd[2]) {
|
||||
throw scsi_error_exception(sense_key::ILLEGAL_REQUEST, asc::INVALID_FIELD_IN_CDB);
|
||||
throw scsi_exception(sense_key::ILLEGAL_REQUEST, asc::INVALID_FIELD_IN_CDB);
|
||||
}
|
||||
|
||||
uint32_t allocation_length = GetInt32(ctrl->cmd, 6);
|
||||
const uint32_t allocation_length = GetInt32(ctrl->cmd, 6);
|
||||
|
||||
vector<BYTE>& buf = controller->GetBuffer();
|
||||
fill_n(buf.begin(), min(buf.size(), (size_t)allocation_length), 0);
|
||||
@ -129,7 +129,7 @@ void PrimaryDevice::RequestSense()
|
||||
|
||||
vector<byte> buf = controller->GetDeviceForLun(lun)->HandleRequestSense();
|
||||
|
||||
size_t allocation_length = min(buf.size(), (size_t)ctrl->cmd[4]);
|
||||
const size_t allocation_length = min(buf.size(), (size_t)ctrl->cmd[4]);
|
||||
|
||||
memcpy(controller->GetBuffer().data(), buf.data(), allocation_length);
|
||||
ctrl->length = (uint32_t)allocation_length;
|
||||
@ -143,20 +143,20 @@ void PrimaryDevice::CheckReady()
|
||||
if (IsReset()) {
|
||||
SetReset(false);
|
||||
LOGTRACE("%s Device in reset", __PRETTY_FUNCTION__)
|
||||
throw scsi_error_exception(sense_key::UNIT_ATTENTION, asc::POWER_ON_OR_RESET);
|
||||
throw scsi_exception(sense_key::UNIT_ATTENTION, asc::POWER_ON_OR_RESET);
|
||||
}
|
||||
|
||||
// Not ready if it needs attention
|
||||
if (IsAttn()) {
|
||||
SetAttn(false);
|
||||
LOGTRACE("%s Device in needs attention", __PRETTY_FUNCTION__)
|
||||
throw scsi_error_exception(sense_key::UNIT_ATTENTION, asc::NOT_READY_TO_READY_CHANGE);
|
||||
throw scsi_exception(sense_key::UNIT_ATTENTION, asc::NOT_READY_TO_READY_CHANGE);
|
||||
}
|
||||
|
||||
// Return status if not ready
|
||||
if (!IsReady()) {
|
||||
LOGTRACE("%s Device not ready", __PRETTY_FUNCTION__)
|
||||
throw scsi_error_exception(sense_key::NOT_READY, asc::MEDIUM_NOT_PRESENT);
|
||||
throw scsi_exception(sense_key::NOT_READY, asc::MEDIUM_NOT_PRESENT);
|
||||
}
|
||||
|
||||
// Initialization with no error
|
||||
@ -180,7 +180,7 @@ vector<byte> PrimaryDevice::HandleInquiry(device_type type, scsi_level level, bo
|
||||
buf[4] = (byte)0x1F;
|
||||
|
||||
// Padded vendor, product, revision
|
||||
memcpy(&buf[8], GetPaddedName().c_str(), 28);
|
||||
memcpy(&buf.data()[8], GetPaddedName().c_str(), 28);
|
||||
|
||||
return buf;
|
||||
}
|
||||
@ -189,7 +189,7 @@ vector<byte> PrimaryDevice::HandleRequestSense() const
|
||||
{
|
||||
// Return not ready only if there are no errors
|
||||
if (!GetStatusCode() && !IsReady()) {
|
||||
throw scsi_error_exception(sense_key::NOT_READY, asc::MEDIUM_NOT_PRESENT);
|
||||
throw scsi_exception(sense_key::NOT_READY, asc::MEDIUM_NOT_PRESENT);
|
||||
}
|
||||
|
||||
// Set 18 bytes including extended sense data
|
||||
|
@ -17,7 +17,7 @@
|
||||
#include "dispatcher.h"
|
||||
#include <string>
|
||||
|
||||
class PrimaryDevice: public ScsiPrimaryCommands, public Device
|
||||
class PrimaryDevice: private ScsiPrimaryCommands, public Device
|
||||
{
|
||||
public:
|
||||
|
||||
|
@ -20,7 +20,7 @@ void scsi_command_util::ModeSelect(const vector<int>& cdb, const vector<BYTE>& b
|
||||
// PF
|
||||
if (!(cdb[1] & 0x10)) {
|
||||
// Vendor-specific parameters (SCSI-1) are not supported
|
||||
throw scsi_error_exception(sense_key::ILLEGAL_REQUEST, asc::INVALID_FIELD_IN_PARAMETER_LIST);
|
||||
throw scsi_exception(sense_key::ILLEGAL_REQUEST, asc::INVALID_FIELD_IN_PARAMETER_LIST);
|
||||
}
|
||||
|
||||
bool has_valid_page_code = false;
|
||||
@ -33,7 +33,7 @@ void scsi_command_util::ModeSelect(const vector<int>& cdb, const vector<BYTE>& b
|
||||
buf[11] != (BYTE)sector_size) {
|
||||
// See below for details
|
||||
LOGWARN("In order to change the sector size use the -b option when launching rascsi")
|
||||
throw scsi_error_exception(sense_key::ILLEGAL_REQUEST, asc::INVALID_FIELD_IN_PARAMETER_LIST);
|
||||
throw scsi_exception(sense_key::ILLEGAL_REQUEST, asc::INVALID_FIELD_IN_PARAMETER_LIST);
|
||||
}
|
||||
|
||||
offset += 12;
|
||||
@ -52,7 +52,7 @@ void scsi_command_util::ModeSelect(const vector<int>& cdb, const vector<BYTE>& b
|
||||
// With rascsi it is not possible to permanently (by formatting) change the sector size,
|
||||
// because the size is an externally configurable setting only
|
||||
LOGWARN("In order to change the sector size use the -b option when launching rascsi")
|
||||
throw scsi_error_exception(sense_key::ILLEGAL_REQUEST, asc::INVALID_FIELD_IN_PARAMETER_LIST);
|
||||
throw scsi_exception(sense_key::ILLEGAL_REQUEST, asc::INVALID_FIELD_IN_PARAMETER_LIST);
|
||||
}
|
||||
|
||||
has_valid_page_code = true;
|
||||
@ -68,7 +68,7 @@ void scsi_command_util::ModeSelect(const vector<int>& cdb, const vector<BYTE>& b
|
||||
}
|
||||
|
||||
if (!has_valid_page_code) {
|
||||
throw scsi_error_exception(sense_key::ILLEGAL_REQUEST, asc::INVALID_FIELD_IN_PARAMETER_LIST);
|
||||
throw scsi_exception(sense_key::ILLEGAL_REQUEST, asc::INVALID_FIELD_IN_PARAMETER_LIST);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -21,9 +21,6 @@
|
||||
// following link:
|
||||
// - https://github.com/akuker/RASCSI/wiki/Dayna-Port-SCSI-Link
|
||||
//
|
||||
// This does NOT include the file system functionality that is present
|
||||
// in the Sharp X68000 host bridge.
|
||||
//
|
||||
// Note: This requires a DaynaPort SCSI Link driver.
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
@ -133,12 +130,11 @@ vector<byte> SCSIDaynaPort::InquiryInternal() const
|
||||
int SCSIDaynaPort::Read(const vector<int>& cdb, vector<BYTE>& buf, uint64_t)
|
||||
{
|
||||
int rx_packet_size = 0;
|
||||
auto response = (scsi_resp_read_t*)buf.data();
|
||||
const auto response = (scsi_resp_read_t*)buf.data();
|
||||
|
||||
int requested_length = cdb[4];
|
||||
const int requested_length = cdb[4];
|
||||
LOGTRACE("%s Read maximum length %d, (%04X)", __PRETTY_FUNCTION__, requested_length, requested_length)
|
||||
|
||||
|
||||
// At host startup, it will send a READ(6) command with a length of 1. We should
|
||||
// respond by going into the status mode with a code of 0x02
|
||||
if (requested_length == 1) {
|
||||
@ -207,8 +203,7 @@ int SCSIDaynaPort::Read(const vector<int>& cdb, vector<BYTE>& buf, uint64_t)
|
||||
|
||||
// If there are pending packets to be processed, we'll tell the host that the read
|
||||
// length was 0.
|
||||
if (!m_tap.PendingPackets())
|
||||
{
|
||||
if (!m_tap.PendingPackets()) {
|
||||
response->length = 0;
|
||||
response->flags = read_data_flags_t::e_no_more_data;
|
||||
return DAYNAPORT_READ_HEADER_SZ;
|
||||
@ -252,8 +247,8 @@ int SCSIDaynaPort::WriteCheck(uint64_t)
|
||||
{
|
||||
CheckReady();
|
||||
|
||||
if (!m_bTapEnable){
|
||||
throw scsi_error_exception(sense_key::UNIT_ATTENTION, asc::MEDIUM_NOT_PRESENT);
|
||||
if (!m_bTapEnable) {
|
||||
throw scsi_exception(sense_key::UNIT_ATTENTION, asc::MEDIUM_NOT_PRESENT);
|
||||
}
|
||||
|
||||
return 1;
|
||||
@ -279,22 +274,20 @@ int SCSIDaynaPort::WriteCheck(uint64_t)
|
||||
//---------------------------------------------------------------------------
|
||||
bool SCSIDaynaPort::WriteBytes(const vector<int>& cdb, const vector<BYTE>& buf, uint64_t)
|
||||
{
|
||||
int data_format = cdb[5];
|
||||
const int data_format = cdb[5];
|
||||
int data_length = GetInt16(cdb, 3);
|
||||
|
||||
if (data_format == 0x00){
|
||||
if (data_format == 0x00) {
|
||||
m_tap.Send(buf.data(), data_length);
|
||||
LOGTRACE("%s Transmitted %u bytes (00 format)", __PRETTY_FUNCTION__, data_length)
|
||||
}
|
||||
else if (data_format == 0x80){
|
||||
else if (data_format == 0x80) {
|
||||
// The data length is specified in the first 2 bytes of the payload
|
||||
data_length=buf[1] + (buf[0] << 8);
|
||||
data_length = buf[1] + (((int)buf[0] & 0xff) << 8);
|
||||
m_tap.Send(&(buf.data()[4]), data_length);
|
||||
LOGTRACE("%s Transmitted %u bytes (80 format)", __PRETTY_FUNCTION__, data_length)
|
||||
}
|
||||
else
|
||||
{
|
||||
// LOGWARN("%s Unknown data format %02X", __PRETTY_FUNCTION__, (unsigned int)command->format)
|
||||
else {
|
||||
LOGWARN("%s Unknown data format %02X", __PRETTY_FUNCTION__, data_format)
|
||||
}
|
||||
|
||||
@ -321,45 +314,7 @@ int SCSIDaynaPort::RetrieveStats(const vector<int>& cdb, vector<BYTE>& buf) cons
|
||||
{
|
||||
memcpy(buf.data(), &m_scsi_link_stats, sizeof(m_scsi_link_stats));
|
||||
|
||||
return (int)min(sizeof(m_scsi_link_stats), (size_t)GetInt16(cdb, 4));
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
//
|
||||
// Enable or Disable the interface
|
||||
//
|
||||
// Command: 0e 00 00 00 00 XX (XX = 80 or 00)
|
||||
// Function: Enable (80) / disable (00) Ethernet interface
|
||||
// Type: No data transferred
|
||||
// Notes: After issuing an Enable, the initiator should avoid sending
|
||||
// any subsequent commands to the device for approximately 0.5
|
||||
// seconds
|
||||
//
|
||||
//---------------------------------------------------------------------------
|
||||
bool SCSIDaynaPort::EnableInterface(const vector<int>& cdb)
|
||||
{
|
||||
bool result;
|
||||
if (cdb[5] & 0x80) {
|
||||
result = m_tap.Enable();
|
||||
if (result) {
|
||||
LOGINFO("The DaynaPort interface has been ENABLED.")
|
||||
}
|
||||
else{
|
||||
LOGWARN("Unable to enable the DaynaPort Interface")
|
||||
}
|
||||
m_tap.Flush();
|
||||
}
|
||||
else {
|
||||
result = m_tap.Disable();
|
||||
if (result) {
|
||||
LOGINFO("The DaynaPort interface has been DISABLED.")
|
||||
}
|
||||
else{
|
||||
LOGWARN("Unable to disable the DaynaPort Interface")
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
return (int)min(sizeof(m_scsi_link_stats), (size_t)GetInt16(cdb, 3));
|
||||
}
|
||||
|
||||
void SCSIDaynaPort::TestUnitReady()
|
||||
@ -371,14 +326,14 @@ void SCSIDaynaPort::TestUnitReady()
|
||||
void SCSIDaynaPort::Read6()
|
||||
{
|
||||
// Get record number and block number
|
||||
uint32_t record = GetInt24(ctrl->cmd, 1) & 0x1fffff;
|
||||
const uint32_t record = GetInt24(ctrl->cmd, 1) & 0x1fffff;
|
||||
ctrl->blocks=1;
|
||||
|
||||
// If any commands have a bogus control value, they were probably not
|
||||
// generated by the DaynaPort driver so ignore them
|
||||
if (ctrl->cmd[5] != 0xc0 && ctrl->cmd[5] != 0x80) {
|
||||
LOGTRACE("%s Control value %d, (%04X), returning invalid CDB", __PRETTY_FUNCTION__, ctrl->cmd[5], ctrl->cmd[5])
|
||||
throw scsi_error_exception(sense_key::ILLEGAL_REQUEST, asc::INVALID_FIELD_IN_CDB);
|
||||
throw scsi_exception(sense_key::ILLEGAL_REQUEST, asc::INVALID_FIELD_IN_CDB);
|
||||
}
|
||||
|
||||
LOGTRACE("%s READ(6) command record=%d blocks=%d", __PRETTY_FUNCTION__, record, ctrl->blocks)
|
||||
@ -397,7 +352,7 @@ void SCSIDaynaPort::Write6()
|
||||
// Ensure a sufficient buffer size (because it is not transfer for each block)
|
||||
controller->AllocateBuffer(DAYNAPORT_BUFFER_SIZE);
|
||||
|
||||
int data_format = ctrl->cmd[5];
|
||||
const int data_format = ctrl->cmd[5];
|
||||
|
||||
if (data_format == 0x00) {
|
||||
ctrl->length = GetInt16(ctrl->cmd, 3);
|
||||
@ -411,7 +366,7 @@ void SCSIDaynaPort::Write6()
|
||||
LOGTRACE("%s length: $%04X (%d) format: $%02X", __PRETTY_FUNCTION__, ctrl->length, ctrl->length, data_format)
|
||||
|
||||
if (ctrl->length <= 0) {
|
||||
throw scsi_error_exception();
|
||||
throw scsi_exception();
|
||||
}
|
||||
|
||||
// Set next block
|
||||
@ -478,10 +433,12 @@ void SCSIDaynaPort::SetInterfaceMode()
|
||||
case CMD_SCSILINK_ENABLE:
|
||||
case CMD_SCSILINK_SET:
|
||||
LOGWARN("%s Unsupported SetInterface command received: %02X", __PRETTY_FUNCTION__, ctrl->cmd[5])
|
||||
throw scsi_exception();
|
||||
break;
|
||||
|
||||
default:
|
||||
LOGWARN("%s Unknown SetInterface command received: %02X", __PRETTY_FUNCTION__, ctrl->cmd[5])
|
||||
throw scsi_exception();
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -492,16 +449,45 @@ void SCSIDaynaPort::SetMcastAddr()
|
||||
if (ctrl->length == 0) {
|
||||
LOGWARN("%s Not supported SetMcastAddr Command %02X", __PRETTY_FUNCTION__, ctrl->cmd[2])
|
||||
|
||||
throw scsi_error_exception();
|
||||
throw scsi_exception();
|
||||
}
|
||||
|
||||
EnterDataOutPhase();
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
//
|
||||
// Enable or Disable the interface
|
||||
//
|
||||
// Command: 0e 00 00 00 00 XX (XX = 80 or 00)
|
||||
// Function: Enable (80) / disable (00) Ethernet interface
|
||||
// Type: No data transferred
|
||||
// Notes: After issuing an Enable, the initiator should avoid sending
|
||||
// any subsequent commands to the device for approximately 0.5
|
||||
// seconds
|
||||
//
|
||||
//---------------------------------------------------------------------------
|
||||
void SCSIDaynaPort::EnableInterface()
|
||||
{
|
||||
if (!EnableInterface(ctrl->cmd)) {
|
||||
throw scsi_error_exception();
|
||||
if (ctrl->cmd[5] & 0x80) {
|
||||
if (!m_tap.Enable()) {
|
||||
LOGWARN("Unable to enable the DaynaPort Interface")
|
||||
|
||||
throw scsi_exception();
|
||||
}
|
||||
|
||||
m_tap.Flush();
|
||||
|
||||
LOGINFO("The DaynaPort interface has been ENABLED")
|
||||
}
|
||||
else {
|
||||
if (!m_tap.Disable()) {
|
||||
LOGWARN("Unable to disable the DaynaPort Interface")
|
||||
|
||||
throw scsi_exception();
|
||||
}
|
||||
|
||||
LOGINFO("The DaynaPort interface has been DISABLED")
|
||||
}
|
||||
|
||||
EnterStatusPhase();
|
||||
|
@ -41,7 +41,7 @@
|
||||
// DaynaPort SCSI Link
|
||||
//
|
||||
//===========================================================================
|
||||
class SCSIDaynaPort final : public Disk
|
||||
class SCSIDaynaPort : public Disk
|
||||
{
|
||||
public:
|
||||
|
||||
@ -58,7 +58,6 @@ public:
|
||||
int WriteCheck(uint64_t block) override;
|
||||
|
||||
int RetrieveStats(const vector<int>&, vector<BYTE>&) const;
|
||||
bool EnableInterface(const vector<int>&);
|
||||
|
||||
void TestUnitReady() override;
|
||||
void Read6() override;
|
||||
@ -88,9 +87,10 @@ public:
|
||||
// The READ response has a header which consists of:
|
||||
// 2 bytes - payload size
|
||||
// 4 bytes - status flags
|
||||
static const DWORD DAYNAPORT_READ_HEADER_SZ = 2 + 4;
|
||||
static const uint32_t DAYNAPORT_READ_HEADER_SZ = 2 + 4;
|
||||
|
||||
private:
|
||||
|
||||
using super = Disk;
|
||||
|
||||
Dispatcher<SCSIDaynaPort> dispatcher;
|
||||
|
@ -107,13 +107,13 @@ void SCSIBR::TestUnitReady()
|
||||
int SCSIBR::GetMessage10(const vector<int>& cdb, vector<BYTE>& buf)
|
||||
{
|
||||
// Type
|
||||
int type = cdb[2];
|
||||
const int type = cdb[2];
|
||||
|
||||
// Function number
|
||||
int func = cdb[3];
|
||||
const int func = cdb[3];
|
||||
|
||||
// Phase
|
||||
int phase = cdb[9];
|
||||
const int phase = cdb[9];
|
||||
|
||||
switch (type) {
|
||||
case 1: // Ethernet
|
||||
@ -195,16 +195,16 @@ int SCSIBR::GetMessage10(const vector<int>& cdb, vector<BYTE>& buf)
|
||||
bool SCSIBR::WriteBytes(const vector<int>& cdb, vector<BYTE>& buf, uint64_t)
|
||||
{
|
||||
// Type
|
||||
int type = cdb[2];
|
||||
const int type = cdb[2];
|
||||
|
||||
// Function number
|
||||
int func = cdb[3];
|
||||
const int func = cdb[3];
|
||||
|
||||
// Phase
|
||||
int phase = cdb[9];
|
||||
const int phase = cdb[9];
|
||||
|
||||
// Get the number of lights
|
||||
int len = GetInt24(cdb, 6);
|
||||
const int len = GetInt24(cdb, 6);
|
||||
|
||||
switch (type) {
|
||||
case 1: // Ethernet
|
||||
@ -257,7 +257,7 @@ void SCSIBR::GetMessage10()
|
||||
|
||||
ctrl->length = GetMessage10(ctrl->cmd, controller->GetBuffer());
|
||||
if (ctrl->length <= 0) {
|
||||
throw scsi_error_exception();
|
||||
throw scsi_exception();
|
||||
}
|
||||
|
||||
// Set next block
|
||||
@ -278,7 +278,7 @@ void SCSIBR::SendMessage10()
|
||||
{
|
||||
ctrl->length = GetInt24(ctrl->cmd, 6);
|
||||
if (ctrl->length <= 0) {
|
||||
throw scsi_error_exception();
|
||||
throw scsi_exception();
|
||||
}
|
||||
|
||||
// Ensure a sufficient buffer size (because it is not a transfer for each block)
|
||||
@ -368,8 +368,8 @@ void SCSIBR::FS_InitDevice(vector<BYTE>& buf)
|
||||
void SCSIBR::FS_CheckDir(vector<BYTE>& buf)
|
||||
{
|
||||
auto dp = (uint32_t*)buf.data();
|
||||
uint32_t nUnit = ntohl(*dp);
|
||||
int i = sizeof(uint32_t);
|
||||
const uint32_t nUnit = ntohl(*dp);
|
||||
const int i = sizeof(uint32_t);
|
||||
|
||||
const auto pNamests = (Human68k::namests_t*)&(buf.data()[i]);
|
||||
|
||||
@ -384,8 +384,8 @@ void SCSIBR::FS_CheckDir(vector<BYTE>& buf)
|
||||
void SCSIBR::FS_MakeDir(vector<BYTE>& buf)
|
||||
{
|
||||
auto dp = (uint32_t*)buf.data();
|
||||
uint32_t nUnit = ntohl(*dp);
|
||||
int i = sizeof(uint32_t);
|
||||
const uint32_t nUnit = ntohl(*dp);
|
||||
const int i = sizeof(uint32_t);
|
||||
|
||||
const auto pNamests = (Human68k::namests_t*)&(buf.data()[i]);
|
||||
|
||||
@ -400,8 +400,8 @@ void SCSIBR::FS_MakeDir(vector<BYTE>& buf)
|
||||
void SCSIBR::FS_RemoveDir(vector<BYTE>& buf)
|
||||
{
|
||||
auto dp = (uint32_t*)buf.data();
|
||||
uint32_t nUnit = ntohl(*dp);
|
||||
int i = sizeof(uint32_t);
|
||||
const uint32_t nUnit = ntohl(*dp);
|
||||
const int i = sizeof(uint32_t);
|
||||
|
||||
const auto pNamests = (Human68k::namests_t*)&(buf.data()[i]);
|
||||
|
||||
@ -416,7 +416,7 @@ void SCSIBR::FS_RemoveDir(vector<BYTE>& buf)
|
||||
void SCSIBR::FS_Rename(vector<BYTE>& buf)
|
||||
{
|
||||
auto dp = (uint32_t*)buf.data();
|
||||
uint32_t nUnit = ntohl(*dp);
|
||||
const uint32_t nUnit = ntohl(*dp);
|
||||
int i = sizeof(uint32_t);
|
||||
|
||||
const auto pNamests = (Human68k::namests_t*)&(buf.data()[i]);
|
||||
@ -435,8 +435,8 @@ void SCSIBR::FS_Rename(vector<BYTE>& buf)
|
||||
void SCSIBR::FS_Delete(vector<BYTE>& buf)
|
||||
{
|
||||
auto dp = (uint32_t*)buf.data();
|
||||
uint32_t nUnit = ntohl(*dp);
|
||||
int i = sizeof(uint32_t);
|
||||
const uint32_t nUnit = ntohl(*dp);
|
||||
const int i = sizeof(uint32_t);
|
||||
|
||||
const auto *pNamests = (Human68k::namests_t*)&(buf.data()[i]);
|
||||
|
||||
@ -451,7 +451,7 @@ void SCSIBR::FS_Delete(vector<BYTE>& buf)
|
||||
void SCSIBR::FS_Attribute(vector<BYTE>& buf)
|
||||
{
|
||||
auto dp = (uint32_t*)buf.data();
|
||||
uint32_t nUnit = ntohl(*dp);
|
||||
const uint32_t nUnit = ntohl(*dp);
|
||||
int i = sizeof(uint32_t);
|
||||
|
||||
const auto pNamests = (Human68k::namests_t*)&(buf.data()[i]);
|
||||
@ -471,11 +471,11 @@ void SCSIBR::FS_Attribute(vector<BYTE>& buf)
|
||||
void SCSIBR::FS_Files(vector<BYTE>& buf)
|
||||
{
|
||||
auto dp = (uint32_t*)buf.data();
|
||||
uint32_t nUnit = ntohl(*dp);
|
||||
const uint32_t nUnit = ntohl(*dp);
|
||||
int i = sizeof(uint32_t);
|
||||
|
||||
dp = (uint32_t*)&(buf.data()[i]);
|
||||
uint32_t nKey = ntohl(*dp);
|
||||
const uint32_t nKey = ntohl(*dp);
|
||||
i += sizeof(uint32_t);
|
||||
|
||||
const auto pNamests = (Human68k::namests_t*)&(buf.data()[i]);
|
||||
@ -512,11 +512,11 @@ void SCSIBR::FS_Files(vector<BYTE>& buf)
|
||||
void SCSIBR::FS_NFiles(vector<BYTE>& buf)
|
||||
{
|
||||
auto dp = (uint32_t*)buf.data();
|
||||
uint32_t nUnit = ntohl(*dp);
|
||||
const uint32_t nUnit = ntohl(*dp);
|
||||
int i = sizeof(uint32_t);
|
||||
|
||||
dp = (uint32_t*)&(buf.data()[i]);
|
||||
uint32_t nKey = ntohl(*dp);
|
||||
const uint32_t nKey = ntohl(*dp);
|
||||
i += sizeof(uint32_t);
|
||||
|
||||
auto files = (Human68k::files_t*)&(buf.data()[i]);
|
||||
@ -550,11 +550,11 @@ void SCSIBR::FS_NFiles(vector<BYTE>& buf)
|
||||
void SCSIBR::FS_Create(vector<BYTE>& buf)
|
||||
{
|
||||
auto dp = (uint32_t*)buf.data();
|
||||
uint32_t nUnit = ntohl(*dp);
|
||||
const uint32_t nUnit = ntohl(*dp);
|
||||
int i = sizeof(uint32_t);
|
||||
|
||||
dp = (uint32_t*)&(buf.data()[i]);
|
||||
uint32_t nKey = ntohl(*dp);
|
||||
const uint32_t nKey = ntohl(*dp);
|
||||
i += sizeof(uint32_t);
|
||||
|
||||
const auto pNamests = (Human68k::namests_t*)&(buf.data()[i]);
|
||||
@ -564,11 +564,11 @@ void SCSIBR::FS_Create(vector<BYTE>& buf)
|
||||
i += sizeof(Human68k::fcb_t);
|
||||
|
||||
dp = (uint32_t*)&(buf.data()[i]);
|
||||
uint32_t nAttribute = ntohl(*dp);
|
||||
const uint32_t nAttribute = ntohl(*dp);
|
||||
i += sizeof(uint32_t);
|
||||
|
||||
auto bp = (int*)&(buf.data()[i]);
|
||||
uint32_t bForce = ntohl(*bp);
|
||||
const uint32_t bForce = ntohl(*bp);
|
||||
|
||||
pFcb->fileptr = ntohl(pFcb->fileptr);
|
||||
pFcb->mode = ntohs(pFcb->mode);
|
||||
@ -599,11 +599,11 @@ void SCSIBR::FS_Create(vector<BYTE>& buf)
|
||||
void SCSIBR::FS_Open(vector<BYTE>& buf)
|
||||
{
|
||||
auto dp = (uint32_t*)buf.data();
|
||||
uint32_t nUnit = ntohl(*dp);
|
||||
const uint32_t nUnit = ntohl(*dp);
|
||||
int i = sizeof(uint32_t);
|
||||
|
||||
dp = (uint32_t*)&(buf.data()[i]);
|
||||
uint32_t nKey = ntohl(*dp);
|
||||
const uint32_t nKey = ntohl(*dp);
|
||||
i += sizeof(uint32_t);
|
||||
|
||||
const auto pNamests = (Human68k::namests_t*)&(buf.data()[i]);
|
||||
@ -640,11 +640,11 @@ void SCSIBR::FS_Open(vector<BYTE>& buf)
|
||||
void SCSIBR::FS_Close(vector<BYTE>& buf)
|
||||
{
|
||||
auto dp = (uint32_t*)buf.data();
|
||||
uint32_t nUnit = ntohl(*dp);
|
||||
const uint32_t nUnit = ntohl(*dp);
|
||||
int i = sizeof(uint32_t);
|
||||
|
||||
dp = (uint32_t*)&(buf.data()[i]);
|
||||
uint32_t nKey = ntohl(*dp);
|
||||
const uint32_t nKey = ntohl(*dp);
|
||||
i += sizeof(uint32_t);
|
||||
|
||||
auto pFcb = (Human68k::fcb_t*)&(buf.data()[i]);
|
||||
@ -678,14 +678,14 @@ void SCSIBR::FS_Close(vector<BYTE>& buf)
|
||||
void SCSIBR::FS_Read(vector<BYTE>& buf)
|
||||
{
|
||||
auto dp = (uint32_t*)buf.data();
|
||||
uint32_t nKey = ntohl(*dp);
|
||||
const uint32_t nKey = ntohl(*dp);
|
||||
int i = sizeof(uint32_t);
|
||||
|
||||
auto pFcb = (Human68k::fcb_t*)&(buf.data()[i]);
|
||||
i += sizeof(Human68k::fcb_t);
|
||||
|
||||
dp = (uint32_t*)&(buf.data()[i]);
|
||||
uint32_t nSize = ntohl(*dp);
|
||||
const uint32_t nSize = ntohl(*dp);
|
||||
|
||||
pFcb->fileptr = ntohl(pFcb->fileptr);
|
||||
pFcb->mode = ntohs(pFcb->mode);
|
||||
@ -718,14 +718,14 @@ void SCSIBR::FS_Read(vector<BYTE>& buf)
|
||||
void SCSIBR::FS_Write(vector<BYTE>& buf)
|
||||
{
|
||||
auto dp = (uint32_t*)buf.data();
|
||||
uint32_t nKey = ntohl(*dp);
|
||||
const uint32_t nKey = ntohl(*dp);
|
||||
int i = sizeof(uint32_t);
|
||||
|
||||
auto pFcb = (Human68k::fcb_t*)&(buf.data()[i]);
|
||||
i += sizeof(Human68k::fcb_t);
|
||||
|
||||
dp = (uint32_t*)&(buf.data()[i]);
|
||||
uint32_t nSize = ntohl(*dp);
|
||||
const uint32_t nSize = ntohl(*dp);
|
||||
|
||||
pFcb->fileptr = ntohl(pFcb->fileptr);
|
||||
pFcb->mode = ntohs(pFcb->mode);
|
||||
@ -756,14 +756,14 @@ void SCSIBR::FS_Write(vector<BYTE>& buf)
|
||||
void SCSIBR::FS_Seek(vector<BYTE>& buf)
|
||||
{
|
||||
auto dp = (uint32_t*)buf.data();
|
||||
uint32_t nKey = ntohl(*dp);
|
||||
const uint32_t nKey = ntohl(*dp);
|
||||
int i = sizeof(uint32_t);
|
||||
|
||||
auto pFcb = (Human68k::fcb_t*)&(buf.data()[i]);
|
||||
i += sizeof(Human68k::fcb_t);
|
||||
|
||||
dp = (uint32_t*)&(buf.data()[i]);
|
||||
uint32_t nMode = ntohl(*dp);
|
||||
const uint32_t nMode = ntohl(*dp);
|
||||
i += sizeof(uint32_t);
|
||||
|
||||
auto ip = (const int*)&(buf.data()[i]);
|
||||
@ -798,11 +798,11 @@ void SCSIBR::FS_Seek(vector<BYTE>& buf)
|
||||
void SCSIBR::FS_TimeStamp(vector<BYTE>& buf)
|
||||
{
|
||||
auto dp = (uint32_t*)buf.data();
|
||||
uint32_t nUnit = ntohl(*dp);
|
||||
const uint32_t nUnit = ntohl(*dp);
|
||||
int i = sizeof(uint32_t);
|
||||
|
||||
dp = (uint32_t*)&(buf.data()[i]);
|
||||
uint32_t nKey = ntohl(*dp);
|
||||
const uint32_t nKey = ntohl(*dp);
|
||||
i += sizeof(uint32_t);
|
||||
|
||||
auto pFcb = (Human68k::fcb_t*)&(buf.data()[i]);
|
||||
@ -840,7 +840,7 @@ void SCSIBR::FS_TimeStamp(vector<BYTE>& buf)
|
||||
void SCSIBR::FS_GetCapacity(vector<BYTE>& buf)
|
||||
{
|
||||
auto dp = (uint32_t*)buf.data();
|
||||
uint32_t nUnit = ntohl(*dp);
|
||||
const uint32_t nUnit = ntohl(*dp);
|
||||
|
||||
Human68k::capacity_t cap;
|
||||
fsresult = fs.GetCapacity(nUnit, &cap);
|
||||
@ -862,8 +862,8 @@ void SCSIBR::FS_GetCapacity(vector<BYTE>& buf)
|
||||
void SCSIBR::FS_CtrlDrive(vector<BYTE>& buf)
|
||||
{
|
||||
auto dp = (uint32_t*)buf.data();
|
||||
uint32_t nUnit = ntohl(*dp);
|
||||
int i = sizeof(uint32_t);
|
||||
const uint32_t nUnit = ntohl(*dp);
|
||||
const int i = sizeof(uint32_t);
|
||||
|
||||
auto pCtrlDrive = (Human68k::ctrldrive_t*)&(buf.data()[i]);
|
||||
|
||||
@ -881,7 +881,7 @@ void SCSIBR::FS_CtrlDrive(vector<BYTE>& buf)
|
||||
void SCSIBR::FS_GetDPB(vector<BYTE>& buf)
|
||||
{
|
||||
auto dp = (uint32_t*)buf.data();
|
||||
uint32_t nUnit = ntohl(*dp);
|
||||
const uint32_t nUnit = ntohl(*dp);
|
||||
|
||||
Human68k::dpb_t dpb;
|
||||
fsresult = fs.GetDPB(nUnit, &dpb);
|
||||
@ -905,11 +905,11 @@ void SCSIBR::FS_GetDPB(vector<BYTE>& buf)
|
||||
void SCSIBR::FS_DiskRead(vector<BYTE>& buf)
|
||||
{
|
||||
auto dp = (uint32_t*)buf.data();
|
||||
uint32_t nUnit = ntohl(*dp);
|
||||
const uint32_t nUnit = ntohl(*dp);
|
||||
int i = sizeof(uint32_t);
|
||||
|
||||
dp = (uint32_t*)&(buf.data()[i]);
|
||||
uint32_t nSector = ntohl(*dp);
|
||||
const uint32_t nSector = ntohl(*dp);
|
||||
i += sizeof(uint32_t);
|
||||
|
||||
dp = (uint32_t*)&(buf.data()[i]);
|
||||
@ -927,7 +927,7 @@ void SCSIBR::FS_DiskRead(vector<BYTE>& buf)
|
||||
void SCSIBR::FS_DiskWrite(vector<BYTE>& buf)
|
||||
{
|
||||
auto dp = (uint32_t*)buf.data();
|
||||
uint32_t nUnit = ntohl(*dp);
|
||||
const uint32_t nUnit = ntohl(*dp);
|
||||
|
||||
fsresult = fs.DiskWrite(nUnit);
|
||||
}
|
||||
@ -940,18 +940,18 @@ void SCSIBR::FS_DiskWrite(vector<BYTE>& buf)
|
||||
void SCSIBR::FS_Ioctrl(vector<BYTE>& buf)
|
||||
{
|
||||
auto dp = (uint32_t*)buf.data();
|
||||
uint32_t nUnit = ntohl(*dp);
|
||||
const uint32_t nUnit = ntohl(*dp);
|
||||
int i = sizeof(uint32_t);
|
||||
|
||||
dp = (uint32_t*)&(buf.data()[i]);
|
||||
uint32_t nFunction = ntohl(*dp);
|
||||
const uint32_t nFunction = ntohl(*dp);
|
||||
i += sizeof(uint32_t);
|
||||
|
||||
auto pIoctrl = (Human68k::ioctrl_t*)&(buf.data()[i]);
|
||||
|
||||
switch (nFunction) {
|
||||
case 2:
|
||||
case (DWORD)-2:
|
||||
case (uint32_t)-2:
|
||||
pIoctrl->param = htonl(pIoctrl->param);
|
||||
break;
|
||||
default:
|
||||
@ -965,7 +965,7 @@ void SCSIBR::FS_Ioctrl(vector<BYTE>& buf)
|
||||
pIoctrl->media = htons(pIoctrl->media);
|
||||
break;
|
||||
case 1:
|
||||
case (DWORD)-3:
|
||||
case (uint32_t)-3:
|
||||
pIoctrl->param = htonl(pIoctrl->param);
|
||||
break;
|
||||
default:
|
||||
@ -986,7 +986,7 @@ void SCSIBR::FS_Ioctrl(vector<BYTE>& buf)
|
||||
void SCSIBR::FS_Flush(vector<BYTE>& buf)
|
||||
{
|
||||
auto dp = (uint32_t*)buf.data();
|
||||
uint32_t nUnit = ntohl(*dp);
|
||||
const uint32_t nUnit = ntohl(*dp);
|
||||
|
||||
fsresult = fs.Flush(nUnit);
|
||||
}
|
||||
@ -999,7 +999,7 @@ void SCSIBR::FS_Flush(vector<BYTE>& buf)
|
||||
void SCSIBR::FS_CheckMedia(vector<BYTE>& buf)
|
||||
{
|
||||
auto dp = (uint32_t*)buf.data();
|
||||
uint32_t nUnit = ntohl(*dp);
|
||||
const uint32_t nUnit = ntohl(*dp);
|
||||
|
||||
fsresult = fs.CheckMedia(nUnit);
|
||||
}
|
||||
@ -1012,7 +1012,7 @@ void SCSIBR::FS_CheckMedia(vector<BYTE>& buf)
|
||||
void SCSIBR::FS_Lock(vector<BYTE>& buf)
|
||||
{
|
||||
auto dp = (uint32_t*)buf.data();
|
||||
uint32_t nUnit = ntohl(*dp);
|
||||
const uint32_t nUnit = ntohl(*dp);
|
||||
|
||||
fsresult = fs.Lock(nUnit);
|
||||
}
|
||||
|
@ -26,7 +26,7 @@
|
||||
|
||||
using namespace std;
|
||||
|
||||
class SCSIBR final : public Disk
|
||||
class SCSIBR : public Disk
|
||||
{
|
||||
static constexpr const array<BYTE, 6> bcast_addr = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
|
||||
|
||||
@ -99,9 +99,9 @@ private:
|
||||
void FS_Lock(vector<BYTE>&); // $58 - get exclusive control
|
||||
|
||||
CFileSys fs; // File system accessor
|
||||
DWORD fsresult = 0; // File system access result code
|
||||
uint32_t fsresult = 0; // File system access result code
|
||||
array<BYTE, 0x800> fsout; // File system access result buffer
|
||||
DWORD fsoutlen = 0; // File system access result buffer size
|
||||
uint32_t fsoutlen = 0; // File system access result buffer size
|
||||
array<BYTE, 0x1000000> fsopt; // File system access buffer
|
||||
DWORD fsoptlen = 0; // File system access buffer size
|
||||
uint32_t fsoptlen = 0; // File system access buffer size
|
||||
};
|
||||
|
@ -145,7 +145,7 @@ void SCSIPrinter::Print()
|
||||
{
|
||||
CheckReservation();
|
||||
|
||||
uint32_t length = GetInt24(ctrl->cmd, 2);
|
||||
const uint32_t length = GetInt24(ctrl->cmd, 2);
|
||||
|
||||
LOGTRACE("Receiving %d byte(s) to be printed", length)
|
||||
|
||||
@ -153,7 +153,7 @@ void SCSIPrinter::Print()
|
||||
LOGERROR("%s", ("Transfer buffer overflow: Buffer size is " + to_string(controller->GetBuffer().size()) +
|
||||
" bytes, " + to_string(length) + " bytes expected").c_str())
|
||||
|
||||
throw scsi_error_exception(sense_key::ILLEGAL_REQUEST, asc::INVALID_FIELD_IN_CDB);
|
||||
throw scsi_exception(sense_key::ILLEGAL_REQUEST, asc::INVALID_FIELD_IN_CDB);
|
||||
}
|
||||
|
||||
ctrl->length = length;
|
||||
@ -167,11 +167,11 @@ void SCSIPrinter::SynchronizeBuffer()
|
||||
CheckReservation();
|
||||
|
||||
if (fd == -1) {
|
||||
throw scsi_error_exception();
|
||||
throw scsi_exception();
|
||||
}
|
||||
|
||||
// Make the file readable for the lp user
|
||||
fchmod(fd, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
|
||||
fchmod(fd, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH); //NOSONAR Granting permissions to "others" is required here
|
||||
|
||||
struct stat st;
|
||||
fstat(fd, &st);
|
||||
@ -180,7 +180,7 @@ void SCSIPrinter::SynchronizeBuffer()
|
||||
fd = -1;
|
||||
|
||||
string cmd = GetParam("cmd");
|
||||
size_t file_position = cmd.find("%f");
|
||||
const size_t file_position = cmd.find("%f");
|
||||
assert(file_position != string::npos);
|
||||
cmd.replace(file_position, 2, filename);
|
||||
cmd = "sudo -u lp " + cmd;
|
||||
@ -194,7 +194,7 @@ void SCSIPrinter::SynchronizeBuffer()
|
||||
|
||||
unlink(filename);
|
||||
|
||||
throw scsi_error_exception();
|
||||
throw scsi_exception();
|
||||
}
|
||||
|
||||
unlink(filename);
|
||||
@ -217,7 +217,7 @@ void SCSIPrinter::StopPrint()
|
||||
bool SCSIPrinter::WriteByteSequence(vector<BYTE>& buf, uint32_t length)
|
||||
{
|
||||
if (fd == -1) {
|
||||
strcpy(filename, TMP_FILE_PATTERN);
|
||||
strcpy(filename, TMP_FILE_PATTERN); //NOSONAR Using strcpy is safe here
|
||||
fd = mkstemp(filename);
|
||||
if (fd == -1) {
|
||||
LOGERROR("Can't create printer output file '%s': %s", filename, strerror(errno))
|
||||
@ -229,7 +229,7 @@ bool SCSIPrinter::WriteByteSequence(vector<BYTE>& buf, uint32_t length)
|
||||
|
||||
LOGTRACE("Appending %d byte(s) to printer output file '%s'", length, filename)
|
||||
|
||||
auto num_written = (uint32_t)write(fd, buf.data(), length);
|
||||
const auto num_written = (uint32_t)write(fd, buf.data(), length);
|
||||
|
||||
return num_written == length;
|
||||
}
|
||||
@ -248,7 +248,7 @@ void SCSIPrinter::CheckReservation()
|
||||
LOGTRACE("Unknown initiator tries to access reserved device ID %d, LUN %d", GetId(), GetLun())
|
||||
}
|
||||
|
||||
throw scsi_error_exception(sense_key::ABORTED_COMMAND, asc::NO_ADDITIONAL_SENSE_INFORMATION,
|
||||
throw scsi_exception(sense_key::ABORTED_COMMAND, asc::NO_ADDITIONAL_SENSE_INFORMATION,
|
||||
status::RESERVATION_CONFLICT);
|
||||
}
|
||||
|
||||
|
@ -15,9 +15,9 @@
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
|
||||
class SCSIPrinter final : public PrimaryDevice, public ScsiPrinterCommands //NOSONAR Custom destructor cannot be removed
|
||||
class SCSIPrinter : public PrimaryDevice, ScsiPrinterCommands //NOSONAR Custom destructor cannot be removed
|
||||
{
|
||||
static constexpr const char *TMP_FILE_PATTERN = "/tmp/rascsi_sclp-XXXXXX";
|
||||
static constexpr const char *TMP_FILE_PATTERN = "/tmp/rascsi_sclp-XXXXXX"; //NOSONAR Using /tmp is safe
|
||||
static const int TMP_FILENAME_LENGTH = string_view(TMP_FILE_PATTERN).size();
|
||||
|
||||
static const int NOT_RESERVED = -2;
|
||||
|
@ -90,7 +90,7 @@ void SCSICD::Open(const Filepath& path)
|
||||
assert(GetBlockCount() > 0);
|
||||
|
||||
super::Open(path);
|
||||
FileSupport::SetPath(path);
|
||||
SetPath(path);
|
||||
|
||||
SetUpCache(path, 0, rawfile);
|
||||
|
||||
@ -100,7 +100,7 @@ void SCSICD::Open(const Filepath& path)
|
||||
}
|
||||
}
|
||||
|
||||
void SCSICD::OpenCue(const Filepath& /*path*/) const
|
||||
void SCSICD::OpenCue(const Filepath&) const
|
||||
{
|
||||
throw io_exception("Opening CUE CD-ROM files is not supported");
|
||||
}
|
||||
@ -114,7 +114,7 @@ void SCSICD::OpenIso(const Filepath& path)
|
||||
}
|
||||
|
||||
// Get file size
|
||||
off_t size = fio.GetFileSize();
|
||||
const off_t size = fio.GetFileSize();
|
||||
if (size < 0x800) {
|
||||
fio.Close();
|
||||
throw io_exception("ISO CD-ROM file size must be at least 2048 bytes");
|
||||
@ -160,10 +160,10 @@ void SCSICD::OpenIso(const Filepath& path)
|
||||
}
|
||||
|
||||
// Set the number of blocks
|
||||
SetBlockCount((DWORD)(size / 0x930));
|
||||
SetBlockCount((uint32_t)(size / 0x930));
|
||||
} else {
|
||||
// Set the number of blocks
|
||||
SetBlockCount((DWORD)(size >> GetSectorSizeShiftCount()));
|
||||
SetBlockCount((uint32_t)(size >> GetSectorSizeShiftCount()));
|
||||
}
|
||||
|
||||
// Create only one data track
|
||||
@ -197,7 +197,7 @@ void SCSICD::OpenPhysical(const Filepath& path)
|
||||
size = (size / 512) * 512;
|
||||
|
||||
// Set the number of blocks
|
||||
SetBlockCount((DWORD)(size >> GetSectorSizeShiftCount()));
|
||||
SetBlockCount((uint32_t)(size >> GetSectorSizeShiftCount()));
|
||||
|
||||
// Create only one data track
|
||||
assert(!tracks.size());
|
||||
@ -275,11 +275,11 @@ int SCSICD::Read(const vector<int>& cdb, vector<BYTE>& buf, uint64_t block)
|
||||
CheckReady();
|
||||
|
||||
// Search for the track
|
||||
int index = SearchTrack((int)block);
|
||||
const int index = SearchTrack((int)block);
|
||||
|
||||
// If invalid, out of range
|
||||
if (index < 0) {
|
||||
throw scsi_error_exception(sense_key::ILLEGAL_REQUEST, asc::LBA_OUT_OF_RANGE);
|
||||
throw scsi_exception(sense_key::ILLEGAL_REQUEST, asc::LBA_OUT_OF_RANGE);
|
||||
}
|
||||
|
||||
assert(tracks[index]);
|
||||
@ -315,17 +315,17 @@ int SCSICD::ReadTocInternal(const vector<int>& cdb, vector<BYTE>& buf)
|
||||
assert(tracks[0]);
|
||||
|
||||
// Get allocation length, clear buffer
|
||||
int length = GetInt16(cdb, 7);
|
||||
const int length = GetInt16(cdb, 7);
|
||||
fill_n(buf.data(), length, 0);
|
||||
|
||||
// Get MSF Flag
|
||||
bool msf = cdb[1] & 0x02;
|
||||
const bool msf = cdb[1] & 0x02;
|
||||
|
||||
// Get and check the last track number
|
||||
int last = tracks[tracks.size() - 1]->GetTrackNo();
|
||||
const int last = tracks[tracks.size() - 1]->GetTrackNo();
|
||||
// Except for AA
|
||||
if (cdb[6] > last && cdb[6] != 0xaa) {
|
||||
throw scsi_error_exception(sense_key::ILLEGAL_REQUEST, asc::INVALID_FIELD_IN_CDB);
|
||||
throw scsi_exception(sense_key::ILLEGAL_REQUEST, asc::INVALID_FIELD_IN_CDB);
|
||||
}
|
||||
|
||||
// Check start index
|
||||
@ -358,12 +358,12 @@ int SCSICD::ReadTocInternal(const vector<int>& cdb, vector<BYTE>& buf)
|
||||
}
|
||||
|
||||
// Otherwise, error
|
||||
throw scsi_error_exception(sense_key::ILLEGAL_REQUEST, asc::INVALID_FIELD_IN_CDB);
|
||||
throw scsi_exception(sense_key::ILLEGAL_REQUEST, asc::INVALID_FIELD_IN_CDB);
|
||||
}
|
||||
}
|
||||
|
||||
// Number of track descriptors returned this time (number of loops)
|
||||
int loop = last - tracks[index]->GetTrackNo() + 1;
|
||||
const int loop = last - tracks[index]->GetTrackNo() + 1;
|
||||
assert(loop >= 1);
|
||||
|
||||
// Create header
|
||||
@ -407,11 +407,11 @@ void SCSICD::GetEventStatusNotification()
|
||||
{
|
||||
if (!(ctrl->cmd[1] & 0x01)) {
|
||||
// Asynchronous notification is optional and not supported by rascsi
|
||||
throw scsi_error_exception(sense_key::ILLEGAL_REQUEST, asc::INVALID_FIELD_IN_CDB);
|
||||
throw scsi_exception(sense_key::ILLEGAL_REQUEST, asc::INVALID_FIELD_IN_CDB);
|
||||
}
|
||||
|
||||
LOGTRACE("Received request for event polling, which is currently not supported")
|
||||
throw scsi_error_exception(sense_key::ILLEGAL_REQUEST, asc::INVALID_FIELD_IN_CDB);
|
||||
throw scsi_exception(sense_key::ILLEGAL_REQUEST, asc::INVALID_FIELD_IN_CDB);
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
@ -424,7 +424,7 @@ void SCSICD::LBAtoMSF(uint32_t lba, BYTE *msf) const
|
||||
// 75 and 75*60 get the remainder
|
||||
uint32_t m = lba / (75 * 60);
|
||||
uint32_t s = lba % (75 * 60);
|
||||
uint32_t f = s % 75;
|
||||
const uint32_t f = s % 75;
|
||||
s /= 75;
|
||||
|
||||
// The base point is M=0, S=2, F=0
|
||||
@ -459,7 +459,7 @@ void SCSICD::ClearTrack()
|
||||
// * Returns -1 if not found
|
||||
//
|
||||
//---------------------------------------------------------------------------
|
||||
int SCSICD::SearchTrack(DWORD lba) const
|
||||
int SCSICD::SearchTrack(uint32_t lba) const
|
||||
{
|
||||
// Track loop
|
||||
for (size_t i = 0; i < tracks.size(); i++) {
|
||||
|
@ -10,20 +10,16 @@
|
||||
// Licensed under the BSD 3-Clause License.
|
||||
// See LICENSE file in the project root folder.
|
||||
//
|
||||
// [ SCSI CD-ROM ]
|
||||
//
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "disk.h"
|
||||
#include "filepath.h"
|
||||
#include "cd_track.h"
|
||||
#include "file_support.h"
|
||||
#include "disk.h"
|
||||
#include "interfaces/scsi_mmc_commands.h"
|
||||
#include "interfaces/scsi_primary_commands.h"
|
||||
|
||||
class SCSICD : public Disk, public ScsiMmcCommands, public FileSupport
|
||||
class SCSICD : public Disk, private ScsiMmcCommands
|
||||
{
|
||||
public:
|
||||
|
||||
@ -68,7 +64,7 @@ private:
|
||||
|
||||
// Track management
|
||||
void ClearTrack(); // Clear the track
|
||||
int SearchTrack(DWORD lba) const; // Track search
|
||||
int SearchTrack(uint32_t lba) const; // Track search
|
||||
vector<unique_ptr<CDTrack>> tracks; // Track opbject references
|
||||
int dataindex = -1; // Current data track
|
||||
int audioindex = -1; // Current audio track
|
||||
|
@ -40,13 +40,13 @@ void SCSIHD::FinalizeSetup(const Filepath &path, off_t size, off_t image_offset)
|
||||
uint64_t capacity = GetBlockCount() * GetSectorSizeInBytes();
|
||||
string unit;
|
||||
// 10 GiB and more
|
||||
if (capacity >= 1099511627776) {
|
||||
capacity /= 1099511627776;
|
||||
if (capacity >= 1'099'511'627'776) {
|
||||
capacity /= 1'099'511'627'776;
|
||||
unit = "GiB";
|
||||
}
|
||||
// 1 MiB and more
|
||||
else if (capacity >= 1048576) {
|
||||
capacity /= 1048576;
|
||||
else if (capacity >= 1'048'576) {
|
||||
capacity /= 1'048'576;
|
||||
unit = "MiB";
|
||||
}
|
||||
else {
|
||||
@ -62,8 +62,8 @@ void SCSIHD::FinalizeSetup(const Filepath &path, off_t size, off_t image_offset)
|
||||
SetProtectable(true);
|
||||
SetProtected(false);
|
||||
|
||||
Disk::Open(path);
|
||||
FileSupport::SetPath(path);
|
||||
super::Open(path);
|
||||
SetPath(path);
|
||||
|
||||
SetUpCache(path, image_offset);
|
||||
}
|
||||
@ -84,7 +84,7 @@ void SCSIHD::Open(const Filepath& path)
|
||||
|
||||
// Sector size (default 512 bytes) and number of blocks
|
||||
SetSectorSizeInBytes(GetConfiguredSectorSize() ? GetConfiguredSectorSize() : 512);
|
||||
SetBlockCount((DWORD)(size >> GetSectorSizeShiftCount()));
|
||||
SetBlockCount((uint32_t)(size >> GetSectorSizeShiftCount()));
|
||||
|
||||
// Effective size must be a multiple of the sector size
|
||||
size = (size / GetSectorSizeInBytes()) * GetSectorSizeInBytes();
|
||||
|
@ -17,10 +17,9 @@
|
||||
#pragma once
|
||||
|
||||
#include "disk.h"
|
||||
#include "file_support.h"
|
||||
#include "filepath.h"
|
||||
|
||||
class SCSIHD : public Disk, public FileSupport
|
||||
class SCSIHD : public Disk
|
||||
{
|
||||
static constexpr const char *DEFAULT_PRODUCT = "SCSI HD";
|
||||
|
||||
@ -42,5 +41,7 @@ public:
|
||||
|
||||
private:
|
||||
|
||||
using super = Disk;
|
||||
|
||||
scsi_defs::scsi_level scsi_level;
|
||||
};
|
||||
|
@ -7,7 +7,7 @@
|
||||
// Copyright (C) 2014-2020 GIMONS
|
||||
// Copyright (C) akuker
|
||||
//
|
||||
// Licensed under the BSD 3-Clause License.
|
||||
// Licensed under the BSD 3-Clause License.
|
||||
// See LICENSE file in the project root folder.
|
||||
//
|
||||
// [ SCSI NEC "Genuine" Hard Disk]
|
||||
|
@ -59,8 +59,8 @@ void SCSIMO::Open(const Filepath& path)
|
||||
SetProtectable(true);
|
||||
SetProtected(false);
|
||||
|
||||
Disk::Open(path);
|
||||
FileSupport::SetPath(path);
|
||||
super::Open(path);
|
||||
SetPath(path);
|
||||
|
||||
SetUpCache(path, 0);
|
||||
|
||||
|
@ -15,12 +15,11 @@
|
||||
#pragma once
|
||||
|
||||
#include "disk.h"
|
||||
#include "file_support.h"
|
||||
#include "filepath.h"
|
||||
|
||||
using Geometry = pair<uint32_t, uint32_t>;
|
||||
|
||||
class SCSIMO : public Disk, public FileSupport
|
||||
class SCSIMO : public Disk
|
||||
{
|
||||
public:
|
||||
|
||||
@ -40,6 +39,8 @@ protected:
|
||||
|
||||
private:
|
||||
|
||||
using super = Disk;
|
||||
|
||||
void AddOptionPage(map<int, vector<byte>>&, bool) const;
|
||||
|
||||
bool SetGeometryForCapacity(uint64_t);
|
||||
|
@ -11,6 +11,7 @@
|
||||
#include "fileio.h"
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
#include <cassert>
|
||||
|
||||
Fileio::~Fileio()
|
||||
{
|
||||
@ -30,7 +31,7 @@ bool Fileio::Open(const char *fname, OpenMode mode, bool directIO)
|
||||
}
|
||||
|
||||
// Default mode
|
||||
mode_t omode = directIO ? O_DIRECT : 0;
|
||||
const mode_t omode = directIO ? O_DIRECT : 0;
|
||||
|
||||
switch (mode) {
|
||||
case OpenMode::ReadOnly:
|
||||
@ -111,10 +112,10 @@ off_t Fileio::GetFileSize() const
|
||||
assert(handle >= 0);
|
||||
|
||||
// Get file position in 64bit
|
||||
off_t cur = lseek(handle, 0, SEEK_CUR);
|
||||
const off_t cur = lseek(handle, 0, SEEK_CUR);
|
||||
|
||||
// Get file size in64bitで
|
||||
off_t end = lseek(handle, 0, SEEK_END);
|
||||
const off_t end = lseek(handle, 0, SEEK_END);
|
||||
|
||||
// Return to start position
|
||||
Seek(cur);
|
||||
|
@ -11,7 +11,7 @@
|
||||
#pragma once
|
||||
|
||||
#include "filepath.h"
|
||||
#include <sys/types.h>
|
||||
#include <cstdlib>
|
||||
|
||||
class Fileio
|
||||
{
|
||||
|
@ -8,11 +8,11 @@
|
||||
//
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
#include "os.h"
|
||||
#include "filepath.h"
|
||||
#include "config.h"
|
||||
#include "fileio.h"
|
||||
#include <libgen.h>
|
||||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
#include <cassert>
|
||||
|
||||
Filepath& Filepath::operator=(const Filepath& path)
|
||||
{
|
||||
@ -55,7 +55,7 @@ void Filepath::Split()
|
||||
char *pDir = strdup(m_szPath);
|
||||
const char *pDirName = dirname(pDir);
|
||||
char *pBase = strdup(m_szPath);
|
||||
char *pBaseName = basename(pBase);
|
||||
const char *pBaseName = basename(pBase);
|
||||
const char *pExtName = strrchr(pBaseName, '.');
|
||||
|
||||
// Transmit
|
||||
|
@ -32,7 +32,7 @@ BUS::phase_t GetPhase(const data_capture *sample)
|
||||
}
|
||||
|
||||
// Get target phase from bus signal line
|
||||
DWORD mci = GetMsg(sample) ? 0x04 : 0x00;
|
||||
uint32_t mci = GetMsg(sample) ? 0x04 : 0x00;
|
||||
mci |= GetCd(sample) ? 0x02 : 0x00;
|
||||
mci |= GetIo(sample) ? 0x01 : 0x00;
|
||||
return BUS::GetPhase(mci);
|
||||
|
@ -16,7 +16,7 @@
|
||||
|
||||
using data_capture_t = struct data_capture
|
||||
{
|
||||
DWORD data;
|
||||
uint32_t data;
|
||||
uint64_t timestamp;
|
||||
};
|
||||
|
||||
@ -34,7 +34,7 @@ inline bool GetReq(const data_capture *sample) { return BUS::GetPinRaw(sample->d
|
||||
inline bool GetDp(const data_capture *sample) { return BUS::GetPinRaw(sample->data, PIN_DP); }
|
||||
inline BYTE GetData(const data_capture *sample)
|
||||
{
|
||||
DWORD data = sample->data;
|
||||
uint32_t data = sample->data;
|
||||
return (BYTE)((data >> (PIN_DT0 - 0)) & (1 << 0)) |
|
||||
((data >> (PIN_DT1 - 1)) & (1 << 1)) |
|
||||
((data >> (PIN_DT2 - 2)) & (1 << 2)) |
|
||||
|
@ -8,7 +8,6 @@
|
||||
//
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
#include <stdio.h>
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
#include "os.h"
|
||||
@ -98,12 +97,12 @@ for (i = 0; i < coll.length; i++) {
|
||||
)";
|
||||
|
||||
|
||||
static void print_html_data(ofstream& html_fp, const data_capture *data_capture_array, DWORD capture_count)
|
||||
static void print_html_data(ofstream& html_fp, const data_capture *data_capture_array, uint32_t capture_count)
|
||||
{
|
||||
const data_capture *data;
|
||||
bool prev_data_valid = false;
|
||||
bool curr_data_valid;
|
||||
DWORD selected_id = 0;
|
||||
uint32_t selected_id = 0;
|
||||
BUS::phase_t prev_phase = BUS::phase_t::busfree;
|
||||
bool close_row = false;
|
||||
int data_space_count = 0;
|
||||
@ -112,34 +111,26 @@ static void print_html_data(ofstream& html_fp, const data_capture *data_capture_
|
||||
|
||||
html_fp << "<table>" << endl;
|
||||
|
||||
for (DWORD idx = 0; idx < capture_count; idx++)
|
||||
{
|
||||
for (uint32_t idx = 0; idx < capture_count; idx++) {
|
||||
data = &data_capture_array[idx];
|
||||
curr_data_valid = GetAck(data) && GetReq(data);
|
||||
BUS::phase_t phase = GetPhase(data);
|
||||
if (phase == BUS::phase_t::selection && !GetBsy(data))
|
||||
{
|
||||
if (phase == BUS::phase_t::selection && !GetBsy(data)) {
|
||||
selected_id = GetData(data);
|
||||
}
|
||||
if (prev_phase != phase)
|
||||
{
|
||||
if (close_row)
|
||||
{
|
||||
if (collapsible_div_active)
|
||||
{
|
||||
if (prev_phase != phase) {
|
||||
if (close_row) {
|
||||
if (collapsible_div_active) {
|
||||
html_fp << "</code></div>";
|
||||
}
|
||||
else if (button_active)
|
||||
{
|
||||
else if (button_active) {
|
||||
html_fp << "</code></button>";
|
||||
}
|
||||
html_fp << "</td>";
|
||||
if (data_space_count < 1)
|
||||
{
|
||||
if (data_space_count < 1) {
|
||||
html_fp << "<td>--</td>";
|
||||
}
|
||||
else
|
||||
{
|
||||
else {
|
||||
html_fp << "<td>wc: " << std::dec << "(0x" << std::hex << data_space_count << ")</td>";
|
||||
}
|
||||
html_fp << "</tr>" << endl;
|
||||
@ -152,33 +143,27 @@ static void print_html_data(ofstream& html_fp, const data_capture *data_capture_
|
||||
html_fp << "<td>" << std::hex << selected_id << "</td>";
|
||||
html_fp << "<td>";
|
||||
}
|
||||
if (curr_data_valid && !prev_data_valid)
|
||||
{
|
||||
if (data_space_count == 0)
|
||||
{
|
||||
if (curr_data_valid && !prev_data_valid) {
|
||||
if (data_space_count == 0) {
|
||||
button_active = true;
|
||||
html_fp << "<button type=\"button\" class=\"collapsible\"><code>";
|
||||
}
|
||||
if ((data_space_count % 16) == 0)
|
||||
{
|
||||
if ((data_space_count % 16) == 0) {
|
||||
html_fp << std::hex << data_space_count << ": ";
|
||||
}
|
||||
|
||||
html_fp << fmt::format("{0:02X}", GetData(data));
|
||||
|
||||
data_space_count++;
|
||||
if ((data_space_count % 4) == 0)
|
||||
{
|
||||
if ((data_space_count % 4) == 0) {
|
||||
html_fp << " ";
|
||||
}
|
||||
if (data_space_count == 16)
|
||||
{
|
||||
if (data_space_count == 16) {
|
||||
html_fp << "</code></button><div class=\"content\"><code>" << endl;
|
||||
collapsible_div_active = true;
|
||||
button_active = false;
|
||||
}
|
||||
if (((data_space_count % 16) == 0) && (data_space_count > 17))
|
||||
{
|
||||
if (((data_space_count % 16) == 0) && (data_space_count > 17)) {
|
||||
html_fp << "<br>" << endl;
|
||||
}
|
||||
}
|
||||
@ -187,9 +172,9 @@ static void print_html_data(ofstream& html_fp, const data_capture *data_capture_
|
||||
}
|
||||
}
|
||||
|
||||
void scsimon_generate_html(const char *filename, const data_capture *data_capture_array, DWORD capture_count)
|
||||
void scsimon_generate_html(const char *filename, const data_capture *data_capture_array, uint32_t capture_count)
|
||||
{
|
||||
LOGINFO("Creating HTML report file (%s)", filename);
|
||||
LOGINFO("Creating HTML report file (%s)", filename)
|
||||
|
||||
ofstream html_ofstream;
|
||||
|
||||
|
@ -19,45 +19,39 @@ using namespace std;
|
||||
const char timestamp_label[] = "\"timestamp\":\"0x";
|
||||
const char data_label[] = "\"data\":\"0x";
|
||||
|
||||
DWORD scsimon_read_json(const char *json_filename, data_capture *data_capture_array, DWORD max_sz)
|
||||
uint32_t scsimon_read_json(const char *json_filename, data_capture *data_capture_array, uint32_t max_sz)
|
||||
{
|
||||
char str_buf[1024];
|
||||
FILE *fp = fopen(json_filename, "r");
|
||||
DWORD sample_count = 0;
|
||||
uint32_t sample_count = 0;
|
||||
|
||||
while (fgets(str_buf, sizeof(str_buf), fp))
|
||||
{
|
||||
while (fgets(str_buf, sizeof(str_buf), fp)) {
|
||||
char timestamp[1024];
|
||||
char data[1024];
|
||||
uint64_t timestamp_uint;
|
||||
uint32_t data_uint;
|
||||
char *ptr;
|
||||
|
||||
const char *timestamp_str;
|
||||
const char *data_str;
|
||||
timestamp_str = strstr(str_buf, timestamp_label);
|
||||
const char *timestamp_str = strstr(str_buf, timestamp_label);
|
||||
if (!timestamp_str)
|
||||
continue;
|
||||
strncpy(timestamp, ×tamp_str[strlen(timestamp_label)], 16);
|
||||
timestamp[16] = '\0';
|
||||
timestamp_uint = strtoull(timestamp, &ptr, 16);
|
||||
|
||||
data_str = strstr(str_buf, data_label);
|
||||
const char *data_str = strstr(str_buf, data_label);
|
||||
if (!data_str)
|
||||
continue;
|
||||
strncpy(data, &data_str[strlen(data_label)], 8);
|
||||
data[8] = '\0';
|
||||
data_uint = strtoul(data, &ptr, 16);
|
||||
|
||||
// printf("Time: %016llX Data: %08X\n", timestamp_uint, data_uint);
|
||||
|
||||
data_capture_array[sample_count].timestamp = timestamp_uint;
|
||||
data_capture_array[sample_count].data = data_uint;
|
||||
sample_count++;
|
||||
if (sample_count >= max_sz)
|
||||
{
|
||||
LOGWARN("File exceeds maximum buffer size. Some data may be missing.");
|
||||
LOGWARN("Try re-running the tool with a larger buffer size");
|
||||
if (sample_count >= max_sz) {
|
||||
LOGWARN("File exceeds maximum buffer size. Some data may be missing.")
|
||||
LOGWARN("Try re-running the tool with a larger buffer size")
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -74,17 +68,16 @@ DWORD scsimon_read_json(const char *json_filename, data_capture *data_capture_ar
|
||||
// Generate JSON Output File
|
||||
//
|
||||
//---------------------------------------------------------------------------
|
||||
void scsimon_generate_json(const char *filename, const data_capture *data_capture_array, DWORD capture_count)
|
||||
void scsimon_generate_json(const char *filename, const data_capture *data_capture_array, uint32_t capture_count)
|
||||
{
|
||||
LOGTRACE("Creating JSON file (%s)", filename);
|
||||
LOGTRACE("Creating JSON file (%s)", filename)
|
||||
ofstream json_ofstream;
|
||||
json_ofstream.open(filename, ios::out);
|
||||
|
||||
json_ofstream << "[" << endl;
|
||||
|
||||
DWORD i = 0;
|
||||
while (i < capture_count)
|
||||
{
|
||||
uint32_t i = 0;
|
||||
while (i < capture_count) {
|
||||
json_ofstream << fmt::format("{{\"id\": \"{0:d}\", \"timestamp\":\"{1:#016x}\", \"data\":\"{2:#08x}\"}}", i, data_capture_array[i].timestamp, data_capture_array[i].data);
|
||||
|
||||
if (i != (capture_count - 1))
|
||||
|
@ -11,8 +11,8 @@
|
||||
|
||||
#include "data_sample.h"
|
||||
|
||||
DWORD scsimon_read_json(const char *json_filename, data_capture *data_capture_array, DWORD max_sz);
|
||||
uint32_t scsimon_read_json(const char *json_filename, data_capture *data_capture_array, uint32_t max_sz);
|
||||
|
||||
void scsimon_generate_html(const char *filename, const data_capture *data_capture_array, DWORD capture_count);
|
||||
void scsimon_generate_json(const char *filename, const data_capture *data_capture_array, DWORD capture_count);
|
||||
void scsimon_generate_value_change_dump(const char *filename, const data_capture *data_capture_array, DWORD capture_count);
|
||||
void scsimon_generate_html(const char *filename, const data_capture *data_capture_array, uint32_t capture_count);
|
||||
void scsimon_generate_json(const char *filename, const data_capture *data_capture_array, uint32_t capture_count);
|
||||
void scsimon_generate_value_change_dump(const char *filename, const data_capture *data_capture_array, uint32_t capture_count);
|
||||
|
@ -54,14 +54,14 @@ static BYTE prev_value[32] = {0xFF};
|
||||
|
||||
extern double ns_per_loop;
|
||||
|
||||
static BYTE get_pin_value(DWORD data, int pin)
|
||||
static BYTE get_pin_value(uint32_t data, int pin)
|
||||
{
|
||||
return (data >> pin) & 1;
|
||||
}
|
||||
|
||||
static BYTE get_data_field(DWORD data)
|
||||
static BYTE get_data_field(uint32_t data)
|
||||
{
|
||||
DWORD data_out =
|
||||
const uint32_t data_out =
|
||||
((data >> (PIN_DT0 - 0)) & (1 << 7)) |
|
||||
((data >> (PIN_DT1 - 1)) & (1 << 6)) |
|
||||
((data >> (PIN_DT2 - 2)) & (1 << 5)) |
|
||||
@ -74,31 +74,28 @@ static BYTE get_data_field(DWORD data)
|
||||
return (BYTE)data_out;
|
||||
}
|
||||
|
||||
static void vcd_output_if_changed_phase(ofstream& fp, DWORD data, int pin, char symbol)
|
||||
static void vcd_output_if_changed_phase(ofstream& fp, uint32_t data, int pin, char symbol)
|
||||
{
|
||||
BUS::phase_t new_value = GPIOBUS::GetPhaseRaw(data);
|
||||
if (prev_value[pin] != (int)new_value)
|
||||
{
|
||||
const BUS::phase_t new_value = GPIOBUS::GetPhaseRaw(data);
|
||||
if (prev_value[pin] != (int)new_value) {
|
||||
prev_value[pin] = (int)new_value;
|
||||
fp << "s" << GPIOBUS::GetPhaseStrRaw(new_value) << " " << symbol << endl;
|
||||
}
|
||||
}
|
||||
|
||||
static void vcd_output_if_changed_bool(ofstream& fp, DWORD data, int pin, char symbol)
|
||||
static void vcd_output_if_changed_bool(ofstream& fp, uint32_t data, int pin, char symbol)
|
||||
{
|
||||
BYTE new_value = get_pin_value(data, pin);
|
||||
if (prev_value[pin] != new_value)
|
||||
{
|
||||
const BYTE new_value = get_pin_value(data, pin);
|
||||
if (prev_value[pin] != new_value) {
|
||||
prev_value[pin] = new_value;
|
||||
fp << new_value << symbol << endl;
|
||||
}
|
||||
}
|
||||
|
||||
static void vcd_output_if_changed_byte(ofstream& fp, DWORD data, int pin, char symbol)
|
||||
static void vcd_output_if_changed_byte(ofstream& fp, uint32_t data, int pin, char symbol)
|
||||
{
|
||||
BYTE new_value = get_data_field(data);
|
||||
if (prev_value[pin] != new_value)
|
||||
{
|
||||
const BYTE new_value = get_data_field(data);
|
||||
if (prev_value[pin] != new_value) {
|
||||
prev_value[pin] = new_value;
|
||||
fp << "b"
|
||||
<< fmt::format("{0:b}", get_pin_value(data, PIN_DT7))
|
||||
@ -113,9 +110,9 @@ static void vcd_output_if_changed_byte(ofstream& fp, DWORD data, int pin, char s
|
||||
}
|
||||
}
|
||||
|
||||
void scsimon_generate_value_change_dump(const char *filename, const data_capture *data_capture_array, DWORD capture_count)
|
||||
void scsimon_generate_value_change_dump(const char *filename, const data_capture *data_capture_array, uint32_t capture_count)
|
||||
{
|
||||
LOGTRACE("Creating Value Change Dump file (%s)", filename);
|
||||
LOGTRACE("Creating Value Change Dump file (%s)", filename)
|
||||
ofstream vcd_ofstream;
|
||||
vcd_ofstream.open(filename, ios::out);
|
||||
|
||||
@ -126,7 +123,7 @@ void scsimon_generate_value_change_dump(const char *filename, const data_capture
|
||||
char timestamp[256];
|
||||
strftime(timestamp, sizeof(timestamp), "%d-%m-%Y %H-%M-%S", timeinfo);
|
||||
|
||||
vcd_ofstream
|
||||
vcd_ofstream
|
||||
<< "$date" << endl
|
||||
<< timestamp << endl
|
||||
<< "$end" << endl
|
||||
@ -167,9 +164,8 @@ void scsimon_generate_value_change_dump(const char *filename, const data_capture
|
||||
<< "b00000000 " << SYMBOL_PIN_DAT << endl
|
||||
<< "$end" << endl;
|
||||
|
||||
DWORD i = 0;
|
||||
while (i < capture_count)
|
||||
{
|
||||
uint32_t i = 0;
|
||||
while (i < capture_count) {
|
||||
vcd_ofstream << "#" << (uint64_t)(data_capture_array[i].timestamp * ns_per_loop) << endl;
|
||||
vcd_output_if_changed_bool(vcd_ofstream, data_capture_array[i].data, PIN_BSY, SYMBOL_PIN_BSY);
|
||||
vcd_output_if_changed_bool(vcd_ofstream, data_capture_array[i].data, PIN_SEL, SYMBOL_PIN_SEL);
|
||||
|
@ -7,17 +7,11 @@
|
||||
// Copyright (C) 2016-2020 GIMONS
|
||||
// Copyright (C) 2020 akuker
|
||||
//
|
||||
// [ OS related definitions ]
|
||||
//
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
#include <cassert>
|
||||
#include <cstdint>
|
||||
|
||||
using BYTE = unsigned char;
|
||||
using WORD = uint16_t;
|
||||
using DWORD = uint32_t;
|
||||
|
@ -11,7 +11,6 @@
|
||||
#include "protobuf_serializer.h"
|
||||
#include "rascsi_exceptions.h"
|
||||
#include <unistd.h>
|
||||
#include <sstream>
|
||||
|
||||
using namespace std;
|
||||
using namespace rascsi_interface;
|
||||
@ -45,10 +44,11 @@ void ProtobufSerializer::DeserializeMessage(int fd, google::protobuf::Message& m
|
||||
// Read the header with the size of the protobuf data
|
||||
vector<byte> header_buf(4);
|
||||
if (ReadBytes(fd, header_buf) < header_buf.size()) {
|
||||
return;
|
||||
throw io_exception("Invalid protobuf message header");
|
||||
}
|
||||
|
||||
size_t size = ((int)header_buf[3] << 24) + ((int)header_buf[2] << 16) + ((int)header_buf[1] << 8) + (int)header_buf[0];
|
||||
const size_t size = ((int)header_buf[3] << 24) + ((int)header_buf[2] << 16)
|
||||
+ ((int)header_buf[1] << 8) + (int)header_buf[0];
|
||||
if (size <= 0) {
|
||||
throw io_exception("Invalid protobuf message header");
|
||||
}
|
||||
@ -68,7 +68,7 @@ size_t ProtobufSerializer::ReadBytes(int fd, vector<byte>& buf) const
|
||||
{
|
||||
size_t offset = 0;
|
||||
while (offset < buf.size()) {
|
||||
ssize_t len = read(fd, &buf[offset], buf.size() - offset);
|
||||
const ssize_t len = read(fd, &buf.data()[offset], buf.size() - offset);
|
||||
if (len <= 0) {
|
||||
return len;
|
||||
}
|
||||
|
103
src/raspberrypi/protobuf_util.cpp
Normal file
103
src/raspberrypi/protobuf_util.cpp
Normal 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);
|
||||
}
|
@ -5,7 +5,7 @@
|
||||
//
|
||||
// Copyright (C) 2021-2022 Uwe Seimet
|
||||
//
|
||||
// Helper methods for serializing/deserializing protobuf messages
|
||||
// Helper methods for setting up/evaluating protobuf messages
|
||||
//
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
@ -18,7 +18,7 @@
|
||||
using namespace std;
|
||||
using namespace rascsi_interface;
|
||||
|
||||
namespace command_util
|
||||
namespace protobuf_util
|
||||
{
|
||||
void ParseParameters(PbDeviceDefinition&, const string&);
|
||||
string GetParam(const PbCommand&, const string&);
|
||||
@ -26,4 +26,5 @@ namespace command_util
|
||||
void AddParam(PbCommand&, const string&, string_view);
|
||||
void AddParam(PbDevice&, const string&, string_view);
|
||||
void AddParam(PbDeviceDefinition&, const string&, string_view);
|
||||
void SetPatternParams(PbCommand&, string_view);
|
||||
}
|
@ -15,13 +15,13 @@
|
||||
#include "controllers/controller_manager.h"
|
||||
#include "controllers/scsi_controller.h"
|
||||
#include "devices/device_factory.h"
|
||||
#include "devices/file_support.h"
|
||||
#include "devices/disk.h"
|
||||
#include "hal/gpiobus.h"
|
||||
#include "hal/systimer.h"
|
||||
#include "rascsi_version.h"
|
||||
#include "rascsi_exceptions.h"
|
||||
#include "protobuf_serializer.h"
|
||||
#include "command_util.h"
|
||||
#include "rascsi_version.h"
|
||||
#include "protobuf_util.h"
|
||||
#include "rascsi_interface.pb.h"
|
||||
#include "rascsi/rascsi_executor.h"
|
||||
#include "rascsi/rascsi_response.h"
|
||||
@ -43,7 +43,7 @@ using namespace std;
|
||||
using namespace spdlog;
|
||||
using namespace rascsi_interface;
|
||||
using namespace ras_util;
|
||||
using namespace command_util;
|
||||
using namespace protobuf_util;
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
//
|
||||
@ -61,7 +61,7 @@ static const char COMPONENT_SEPARATOR = ':';
|
||||
static volatile bool active; // Processing flag
|
||||
RascsiService service;
|
||||
GPIOBUS bus;
|
||||
string current_log_level; // Some versions of spdlog do not support get_log_level()
|
||||
string current_log_level = "info"; // Some versions of spdlog do not support get_log_level()
|
||||
string access_token;
|
||||
DeviceFactory device_factory;
|
||||
ControllerManager controller_manager(bus);
|
||||
@ -72,28 +72,23 @@ const ProtobufSerializer serializer;
|
||||
|
||||
void Banner(int argc, char* argv[])
|
||||
{
|
||||
cout << "SCSI Target Emulator RaSCSI Reloaded version " << rascsi_get_version_string()
|
||||
<< " (" << __DATE__ << ' ' << __TIME__ << ')' << endl;
|
||||
cout << "Powered by XM6 TypeG Technology / ";
|
||||
cout << "Copyright (C) 2016-2020 GIMONS" << endl;
|
||||
cout << "Copyright (C) 2020-2022 Contributors to the RaSCSI Reloaded project" << endl;
|
||||
cout << "Connect type: " << CONNECT_DESC << endl;
|
||||
cout << Banner("Reloaded");
|
||||
cout << "Connect type: " << CONNECT_DESC << '\n' << flush;
|
||||
|
||||
if ((argc > 1 && strcmp(argv[1], "-h") == 0) || (argc > 1 && strcmp(argv[1], "--help") == 0)){
|
||||
cout << endl;
|
||||
cout << "Usage: " << argv[0] << " [-idn[:m] FILE] ..." << endl << endl;
|
||||
cout << " n is SCSI device ID (0-7)." << endl;
|
||||
cout << " m is the optional logical unit (LUN) (0-31)." << endl;
|
||||
cout << " FILE is a disk image file, \"daynaport\", \"bridge\", \"printer\" or \"services\"." << endl << endl;
|
||||
cout << " Image type is detected based on file extension if no explicit type is specified." << endl;
|
||||
cout << " hd1 : SCSI-1 HD image (Non-removable generic SCSI-1 HD image)" << endl;
|
||||
cout << " hds : SCSI HD image (Non-removable generic SCSI HD image)" << endl;
|
||||
cout << " hdr : SCSI HD image (Removable generic HD image)" << endl;
|
||||
cout << " hdn : SCSI HD image (NEC GENUINE)" << endl;
|
||||
cout << " hdi : SCSI HD image (Anex86 HD image)" << endl;
|
||||
cout << " nhd : SCSI HD image (T98Next HD image)" << endl;
|
||||
cout << " mos : SCSI MO image (MO image)" << endl;
|
||||
cout << " iso : SCSI CD image (ISO 9660 image)" << endl;
|
||||
cout << "\nUsage: " << argv[0] << " [-idn[:m] FILE] ...\n\n";
|
||||
cout << " n is SCSI device ID (0-7).\n";
|
||||
cout << " m is the optional logical unit (LUN) (0-31).\n";
|
||||
cout << " FILE is a disk image file, \"daynaport\", \"bridge\", \"printer\" or \"services\".\n\n";
|
||||
cout << " Image type is detected based on file extension if no explicit type is specified.\n";
|
||||
cout << " hd1 : SCSI-1 HD image (Non-removable generic SCSI-1 HD image)\n";
|
||||
cout << " hds : SCSI HD image (Non-removable generic SCSI HD image)\n";
|
||||
cout << " hdr : SCSI HD image (Removable generic HD image)\n";
|
||||
cout << " hdn : SCSI HD image (NEC GENUINE)\n";
|
||||
cout << " hdi : SCSI HD image (Anex86 HD image)\n";
|
||||
cout << " nhd : SCSI HD image (T98Next HD image)\n";
|
||||
cout << " mos : SCSI MO image (MO image)\n";
|
||||
cout << " iso : SCSI CD image (ISO 9660 image)\n" << flush;
|
||||
|
||||
exit(EXIT_SUCCESS);
|
||||
}
|
||||
@ -185,7 +180,7 @@ void TerminationHandler(int signum)
|
||||
|
||||
bool ProcessId(const string& id_spec, int& id, int& unit)
|
||||
{
|
||||
if (size_t separator_pos = id_spec.find(COMPONENT_SEPARATOR); separator_pos == string::npos) {
|
||||
if (const size_t separator_pos = id_spec.find(COMPONENT_SEPARATOR); separator_pos == string::npos) {
|
||||
if (!GetAsInt(id_spec, id) || id < 0 || id >= 8) {
|
||||
cerr << optarg << ": Invalid device ID (0-7)" << endl;
|
||||
return false;
|
||||
@ -249,7 +244,7 @@ bool ParseArgument(int argc, char* argv[], int& port)
|
||||
continue;
|
||||
|
||||
case 'F': {
|
||||
if (string result = rascsi_image.SetDefaultFolder(optarg); !result.empty()) {
|
||||
if (const string result = rascsi_image.SetDefaultFolder(optarg); !result.empty()) {
|
||||
cerr << result << endl;
|
||||
return false;
|
||||
}
|
||||
@ -365,7 +360,7 @@ bool ParseArgument(int argc, char* argv[], int& port)
|
||||
const list<PbDevice>& devices = { server_info.devices_info().devices().begin(), server_info.devices_info().devices().end() };
|
||||
const string device_list = ListDevices(devices);
|
||||
LogDevices(device_list);
|
||||
cout << device_list << endl;
|
||||
cout << device_list << flush;
|
||||
|
||||
return true;
|
||||
}
|
||||
@ -388,8 +383,8 @@ static bool ExecuteCommand(const CommandContext& context, PbCommand& command)
|
||||
|
||||
switch(command.operation()) {
|
||||
case LOG_LEVEL: {
|
||||
string log_level = GetParam(command, "level");
|
||||
if (bool status = executor.SetLogLevel(log_level); !status) {
|
||||
const string log_level = GetParam(command, "level");
|
||||
if (const bool status = executor.SetLogLevel(log_level); !status) {
|
||||
context.ReturnLocalizedError(LocalizationKey::ERROR_LOG_LEVEL, log_level);
|
||||
}
|
||||
else {
|
||||
@ -401,7 +396,7 @@ static bool ExecuteCommand(const CommandContext& context, PbCommand& command)
|
||||
}
|
||||
|
||||
case DEFAULT_FOLDER: {
|
||||
if (string status = rascsi_image.SetDefaultFolder(GetParam(command, "folder")); !status.empty()) {
|
||||
if (const string status = rascsi_image.SetDefaultFolder(GetParam(command, "folder")); !status.empty()) {
|
||||
context.ReturnStatus(false, status);
|
||||
}
|
||||
else {
|
||||
@ -457,7 +452,7 @@ static bool ExecuteCommand(const CommandContext& context, PbCommand& command)
|
||||
}
|
||||
else {
|
||||
auto image_file = make_unique<PbImageFile>();
|
||||
bool status = rascsi_response.GetImageFile(*image_file.get(), rascsi_image.GetDefaultFolder(), filename);
|
||||
const bool status = rascsi_response.GetImageFile(*image_file.get(), rascsi_image.GetDefaultFolder(), filename);
|
||||
if (status) {
|
||||
result.set_status(true);
|
||||
result.set_allocated_image_file_info(image_file.get());
|
||||
@ -505,7 +500,7 @@ static bool ExecuteCommand(const CommandContext& context, PbCommand& command)
|
||||
|
||||
default: {
|
||||
// Wait until we become idle
|
||||
timespec ts = { .tv_sec = 0, .tv_nsec = 500 * 1000 * 1000};
|
||||
const timespec ts = { .tv_sec = 0, .tv_nsec = 500'000'000};
|
||||
while (active) {
|
||||
nanosleep(&ts, nullptr);
|
||||
}
|
||||
@ -537,10 +532,10 @@ int main(int argc, char* argv[])
|
||||
}
|
||||
}
|
||||
|
||||
executor.SetLogLevel("info");
|
||||
executor.SetLogLevel(current_log_level);
|
||||
|
||||
// Create a thread-safe stdout logger to process the log messages
|
||||
auto logger = stdout_color_mt("rascsi stdout logger");
|
||||
const auto logger = stdout_color_mt("rascsi stdout logger");
|
||||
|
||||
if (!InitBus()) {
|
||||
return EPERM;
|
||||
@ -599,7 +594,7 @@ int main(int argc, char* argv[])
|
||||
#else
|
||||
bus.Acquire();
|
||||
if (!bus.GetSEL()) {
|
||||
timespec ts = { .tv_sec = 0, .tv_nsec = 0};
|
||||
const timespec ts = { .tv_sec = 0, .tv_nsec = 0};
|
||||
nanosleep(&ts, nullptr);
|
||||
continue;
|
||||
}
|
||||
@ -608,8 +603,8 @@ int main(int argc, char* argv[])
|
||||
// Wait until BSY is released as there is a possibility for the
|
||||
// initiator to assert it while setting the ID (for up to 3 seconds)
|
||||
if (bus.GetBSY()) {
|
||||
uint32_t now = SysTimer::GetTimerLow();
|
||||
while ((SysTimer::GetTimerLow() - now) < 3 * 1000 * 1000) {
|
||||
const uint32_t now = SysTimer::GetTimerLow();
|
||||
while ((SysTimer::GetTimerLow() - now) < 3'000'000) {
|
||||
bus.Acquire();
|
||||
if (!bus.GetBSY()) {
|
||||
break;
|
||||
@ -625,7 +620,7 @@ int main(int argc, char* argv[])
|
||||
int initiator_id = -1;
|
||||
|
||||
// The initiator and target ID
|
||||
BYTE id_data = bus.GetDAT();
|
||||
const BYTE id_data = bus.GetDAT();
|
||||
|
||||
BUS::phase_t phase = BUS::phase_t::busfree;
|
||||
|
||||
|
@ -15,10 +15,11 @@
|
||||
using namespace std;
|
||||
using namespace rascsi_interface;
|
||||
|
||||
void CommandContext::Cleanup() const
|
||||
void CommandContext::Cleanup()
|
||||
{
|
||||
if (fd != -1) {
|
||||
close(fd);
|
||||
fd = -1;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -32,7 +32,7 @@ public:
|
||||
CommandContext(const std::string& s = "", int f = -1) : locale(s), fd(f) {}
|
||||
~CommandContext() = default;
|
||||
|
||||
void Cleanup() const;
|
||||
void Cleanup();
|
||||
|
||||
const ProtobufSerializer& GetSerializer() const { return serializer; }
|
||||
int GetFd() const { return fd; }
|
||||
|
@ -13,13 +13,12 @@
|
||||
#include "devices/device_factory.h"
|
||||
#include "devices/primary_device.h"
|
||||
#include "devices/disk.h"
|
||||
#include "devices/file_support.h"
|
||||
#include "rascsi_service.h"
|
||||
#include "rascsi_response.h"
|
||||
#include "rascsi_image.h"
|
||||
#include "rascsi_exceptions.h"
|
||||
#include "localizer.h"
|
||||
#include "command_util.h"
|
||||
#include "protobuf_util.h"
|
||||
#include "command_context.h"
|
||||
#include "rasutil.h"
|
||||
#include "spdlog/spdlog.h"
|
||||
@ -27,7 +26,7 @@
|
||||
#include <sstream>
|
||||
|
||||
using namespace spdlog;
|
||||
using namespace command_util;
|
||||
using namespace protobuf_util;
|
||||
using namespace ras_util;
|
||||
|
||||
bool RascsiExecutor::ProcessCmd(const CommandContext& context, const PbDeviceDefinition& pb_device,
|
||||
@ -103,7 +102,7 @@ bool RascsiExecutor::ProcessCmd(const CommandContext& context, const PbCommand&
|
||||
|
||||
case RESERVE_IDS: {
|
||||
const string ids = GetParam(command, "ids");
|
||||
if (string error = SetReservedIds(ids); !error.empty()) {
|
||||
if (const string error = SetReservedIds(ids); !error.empty()) {
|
||||
return context.ReturnStatus(false, error);
|
||||
}
|
||||
|
||||
@ -132,19 +131,19 @@ bool RascsiExecutor::ProcessCmd(const CommandContext& context, const PbCommand&
|
||||
}
|
||||
|
||||
// Remember the list of reserved files, than run the dry run
|
||||
const auto& reserved_files = FileSupport::GetReservedFiles();
|
||||
const auto& reserved_files = Disk::GetReservedFiles();
|
||||
for (const auto& device : command.devices()) {
|
||||
if (!ProcessCmd(context, device, command, true)) {
|
||||
// Dry run failed, restore the file list
|
||||
FileSupport::SetReservedFiles(reserved_files);
|
||||
Disk::SetReservedFiles(reserved_files);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Restore the list of reserved files before proceeding
|
||||
FileSupport::SetReservedFiles(reserved_files);
|
||||
Disk::SetReservedFiles(reserved_files);
|
||||
|
||||
if (string result = ValidateLunSetup(command); !result.empty()) {
|
||||
if (const string result = ValidateLunSetup(command); !result.empty()) {
|
||||
return context.ReturnStatus(false, result);
|
||||
}
|
||||
|
||||
@ -283,7 +282,7 @@ bool RascsiExecutor::Attach(const CommandContext& context, const PbDeviceDefinit
|
||||
return context.ReturnLocalizedError(LocalizationKey::ERROR_RESERVED_ID, to_string(id));
|
||||
}
|
||||
|
||||
string filename = GetParam(pb_device, "file");
|
||||
const string filename = GetParam(pb_device, "file");
|
||||
|
||||
auto device = CreateDevice(context, type, lun, filename);
|
||||
if (device == nullptr) {
|
||||
@ -291,8 +290,8 @@ bool RascsiExecutor::Attach(const CommandContext& context, const PbDeviceDefinit
|
||||
}
|
||||
|
||||
// If no filename was provided the medium is considered removed
|
||||
auto file_support = dynamic_cast<FileSupport *>(device.get());
|
||||
device->SetRemoved(file_support != nullptr ? filename.empty() : false);
|
||||
auto disk = dynamic_pointer_cast<Disk>(device);
|
||||
device->SetRemoved(disk != nullptr ? filename.empty() : false);
|
||||
|
||||
if (!SetProductData(context, pb_device, device)) {
|
||||
return false;
|
||||
@ -303,8 +302,8 @@ bool RascsiExecutor::Attach(const CommandContext& context, const PbDeviceDefinit
|
||||
}
|
||||
|
||||
string full_path;
|
||||
if (file_support != nullptr) {
|
||||
// File check (type is HD, for removable media drives, CD and MO the medium (=file) may be inserted later
|
||||
if (device->SupportsFile()) {
|
||||
// Only with removable media drives, CD and MO the medium (=file) may be inserted later
|
||||
if (!device->IsRemovable() && filename.empty()) {
|
||||
return context.ReturnLocalizedError(LocalizationKey::ERROR_MISSING_FILENAME, PbDeviceType_Name(type));
|
||||
}
|
||||
@ -341,7 +340,7 @@ bool RascsiExecutor::Attach(const CommandContext& context, const PbDeviceDefinit
|
||||
|
||||
Filepath filepath;
|
||||
filepath.SetPath(full_path.c_str());
|
||||
file_support->ReserveFile(filepath, id, lun);
|
||||
disk->ReserveFile(filepath, id, lun);
|
||||
|
||||
string msg = "Attached ";
|
||||
if (device->IsReadOnly()) {
|
||||
@ -367,7 +366,7 @@ bool RascsiExecutor::Insert(const CommandContext& context, const PbDeviceDefinit
|
||||
return context.ReturnLocalizedError(LocalizationKey::ERROR_DEVICE_NAME_UPDATE);
|
||||
}
|
||||
|
||||
string filename = GetParam(pb_device, "file");
|
||||
const string filename = GetParam(pb_device, "file");
|
||||
if (filename.empty()) {
|
||||
return context.ReturnLocalizedError(LocalizationKey::ERROR_MISSING_FILENAME);
|
||||
}
|
||||
@ -390,7 +389,7 @@ bool RascsiExecutor::Insert(const CommandContext& context, const PbDeviceDefinit
|
||||
|
||||
Filepath filepath;
|
||||
filepath.SetPath(full_path.c_str());
|
||||
dynamic_pointer_cast<FileSupport>(device)->ReserveFile(filepath, device->GetId(), device->GetLun());
|
||||
dynamic_pointer_cast<Disk>(device)->ReserveFile(filepath, device->GetId(), device->GetLun());
|
||||
|
||||
// Only non read-only devices support protect/unprotect.
|
||||
// This operation must not be executed before Open() because Open() overrides some settings.
|
||||
@ -407,31 +406,32 @@ bool RascsiExecutor::Insert(const CommandContext& context, const PbDeviceDefinit
|
||||
|
||||
bool RascsiExecutor::Detach(const CommandContext& context, shared_ptr<PrimaryDevice> device, bool dryRun) const
|
||||
{
|
||||
auto controller = controller_manager.FindController(device->GetId());
|
||||
if (controller == nullptr) {
|
||||
return context.ReturnLocalizedError(LocalizationKey::ERROR_DETACH);
|
||||
}
|
||||
|
||||
// LUN 0 can only be detached if there is no other LUN anymore
|
||||
if (!device->GetLun() && controller_manager.FindController(device->GetId())->GetLunCount() > 1) {
|
||||
if (!device->GetLun() && controller->GetLunCount() > 1) {
|
||||
return context.ReturnLocalizedError(LocalizationKey::ERROR_LUN0);
|
||||
}
|
||||
|
||||
if (!dryRun) {
|
||||
// Prepare log string before the device data are lost due to deletion
|
||||
string s = "Detached " + device->GetType() + " device with ID " + to_string(device->GetId())
|
||||
+ ", unit " + to_string(device->GetLun());
|
||||
|
||||
if (auto file_support = dynamic_pointer_cast<FileSupport>(device); file_support != nullptr) {
|
||||
file_support->UnreserveFile();
|
||||
}
|
||||
|
||||
auto controller = controller_manager.FindController(device->GetId());
|
||||
if (controller == nullptr || !controller->DeleteDevice(device)) {
|
||||
if (!controller->DeleteDevice(device)) {
|
||||
return context.ReturnLocalizedError(LocalizationKey::ERROR_DETACH);
|
||||
}
|
||||
|
||||
// If no LUN is left also delete the controller
|
||||
if (!controller->GetLunCount()) {
|
||||
controller_manager.DeleteController(controller);
|
||||
if (!controller->GetLunCount() && !controller_manager.DeleteController(controller)) {
|
||||
return context.ReturnLocalizedError(LocalizationKey::ERROR_DETACH);
|
||||
}
|
||||
|
||||
LOGINFO("%s", s.c_str())
|
||||
if (auto disk = dynamic_pointer_cast<Disk>(device); disk != nullptr) {
|
||||
disk->UnreserveFile();
|
||||
}
|
||||
|
||||
LOGINFO("%s", ("Detached " + device->GetType() + " device with ID " + to_string(device->GetId())
|
||||
+ ", unit " + to_string(device->GetLun())).c_str())
|
||||
}
|
||||
|
||||
return true;
|
||||
@ -440,7 +440,7 @@ bool RascsiExecutor::Detach(const CommandContext& context, shared_ptr<PrimaryDev
|
||||
void RascsiExecutor::DetachAll()
|
||||
{
|
||||
controller_manager.DeleteAllControllers();
|
||||
FileSupport::UnreserveAll();
|
||||
Disk::UnreserveAll();
|
||||
|
||||
LOGINFO("Detached all devices")
|
||||
}
|
||||
@ -511,7 +511,7 @@ string RascsiExecutor::SetReservedIds(string_view ids)
|
||||
}
|
||||
|
||||
unordered_set<int> reserved;
|
||||
for (string id_to_reserve : ids_to_reserve) {
|
||||
for (const string& id_to_reserve : ids_to_reserve) {
|
||||
int res_id;
|
||||
if (!GetAsInt(id_to_reserve, res_id) || res_id > 7) {
|
||||
return "Invalid ID " + id_to_reserve;
|
||||
@ -549,8 +549,12 @@ string RascsiExecutor::SetReservedIds(string_view ids)
|
||||
bool RascsiExecutor::ValidateImageFile(const CommandContext& context, shared_ptr<PrimaryDevice> device,
|
||||
const string& filename, string& full_path) const
|
||||
{
|
||||
auto file_support = dynamic_pointer_cast<FileSupport>(device);
|
||||
if (file_support == nullptr || filename.empty()) {
|
||||
if (!device->SupportsFile()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
auto disk = dynamic_pointer_cast<Disk>(device);
|
||||
if (disk == nullptr || filename.empty()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -559,7 +563,7 @@ bool RascsiExecutor::ValidateImageFile(const CommandContext& context, shared_ptr
|
||||
Filepath filepath;
|
||||
filepath.SetPath(filename.c_str());
|
||||
|
||||
if (FileSupport::GetIdsForReservedFile(filepath, id, lun)) {
|
||||
if (Disk::GetIdsForReservedFile(filepath, id, lun)) {
|
||||
return context.ReturnLocalizedError(LocalizationKey::ERROR_IMAGE_IN_USE, filename,
|
||||
to_string(id), to_string(lun));
|
||||
}
|
||||
@ -567,16 +571,16 @@ bool RascsiExecutor::ValidateImageFile(const CommandContext& context, shared_ptr
|
||||
string initial_filename = filepath.GetPath();
|
||||
|
||||
try {
|
||||
if (!file_support->FileExists(filepath)) {
|
||||
if (!disk->FileExists(filepath)) {
|
||||
// If the file does not exist search for it in the default image folder
|
||||
filepath.SetPath((rascsi_image.GetDefaultFolder() + "/" + filename).c_str());
|
||||
|
||||
if (FileSupport::GetIdsForReservedFile(filepath, id, lun)) {
|
||||
if (Disk::GetIdsForReservedFile(filepath, id, lun)) {
|
||||
return context.ReturnLocalizedError(LocalizationKey::ERROR_IMAGE_IN_USE, filename,
|
||||
to_string(id), to_string(lun));
|
||||
}
|
||||
|
||||
file_support->Open(filepath);
|
||||
disk->Open(filepath);
|
||||
}
|
||||
}
|
||||
catch(const io_exception& e) {
|
||||
@ -645,7 +649,7 @@ string RascsiExecutor::ValidateLunSetup(const PbCommand& command) const
|
||||
}
|
||||
|
||||
// LUN 0 must exist for all devices
|
||||
for (auto const& [id, lun]: luns) {
|
||||
for (const auto& [id, lun]: luns) {
|
||||
if (!(lun & 0x01)) {
|
||||
return "LUN 0 is missing for device ID " + to_string(id);
|
||||
}
|
||||
|
@ -12,8 +12,8 @@
|
||||
#include "log.h"
|
||||
#include "filepath.h"
|
||||
#include "spdlog/spdlog.h"
|
||||
#include "devices/file_support.h"
|
||||
#include "command_util.h"
|
||||
#include "devices/disk.h"
|
||||
#include "protobuf_util.h"
|
||||
#include "command_context.h"
|
||||
#include "rascsi_image.h"
|
||||
#include <string>
|
||||
@ -26,7 +26,7 @@
|
||||
using namespace std;
|
||||
using namespace spdlog;
|
||||
using namespace rascsi_interface;
|
||||
using namespace command_util;
|
||||
using namespace protobuf_util;
|
||||
|
||||
RascsiImage::RascsiImage()
|
||||
{
|
||||
@ -41,8 +41,8 @@ bool RascsiImage::CheckDepth(string_view filename) const
|
||||
|
||||
bool RascsiImage::CreateImageFolder(const CommandContext& context, const string& filename) const
|
||||
{
|
||||
if (size_t filename_start = filename.rfind('/'); filename_start != string::npos) {
|
||||
string folder = filename.substr(0, filename_start);
|
||||
if (const size_t filename_start = filename.rfind('/'); filename_start != string::npos) {
|
||||
const string folder = filename.substr(0, filename_start);
|
||||
|
||||
// Checking for existence first prevents an error if the top-level folder is a softlink
|
||||
if (struct stat st; stat(folder.c_str(), &st)) {
|
||||
@ -105,7 +105,7 @@ bool RascsiImage::IsValidDstFilename(const string& filename) const
|
||||
|
||||
bool RascsiImage::CreateImage(const CommandContext& context, const PbCommand& command) const
|
||||
{
|
||||
string filename = GetParam(command, "file");
|
||||
const string filename = GetParam(command, "file");
|
||||
if (filename.empty()) {
|
||||
return context.ReturnStatus(false, "Can't create image file: Missing image filename");
|
||||
}
|
||||
@ -114,7 +114,7 @@ bool RascsiImage::CreateImage(const CommandContext& context, const PbCommand& co
|
||||
return context.ReturnStatus(false, ("Invalid folder hierarchy depth '" + filename + "'").c_str());
|
||||
}
|
||||
|
||||
string full_filename = GetFullName(filename);
|
||||
const string full_filename = GetFullName(filename);
|
||||
if (!IsValidDstFilename(full_filename)) {
|
||||
return context.ReturnStatus(false, "Can't create image file: '" + full_filename + "': File already exists");
|
||||
}
|
||||
@ -142,12 +142,12 @@ bool RascsiImage::CreateImage(const CommandContext& context, const PbCommand& co
|
||||
return false;
|
||||
}
|
||||
|
||||
string permission = GetParam(command, "read_only");
|
||||
const string permission = GetParam(command, "read_only");
|
||||
// Since rascsi is running as root ensure that others can access the file
|
||||
int permissions = !strcasecmp(permission.c_str(), "true") ?
|
||||
const int permissions = !strcasecmp(permission.c_str(), "true") ?
|
||||
S_IRUSR | S_IRGRP | S_IROTH : S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH;
|
||||
|
||||
int image_fd = open(full_filename.c_str(), O_CREAT|O_WRONLY, permissions);
|
||||
const int image_fd = open(full_filename.c_str(), O_CREAT|O_WRONLY, permissions);
|
||||
if (image_fd == -1) {
|
||||
return context.ReturnStatus(false, "Can't create image file '" + full_filename + "': " + string(strerror(errno)));
|
||||
}
|
||||
@ -178,7 +178,7 @@ bool RascsiImage::CreateImage(const CommandContext& context, const PbCommand& co
|
||||
|
||||
bool RascsiImage::DeleteImage(const CommandContext& context, const PbCommand& command) const
|
||||
{
|
||||
string filename = GetParam(command, "file");
|
||||
const string filename = GetParam(command, "file");
|
||||
if (filename.empty()) {
|
||||
return context.ReturnStatus(false, "Missing image filename");
|
||||
}
|
||||
@ -187,13 +187,13 @@ bool RascsiImage::DeleteImage(const CommandContext& context, const PbCommand& co
|
||||
return context.ReturnStatus(false, ("Invalid folder hierarchy depth '" + filename + "'").c_str());
|
||||
}
|
||||
|
||||
string full_filename = GetFullName(filename);
|
||||
const string full_filename = GetFullName(filename);
|
||||
|
||||
int id;
|
||||
int unit;
|
||||
Filepath filepath;
|
||||
filepath.SetPath(full_filename.c_str());
|
||||
if (FileSupport::GetIdsForReservedFile(filepath, id, unit)) {
|
||||
if (Disk::GetIdsForReservedFile(filepath, id, unit)) {
|
||||
return context.ReturnStatus(false, "Can't delete image file '" + full_filename +
|
||||
"', it is currently being used by device ID " + to_string(id) + ", unit " + to_string(unit));
|
||||
}
|
||||
@ -273,17 +273,17 @@ bool RascsiImage::CopyImage(const CommandContext& context, const PbCommand& comm
|
||||
return context.ReturnStatus();
|
||||
}
|
||||
|
||||
int fd_src = open(from.c_str(), O_RDONLY, 0);
|
||||
const int fd_src = open(from.c_str(), O_RDONLY, 0);
|
||||
if (fd_src == -1) {
|
||||
return context.ReturnStatus(false, "Can't open source image file '" + from + "': " + string(strerror(errno)));
|
||||
}
|
||||
|
||||
string permission = GetParam(command, "read_only");
|
||||
const string permission = GetParam(command, "read_only");
|
||||
// Since rascsi is running as root ensure that others can access the file
|
||||
int permissions = !strcasecmp(permission.c_str(), "true") ?
|
||||
const int permissions = !strcasecmp(permission.c_str(), "true") ?
|
||||
S_IRUSR | S_IRGRP | S_IROTH : S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH;
|
||||
|
||||
int fd_dst = open(to.c_str(), O_WRONLY | O_CREAT, permissions);
|
||||
const int fd_dst = open(to.c_str(), O_WRONLY | O_CREAT, permissions);
|
||||
if (fd_dst == -1) {
|
||||
close(fd_src);
|
||||
|
||||
@ -334,9 +334,9 @@ bool RascsiImage::SetImagePermissions(const CommandContext& context, const PbCom
|
||||
return context.ReturnStatus(false, "Can't modify image file '" + filename + "': Invalid name or type");
|
||||
}
|
||||
|
||||
bool protect = command.operation() == PROTECT_IMAGE;
|
||||
const bool protect = command.operation() == PROTECT_IMAGE;
|
||||
|
||||
if (int permissions = protect ? S_IRUSR | S_IRGRP | S_IROTH : S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH;
|
||||
if (const int permissions = protect ? S_IRUSR | S_IRGRP | S_IROTH : S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH;
|
||||
chmod(filename.c_str(), permissions) == -1) {
|
||||
return context.ReturnStatus(false, "Can't " + string(protect ? "protect" : "unprotect") + " image file '" + filename + "': " +
|
||||
strerror(errno));
|
||||
|
@ -8,16 +8,15 @@
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
#include "controllers/controller_manager.h"
|
||||
#include "devices/file_support.h"
|
||||
#include "devices/disk.h"
|
||||
#include "devices/device_factory.h"
|
||||
#include "command_util.h"
|
||||
#include "protobuf_util.h"
|
||||
#include "rascsi_version.h"
|
||||
#include "rascsi_interface.pb.h"
|
||||
#include "rascsi_response.h"
|
||||
|
||||
using namespace rascsi_interface;
|
||||
using namespace command_util;
|
||||
using namespace protobuf_util;
|
||||
|
||||
unique_ptr<PbDeviceProperties> RascsiResponse::GetDeviceProperties(const Device& device) const
|
||||
{
|
||||
@ -29,7 +28,7 @@ unique_ptr<PbDeviceProperties> RascsiResponse::GetDeviceProperties(const Device&
|
||||
properties->set_stoppable(device.IsStoppable());
|
||||
properties->set_removable(device.IsRemovable());
|
||||
properties->set_lockable(device.IsLockable());
|
||||
properties->set_supports_file(dynamic_cast<const FileSupport *>(&device) != nullptr);
|
||||
properties->set_supports_file(device.SupportsFile());
|
||||
properties->set_supports_params(device.SupportsParams());
|
||||
|
||||
PbDeviceType t = UNDEFINED;
|
||||
@ -53,7 +52,7 @@ void RascsiResponse::GetDeviceTypeProperties(PbDeviceTypesInfo& device_types_inf
|
||||
{
|
||||
auto type_properties = device_types_info.add_properties();
|
||||
type_properties->set_type(type);
|
||||
auto device = device_factory.CreateDevice(controller_manager, type, 0, "");
|
||||
const auto device = device_factory.CreateDevice(controller_manager, type, 0, "");
|
||||
type_properties->set_allocated_properties(GetDeviceProperties(*device).release());
|
||||
} //NOSONAR The allocated memory is managed by protobuf
|
||||
|
||||
@ -101,10 +100,10 @@ void RascsiResponse::GetDevice(const Device& device, PbDevice& pb_device, const
|
||||
pb_device.set_block_count(device.IsRemoved() ? 0: disk->GetBlockCount());
|
||||
}
|
||||
|
||||
const auto file_support = dynamic_cast<const FileSupport *>(&device);
|
||||
if (file_support) {
|
||||
const auto disk = dynamic_cast<const Disk *>(&device);
|
||||
if (disk != nullptr) {
|
||||
Filepath filepath;
|
||||
file_support->GetPath(filepath);
|
||||
disk->GetPath(filepath);
|
||||
auto image_file = make_unique<PbImageFile>().release();
|
||||
GetImageFile(*image_file, default_folder, device.IsRemovable() && !device.IsReady() ? "" : filepath.GetPath());
|
||||
pb_device.set_allocated_file(image_file);
|
||||
@ -117,7 +116,7 @@ bool RascsiResponse::GetImageFile(PbImageFile& image_file, const string& default
|
||||
image_file.set_name(filename);
|
||||
image_file.set_type(device_factory.GetTypeForFile(filename));
|
||||
|
||||
string f = filename[0] == '/' ? filename : default_folder + "/" + filename;
|
||||
const string f = filename[0] == '/' ? filename : default_folder + "/" + filename;
|
||||
|
||||
image_file.set_read_only(access(f.c_str(), W_OK));
|
||||
|
||||
@ -209,7 +208,7 @@ void RascsiResponse::GetAvailableImages(PbResult& result, PbServerInfo& server_i
|
||||
unique_ptr<PbReservedIdsInfo> RascsiResponse::GetReservedIds(PbResult& result, const unordered_set<int>& ids) const
|
||||
{
|
||||
auto reserved_ids_info = make_unique<PbReservedIdsInfo>();
|
||||
for (int id : ids) {
|
||||
for (const int id : ids) {
|
||||
reserved_ids_info->add_ids(id);
|
||||
}
|
||||
|
||||
@ -533,14 +532,14 @@ string RascsiResponse::GetNextImageFile(const dirent *dir, const string& folder)
|
||||
return "";
|
||||
}
|
||||
|
||||
string filename = folder + "/" + dir->d_name;
|
||||
const string filename = folder + "/" + dir->d_name;
|
||||
|
||||
struct stat st;
|
||||
|
||||
bool file_exists = !stat(filename.c_str(), &st);
|
||||
const bool file_exists = !stat(filename.c_str(), &st);
|
||||
|
||||
if (dir->d_type == DT_REG && file_exists && !st.st_size) {
|
||||
LOGWARN("File '%s' in image folder '%s' has a size of 0 bytes", dir->d_name, folder.c_str())
|
||||
LOGWARN("File '%s' in image folder '%s' is empty", dir->d_name, folder.c_str())
|
||||
return "";
|
||||
}
|
||||
|
||||
|
@ -77,7 +77,7 @@ void RascsiService::Execute() const
|
||||
ras_util::FixCpu(2);
|
||||
|
||||
// Wait for the execution to start
|
||||
timespec ts = { .tv_sec = 0, .tv_nsec = 1000};
|
||||
const timespec ts = { .tv_sec = 0, .tv_nsec = 1000};
|
||||
while (!running) {
|
||||
nanosleep(&ts, nullptr);
|
||||
}
|
||||
@ -109,7 +109,7 @@ PbCommand RascsiService::ReadCommand(CommandContext& context) const
|
||||
// Wait for connection
|
||||
sockaddr client = {};
|
||||
socklen_t socklen = sizeof(client);
|
||||
int fd = accept(service_socket, &client, &socklen);
|
||||
const int fd = accept(service_socket, &client, &socklen);
|
||||
if (fd == -1) {
|
||||
throw io_exception("accept() failed");
|
||||
}
|
||||
@ -118,7 +118,7 @@ PbCommand RascsiService::ReadCommand(CommandContext& context) const
|
||||
|
||||
// Read magic string
|
||||
vector<byte> magic(6);
|
||||
if (size_t bytes_read = context.GetSerializer().ReadBytes(fd, magic);
|
||||
if (const size_t bytes_read = context.GetSerializer().ReadBytes(fd, magic);
|
||||
bytes_read != magic.size() || memcmp(magic.data(), "RASCSI", magic.size())) {
|
||||
throw io_exception("Invalid magic");
|
||||
}
|
||||
|
@ -30,7 +30,7 @@ class file_not_found_exception : public io_exception
|
||||
using io_exception::io_exception;
|
||||
};
|
||||
|
||||
class scsi_error_exception final : public std::exception
|
||||
class scsi_exception : public std::exception
|
||||
{
|
||||
scsi_defs::sense_key sense_key;
|
||||
scsi_defs::asc asc;
|
||||
@ -38,11 +38,11 @@ class scsi_error_exception final : public std::exception
|
||||
|
||||
public:
|
||||
|
||||
scsi_error_exception(scsi_defs::sense_key sense_key = scsi_defs::sense_key::ABORTED_COMMAND,
|
||||
scsi_exception(scsi_defs::sense_key sense_key = scsi_defs::sense_key::ABORTED_COMMAND,
|
||||
scsi_defs::asc asc = scsi_defs::asc::NO_ADDITIONAL_SENSE_INFORMATION,
|
||||
scsi_defs::status status = scsi_defs::status::CHECK_CONDITION)
|
||||
: sense_key(sense_key), asc(asc), status(status) {}
|
||||
~scsi_error_exception() override = default;
|
||||
~scsi_exception() override = default;
|
||||
|
||||
scsi_defs::sense_key get_sense_key() const { return sense_key; }
|
||||
scsi_defs::asc get_asc() const { return asc; }
|
||||
|
@ -23,7 +23,7 @@ string rascsi_get_version_string()
|
||||
{
|
||||
stringstream s;
|
||||
|
||||
s << setw(2) << setfill('0') << rascsi_major_version << '.' << setw(2) << setfill('0') << rascsi_minor_version;
|
||||
s << setw(2) << setfill('0') << rascsi_major_version << '.' << rascsi_minor_version;
|
||||
|
||||
if (rascsi_patch_version < 0) {
|
||||
s << " --DEVELOPMENT BUILD--";
|
||||
|
@ -10,11 +10,11 @@
|
||||
//
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
#include <unistd.h>
|
||||
#include "rascsi_version.h"
|
||||
#include "command_util.h"
|
||||
#include "protobuf_util.h"
|
||||
#include "rasutil.h"
|
||||
#include "rascsi_interface.pb.h"
|
||||
#include "rasctl/rasctl_parser.h"
|
||||
#include "rasctl/rasctl_commands.h"
|
||||
#include <unistd.h>
|
||||
#include <clocale>
|
||||
@ -27,125 +27,45 @@ static const char COMPONENT_SEPARATOR = ':';
|
||||
using namespace std;
|
||||
using namespace rascsi_interface;
|
||||
using namespace ras_util;
|
||||
using namespace command_util;
|
||||
using namespace protobuf_util;
|
||||
|
||||
PbOperation ParseOperation(const string& operation)
|
||||
void Banner(int argc, char* argv[])
|
||||
{
|
||||
switch (tolower(operation[0])) {
|
||||
case 'a':
|
||||
return ATTACH;
|
||||
if (argc < 2) {
|
||||
cout << Banner("Controller");
|
||||
|
||||
case 'd':
|
||||
return DETACH;
|
||||
cout << "\nUsage: " << argv[0] << " -i ID [-u UNIT] [-c CMD] [-C FILE] [-t TYPE] [-b BLOCK_SIZE] [-n NAME] [-f FILE|PARAM] ";
|
||||
cout << "[-F IMAGE_FOLDER] [-L LOG_LEVEL] [-h HOST] [-p PORT] [-r RESERVED_IDS] ";
|
||||
cout << "[-C FILENAME:FILESIZE] [-d FILENAME] [-w FILENAME] [-R CURRENT_NAME:NEW_NAME] ";
|
||||
cout << "[-x CURRENT_NAME:NEW_NAME] [-z LOCALE] ";
|
||||
cout << "[-e] [-E FILENAME] [-D] [-I] [-l] [-m] [o] [-O] [-P] [-s] [-v] [-V] [-y] [-X]\n";
|
||||
cout << " where ID := {0-7}\n";
|
||||
cout << " UNIT := {0-31}, default is 0\n";
|
||||
cout << " CMD := {attach|detach|insert|eject|protect|unprotect|show}\n";
|
||||
cout << " TYPE := {schd|scrm|sccd|scmo|scbr|scdp} or convenience type {hd|rm|mo|cd|bridge|daynaport}\n";
|
||||
cout << " BLOCK_SIZE := {512|1024|2048|4096) bytes per hard disk drive block\n";
|
||||
cout << " NAME := name of device to attach (VENDOR:PRODUCT:REVISION)\n";
|
||||
cout << " FILE|PARAM := image file path or device-specific parameter\n";
|
||||
cout << " IMAGE_FOLDER := default location for image files, default is '~/images'\n";
|
||||
cout << " HOST := rascsi host to connect to, default is 'localhost'\n";
|
||||
cout << " PORT := rascsi port to connect to, default is 6868\n";
|
||||
cout << " RESERVED_IDS := comma-separated list of IDs to reserve\n";
|
||||
cout << " LOG_LEVEL := log level {trace|debug|info|warn|err|critical|off}, default is 'info'\n";
|
||||
cout << " If CMD is 'attach' or 'insert' the FILE parameter is required.\n";
|
||||
cout << "Usage: " << argv[0] << " -l\n";
|
||||
cout << " Print device list.\n" << flush;
|
||||
|
||||
case 'i':
|
||||
return INSERT;
|
||||
|
||||
case 'e':
|
||||
return EJECT;
|
||||
|
||||
case 'p':
|
||||
return PROTECT;
|
||||
|
||||
case 'u':
|
||||
return UNPROTECT;
|
||||
|
||||
case 's':
|
||||
return DEVICES_INFO;
|
||||
|
||||
default:
|
||||
return NO_OPERATION;
|
||||
exit(EXIT_SUCCESS);
|
||||
}
|
||||
}
|
||||
|
||||
PbDeviceType ParseType(const char *type)
|
||||
{
|
||||
string t = type;
|
||||
transform(t.begin(), t.end(), t.begin(), ::toupper);
|
||||
|
||||
if (PbDeviceType parsed_type; PbDeviceType_Parse(t, &parsed_type)) {
|
||||
return parsed_type;
|
||||
}
|
||||
|
||||
// Parse convenience device types (shortcuts)
|
||||
switch (tolower(type[0])) {
|
||||
case 'c':
|
||||
return SCCD;
|
||||
|
||||
case 'b':
|
||||
return SCBR;
|
||||
|
||||
case 'd':
|
||||
return SCDP;
|
||||
|
||||
case 'h':
|
||||
return SCHD;
|
||||
|
||||
case 'm':
|
||||
return SCMO;
|
||||
|
||||
case 'r':
|
||||
return SCRM;
|
||||
|
||||
case 'l':
|
||||
return SCLP;
|
||||
|
||||
case 's':
|
||||
return SCHS;
|
||||
|
||||
default:
|
||||
return UNDEFINED;
|
||||
}
|
||||
}
|
||||
|
||||
void SetPatternParams(PbCommand& command, string_view patterns)
|
||||
{
|
||||
string folder_pattern;
|
||||
string file_pattern;
|
||||
if (size_t separator_pos = patterns.find(COMPONENT_SEPARATOR); separator_pos != string::npos) {
|
||||
folder_pattern = patterns.substr(0, separator_pos);
|
||||
file_pattern = patterns.substr(separator_pos + 1);
|
||||
}
|
||||
else {
|
||||
file_pattern = patterns;
|
||||
}
|
||||
|
||||
AddParam(command, "folder_pattern", folder_pattern);
|
||||
AddParam(command, "file_pattern", file_pattern);
|
||||
}
|
||||
|
||||
int main(int argc, char* argv[])
|
||||
{
|
||||
GOOGLE_PROTOBUF_VERIFY_VERSION;
|
||||
|
||||
// Display help
|
||||
if (argc < 2) {
|
||||
cerr << "SCSI Target Emulator RaSCSI Controller" << endl;
|
||||
cerr << "version " << rascsi_get_version_string() << " (" << __DATE__ << ", " << __TIME__ << ")" << endl;
|
||||
cerr << "Usage: " << argv[0] << " -i ID [-u UNIT] [-c CMD] [-C FILE] [-t TYPE] [-b BLOCK_SIZE] [-n NAME] [-f FILE|PARAM] ";
|
||||
cerr << "[-F IMAGE_FOLDER] [-L LOG_LEVEL] [-h HOST] [-p PORT] [-r RESERVED_IDS] ";
|
||||
cerr << "[-C FILENAME:FILESIZE] [-d FILENAME] [-w FILENAME] [-R CURRENT_NAME:NEW_NAME] ";
|
||||
cerr << "[-x CURRENT_NAME:NEW_NAME] [-z LOCALE] ";
|
||||
cerr << "[-e] [-E FILENAME] [-D] [-I] [-l] [-L] [-m] [o] [-O] [-P] [-s] [-v] [-V] [-y] [-X]" << endl;
|
||||
cerr << " where ID := {0-7}" << endl;
|
||||
cerr << " UNIT := {0-31}, default is 0" << endl;
|
||||
cerr << " CMD := {attach|detach|insert|eject|protect|unprotect|show}" << endl;
|
||||
cerr << " TYPE := {schd|scrm|sccd|scmo|scbr|scdp} or convenience type {hd|rm|mo|cd|bridge|daynaport}" << endl;
|
||||
cerr << " BLOCK_SIZE := {512|1024|2048|4096) bytes per hard disk drive block" << endl;
|
||||
cerr << " NAME := name of device to attach (VENDOR:PRODUCT:REVISION)" << endl;
|
||||
cerr << " FILE|PARAM := image file path or device-specific parameter" << endl;
|
||||
cerr << " IMAGE_FOLDER := default location for image files, default is '~/images'" << endl;
|
||||
cerr << " HOST := rascsi host to connect to, default is 'localhost'" << endl;
|
||||
cerr << " PORT := rascsi port to connect to, default is 6868" << endl;
|
||||
cerr << " RESERVED_IDS := comma-separated list of IDs to reserve" << endl;
|
||||
cerr << " LOG_LEVEL := log level {trace|debug|info|warn|err|critical|off}, default is 'info'" << endl;
|
||||
cerr << " If CMD is 'attach' or 'insert' the FILE parameter is required." << endl;
|
||||
cerr << "Usage: " << argv[0] << " -l" << endl;
|
||||
cerr << " Print device list." << endl;
|
||||
|
||||
exit(EXIT_SUCCESS);
|
||||
}
|
||||
Banner(argc, argv);
|
||||
|
||||
RasctlParser parser;
|
||||
PbCommand command;
|
||||
list<PbDeviceDefinition> devices;
|
||||
PbDeviceDefinition* device = command.add_devices();
|
||||
@ -205,7 +125,7 @@ int main(int argc, char* argv[])
|
||||
break;
|
||||
|
||||
case 'c':
|
||||
command.set_operation(ParseOperation(optarg));
|
||||
command.set_operation(parser.ParseOperation(optarg));
|
||||
if (command.operation() == NO_OPERATION) {
|
||||
cerr << "Error: Unknown operation '" << optarg << "'" << endl;
|
||||
exit(EXIT_FAILURE);
|
||||
@ -276,7 +196,7 @@ int main(int argc, char* argv[])
|
||||
break;
|
||||
|
||||
case 't':
|
||||
device->set_type(ParseType(optarg));
|
||||
device->set_type(parser.ParseType(optarg));
|
||||
if (device->type() == UNDEFINED) {
|
||||
cerr << "Error: Unknown device type '" << optarg << "'" << endl;
|
||||
exit(EXIT_FAILURE);
|
||||
|
@ -9,7 +9,7 @@
|
||||
|
||||
#include "rascsi_exceptions.h"
|
||||
#include "protobuf_serializer.h"
|
||||
#include "command_util.h"
|
||||
#include "protobuf_util.h"
|
||||
#include "rasutil.h"
|
||||
#include "rasctl_commands.h"
|
||||
#include "rascsi_interface.pb.h"
|
||||
@ -20,7 +20,7 @@
|
||||
|
||||
using namespace std;
|
||||
using namespace rascsi_interface;
|
||||
using namespace command_util;
|
||||
using namespace protobuf_util;
|
||||
|
||||
// Separator for the INQUIRY name components
|
||||
static const char COMPONENT_SEPARATOR = ':';
|
||||
@ -115,36 +115,25 @@ void RasctlCommands::Execute(const string& log_level, const string& default_fold
|
||||
|
||||
void RasctlCommands::SendCommand()
|
||||
{
|
||||
if (!token.empty()) {
|
||||
AddParam(command, "token", token);
|
||||
}
|
||||
AddParam(command, "token", token);
|
||||
AddParam(command, "locale", locale);
|
||||
|
||||
if (!locale.empty()) {
|
||||
AddParam(command, "locale", locale);
|
||||
}
|
||||
|
||||
// Send command
|
||||
int fd = -1;
|
||||
try {
|
||||
const hostent *host = gethostbyname(hostname.c_str());
|
||||
if (!host) {
|
||||
fd = socket(AF_INET, SOCK_STREAM, 0);
|
||||
if (fd == -1) {
|
||||
throw io_exception("Can't create socket: " + string(strerror(errno)));
|
||||
}
|
||||
|
||||
sockaddr_in server_addr = {};
|
||||
if (!ResolveHostName(hostname, &server_addr)) {
|
||||
throw io_exception("Can't resolve hostname '" + hostname + "'");
|
||||
}
|
||||
|
||||
fd = socket(AF_INET, SOCK_STREAM, 0);
|
||||
if (fd < 0) {
|
||||
throw io_exception("Can't create socket");
|
||||
}
|
||||
|
||||
sockaddr_in server = {};
|
||||
server.sin_family = AF_INET;
|
||||
server.sin_port = htons((uint16_t)port);
|
||||
server.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
|
||||
memcpy(&server.sin_addr.s_addr, host->h_addr, host->h_length);
|
||||
|
||||
if (connect(fd, (struct sockaddr *)&server, sizeof(struct sockaddr_in)) < 0) {
|
||||
throw io_exception("Can't connect to rascsi process on host '" + hostname + "', port "
|
||||
+ to_string(port));
|
||||
server_addr.sin_port = htons(uint16_t(port));
|
||||
if (connect(fd, (sockaddr *)&server_addr, sizeof(server_addr)) < 0) {
|
||||
throw io_exception("Can't connect to rascsi on host '" + hostname + "', port " + to_string(port)
|
||||
+ ": " + strerror(errno));
|
||||
}
|
||||
|
||||
if (write(fd, "RASCSI", 6) != 6) {
|
||||
@ -156,11 +145,11 @@ void RasctlCommands::SendCommand()
|
||||
catch(const io_exception& e) {
|
||||
cerr << "Error: " << e.get_msg() << endl;
|
||||
|
||||
if (fd >= 0) {
|
||||
if (fd != -1) {
|
||||
close(fd);
|
||||
}
|
||||
|
||||
exit(fd < 0 ? ENOTCONN : EXIT_FAILURE);
|
||||
exit(fd == -1 ? ENOTCONN : EXIT_FAILURE);
|
||||
}
|
||||
|
||||
// Receive result
|
||||
@ -190,7 +179,7 @@ void RasctlCommands::CommandDevicesInfo()
|
||||
{
|
||||
SendCommand();
|
||||
|
||||
rasctl_display.DisplayDevices(result.devices_info());
|
||||
cout << rasctl_display.DisplayDevicesInfo(result.devices_info()) << flush;
|
||||
}
|
||||
|
||||
void RasctlCommands::CommandLogLevel(const string& log_level)
|
||||
@ -209,7 +198,7 @@ void RasctlCommands::CommandReserveIds(const string& reserved_ids)
|
||||
|
||||
void RasctlCommands::CommandCreateImage(const string& image_params)
|
||||
{
|
||||
if (size_t separator_pos = image_params.find(COMPONENT_SEPARATOR); separator_pos != string::npos) {
|
||||
if (const size_t separator_pos = image_params.find(COMPONENT_SEPARATOR); separator_pos != string::npos) {
|
||||
AddParam(command, "file", string_view(image_params).substr(0, separator_pos));
|
||||
AddParam(command, "size", string_view(image_params).substr(separator_pos + 1));
|
||||
}
|
||||
@ -232,7 +221,7 @@ void RasctlCommands::CommandDeleteImage(const string& filename)
|
||||
|
||||
void RasctlCommands::CommandRenameImage(const string& image_params)
|
||||
{
|
||||
if (size_t separator_pos = image_params.find(COMPONENT_SEPARATOR); separator_pos != string::npos) {
|
||||
if (const size_t separator_pos = image_params.find(COMPONENT_SEPARATOR); separator_pos != string::npos) {
|
||||
AddParam(command, "from", string_view(image_params).substr(0, separator_pos));
|
||||
AddParam(command, "to", string_view(image_params).substr(separator_pos + 1));
|
||||
}
|
||||
@ -246,7 +235,7 @@ void RasctlCommands::CommandRenameImage(const string& image_params)
|
||||
|
||||
void RasctlCommands::CommandCopyImage(const string& image_params)
|
||||
{
|
||||
if (size_t separator_pos = image_params.find(COMPONENT_SEPARATOR); separator_pos != string::npos) {
|
||||
if (const size_t separator_pos = image_params.find(COMPONENT_SEPARATOR); separator_pos != string::npos) {
|
||||
AddParam(command, "from", string_view(image_params).substr(0, separator_pos));
|
||||
AddParam(command, "to", string_view(image_params).substr(separator_pos + 1));
|
||||
}
|
||||
@ -270,22 +259,24 @@ void RasctlCommands::CommandDeviceInfo()
|
||||
SendCommand();
|
||||
|
||||
for (const auto& device : result.devices_info().devices()) {
|
||||
rasctl_display.DisplayDeviceInfo(device);
|
||||
cout << rasctl_display.DisplayDeviceInfo(device);
|
||||
}
|
||||
|
||||
cout << flush;
|
||||
}
|
||||
|
||||
void RasctlCommands::CommandDeviceTypesInfo()
|
||||
{
|
||||
SendCommand();
|
||||
|
||||
rasctl_display.DisplayDeviceTypesInfo(result.device_types_info());
|
||||
cout << rasctl_display.DisplayDeviceTypesInfo(result.device_types_info()) << flush;
|
||||
}
|
||||
|
||||
void RasctlCommands::CommandVersionInfo()
|
||||
{
|
||||
SendCommand();
|
||||
|
||||
rasctl_display.DisplayVersionInfo(result.version_info());
|
||||
cout << rasctl_display.DisplayVersionInfo(result.version_info()) << flush;
|
||||
}
|
||||
|
||||
void RasctlCommands::CommandServerInfo()
|
||||
@ -294,32 +285,34 @@ void RasctlCommands::CommandServerInfo()
|
||||
|
||||
PbServerInfo server_info = result.server_info();
|
||||
|
||||
rasctl_display.DisplayVersionInfo(server_info.version_info());
|
||||
rasctl_display.DisplayLogLevelInfo(server_info.log_level_info());
|
||||
rasctl_display.DisplayImageFiles(server_info.image_files_info());
|
||||
rasctl_display.DisplayMappingInfo(server_info.mapping_info());
|
||||
rasctl_display.DisplayNetworkInterfaces(server_info.network_interfaces_info());
|
||||
rasctl_display.DisplayDeviceTypesInfo(server_info.device_types_info());
|
||||
rasctl_display.DisplayReservedIdsInfo(server_info.reserved_ids_info());
|
||||
rasctl_display.DisplayOperationInfo(server_info.operation_info());
|
||||
cout << rasctl_display.DisplayVersionInfo(server_info.version_info());
|
||||
cout << rasctl_display.DisplayLogLevelInfo(server_info.log_level_info());
|
||||
cout << rasctl_display.DisplayImageFilesInfo(server_info.image_files_info());
|
||||
cout << rasctl_display.DisplayMappingInfo(server_info.mapping_info());
|
||||
cout << rasctl_display.DisplayNetworkInterfaces(server_info.network_interfaces_info());
|
||||
cout << rasctl_display.DisplayDeviceTypesInfo(server_info.device_types_info());
|
||||
cout << rasctl_display.DisplayReservedIdsInfo(server_info.reserved_ids_info());
|
||||
cout << rasctl_display.DisplayOperationInfo(server_info.operation_info());
|
||||
|
||||
if (server_info.devices_info().devices_size()) {
|
||||
list<PbDevice> sorted_devices = { server_info.devices_info().devices().begin(), server_info.devices_info().devices().end() };
|
||||
sorted_devices.sort([](const auto& a, const auto& b) { return a.id() < b.id() || a.unit() < b.unit(); });
|
||||
|
||||
cout << "Attached devices:" << endl;
|
||||
cout << "Attached devices:\n";
|
||||
|
||||
for (const auto& device : sorted_devices) {
|
||||
rasctl_display.DisplayDeviceInfo(device);
|
||||
cout << rasctl_display.DisplayDeviceInfo(device);
|
||||
}
|
||||
}
|
||||
|
||||
cout << flush;
|
||||
}
|
||||
|
||||
void RasctlCommands::CommandDefaultImageFilesInfo()
|
||||
{
|
||||
SendCommand();
|
||||
|
||||
rasctl_display.DisplayImageFiles(result.image_files_info());
|
||||
cout << rasctl_display.DisplayImageFilesInfo(result.image_files_info()) << flush;
|
||||
}
|
||||
|
||||
void RasctlCommands::CommandImageFileInfo(const string& filename)
|
||||
@ -328,40 +321,55 @@ void RasctlCommands::CommandImageFileInfo(const string& filename)
|
||||
|
||||
SendCommand();
|
||||
|
||||
rasctl_display.DisplayImageFile(result.image_file_info());
|
||||
cout << rasctl_display.DisplayImageFile(result.image_file_info()) << flush;
|
||||
}
|
||||
|
||||
void RasctlCommands::CommandNetworkInterfacesInfo()
|
||||
{
|
||||
SendCommand();
|
||||
|
||||
rasctl_display.DisplayNetworkInterfaces(result.network_interfaces_info());
|
||||
cout << rasctl_display.DisplayNetworkInterfaces(result.network_interfaces_info()) << flush;
|
||||
}
|
||||
|
||||
void RasctlCommands::CommandLogLevelInfo()
|
||||
{
|
||||
SendCommand();
|
||||
|
||||
rasctl_display.DisplayLogLevelInfo(result.log_level_info());
|
||||
cout << rasctl_display.DisplayLogLevelInfo(result.log_level_info()) << flush;
|
||||
}
|
||||
|
||||
void RasctlCommands::CommandReservedIdsInfo()
|
||||
{
|
||||
SendCommand();
|
||||
|
||||
rasctl_display.DisplayReservedIdsInfo(result.reserved_ids_info());
|
||||
cout << rasctl_display.DisplayReservedIdsInfo(result.reserved_ids_info()) << flush;
|
||||
}
|
||||
|
||||
void RasctlCommands::CommandMappingInfo()
|
||||
{
|
||||
SendCommand();
|
||||
|
||||
rasctl_display.DisplayMappingInfo(result.mapping_info());
|
||||
cout << rasctl_display.DisplayMappingInfo(result.mapping_info()) << flush;
|
||||
}
|
||||
|
||||
void RasctlCommands::CommandOperationInfo()
|
||||
{
|
||||
SendCommand();
|
||||
|
||||
rasctl_display.DisplayOperationInfo(result.operation_info());
|
||||
cout << rasctl_display.DisplayOperationInfo(result.operation_info()) << flush;
|
||||
}
|
||||
|
||||
bool RasctlCommands::ResolveHostName(const string& host, sockaddr_in *addr)
|
||||
{
|
||||
addrinfo hints = {};
|
||||
hints.ai_family = AF_INET;
|
||||
hints.ai_socktype = SOCK_STREAM;
|
||||
|
||||
if (addrinfo *result; !getaddrinfo(host.c_str(), nullptr, &hints, &result)) {
|
||||
*addr = *(sockaddr_in *)(result->ai_addr);
|
||||
freeaddrinfo(result);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
@ -3,7 +3,7 @@
|
||||
// SCSI Target Emulator RaSCSI Reloaded
|
||||
// for Raspberry Pi
|
||||
//
|
||||
// Copyright (C) 2021 Uwe Seimet
|
||||
// Copyright (C) 2021-2022 Uwe Seimet
|
||||
//
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
@ -12,6 +12,7 @@
|
||||
#include "protobuf_serializer.h"
|
||||
#include "rascsi_interface.pb.h"
|
||||
#include "rasctl_display.h"
|
||||
#include <netdb.h>
|
||||
#include <string>
|
||||
|
||||
using namespace rascsi_interface;
|
||||
@ -49,6 +50,8 @@ private:
|
||||
void CommandOperationInfo();
|
||||
void SendCommand();
|
||||
|
||||
static bool ResolveHostName(const string&, sockaddr_in *);
|
||||
|
||||
ProtobufSerializer serializer;
|
||||
PbCommand command;
|
||||
string hostname;
|
||||
|
@ -10,274 +10,282 @@
|
||||
#include "rascsi_interface.pb.h"
|
||||
#include "rasutil.h"
|
||||
#include "rasctl_display.h"
|
||||
#include <iostream>
|
||||
#include <sstream>
|
||||
#include <list>
|
||||
#include <iomanip>
|
||||
|
||||
using namespace std;
|
||||
using namespace rascsi_interface;
|
||||
using namespace ras_util;
|
||||
|
||||
void RasctlDisplay::DisplayDevices(const PbDevicesInfo& devices_info) const
|
||||
string RasctlDisplay::DisplayDevicesInfo(const PbDevicesInfo& devices_info) const
|
||||
{
|
||||
ostringstream s;
|
||||
|
||||
const list<PbDevice>& devices = { devices_info.devices().begin(), devices_info.devices().end() };
|
||||
cout << ListDevices(devices) << endl;
|
||||
|
||||
s << ListDevices(devices);
|
||||
|
||||
return s.str();
|
||||
}
|
||||
|
||||
void RasctlDisplay::DisplayDeviceInfo(const PbDevice& pb_device) const
|
||||
string RasctlDisplay::DisplayDeviceInfo(const PbDevice& pb_device) const
|
||||
{
|
||||
cout << " " << pb_device.id() << ":" << pb_device.unit() << " " << PbDeviceType_Name(pb_device.type())
|
||||
ostringstream s;
|
||||
|
||||
s << " " << pb_device.id() << ":" << pb_device.unit() << " " << PbDeviceType_Name(pb_device.type())
|
||||
<< " " << pb_device.vendor() << ":" << pb_device.product() << ":" << pb_device.revision();
|
||||
|
||||
if (pb_device.block_size()) {
|
||||
cout << " " << pb_device.block_size() << " bytes per sector";
|
||||
s << " " << pb_device.block_size() << " bytes per sector";
|
||||
|
||||
if (pb_device.block_count()) {
|
||||
cout << " " << pb_device.block_size() * pb_device.block_count() << " bytes capacity";
|
||||
s << " " << pb_device.block_size() * pb_device.block_count() << " bytes capacity";
|
||||
}
|
||||
}
|
||||
|
||||
if (pb_device.properties().supports_file() && !pb_device.file().name().empty()) {
|
||||
cout << " " << pb_device.file().name();
|
||||
s << " " << pb_device.file().name();
|
||||
}
|
||||
|
||||
cout << " ";
|
||||
s << " ";
|
||||
|
||||
bool hasProperty = false;
|
||||
|
||||
if (pb_device.properties().read_only()) {
|
||||
cout << "read-only";
|
||||
s << "read-only";
|
||||
hasProperty = true;
|
||||
}
|
||||
|
||||
if (pb_device.properties().protectable() && pb_device.status().protected_()) {
|
||||
if (hasProperty) {
|
||||
cout << ", ";
|
||||
s << ", ";
|
||||
}
|
||||
cout << "protected";
|
||||
s << "protected";
|
||||
hasProperty = true;
|
||||
}
|
||||
|
||||
if (pb_device.properties().stoppable() && pb_device.status().stopped()) {
|
||||
if (hasProperty) {
|
||||
cout << ", ";
|
||||
s << ", ";
|
||||
}
|
||||
cout << "stopped";
|
||||
s << "stopped";
|
||||
hasProperty = true;
|
||||
}
|
||||
|
||||
if (pb_device.properties().removable() && pb_device.status().removed()) {
|
||||
if (hasProperty) {
|
||||
cout << ", ";
|
||||
s << ", ";
|
||||
}
|
||||
cout << "removed";
|
||||
s << "removed";
|
||||
hasProperty = true;
|
||||
}
|
||||
|
||||
if (pb_device.properties().lockable() && pb_device.status().locked()) {
|
||||
if (hasProperty) {
|
||||
cout << ", ";
|
||||
s << ", ";
|
||||
}
|
||||
cout << "locked";
|
||||
s << "locked";
|
||||
}
|
||||
|
||||
if (hasProperty) {
|
||||
cout << " ";
|
||||
s << " ";
|
||||
}
|
||||
|
||||
// Creates a sorted map
|
||||
map<string, string> params = { pb_device.params().begin(), pb_device.params().end() };
|
||||
bool isFirst = true;
|
||||
for (const auto& [key, value] : params) {
|
||||
if (!isFirst) {
|
||||
cout << ":";
|
||||
}
|
||||
isFirst = false;
|
||||
cout << key << "=" << value;
|
||||
}
|
||||
DisplayParams(s, pb_device);
|
||||
|
||||
cout << endl;
|
||||
s << '\n';
|
||||
|
||||
return s.str();
|
||||
}
|
||||
|
||||
void RasctlDisplay::DisplayVersionInfo(const PbVersionInfo& version_info) const
|
||||
string RasctlDisplay::DisplayVersionInfo(const PbVersionInfo& version_info) const
|
||||
{
|
||||
cout << "rascsi server version: " << version_info.major_version() << "." << version_info.minor_version();
|
||||
ostringstream s;
|
||||
|
||||
s << "rascsi server version: " << setw(2) << setfill('0') << version_info.major_version() << "."
|
||||
<< setw(2) << setfill('0') << version_info.minor_version();
|
||||
|
||||
if (version_info.patch_version() > 0) {
|
||||
cout << "." << version_info.patch_version();
|
||||
s << "." << version_info.patch_version();
|
||||
}
|
||||
else if (version_info.patch_version() < 0) {
|
||||
cout << " (development version)";
|
||||
s << " (development version)";
|
||||
}
|
||||
cout << endl;
|
||||
|
||||
s << '\n';
|
||||
|
||||
return s.str();
|
||||
}
|
||||
|
||||
void RasctlDisplay::DisplayLogLevelInfo(const PbLogLevelInfo& log_level_info) const
|
||||
string RasctlDisplay::DisplayLogLevelInfo(const PbLogLevelInfo& log_level_info) const
|
||||
{
|
||||
ostringstream s;
|
||||
|
||||
if (!log_level_info.log_levels_size()) {
|
||||
cout << " No log level settings available" << endl;
|
||||
s << " No log level settings available\n";
|
||||
}
|
||||
else {
|
||||
cout << "rascsi log levels, sorted by severity:" << endl;
|
||||
s << "rascsi log levels, sorted by severity:\n";
|
||||
|
||||
for (const auto& log_level : log_level_info.log_levels()) {
|
||||
cout << " " << log_level << endl;
|
||||
s << " " << log_level << '\n';
|
||||
}
|
||||
}
|
||||
|
||||
cout << "Current rascsi log level: " << log_level_info.current_log_level() << endl;
|
||||
s << "Current rascsi log level: " << log_level_info.current_log_level() << '\n';
|
||||
|
||||
return s.str();
|
||||
}
|
||||
|
||||
void RasctlDisplay::DisplayDeviceTypesInfo(const PbDeviceTypesInfo& device_types_info) const
|
||||
string RasctlDisplay::DisplayDeviceTypesInfo(const PbDeviceTypesInfo& device_types_info) const
|
||||
{
|
||||
cout << "Supported device types and their properties:";
|
||||
ostringstream s;
|
||||
|
||||
s << "Supported device types and their properties:";
|
||||
|
||||
for (const auto& device_type_info : device_types_info.properties()) {
|
||||
cout << endl << " " << PbDeviceType_Name(device_type_info.type()) << " ";
|
||||
s << "\n " << PbDeviceType_Name(device_type_info.type()) << " ";
|
||||
|
||||
const PbDeviceProperties& properties = device_type_info.properties();
|
||||
|
||||
if (properties.read_only() || properties.protectable() || properties.stoppable() || properties.lockable()) {
|
||||
cout << "Properties: ";
|
||||
bool has_property = false;
|
||||
if (properties.read_only()) {
|
||||
cout << "read-only";
|
||||
has_property = true;
|
||||
}
|
||||
if (properties.protectable()) {
|
||||
cout << (has_property ? ", " : "") << "protectable";
|
||||
has_property = true;
|
||||
}
|
||||
if (properties.stoppable()) {
|
||||
cout << (has_property ? ", " : "") << "stoppable";
|
||||
has_property = true;
|
||||
}
|
||||
if (properties.removable()) {
|
||||
cout << (has_property ? ", " : "") << "removable";
|
||||
has_property = true;
|
||||
}
|
||||
if (properties.lockable()) {
|
||||
cout << (has_property ? ", " : "") << "lockable";
|
||||
}
|
||||
cout << endl << " ";
|
||||
}
|
||||
DisplayAttributes(s, properties);
|
||||
|
||||
if (properties.supports_file()) {
|
||||
cout << "Image file support" << endl << " ";
|
||||
s << "Image file support\n ";
|
||||
}
|
||||
|
||||
if (properties.supports_params()) {
|
||||
cout << "Parameter support" << endl << " ";
|
||||
s << "Parameter support\n ";
|
||||
}
|
||||
|
||||
if (properties.supports_params() && properties.default_params_size()) {
|
||||
// Creates a sorted map
|
||||
map<string, string> params = { properties.default_params().begin(), properties.default_params().end() };
|
||||
DisplayDefaultParameters(s, properties);
|
||||
|
||||
cout << "Default parameters: ";
|
||||
|
||||
bool isFirst = true;
|
||||
for (const auto& [key, value] : params) {
|
||||
if (!isFirst) {
|
||||
cout << endl << " ";
|
||||
}
|
||||
cout << key << "=" << value;
|
||||
|
||||
isFirst = false;
|
||||
}
|
||||
}
|
||||
|
||||
if (properties.block_sizes_size()) {
|
||||
// Creates a sorted set
|
||||
set<uint32_t> block_sizes = { properties.block_sizes().begin(), properties.block_sizes().end() };
|
||||
|
||||
cout << "Configurable block sizes in bytes: ";
|
||||
|
||||
bool isFirst = true;
|
||||
for (const auto& block_size : block_sizes) {
|
||||
if (!isFirst) {
|
||||
cout << ", ";
|
||||
}
|
||||
cout << block_size;
|
||||
|
||||
isFirst = false;
|
||||
}
|
||||
}
|
||||
DisplayBlockSizes(s, properties);
|
||||
}
|
||||
|
||||
return s.str();
|
||||
}
|
||||
|
||||
void RasctlDisplay::DisplayReservedIdsInfo(const PbReservedIdsInfo& reserved_ids_info) const
|
||||
string RasctlDisplay::DisplayReservedIdsInfo(const PbReservedIdsInfo& reserved_ids_info) const
|
||||
{
|
||||
ostringstream s;
|
||||
|
||||
if (reserved_ids_info.ids_size()) {
|
||||
cout << "Reserved device IDs: ";
|
||||
s << "Reserved device IDs: ";
|
||||
|
||||
for (int i = 0; i < reserved_ids_info.ids_size(); i++) {
|
||||
if(i) {
|
||||
cout << ", ";
|
||||
s << ", ";
|
||||
}
|
||||
cout << reserved_ids_info.ids(i);
|
||||
|
||||
s << reserved_ids_info.ids(i);
|
||||
}
|
||||
cout <<endl;
|
||||
|
||||
s << '\n';
|
||||
}
|
||||
else {
|
||||
s << "No reserved device IDs\n";
|
||||
}
|
||||
|
||||
return s.str();
|
||||
}
|
||||
|
||||
void RasctlDisplay::DisplayImageFile(const PbImageFile& image_file_info) const
|
||||
string RasctlDisplay::DisplayImageFile(const PbImageFile& image_file_info) const
|
||||
{
|
||||
cout << image_file_info.name() << " " << image_file_info.size() << " bytes";
|
||||
ostringstream s;
|
||||
|
||||
s << image_file_info.name() << " " << image_file_info.size() << " bytes";
|
||||
|
||||
if (image_file_info.read_only()) {
|
||||
cout << " read-only";
|
||||
s << " read-only";
|
||||
}
|
||||
if (image_file_info.type() != UNDEFINED) {
|
||||
cout << " " << PbDeviceType_Name(image_file_info.type());
|
||||
}
|
||||
cout << endl;
|
||||
|
||||
if (image_file_info.type() != UNDEFINED) {
|
||||
s << " " << PbDeviceType_Name(image_file_info.type());
|
||||
}
|
||||
|
||||
s << '\n';
|
||||
|
||||
return s.str();
|
||||
}
|
||||
|
||||
void RasctlDisplay::DisplayImageFiles(const PbImageFilesInfo& image_files_info) const
|
||||
string RasctlDisplay::DisplayImageFilesInfo(const PbImageFilesInfo& image_files_info) const
|
||||
{
|
||||
cout << "Default image file folder: " << image_files_info.default_image_folder() << endl;
|
||||
cout << "Supported folder depth: " << image_files_info.depth() << endl;
|
||||
ostringstream s;
|
||||
|
||||
s << "Default image file folder: " << image_files_info.default_image_folder() << '\n';
|
||||
s << "Supported folder depth: " << image_files_info.depth() << '\n';
|
||||
|
||||
if (image_files_info.image_files().empty()) {
|
||||
cout << " No image files available" << endl;
|
||||
s << " No image files available\n";
|
||||
}
|
||||
else {
|
||||
list<PbImageFile> image_files = { image_files_info.image_files().begin(), image_files_info.image_files().end() };
|
||||
image_files.sort([](const auto& a, const auto& b) { return a.name() < b.name(); });
|
||||
|
||||
cout << "Available image files:" << endl;
|
||||
s << "Available image files:\n";
|
||||
for (const auto& image_file : image_files) {
|
||||
cout << " ";
|
||||
DisplayImageFile(image_file);
|
||||
s << " ";
|
||||
|
||||
s << DisplayImageFile(image_file);
|
||||
}
|
||||
}
|
||||
|
||||
return s.str();
|
||||
}
|
||||
|
||||
void RasctlDisplay::DisplayNetworkInterfaces(const PbNetworkInterfacesInfo& network_interfaces_info) const
|
||||
string RasctlDisplay::DisplayNetworkInterfaces(const PbNetworkInterfacesInfo& network_interfaces_info) const
|
||||
{
|
||||
// Creates a sorted list
|
||||
const list<string> interfaces = { network_interfaces_info.name().begin(), network_interfaces_info.name().end() };
|
||||
ostringstream s;
|
||||
|
||||
s << "Available (up) network interfaces:\n";
|
||||
|
||||
const list<string> sorted_interfaces = { network_interfaces_info.name().begin(), network_interfaces_info.name().end() };
|
||||
|
||||
cout << "Available (up) network interfaces:" << endl;
|
||||
bool isFirst = true;
|
||||
for (const auto& interface : interfaces) {
|
||||
for (const auto& interface : sorted_interfaces) {
|
||||
if (!isFirst) {
|
||||
cout << ", ";
|
||||
s << ", ";
|
||||
}
|
||||
else {
|
||||
cout << " ";
|
||||
s << " ";
|
||||
}
|
||||
|
||||
isFirst = false;
|
||||
cout << interface;
|
||||
s << interface;
|
||||
}
|
||||
cout << endl;
|
||||
|
||||
s << '\n';
|
||||
|
||||
return s.str();
|
||||
}
|
||||
|
||||
void RasctlDisplay::DisplayMappingInfo(const PbMappingInfo& mapping_info) const
|
||||
string RasctlDisplay::DisplayMappingInfo(const PbMappingInfo& mapping_info) const
|
||||
{
|
||||
// Creates a sorted map
|
||||
const map<string, PbDeviceType> mappings = { mapping_info.mapping().begin(), mapping_info.mapping().end() };
|
||||
ostringstream s;
|
||||
|
||||
cout << "Supported image file extension to device type mappings:" << endl;
|
||||
for (const auto& [extension, type] : mappings) {
|
||||
cout << " " << extension << "->" << PbDeviceType_Name(type) << endl;
|
||||
s << "Supported image file extension to device type mappings:\n";
|
||||
|
||||
const map<string, PbDeviceType, less<>> sorted_mappings = { mapping_info.mapping().begin(), mapping_info.mapping().end() };
|
||||
|
||||
for (const auto& [extension, type] : sorted_mappings) {
|
||||
s << " " << extension << "->" << PbDeviceType_Name(type) << '\n';
|
||||
}
|
||||
|
||||
return s.str();
|
||||
}
|
||||
|
||||
void RasctlDisplay::DisplayOperationInfo(const PbOperationInfo& operation_info) const
|
||||
string RasctlDisplay::DisplayOperationInfo(const PbOperationInfo& operation_info) const
|
||||
{
|
||||
const map<int, PbOperationMetaData> operations = { operation_info.operations().begin(), operation_info.operations().end() };
|
||||
ostringstream s;
|
||||
|
||||
const map<int, PbOperationMetaData, less<>> operations = { operation_info.operations().begin(), operation_info.operations().end() };
|
||||
|
||||
// Copies result into a map sorted by operation name
|
||||
const PbOperationMetaData *unknown_operation = new PbOperationMetaData();
|
||||
map<string, PbOperationMetaData> sorted_operations;
|
||||
auto unknown_operation = make_unique<PbOperationMetaData>();
|
||||
map<string, PbOperationMetaData, less<>> sorted_operations;
|
||||
|
||||
for (const auto& [ordinal, meta_data] : operations) {
|
||||
if (PbOperation_IsValid(static_cast<PbOperation>(ordinal))) {
|
||||
sorted_operations[PbOperation_Name(static_cast<PbOperation>(ordinal))] = meta_data;
|
||||
@ -289,46 +297,149 @@ void RasctlDisplay::DisplayOperationInfo(const PbOperationInfo& operation_info)
|
||||
}
|
||||
}
|
||||
|
||||
cout << "Operations supported by rascsi server and their parameters:" << endl;
|
||||
s << "Operations supported by rascsi server and their parameters:\n";
|
||||
for (const auto& [name, meta_data] : sorted_operations) {
|
||||
if (!meta_data.server_side_name().empty()) {
|
||||
cout << " " << name;
|
||||
s << " " << name;
|
||||
if (!meta_data.description().empty()) {
|
||||
cout << " (" << meta_data.description() << ")";
|
||||
s << " (" << meta_data.description() << ")";
|
||||
}
|
||||
cout << endl;
|
||||
s << '\n';
|
||||
|
||||
list<PbOperationParameter> sorted_parameters = { meta_data.parameters().begin(), meta_data.parameters().end() };
|
||||
sorted_parameters.sort([](const auto& a, const auto& b) { return a.name() < b.name(); });
|
||||
|
||||
for (const auto& parameter : sorted_parameters) {
|
||||
cout << " " << parameter.name() << ": "
|
||||
<< (parameter.is_mandatory() ? "mandatory" : "optional");
|
||||
if (!parameter.description().empty()) {
|
||||
cout << " (" << parameter.description() << ")";
|
||||
}
|
||||
cout << endl;
|
||||
|
||||
if (parameter.permitted_values_size()) {
|
||||
cout << " Permitted values: ";
|
||||
bool isFirst = true;
|
||||
for (const auto& permitted_value : parameter.permitted_values()) {
|
||||
if (!isFirst) {
|
||||
cout << ", ";
|
||||
}
|
||||
isFirst = false;
|
||||
cout << permitted_value;
|
||||
}
|
||||
cout << endl;
|
||||
}
|
||||
|
||||
if (!parameter.default_value().empty()) {
|
||||
cout << " Default value: " << parameter.default_value() << endl;
|
||||
}
|
||||
}
|
||||
DisplayParameters(s, meta_data);
|
||||
}
|
||||
else {
|
||||
cout << " " << name << " (Unknown server-side operation)" << endl;
|
||||
s << " " << name << " (Unknown server-side operation)\n";
|
||||
}
|
||||
}
|
||||
|
||||
return s.str();
|
||||
}
|
||||
|
||||
void RasctlDisplay::DisplayParams(ostringstream& s, const PbDevice& pb_device) const
|
||||
{
|
||||
const map<string, string, less<>> sorted_params = { pb_device.params().begin(), pb_device.params().end() };
|
||||
|
||||
bool isFirst = true;
|
||||
for (const auto& [key, value] : sorted_params) {
|
||||
if (!isFirst) {
|
||||
s << ":";
|
||||
}
|
||||
|
||||
isFirst = false;
|
||||
s << key << "=" << value;
|
||||
}
|
||||
}
|
||||
|
||||
void RasctlDisplay::DisplayAttributes(ostringstream& s, const PbDeviceProperties& properties) const
|
||||
{
|
||||
if (properties.read_only() || properties.protectable() || properties.stoppable() || properties.lockable()) {
|
||||
s << "Properties: ";
|
||||
|
||||
bool has_property = false;
|
||||
|
||||
if (properties.read_only()) {
|
||||
s << "read-only";
|
||||
has_property = true;
|
||||
}
|
||||
|
||||
if (properties.protectable()) {
|
||||
s << (has_property ? ", " : "") << "protectable";
|
||||
has_property = true;
|
||||
}
|
||||
if (properties.stoppable()) {
|
||||
s << (has_property ? ", " : "") << "stoppable";
|
||||
has_property = true;
|
||||
}
|
||||
if (properties.removable()) {
|
||||
s << (has_property ? ", " : "") << "removable";
|
||||
has_property = true;
|
||||
}
|
||||
if (properties.lockable()) {
|
||||
s << (has_property ? ", " : "") << "lockable";
|
||||
}
|
||||
|
||||
s << "\n ";
|
||||
}
|
||||
}
|
||||
|
||||
void RasctlDisplay::DisplayDefaultParameters(ostringstream& s, const PbDeviceProperties& properties) const
|
||||
{
|
||||
if (properties.supports_params() && properties.default_params_size()) {
|
||||
s << "Default parameters: ";
|
||||
|
||||
const map<string, string, less<>> sorted_params = { properties.default_params().begin(), properties.default_params().end() };
|
||||
|
||||
bool isFirst = true;
|
||||
for (const auto& [key, value] : sorted_params) {
|
||||
if (!isFirst) {
|
||||
s << "\n ";
|
||||
}
|
||||
s << key << "=" << value;
|
||||
|
||||
isFirst = false;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void RasctlDisplay::DisplayBlockSizes(ostringstream& s, const PbDeviceProperties& properties) const
|
||||
{
|
||||
if (properties.block_sizes_size()) {
|
||||
s << "Configurable block sizes in bytes: ";
|
||||
|
||||
const set<uint32_t> sorted_sizes = { properties.block_sizes().begin(), properties.block_sizes().end() };
|
||||
|
||||
bool isFirst = true;
|
||||
for (const auto& size : sorted_sizes) {
|
||||
if (!isFirst) {
|
||||
s << ", ";
|
||||
}
|
||||
s << size;
|
||||
|
||||
isFirst = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void RasctlDisplay::DisplayParameters(ostringstream& s, const PbOperationMetaData& meta_data) const
|
||||
{
|
||||
list<PbOperationParameter> sorted_parameters = { meta_data.parameters().begin(), meta_data.parameters().end() };
|
||||
sorted_parameters.sort([](const auto& a, const auto& b) { return a.name() < b.name(); });
|
||||
|
||||
for (const auto& parameter : sorted_parameters) {
|
||||
s << " " << parameter.name() << ": "
|
||||
<< (parameter.is_mandatory() ? "mandatory" : "optional");
|
||||
|
||||
if (!parameter.description().empty()) {
|
||||
s << " (" << parameter.description() << ")";
|
||||
}
|
||||
s << '\n';
|
||||
|
||||
DisplayPermittedValues(s, parameter);
|
||||
|
||||
if (!parameter.default_value().empty()) {
|
||||
s << " Default value: " << parameter.default_value() << '\n';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void RasctlDisplay::DisplayPermittedValues(ostringstream& s, const PbOperationParameter& parameter) const
|
||||
{
|
||||
if (parameter.permitted_values_size()) {
|
||||
s << " Permitted values: ";
|
||||
|
||||
bool isFirst = true;
|
||||
|
||||
for (const auto& permitted_value : parameter.permitted_values()) {
|
||||
if (!isFirst) {
|
||||
s << ", ";
|
||||
}
|
||||
|
||||
isFirst = false;
|
||||
s << permitted_value;
|
||||
}
|
||||
|
||||
s << '\n';
|
||||
}
|
||||
}
|
||||
|
@ -10,25 +10,37 @@
|
||||
#pragma once
|
||||
|
||||
#include "rascsi_interface.pb.h"
|
||||
#include <string>
|
||||
#include <sstream>
|
||||
|
||||
using namespace std;
|
||||
using namespace rascsi_interface;
|
||||
|
||||
class RasctlDisplay
|
||||
{
|
||||
friend class RasctlCommands;
|
||||
public:
|
||||
|
||||
RasctlDisplay() = default;
|
||||
~RasctlDisplay() = default;
|
||||
|
||||
void DisplayDevices(const PbDevicesInfo&) const;
|
||||
void DisplayDeviceInfo(const PbDevice&) const;
|
||||
void DisplayVersionInfo(const PbVersionInfo&) const;
|
||||
void DisplayLogLevelInfo(const PbLogLevelInfo&) const;
|
||||
void DisplayDeviceTypesInfo(const PbDeviceTypesInfo&) const;
|
||||
void DisplayReservedIdsInfo(const PbReservedIdsInfo&) const;
|
||||
void DisplayImageFile(const PbImageFile&) const;
|
||||
void DisplayImageFiles(const PbImageFilesInfo&) const;
|
||||
void DisplayNetworkInterfaces(const PbNetworkInterfacesInfo&) const;
|
||||
void DisplayMappingInfo(const PbMappingInfo&) const;
|
||||
void DisplayOperationInfo(const PbOperationInfo&) const;
|
||||
string DisplayDevicesInfo(const PbDevicesInfo&) const;
|
||||
string DisplayDeviceInfo(const PbDevice&) const;
|
||||
string DisplayVersionInfo(const PbVersionInfo&) const;
|
||||
string DisplayLogLevelInfo(const PbLogLevelInfo&) const;
|
||||
string DisplayDeviceTypesInfo(const PbDeviceTypesInfo&) const;
|
||||
string DisplayReservedIdsInfo(const PbReservedIdsInfo&) const;
|
||||
string DisplayImageFile(const PbImageFile&) const;
|
||||
string DisplayImageFilesInfo(const PbImageFilesInfo&) const;
|
||||
string DisplayNetworkInterfaces(const PbNetworkInterfacesInfo&) const;
|
||||
string DisplayMappingInfo(const PbMappingInfo&) const;
|
||||
string DisplayOperationInfo(const PbOperationInfo&) const;
|
||||
|
||||
private:
|
||||
|
||||
void DisplayParams(ostringstream&, const PbDevice&) const;
|
||||
void DisplayAttributes(ostringstream&, const PbDeviceProperties&) const;
|
||||
void DisplayDefaultParameters(ostringstream&, const PbDeviceProperties&) const;
|
||||
void DisplayBlockSizes(ostringstream&, const PbDeviceProperties&) const;
|
||||
void DisplayParameters(ostringstream&, const PbOperationMetaData&) const;
|
||||
void DisplayPermittedValues(ostringstream&, const PbOperationParameter&) const;
|
||||
};
|
||||
|
31
src/raspberrypi/rasctl/rasctl_parser.cpp
Normal file
31
src/raspberrypi/rasctl/rasctl_parser.cpp
Normal 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;
|
||||
}
|
49
src/raspberrypi/rasctl/rasctl_parser.h
Normal file
49
src/raspberrypi/rasctl/rasctl_parser.h
Normal 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 }
|
||||
};
|
||||
};
|
@ -217,7 +217,7 @@ bool ParseArgument(int argc, char* argv[])
|
||||
bool WaitPhase(BUS::phase_t phase)
|
||||
{
|
||||
// Timeout (3000ms)
|
||||
uint32_t now = SysTimer::GetTimerLow();
|
||||
const uint32_t now = SysTimer::GetTimerLow();
|
||||
while ((SysTimer::GetTimerLow() - now) < 3 * 1000 * 1000) {
|
||||
bus.Acquire();
|
||||
if (bus.GetREQ() && bus.GetPhase() == phase) {
|
||||
@ -246,21 +246,17 @@ void BusFree()
|
||||
//---------------------------------------------------------------------------
|
||||
bool Selection(int id)
|
||||
{
|
||||
BYTE data;
|
||||
int count;
|
||||
|
||||
// ID setting and SEL assert
|
||||
data = 0;
|
||||
data |= (1 << boardid);
|
||||
BYTE data = 1 << boardid;
|
||||
data |= (1 << id);
|
||||
bus.SetDAT(data);
|
||||
bus.SetSEL(true);
|
||||
|
||||
// wait for busy
|
||||
count = 10000;
|
||||
int count = 10000;
|
||||
do {
|
||||
// Wait 20 microseconds
|
||||
timespec ts = { .tv_sec = 0, .tv_nsec = 20 * 1000};
|
||||
const timespec ts = { .tv_sec = 0, .tv_nsec = 20 * 1000};
|
||||
nanosleep(&ts, nullptr);
|
||||
bus.Acquire();
|
||||
if (bus.GetBSY()) {
|
||||
@ -282,15 +278,13 @@ bool Selection(int id)
|
||||
//---------------------------------------------------------------------------
|
||||
bool Command(BYTE *buf, int length)
|
||||
{
|
||||
int count;
|
||||
|
||||
// Waiting for Phase
|
||||
if (!WaitPhase(BUS::phase_t::command)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Send Command
|
||||
count = bus.SendHandShake(buf, length, BUS::SEND_NO_DELAY);
|
||||
const int count = bus.SendHandShake(buf, length, BUS::SEND_NO_DELAY);
|
||||
|
||||
// Success if the transmission result is the same as the number
|
||||
// of requests
|
||||
@ -665,7 +659,7 @@ exit:
|
||||
// READ10
|
||||
//
|
||||
//---------------------------------------------------------------------------
|
||||
int Read10(int id, DWORD bstart, DWORD blength, DWORD length, BYTE *buf)
|
||||
int Read10(int id, uint32_t bstart, uint32_t blength, uint32_t length, BYTE *buf)
|
||||
{
|
||||
array<BYTE, 256> cmd = {};
|
||||
|
||||
@ -728,7 +722,7 @@ exit:
|
||||
// WRITE10
|
||||
//
|
||||
//---------------------------------------------------------------------------
|
||||
int Write10(int id, DWORD bstart, DWORD blength, DWORD length, BYTE *buf)
|
||||
int Write10(int id, uint32_t bstart, uint32_t blength, uint32_t length, BYTE *buf)
|
||||
{
|
||||
array<BYTE, 256> cmd = {};
|
||||
|
||||
@ -794,13 +788,12 @@ exit:
|
||||
int main(int argc, char* argv[])
|
||||
{
|
||||
int i;
|
||||
int count;
|
||||
char str[32];
|
||||
DWORD bsiz;
|
||||
DWORD bnum;
|
||||
DWORD duni;
|
||||
DWORD dsiz;
|
||||
DWORD dnum;
|
||||
uint32_t bsiz;
|
||||
uint32_t bnum;
|
||||
uint32_t duni;
|
||||
uint32_t dsiz;
|
||||
uint32_t dnum;
|
||||
Fileio fio;
|
||||
Fileio::OpenMode omode;
|
||||
off_t size;
|
||||
@ -855,7 +848,7 @@ int main(int argc, char* argv[])
|
||||
// Assert reset signal
|
||||
bus.SetRST(true);
|
||||
// Wait 1 ms
|
||||
timespec ts = { .tv_sec = 0, .tv_nsec = 1000 * 1000};
|
||||
const timespec ts = { .tv_sec = 0, .tv_nsec = 1000 * 1000};
|
||||
nanosleep(&ts, nullptr);
|
||||
bus.SetRST(false);
|
||||
|
||||
@ -864,7 +857,7 @@ int main(int argc, char* argv[])
|
||||
printf("BOARD ID : %d\n", boardid);
|
||||
|
||||
// TEST UNIT READY
|
||||
count = TestUnitReady(targetid);
|
||||
int count = TestUnitReady(targetid);
|
||||
if (count < 0) {
|
||||
fprintf(stderr, "TEST UNIT READY ERROR %d\n", count);
|
||||
goto cleanup_exit;
|
||||
|
@ -7,10 +7,9 @@
|
||||
//
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
#include <list>
|
||||
#include <sstream>
|
||||
#include "rascsi_interface.pb.h"
|
||||
#include "rascsi_version.h"
|
||||
#include "rasutil.h"
|
||||
#include <sstream>
|
||||
|
||||
using namespace std;
|
||||
using namespace rascsi_interface;
|
||||
@ -35,16 +34,30 @@ bool ras_util::GetAsInt(const string& value, int& result)
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
string ras_util::Banner(const string& app)
|
||||
{
|
||||
ostringstream s;
|
||||
|
||||
s << "SCSI Target Emulator RaSCSI " << app << " version " << rascsi_get_version_string()
|
||||
<< " (" << __DATE__ << ' ' << __TIME__ << ")\n";
|
||||
s << "Powered by XM6 TypeG Technology / ";
|
||||
s << "Copyright (C) 2016-2020 GIMONS\n";
|
||||
s << "Copyright (C) 2020-2022 Contributors to the RaSCSI Reloaded project\n";
|
||||
|
||||
return s.str();
|
||||
}
|
||||
|
||||
string ras_util::ListDevices(const list<PbDevice>& pb_devices)
|
||||
{
|
||||
if (pb_devices.empty()) {
|
||||
return "No devices currently attached.";
|
||||
return "No devices currently attached.\n";
|
||||
}
|
||||
|
||||
ostringstream s;
|
||||
s << "+----+-----+------+-------------------------------------" << endl
|
||||
<< "| ID | LUN | TYPE | IMAGE FILE" << endl
|
||||
<< "+----+-----+------+-------------------------------------" << endl;
|
||||
s << "+----+-----+------+-------------------------------------\n"
|
||||
<< "| ID | LUN | TYPE | IMAGE FILE\n"
|
||||
<< "+----+-----+------+-------------------------------------\n";
|
||||
|
||||
list<PbDevice> devices = pb_devices;
|
||||
devices.sort([](const auto& a, const auto& b) { return a.id() < b.id() || a.unit() < b.unit(); });
|
||||
@ -76,10 +89,10 @@ string ras_util::ListDevices(const list<PbDevice>& pb_devices)
|
||||
s << "| " << device.id() << " | " << device.unit() << " | " << PbDeviceType_Name(device.type()) << " | "
|
||||
<< (filename.empty() ? "NO MEDIA" : filename)
|
||||
<< (!device.status().removed() && (device.properties().read_only() || device.status().protected_()) ? " (READ-ONLY)" : "")
|
||||
<< endl;
|
||||
<< '\n';
|
||||
}
|
||||
|
||||
s << "+----+-----+------+-------------------------------------";
|
||||
s << "+----+-----+------+-------------------------------------\n";
|
||||
|
||||
return s.str();
|
||||
}
|
||||
|
@ -15,10 +15,13 @@
|
||||
#include <string>
|
||||
#include "rascsi_interface.pb.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
namespace ras_util
|
||||
{
|
||||
bool GetAsInt(const std::string&, int&);
|
||||
std::string ListDevices(const std::list<rascsi_interface::PbDevice>&);
|
||||
bool GetAsInt(const string&, int&);
|
||||
string Banner(const string&);
|
||||
string ListDevices(const list<rascsi_interface::PbDevice>&);
|
||||
|
||||
void FixCpu(int);
|
||||
}
|
||||
|
@ -33,6 +33,7 @@ namespace scsi_defs {
|
||||
COMMUNICATIONS = 9
|
||||
};
|
||||
|
||||
// TODO Use a mapping of enum to structure with command byte count and enum name
|
||||
enum class scsi_command : int {
|
||||
eCmdTestUnitReady = 0x00,
|
||||
eCmdRezero = 0x01,
|
||||
|
@ -35,9 +35,9 @@ static const int _MAX_FNAME = 256;
|
||||
static volatile bool running; // Running flag
|
||||
GPIOBUS bus; // GPIO Bus
|
||||
|
||||
DWORD buff_size = 1000000;
|
||||
uint32_t buff_size = 1000000;
|
||||
data_capture *data_buffer;
|
||||
DWORD data_idx = 0;
|
||||
uint32_t data_idx = 0;
|
||||
|
||||
double ns_per_loop;
|
||||
|
||||
@ -94,8 +94,7 @@ void parse_arguments(int argc, char *argv[])
|
||||
}
|
||||
|
||||
/* Process any remaining command line arguments (not options). */
|
||||
if (optind < argc)
|
||||
{
|
||||
if (optind < argc) {
|
||||
while (optind < argc)
|
||||
strncpy(file_base_name, argv[optind++], sizeof(file_base_name)-1);
|
||||
}
|
||||
@ -147,12 +146,10 @@ void print_help_text(int, char *argv[])
|
||||
//---------------------------------------------------------------------------
|
||||
void Banner(int, char *[])
|
||||
{
|
||||
if (import_data)
|
||||
{
|
||||
if (import_data) {
|
||||
LOGINFO("Reading input file: %s", input_file_name)
|
||||
}
|
||||
else
|
||||
{
|
||||
else {
|
||||
LOGINFO("Reading live data from the GPIO pins")
|
||||
LOGINFO(" Connection type : %s", CONNECT_DESC.c_str())
|
||||
}
|
||||
@ -172,16 +169,13 @@ void Banner(int, char *[])
|
||||
bool Init()
|
||||
{
|
||||
// Interrupt handler settings
|
||||
if (signal(SIGINT, KillHandler) == SIG_ERR)
|
||||
{
|
||||
if (signal(SIGINT, KillHandler) == SIG_ERR) {
|
||||
return false;
|
||||
}
|
||||
if (signal(SIGHUP, KillHandler) == SIG_ERR)
|
||||
{
|
||||
if (signal(SIGHUP, KillHandler) == SIG_ERR) {
|
||||
return false;
|
||||
}
|
||||
if (signal(SIGTERM, KillHandler) == SIG_ERR)
|
||||
{
|
||||
if (signal(SIGTERM, KillHandler) == SIG_ERR) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -249,8 +243,8 @@ void FixCpu(int cpu)
|
||||
#endif
|
||||
|
||||
#ifdef DEBUG
|
||||
static DWORD high_bits = 0x0;
|
||||
static DWORD low_bits = 0xFFFFFFFF;
|
||||
static uint32_t high_bits = 0x0;
|
||||
static uint32_t low_bits = 0xFFFFFFFF;
|
||||
#endif
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
@ -272,12 +266,12 @@ int main(int argc, char *argv[])
|
||||
parse_arguments(argc, argv);
|
||||
|
||||
#ifdef DEBUG
|
||||
DWORD prev_high = high_bits;
|
||||
DWORD prev_low = low_bits;
|
||||
uint32_t prev_high = high_bits;
|
||||
uint32_t prev_low = low_bits;
|
||||
#endif
|
||||
ostringstream s;
|
||||
DWORD prev_sample = 0xFFFFFFFF;
|
||||
DWORD this_sample = 0;
|
||||
uint32_t prev_sample = 0xFFFFFFFF;
|
||||
uint32_t this_sample = 0;
|
||||
timeval start_time;
|
||||
timeval stop_time;
|
||||
uint64_t loop_count = 0;
|
||||
@ -312,8 +306,7 @@ int main(int argc, char *argv[])
|
||||
|
||||
// Initialize
|
||||
int ret = 0;
|
||||
if (!Init())
|
||||
{
|
||||
if (!Init()) {
|
||||
ret = EPERM;
|
||||
goto init_exit;
|
||||
}
|
||||
|
@ -75,10 +75,10 @@ TEST(AbstractControllerTest, ProcessPhase)
|
||||
controller.ProcessPhase();
|
||||
|
||||
controller.SetPhase(BUS::phase_t::reselection);
|
||||
EXPECT_THROW(controller.ProcessPhase(), scsi_error_exception);
|
||||
EXPECT_THROW(controller.ProcessPhase(), scsi_exception);
|
||||
|
||||
controller.SetPhase(BUS::phase_t::reserved);
|
||||
EXPECT_THROW(controller.ProcessPhase(), scsi_error_exception);
|
||||
EXPECT_THROW(controller.ProcessPhase(), scsi_exception);
|
||||
}
|
||||
|
||||
TEST(AbstractControllerTest, DeviceLunLifeCycle)
|
||||
|
89
src/raspberrypi/test/bus_test.cpp
Normal file
89
src/raspberrypi/test/bus_test.cpp
Normal 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));
|
||||
}
|
@ -7,14 +7,48 @@
|
||||
//
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
#include "mocks.h"
|
||||
#include <gmock/gmock.h>
|
||||
|
||||
#include "rascsi/command_context.h"
|
||||
|
||||
using namespace rascsi_interface;
|
||||
TEST(CommandContext, GetSerializer)
|
||||
{
|
||||
CommandContext context("", -1);
|
||||
|
||||
// There is nothing more that can be tested
|
||||
context.GetSerializer();
|
||||
}
|
||||
|
||||
TEST(CommandContext, IsValid)
|
||||
{
|
||||
CommandContext context("", -1);
|
||||
|
||||
EXPECT_FALSE(context.IsValid());
|
||||
|
||||
context.SetFd(1);
|
||||
EXPECT_TRUE(context.IsValid());
|
||||
}
|
||||
|
||||
TEST(CommandContext, Cleanup)
|
||||
{
|
||||
CommandContext context("", 0);
|
||||
|
||||
EXPECT_EQ(0, context.GetFd());
|
||||
context.Cleanup();
|
||||
EXPECT_EQ(-1, context.GetFd());
|
||||
}
|
||||
|
||||
TEST(CommandContext, ReturnLocalizedError)
|
||||
{
|
||||
MockCommandContext context;
|
||||
CommandContext context("en_US", -1);
|
||||
|
||||
EXPECT_FALSE(context.ReturnLocalizedError(LocalizationKey::ERROR_LOG_LEVEL));
|
||||
}
|
||||
|
||||
TEST(CommandContext, ReturnStatus)
|
||||
{
|
||||
CommandContext context("", -1);
|
||||
|
||||
EXPECT_TRUE(context.ReturnStatus(true, "status"));
|
||||
EXPECT_FALSE(context.ReturnStatus(false, "status"));
|
||||
}
|
||||
|
@ -21,8 +21,11 @@ TEST(ControllerManagerTest, LifeCycle)
|
||||
ControllerManager controller_manager(bus);
|
||||
DeviceFactory device_factory;
|
||||
|
||||
auto device = device_factory.CreateDevice(controller_manager, UNDEFINED, LUN1, "services");
|
||||
controller_manager.AttachToScsiController(ID, device);
|
||||
auto device = device_factory.CreateDevice(controller_manager, UNDEFINED, -1, "services");
|
||||
EXPECT_FALSE(controller_manager.AttachToScsiController(ID, device));
|
||||
|
||||
device = device_factory.CreateDevice(controller_manager, UNDEFINED, LUN1, "services");
|
||||
EXPECT_TRUE(controller_manager.AttachToScsiController(ID, device));
|
||||
auto controller = controller_manager.FindController(ID);
|
||||
EXPECT_NE(nullptr, controller);
|
||||
EXPECT_EQ(1, controller->GetLunCount());
|
||||
@ -33,9 +36,9 @@ TEST(ControllerManagerTest, LifeCycle)
|
||||
EXPECT_EQ(nullptr, controller_manager.GetDeviceByIdAndLun(0, 0));
|
||||
|
||||
device = device_factory.CreateDevice(controller_manager, UNDEFINED, LUN2, "services");
|
||||
controller_manager.AttachToScsiController(ID, device);
|
||||
EXPECT_TRUE(controller_manager.AttachToScsiController(ID, device));
|
||||
controller = controller_manager.FindController(ID);
|
||||
controller_manager.DeleteController(controller);
|
||||
EXPECT_TRUE(controller_manager.DeleteController(controller));
|
||||
EXPECT_EQ(nullptr, controller_manager.FindController(ID));
|
||||
|
||||
controller_manager.DeleteAllControllers();
|
||||
@ -52,7 +55,7 @@ TEST(ControllerManagerTest, ResetAllControllers)
|
||||
DeviceFactory device_factory;
|
||||
|
||||
auto device = device_factory.CreateDevice(controller_manager, UNDEFINED, 0, "services");
|
||||
controller_manager.AttachToScsiController(ID, device);
|
||||
EXPECT_TRUE(controller_manager.AttachToScsiController(ID, device));
|
||||
auto controller = controller_manager.FindController(ID);
|
||||
EXPECT_NE(nullptr, controller);
|
||||
|
||||
|
@ -22,10 +22,8 @@ TEST(DiskTest, Dispatch)
|
||||
|
||||
controller.AddDevice(disk);
|
||||
|
||||
controller.InitCmd(6);
|
||||
|
||||
disk->MediumChanged();
|
||||
EXPECT_THROW(disk->Dispatch(scsi_command::eCmdTestUnitReady), scsi_error_exception);
|
||||
EXPECT_THROW(disk->Dispatch(scsi_command::eCmdTestUnitReady), scsi_exception);
|
||||
}
|
||||
|
||||
TEST(DiskTest, Rezero)
|
||||
@ -35,7 +33,7 @@ TEST(DiskTest, Rezero)
|
||||
|
||||
controller.AddDevice(disk);
|
||||
|
||||
EXPECT_THROW(disk->Dispatch(scsi_command::eCmdRezero), scsi_error_exception)
|
||||
EXPECT_THROW(disk->Dispatch(scsi_command::eCmdRezero), scsi_exception)
|
||||
<< "REZERO must fail because drive is not ready";
|
||||
|
||||
disk->SetReady(true);
|
||||
@ -54,7 +52,7 @@ TEST(DiskTest, FormatUnit)
|
||||
|
||||
vector<int>& cmd = controller.InitCmd(6);
|
||||
|
||||
EXPECT_THROW(disk->Dispatch(scsi_command::eCmdFormat), scsi_error_exception);
|
||||
EXPECT_THROW(disk->Dispatch(scsi_command::eCmdFormat), scsi_exception);
|
||||
|
||||
disk->SetReady(true);
|
||||
|
||||
@ -64,7 +62,7 @@ TEST(DiskTest, FormatUnit)
|
||||
|
||||
cmd[1] = 0x10;
|
||||
cmd[4] = 1;
|
||||
EXPECT_THROW(disk->Dispatch(scsi_command::eCmdFormat), scsi_error_exception);
|
||||
EXPECT_THROW(disk->Dispatch(scsi_command::eCmdFormat), scsi_exception);
|
||||
}
|
||||
|
||||
TEST(DiskTest, ReassignBlocks)
|
||||
@ -74,7 +72,7 @@ TEST(DiskTest, ReassignBlocks)
|
||||
|
||||
controller.AddDevice(disk);
|
||||
|
||||
EXPECT_THROW(disk->Dispatch(scsi_command::eCmdReassign), scsi_error_exception)
|
||||
EXPECT_THROW(disk->Dispatch(scsi_command::eCmdReassign), scsi_exception)
|
||||
<< "REASSIGN must fail because drive is not ready";
|
||||
|
||||
disk->SetReady(true);
|
||||
@ -93,15 +91,15 @@ TEST(DiskTest, Seek)
|
||||
|
||||
vector<int>& cmd = controller.InitCmd(10);
|
||||
|
||||
EXPECT_THROW(disk->Dispatch(scsi_command::eCmdSeek6), scsi_error_exception)
|
||||
EXPECT_THROW(disk->Dispatch(scsi_command::eCmdSeek6), scsi_exception)
|
||||
<< "SEEK(6) must fail for a medium with 0 blocks";
|
||||
EXPECT_THROW(disk->Dispatch(scsi_command::eCmdSeek10), scsi_error_exception)
|
||||
EXPECT_THROW(disk->Dispatch(scsi_command::eCmdSeek10), scsi_exception)
|
||||
<< "SEEK(10) must fail for a medium with 0 blocks";
|
||||
|
||||
disk->SetBlockCount(1);
|
||||
EXPECT_THROW(disk->Dispatch(scsi_command::eCmdSeek6), scsi_error_exception)
|
||||
EXPECT_THROW(disk->Dispatch(scsi_command::eCmdSeek6), scsi_exception)
|
||||
<< "SEEK(6) must fail because drive is not ready";
|
||||
EXPECT_THROW(disk->Dispatch(scsi_command::eCmdSeek10), scsi_error_exception)
|
||||
EXPECT_THROW(disk->Dispatch(scsi_command::eCmdSeek10), scsi_exception)
|
||||
<< "SEEK(10) must fail because drive is not ready";
|
||||
|
||||
disk->SetReady(true);
|
||||
@ -129,23 +127,23 @@ TEST(DiskTest, ReadCapacity)
|
||||
|
||||
vector<int>& cmd = controller.InitCmd(16);
|
||||
|
||||
EXPECT_THROW(disk->Dispatch(scsi_command::eCmdReadCapacity16_ReadLong16), scsi_error_exception)
|
||||
EXPECT_THROW(disk->Dispatch(scsi_command::eCmdReadCapacity16_ReadLong16), scsi_exception)
|
||||
<< "Neithed READ CAPACITY(16) nor READ LONG(16)";
|
||||
|
||||
EXPECT_THROW(disk->Dispatch(scsi_command::eCmdReadCapacity10), scsi_error_exception)
|
||||
EXPECT_THROW(disk->Dispatch(scsi_command::eCmdReadCapacity10), scsi_exception)
|
||||
<< "READ CAPACITY(10) must fail because drive is not ready";
|
||||
// READ CAPACITY(16), not READ LONG(16)
|
||||
cmd[1] = 0x10;
|
||||
EXPECT_THROW(disk->Dispatch(scsi_command::eCmdReadCapacity16_ReadLong16), scsi_error_exception)
|
||||
EXPECT_THROW(disk->Dispatch(scsi_command::eCmdReadCapacity16_ReadLong16), scsi_exception)
|
||||
<< "READ CAPACITY(16) must fail because drive is not ready";
|
||||
cmd[1] = 0x00;
|
||||
|
||||
disk->SetReady(true);
|
||||
EXPECT_THROW(disk->Dispatch(scsi_command::eCmdReadCapacity10), scsi_error_exception)
|
||||
EXPECT_THROW(disk->Dispatch(scsi_command::eCmdReadCapacity10), scsi_exception)
|
||||
<< "READ CAPACITY(10) must fail because the medium has no capacity";
|
||||
// READ CAPACITY(16), not READ LONG(16)
|
||||
cmd[1] = 0x10;
|
||||
EXPECT_THROW(disk->Dispatch(scsi_command::eCmdReadCapacity16_ReadLong16), scsi_error_exception)
|
||||
EXPECT_THROW(disk->Dispatch(scsi_command::eCmdReadCapacity16_ReadLong16), scsi_exception)
|
||||
<< "READ CAPACITY(16) must fail because the medium has no capacity";
|
||||
cmd[1] = 0x00;
|
||||
|
||||
@ -201,22 +199,22 @@ TEST(DiskTest, ReadWriteLong)
|
||||
EXPECT_EQ(status::GOOD, controller.GetStatus());
|
||||
|
||||
cmd[2] = 1;
|
||||
EXPECT_THROW(disk->Dispatch(scsi_command::eCmdReadLong10), scsi_error_exception)
|
||||
EXPECT_THROW(disk->Dispatch(scsi_command::eCmdReadLong10), scsi_exception)
|
||||
<< "READ LONG(10) must fail because the capacity is exceeded";
|
||||
EXPECT_THROW(disk->Dispatch(scsi_command::eCmdWriteLong10), scsi_error_exception)
|
||||
EXPECT_THROW(disk->Dispatch(scsi_command::eCmdWriteLong10), scsi_exception)
|
||||
<< "WRITE LONG(10) must fail because the capacity is exceeded";
|
||||
// READ LONG(16), not READ CAPACITY(16)
|
||||
cmd[1] = 0x11;
|
||||
EXPECT_THROW(disk->Dispatch(scsi_command::eCmdReadCapacity16_ReadLong16), scsi_error_exception)
|
||||
EXPECT_THROW(disk->Dispatch(scsi_command::eCmdReadCapacity16_ReadLong16), scsi_exception)
|
||||
<< "READ LONG(16) must fail because the capacity is exceeded";
|
||||
EXPECT_THROW(disk->Dispatch(scsi_command::eCmdWriteLong16), scsi_error_exception)
|
||||
EXPECT_THROW(disk->Dispatch(scsi_command::eCmdWriteLong16), scsi_exception)
|
||||
<< "WRITE LONG(16) must fail because the capacity is exceeded";
|
||||
cmd[2] = 0;
|
||||
|
||||
cmd[7] = 1;
|
||||
EXPECT_THROW(disk->Dispatch(scsi_command::eCmdReadLong10), scsi_error_exception)
|
||||
EXPECT_THROW(disk->Dispatch(scsi_command::eCmdReadLong10), scsi_exception)
|
||||
<< "READ LONG(10) must fail because it currently only supports 0 bytes transfer length";
|
||||
EXPECT_THROW(disk->Dispatch(scsi_command::eCmdWriteLong10), scsi_error_exception)
|
||||
EXPECT_THROW(disk->Dispatch(scsi_command::eCmdWriteLong10), scsi_exception)
|
||||
<< "WRITE LONG(10) must fail because it currently only supports 0 bytes transfer length";
|
||||
cmd[7] = 0;
|
||||
|
||||
@ -233,25 +231,31 @@ TEST(DiskTest, ReadWriteLong)
|
||||
cmd[13] = 1;
|
||||
// READ LONG(16), not READ CAPACITY(16)
|
||||
cmd[1] = 0x11;
|
||||
EXPECT_THROW(disk->Dispatch(scsi_command::eCmdReadCapacity16_ReadLong16), scsi_error_exception)
|
||||
EXPECT_THROW(disk->Dispatch(scsi_command::eCmdReadCapacity16_ReadLong16), scsi_exception)
|
||||
<< "READ LONG(16) must fail because it currently only supports 0 bytes transfer length";
|
||||
cmd[1] = 0x00;
|
||||
EXPECT_THROW(disk->Dispatch(scsi_command::eCmdWriteLong16), scsi_error_exception)
|
||||
EXPECT_THROW(disk->Dispatch(scsi_command::eCmdWriteLong16), scsi_exception)
|
||||
<< "WRITE LONG(16) must fail because it currently only supports 0 bytes transfer length";
|
||||
}
|
||||
|
||||
TEST(DiskTest, ReserveRelease)
|
||||
TEST(DiskTest, Reserve)
|
||||
{
|
||||
MockAbstractController controller(0);
|
||||
auto disk = make_shared<MockDisk>();
|
||||
|
||||
controller.AddDevice(disk);
|
||||
|
||||
controller.InitCmd(6);
|
||||
|
||||
EXPECT_CALL(controller, Status()).Times(1);
|
||||
EXPECT_TRUE(disk->Dispatch(scsi_command::eCmdReserve6));
|
||||
EXPECT_EQ(status::GOOD, controller.GetStatus());
|
||||
}
|
||||
|
||||
TEST(DiskTest, Release)
|
||||
{
|
||||
MockAbstractController controller(0);
|
||||
auto disk = make_shared<MockDisk>();
|
||||
|
||||
controller.AddDevice(disk);
|
||||
|
||||
EXPECT_CALL(controller, Status()).Times(1);
|
||||
EXPECT_TRUE(disk->Dispatch(scsi_command::eCmdRelease6));
|
||||
@ -272,16 +276,16 @@ TEST(DiskTest, SendDiagnostic)
|
||||
EXPECT_EQ(status::GOOD, controller.GetStatus());
|
||||
|
||||
cmd[1] = 0x10;
|
||||
EXPECT_THROW(disk->Dispatch(scsi_command::eCmdSendDiag), scsi_error_exception)
|
||||
EXPECT_THROW(disk->Dispatch(scsi_command::eCmdSendDiag), scsi_exception)
|
||||
<< "SEND DIAGNOSTIC must fail because PF bit is not supported";
|
||||
cmd[1] = 0;
|
||||
|
||||
cmd[3] = 1;
|
||||
EXPECT_THROW(disk->Dispatch(scsi_command::eCmdSendDiag), scsi_error_exception)
|
||||
EXPECT_THROW(disk->Dispatch(scsi_command::eCmdSendDiag), scsi_exception)
|
||||
<< "SEND DIAGNOSTIC must fail because parameter list is not supported";
|
||||
cmd[3] = 0;
|
||||
cmd[4] = 1;
|
||||
EXPECT_THROW(disk->Dispatch(scsi_command::eCmdSendDiag), scsi_error_exception)
|
||||
EXPECT_THROW(disk->Dispatch(scsi_command::eCmdSendDiag), scsi_exception)
|
||||
<< "SEND DIAGNOSTIC must fail because parameter list is not supported";
|
||||
}
|
||||
|
||||
@ -294,7 +298,7 @@ TEST(DiskTest, PreventAllowMediumRemoval)
|
||||
|
||||
vector<int>& cmd = controller.InitCmd(6);
|
||||
|
||||
EXPECT_THROW(disk->Dispatch(scsi_command::eCmdRemoval), scsi_error_exception)
|
||||
EXPECT_THROW(disk->Dispatch(scsi_command::eCmdRemoval), scsi_exception)
|
||||
<< "REMOVAL must fail because drive is not ready";
|
||||
|
||||
disk->SetReady(true);
|
||||
@ -318,15 +322,11 @@ TEST(DiskTest, SynchronizeCache)
|
||||
|
||||
controller.AddDevice(disk);
|
||||
|
||||
controller.InitCmd(10);
|
||||
|
||||
EXPECT_CALL(*disk, FlushCache()).Times(1);
|
||||
EXPECT_CALL(controller, Status()).Times(1);
|
||||
EXPECT_TRUE(disk->Dispatch(scsi_command::eCmdSynchronizeCache10));
|
||||
EXPECT_EQ(status::GOOD, controller.GetStatus());
|
||||
|
||||
controller.InitCmd(16);
|
||||
|
||||
EXPECT_CALL(*disk, FlushCache()).Times(1);
|
||||
EXPECT_CALL(controller, Status()).Times(1);
|
||||
EXPECT_TRUE(disk->Dispatch(scsi_command::eCmdSynchronizeCache16));
|
||||
@ -410,3 +410,46 @@ TEST(DiskTest, BlockCount)
|
||||
disk.SetBlockCount(0x1234567887654321);
|
||||
EXPECT_EQ(0x1234567887654321, disk.GetBlockCount());
|
||||
}
|
||||
|
||||
TEST(DiskTest, GetIdsForReservedFile)
|
||||
{
|
||||
const int ID = 1;
|
||||
const int LUN = 2;
|
||||
|
||||
Filepath path;
|
||||
path.SetPath("path");
|
||||
MockDisk disk;
|
||||
|
||||
disk.SetPath(path);
|
||||
Filepath result;
|
||||
disk.GetPath(result);
|
||||
EXPECT_STREQ("path", result.GetPath());
|
||||
|
||||
int id;
|
||||
int lun;
|
||||
EXPECT_FALSE(Disk::GetIdsForReservedFile(path, id, lun));
|
||||
|
||||
disk.ReserveFile(path, ID, LUN);
|
||||
EXPECT_TRUE(Disk::GetIdsForReservedFile(path, id, lun));
|
||||
EXPECT_EQ(ID, id);
|
||||
EXPECT_EQ(LUN, lun);
|
||||
|
||||
disk.UnreserveFile();
|
||||
EXPECT_FALSE(Disk::GetIdsForReservedFile(path, id, lun));
|
||||
}
|
||||
|
||||
TEST(DiskTest, UnreserveAll)
|
||||
{
|
||||
const int ID = 2;
|
||||
const int LUN = 31;
|
||||
|
||||
Filepath path;
|
||||
path.SetPath("path");
|
||||
MockDisk disk;
|
||||
|
||||
disk.ReserveFile(path, ID, LUN);
|
||||
Disk::UnreserveAll();
|
||||
int id;
|
||||
int lun;
|
||||
EXPECT_FALSE(Disk::GetIdsForReservedFile(path, id, lun));
|
||||
}
|
||||
|
@ -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));
|
||||
}
|
149
src/raspberrypi/test/host_services_test.cpp
Normal file
149
src/raspberrypi/test/host_services_test.cpp
Normal 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());
|
||||
}
|
@ -11,6 +11,7 @@
|
||||
|
||||
#include <gmock/gmock.h>
|
||||
|
||||
#include "test_shared.h"
|
||||
#include "controllers/scsi_controller.h"
|
||||
#include "devices/primary_device.h"
|
||||
#include "devices/scsihd.h"
|
||||
@ -20,7 +21,9 @@
|
||||
#include "devices/host_services.h"
|
||||
#include "rascsi/command_context.h"
|
||||
|
||||
class MockBus final : public BUS //NOSONAR Having many fields/methods cannot be avoided
|
||||
using namespace testing;
|
||||
|
||||
class MockBus : public BUS //NOSONAR Having many fields/methods cannot be avoided
|
||||
{
|
||||
public:
|
||||
|
||||
@ -78,8 +81,12 @@ public:
|
||||
using PhaseHandler::PhaseHandler;
|
||||
};
|
||||
|
||||
class MockAbstractController final : public AbstractController //NOSONAR Having many fields/methods cannot be avoided
|
||||
class MockAbstractController : public AbstractController //NOSONAR Having many fields/methods cannot be avoided
|
||||
{
|
||||
friend shared_ptr<PrimaryDevice> CreateDevice(rascsi_interface::PbDeviceType, AbstractController&, int);
|
||||
friend void TestInquiry(rascsi_interface::PbDeviceType, scsi_defs::device_type, scsi_defs::scsi_level,
|
||||
scsi_defs::scsi_level, const std::string&, int, bool);
|
||||
|
||||
FRIEND_TEST(AbstractControllerTest, Reset);
|
||||
FRIEND_TEST(AbstractControllerTest, ProcessPhase);
|
||||
FRIEND_TEST(AbstractControllerTest, DeviceLunLifeCycle);
|
||||
@ -93,6 +100,10 @@ class MockAbstractController final : public AbstractController //NOSONAR Having
|
||||
FRIEND_TEST(PrimaryDeviceTest, RequestSense);
|
||||
FRIEND_TEST(PrimaryDeviceTest, ReportLuns);
|
||||
FRIEND_TEST(PrimaryDeviceTest, UnknownCommand);
|
||||
FRIEND_TEST(ModePageDeviceTest, ModeSense6);
|
||||
FRIEND_TEST(ModePageDeviceTest, ModeSense10);
|
||||
FRIEND_TEST(ModePageDeviceTest, ModeSelect6);
|
||||
FRIEND_TEST(ModePageDeviceTest, ModeSelect10);
|
||||
FRIEND_TEST(DiskTest, Dispatch);
|
||||
FRIEND_TEST(DiskTest, Rezero);
|
||||
FRIEND_TEST(DiskTest, FormatUnit);
|
||||
@ -100,7 +111,8 @@ class MockAbstractController final : public AbstractController //NOSONAR Having
|
||||
FRIEND_TEST(DiskTest, Seek);
|
||||
FRIEND_TEST(DiskTest, ReadCapacity);
|
||||
FRIEND_TEST(DiskTest, ReadWriteLong);
|
||||
FRIEND_TEST(DiskTest, ReserveRelease);
|
||||
FRIEND_TEST(DiskTest, Reserve);
|
||||
FRIEND_TEST(DiskTest, Release);
|
||||
FRIEND_TEST(DiskTest, SendDiagnostic);
|
||||
FRIEND_TEST(DiskTest, PreventAllowMediumRemoval);
|
||||
FRIEND_TEST(DiskTest, SynchronizeCache);
|
||||
@ -128,10 +140,12 @@ public:
|
||||
}
|
||||
~MockAbstractController() override = default;
|
||||
|
||||
vector<int>& InitCmd(int size) { return AbstractController::InitCmd(size); } //NOSONAR Hides function on purpose
|
||||
|
||||
MockBus bus;
|
||||
};
|
||||
|
||||
class MockScsiController final : public ScsiController
|
||||
class MockScsiController : public ScsiController
|
||||
{
|
||||
FRIEND_TEST(ScsiControllerTest, RequestSense);
|
||||
FRIEND_TEST(PrimaryDeviceTest, RequestSense);
|
||||
@ -150,7 +164,7 @@ public:
|
||||
MockBus bus;
|
||||
};
|
||||
|
||||
class MockDevice final : public Device
|
||||
class MockDevice : public Device
|
||||
{
|
||||
FRIEND_TEST(DeviceTest, Params);
|
||||
FRIEND_TEST(DeviceTest, StatusCode);
|
||||
@ -167,7 +181,7 @@ public:
|
||||
~MockDevice() override = default;
|
||||
};
|
||||
|
||||
class MockPrimaryDevice final : public PrimaryDevice
|
||||
class MockPrimaryDevice : public PrimaryDevice
|
||||
{
|
||||
FRIEND_TEST(PrimaryDeviceTest, PhaseChange);
|
||||
FRIEND_TEST(PrimaryDeviceTest, TestUnitReady);
|
||||
@ -185,17 +199,19 @@ public:
|
||||
~MockPrimaryDevice() override = default;
|
||||
};
|
||||
|
||||
class MockModePageDevice final : public ModePageDevice
|
||||
class MockModePageDevice : public ModePageDevice
|
||||
{
|
||||
FRIEND_TEST(ModePagesTest, ModePageDevice_AddModePages);
|
||||
FRIEND_TEST(ModePageDeviceTest, AddModePages);
|
||||
|
||||
explicit MockModePageDevice(int lun) : ModePageDevice("test", lun) {}
|
||||
~MockModePageDevice() override = default;
|
||||
public:
|
||||
|
||||
MOCK_METHOD(vector<byte>, InquiryInternal, (), (const));
|
||||
MOCK_METHOD(int, ModeSense6, (const vector<int>&, vector<BYTE>&), (const override));
|
||||
MOCK_METHOD(int, ModeSense10, (const vector<int>&, vector<BYTE>&), (const override));
|
||||
|
||||
explicit MockModePageDevice() : ModePageDevice("test", 0) {}
|
||||
~MockModePageDevice() override = default;
|
||||
|
||||
void SetUpModePages(map<int, vector<byte>>& pages, int page, bool) const override {
|
||||
// Return dummy data for other pages than page 0
|
||||
if (page) {
|
||||
@ -205,7 +221,7 @@ class MockModePageDevice final : public ModePageDevice
|
||||
}
|
||||
};
|
||||
|
||||
class MockDisk final : public Disk
|
||||
class MockDisk : public Disk
|
||||
{
|
||||
FRIEND_TEST(DiskTest, Rezero);
|
||||
FRIEND_TEST(DiskTest, FormatUnit);
|
||||
@ -220,6 +236,7 @@ class MockDisk final : public Disk
|
||||
FRIEND_TEST(DiskTest, ReadDefectData);
|
||||
FRIEND_TEST(DiskTest, SectorSize);
|
||||
FRIEND_TEST(DiskTest, BlockCount);
|
||||
FRIEND_TEST(DiskTest, GetIdsForReservedFile);
|
||||
|
||||
public:
|
||||
|
||||
@ -230,41 +247,39 @@ public:
|
||||
~MockDisk() override = default;
|
||||
};
|
||||
|
||||
class MockSCSIHD final : public SCSIHD
|
||||
class MockSCSIHD : public SCSIHD
|
||||
{
|
||||
FRIEND_TEST(DiskTest, ConfiguredSectorSize);
|
||||
FRIEND_TEST(ModePagesTest, SCSIHD_SetUpModePages);
|
||||
FRIEND_TEST(ScsiHdTest, SetUpModePages);
|
||||
FRIEND_TEST(RascsiExecutorTest, SetSectorSize);
|
||||
|
||||
using SCSIHD::SCSIHD;
|
||||
};
|
||||
|
||||
class MockSCSIHD_NEC final : public SCSIHD_NEC //NOSONAR Ignore inheritance hierarchy depth in unit tests
|
||||
class MockSCSIHD_NEC : public SCSIHD_NEC //NOSONAR Ignore inheritance hierarchy depth in unit tests
|
||||
{
|
||||
FRIEND_TEST(ModePagesTest, SCSIHD_NEC_SetUpModePages);
|
||||
|
||||
MOCK_METHOD(void, FlushCache, (), (override));
|
||||
FRIEND_TEST(ScsiHdNecTest, SetUpModePages);
|
||||
|
||||
using SCSIHD_NEC::SCSIHD_NEC;
|
||||
};
|
||||
|
||||
class MockSCSICD final : public SCSICD
|
||||
class MockSCSICD : public SCSICD
|
||||
{
|
||||
FRIEND_TEST(ModePagesTest, SCSICD_SetUpModePages);
|
||||
FRIEND_TEST(ScsiCdTest, SetUpModePages);
|
||||
|
||||
using SCSICD::SCSICD;
|
||||
};
|
||||
|
||||
class MockSCSIMO final : public SCSIMO
|
||||
class MockSCSIMO : public SCSIMO
|
||||
{
|
||||
FRIEND_TEST(ModePagesTest, SCSIMO_SetUpModePages);
|
||||
FRIEND_TEST(ScsiMoTest, SetUpModePages);
|
||||
|
||||
using SCSIMO::SCSIMO;
|
||||
};
|
||||
|
||||
class MockHostServices final : public HostServices
|
||||
class MockHostServices : public HostServices
|
||||
{
|
||||
FRIEND_TEST(ModePagesTest, HostServices_SetUpModePages);
|
||||
FRIEND_TEST(HostServicesTest, SetUpModePages);
|
||||
|
||||
using HostServices::HostServices;
|
||||
};
|
||||
|
100
src/raspberrypi/test/mode_page_device_test.cpp
Normal file
100
src/raspberrypi/test/mode_page_device_test.cpp
Normal 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";
|
||||
}
|
@ -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);
|
||||
}
|
@ -16,25 +16,81 @@ TEST(PhaseHandlerTest, Phases)
|
||||
|
||||
handler.SetPhase(BUS::phase_t::selection);
|
||||
EXPECT_TRUE(handler.IsSelection());
|
||||
EXPECT_FALSE(handler.IsBusFree());
|
||||
EXPECT_FALSE(handler.IsCommand());
|
||||
EXPECT_FALSE(handler.IsStatus());
|
||||
EXPECT_FALSE(handler.IsDataIn());
|
||||
EXPECT_FALSE(handler.IsDataOut());
|
||||
EXPECT_FALSE(handler.IsMsgIn());
|
||||
EXPECT_FALSE(handler.IsMsgOut());
|
||||
|
||||
handler.SetPhase(BUS::phase_t::busfree);
|
||||
EXPECT_TRUE(handler.IsBusFree());
|
||||
EXPECT_FALSE(handler.IsSelection());
|
||||
EXPECT_FALSE(handler.IsCommand());
|
||||
EXPECT_FALSE(handler.IsStatus());
|
||||
EXPECT_FALSE(handler.IsDataIn());
|
||||
EXPECT_FALSE(handler.IsDataOut());
|
||||
EXPECT_FALSE(handler.IsMsgIn());
|
||||
EXPECT_FALSE(handler.IsMsgOut());
|
||||
|
||||
handler.SetPhase(BUS::phase_t::command);
|
||||
EXPECT_TRUE(handler.IsCommand());
|
||||
EXPECT_FALSE(handler.IsBusFree());
|
||||
EXPECT_FALSE(handler.IsSelection());
|
||||
EXPECT_FALSE(handler.IsStatus());
|
||||
EXPECT_FALSE(handler.IsDataIn());
|
||||
EXPECT_FALSE(handler.IsDataOut());
|
||||
EXPECT_FALSE(handler.IsMsgIn());
|
||||
EXPECT_FALSE(handler.IsMsgOut());
|
||||
|
||||
handler.SetPhase(BUS::phase_t::status);
|
||||
EXPECT_TRUE(handler.IsStatus());
|
||||
EXPECT_FALSE(handler.IsBusFree());
|
||||
EXPECT_FALSE(handler.IsSelection());
|
||||
EXPECT_FALSE(handler.IsCommand());
|
||||
EXPECT_FALSE(handler.IsDataIn());
|
||||
EXPECT_FALSE(handler.IsDataOut());
|
||||
EXPECT_FALSE(handler.IsMsgIn());
|
||||
EXPECT_FALSE(handler.IsMsgOut());
|
||||
|
||||
handler.SetPhase(BUS::phase_t::datain);
|
||||
EXPECT_TRUE(handler.IsDataIn());
|
||||
EXPECT_FALSE(handler.IsBusFree());
|
||||
EXPECT_FALSE(handler.IsSelection());
|
||||
EXPECT_FALSE(handler.IsCommand());
|
||||
EXPECT_FALSE(handler.IsStatus());
|
||||
EXPECT_FALSE(handler.IsDataOut());
|
||||
EXPECT_FALSE(handler.IsMsgIn());
|
||||
EXPECT_FALSE(handler.IsMsgOut());
|
||||
|
||||
handler.SetPhase(BUS::phase_t::dataout);
|
||||
EXPECT_TRUE(handler.IsDataOut());
|
||||
EXPECT_FALSE(handler.IsBusFree());
|
||||
EXPECT_FALSE(handler.IsSelection());
|
||||
EXPECT_FALSE(handler.IsCommand());
|
||||
EXPECT_FALSE(handler.IsStatus());
|
||||
EXPECT_FALSE(handler.IsDataIn());
|
||||
EXPECT_FALSE(handler.IsMsgIn());
|
||||
EXPECT_FALSE(handler.IsMsgOut());
|
||||
|
||||
handler.SetPhase(BUS::phase_t::msgin);
|
||||
EXPECT_TRUE(handler.IsMsgIn());
|
||||
EXPECT_FALSE(handler.IsBusFree());
|
||||
EXPECT_FALSE(handler.IsSelection());
|
||||
EXPECT_FALSE(handler.IsCommand());
|
||||
EXPECT_FALSE(handler.IsStatus());
|
||||
EXPECT_FALSE(handler.IsDataIn());
|
||||
EXPECT_FALSE(handler.IsDataOut());
|
||||
EXPECT_FALSE(handler.IsMsgOut());
|
||||
|
||||
handler.SetPhase(BUS::phase_t::msgout);
|
||||
EXPECT_TRUE(handler.IsMsgOut());
|
||||
EXPECT_FALSE(handler.IsBusFree());
|
||||
EXPECT_FALSE(handler.IsSelection());
|
||||
EXPECT_FALSE(handler.IsCommand());
|
||||
EXPECT_FALSE(handler.IsStatus());
|
||||
EXPECT_FALSE(handler.IsDataIn());
|
||||
EXPECT_FALSE(handler.IsDataOut());
|
||||
EXPECT_FALSE(handler.IsMsgIn());
|
||||
}
|
||||
|
@ -56,25 +56,25 @@ TEST(PrimaryDeviceTest, TestUnitReady)
|
||||
device->SetAttn(true);
|
||||
device->SetReady(false);
|
||||
EXPECT_CALL(controller, DataIn()).Times(0);
|
||||
EXPECT_THROW(device->Dispatch(scsi_command::eCmdTestUnitReady), scsi_error_exception);
|
||||
EXPECT_THROW(device->Dispatch(scsi_command::eCmdTestUnitReady), scsi_exception);
|
||||
|
||||
device->SetReset(false);
|
||||
EXPECT_CALL(controller, DataIn()).Times(0);
|
||||
EXPECT_THROW(device->Dispatch(scsi_command::eCmdTestUnitReady), scsi_error_exception);
|
||||
EXPECT_THROW(device->Dispatch(scsi_command::eCmdTestUnitReady), scsi_exception);
|
||||
|
||||
device->SetReset(true);
|
||||
device->SetAttn(false);
|
||||
EXPECT_CALL(controller, DataIn()).Times(0);
|
||||
EXPECT_THROW(device->Dispatch(scsi_command::eCmdTestUnitReady), scsi_error_exception);
|
||||
EXPECT_THROW(device->Dispatch(scsi_command::eCmdTestUnitReady), scsi_exception);
|
||||
|
||||
device->SetReset(false);
|
||||
device->SetAttn(true);
|
||||
EXPECT_CALL(controller, DataIn()).Times(0);
|
||||
EXPECT_THROW(device->Dispatch(scsi_command::eCmdTestUnitReady), scsi_error_exception);
|
||||
EXPECT_THROW(device->Dispatch(scsi_command::eCmdTestUnitReady), scsi_exception);
|
||||
|
||||
device->SetAttn(false);
|
||||
EXPECT_CALL(controller, DataIn()).Times(0);
|
||||
EXPECT_THROW(device->Dispatch(scsi_command::eCmdTestUnitReady), scsi_error_exception);
|
||||
EXPECT_THROW(device->Dispatch(scsi_command::eCmdTestUnitReady), scsi_exception);
|
||||
|
||||
device->SetReady(true);
|
||||
EXPECT_CALL(controller, Status()).Times(1);
|
||||
@ -84,7 +84,7 @@ TEST(PrimaryDeviceTest, TestUnitReady)
|
||||
|
||||
TEST(PrimaryDeviceTest, Inquiry)
|
||||
{
|
||||
MockAbstractController controller(0);
|
||||
NiceMock<MockAbstractController> controller(0);
|
||||
auto device = make_shared<MockPrimaryDevice>(0);
|
||||
|
||||
device->SetController(&controller);
|
||||
@ -126,11 +126,11 @@ TEST(PrimaryDeviceTest, Inquiry)
|
||||
|
||||
cmd[1] = 0x01;
|
||||
EXPECT_CALL(controller, DataIn()).Times(0);
|
||||
EXPECT_THROW(device->Dispatch(scsi_command::eCmdInquiry), scsi_error_exception) << "EVPD bit is not supported";
|
||||
EXPECT_THROW(device->Dispatch(scsi_command::eCmdInquiry), scsi_exception) << "EVPD bit is not supported";
|
||||
|
||||
cmd[2] = 0x01;
|
||||
EXPECT_CALL(controller, DataIn()).Times(0);
|
||||
EXPECT_THROW(device->Dispatch(scsi_command::eCmdInquiry), scsi_error_exception) << "PAGE CODE field is not supported";
|
||||
EXPECT_THROW(device->Dispatch(scsi_command::eCmdInquiry), scsi_exception) << "PAGE CODE field is not supported";
|
||||
|
||||
cmd[1] = 0x00;
|
||||
cmd[2] = 0x00;
|
||||
@ -145,7 +145,7 @@ TEST(PrimaryDeviceTest, Inquiry)
|
||||
|
||||
TEST(PrimaryDeviceTest, RequestSense)
|
||||
{
|
||||
MockAbstractController controller(0);
|
||||
NiceMock<MockAbstractController> controller(0);
|
||||
auto device = make_shared<MockPrimaryDevice>(0);
|
||||
|
||||
controller.AddDevice(device);
|
||||
@ -155,7 +155,7 @@ TEST(PrimaryDeviceTest, RequestSense)
|
||||
cmd[4] = 255;
|
||||
|
||||
device->SetReady(false);
|
||||
EXPECT_THROW(device->Dispatch(scsi_command::eCmdRequestSense), scsi_error_exception);
|
||||
EXPECT_THROW(device->Dispatch(scsi_command::eCmdRequestSense), scsi_exception);
|
||||
|
||||
device->SetReady(true);
|
||||
EXPECT_CALL(controller, DataIn()).Times(1);
|
||||
@ -206,7 +206,7 @@ TEST(PrimaryDeviceTest, ReportLuns)
|
||||
EXPECT_EQ(LUN2, buffer[23]) << "Wrong LUN2 number";
|
||||
|
||||
cmd[2] = 0x01;
|
||||
EXPECT_THROW(device1->Dispatch(scsi_command::eCmdReportLuns), scsi_error_exception) << "Only SELECT REPORT mode 0 is supported";
|
||||
EXPECT_THROW(device1->Dispatch(scsi_command::eCmdReportLuns), scsi_exception) << "Only SELECT REPORT mode 0 is supported";
|
||||
}
|
||||
|
||||
TEST(PrimaryDeviceTest, UnknownCommand)
|
||||
@ -216,7 +216,6 @@ TEST(PrimaryDeviceTest, UnknownCommand)
|
||||
|
||||
controller.AddDevice(device);
|
||||
|
||||
controller.InitCmd(1);
|
||||
EXPECT_FALSE(device->Dispatch((scsi_command)0xFF));
|
||||
}
|
||||
|
||||
|
@ -16,12 +16,50 @@ using namespace rascsi_interface;
|
||||
|
||||
TEST(ProtobufSerializerTest, SerializeMessage)
|
||||
{
|
||||
PbResult message;
|
||||
PbResult result;
|
||||
ProtobufSerializer serializer;
|
||||
|
||||
int fd = open("/dev/null", O_WRONLY);
|
||||
ASSERT_NE(-1, fd);
|
||||
serializer.SerializeMessage(fd, message);
|
||||
int fd = open("/dev/zero", O_RDONLY);
|
||||
EXPECT_NE(-1, fd);
|
||||
EXPECT_THROW(serializer.DeserializeMessage(fd, result), io_exception) << "Writing the message header must fail";
|
||||
close(fd);
|
||||
|
||||
fd = open("/dev/null", O_WRONLY);
|
||||
EXPECT_NE(-1, fd);
|
||||
serializer.SerializeMessage(fd, result);
|
||||
EXPECT_THROW(serializer.SerializeMessage(-1, result), io_exception) << "Writing a message must fail";
|
||||
close(fd);
|
||||
}
|
||||
|
||||
TEST(ProtobufSerializerTest, DeserializeMessage)
|
||||
{
|
||||
PbResult result;
|
||||
ProtobufSerializer serializer;
|
||||
vector<byte> buf(1);
|
||||
|
||||
int fd = open("/dev/null", O_RDONLY);
|
||||
EXPECT_NE(-1, fd);
|
||||
EXPECT_THROW(serializer.DeserializeMessage(fd, result), io_exception) << "Reading the message header must fail";
|
||||
close(fd);
|
||||
|
||||
fd = open("/dev/zero", O_RDONLY);
|
||||
EXPECT_NE(-1, fd);
|
||||
EXPECT_THROW(serializer.DeserializeMessage(fd, result), io_exception) << "Reading a message must fail";
|
||||
close(fd);
|
||||
}
|
||||
|
||||
TEST(ProtobufSerializerTest, ReadBytes)
|
||||
{
|
||||
ProtobufSerializer serializer;
|
||||
vector<byte> buf(1);
|
||||
|
||||
int fd = open("/dev/null", O_RDONLY);
|
||||
EXPECT_NE(-1, fd);
|
||||
EXPECT_EQ(0, serializer.ReadBytes(fd, buf));
|
||||
close(fd);
|
||||
|
||||
fd = open("/dev/zero", O_RDONLY);
|
||||
EXPECT_NE(-1, fd);
|
||||
EXPECT_EQ(1, serializer.ReadBytes(fd, buf));
|
||||
close(fd);
|
||||
EXPECT_THROW(serializer.SerializeMessage(-1, message), io_exception);
|
||||
}
|
||||
|
@ -9,10 +9,10 @@
|
||||
|
||||
#include "mocks.h"
|
||||
#include "rascsi_interface.pb.h"
|
||||
#include "command_util.h"
|
||||
#include "protobuf_util.h"
|
||||
|
||||
using namespace rascsi_interface;
|
||||
using namespace command_util;
|
||||
using namespace protobuf_util;
|
||||
|
||||
void TestSpecialDevice(const string& name)
|
||||
{
|
||||
@ -59,3 +59,26 @@ TEST(CommandUtil, ParseParameters)
|
||||
TestSpecialDevice("printer");
|
||||
TestSpecialDevice("services");
|
||||
}
|
||||
|
||||
TEST(CommandUtil, SetPatternParams)
|
||||
{
|
||||
PbCommand command1;
|
||||
SetPatternParams(command1, "file");
|
||||
EXPECT_EQ("", GetParam(command1, "folder_pattern"));
|
||||
EXPECT_EQ("file", GetParam(command1, "file_pattern"));
|
||||
|
||||
PbCommand command2;
|
||||
SetPatternParams(command2, ":file");
|
||||
EXPECT_EQ("", GetParam(command2, "folder_pattern"));
|
||||
EXPECT_EQ("file", GetParam(command2, "file_pattern"));
|
||||
|
||||
PbCommand command3;
|
||||
SetPatternParams(command3, "folder:");
|
||||
EXPECT_EQ("folder", GetParam(command3, "folder_pattern"));
|
||||
EXPECT_EQ("", GetParam(command3, "file_pattern"));
|
||||
|
||||
PbCommand command4;
|
||||
SetPatternParams(command4, "folder:file");
|
||||
EXPECT_EQ("folder", GetParam(command4, "folder_pattern"));
|
||||
EXPECT_EQ("file", GetParam(command4, "file_pattern"));
|
||||
}
|
@ -35,36 +35,36 @@ TEST(RascsiExceptionsTest, FileNotFoundException)
|
||||
TEST(RascsiExceptionsTest, ScsiErrorException)
|
||||
{
|
||||
try {
|
||||
throw scsi_error_exception();
|
||||
throw scsi_exception();
|
||||
}
|
||||
catch(const scsi_error_exception& e) {
|
||||
catch(const scsi_exception& e) {
|
||||
EXPECT_EQ(sense_key::ABORTED_COMMAND, e.get_sense_key());
|
||||
EXPECT_EQ(asc::NO_ADDITIONAL_SENSE_INFORMATION, e.get_asc());
|
||||
EXPECT_EQ(status::CHECK_CONDITION, e.get_status());
|
||||
}
|
||||
|
||||
try {
|
||||
throw scsi_error_exception(sense_key::UNIT_ATTENTION);
|
||||
throw scsi_exception(sense_key::UNIT_ATTENTION);
|
||||
}
|
||||
catch(const scsi_error_exception& e) {
|
||||
catch(const scsi_exception& e) {
|
||||
EXPECT_EQ(sense_key::UNIT_ATTENTION, e.get_sense_key());
|
||||
EXPECT_EQ(asc::NO_ADDITIONAL_SENSE_INFORMATION, e.get_asc());
|
||||
EXPECT_EQ(status::CHECK_CONDITION, e.get_status());
|
||||
}
|
||||
|
||||
try {
|
||||
throw scsi_error_exception(sense_key::UNIT_ATTENTION, asc::LBA_OUT_OF_RANGE);
|
||||
throw scsi_exception(sense_key::UNIT_ATTENTION, asc::LBA_OUT_OF_RANGE);
|
||||
}
|
||||
catch(const scsi_error_exception& e) {
|
||||
catch(const scsi_exception& e) {
|
||||
EXPECT_EQ(sense_key::UNIT_ATTENTION, e.get_sense_key());
|
||||
EXPECT_EQ(asc::LBA_OUT_OF_RANGE, e.get_asc());
|
||||
EXPECT_EQ(status::CHECK_CONDITION, e.get_status());
|
||||
}
|
||||
|
||||
try {
|
||||
throw scsi_error_exception(sense_key::UNIT_ATTENTION, asc::LBA_OUT_OF_RANGE, status::BUSY);
|
||||
throw scsi_exception(sense_key::UNIT_ATTENTION, asc::LBA_OUT_OF_RANGE, status::BUSY);
|
||||
}
|
||||
catch(const scsi_error_exception& e) {
|
||||
catch(const scsi_exception& e) {
|
||||
EXPECT_EQ(sense_key::UNIT_ATTENTION, e.get_sense_key());
|
||||
EXPECT_EQ(asc::LBA_OUT_OF_RANGE, e.get_asc());
|
||||
EXPECT_EQ(status::BUSY, e.get_status());
|
||||
|
@ -8,7 +8,7 @@
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
#include "mocks.h"
|
||||
#include "command_util.h"
|
||||
#include "protobuf_util.h"
|
||||
#include "controllers/controller_manager.h"
|
||||
#include "devices/device_factory.h"
|
||||
#include "rascsi/command_context.h"
|
||||
@ -17,7 +17,7 @@
|
||||
#include "rascsi/rascsi_executor.h"
|
||||
|
||||
using namespace rascsi_interface;
|
||||
using namespace command_util;
|
||||
using namespace protobuf_util;
|
||||
|
||||
TEST(RascsiExecutorTest, ProcessCmd)
|
||||
{
|
||||
|
288
src/raspberrypi/test/rasctl_display_test.cpp
Normal file
288
src/raspberrypi/test/rasctl_display_test.cpp
Normal 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"));
|
||||
}
|
55
src/raspberrypi/test/rasctl_parser_test.cpp
Normal file
55
src/raspberrypi/test/rasctl_parser_test.cpp
Normal 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"));
|
||||
}
|
@ -25,3 +25,33 @@ TEST(RasUtilTest, GetAsInt)
|
||||
EXPECT_TRUE(GetAsInt("1234", result));
|
||||
EXPECT_EQ(1234, result);
|
||||
}
|
||||
|
||||
TEST(RasUtilTest, Banner)
|
||||
{
|
||||
EXPECT_FALSE(Banner("Test").empty());
|
||||
}
|
||||
|
||||
TEST(RasUtilTest, ListDevices)
|
||||
{
|
||||
list<PbDevice> devices;
|
||||
|
||||
EXPECT_FALSE(ListDevices(devices).empty());
|
||||
|
||||
PbDevice device;
|
||||
device.set_type(SCHD);
|
||||
devices.push_back(device);
|
||||
device.set_type(SCBR);
|
||||
devices.push_back(device);
|
||||
device.set_type(SCDP);
|
||||
devices.push_back(device);
|
||||
device.set_type(SCHS);
|
||||
devices.push_back(device);
|
||||
device.set_type(SCLP);
|
||||
devices.push_back(device);
|
||||
const string device_list = ListDevices(devices);
|
||||
EXPECT_FALSE(device_list.empty());
|
||||
EXPECT_NE(string::npos, device_list.find("X68000 HOST BRIDGE"));
|
||||
EXPECT_NE(string::npos, device_list.find("DaynaPort SCSI/Link"));
|
||||
EXPECT_NE(string::npos, device_list.find("Host Services"));
|
||||
EXPECT_NE(string::npos, device_list.find("SCSI Printer"));
|
||||
}
|
||||
|
@ -8,10 +8,47 @@
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
#include "mocks.h"
|
||||
#include "rascsi_exceptions.h"
|
||||
#include "devices/scsi_command_util.h"
|
||||
|
||||
using namespace scsi_command_util;
|
||||
|
||||
TEST(ScsiCommandUtilTest, ModeSelect)
|
||||
{
|
||||
const int LENGTH = 12;
|
||||
|
||||
vector<int> cdb(16);
|
||||
vector<BYTE> buf(255);
|
||||
|
||||
// PF (vendor-specific parameter format)
|
||||
cdb[1] = 0x00;
|
||||
EXPECT_THROW(ModeSelect(cdb, buf, LENGTH, 0), scsi_exception)
|
||||
<< "Vendor-specific parameters are not supported";
|
||||
|
||||
// PF (standard parameter format)
|
||||
cdb[1] = 0x10;
|
||||
// Request 512 bytes per sector
|
||||
buf[9] = 0x00;
|
||||
buf[10] = 0x02;
|
||||
buf[11] = 0x00;
|
||||
EXPECT_THROW(ModeSelect(cdb, buf, LENGTH, 256), scsi_exception)
|
||||
<< "Requested sector size does not match current sector size";
|
||||
|
||||
// Page 0
|
||||
buf[LENGTH] = 0x00;
|
||||
EXPECT_THROW(ModeSelect(cdb, buf, LENGTH + 2, 512), scsi_exception)
|
||||
<< "Unsupported page 0 was not rejected";
|
||||
|
||||
// Page 3 (Format Device Page)
|
||||
buf[LENGTH] = 0x03;
|
||||
EXPECT_THROW(ModeSelect(cdb, buf, LENGTH + 2, 512), scsi_exception)
|
||||
<< "Requested sector size does not match current sector size";
|
||||
|
||||
// Match the requested to the current sector size
|
||||
buf[LENGTH + 12] = 0x02;
|
||||
ModeSelect(cdb, buf, LENGTH + 2, 512);
|
||||
}
|
||||
|
||||
TEST(ScsiCommandUtilTest, EnrichFormatPage)
|
||||
{
|
||||
const int SECTOR_SIZE = 512;
|
||||
|
125
src/raspberrypi/test/scsi_daynaport_test.cpp
Normal file
125
src/raspberrypi/test/scsi_daynaport_test.cpp
Normal 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());
|
||||
}
|
16
src/raspberrypi/test/scsi_host_bridge_test.cpp
Normal file
16
src/raspberrypi/test/scsi_host_bridge_test.cpp
Normal 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);
|
||||
}
|
72
src/raspberrypi/test/scsi_printer_test.cpp
Normal file
72
src/raspberrypi/test/scsi_printer_test.cpp
Normal 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
Loading…
x
Reference in New Issue
Block a user