diff --git a/lib/vfs/acorndfs.cc b/lib/vfs/acorndfs.cc index 47b9a28e..a95ac808 100644 --- a/lib/vfs/acorndfs.cc +++ b/lib/vfs/acorndfs.cc @@ -59,6 +59,23 @@ public: return result; } + Bytes getFile(const Path& path) + { + auto dirent = findFile(path); + int sectors = (dirent->length + 255) / 256; + + Bytes data; + ByteWriter bw(data); + for (int i = 0; i < sectors; i++) + { + auto sector = getLogicalSector(dirent->start_sector + i); + bw.append(sector); + } + + data.resize(dirent->length); + return data; + } + std::map getMetadata(const Path& path) { std::map attributes; diff --git a/lib/vfs/brother120fs.cc b/lib/vfs/brother120fs.cc index 2819c5f0..fb9e0fb2 100644 --- a/lib/vfs/brother120fs.cc +++ b/lib/vfs/brother120fs.cc @@ -6,7 +6,10 @@ /* Number of sectors on a 120kB disk. */ static constexpr int SECTOR_COUNT = 468; -/* Start sector for data (after the directory */ +/* Start sector for the FAT (after the directory) */ +static constexpr int FAT_START_SECTOR = 8; + +/* Start sector for data (after the FAT) */ static constexpr int DATA_START_SECTOR = 14; /* Size of a sector */ @@ -15,6 +18,9 @@ static constexpr int SECTOR_SIZE = 256; /* Number of dirents in a directory. */ static constexpr int DIRECTORY_SIZE = 128; +/* Number of sectors in the FAT. */ +static constexpr int FAT_SECTORS = 4; + /* Number of sectors in a directory. */ static constexpr int DIRECTORY_SECTORS = 8; @@ -68,6 +74,23 @@ public: return result; } + Bytes getFile(const Path& path) + { + auto fat = readFat(); + auto dirent = findFile(path); + int sector = dirent->start_sector; + + Bytes data; + ByteWriter bw(data); + while ((sector != 0) && (sector != 0xffff)) + { + bw += getLogicalSector(sector - 1); + sector = fat.at(sector); + } + + return data; + } + std::map getMetadata(const Path& path) { std::map attributes; @@ -85,6 +108,19 @@ public: } private: + std::vector readFat() + { + Bytes bytes = getLogicalSector(FAT_START_SECTOR, FAT_SECTORS); + ByteReader br(bytes); + std::vector table; + + table.push_back(0xffff); + for (int sector = 1; sector != SECTOR_COUNT; sector++) + table.push_back(br.read_be16()); + + return table; + } + std::vector> findAllFiles() { std::vector> result; diff --git a/lib/vfs/vfs.cc b/lib/vfs/vfs.cc index 2ff29411..ec26a0c7 100644 --- a/lib/vfs/vfs.cc +++ b/lib/vfs/vfs.cc @@ -68,13 +68,19 @@ std::unique_ptr Filesystem::createFilesystem( } } -Bytes Filesystem::getLogicalSector(uint32_t number) +Bytes Filesystem::getLogicalSector(uint32_t number, uint32_t count) { - if (number >= _locations.size()) + if ((number+count) > _locations.size()) throw BadFilesystemException(); - auto& i = _locations[number]; - return _sectors->get(std::get<0>(i), std::get<1>(i), std::get<2>(i))->data; + Bytes data; + ByteWriter bw(data); + for (int i = 0; i < count; i++) + { + auto& it = _locations[number + i]; + bw += _sectors->get(std::get<0>(it), std::get<1>(it), std::get<2>(it))->data; + } + return data; } void Filesystem::putLogicalSector(uint32_t number, const Bytes& data) diff --git a/lib/vfs/vfs.h b/lib/vfs/vfs.h index 8b8bac68..e6ef3bdc 100644 --- a/lib/vfs/vfs.h +++ b/lib/vfs/vfs.h @@ -59,22 +59,22 @@ public: virtual std::vector> list(const Path& path) { throw UnimplementedFilesystemException(); } - virtual Bytes read(const Path& path) + virtual Bytes getFile(const Path& path) { throw UnimplementedFilesystemException(); } - virtual void write(const Path& path, const Bytes& data) + virtual void putFile(const Path& path, const Bytes& data) { throw UnimplementedFilesystemException(); } virtual std::map getMetadata(const Path& path) { throw UnimplementedFilesystemException(); } - virtual void setMetadata(const Path& path, const std::map& metadata) + virtual void putMetadata(const Path& path, const std::map& metadata) { throw UnimplementedFilesystemException(); } protected: Filesystem(std::shared_ptr sectors); - Bytes getLogicalSector(uint32_t number); + Bytes getLogicalSector(uint32_t number, uint32_t count = 1); void putLogicalSector(uint32_t number, const Bytes& data); private: diff --git a/src/build.mk b/src/build.mk index c324545d..90e91050 100644 --- a/src/build.mk +++ b/src/build.mk @@ -3,6 +3,7 @@ include src/formats/build.mk FLUXENGINE_SRCS = \ src/fe-analysedriveresponse.cc \ src/fe-analyselayout.cc \ + src/fe-getfile.cc \ src/fe-getfileinfo.cc \ src/fe-inspect.cc \ src/fe-ls.cc \ diff --git a/src/fe-getfile.cc b/src/fe-getfile.cc new file mode 100644 index 00000000..334a3acc --- /dev/null +++ b/src/fe-getfile.cc @@ -0,0 +1,44 @@ +#include "globals.h" +#include "flags.h" +#include "fluxmap.h" +#include "sector.h" +#include "proto.h" +#include "readerwriter.h" +#include "imagereader/imagereader.h" +#include "imagewriter/imagewriter.h" +#include "lib/fluxsource/fluxsource.h" +#include "lib/decoders/decoders.h" +#include "fmt/format.h" +#include "fluxengine.h" +#include "lib/vfs/sectorinterface.h" +#include "lib/vfs/vfs.h" +#include "src/fileutils.h" +#include +#include + +static FlagGroup flags({ &fileFlags }); + +static StringFlag directory({"-p", "--path"}, "path to work on", ""); +static StringFlag output({"-o", "--output"}, "local filename to write to", ""); + +int mainGetFile(int argc, const char* argv[]) +{ + if (argc == 1) + showProfiles("getfile", formats); + flags.parseFlagsWithConfigFiles(argc, argv, formats); + + Path inputFilename(directory); + if (inputFilename.size() == 0) + Error() << "you must supply a filename to read"; + + std::string outputFilename = output; + if (outputFilename.empty()) + outputFilename = inputFilename.back(); + fmt::print("{}\n", outputFilename); + + auto filesystem = createFilesystemFromConfig(); + auto data = filesystem->getFile(inputFilename); + data.writeToFile(outputFilename); + + return 0; +} diff --git a/src/fe-getfileinfo.cc b/src/fe-getfileinfo.cc index 3d8940c7..550e9923 100644 --- a/src/fe-getfileinfo.cc +++ b/src/fe-getfileinfo.cc @@ -23,7 +23,7 @@ static StringFlag directory({"-p", "--path"}, "path to work on", ""); int mainGetFileInfo(int argc, const char* argv[]) { if (argc == 1) - showProfiles("ls", formats); + showProfiles("getfileinfo", formats); flags.parseFlagsWithConfigFiles(argc, argv, formats); auto filesystem = createFilesystemFromConfig(); diff --git a/src/fluxengine.cc b/src/fluxengine.cc index d7923a4d..871dce7a 100644 --- a/src/fluxengine.cc +++ b/src/fluxengine.cc @@ -6,6 +6,7 @@ typedef int command_cb(int agrc, const char* argv[]); extern command_cb mainAnalyseDriveResponse; extern command_cb mainAnalyseLayout; +extern command_cb mainGetFile; extern command_cb mainGetFileInfo; extern command_cb mainInspect; extern command_cb mainLs; @@ -37,6 +38,7 @@ static std::vector commands = { "rawread", mainRawRead, "Reads raw flux from a disk. Warning: you can't use this to copy disks.", }, { "rawwrite", mainRawWrite, "Writes a flux file to a disk. Warning: you can't use this to copy disks.", }, { "ls", mainLs, "Show files on disk (or image).", }, + { "getfile", mainGetFile, "Read a file off a disk (or image).", }, { "getfileinfo", mainGetFileInfo, "Read file metadata off a disk (or image).", }, { "rpm", mainRpm, "Measures the disk rotational speed.", }, { "seek", mainSeek, "Moves the disk head.", },