Allow reading files from cbmfs disks (not .REL, though).

This commit is contained in:
David Given
2022-08-30 20:21:30 +02:00
parent b91edac0ba
commit 1afa9ce697
6 changed files with 118 additions and 11 deletions

View File

@@ -102,3 +102,54 @@ std::string toIso8601(time_t t)
ss << std::put_time(tm, "%FT%T%z");
return ss.str();
}
std::string quote(const std::string& s)
{
bool spaces = s.find(' ') != std::string::npos;
if (!spaces
&& (s.find('\\') == std::string::npos)
&& (s.find('\'') == std::string::npos)
&& (s.find('"') == std::string::npos))
return s;
std::stringstream ss;
if (spaces)
ss << '"';
for (char c : s)
{
if ((c == '\\') || (c == '\"') || (c == '!'))
ss << '\\';
ss << (char)c;
}
if (spaces)
ss << '"';
return ss.str();
}
std::string unhex(const std::string& s)
{
std::stringstream sin(s);
std::stringstream sout;
for (;;)
{
int c = sin.get();
if (c == -1)
break;
if (c == '%')
{
char buf[3];
buf[0] = sin.get();
buf[1] = sin.get();
buf[2] = 0;
c = std::stoul(buf, nullptr, 16);
}
sout << (char)c;
}
return sout.str();
}

View File

@@ -11,6 +11,8 @@ extern std::string rightTrimWhitespace(std::string value);
extern std::string trimWhitespace(const std::string& value);
extern std::string getLeafname(const std::string& value);
extern std::string toIso8601(time_t t);
extern std::string quote(const std::string& s);
extern std::string unhex(const std::string& s);
/* If set, any running job will terminate as soon as possible (with an error).
*/

View File

@@ -1,8 +1,18 @@
#include "lib/globals.h"
#include "lib/vfs/vfs.h"
#include "lib/config.pb.h"
#include "lib/utils.h"
#include <fmt/format.h>
enum
{
DEL,
SEQ,
PRG,
USR,
REL
};
static std::string fromPetscii(const Bytes& bytes)
{
std::stringstream ss;
@@ -32,11 +42,11 @@ static std::string toFileType(uint8_t cbm_type)
{
switch (cbm_type & 0x0f)
{
case 0: return "del";
case 1: return "seq";
case 2: return "prg";
case 3: return "usr";
case 4: return "rel";
case DEL: return "DEL";
case SEQ: return "SEQ";
case PRG: return "PRG";
case USR: return "USR";
case REL: return "REL";
default: return fmt::format("[bad type {:x}]", cbm_type & 0x0f);
}
}
@@ -123,13 +133,13 @@ public:
{
if (path.size() != 1)
throw BadPathException();
auto de = findFile(path[0]);
auto de = findFile(unhex(path[0]));
if (!de)
throw FileNotFoundException();
std::map<std::string, std::string> attributes;
attributes["filename"] = de->filename;
attributes["length"] = de->length;
attributes["length"] = fmt::format("{}", de->length);
attributes["mode"] = de->mode;
attributes["type"] = "file";
attributes["cbmfs.type"] = toFileType(de->cbm_type);
@@ -142,6 +152,40 @@ public:
return attributes;
}
Bytes getFile(const Path& path)
{
if (path.size() != 1)
throw BadPathException();
auto de = findFile(unhex(path[0]));
if (!de)
throw FileNotFoundException();
if (de->cbm_type == REL)
throw UnimplementedFilesystemException("cannot read .REL files");
Bytes bytes;
ByteWriter bw(bytes);
uint8_t t = de->start_track - 1;
uint8_t s = de->start_sector;
for (;;)
{
auto b = getSector(t, 0, s);
if (b[0])
bw += b.slice(2);
else
{
bw += b.slice(2, b[1]);
break;
}
t = b[0] - 1;
s = b[1];
}
return bytes;
}
private:
std::unique_ptr<CbmfsDirent> findFile(const std::string& filename)
{

View File

@@ -12,6 +12,7 @@
#include "fluxengine.h"
#include "lib/vfs/sectorinterface.h"
#include "lib/vfs/vfs.h"
#include "lib/utils.h"
#include "src/fileutils.h"
#include <google/protobuf/text_format.h>
#include <fstream>
@@ -32,7 +33,7 @@ int mainGetFileInfo(int argc, const char* argv[])
auto attributes = filesystem->getMetadata(Path(directory));
for (const auto& e : attributes)
fmt::print("{}={}\n", e.first, e.second);
fmt::print("{}={}\n", e.first, quote(e.second));
}
catch (const FilesystemException& e)
{

View File

@@ -11,6 +11,7 @@
#include "fluxengine.h"
#include "lib/vfs/sectorinterface.h"
#include "lib/vfs/vfs.h"
#include "lib/utils.h"
#include "src/fileutils.h"
#include <google/protobuf/text_format.h>
#include <fstream>
@@ -47,15 +48,15 @@ int mainLs(int argc, const char* argv[])
int maxlen = 0;
for (const auto& dirent : files)
maxlen = std::max(maxlen, (int)dirent->filename.size());
maxlen = std::max(maxlen, (int)quote(dirent->filename).size());
uint32_t total = 0;
for (const auto& dirent : files)
{
fmt::print("{} {:{}} {:6} {}\n",
fileTypeChar(dirent->file_type),
"'" + dirent->filename + "'",
maxlen,
quote(dirent->filename),
maxlen + 2,
dirent->length,
dirent->mode);
total += dirent->length;

View File

@@ -43,6 +43,13 @@ static void testLeafname()
AssertThat(getLeafname("/path/path/filename"), Equals("filename"));
}
static void testUnhex()
{
AssertThat(unhex(""), Equals(""));
AssertThat(unhex("foo"), Equals("foo"));
AssertThat(unhex("f%20o"), Equals("f o"));
}
int main(void)
{
testJoin();
@@ -50,5 +57,6 @@ int main(void)
testRightTrim();
testTrim();
testLeafname();
testUnhex();
return 0;
}