Merge branch 'develop' into feature_bpi4

This commit is contained in:
Tony Kuker 2022-10-25 19:45:10 -05:00
commit 5dc1cb45df
217 changed files with 971 additions and 6405 deletions

View File

@ -34,11 +34,11 @@ jobs:
- name: make standard - name: make standard
run: make all -j6 CONNECT_TYPE=STANDARD CROSS_COMPILE=arm-linux-gnueabihf- run: make all -j6 CONNECT_TYPE=STANDARD CROSS_COMPILE=arm-linux-gnueabihf-
working-directory: ./src/raspberrypi working-directory: ./cpp
- name: make fullspec - name: make fullspec
run: make all -j6 CONNECT_TYPE=FULLSPEC CROSS_COMPILE=arm-linux-gnueabihf- run: make all -j6 CONNECT_TYPE=FULLSPEC CROSS_COMPILE=arm-linux-gnueabihf-
working-directory: ./src/raspberrypi working-directory: ./cpp
# We need to tar the binary outputs to retain the executable # We need to tar the binary outputs to retain the executable
# file permission. Currently, actions/upload-artifact only # file permission. Currently, actions/upload-artifact only
@ -46,11 +46,11 @@ jobs:
# This is workaround for https://github.com/actions/upload-artifact/issues/38 # This is workaround for https://github.com/actions/upload-artifact/issues/38
- name: tar binary outputs - name: tar binary outputs
run: tar -czvf rascsi.tar.gz ./bin run: tar -czvf rascsi.tar.gz ./bin
working-directory: ./src/raspberrypi working-directory: ./cpp
- name: upload artifacts - name: upload artifacts
uses: actions/upload-artifact@v2 uses: actions/upload-artifact@v2
with: with:
name: arm-binaries name: arm-binaries
path: ./src/raspberrypi/rascsi.tar.gz path: ./cpp/rascsi.tar.gz

View File

@ -7,7 +7,7 @@ jobs:
runs-on: ubuntu-22.04 runs-on: ubuntu-22.04
env: env:
MAKEFLAGS: -j2 # Number of available processors MAKEFLAGS: -j2 # Number of available processors
SOURCES: src/raspberrypi SOURCES: cpp
SONAR_SCANNER_VERSION: 4.7.0.2747 SONAR_SCANNER_VERSION: 4.7.0.2747
SONAR_SERVER_URL: "https://sonarcloud.io" SONAR_SERVER_URL: "https://sonarcloud.io"
BUILD_WRAPPER_OUT_DIR: build_wrapper_output_directory # Directory where build-wrapper output will be placed BUILD_WRAPPER_OUT_DIR: build_wrapper_output_directory # Directory where build-wrapper output will be placed

View File

@ -68,7 +68,7 @@ RSYSLOG_LOG = /var/log/rascsi.log
USR_LOCAL_BIN = /usr/local/bin USR_LOCAL_BIN = /usr/local/bin
MAN_PAGE_DIR = /usr/local/man/man1 MAN_PAGE_DIR = /usr/local/man/man1
DOC_DIR = ../../doc DOC_DIR = ../doc
COVERAGE_DIR = ./coverage COVERAGE_DIR = ./coverage
COVERAGE_FILE = rascsi.dat COVERAGE_FILE = rascsi.dat
OS_FILES = ./os_integration OS_FILES = ./os_integration
@ -95,9 +95,7 @@ SRC_SHARED = \
protobuf_serializer.cpp protobuf_serializer.cpp
SRC_RASCSI_CORE = \ SRC_RASCSI_CORE = \
bus.cpp \ bus.cpp
filepath.cpp \
fileio.cpp
SRC_RASCSI_CORE += $(shell find ./rascsi -name '*.cpp') SRC_RASCSI_CORE += $(shell find ./rascsi -name '*.cpp')
SRC_RASCSI_CORE += $(shell find ./controllers -name '*.cpp') SRC_RASCSI_CORE += $(shell find ./controllers -name '*.cpp')
SRC_RASCSI_CORE += $(shell find ./devices -name '*.cpp') SRC_RASCSI_CORE += $(shell find ./devices -name '*.cpp')
@ -120,8 +118,7 @@ SRC_RASCTL = rasctl.cpp
SRC_RASDUMP = \ SRC_RASDUMP = \
rasdump.cpp \ rasdump.cpp \
bus.cpp \ bus.cpp \
filepath.cpp \ rasdump_fileio.cpp \
fileio.cpp \
rascsi_version.cpp rascsi_version.cpp
SRC_RASDUMP += $(shell find ./hal -name '*.cpp') SRC_RASDUMP += $(shell find ./hal -name '*.cpp')
@ -191,7 +188,7 @@ coverage: test
lcov: CXXFLAGS += --coverage lcov: CXXFLAGS += --coverage
lcov: test lcov: test
lcov -q -c -d . --include '*/raspberrypi/*' -o $(COVERAGE_FILE) --exclude '*/test/*' --exclude '*/interfaces/*' --exclude '*/rascsi_interface.pb*' lcov -q -c -d . --include '*/cpp/*' -o $(COVERAGE_FILE) --exclude '*/test/*' --exclude '*/interfaces/*' --exclude '*/rascsi_interface.pb*'
genhtml -q -o $(COVERAGE_DIR) --legend $(COVERAGE_FILE) genhtml -q -o $(COVERAGE_DIR) --legend $(COVERAGE_FILE)
docs: $(DOC_DIR)/rascsi_man_page.txt $(DOC_DIR)/rasctl_man_page.txt $(DOC_DIR)/scsimon_man_page.txt docs: $(DOC_DIR)/rascsi_man_page.txt $(DOC_DIR)/rasctl_man_page.txt $(DOC_DIR)/scsimon_man_page.txt

View File

@ -27,6 +27,8 @@
using namespace scsi_defs; using namespace scsi_defs;
const int ScsiController::LUN_MAX = 32;
ScsiController::ScsiController(shared_ptr<BUS> bus, int target_id) : AbstractController(bus, target_id, LUN_MAX) ScsiController::ScsiController(shared_ptr<BUS> bus, int target_id) : AbstractController(bus, target_id, LUN_MAX)
{ {
// The initial buffer size will default to either the default buffer size OR // The initial buffer size will default to either the default buffer size OR

View File

@ -52,7 +52,7 @@ class ScsiController : public AbstractController
public: public:
// Maximum number of logical units // Maximum number of logical units
static const int LUN_MAX = 32; static const int LUN_MAX;
ScsiController(shared_ptr<BUS>, int); ScsiController(shared_ptr<BUS>, int);
~ScsiController() override = default; ~ScsiController() override = default;

View File

@ -30,7 +30,7 @@ void CDTrack::Init(int track, uint32_t first, uint32_t last)
last_lba = last; last_lba = last;
} }
void CDTrack::SetPath(bool cdda, const Filepath& path) void CDTrack::SetPath(bool cdda, string_view path)
{ {
assert(valid); assert(valid);
@ -41,12 +41,11 @@ void CDTrack::SetPath(bool cdda, const Filepath& path)
imgpath = path; imgpath = path;
} }
void CDTrack::GetPath(Filepath& path) const string CDTrack::GetPath() const
{ {
assert(valid); assert(valid);
// Return the path (by reference) return imgpath;
path = imgpath;
} }
//--------------------------------------------------------------------------- //---------------------------------------------------------------------------

View File

@ -14,7 +14,9 @@
#pragma once #pragma once
#include "filepath.h" #include <string>
using namespace std;
class CDTrack final class CDTrack final
{ {
@ -26,8 +28,8 @@ public:
void Init(int track, uint32_t first, uint32_t last); void Init(int track, uint32_t first, uint32_t last);
// Properties // Properties
void SetPath(bool cdda, const Filepath& path); // Set the path void SetPath(bool, string_view); // Set the path
void GetPath(Filepath& path) const; // Get the path string GetPath() const; // Get the path
uint32_t GetFirst() const; // Get the start LBA uint32_t GetFirst() const; // Get the start LBA
uint32_t GetLast() const; // Get the last LBA uint32_t GetLast() const; // Get the last LBA
uint32_t GetBlocks() const; // Get the number of blocks uint32_t GetBlocks() const; // Get the number of blocks
@ -41,5 +43,6 @@ private:
uint32_t first_lba = 0; // First LBA uint32_t first_lba = 0; // First LBA
uint32_t last_lba = 0; // Last LBA uint32_t last_lba = 0; // Last LBA
bool audio = false; // Audio track flag bool audio = false; // Audio track flag
Filepath imgpath; // Image file path
string imgpath; // Image file path
}; };

View File

@ -19,7 +19,6 @@
#include "os.h" #include "os.h"
#include "log.h" #include "log.h"
#include "filepath.h"
#include "cfilesystem.h" #include "cfilesystem.h"
#include <dirent.h> #include <dirent.h>
#include <iconv.h> #include <iconv.h>

View File

@ -13,6 +13,10 @@
#pragma once #pragma once
using TCHAR = char;
static const int FILEPATH_MAX = 260;
//--------------------------------------------------------------------------- //---------------------------------------------------------------------------
// //
// Status code definitions // Status code definitions

View File

@ -373,20 +373,20 @@ bool CTapDriver::Init(const unordered_map<string, string>& const_params)
#endif #endif
} }
void CTapDriver::OpenDump(const Filepath& path) { void CTapDriver::OpenDump(const string& path) {
if (m_pcap == nullptr) { if (m_pcap == nullptr) {
m_pcap = pcap_open_dead(DLT_EN10MB, 65535); m_pcap = pcap_open_dead(DLT_EN10MB, 65535);
} }
if (m_pcap_dumper != nullptr) { if (m_pcap_dumper != nullptr) {
pcap_dump_close(m_pcap_dumper); pcap_dump_close(m_pcap_dumper);
} }
m_pcap_dumper = pcap_dump_open(m_pcap, path.GetPath()); m_pcap_dumper = pcap_dump_open(m_pcap, path.c_str());
if (m_pcap_dumper == nullptr) { if (m_pcap_dumper == nullptr) {
LOGERROR("Can't open pcap file: %s", pcap_geterr(m_pcap)) LOGERROR("Can't open pcap file: %s", pcap_geterr(m_pcap))
throw io_exception("Can't open pcap file"); throw io_exception("Can't open pcap file");
} }
LOGTRACE("%s Opened %s for dumping", __PRETTY_FUNCTION__, path.GetPath()) LOGTRACE("%s Opened %s for dumping", __PRETTY_FUNCTION__, path.c_str())
} }
bool CTapDriver::Enable() const bool CTapDriver::Enable() const

View File

@ -13,7 +13,6 @@
#include <pcap/pcap.h> #include <pcap/pcap.h>
#include <net/ethernet.h> #include <net/ethernet.h>
#include "filepath.h"
#include <unordered_map> #include <unordered_map>
#include <list> #include <list>
#include <string> #include <string>
@ -33,7 +32,7 @@ public:
CTapDriver& operator=(const CTapDriver&) = default; CTapDriver& operator=(const CTapDriver&) = default;
bool Init(const unordered_map<string, string>&); bool Init(const unordered_map<string, string>&);
void OpenDump(const Filepath& path); // Capture packets void OpenDump(const string& path); // Capture packets
void GetMacAddr(BYTE *mac) const; void GetMacAddr(BYTE *mac) const;
int Receive(BYTE *buf); int Receive(BYTE *buf);
int Send(const BYTE *buf, int len); int Send(const BYTE *buf, int len);

View File

@ -14,7 +14,6 @@
// //
//--------------------------------------------------------------------------- //---------------------------------------------------------------------------
#include "fileio.h"
#include "rascsi_exceptions.h" #include "rascsi_exceptions.h"
#include "dispatcher.h" #include "dispatcher.h"
#include "scsi_command_util.h" #include "scsi_command_util.h"
@ -79,17 +78,13 @@ bool Disk::Dispatch(scsi_command cmd)
void Disk::SetUpCache(off_t image_offset, bool raw) void Disk::SetUpCache(off_t image_offset, bool raw)
{ {
Filepath path; cache = make_unique<DiskCache>(GetFilename(), size_shift_count, (uint32_t)GetBlockCount(), image_offset);
path.SetPath(GetFilename().c_str());
cache = make_unique<DiskCache>(path, size_shift_count, (uint32_t)GetBlockCount(), image_offset);
cache->SetRawMode(raw); cache->SetRawMode(raw);
} }
void Disk::ResizeCache(const string& filename, bool raw) void Disk::ResizeCache(const string& path, bool raw)
{ {
Filepath path; cache.reset(new DiskCache(path, size_shift_count, (uint32_t)GetBlockCount()));
path.SetPath(filename.c_str());
cache.reset(new DiskCache(path, GetSectorSizeShiftCount(), (uint32_t)GetBlockCount()));
cache->SetRawMode(raw); cache->SetRawMode(raw);
} }
@ -501,8 +496,7 @@ int Disk::Read(const vector<int>&, vector<BYTE>& buf, uint64_t block)
throw scsi_exception(sense_key::MEDIUM_ERROR, asc::READ_FAULT); throw scsi_exception(sense_key::MEDIUM_ERROR, asc::READ_FAULT);
} }
// Success return GetSectorSizeInBytes();
return 1 << size_shift_count;
} }
int Disk::WriteCheck(uint64_t block) int Disk::WriteCheck(uint64_t block)
@ -519,18 +513,14 @@ int Disk::WriteCheck(uint64_t block)
throw scsi_exception(sense_key::DATA_PROTECT, asc::WRITE_PROTECTED); throw scsi_exception(sense_key::DATA_PROTECT, asc::WRITE_PROTECTED);
} }
// Success return GetSectorSizeInBytes();
return 1 << size_shift_count;
} }
void Disk::Write(const vector<int>&, const vector<BYTE>& buf, uint64_t block) void Disk::Write(const vector<int>&, const vector<BYTE>& buf, uint64_t block)
{ {
LOGTRACE("%s", __PRETTY_FUNCTION__) LOGTRACE("%s", __PRETTY_FUNCTION__)
// Error if not ready CheckReady();
if (!IsReady()) {
throw scsi_exception(sense_key::NOT_READY);
}
// Error if the total number of blocks is exceeded // Error if the total number of blocks is exceeded
if (block >= GetBlockCount()) { if (block >= GetBlockCount()) {

View File

@ -14,18 +14,17 @@
// //
//--------------------------------------------------------------------------- //---------------------------------------------------------------------------
#include "os.h"
#include "disk_track.h" #include "disk_track.h"
#include "disk_cache.h" #include "disk_cache.h"
#include <cstdlib> #include <cstdlib>
#include <cassert> #include <cassert>
DiskCache::DiskCache(const Filepath& path, int size, uint32_t blocks, off_t imgoff) DiskCache::DiskCache(const string& path, int size, uint32_t blocks, off_t imgoff)
: sec_size(size), sec_blocks(blocks), imgoffset(imgoff) : sec_path(path), sec_size(size), sec_blocks(blocks), imgoffset(imgoff)
{ {
assert(blocks > 0); assert(blocks > 0);
assert(imgoff >= 0); assert(imgoff >= 0);
sec_path = path;
} }
bool DiskCache::Save() const bool DiskCache::Save() const

View File

@ -15,9 +15,9 @@
#pragma once #pragma once
#include "filepath.h"
#include <array> #include <array>
#include <memory> #include <memory>
#include <string>
using namespace std; using namespace std;
@ -34,7 +34,7 @@ public:
uint32_t serial; // Serial uint32_t serial; // Serial
}; };
DiskCache(const Filepath& path, int size, uint32_t blocks, off_t imgoff = 0); DiskCache(const string&, int, uint32_t, off_t = 0);
~DiskCache() = default; ~DiskCache() = default;
void SetRawMode(bool b) { cd_raw = b; } // CD-ROM raw mode setting void SetRawMode(bool b) { cd_raw = b; } // CD-ROM raw mode setting
@ -55,7 +55,7 @@ private:
// Internal data // Internal data
array<cache_t, CACHE_MAX> cache = {}; // Cache management array<cache_t, CACHE_MAX> cache = {}; // Cache management
uint32_t serial = 0; // Last serial number uint32_t serial = 0; // Last serial number
Filepath sec_path; // Path string sec_path; // Path
int sec_size; // Sector Size (8=256, 9=512, 10=1024, 11=2048, 12=4096) int sec_size; // Sector Size (8=256, 9=512, 10=1024, 11=2048, 12=4096)
int sec_blocks; // Blocks per sector int sec_blocks; // Blocks per sector
bool cd_raw = false; // CD-ROM RAW mode bool cd_raw = false; // CD-ROM RAW mode

View File

@ -15,8 +15,8 @@
//--------------------------------------------------------------------------- //---------------------------------------------------------------------------
#include "log.h" #include "log.h"
#include "fileio.h"
#include "disk_track.h" #include "disk_track.h"
#include <fstream>
DiskTrack::~DiskTrack() DiskTrack::~DiskTrack()
{ {
@ -46,7 +46,7 @@ void DiskTrack::Init(int track, int size, int sectors, bool raw, off_t imgoff)
dt.imgoffset = imgoff; dt.imgoffset = imgoff;
} }
bool DiskTrack::Load(const Filepath& path) bool DiskTrack::Load(const string& path)
{ {
// Not needed if already loaded // Not needed if already loaded
if (dt.init) { if (dt.init) {
@ -97,24 +97,21 @@ bool DiskTrack::Load(const Filepath& path)
dt.changemap.resize(dt.sectors); dt.changemap.resize(dt.sectors);
fill(dt.changemap.begin(), dt.changemap.end(), false); fill(dt.changemap.begin(), dt.changemap.end(), false);
// Read from File ifstream in(path, ios::binary);
Fileio fio; if (in.fail()) {
if (!fio.OpenDIO(path, Fileio::OpenMode::ReadOnly)) {
return false; return false;
} }
if (dt.raw) { if (dt.raw) {
// Split Reading // Split Reading
for (int i = 0; i < dt.sectors; i++) { for (int i = 0; i < dt.sectors; i++) {
// Seek in.seekg(offset);
if (!fio.Seek(offset)) { if (in.fail()) {
fio.Close();
return false; return false;
} }
// Read in.read((char *)&dt.buffer[i << dt.size], 1 << dt.size);
if (!fio.Read(&dt.buffer[i << dt.size], 1 << dt.size)) { if (in.fail()) {
fio.Close();
return false; return false;
} }
@ -123,16 +120,15 @@ bool DiskTrack::Load(const Filepath& path)
} }
} else { } else {
// Continuous reading // Continuous reading
if (!fio.Seek(offset)) { in.seekg(offset);
fio.Close(); if (in.fail()) {
return false; return false;
} }
if (!fio.Read(dt.buffer, length)) { in.read((char *)dt.buffer, length);
fio.Close(); if (in.fail()) {
return false; return false;
} }
} }
fio.Close();
// Set a flag and end normally // Set a flag and end normally
dt.init = true; dt.init = true;
@ -140,7 +136,7 @@ bool DiskTrack::Load(const Filepath& path)
return true; return true;
} }
bool DiskTrack::Save(const Filepath& path) bool DiskTrack::Save(const string& path)
{ {
// Not needed if not initialized // Not needed if not initialized
if (!dt.init) { if (!dt.init) {
@ -169,9 +165,8 @@ bool DiskTrack::Save(const Filepath& path)
// Calculate length per sector // Calculate length per sector
const int length = 1 << dt.size; const int length = 1 << dt.size;
// Open file ofstream out(path, ios::in | ios::out | ios::binary);
Fileio fio; if (out.fail()) {
if (!fio.Open(path, Fileio::OpenMode::ReadWrite)) {
return false; return false;
} }
@ -183,9 +178,8 @@ bool DiskTrack::Save(const Filepath& path)
// Initialize write size // Initialize write size
total = 0; total = 0;
// Seek out.seekp(offset + ((off_t)i << dt.size));
if (!fio.Seek(offset + ((off_t)i << dt.size))) { if (out.fail()) {
fio.Close();
return false; return false;
} }
@ -201,9 +195,8 @@ bool DiskTrack::Save(const Filepath& path)
total += length; total += length;
} }
// Write out.write((const char *)&dt.buffer[i << dt.size], total);
if (!fio.Write(&dt.buffer[i << dt.size], total)) { if (out.fail()) {
fio.Close();
return false; return false;
} }
@ -215,8 +208,6 @@ bool DiskTrack::Save(const Filepath& path)
} }
} }
fio.Close();
// Drop the change flag and exit // Drop the change flag and exit
fill(dt.changemap.begin(), dt.changemap.end(), false); fill(dt.changemap.begin(), dt.changemap.end(), false);
dt.changed = false; dt.changed = false;

View File

@ -15,9 +15,10 @@
#pragma once #pragma once
#include "filepath.h" #include "os.h"
#include <cstdlib> #include <cstdlib>
#include <vector> #include <vector>
#include <string>
using namespace std; using namespace std;
@ -31,7 +32,7 @@ class DiskTrack
BYTE *buffer; // Data buffer BYTE *buffer; // Data buffer
bool init; // Is it initilized? bool init; // Is it initilized?
bool changed; // Changed flag bool changed; // Changed flag
std::vector<bool> changemap; // Changed map vector<bool> changemap; // Changed map
bool raw; // RAW mode flag bool raw; // RAW mode flag
off_t imgoffset; // Offset to actual data off_t imgoffset; // Offset to actual data
} dt = {}; } dt = {};
@ -48,12 +49,12 @@ private:
friend class DiskCache; friend class DiskCache;
void Init(int track, int size, int sectors, bool raw = false, off_t imgoff = 0); void Init(int track, int size, int sectors, bool raw = false, off_t imgoff = 0);
bool Load(const Filepath& path); bool Load(const string& path);
bool Save(const Filepath& path); bool Save(const string& path);
// Read / Write // Read / Write
bool ReadSector(vector<BYTE>&, int) const; // Sector Read bool ReadSector(vector<BYTE>&, int) const; // Sector Read
bool WriteSector(const vector<BYTE>& buf, int); // Sector Write bool WriteSector(const vector<BYTE>& buf, int); // Sector Write
int GetTrack() const { return dt.track; } // Get track int GetTrack() const { return dt.track; } // Get track
}; };

View File

@ -91,9 +91,7 @@ bool SCSIDaynaPort::Init(const unordered_map<string, string>& params)
void SCSIDaynaPort::Open() void SCSIDaynaPort::Open()
{ {
Filepath path; m_tap.OpenDump(GetFilename().c_str());
path.SetPath(GetFilename().c_str());
m_tap.OpenDump(path);
} }
vector<byte> SCSIDaynaPort::InquiryInternal() const vector<byte> SCSIDaynaPort::InquiryInternal() const

View File

@ -39,7 +39,7 @@ public:
bool Dispatch(scsi_command) override; bool Dispatch(scsi_command) override;
// TODO Remove as soon as SCSIBR is not a subclass of Disk anymore // TODO Remove as soon as SCSIBR is not a subclass of Disk anymore
void Open() override { super::ValidateFile(GetFilename()); } void Open() override { super::ValidateFile(); }
// Commands // Commands
vector<byte> InquiryInternal() const override; vector<byte> InquiryInternal() const override;

View File

@ -17,6 +17,7 @@
// 2. The client triggers printing with SYNCHRONIZE BUFFER. Each SYNCHRONIZE BUFFER results in // 2. The client triggers printing with SYNCHRONIZE BUFFER. Each SYNCHRONIZE BUFFER results in
// the print command for this printer (see below) to be called for the data not yet printed. // the print command for this printer (see below) to be called for the data not yet printed.
// //
// It is recommended to reserve the printer device before printing and to release it afterwards.
// The command to be used for printing can be set with the "cmd" property when attaching the device. // The command to be used for printing can be set with the "cmd" property when attaching the device.
// By default the data to be printed are sent to the printer unmodified, using "lp -oraw %f". This // By default the data to be printed are sent to the printer unmodified, using "lp -oraw %f". This
// requires that the client uses a printer driver compatible with the respective printer, or that the // requires that the client uses a printer driver compatible with the respective printer, or that the
@ -33,8 +34,10 @@
#include "scsi_command_util.h" #include "scsi_command_util.h"
#include "dispatcher.h" #include "dispatcher.h"
#include "scsi_printer.h" #include "scsi_printer.h"
#include <filesystem>
using namespace std; using namespace std;
using namespace filesystem;
using namespace scsi_defs; using namespace scsi_defs;
using namespace scsi_command_util; using namespace scsi_command_util;
@ -43,13 +46,18 @@ SCSIPrinter::SCSIPrinter(int lun) : PrimaryDevice(SCLP, lun)
dispatcher.Add(scsi_command::eCmdTestUnitReady, "TestUnitReady", &SCSIPrinter::TestUnitReady); dispatcher.Add(scsi_command::eCmdTestUnitReady, "TestUnitReady", &SCSIPrinter::TestUnitReady);
dispatcher.Add(scsi_command::eCmdPrint, "Print", &SCSIPrinter::Print); dispatcher.Add(scsi_command::eCmdPrint, "Print", &SCSIPrinter::Print);
dispatcher.Add(scsi_command::eCmdSynchronizeBuffer, "SynchronizeBuffer", &SCSIPrinter::SynchronizeBuffer); dispatcher.Add(scsi_command::eCmdSynchronizeBuffer, "SynchronizeBuffer", &SCSIPrinter::SynchronizeBuffer);
dispatcher.Add(scsi_command::eCmdStopPrint, "StopPrint", &SCSIPrinter::StopPrint); // STOP PRINT is identical with TEST UNIT READY, it just returns the status
dispatcher.Add(scsi_command::eCmdStopPrint, "StopPrint", &SCSIPrinter::TestUnitReady);
// Required also in this class in order to fulfill the ScsiPrinterCommands interface contract // Required also in this class in order to fulfill the ScsiPrinterCommands interface contract
dispatcher.Add(scsi_command::eCmdReserve6, "ReserveUnit", &SCSIPrinter::ReserveUnit); dispatcher.Add(scsi_command::eCmdReserve6, "ReserveUnit", &SCSIPrinter::ReserveUnit);
dispatcher.Add(scsi_command::eCmdRelease6, "ReleaseUnit", &SCSIPrinter::ReleaseUnit); dispatcher.Add(scsi_command::eCmdRelease6, "ReleaseUnit", &SCSIPrinter::ReleaseUnit);
dispatcher.Add(scsi_command::eCmdSendDiag, "SendDiagnostic", &SCSIPrinter::SendDiagnostic); dispatcher.Add(scsi_command::eCmdSendDiag, "SendDiagnostic", &SCSIPrinter::SendDiagnostic);
error_code error;
file_template = temp_directory_path(error); //NOSONAR Publicly writable directory is fine here
file_template += PRINTER_FILE_PATTERN;
SupportsParams(true); SupportsParams(true);
SetReady(true); SetReady(true);
} }
@ -109,70 +117,75 @@ void SCSIPrinter::Print()
void SCSIPrinter::SynchronizeBuffer() void SCSIPrinter::SynchronizeBuffer()
{ {
if (fd == -1) { if (!out.is_open()) {
LOGWARN("Missing printer output file") LOGWARN("Nothing to print")
throw scsi_exception(sense_key::ABORTED_COMMAND); throw scsi_exception(sense_key::ABORTED_COMMAND);
} }
struct stat st;
fstat(fd, &st);
close(fd);
fd = -1;
string cmd = GetParam("cmd"); string cmd = GetParam("cmd");
const size_t file_position = cmd.find("%f"); const size_t file_position = cmd.find("%f");
assert(file_position != string::npos); assert(file_position != string::npos);
cmd.replace(file_position, 2, filename); cmd.replace(file_position, 2, filename);
LOGTRACE("%s", string("Printing file with size of " + to_string(st.st_size) +" byte(s)").c_str()) error_code error;
LOGTRACE("Printing file '%s' with %s byte(s)", filename.c_str(), to_string(file_size(path(filename), error)).c_str())
LOGDEBUG("Executing '%s'", cmd.c_str()) LOGDEBUG("Executing '%s'", cmd.c_str())
if (system(cmd.c_str())) { if (system(cmd.c_str())) {
LOGERROR("Printing failed, the printing system might not be configured") LOGERROR("Printing file '%s' failed, the printing system might not be configured", filename.c_str())
unlink(filename); Cleanup();
throw scsi_exception(sense_key::ABORTED_COMMAND); throw scsi_exception(sense_key::ABORTED_COMMAND);
} }
unlink(filename); Cleanup();
EnterStatusPhase(); EnterStatusPhase();
} }
void SCSIPrinter::StopPrint()
{
// Command implementations are identical
TestUnitReady();
}
bool SCSIPrinter::WriteByteSequence(vector<BYTE>& buf, uint32_t length) bool SCSIPrinter::WriteByteSequence(vector<BYTE>& buf, uint32_t length)
{ {
if (fd == -1) { if (!out.is_open()) {
strcpy(filename, TMP_FILE_PATTERN); //NOSONAR Using strcpy is safe here vector<char> f(file_template.begin(), file_template.end());
fd = mkstemp(filename); f.push_back(0);
// There is no C++ API that generates a file with a unique name
const int fd = mkstemp(f.data());
if (fd == -1) { if (fd == -1) {
LOGERROR("Can't create printer output file '%s': %s", filename, strerror(errno)) LOGERROR("Can't create printer output file for pattern '%s': %s", filename.c_str(), strerror(errno))
return false; return false;
} }
close(fd);
LOGTRACE("Created printer output file '%s'", filename) filename = f.data();
out.open(filename, ios::binary);
if (out.fail()) {
throw scsi_exception(sense_key::ABORTED_COMMAND);
}
LOGTRACE("Created printer output file '%s'", filename.c_str())
} }
LOGTRACE("Appending %d byte(s) to printer output file '%s'", length, filename) LOGTRACE("Appending %d byte(s) to printer output file '%s'", length, filename.c_str())
return (uint32_t)write(fd, buf.data(), length) == length; out.write((const char*)buf.data(), length);
return !out.fail();
} }
void SCSIPrinter::Cleanup() void SCSIPrinter::Cleanup()
{ {
if (fd != -1) { if (out.is_open()) {
close(fd); out.close();
fd = -1;
unlink(filename); error_code error;
remove(path(filename), error);
filename = "";
} }
} }

View File

@ -12,16 +12,18 @@
#include "interfaces/scsi_printer_commands.h" #include "interfaces/scsi_printer_commands.h"
#include "primary_device.h" #include "primary_device.h"
#include <fstream>
#include <string> #include <string>
#include <unordered_map> #include <unordered_map>
using namespace std;
class SCSIPrinter : public PrimaryDevice, 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"; //NOSONAR Using /tmp is safe
static const int TMP_FILENAME_LENGTH = string_view(TMP_FILE_PATTERN).size();
static const int NOT_RESERVED = -2; static const int NOT_RESERVED = -2;
static constexpr const char *PRINTER_FILE_PATTERN = "/rascsi_sclp-XXXXXX";
public: public:
explicit SCSIPrinter(int); explicit SCSIPrinter(int);
@ -39,7 +41,6 @@ public:
void SendDiagnostic() override { PrimaryDevice::SendDiagnostic(); } void SendDiagnostic() override { PrimaryDevice::SendDiagnostic(); }
void Print() override; void Print() override;
void SynchronizeBuffer(); void SynchronizeBuffer();
void StopPrint();
bool WriteByteSequence(vector<BYTE>&, uint32_t) override; bool WriteByteSequence(vector<BYTE>&, uint32_t) override;
@ -49,6 +50,9 @@ private:
Dispatcher<SCSIPrinter> dispatcher; Dispatcher<SCSIPrinter> dispatcher;
char filename[TMP_FILENAME_LENGTH + 1]; //NOSONAR mkstemp() requires a modifiable string string file_template;
int fd = -1;
string filename;
ofstream out;
}; };

View File

@ -14,12 +14,12 @@
// //
//--------------------------------------------------------------------------- //---------------------------------------------------------------------------
#include "fileio.h"
#include "rascsi_exceptions.h" #include "rascsi_exceptions.h"
#include "scsi_command_util.h" #include "scsi_command_util.h"
#include "dispatcher.h" #include "dispatcher.h"
#include "scsicd.h" #include "scsicd.h"
#include <array> #include <array>
#include <fstream>
using namespace scsi_defs; using namespace scsi_defs;
using namespace scsi_command_util; using namespace scsi_command_util;
@ -50,48 +50,29 @@ void SCSICD::Open()
rawfile = false; rawfile = false;
ClearTrack(); ClearTrack();
// Open as read-only
Filepath path;
path.SetPath(GetFilename().c_str());
Fileio fio;
if (!fio.Open(path, Fileio::OpenMode::ReadOnly)) {
throw file_not_found_exception("Can't open CD-ROM file '" + GetFilename() + "'");
}
// Default sector size is 2048 bytes // Default sector size is 2048 bytes
SetSectorSizeInBytes(GetConfiguredSectorSize() ? GetConfiguredSectorSize() : 2048); SetSectorSizeInBytes(GetConfiguredSectorSize() ? GetConfiguredSectorSize() : 2048);
// Close and transfer for physical CD access if (GetFilename()[0] == '\\') {
if (path.GetPath()[0] == '\\') {
// Close
fio.Close();
// Open physical CD
OpenPhysical(); OpenPhysical();
} else { } else {
if (GetFileSize() < 4) { // Judge whether it is a CUE sheet or an ISO file
fio.Close(); array<char, 4> cue;
throw io_exception("CD-ROM file size must be at least 4 bytes"); ifstream in(GetFilename(), ios::binary);
in.read(cue.data(), cue.size());
if (!in.good()) {
throw io_exception("Can't read header of CD-ROM file '" + GetFilename() + "'");
} }
// Judge whether it is a CUE sheet or an ISO file // If it starts with FILE consider it a CUE sheet
array<TCHAR, 5> file; if (!strncasecmp(cue.data(), "FILE", cue.size())) {
fio.Read((BYTE *)file.data(), 4); throw io_exception("CUE CD-ROM files are not supported");
file[4] = '\0';
fio.Close();
// If it starts with FILE, consider it as a CUE sheet
if (!strcasecmp(file.data(), "FILE")) {
throw io_exception("Opening CUE CD-ROM files is not supported");
} else { } else {
OpenIso(); OpenIso();
} }
} }
// Successful opening super::ValidateFile();
assert(GetBlockCount() > 0);
super::ValidateFile(GetFilename());
SetUpCache(0, rawfile); SetUpCache(0, rawfile);
@ -106,80 +87,56 @@ void SCSICD::Open()
void SCSICD::OpenIso() void SCSICD::OpenIso()
{ {
// Open as read-only
Fileio fio;
if (!fio.Open(GetFilename().c_str(), Fileio::OpenMode::ReadOnly)) {
throw io_exception("Can't open ISO CD-ROM file");
}
// Get file size
const off_t size = GetFileSize(); const off_t size = GetFileSize();
if (size < 0x800) { if (size < 2048) {
fio.Close();
throw io_exception("ISO CD-ROM file size must be at least 2048 bytes"); throw io_exception("ISO CD-ROM file size must be at least 2048 bytes");
} }
// Read the first 12 bytes and close // Validate header
array<BYTE, 12> header; array<char, 16> header;
if (!fio.Read(header.data(), header.size())) { ifstream in(GetFilename(), ios::binary);
fio.Close(); in.read(header.data(), header.size());
if (!in.good()) {
throw io_exception("Can't read header of ISO CD-ROM file"); throw io_exception("Can't read header of ISO CD-ROM file");
} }
// Check if it is RAW format // Check if it is in RAW format
array<BYTE, 12> sync; array<char, 12> sync = {};
sync.fill(0xff); // 00,FFx10,00 is presumed to be RAW format
sync[0] = 0x00; fill_n(sync.begin() + 1, 10, 0xff);
sync[11] = 0x00;
rawfile = false; rawfile = false;
if (memcmp(header.data(), sync.data(), sync.size()) == 0) {
// 00,FFx10,00, so it is presumed to be RAW format
if (!fio.Read(header.data(), 4)) {
fio.Close();
throw io_exception("Can't read header of raw ISO CD-ROM file");
}
if (memcmp(header.data(), sync.data(), sync.size()) == 0) {
// Supports MODE1/2048 or MODE1/2352 only // Supports MODE1/2048 or MODE1/2352 only
if (header[3] != 0x01) { if (header[15] != 0x01) {
// Different mode // Different mode
fio.Close();
throw io_exception("Illegal raw ISO CD-ROM file header"); throw io_exception("Illegal raw ISO CD-ROM file header");
} }
// Set to RAW file // Set to RAW file
rawfile = true; rawfile = true;
} }
fio.Close();
if (rawfile) { if (rawfile) {
// Size must be a multiple of 2536
if (size % 2536) { if (size % 2536) {
throw io_exception("Raw ISO CD-ROM file size must be a multiple of 2536 bytes but is " throw io_exception("Raw ISO CD-ROM file size must be a multiple of 2536 bytes but is "
+ to_string(size) + " bytes"); + to_string(size) + " bytes");
} }
// Set the number of blocks SetBlockCount((uint32_t)(size / 2352));
SetBlockCount((uint32_t)(size / 0x930));
} else { } else {
// Set the number of blocks
SetBlockCount((uint32_t)(size >> GetSectorSizeShiftCount())); SetBlockCount((uint32_t)(size >> GetSectorSizeShiftCount()));
} }
CreateDataTrack(); CreateDataTrack();
} }
// TODO This code is only executed if the filename starts with a `\`, but fails to open files starting with `\`.
void SCSICD::OpenPhysical() void SCSICD::OpenPhysical()
{ {
// Open as read-only
Fileio fio;
if (!fio.Open(GetFilename().c_str(), Fileio::OpenMode::ReadOnly)) {
throw file_not_found_exception("Can't open CD-ROM file '" + GetFilename() + "'");
}
fio.Close();
// Get size // Get size
off_t size = GetFileSize(); off_t size = GetFileSize();
if (size < 0x800) { if (size < 2048) {
throw io_exception("CD-ROM file size must be at least 2048 bytes"); throw io_exception("CD-ROM file size must be at least 2048 bytes");
} }
@ -198,9 +155,7 @@ void SCSICD::CreateDataTrack()
assert(!tracks.size()); assert(!tracks.size());
auto track = make_unique<CDTrack>(); auto track = make_unique<CDTrack>();
track->Init(1, 0, (int)GetBlockCount() - 1); track->Init(1, 0, (int)GetBlockCount() - 1);
Filepath path; track->SetPath(false, GetFilename());
path.SetPath(GetFilename().c_str());
track->SetPath(false, path);
tracks.push_back(move(track)); tracks.push_back(move(track));
dataindex = 0; dataindex = 0;
} }
@ -287,12 +242,8 @@ int SCSICD::Read(const vector<int>& cdb, vector<BYTE>& buf, uint64_t block)
SetBlockCount(tracks[index]->GetBlocks()); SetBlockCount(tracks[index]->GetBlocks());
assert(GetBlockCount() > 0); assert(GetBlockCount() > 0);
// Recreate the disk cache
Filepath path;
tracks[index]->GetPath(path);
// Re-assign disk cache (no need to save) // Re-assign disk cache (no need to save)
ResizeCache(path.GetPath(), rawfile); ResizeCache(tracks[index]->GetPath(), rawfile);
// Reset data index // Reset data index
dataindex = index; dataindex = index;

View File

@ -5,17 +5,15 @@
// //
// Copyright (C) 2001-2006 (ytanaka@ipc-tokai.or.jp) // Copyright (C) 2001-2006 (ytanaka@ipc-tokai.or.jp)
// Copyright (C) 2014-2020 GIMONS // Copyright (C) 2014-2020 GIMONS
// Copyright (C) 2022 Uwe Seimet
// Copyright (C) akuker // Copyright (C) akuker
// //
// Licensed under the BSD 3-Clause License. // Licensed under the BSD 3-Clause License.
// See LICENSE file in the project root folder. // See LICENSE file in the project root folder.
// //
// [ SCSI hard disk ]
//
//--------------------------------------------------------------------------- //---------------------------------------------------------------------------
#include "scsihd.h" #include "scsihd.h"
#include "fileio.h"
#include "rascsi_exceptions.h" #include "rascsi_exceptions.h"
#include "scsi_command_util.h" #include "scsi_command_util.h"
@ -56,23 +54,15 @@ string SCSIHD::GetProductData() const
return DEFAULT_PRODUCT + " " + to_string(capacity) + " " + unit; return DEFAULT_PRODUCT + " " + to_string(capacity) + " " + unit;
} }
void SCSIHD::FinalizeSetup(off_t size, off_t image_offset) void SCSIHD::FinalizeSetup(off_t image_offset)
{ {
// Effective size must be a multiple of the sector size super::ValidateFile();
size = (size / GetSectorSizeInBytes()) * GetSectorSizeInBytes();
// 2 TiB is the current maximum
if (size > 2LL * 1024 * 1024 * 1024 * 1024) {
throw io_exception("Drive capacity cannot exceed 2 TiB");
}
// For non-removable media drives set the default product name based on the drive capacity // For non-removable media drives set the default product name based on the drive capacity
if (!IsRemovable()) { if (!IsRemovable()) {
SetProduct(GetProductData(), false); SetProduct(GetProductData(), false);
} }
super::ValidateFile(GetFilename());
SetUpCache(image_offset); SetUpCache(image_offset);
} }
@ -86,7 +76,7 @@ void SCSIHD::Open()
SetSectorSizeInBytes(GetConfiguredSectorSize() ? GetConfiguredSectorSize() : 512); SetSectorSizeInBytes(GetConfiguredSectorSize() ? GetConfiguredSectorSize() : 512);
SetBlockCount((uint32_t)(size >> GetSectorSizeShiftCount())); SetBlockCount((uint32_t)(size >> GetSectorSizeShiftCount()));
FinalizeSetup(size); FinalizeSetup(0);
} }
vector<byte> SCSIHD::InquiryInternal() const vector<byte> SCSIHD::InquiryInternal() const

View File

@ -5,19 +5,21 @@
// //
// Copyright (C) 2001-2006 (ytanaka@ipc-tokai.or.jp) // Copyright (C) 2001-2006 (ytanaka@ipc-tokai.or.jp)
// Copyright (C) 2014-2020 GIMONS // Copyright (C) 2014-2020 GIMONS
// Copyright (C) 2022 Uwe Seimet
// Copyright (C) akuker // Copyright (C) akuker
// //
// Licensed under the BSD 3-Clause License. // Licensed under the BSD 3-Clause License.
// See LICENSE file in the project root folder. // See LICENSE file in the project root folder.
// //
// [ SCSI hard disk ]
//
//--------------------------------------------------------------------------- //---------------------------------------------------------------------------
#pragma once #pragma once
#include "scsi.h"
#include "disk.h" #include "disk.h"
#include <string> #include <string>
#include <vector>
#include <map>
class SCSIHD : public Disk class SCSIHD : public Disk
{ {
@ -28,7 +30,7 @@ public:
SCSIHD(int, const unordered_set<uint32_t>&, bool, scsi_defs::scsi_level = scsi_level::SCSI_2); SCSIHD(int, const unordered_set<uint32_t>&, bool, scsi_defs::scsi_level = scsi_level::SCSI_2);
~SCSIHD() override = default; ~SCSIHD() override = default;
void FinalizeSetup(off_t, off_t = 0); void FinalizeSetup(off_t);
void Open() override; void Open() override;

View File

@ -14,11 +14,13 @@
// //
//--------------------------------------------------------------------------- //---------------------------------------------------------------------------
#include "scsihd_nec.h"
#include "fileio.h"
#include "rascsi_exceptions.h" #include "rascsi_exceptions.h"
#include "rasutil.h"
#include "scsi_command_util.h" #include "scsi_command_util.h"
#include "scsihd_nec.h"
#include <fstream>
using namespace ras_util;
using namespace scsi_command_util; using namespace scsi_command_util;
const unordered_set<uint32_t> SCSIHD_NEC::sector_sizes = { 512 }; const unordered_set<uint32_t> SCSIHD_NEC::sector_sizes = { 512 };
@ -27,64 +29,38 @@ void SCSIHD_NEC::Open()
{ {
assert(!IsReady()); assert(!IsReady());
// Open as read-only
Filepath path;
path.SetPath(GetFilename().c_str());
Fileio fio;
if (!fio.Open(path, Fileio::OpenMode::ReadOnly)) {
throw file_not_found_exception("Can't open hard disk file '" + GetFilename() + '"');
}
off_t size = GetFileSize(); off_t size = GetFileSize();
// NEC root sector array<char, 512> root_sector;
array<BYTE, 512> root_sector; ifstream in(GetFilename(), ios::binary);
if (size < (off_t)root_sector.size() || !fio.Read(root_sector.data(), root_sector.size())) { in.read(root_sector.data(), root_sector.size());
fio.Close(); if (!in.good() || size < (off_t)root_sector.size()) {
throw io_exception("Can't read NEC hard disk file root sector"); throw io_exception("Can't read NEC hard disk file root sector");
} }
fio.Close();
// Effective size must be a multiple of 512 // Effective size must be a multiple of 512
size = (size / 512) * 512; size = (size / 512) * 512;
// Determine parameters by extension // Determine parameters by extension
const auto [image_size, sector_size] = SetParameters(path.GetFileExt(), root_sector, (int)size); const auto [image_size, sector_size] = SetParameters(root_sector, (int)size);
if (sector_size == 0) {
throw io_exception("Invalid NEC drive sector size");
}
// Image size consistency check
if (image_offset + image_size > size || image_size % sector_size != 0) {
throw io_exception("Image size consistency check failed");
}
// Calculate sector size
for (size = 16; size > 0; --size) {
if ((1 << size) == sector_size)
break;
}
if (size <= 0 || size > 16) {
throw io_exception("Invalid NEC disk size");
}
SetSectorSizeShiftCount((uint32_t)size); SetSectorSizeShiftCount((uint32_t)size);
SetBlockCount(image_size >> GetSectorSizeShiftCount()); SetBlockCount(image_size >> GetSectorSizeShiftCount());
FinalizeSetup(size, image_offset); FinalizeSetup(image_offset);
} }
pair<int, int> SCSIHD_NEC::SetParameters(const string& extension, const array<BYTE, 512>& root_sector, int size) pair<int, int> SCSIHD_NEC::SetParameters(const array<char, 512>& data, int size)
{ {
string ext = extension; array<BYTE, 512> root_sector = {};
transform(ext.begin(), ext.end(), ext.begin(), ::tolower); memcpy(root_sector.data(), data.data(), root_sector.size());
int image_size; int image_size;
int sector_size; int sector_size;
// PC-9801-55 NEC compatible? // PC-9801-55 NEC compatible?
if (ext == ".hdn") { if (const string ext = GetExtensionLowerCase(GetFilename()); ext == "hdn") {
// Assuming sector size 512, number of sectors 25, number of heads 8 as default settings // Assuming sector size 512, number of sectors 25, number of heads 8 as default settings
image_offset = 0; image_offset = 0;
image_size = size; image_size = size;
@ -96,7 +72,7 @@ pair<int, int> SCSIHD_NEC::SetParameters(const string& extension, const array<BY
cylinders /= 25; cylinders /= 25;
} }
// Anex86 HD image? // Anex86 HD image?
else if (ext == ".hdi") { else if (ext == "hdi") {
image_offset = GetInt32LittleEndian(&root_sector[8]); image_offset = GetInt32LittleEndian(&root_sector[8]);
image_size = GetInt32LittleEndian(&root_sector[12]); image_size = GetInt32LittleEndian(&root_sector[12]);
sector_size = GetInt32LittleEndian(&root_sector[16]); sector_size = GetInt32LittleEndian(&root_sector[16]);
@ -105,7 +81,7 @@ pair<int, int> SCSIHD_NEC::SetParameters(const string& extension, const array<BY
cylinders = GetInt32LittleEndian(&root_sector[28]); cylinders = GetInt32LittleEndian(&root_sector[28]);
} }
// T98Next HD image? // T98Next HD image?
else if (ext == ".nhd") { else if (ext == "nhd") {
if (!memcmp(root_sector.data(), "T98HDDIMAGE.R0\0", 15)) { if (!memcmp(root_sector.data(), "T98HDDIMAGE.R0\0", 15)) {
image_offset = GetInt32LittleEndian(&root_sector[0x110]); image_offset = GetInt32LittleEndian(&root_sector[0x110]);
cylinders = GetInt32LittleEndian(&root_sector[0x114]); cylinders = GetInt32LittleEndian(&root_sector[0x114]);
@ -122,6 +98,19 @@ pair<int, int> SCSIHD_NEC::SetParameters(const string& extension, const array<BY
throw io_exception("Invalid NEC image file extension"); throw io_exception("Invalid NEC image file extension");
} }
if (sector_size == 0) {
throw io_exception("Invalid NEC sector size 0");
}
// Image size consistency check
if (image_offset + image_size > size) {
throw io_exception("NEC image offset/size consistency check failed");
}
if (CalculateShiftCount(sector_size) == 0) {
throw io_exception("Invalid NEC sector size of " + to_string(sector_size) + " byte(s)");
}
return make_pair(image_size, sector_size); return make_pair(image_size, sector_size);
} }

View File

@ -47,14 +47,14 @@ protected:
private: private:
pair<int, int> SetParameters(const string&, const array<BYTE, 512>&, int); pair<int, int> SetParameters(const array<char, 512>&, int);
static int GetInt16LittleEndian(const BYTE *); static int GetInt16LittleEndian(const BYTE *);
static int GetInt32LittleEndian(const BYTE *); static int GetInt32LittleEndian(const BYTE *);
static const unordered_set<uint32_t> sector_sizes; static const unordered_set<uint32_t> sector_sizes;
// Image file offset (NEC only) // Image file offset
off_t image_offset = 0; off_t image_offset = 0;
// Geometry data // Geometry data

View File

@ -12,7 +12,6 @@
// //
//--------------------------------------------------------------------------- //---------------------------------------------------------------------------
#include "fileio.h"
#include "rascsi_exceptions.h" #include "rascsi_exceptions.h"
#include "scsi_command_util.h" #include "scsi_command_util.h"
#include "scsimo.h" #include "scsimo.h"
@ -43,21 +42,14 @@ void SCSIMO::Open()
{ {
assert(!IsReady()); assert(!IsReady());
off_t size = GetFileSize();
// 2 TiB is the current maximum
if (size > 2LL * 1024 * 1024 * 1024 * 1024) {
throw io_exception("Drive capacity cannot exceed 2 TiB");
}
// For some capacities there are hard-coded, well-defined sector sizes and block counts // For some capacities there are hard-coded, well-defined sector sizes and block counts
if (!SetGeometryForCapacity(size)) { if (const off_t size = GetFileSize(); !SetGeometryForCapacity(size)) {
// Sector size (default 512 bytes) and number of blocks // Sector size (default 512 bytes) and number of blocks
SetSectorSizeInBytes(GetConfiguredSectorSize() ? GetConfiguredSectorSize() : 512); SetSectorSizeInBytes(GetConfiguredSectorSize() ? GetConfiguredSectorSize() : 512);
SetBlockCount(size >> GetSectorSizeShiftCount()); SetBlockCount(size >> GetSectorSizeShiftCount());
} }
super::ValidateFile(GetFilename()); super::ValidateFile();
SetUpCache(0); SetUpCache(0);

View File

@ -15,6 +15,8 @@
#pragma once #pragma once
#include "disk.h" #include "disk.h"
#include <vector>
#include <map>
using Geometry = pair<uint32_t, uint32_t>; using Geometry = pair<uint32_t, uint32_t>;

View File

@ -23,14 +23,22 @@ StorageDevice::StorageDevice(PbDeviceType type, int lun) : ModePageDevice(type,
SetStoppable(true); SetStoppable(true);
} }
void StorageDevice::ValidateFile(const string& file) void StorageDevice::ValidateFile()
{ {
if (blocks == 0) { if (blocks == 0) {
throw io_exception(string(GetTypeString()) + " device has 0 blocks"); throw io_exception(string(GetTypeString()) + " device has 0 blocks");
} }
if (!exists(path(filename))) {
throw file_not_found_exception("Image file '" + filename + "' for " + GetTypeString() + " device does not exist");
}
if (GetFileSize() > 2LL * 1024 * 1024 * 1024 * 1024) {
throw io_exception("Drive capacity cannot exceed 2 TiB");
}
// TODO Check for duplicate handling of these properties (-> rascsi_executor.cpp) // TODO Check for duplicate handling of these properties (-> rascsi_executor.cpp)
if (access(file.c_str(), W_OK)) { if (access(filename.c_str(), W_OK)) {
// Permanently write-protected // Permanently write-protected
SetReadOnly(true); SetReadOnly(true);
SetProtectable(false); SetProtectable(false);
@ -65,16 +73,13 @@ void StorageDevice::UnreserveFile()
filename = ""; filename = "";
} }
bool StorageDevice::GetIdsForReservedFile(const string& file, int& id, int& lun) pair<int, int> StorageDevice::GetIdsForReservedFile(const string& file)
{ {
if (const auto& it = reserved_files.find(file); it != reserved_files.end()) { if (const auto& it = reserved_files.find(file); it != reserved_files.end()) {
id = it->second.first; return make_pair(it->second.first, it->second.second);
lun = it->second.second;
return true;
} }
return false; return make_pair(-1, -1);
} }
void StorageDevice::UnreserveAll() void StorageDevice::UnreserveAll()
@ -94,7 +99,7 @@ bool StorageDevice::IsReadOnlyFile() const
off_t StorageDevice::GetFileSize() const off_t StorageDevice::GetFileSize() const
{ {
// filesystem::file_size cannot be used here because gcc < 10.3.0 cannot handled more than 2 GiB // filesystem::file_size cannot be used here because gcc < 10.3.0 cannot handle more than 2 GiB
if (struct stat st; !stat(filename.c_str(), &st)) { if (struct stat st; !stat(filename.c_str(), &st)) {
return st.st_size; return st.st_size;
} }

View File

@ -28,7 +28,6 @@ public:
virtual void Open() = 0; virtual void Open() = 0;
void ValidateFile(const string&);
string GetFilename() const { return filename; } string GetFilename() const { return filename; }
void SetFilename(string_view f) { filename = f; } void SetFilename(string_view f) { filename = f; }
@ -45,10 +44,12 @@ public:
static unordered_map<string, id_set> GetReservedFiles() { return reserved_files; } static unordered_map<string, id_set> GetReservedFiles() { return reserved_files; }
static void SetReservedFiles(const unordered_map<string, id_set>& r) { reserved_files = r; } static void SetReservedFiles(const unordered_map<string, id_set>& r) { reserved_files = r; }
static bool GetIdsForReservedFile(const string&, int&, int&); static pair<int, int> GetIdsForReservedFile(const string&);
protected: protected:
void ValidateFile();
bool IsMediumChanged() const { return medium_changed; } bool IsMediumChanged() const { return medium_changed; }
void SetMediumChanged(bool b) { medium_changed = b; } void SetMediumChanged(bool b) { medium_changed = b; }

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