Add a very prototype AppleDOS VFS plugin.

This commit is contained in:
dg
2023-03-28 19:29:02 +00:00
parent 91dbb86e64
commit c28f757c5c
6 changed files with 190 additions and 1 deletions

View File

@@ -69,6 +69,7 @@ LIBFLUXENGINE_SRCS = \
lib/utils.cc \
lib/vfs/acorndfs.cc \
lib/vfs/amigaffs.cc \
lib/vfs/appledos.cc \
lib/vfs/applesingle.cc \
lib/vfs/brother120fs.cc \
lib/vfs/cbmfs.cc \

175
lib/vfs/appledos.cc Normal file
View File

@@ -0,0 +1,175 @@
#include "lib/globals.h"
#include "lib/vfs/vfs.h"
#include "lib/utils.h"
#include "lib/config.pb.h"
#include <fmt/format.h>
/* This is described here:
* http://fileformats.archiveteam.org/wiki/Apple_DOS_file_system
* (also in Inside AppleDOS)
*/
class AppledosFilesystem : public Filesystem
{
static constexpr int VTOC_BLOCK = 17 * 16;
class AppledosDirent : public Dirent
{
public:
AppledosDirent(const Bytes& de)
{
ByteReader br(de);
track = br.read_8();
sector = br.read_8();
flags = br.read_8();
filename = br.read(30);
length = br.read_le16() * 256;
for (char& c : filename)
c &= 0x7f;
filename = rightTrimWhitespace(filename);
file_type = TYPE_FILE;
attributes[FILENAME] = filename;
attributes[LENGTH] = std::to_string(length);
attributes[FILE_TYPE] = "file";
attributes["appledos.flags"] = fmt::format("0x{:x}", flags);
}
uint8_t track;
uint8_t sector;
uint8_t flags;
};
public:
AppledosFilesystem(
const AppledosProto& config, std::shared_ptr<SectorInterface> sectors):
Filesystem(sectors),
_config(config)
{
}
uint32_t capabilities() const
{
return OP_LIST | OP_GETDIRENT | OP_GETFSDATA | OP_GETFILE;
}
std::map<std::string, std::string> getMetadata() override
{
mount();
std::map<std::string, std::string> attributes;
attributes[VOLUME_NAME] = "";
attributes[TOTAL_BLOCKS] = std::to_string(_vtoc[0x34] * _vtoc[0x35]);
attributes[USED_BLOCKS] = "0";
attributes[BLOCK_SIZE] = "256";
return attributes;
}
std::vector<std::shared_ptr<Dirent>> list(const Path& path) override
{
mount();
if (path.size() != 0)
throw BadPathException();
std::vector<std::shared_ptr<Dirent>> results;
for (auto& de : _dirents)
results.push_back(de);
return results;
}
std::shared_ptr<Dirent> getDirent(const Path& path) override
{
mount();
if (path.size() != 1)
throw BadPathException();
return find(path.front());
}
Bytes getFile(const Path& path) override
{
mount();
if (path.size() != 1)
throw BadPathException();
auto dirent = find(path.front());
int tstrack = dirent->track;
int tssector = dirent->sector;
Bytes bytes;
ByteWriter bw(bytes);
while (tstrack)
{
Bytes ts = getLogicalSector(tstrack * 16 + tssector);
ByteReader br(ts);
br.seek(0x0c);
while (!br.eof())
{
int track = br.read_8();
int sector = br.read_8();
if (!track)
goto done;
bw += getLogicalSector(track * 16 + sector);
}
tstrack = ts[1];
tssector = ts[2];
}
done:
return bytes;
}
private:
void mount()
{
_vtoc = getLogicalSector(VTOC_BLOCK);
if ((_vtoc[0x27] != 122) || (_vtoc[0x36] != 0) || (_vtoc[0x37] != 1))
throw BadFilesystemException();
_dirents.clear();
int track = _vtoc[1];
int sector = _vtoc[2];
while (track)
{
Bytes dir = getLogicalSector(track * 16 + sector);
ByteReader br(dir);
br.seek(0x0b);
while (!br.eof())
{
Bytes fde = br.read(0x23);
if ((fde[0] != 0) && (fde[0] != 255))
_dirents.push_back(std::make_shared<AppledosDirent>(fde));
}
track = dir[1];
sector = dir[2];
}
}
std::shared_ptr<AppledosDirent> find(const std::string filename)
{
for (auto& de : _dirents)
if (de->filename == filename)
return de;
throw FileNotFoundException();
}
private:
const AppledosProto& _config;
Bytes _vtoc;
std::vector<std::shared_ptr<AppledosDirent>> _dirents;
};
std::unique_ptr<Filesystem> Filesystem::createAppledosFilesystem(
const FilesystemProto& config, std::shared_ptr<SectorInterface> sectors)
{
return std::make_unique<AppledosFilesystem>(config.appledos(), sectors);
}

View File

@@ -203,6 +203,9 @@ std::unique_ptr<Filesystem> Filesystem::createFilesystem(
case FilesystemProto::PRODOS:
return Filesystem::createProdosFilesystem(config, image);
case FilesystemProto::APPLEDOS:
return Filesystem::createAppledosFilesystem(config, image);
case FilesystemProto::SMAKY6:
return Filesystem::createSmaky6Filesystem(config, image);

View File

@@ -248,6 +248,8 @@ public:
const FilesystemProto& config, std::shared_ptr<SectorInterface> image);
static std::unique_ptr<Filesystem> createProdosFilesystem(
const FilesystemProto& config, std::shared_ptr<SectorInterface> image);
static std::unique_ptr<Filesystem> createAppledosFilesystem(
const FilesystemProto& config, std::shared_ptr<SectorInterface> image);
static std::unique_ptr<Filesystem> createSmaky6Filesystem(
const FilesystemProto& config, std::shared_ptr<SectorInterface> image);

View File

@@ -59,9 +59,11 @@ message CbmfsProto
message ProdosProto {}
message AppledosProto {}
message Smaky6FsProto {}
// NEXT_TAG: 12
// NEXT_TAG: 13
message FilesystemProto
{
enum FilesystemType {
@@ -75,6 +77,7 @@ message FilesystemProto
CBMFS = 7;
PRODOS = 8;
SMAKY6 = 9;
APPLEDOS = 10;
}
optional FilesystemType type = 10 [default = NOT_SET, (help) = "filesystem type"];
@@ -87,6 +90,7 @@ message FilesystemProto
optional MacHfsProto machfs = 6;
optional CbmfsProto cbmfs = 7;
optional ProdosProto prodos = 8;
optional AppledosProto appledos = 12;
optional Smaky6FsProto smaky6 = 11;
optional SectorListProto sector_order = 9 [(help) = "specify the filesystem order of sectors"];

View File

@@ -23,6 +23,10 @@ option {
filesystem_sector_order: true
}
filesystem {
type: APPLEDOS
}
layout {
layoutdata {
filesystem {