mirror of
https://github.com/akuker/RASCSI.git
synced 2026-04-19 20:16:52 +00:00
b7e7c4e529
The X68000 host bridge and associated host file system module has not been functional for many years, as reported by multiple users Removing the code will reduce complexity for users - the SCBR device has caused some misunderstandings in the past - while eliminating code that has been flagged as insecure by SonarQube
239 lines
5.9 KiB
C++
239 lines
5.9 KiB
C++
//---------------------------------------------------------------------------
|
|
//
|
|
// SCSI Target Emulator PiSCSI
|
|
// for Raspberry Pi
|
|
//
|
|
// Copyright (C) 2021-2023 Uwe Seimet
|
|
//
|
|
//---------------------------------------------------------------------------
|
|
|
|
#include "shared/piscsi_exceptions.h"
|
|
#include "piscsi_util.h"
|
|
#include "protobuf_util.h"
|
|
#include <unistd.h>
|
|
#include <sstream>
|
|
#include <array>
|
|
#include <vector>
|
|
#include <iomanip>
|
|
|
|
using namespace std;
|
|
using namespace piscsi_util;
|
|
using namespace piscsi_interface;
|
|
|
|
#define FPRT(fp, ...) fprintf(fp, __VA_ARGS__ )
|
|
|
|
void protobuf_util::ParseParameters(PbDeviceDefinition& device, const string& params)
|
|
{
|
|
if (params.empty()) {
|
|
return;
|
|
}
|
|
|
|
// Old style parameter (filename), for backwards compatibility only
|
|
if (params.find(KEY_VALUE_SEPARATOR) == string::npos) {
|
|
SetParam(device, "file", params);
|
|
|
|
return;
|
|
}
|
|
|
|
for (const auto& p : Split(params, COMPONENT_SEPARATOR)) {
|
|
if (const auto& param = Split(p, KEY_VALUE_SEPARATOR, 2); param.size() == 2) {
|
|
SetParam(device, param[0], param[1]);
|
|
}
|
|
}
|
|
}
|
|
|
|
string protobuf_util::SetCommandParams(PbCommand& command, const string& params)
|
|
{
|
|
if (params.find(KEY_VALUE_SEPARATOR) != string::npos) {
|
|
return SetFromGenericParams(command, params);
|
|
}
|
|
|
|
string folder_pattern;
|
|
string file_pattern;
|
|
string operations;
|
|
|
|
switch (const auto& components = Split(params, COMPONENT_SEPARATOR, 3); components.size()) {
|
|
case 3:
|
|
operations = components[2];
|
|
[[fallthrough]];
|
|
|
|
case 2:
|
|
folder_pattern = components[0];
|
|
file_pattern = components[1];
|
|
break;
|
|
|
|
case 1:
|
|
file_pattern = components[0];
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
|
|
SetParam(command, "folder_pattern", folder_pattern);
|
|
SetParam(command, "file_pattern", file_pattern);
|
|
SetParam(command, "operations", operations);
|
|
|
|
return "";
|
|
}
|
|
|
|
string protobuf_util::SetFromGenericParams(PbCommand& command, const string& params)
|
|
{
|
|
for (const string& key_value : Split(params, COMPONENT_SEPARATOR)) {
|
|
const auto& param = Split(key_value, KEY_VALUE_SEPARATOR, 2);
|
|
if (param.size() > 1 && !param[0].empty()) {
|
|
SetParam(command, param[0], param[1]);
|
|
}
|
|
else {
|
|
return "Parameter '" + key_value + "' has to be a key/value pair";
|
|
}
|
|
}
|
|
|
|
return "";
|
|
}
|
|
|
|
void protobuf_util::SetProductData(PbDeviceDefinition& device, const string& data)
|
|
{
|
|
const auto& components = Split(data, COMPONENT_SEPARATOR, 3);
|
|
switch (components.size()) {
|
|
case 3:
|
|
device.set_revision(components[2]);
|
|
[[fallthrough]];
|
|
|
|
case 2:
|
|
device.set_product(components[1]);
|
|
[[fallthrough]];
|
|
|
|
case 1:
|
|
device.set_vendor(components[0]);
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
string protobuf_util::SetIdAndLun(PbDeviceDefinition& device, const string& value)
|
|
{
|
|
int id;
|
|
int lun;
|
|
if (const string error = ProcessId(value, id, lun); !error.empty()) {
|
|
return error;
|
|
}
|
|
|
|
device.set_id(id);
|
|
device.set_unit(lun != -1 ? lun : 0);
|
|
|
|
return "";
|
|
}
|
|
|
|
string protobuf_util::ListDevices(const vector<PbDevice>& pb_devices)
|
|
{
|
|
if (pb_devices.empty()) {
|
|
return "No devices currently attached.\n";
|
|
}
|
|
|
|
ostringstream s;
|
|
s << "+----+-----+------+-------------------------------------\n"
|
|
<< "| ID | LUN | TYPE | IMAGE FILE\n"
|
|
<< "+----+-----+------+-------------------------------------\n";
|
|
|
|
vector<PbDevice> devices = pb_devices;
|
|
ranges::sort(devices, [](const auto& a, const auto& b) { return a.id() < b.id() || a.unit() < b.unit(); });
|
|
|
|
for (const auto& device : devices) {
|
|
string filename;
|
|
switch (device.type()) {
|
|
case SCDP:
|
|
filename = "DaynaPort SCSI/Link";
|
|
break;
|
|
|
|
case SCHS:
|
|
filename = "Host Services";
|
|
break;
|
|
|
|
case SCLP:
|
|
filename = "SCSI Printer";
|
|
break;
|
|
|
|
default:
|
|
filename = device.file().name();
|
|
break;
|
|
}
|
|
|
|
s << "| " << device.id() << " | " << setw(3) << device.unit() << " | " << PbDeviceType_Name(device.type()) << " | "
|
|
<< (filename.empty() ? "NO MEDIUM" : filename)
|
|
<< (!device.status().removed() && (device.properties().read_only() || device.status().protected_()) ? " (READ-ONLY)" : "")
|
|
<< '\n';
|
|
}
|
|
|
|
s << "+----+-----+------+-------------------------------------\n";
|
|
|
|
return s.str();
|
|
}
|
|
|
|
//---------------------------------------------------------------------------
|
|
//
|
|
// Serialize/Deserialize protobuf message: Length followed by the actual data.
|
|
// A little endian platform is assumed.
|
|
//
|
|
//---------------------------------------------------------------------------
|
|
|
|
void protobuf_util::SerializeMessage(int fd, const google::protobuf::Message& message)
|
|
{
|
|
const string data = message.SerializeAsString();
|
|
|
|
// Write the size of the protobuf data as a header
|
|
const auto size = static_cast<int32_t>(data.length());
|
|
if (write(fd, &size, sizeof(size)) != sizeof(size)) {
|
|
throw io_exception("Can't write protobuf message size");
|
|
}
|
|
|
|
// Write the actual protobuf data
|
|
if (write(fd, data.data(), size) != size) {
|
|
throw io_exception("Can't write protobuf message data");
|
|
}
|
|
}
|
|
|
|
void protobuf_util::DeserializeMessage(int fd, google::protobuf::Message& message)
|
|
{
|
|
// Read the header with the size of the protobuf data
|
|
array<byte, sizeof(int32_t)> header_buf;
|
|
if (ReadBytes(fd, header_buf) < header_buf.size()) {
|
|
throw io_exception("Can't read protobuf message size");
|
|
}
|
|
|
|
const int size = (static_cast<int>(header_buf[3]) << 24) + (static_cast<int>(header_buf[2]) << 16)
|
|
+ (static_cast<int>(header_buf[1]) << 8) + static_cast<int>(header_buf[0]);
|
|
if (size < 0) {
|
|
throw io_exception("Invalid protobuf message size");
|
|
}
|
|
|
|
// Read the binary protobuf data
|
|
vector<byte> data_buf(size);
|
|
if (ReadBytes(fd, data_buf) != data_buf.size()) {
|
|
throw io_exception("Invalid protobuf message data");
|
|
}
|
|
|
|
message.ParseFromArray(data_buf.data(), size);
|
|
}
|
|
|
|
size_t protobuf_util::ReadBytes(int fd, span<byte> buf)
|
|
{
|
|
size_t offset = 0;
|
|
while (offset < buf.size()) {
|
|
const auto len = read(fd, &buf.data()[offset], buf.size() - offset);
|
|
if (len == -1) {
|
|
throw io_exception("Read error: " + string(strerror(errno)));
|
|
}
|
|
|
|
if (!len) {
|
|
break;
|
|
}
|
|
|
|
offset += len;
|
|
}
|
|
|
|
return offset;
|
|
}
|