Files
RASCSI/cpp/shared/protobuf_util.cpp
Daniel Markstedt b7e7c4e529 Remove bitrotted X68000 host bridge device
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
2025-11-09 08:45:56 +01:00

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;
}