From c28f757c5c08f5649f91e292fc622d5072c77bbf Mon Sep 17 00:00:00 2001 From: dg Date: Tue, 28 Mar 2023 19:29:02 +0000 Subject: [PATCH] Add a very prototype AppleDOS VFS plugin. --- lib/build.mk | 1 + lib/vfs/appledos.cc | 175 +++++++++++++++++++++++++++++++++++++ lib/vfs/vfs.cc | 3 + lib/vfs/vfs.h | 2 + lib/vfs/vfs.proto | 6 +- src/formats/_apple2.textpb | 4 + 6 files changed, 190 insertions(+), 1 deletion(-) create mode 100644 lib/vfs/appledos.cc diff --git a/lib/build.mk b/lib/build.mk index 0d58ae99..43e73e22 100644 --- a/lib/build.mk +++ b/lib/build.mk @@ -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 \ diff --git a/lib/vfs/appledos.cc b/lib/vfs/appledos.cc new file mode 100644 index 00000000..de23cb36 --- /dev/null +++ b/lib/vfs/appledos.cc @@ -0,0 +1,175 @@ +#include "lib/globals.h" +#include "lib/vfs/vfs.h" +#include "lib/utils.h" +#include "lib/config.pb.h" +#include + +/* 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 sectors): + Filesystem(sectors), + _config(config) + { + } + + uint32_t capabilities() const + { + return OP_LIST | OP_GETDIRENT | OP_GETFSDATA | OP_GETFILE; + } + + std::map getMetadata() override + { + mount(); + + std::map 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> list(const Path& path) override + { + mount(); + if (path.size() != 0) + throw BadPathException(); + + std::vector> results; + for (auto& de : _dirents) + results.push_back(de); + + return results; + } + + std::shared_ptr 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(fde)); + } + + track = dir[1]; + sector = dir[2]; + } + } + + std::shared_ptr 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> _dirents; +}; + +std::unique_ptr Filesystem::createAppledosFilesystem( + const FilesystemProto& config, std::shared_ptr sectors) +{ + return std::make_unique(config.appledos(), sectors); +} diff --git a/lib/vfs/vfs.cc b/lib/vfs/vfs.cc index 9f4d8630..c1337a5c 100644 --- a/lib/vfs/vfs.cc +++ b/lib/vfs/vfs.cc @@ -203,6 +203,9 @@ std::unique_ptr 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); diff --git a/lib/vfs/vfs.h b/lib/vfs/vfs.h index e5c40a56..2024ab49 100644 --- a/lib/vfs/vfs.h +++ b/lib/vfs/vfs.h @@ -248,6 +248,8 @@ public: const FilesystemProto& config, std::shared_ptr image); static std::unique_ptr createProdosFilesystem( const FilesystemProto& config, std::shared_ptr image); + static std::unique_ptr createAppledosFilesystem( + const FilesystemProto& config, std::shared_ptr image); static std::unique_ptr createSmaky6Filesystem( const FilesystemProto& config, std::shared_ptr image); diff --git a/lib/vfs/vfs.proto b/lib/vfs/vfs.proto index f5c625bb..7c86d7b8 100644 --- a/lib/vfs/vfs.proto +++ b/lib/vfs/vfs.proto @@ -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"]; diff --git a/src/formats/_apple2.textpb b/src/formats/_apple2.textpb index 39b5608d..6e89c203 100644 --- a/src/formats/_apple2.textpb +++ b/src/formats/_apple2.textpb @@ -23,6 +23,10 @@ option { filesystem_sector_order: true } + filesystem { + type: APPLEDOS + } + layout { layoutdata { filesystem {