#include "lib/core/globals.h" #include "lib/config.h" #include "vfs.h" #include "lib/proto.h" #include "lib/layout.pb.h" #include "lib/layout.h" #include "lib/image.h" #include "lib/sector.h" #include "lib/vfs/sectorinterface.h" #include "lib/imagereader/imagereader.h" #include "lib/imagewriter/imagewriter.h" #include "lib/fluxsource/fluxsource.h" #include "lib/fluxsink/fluxsink.h" #include "lib/decoders/decoders.h" #include "lib/encoders/encoders.h" #include "lib/config.pb.h" #include "lib/core/utils.h" Path::Path(const std::vector other): std::vector(other) { } Path::Path(const std::string& path) { if (path == "") return; auto p = path; if (p[0] == '/') p = p.substr(1); std::stringstream ss(p); std::string item; while (std::getline(ss, item, '/')) { if (item.empty()) throw BadPathException(); push_back(item); } } Path Path::parent() const { Path p; if (!empty()) { for (int i = 0; i < (size() - 1); i++) p.push_back((*this)[i]); } return p; } Path Path::concat(const std::string& s) const { Path p(*this); p.push_back(s); return p; } std::string Path::to_str(const std::string sep) const { return join(*this, sep); } uint32_t Filesystem::capabilities() const { return 0; } void Filesystem::create(bool quick, const std::string& volumeName) { throw UnimplementedFilesystemException(); } FilesystemStatus Filesystem::check() { throw UnimplementedFilesystemException(); } std::map Filesystem::getMetadata() { throw UnimplementedFilesystemException(); } void Filesystem::putMetadata(const std::map& metadata) { throw UnimplementedFilesystemException(); } std::vector> Filesystem::list(const Path& path) { throw UnimplementedFilesystemException(); } Bytes Filesystem::getFile(const Path& path) { throw UnimplementedFilesystemException(); } void Filesystem::putFile(const Path& path, const Bytes& data) { throw UnimplementedFilesystemException(); } std::shared_ptr Filesystem::getDirent(const Path& path) { throw UnimplementedFilesystemException(); } void Filesystem::putMetadata( const Path& path, const std::map& metadata) { throw UnimplementedFilesystemException(); } void Filesystem::createDirectory(const Path& path) { throw UnimplementedFilesystemException(); } void Filesystem::deleteFile(const Path& path) { throw UnimplementedFilesystemException(); } void Filesystem::moveFile(const Path& oldName, const Path& newName) { throw UnimplementedFilesystemException(); } bool Filesystem::isReadOnly() { return _sectors->isReadOnly(); } bool Filesystem::needsFlushing() { return _sectors->needsFlushing(); } void Filesystem::flushChanges() { _sectors->flushChanges(); } void Filesystem::discardChanges() { _sectors->discardChanges(); } Filesystem::Filesystem(std::shared_ptr sectors): _sectors(sectors) { auto& layout = globalConfig()->layout(); if (!layout.has_tracks() || !layout.has_sides()) error( "FS: filesystem support cannot be used without concrete layout " "information"); unsigned block = 0; for (const auto& p : Layout::getTrackOrdering(layout.tracks(), layout.sides())) { int track = p.first; int side = p.second; auto trackLayout = Layout::getLayoutOfTrack(track, side); if (trackLayout->numSectors == 0) error( "FS: filesystem support cannot be used without concrete " "layout information"); for (int sectorId : trackLayout->filesystemSectorOrder) _locations.push_back(std::make_tuple(track, side, sectorId)); } } std::unique_ptr Filesystem::createFilesystem( const FilesystemProto& config, std::shared_ptr image) { switch (config.type()) { case FilesystemProto::BROTHER120: return Filesystem::createBrother120Filesystem(config, image); case FilesystemProto::ACORNDFS: return Filesystem::createAcornDfsFilesystem(config, image); case FilesystemProto::FATFS: return Filesystem::createFatFsFilesystem(config, image); case FilesystemProto::CPMFS: return Filesystem::createCpmFsFilesystem(config, image); case FilesystemProto::AMIGAFFS: return Filesystem::createAmigaFfsFilesystem(config, image); case FilesystemProto::MACHFS: return Filesystem::createMacHfsFilesystem(config, image); case FilesystemProto::CBMFS: return Filesystem::createCbmfsFilesystem(config, image); case FilesystemProto::PRODOS: return Filesystem::createProdosFilesystem(config, image); case FilesystemProto::APPLEDOS: return Filesystem::createAppledosFilesystem(config, image); case FilesystemProto::SMAKY6: return Filesystem::createSmaky6Filesystem(config, image); case FilesystemProto::PHILE: return Filesystem::createPhileFilesystem(config, image); case FilesystemProto::LIF: return Filesystem::createLifFilesystem(config, image); case FilesystemProto::MICRODOS: return Filesystem::createMicrodosFilesystem(config, image); case FilesystemProto::ZDOS: return Filesystem::createZDosFilesystem(config, image); case FilesystemProto::ROLAND: return Filesystem::createRolandFsFilesystem(config, image); default: error("no filesystem configured"); return std::unique_ptr(); } } std::unique_ptr Filesystem::createFilesystemFromConfig() { std::shared_ptr sectorInterface; if (globalConfig().hasFluxSource() || globalConfig().hasFluxSink()) { std::shared_ptr fluxSource; std::shared_ptr decoder; std::shared_ptr fluxSink; std::shared_ptr encoder; if (globalConfig().hasFluxSource()) { fluxSource = globalConfig().getFluxSource(); decoder = globalConfig().getDecoder(); } if (globalConfig()->flux_sink().type() == FLUXTYPE_DRIVE) { fluxSink = globalConfig().getFluxSink(); encoder = globalConfig().getEncoder(); } sectorInterface = SectorInterface::createFluxSectorInterface( fluxSource, fluxSink, encoder, decoder); } else { std::shared_ptr reader; std::shared_ptr writer; if (globalConfig().hasImageReader() && doesFileExist(globalConfig()->image_reader().filename())) reader = globalConfig().getImageReader(); if (globalConfig().hasImageWriter()) writer = globalConfig().getImageWriter(); sectorInterface = SectorInterface::createImageSectorInterface(reader, writer); } return createFilesystem(globalConfig()->filesystem(), sectorInterface); } Bytes Filesystem::getSector(unsigned track, unsigned side, unsigned sector) { auto s = _sectors->get(track, side, sector); if (!s) throw BadFilesystemException(); return s->data; } Bytes Filesystem::getLogicalSector(uint32_t number, uint32_t count) { if ((number + count) > _locations.size()) throw BadFilesystemException(fmt::format( "invalid filesystem: sector {} is out of bounds ({} maximum)", number + count - 1, _locations.size())); Bytes data; ByteWriter bw(data); for (int i = 0; i < count; i++) { auto& it = _locations[number + i]; int track = std::get<0>(it); int side = std::get<1>(it); int sector = std::get<2>(it); auto trackLayout = Layout::getLayoutOfTrack(track, side); bw += _sectors->get(track, side, sector) ->data.slice(0, trackLayout->sectorSize); } return data; } void Filesystem::putLogicalSector(uint32_t number, const Bytes& data) { if (number >= _locations.size()) throw BadFilesystemException(fmt::format( "invalid filesystem: sector {} is out of bounds", number)); unsigned pos = 0; while (pos < data.size()) { auto& it = _locations[number]; int track = std::get<0>(it); int side = std::get<1>(it); int sector = std::get<2>(it); int sectorSize = Layout::getLayoutOfTrack(track, side)->sectorSize; _sectors->put(track, side, sector)->data = data.slice(pos, sectorSize); pos += sectorSize; number++; } } unsigned Filesystem::getOffsetOfSector( unsigned track, unsigned side, unsigned sector) { location_t key = {track, side, sector}; for (int i = 0; i < _locations.size(); i++) { if (_locations[i] >= key) return i; } throw BadFilesystemException(); } unsigned Filesystem::getLogicalSectorCount() { return _locations.size(); } unsigned Filesystem::getLogicalSectorSize(unsigned track, unsigned side) { return Layout::getLayoutOfTrack(track, side)->sectorSize; } void Filesystem::eraseEverythingOnDisk() { for (int i = 0; i < getLogicalSectorCount(); i++) putLogicalSector(i, Bytes(1)); }