mirror of
https://github.com/akuker/RASCSI.git
synced 2025-04-16 12:37:06 +00:00
Merge branch 'develop' into feature_bpi4
This commit is contained in:
commit
5dc1cb45df
8
.github/workflows/build_code.yml
vendored
8
.github/workflows/build_code.yml
vendored
@ -34,11 +34,11 @@ jobs:
|
||||
|
||||
- name: make standard
|
||||
run: make all -j6 CONNECT_TYPE=STANDARD CROSS_COMPILE=arm-linux-gnueabihf-
|
||||
working-directory: ./src/raspberrypi
|
||||
working-directory: ./cpp
|
||||
|
||||
- name: make fullspec
|
||||
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
|
||||
# file permission. Currently, actions/upload-artifact only
|
||||
@ -46,11 +46,11 @@ jobs:
|
||||
# This is workaround for https://github.com/actions/upload-artifact/issues/38
|
||||
- name: tar binary outputs
|
||||
run: tar -czvf rascsi.tar.gz ./bin
|
||||
working-directory: ./src/raspberrypi
|
||||
working-directory: ./cpp
|
||||
|
||||
- name: upload artifacts
|
||||
uses: actions/upload-artifact@v2
|
||||
with:
|
||||
name: arm-binaries
|
||||
path: ./src/raspberrypi/rascsi.tar.gz
|
||||
path: ./cpp/rascsi.tar.gz
|
||||
|
||||
|
2
.github/workflows/run_tests.yml
vendored
2
.github/workflows/run_tests.yml
vendored
@ -7,7 +7,7 @@ jobs:
|
||||
runs-on: ubuntu-22.04
|
||||
env:
|
||||
MAKEFLAGS: -j2 # Number of available processors
|
||||
SOURCES: src/raspberrypi
|
||||
SOURCES: cpp
|
||||
SONAR_SCANNER_VERSION: 4.7.0.2747
|
||||
SONAR_SERVER_URL: "https://sonarcloud.io"
|
||||
BUILD_WRAPPER_OUT_DIR: build_wrapper_output_directory # Directory where build-wrapper output will be placed
|
||||
|
@ -68,7 +68,7 @@ RSYSLOG_LOG = /var/log/rascsi.log
|
||||
|
||||
USR_LOCAL_BIN = /usr/local/bin
|
||||
MAN_PAGE_DIR = /usr/local/man/man1
|
||||
DOC_DIR = ../../doc
|
||||
DOC_DIR = ../doc
|
||||
COVERAGE_DIR = ./coverage
|
||||
COVERAGE_FILE = rascsi.dat
|
||||
OS_FILES = ./os_integration
|
||||
@ -95,9 +95,7 @@ SRC_SHARED = \
|
||||
protobuf_serializer.cpp
|
||||
|
||||
SRC_RASCSI_CORE = \
|
||||
bus.cpp \
|
||||
filepath.cpp \
|
||||
fileio.cpp
|
||||
bus.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')
|
||||
@ -120,8 +118,7 @@ SRC_RASCTL = rasctl.cpp
|
||||
SRC_RASDUMP = \
|
||||
rasdump.cpp \
|
||||
bus.cpp \
|
||||
filepath.cpp \
|
||||
fileio.cpp \
|
||||
rasdump_fileio.cpp \
|
||||
rascsi_version.cpp
|
||||
SRC_RASDUMP += $(shell find ./hal -name '*.cpp')
|
||||
|
||||
@ -191,7 +188,7 @@ coverage: test
|
||||
|
||||
lcov: CXXFLAGS += --coverage
|
||||
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)
|
||||
|
||||
docs: $(DOC_DIR)/rascsi_man_page.txt $(DOC_DIR)/rasctl_man_page.txt $(DOC_DIR)/scsimon_man_page.txt
|
@ -27,6 +27,8 @@
|
||||
|
||||
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)
|
||||
{
|
||||
// The initial buffer size will default to either the default buffer size OR
|
@ -52,7 +52,7 @@ class ScsiController : public AbstractController
|
||||
public:
|
||||
|
||||
// Maximum number of logical units
|
||||
static const int LUN_MAX = 32;
|
||||
static const int LUN_MAX;
|
||||
|
||||
ScsiController(shared_ptr<BUS>, int);
|
||||
~ScsiController() override = default;
|
@ -30,7 +30,7 @@ void CDTrack::Init(int track, uint32_t first, uint32_t last)
|
||||
last_lba = last;
|
||||
}
|
||||
|
||||
void CDTrack::SetPath(bool cdda, const Filepath& path)
|
||||
void CDTrack::SetPath(bool cdda, string_view path)
|
||||
{
|
||||
assert(valid);
|
||||
|
||||
@ -41,12 +41,11 @@ void CDTrack::SetPath(bool cdda, const Filepath& path)
|
||||
imgpath = path;
|
||||
}
|
||||
|
||||
void CDTrack::GetPath(Filepath& path) const
|
||||
string CDTrack::GetPath() const
|
||||
{
|
||||
assert(valid);
|
||||
|
||||
// Return the path (by reference)
|
||||
path = imgpath;
|
||||
return imgpath;
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
@ -14,7 +14,9 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "filepath.h"
|
||||
#include <string>
|
||||
|
||||
using namespace std;
|
||||
|
||||
class CDTrack final
|
||||
{
|
||||
@ -26,8 +28,8 @@ public:
|
||||
void Init(int track, uint32_t first, uint32_t last);
|
||||
|
||||
// Properties
|
||||
void SetPath(bool cdda, const Filepath& path); // Set the path
|
||||
void GetPath(Filepath& path) const; // Get the path
|
||||
void SetPath(bool, string_view); // Set the path
|
||||
string GetPath() const; // Get the path
|
||||
uint32_t GetFirst() const; // Get the start LBA
|
||||
uint32_t GetLast() const; // Get the last LBA
|
||||
uint32_t GetBlocks() const; // Get the number of blocks
|
||||
@ -41,5 +43,6 @@ private:
|
||||
uint32_t first_lba = 0; // First LBA
|
||||
uint32_t last_lba = 0; // Last LBA
|
||||
bool audio = false; // Audio track flag
|
||||
Filepath imgpath; // Image file path
|
||||
|
||||
string imgpath; // Image file path
|
||||
};
|
@ -19,7 +19,6 @@
|
||||
|
||||
#include "os.h"
|
||||
#include "log.h"
|
||||
#include "filepath.h"
|
||||
#include "cfilesystem.h"
|
||||
#include <dirent.h>
|
||||
#include <iconv.h>
|
@ -13,6 +13,10 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
using TCHAR = char;
|
||||
|
||||
static const int FILEPATH_MAX = 260;
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
//
|
||||
// Status code definitions
|
@ -373,20 +373,20 @@ bool CTapDriver::Init(const unordered_map<string, string>& const_params)
|
||||
#endif
|
||||
}
|
||||
|
||||
void CTapDriver::OpenDump(const Filepath& path) {
|
||||
void CTapDriver::OpenDump(const string& path) {
|
||||
if (m_pcap == nullptr) {
|
||||
m_pcap = pcap_open_dead(DLT_EN10MB, 65535);
|
||||
}
|
||||
if (m_pcap_dumper != nullptr) {
|
||||
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) {
|
||||
LOGERROR("Can't open pcap file: %s", pcap_geterr(m_pcap))
|
||||
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
|
@ -13,7 +13,6 @@
|
||||
|
||||
#include <pcap/pcap.h>
|
||||
#include <net/ethernet.h>
|
||||
#include "filepath.h"
|
||||
#include <unordered_map>
|
||||
#include <list>
|
||||
#include <string>
|
||||
@ -33,7 +32,7 @@ public:
|
||||
CTapDriver& operator=(const CTapDriver&) = default;
|
||||
|
||||
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;
|
||||
int Receive(BYTE *buf);
|
||||
int Send(const BYTE *buf, int len);
|
@ -14,7 +14,6 @@
|
||||
//
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
#include "fileio.h"
|
||||
#include "rascsi_exceptions.h"
|
||||
#include "dispatcher.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)
|
||||
{
|
||||
Filepath path;
|
||||
path.SetPath(GetFilename().c_str());
|
||||
cache = make_unique<DiskCache>(path, size_shift_count, (uint32_t)GetBlockCount(), image_offset);
|
||||
cache = make_unique<DiskCache>(GetFilename(), size_shift_count, (uint32_t)GetBlockCount(), image_offset);
|
||||
cache->SetRawMode(raw);
|
||||
}
|
||||
|
||||
void Disk::ResizeCache(const string& filename, bool raw)
|
||||
void Disk::ResizeCache(const string& path, bool raw)
|
||||
{
|
||||
Filepath path;
|
||||
path.SetPath(filename.c_str());
|
||||
cache.reset(new DiskCache(path, GetSectorSizeShiftCount(), (uint32_t)GetBlockCount()));
|
||||
cache.reset(new DiskCache(path, size_shift_count, (uint32_t)GetBlockCount()));
|
||||
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);
|
||||
}
|
||||
|
||||
// Success
|
||||
return 1 << size_shift_count;
|
||||
return GetSectorSizeInBytes();
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
// Success
|
||||
return 1 << size_shift_count;
|
||||
return GetSectorSizeInBytes();
|
||||
}
|
||||
|
||||
void Disk::Write(const vector<int>&, const vector<BYTE>& buf, uint64_t block)
|
||||
{
|
||||
LOGTRACE("%s", __PRETTY_FUNCTION__)
|
||||
|
||||
// Error if not ready
|
||||
if (!IsReady()) {
|
||||
throw scsi_exception(sense_key::NOT_READY);
|
||||
}
|
||||
CheckReady();
|
||||
|
||||
// Error if the total number of blocks is exceeded
|
||||
if (block >= GetBlockCount()) {
|
@ -14,18 +14,17 @@
|
||||
//
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
#include "os.h"
|
||||
#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)
|
||||
DiskCache::DiskCache(const string& path, int size, uint32_t blocks, off_t imgoff)
|
||||
: sec_path(path), sec_size(size), sec_blocks(blocks), imgoffset(imgoff)
|
||||
{
|
||||
assert(blocks > 0);
|
||||
assert(imgoff >= 0);
|
||||
|
||||
sec_path = path;
|
||||
}
|
||||
|
||||
bool DiskCache::Save() const
|
@ -15,9 +15,9 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "filepath.h"
|
||||
#include <array>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
|
||||
using namespace std;
|
||||
|
||||
@ -34,7 +34,7 @@ public:
|
||||
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;
|
||||
|
||||
void SetRawMode(bool b) { cd_raw = b; } // CD-ROM raw mode setting
|
||||
@ -55,7 +55,7 @@ private:
|
||||
// Internal data
|
||||
array<cache_t, CACHE_MAX> cache = {}; // Cache management
|
||||
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_blocks; // Blocks per sector
|
||||
bool cd_raw = false; // CD-ROM RAW mode
|
@ -15,8 +15,8 @@
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
#include "log.h"
|
||||
#include "fileio.h"
|
||||
#include "disk_track.h"
|
||||
#include <fstream>
|
||||
|
||||
DiskTrack::~DiskTrack()
|
||||
{
|
||||
@ -46,7 +46,7 @@ void DiskTrack::Init(int track, int size, int sectors, bool raw, off_t imgoff)
|
||||
dt.imgoffset = imgoff;
|
||||
}
|
||||
|
||||
bool DiskTrack::Load(const Filepath& path)
|
||||
bool DiskTrack::Load(const string& path)
|
||||
{
|
||||
// Not needed if already loaded
|
||||
if (dt.init) {
|
||||
@ -97,24 +97,21 @@ bool DiskTrack::Load(const Filepath& path)
|
||||
dt.changemap.resize(dt.sectors);
|
||||
fill(dt.changemap.begin(), dt.changemap.end(), false);
|
||||
|
||||
// Read from File
|
||||
Fileio fio;
|
||||
if (!fio.OpenDIO(path, Fileio::OpenMode::ReadOnly)) {
|
||||
ifstream in(path, ios::binary);
|
||||
if (in.fail()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (dt.raw) {
|
||||
// Split Reading
|
||||
for (int i = 0; i < dt.sectors; i++) {
|
||||
// Seek
|
||||
if (!fio.Seek(offset)) {
|
||||
fio.Close();
|
||||
in.seekg(offset);
|
||||
if (in.fail()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Read
|
||||
if (!fio.Read(&dt.buffer[i << dt.size], 1 << dt.size)) {
|
||||
fio.Close();
|
||||
in.read((char *)&dt.buffer[i << dt.size], 1 << dt.size);
|
||||
if (in.fail()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -123,16 +120,15 @@ bool DiskTrack::Load(const Filepath& path)
|
||||
}
|
||||
} else {
|
||||
// Continuous reading
|
||||
if (!fio.Seek(offset)) {
|
||||
fio.Close();
|
||||
in.seekg(offset);
|
||||
if (in.fail()) {
|
||||
return false;
|
||||
}
|
||||
if (!fio.Read(dt.buffer, length)) {
|
||||
fio.Close();
|
||||
in.read((char *)dt.buffer, length);
|
||||
if (in.fail()) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
fio.Close();
|
||||
|
||||
// Set a flag and end normally
|
||||
dt.init = true;
|
||||
@ -140,7 +136,7 @@ bool DiskTrack::Load(const Filepath& path)
|
||||
return true;
|
||||
}
|
||||
|
||||
bool DiskTrack::Save(const Filepath& path)
|
||||
bool DiskTrack::Save(const string& path)
|
||||
{
|
||||
// Not needed if not initialized
|
||||
if (!dt.init) {
|
||||
@ -169,9 +165,8 @@ bool DiskTrack::Save(const Filepath& path)
|
||||
// Calculate length per sector
|
||||
const int length = 1 << dt.size;
|
||||
|
||||
// Open file
|
||||
Fileio fio;
|
||||
if (!fio.Open(path, Fileio::OpenMode::ReadWrite)) {
|
||||
ofstream out(path, ios::in | ios::out | ios::binary);
|
||||
if (out.fail()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -183,9 +178,8 @@ bool DiskTrack::Save(const Filepath& path)
|
||||
// Initialize write size
|
||||
total = 0;
|
||||
|
||||
// Seek
|
||||
if (!fio.Seek(offset + ((off_t)i << dt.size))) {
|
||||
fio.Close();
|
||||
out.seekp(offset + ((off_t)i << dt.size));
|
||||
if (out.fail()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -201,9 +195,8 @@ bool DiskTrack::Save(const Filepath& path)
|
||||
total += length;
|
||||
}
|
||||
|
||||
// Write
|
||||
if (!fio.Write(&dt.buffer[i << dt.size], total)) {
|
||||
fio.Close();
|
||||
out.write((const char *)&dt.buffer[i << dt.size], total);
|
||||
if (out.fail()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -215,8 +208,6 @@ bool DiskTrack::Save(const Filepath& path)
|
||||
}
|
||||
}
|
||||
|
||||
fio.Close();
|
||||
|
||||
// Drop the change flag and exit
|
||||
fill(dt.changemap.begin(), dt.changemap.end(), false);
|
||||
dt.changed = false;
|
@ -15,9 +15,10 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "filepath.h"
|
||||
#include "os.h"
|
||||
#include <cstdlib>
|
||||
#include <vector>
|
||||
#include <string>
|
||||
|
||||
using namespace std;
|
||||
|
||||
@ -31,7 +32,7 @@ class DiskTrack
|
||||
BYTE *buffer; // Data buffer
|
||||
bool init; // Is it initilized?
|
||||
bool changed; // Changed flag
|
||||
std::vector<bool> changemap; // Changed map
|
||||
vector<bool> changemap; // Changed map
|
||||
bool raw; // RAW mode flag
|
||||
off_t imgoffset; // Offset to actual data
|
||||
} dt = {};
|
||||
@ -48,12 +49,12 @@ private:
|
||||
friend class DiskCache;
|
||||
|
||||
void Init(int track, int size, int sectors, bool raw = false, off_t imgoff = 0);
|
||||
bool Load(const Filepath& path);
|
||||
bool Save(const Filepath& path);
|
||||
bool Load(const string& path);
|
||||
bool Save(const string& path);
|
||||
|
||||
// Read / Write
|
||||
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
|
||||
};
|
@ -91,9 +91,7 @@ bool SCSIDaynaPort::Init(const unordered_map<string, string>& params)
|
||||
|
||||
void SCSIDaynaPort::Open()
|
||||
{
|
||||
Filepath path;
|
||||
path.SetPath(GetFilename().c_str());
|
||||
m_tap.OpenDump(path);
|
||||
m_tap.OpenDump(GetFilename().c_str());
|
||||
}
|
||||
|
||||
vector<byte> SCSIDaynaPort::InquiryInternal() const
|
@ -39,7 +39,7 @@ public:
|
||||
bool Dispatch(scsi_command) override;
|
||||
|
||||
// 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
|
||||
vector<byte> InquiryInternal() const override;
|
@ -17,6 +17,7 @@
|
||||
// 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.
|
||||
//
|
||||
// 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.
|
||||
// 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
|
||||
@ -33,8 +34,10 @@
|
||||
#include "scsi_command_util.h"
|
||||
#include "dispatcher.h"
|
||||
#include "scsi_printer.h"
|
||||
#include <filesystem>
|
||||
|
||||
using namespace std;
|
||||
using namespace filesystem;
|
||||
using namespace scsi_defs;
|
||||
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::eCmdPrint, "Print", &SCSIPrinter::Print);
|
||||
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
|
||||
dispatcher.Add(scsi_command::eCmdReserve6, "ReserveUnit", &SCSIPrinter::ReserveUnit);
|
||||
dispatcher.Add(scsi_command::eCmdRelease6, "ReleaseUnit", &SCSIPrinter::ReleaseUnit);
|
||||
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);
|
||||
SetReady(true);
|
||||
}
|
||||
@ -109,70 +117,75 @@ void SCSIPrinter::Print()
|
||||
|
||||
void SCSIPrinter::SynchronizeBuffer()
|
||||
{
|
||||
if (fd == -1) {
|
||||
LOGWARN("Missing printer output file")
|
||||
if (!out.is_open()) {
|
||||
LOGWARN("Nothing to print")
|
||||
|
||||
throw scsi_exception(sense_key::ABORTED_COMMAND);
|
||||
}
|
||||
|
||||
struct stat st;
|
||||
fstat(fd, &st);
|
||||
|
||||
close(fd);
|
||||
fd = -1;
|
||||
|
||||
string cmd = GetParam("cmd");
|
||||
const size_t file_position = cmd.find("%f");
|
||||
assert(file_position != string::npos);
|
||||
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())
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
unlink(filename);
|
||||
Cleanup();
|
||||
|
||||
EnterStatusPhase();
|
||||
}
|
||||
|
||||
void SCSIPrinter::StopPrint()
|
||||
{
|
||||
// Command implementations are identical
|
||||
TestUnitReady();
|
||||
}
|
||||
|
||||
bool SCSIPrinter::WriteByteSequence(vector<BYTE>& buf, uint32_t length)
|
||||
{
|
||||
if (fd == -1) {
|
||||
strcpy(filename, TMP_FILE_PATTERN); //NOSONAR Using strcpy is safe here
|
||||
fd = mkstemp(filename);
|
||||
if (!out.is_open()) {
|
||||
vector<char> f(file_template.begin(), file_template.end());
|
||||
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) {
|
||||
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;
|
||||
}
|
||||
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()
|
||||
{
|
||||
if (fd != -1) {
|
||||
close(fd);
|
||||
fd = -1;
|
||||
if (out.is_open()) {
|
||||
out.close();
|
||||
|
||||
unlink(filename);
|
||||
error_code error;
|
||||
remove(path(filename), error);
|
||||
|
||||
filename = "";
|
||||
}
|
||||
}
|
@ -12,16 +12,18 @@
|
||||
|
||||
#include "interfaces/scsi_printer_commands.h"
|
||||
#include "primary_device.h"
|
||||
#include <fstream>
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
|
||||
using namespace std;
|
||||
|
||||
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 constexpr const char *PRINTER_FILE_PATTERN = "/rascsi_sclp-XXXXXX";
|
||||
|
||||
public:
|
||||
|
||||
explicit SCSIPrinter(int);
|
||||
@ -39,7 +41,6 @@ public:
|
||||
void SendDiagnostic() override { PrimaryDevice::SendDiagnostic(); }
|
||||
void Print() override;
|
||||
void SynchronizeBuffer();
|
||||
void StopPrint();
|
||||
|
||||
bool WriteByteSequence(vector<BYTE>&, uint32_t) override;
|
||||
|
||||
@ -49,6 +50,9 @@ private:
|
||||
|
||||
Dispatcher<SCSIPrinter> dispatcher;
|
||||
|
||||
char filename[TMP_FILENAME_LENGTH + 1]; //NOSONAR mkstemp() requires a modifiable string
|
||||
int fd = -1;
|
||||
string file_template;
|
||||
|
||||
string filename;
|
||||
|
||||
ofstream out;
|
||||
};
|
@ -14,12 +14,12 @@
|
||||
//
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
#include "fileio.h"
|
||||
#include "rascsi_exceptions.h"
|
||||
#include "scsi_command_util.h"
|
||||
#include "dispatcher.h"
|
||||
#include "scsicd.h"
|
||||
#include <array>
|
||||
#include <fstream>
|
||||
|
||||
using namespace scsi_defs;
|
||||
using namespace scsi_command_util;
|
||||
@ -50,48 +50,29 @@ void SCSICD::Open()
|
||||
rawfile = false;
|
||||
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
|
||||
SetSectorSizeInBytes(GetConfiguredSectorSize() ? GetConfiguredSectorSize() : 2048);
|
||||
|
||||
// Close and transfer for physical CD access
|
||||
if (path.GetPath()[0] == '\\') {
|
||||
// Close
|
||||
fio.Close();
|
||||
|
||||
// Open physical CD
|
||||
if (GetFilename()[0] == '\\') {
|
||||
OpenPhysical();
|
||||
} else {
|
||||
if (GetFileSize() < 4) {
|
||||
fio.Close();
|
||||
throw io_exception("CD-ROM file size must be at least 4 bytes");
|
||||
// Judge whether it is a CUE sheet or an ISO file
|
||||
array<char, 4> cue;
|
||||
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
|
||||
array<TCHAR, 5> file;
|
||||
fio.Read((BYTE *)file.data(), 4);
|
||||
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");
|
||||
// If it starts with FILE consider it a CUE sheet
|
||||
if (!strncasecmp(cue.data(), "FILE", cue.size())) {
|
||||
throw io_exception("CUE CD-ROM files are not supported");
|
||||
} else {
|
||||
OpenIso();
|
||||
}
|
||||
}
|
||||
|
||||
// Successful opening
|
||||
assert(GetBlockCount() > 0);
|
||||
|
||||
super::ValidateFile(GetFilename());
|
||||
super::ValidateFile();
|
||||
|
||||
SetUpCache(0, rawfile);
|
||||
|
||||
@ -106,80 +87,56 @@ void SCSICD::Open()
|
||||
|
||||
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();
|
||||
if (size < 0x800) {
|
||||
fio.Close();
|
||||
if (size < 2048) {
|
||||
throw io_exception("ISO CD-ROM file size must be at least 2048 bytes");
|
||||
}
|
||||
|
||||
// Read the first 12 bytes and close
|
||||
array<BYTE, 12> header;
|
||||
if (!fio.Read(header.data(), header.size())) {
|
||||
fio.Close();
|
||||
// Validate header
|
||||
array<char, 16> header;
|
||||
ifstream in(GetFilename(), ios::binary);
|
||||
in.read(header.data(), header.size());
|
||||
if (!in.good()) {
|
||||
throw io_exception("Can't read header of ISO CD-ROM file");
|
||||
}
|
||||
|
||||
// Check if it is RAW format
|
||||
array<BYTE, 12> sync;
|
||||
sync.fill(0xff);
|
||||
sync[0] = 0x00;
|
||||
sync[11] = 0x00;
|
||||
// Check if it is in RAW format
|
||||
array<char, 12> sync = {};
|
||||
// 00,FFx10,00 is presumed to be RAW format
|
||||
fill_n(sync.begin() + 1, 10, 0xff);
|
||||
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
|
||||
if (header[3] != 0x01) {
|
||||
if (header[15] != 0x01) {
|
||||
// Different mode
|
||||
fio.Close();
|
||||
throw io_exception("Illegal raw ISO CD-ROM file header");
|
||||
}
|
||||
|
||||
// Set to RAW file
|
||||
rawfile = true;
|
||||
}
|
||||
fio.Close();
|
||||
|
||||
if (rawfile) {
|
||||
// Size must be a multiple of 2536
|
||||
if (size % 2536) {
|
||||
throw io_exception("Raw ISO CD-ROM file size must be a multiple of 2536 bytes but is "
|
||||
+ to_string(size) + " bytes");
|
||||
}
|
||||
|
||||
// Set the number of blocks
|
||||
SetBlockCount((uint32_t)(size / 0x930));
|
||||
SetBlockCount((uint32_t)(size / 2352));
|
||||
} else {
|
||||
// Set the number of blocks
|
||||
SetBlockCount((uint32_t)(size >> GetSectorSizeShiftCount()));
|
||||
}
|
||||
|
||||
CreateDataTrack();
|
||||
}
|
||||
|
||||
// TODO This code is only executed if the filename starts with a `\`, but fails to open files starting with `\`.
|
||||
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
|
||||
off_t size = GetFileSize();
|
||||
if (size < 0x800) {
|
||||
if (size < 2048) {
|
||||
throw io_exception("CD-ROM file size must be at least 2048 bytes");
|
||||
}
|
||||
|
||||
@ -198,9 +155,7 @@ void SCSICD::CreateDataTrack()
|
||||
assert(!tracks.size());
|
||||
auto track = make_unique<CDTrack>();
|
||||
track->Init(1, 0, (int)GetBlockCount() - 1);
|
||||
Filepath path;
|
||||
path.SetPath(GetFilename().c_str());
|
||||
track->SetPath(false, path);
|
||||
track->SetPath(false, GetFilename());
|
||||
tracks.push_back(move(track));
|
||||
dataindex = 0;
|
||||
}
|
||||
@ -287,12 +242,8 @@ int SCSICD::Read(const vector<int>& cdb, vector<BYTE>& buf, uint64_t block)
|
||||
SetBlockCount(tracks[index]->GetBlocks());
|
||||
assert(GetBlockCount() > 0);
|
||||
|
||||
// Recreate the disk cache
|
||||
Filepath path;
|
||||
tracks[index]->GetPath(path);
|
||||
|
||||
// Re-assign disk cache (no need to save)
|
||||
ResizeCache(path.GetPath(), rawfile);
|
||||
ResizeCache(tracks[index]->GetPath(), rawfile);
|
||||
|
||||
// Reset data index
|
||||
dataindex = index;
|
@ -5,17 +5,15 @@
|
||||
//
|
||||
// Copyright (C) 2001-2006 PI.(ytanaka@ipc-tokai.or.jp)
|
||||
// Copyright (C) 2014-2020 GIMONS
|
||||
// Copyright (C) 2022 Uwe Seimet
|
||||
// Copyright (C) akuker
|
||||
//
|
||||
// Licensed under the BSD 3-Clause License.
|
||||
// See LICENSE file in the project root folder.
|
||||
//
|
||||
// [ SCSI hard disk ]
|
||||
//
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
#include "scsihd.h"
|
||||
#include "fileio.h"
|
||||
#include "rascsi_exceptions.h"
|
||||
#include "scsi_command_util.h"
|
||||
|
||||
@ -56,23 +54,15 @@ string SCSIHD::GetProductData() const
|
||||
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
|
||||
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");
|
||||
}
|
||||
super::ValidateFile();
|
||||
|
||||
// For non-removable media drives set the default product name based on the drive capacity
|
||||
if (!IsRemovable()) {
|
||||
SetProduct(GetProductData(), false);
|
||||
}
|
||||
|
||||
super::ValidateFile(GetFilename());
|
||||
|
||||
SetUpCache(image_offset);
|
||||
}
|
||||
|
||||
@ -86,7 +76,7 @@ void SCSIHD::Open()
|
||||
SetSectorSizeInBytes(GetConfiguredSectorSize() ? GetConfiguredSectorSize() : 512);
|
||||
SetBlockCount((uint32_t)(size >> GetSectorSizeShiftCount()));
|
||||
|
||||
FinalizeSetup(size);
|
||||
FinalizeSetup(0);
|
||||
}
|
||||
|
||||
vector<byte> SCSIHD::InquiryInternal() const
|
@ -5,19 +5,21 @@
|
||||
//
|
||||
// Copyright (C) 2001-2006 PI.(ytanaka@ipc-tokai.or.jp)
|
||||
// Copyright (C) 2014-2020 GIMONS
|
||||
// Copyright (C) 2022 Uwe Seimet
|
||||
// Copyright (C) akuker
|
||||
//
|
||||
// Licensed under the BSD 3-Clause License.
|
||||
// See LICENSE file in the project root folder.
|
||||
//
|
||||
// [ SCSI hard disk ]
|
||||
//
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "scsi.h"
|
||||
#include "disk.h"
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <map>
|
||||
|
||||
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() override = default;
|
||||
|
||||
void FinalizeSetup(off_t, off_t = 0);
|
||||
void FinalizeSetup(off_t);
|
||||
|
||||
void Open() override;
|
||||
|
@ -14,11 +14,13 @@
|
||||
//
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
#include "scsihd_nec.h"
|
||||
#include "fileio.h"
|
||||
#include "rascsi_exceptions.h"
|
||||
#include "rasutil.h"
|
||||
#include "scsi_command_util.h"
|
||||
#include "scsihd_nec.h"
|
||||
#include <fstream>
|
||||
|
||||
using namespace ras_util;
|
||||
using namespace scsi_command_util;
|
||||
|
||||
const unordered_set<uint32_t> SCSIHD_NEC::sector_sizes = { 512 };
|
||||
@ -27,64 +29,38 @@ void SCSIHD_NEC::Open()
|
||||
{
|
||||
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();
|
||||
|
||||
// NEC root sector
|
||||
array<BYTE, 512> root_sector;
|
||||
if (size < (off_t)root_sector.size() || !fio.Read(root_sector.data(), root_sector.size())) {
|
||||
fio.Close();
|
||||
array<char, 512> root_sector;
|
||||
ifstream in(GetFilename(), ios::binary);
|
||||
in.read(root_sector.data(), root_sector.size());
|
||||
if (!in.good() || size < (off_t)root_sector.size()) {
|
||||
throw io_exception("Can't read NEC hard disk file root sector");
|
||||
}
|
||||
fio.Close();
|
||||
|
||||
// Effective size must be a multiple of 512
|
||||
size = (size / 512) * 512;
|
||||
|
||||
// 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);
|
||||
|
||||
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;
|
||||
transform(ext.begin(), ext.end(), ext.begin(), ::tolower);
|
||||
array<BYTE, 512> root_sector = {};
|
||||
memcpy(root_sector.data(), data.data(), root_sector.size());
|
||||
|
||||
int image_size;
|
||||
int sector_size;
|
||||
|
||||
// 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
|
||||
image_offset = 0;
|
||||
image_size = size;
|
||||
@ -96,7 +72,7 @@ pair<int, int> SCSIHD_NEC::SetParameters(const string& extension, const array<BY
|
||||
cylinders /= 25;
|
||||
}
|
||||
// Anex86 HD image?
|
||||
else if (ext == ".hdi") {
|
||||
else if (ext == "hdi") {
|
||||
image_offset = GetInt32LittleEndian(&root_sector[8]);
|
||||
image_size = GetInt32LittleEndian(&root_sector[12]);
|
||||
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]);
|
||||
}
|
||||
// T98Next HD image?
|
||||
else if (ext == ".nhd") {
|
||||
else if (ext == "nhd") {
|
||||
if (!memcmp(root_sector.data(), "T98HDDIMAGE.R0\0", 15)) {
|
||||
image_offset = GetInt32LittleEndian(&root_sector[0x110]);
|
||||
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");
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
@ -47,14 +47,14 @@ protected:
|
||||
|
||||
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 GetInt32LittleEndian(const BYTE *);
|
||||
|
||||
static const unordered_set<uint32_t> sector_sizes;
|
||||
|
||||
// Image file offset (NEC only)
|
||||
// Image file offset
|
||||
off_t image_offset = 0;
|
||||
|
||||
// Geometry data
|
@ -12,7 +12,6 @@
|
||||
//
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
#include "fileio.h"
|
||||
#include "rascsi_exceptions.h"
|
||||
#include "scsi_command_util.h"
|
||||
#include "scsimo.h"
|
||||
@ -43,21 +42,14 @@ void SCSIMO::Open()
|
||||
{
|
||||
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
|
||||
if (!SetGeometryForCapacity(size)) {
|
||||
if (const off_t size = GetFileSize(); !SetGeometryForCapacity(size)) {
|
||||
// Sector size (default 512 bytes) and number of blocks
|
||||
SetSectorSizeInBytes(GetConfiguredSectorSize() ? GetConfiguredSectorSize() : 512);
|
||||
SetBlockCount(size >> GetSectorSizeShiftCount());
|
||||
}
|
||||
|
||||
super::ValidateFile(GetFilename());
|
||||
super::ValidateFile();
|
||||
|
||||
SetUpCache(0);
|
||||
|
@ -15,6 +15,8 @@
|
||||
#pragma once
|
||||
|
||||
#include "disk.h"
|
||||
#include <vector>
|
||||
#include <map>
|
||||
|
||||
using Geometry = pair<uint32_t, uint32_t>;
|
||||
|
@ -23,14 +23,22 @@ StorageDevice::StorageDevice(PbDeviceType type, int lun) : ModePageDevice(type,
|
||||
SetStoppable(true);
|
||||
}
|
||||
|
||||
void StorageDevice::ValidateFile(const string& file)
|
||||
void StorageDevice::ValidateFile()
|
||||
{
|
||||
if (blocks == 0) {
|
||||
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)
|
||||
if (access(file.c_str(), W_OK)) {
|
||||
if (access(filename.c_str(), W_OK)) {
|
||||
// Permanently write-protected
|
||||
SetReadOnly(true);
|
||||
SetProtectable(false);
|
||||
@ -65,16 +73,13 @@ void StorageDevice::UnreserveFile()
|
||||
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()) {
|
||||
id = it->second.first;
|
||||
lun = it->second.second;
|
||||
|
||||
return true;
|
||||
return make_pair(it->second.first, it->second.second);
|
||||
}
|
||||
|
||||
return false;
|
||||
return make_pair(-1, -1);
|
||||
}
|
||||
|
||||
void StorageDevice::UnreserveAll()
|
||||
@ -94,7 +99,7 @@ bool StorageDevice::IsReadOnlyFile() 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)) {
|
||||
return st.st_size;
|
||||
}
|
@ -28,7 +28,6 @@ public:
|
||||
|
||||
virtual void Open() = 0;
|
||||
|
||||
void ValidateFile(const string&);
|
||||
string GetFilename() const { return filename; }
|
||||
void SetFilename(string_view f) { filename = f; }
|
||||
|
||||
@ -45,10 +44,12 @@ public:
|
||||
|
||||
static unordered_map<string, id_set> GetReservedFiles() { return reserved_files; }
|
||||
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:
|
||||
|
||||
void ValidateFile();
|
||||
|
||||
bool IsMediumChanged() const { return medium_changed; }
|
||||
void SetMediumChanged(bool b) { medium_changed = b; }
|
||||
|
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