Merge pull request #570 from davidgiven/vfs

Add VFS write support.
This commit is contained in:
David Given
2022-08-31 00:32:38 +02:00
committed by GitHub
26 changed files with 760 additions and 389 deletions

View File

@@ -128,6 +128,19 @@ uint8_t& Bytes::operator [] (unsigned pos)
return (*_data)[pos]; return (*_data)[pos];
} }
Bytes Bytes::readFromFile(const std::string& filename)
{
Bytes bytes;
ByteWriter bw(bytes);
std::ifstream f(filename);
if (!f)
Error() << fmt::format("cannot open '{}': {}", filename, strerror(errno));
bw += f;
return bytes;
}
Bytes Bytes::slice(unsigned start, unsigned len) const Bytes Bytes::slice(unsigned start, unsigned len) const
{ {
start += _low; start += _low;

View File

@@ -19,6 +19,9 @@ public:
Bytes* operator = (const Bytes& other); Bytes* operator = (const Bytes& other);
public:
static Bytes readFromFile(const std::string& filename);
public: public:
/* General purpose methods */ /* General purpose methods */

View File

@@ -15,6 +15,17 @@ Image::Image(std::set<std::shared_ptr<const Sector>>& sectors)
calculateSize(); calculateSize();
} }
bool Image::empty() const
{
return _sectors.empty();
}
bool Image::contains(unsigned track, unsigned side, unsigned sectorid) const
{
key_t key = std::make_tuple(track, side, sectorid);
return _sectors.find(key) != _sectors.end();
}
std::shared_ptr<const Sector> Image::get(unsigned track, unsigned side, unsigned sectorid) const std::shared_ptr<const Sector> Image::get(unsigned track, unsigned side, unsigned sectorid) const
{ {
static std::shared_ptr<const Sector> NONE; static std::shared_ptr<const Sector> NONE;
@@ -37,6 +48,12 @@ std::shared_ptr<Sector> Image::put(unsigned track, unsigned side, unsigned secto
return sector; return sector;
} }
void Image::erase(unsigned track, unsigned side, unsigned sectorid)
{
key_t key = std::make_tuple(track, side, sectorid);
_sectors.erase(key);
}
void Image::calculateSize() void Image::calculateSize()
{ {
_geometry = {}; _geometry = {};

View File

@@ -39,8 +39,11 @@ public:
public: public:
void calculateSize(); void calculateSize();
bool empty() const;
bool contains(unsigned track, unsigned side, unsigned sectorId) const;
std::shared_ptr<const Sector> get(unsigned track, unsigned side, unsigned sectorId) const; std::shared_ptr<const Sector> get(unsigned track, unsigned side, unsigned sectorId) const;
std::shared_ptr<Sector> put(unsigned track, unsigned side, unsigned sectorId); std::shared_ptr<Sector> put(unsigned track, unsigned side, unsigned sectorId);
void erase(unsigned track, unsigned side, unsigned sectorId);
const_iterator begin() const { return const_iterator(_sectors.cbegin()); } const_iterator begin() const { return const_iterator(_sectors.cbegin()); }
const_iterator end() const { return const_iterator(_sectors.cend()); } const_iterator end() const { return const_iterator(_sectors.cend()); }

View File

@@ -187,8 +187,6 @@ void writeTracks(FluxSink& fluxSink,
producer, producer,
std::function<bool(const Location& location)> verifier) std::function<bool(const Location& location)> verifier)
{ {
Logger() << fmt::format("Writing to: {}", (std::string)fluxSink);
for (const auto& location : Mapper::computeLocations()) for (const auto& location : Mapper::computeLocations())
{ {
testForEmergencyStop(); testForEmergencyStop();
@@ -287,44 +285,53 @@ void writeTracksAndVerify(FluxSink& fluxSink,
return false; return false;
} }
auto wantedSectors = encoder.collectSectors(location, image); Image wanted;
std::sort(wantedSectors.begin(), for (const auto& sector : encoder.collectSectors(location, image))
wantedSectors.end(), wanted.put(sector->logicalTrack, sector->logicalSide, sector->logicalSector)->data = sector->data;
sectorPointerSortPredicate);
std::vector<std::shared_ptr<const Sector>> gotSectors( for (const auto& sector : trackFlux->sectors)
trackFlux->sectors.begin(), trackFlux->sectors.end()); {
std::sort(gotSectors.begin(), const auto s = wanted.get(sector->logicalTrack, sector->logicalSide, sector->logicalSector);
gotSectors.end(), if (!s)
sectorPointerSortPredicate); {
Logger() << "spurious sector on verify";
if (!std::equal(gotSectors.begin(), return false;
gotSectors.end(), }
wantedSectors.begin(), if (s->data != sector->data.slice(0, s->data.size()))
wantedSectors.end(), {
sectorPointerEqualsPredicate)) Logger() << "data mismatch on verify";
{ return false;
Logger() << "good read but the data doesn't match"; }
return false; wanted.erase(sector->logicalTrack, sector->logicalSide, sector->logicalSector);
} }
if (!wanted.empty())
{
Logger() << "missing sector on verify";
return false;
}
return true; return true;
}); });
} }
void writeDiskCommand(std::shared_ptr<const Image> image, void writeDiskCommand(const Image& image,
AbstractEncoder& encoder, AbstractEncoder& encoder,
FluxSink& fluxSink, FluxSink& fluxSink,
AbstractDecoder* decoder, AbstractDecoder* decoder,
FluxSource* fluxSource) FluxSource* fluxSource)
{ {
const Image* imagep = &image;
std::unique_ptr<const Image> remapped;
if (config.has_sector_mapping()) if (config.has_sector_mapping())
image = std::move(Mapper::remapSectorsLogicalToPhysical( {
*image, config.sector_mapping())); remapped = Mapper::remapSectorsLogicalToPhysical(
image, config.sector_mapping());
imagep = &*remapped;
}
if (fluxSource && decoder) if (fluxSource && decoder)
writeTracksAndVerify(fluxSink, encoder, *fluxSource, *decoder, *image); writeTracksAndVerify(fluxSink, encoder, *fluxSource, *decoder, *imagep);
else else
writeTracks(fluxSink, encoder, *image); writeTracks(fluxSink, encoder, *imagep);
} }
void writeRawDiskCommand(FluxSource& fluxSource, FluxSink& fluxSink) void writeRawDiskCommand(FluxSource& fluxSource, FluxSink& fluxSink)

View File

@@ -23,7 +23,7 @@ extern void fillBitmapTo(std::vector<bool>& bitmap,
unsigned terminateAt, unsigned terminateAt,
const std::vector<bool>& pattern); const std::vector<bool>& pattern);
extern void writeDiskCommand(std::shared_ptr<const Image> image, extern void writeDiskCommand(const Image& image,
AbstractEncoder& encoder, AbstractEncoder& encoder,
FluxSink& fluxSink, FluxSink& fluxSink,
AbstractDecoder* decoder = nullptr, AbstractDecoder* decoder = nullptr,

View File

@@ -6,30 +6,32 @@
class AcornDfsDirent : public Dirent class AcornDfsDirent : public Dirent
{ {
public: public:
AcornDfsDirent(int inode, const Bytes& bytes0, const Bytes& bytes1) AcornDfsDirent(int inode, const Bytes& bytes0, const Bytes& bytes1)
{ {
filename += (char)(bytes0[7] & 0x7f); filename += (char)(bytes0[7] & 0x7f);
filename += '.'; filename += '.';
for (int j = 0; j < 7; j++) for (int j = 0; j < 7; j++)
filename += bytes0[j] & 0x7f; filename += bytes0[j] & 0x7f;
filename = filename.substr(0, filename.find(' ')); filename = filename.substr(0, filename.find(' '));
this->inode = inode; this->inode = inode;
start_sector = ((bytes1[6] & 0x03) << 8) | bytes1[7]; start_sector = ((bytes1[6] & 0x03) << 8) | bytes1[7];
load_address = ((bytes1[6] & 0x0c) << 14) | (bytes1[1] << 8) | bytes1[0]; load_address =
exec_address = ((bytes1[6] & 0xc0) << 10) | (bytes1[3] << 8) | bytes1[2]; ((bytes1[6] & 0x0c) << 14) | (bytes1[1] << 8) | bytes1[0];
locked = bytes0[7] & 0x80; exec_address =
length = ((bytes1[6] & 0x30) << 12) | (bytes1[5] << 8) | bytes1[4]; ((bytes1[6] & 0xc0) << 10) | (bytes1[3] << 8) | bytes1[2];
file_type = TYPE_FILE; locked = bytes0[7] & 0x80;
mode = locked ? "L" : ""; length = ((bytes1[6] & 0x30) << 12) | (bytes1[5] << 8) | bytes1[4];
} file_type = TYPE_FILE;
mode = locked ? "L" : "";
}
public: public:
int inode; int inode;
uint32_t start_sector; uint32_t start_sector;
uint32_t load_address; uint32_t load_address;
uint32_t exec_address; uint32_t exec_address;
bool locked; bool locked;
}; };
class AcornDfsFilesystem : public Filesystem class AcornDfsFilesystem : public Filesystem
@@ -37,7 +39,7 @@ class AcornDfsFilesystem : public Filesystem
public: public:
AcornDfsFilesystem( AcornDfsFilesystem(
const AcornDfsProto& config, std::shared_ptr<SectorInterface> sectors): const AcornDfsProto& config, std::shared_ptr<SectorInterface> sectors):
Filesystem(sectors), Filesystem(sectors),
_config(config) _config(config)
{ {
} }
@@ -53,46 +55,49 @@ public:
throw FileNotFoundException(); throw FileNotFoundException();
std::vector<std::unique_ptr<Dirent>> result; std::vector<std::unique_ptr<Dirent>> result;
for (auto& dirent : findAllFiles()) for (auto& dirent : findAllFiles())
result.push_back(std::move(dirent)); result.push_back(std::move(dirent));
return result; return result;
} }
Bytes getFile(const Path& path) Bytes getFile(const Path& path)
{ {
auto dirent = findFile(path); auto dirent = findFile(path);
int sectors = (dirent->length + 255) / 256; int sectors = (dirent->length + 255) / 256;
Bytes data; Bytes data;
ByteWriter bw(data); ByteWriter bw(data);
for (int i = 0; i < sectors; i++) for (int i = 0; i < sectors; i++)
{ {
auto sector = getLogicalSector(dirent->start_sector + i); auto sector = getLogicalSector(dirent->start_sector + i);
bw.append(sector); bw.append(sector);
} }
data.resize(dirent->length); data.resize(dirent->length);
return data; return data;
} }
std::map<std::string, std::string> getMetadata(const Path& path) std::map<std::string, std::string> getMetadata(const Path& path)
{ {
std::map<std::string, std::string> attributes; std::map<std::string, std::string> attributes;
auto dirent = findFile(path); auto dirent = findFile(path);
attributes["filename"] = dirent->filename; attributes["filename"] = dirent->filename;
attributes["length"] = fmt::format("{}", dirent->length); attributes["length"] = fmt::format("{}", dirent->length);
attributes["type"] = "file"; attributes["type"] = "file";
attributes["mode"] = dirent->mode; attributes["mode"] = dirent->mode;
attributes["acorndfs.inode"] = fmt::format("{}", dirent->inode); attributes["acorndfs.inode"] = fmt::format("{}", dirent->inode);
attributes["acorndfs.start_sector"] = fmt::format("{}", dirent->start_sector); attributes["acorndfs.start_sector"] =
attributes["acorndfs.load_address"] = fmt::format("0x{:x}", dirent->load_address); fmt::format("{}", dirent->start_sector);
attributes["acorndfs.exec_address"] = fmt::format("0x{:x}", dirent->exec_address); attributes["acorndfs.load_address"] =
attributes["acorndfs.locked"] = fmt::format("{}", dirent->locked); fmt::format("0x{:x}", dirent->load_address);
attributes["acorndfs.exec_address"] =
fmt::format("0x{:x}", dirent->exec_address);
attributes["acorndfs.locked"] = fmt::format("{}", dirent->locked);
return attributes; return attributes;
} }
private: private:
std::vector<std::unique_ptr<AcornDfsDirent>> findAllFiles() std::vector<std::unique_ptr<AcornDfsDirent>> findAllFiles()
@@ -110,25 +115,26 @@ private:
auto bytes0 = sector0.slice(i * 8 + 8, 8); auto bytes0 = sector0.slice(i * 8 + 8, 8);
auto bytes1 = sector1.slice(i * 8 + 8, 8); auto bytes1 = sector1.slice(i * 8 + 8, 8);
result.push_back(std::make_unique<AcornDfsDirent>(i, bytes0, bytes1)); result.push_back(
std::make_unique<AcornDfsDirent>(i, bytes0, bytes1));
} }
return result; return result;
} }
std::unique_ptr<AcornDfsDirent> findFile(const Path& path) std::unique_ptr<AcornDfsDirent> findFile(const Path& path)
{ {
if (path.size() != 1) if (path.size() != 1)
throw BadPathException(); throw BadPathException();
for (auto& dirent : findAllFiles()) for (auto& dirent : findAllFiles())
{ {
if (dirent->filename == path[0]) if (dirent->filename == path[0])
return std::move(dirent); return std::move(dirent);
} }
throw FileNotFoundException(); throw FileNotFoundException();
} }
private: private:
const AcornDfsProto& _config; const AcornDfsProto& _config;

View File

@@ -147,6 +147,30 @@ public:
return bytes; return bytes;
} }
void putFile(const Path& path, const Bytes& data)
{
AdfMount m(this);
if (path.size() == 0)
throw BadPathException();
auto* vol = m.getVolume();
changeDirButOne(vol, path);
auto* file = adfOpenFile(vol, (char*)path.back().c_str(), (char*)"w");
if (!file)
throw CannotWriteException();
unsigned pos = 0;
while (pos != data.size())
{
long done = adfWriteFile(
file, data.size() - pos, (uint8_t*)data.cbegin() + pos);
pos += done;
}
adfCloseFile(file);
}
private: private:
class AdfEntry class AdfEntry
{ {
@@ -270,6 +294,8 @@ public:
RETCODE adfNativeWriteSector( RETCODE adfNativeWriteSector(
struct Device* dev, int32_t sector, int size, uint8_t* buffer) struct Device* dev, int32_t sector, int size, uint8_t* buffer)
{ {
Bytes bytes(buffer, size);
putLogicalSector(sector, bytes);
return RC_OK; return RC_OK;
} }

View File

@@ -33,9 +33,9 @@ void AppleSingle::parse(const Bytes& bytes)
case 9: case 9:
{ {
Bytes finderinfo = bytes.slice(offset, length); Bytes finderinfo = bytes.slice(offset, length);
type = finderinfo.slice(0, 4); type = finderinfo.slice(0, 4);
creator = finderinfo.slice(4, 4); creator = finderinfo.slice(4, 4);
break; break;
} }

View File

@@ -27,32 +27,32 @@ static constexpr int DIRECTORY_SECTORS = 8;
class Brother120Dirent : public Dirent class Brother120Dirent : public Dirent
{ {
public: public:
Brother120Dirent(int inode, const Bytes& bytes) Brother120Dirent(int inode, const Bytes& bytes)
{ {
ByteReader br(bytes); ByteReader br(bytes);
filename = br.read(8); filename = br.read(8);
filename = filename.substr(0, filename.find(' ')); filename = filename.substr(0, filename.find(' '));
this->inode = inode; this->inode = inode;
brother_type = br.read_8(); brother_type = br.read_8();
start_sector = br.read_be16(); start_sector = br.read_be16();
length = br.read_8() * SECTOR_SIZE; length = br.read_8() * SECTOR_SIZE;
file_type = TYPE_FILE; file_type = TYPE_FILE;
mode = ""; mode = "";
} }
public: public:
int inode; int inode;
int brother_type; int brother_type;
uint32_t start_sector; uint32_t start_sector;
}; };
class Brother120Filesystem : public Filesystem class Brother120Filesystem : public Filesystem
{ {
public: public:
Brother120Filesystem( Brother120Filesystem(const Brother120FsProto& config,
const Brother120FsProto& config, std::shared_ptr<SectorInterface> sectors): std::shared_ptr<SectorInterface> sectors):
Filesystem(sectors), Filesystem(sectors),
_config(config) _config(config)
{ {
} }
@@ -64,97 +64,98 @@ public:
std::vector<std::unique_ptr<Dirent>> list(const Path& path) std::vector<std::unique_ptr<Dirent>> list(const Path& path)
{ {
if (!path.empty()) if (!path.empty())
throw FileNotFoundException(); throw FileNotFoundException();
std::vector<std::unique_ptr<Dirent>> result; std::vector<std::unique_ptr<Dirent>> result;
for (auto& dirent : findAllFiles()) for (auto& dirent : findAllFiles())
result.push_back(std::move(dirent)); result.push_back(std::move(dirent));
return result; return result;
} }
Bytes getFile(const Path& path) Bytes getFile(const Path& path)
{ {
auto fat = readFat(); auto fat = readFat();
auto dirent = findFile(path); auto dirent = findFile(path);
int sector = dirent->start_sector; int sector = dirent->start_sector;
Bytes data; Bytes data;
ByteWriter bw(data); ByteWriter bw(data);
while ((sector != 0) && (sector != 0xffff)) while ((sector != 0) && (sector != 0xffff))
{ {
bw += getLogicalSector(sector - 1); bw += getLogicalSector(sector - 1);
sector = fat.at(sector); sector = fat.at(sector);
} }
return data; return data;
} }
std::map<std::string, std::string> getMetadata(const Path& path) std::map<std::string, std::string> getMetadata(const Path& path)
{ {
std::map<std::string, std::string> attributes; std::map<std::string, std::string> attributes;
auto dirent = findFile(path); auto dirent = findFile(path);
attributes["filename"] = dirent->filename; attributes["filename"] = dirent->filename;
attributes["length"] = fmt::format("{}", dirent->length); attributes["length"] = fmt::format("{}", dirent->length);
attributes["type"] = "file"; attributes["type"] = "file";
attributes["mode"] = dirent->mode; attributes["mode"] = dirent->mode;
attributes["brother120.inode"] = fmt::format("{}", dirent->inode); attributes["brother120.inode"] = fmt::format("{}", dirent->inode);
attributes["brother120.start_sector"] = fmt::format("{}", dirent->start_sector); attributes["brother120.start_sector"] =
attributes["brother120.type"] = fmt::format("{}", dirent->brother_type); fmt::format("{}", dirent->start_sector);
attributes["brother120.type"] = fmt::format("{}", dirent->brother_type);
return attributes; return attributes;
} }
private: private:
std::vector<uint32_t> readFat() std::vector<uint32_t> readFat()
{ {
Bytes bytes = getLogicalSector(FAT_START_SECTOR, FAT_SECTORS); Bytes bytes = getLogicalSector(FAT_START_SECTOR, FAT_SECTORS);
ByteReader br(bytes); ByteReader br(bytes);
std::vector<uint32_t> table; std::vector<uint32_t> table;
table.push_back(0xffff); table.push_back(0xffff);
for (int sector = 1; sector != SECTOR_COUNT; sector++) for (int sector = 1; sector != SECTOR_COUNT; sector++)
table.push_back(br.read_be16()); table.push_back(br.read_be16());
return table; return table;
} }
std::vector<std::unique_ptr<Brother120Dirent>> findAllFiles() std::vector<std::unique_ptr<Brother120Dirent>> findAllFiles()
{ {
std::vector<std::unique_ptr<Brother120Dirent>> result; std::vector<std::unique_ptr<Brother120Dirent>> result;
int inode = 0; int inode = 0;
for (int block = 0; block < DIRECTORY_SECTORS; block++) for (int block = 0; block < DIRECTORY_SECTORS; block++)
{ {
auto bytes = getLogicalSector(block); auto bytes = getLogicalSector(block);
for (int d = 0; d < SECTOR_SIZE/16; d++, inode++) for (int d = 0; d < SECTOR_SIZE / 16; d++, inode++)
{ {
Bytes buffer = bytes.slice(d*16, 16); Bytes buffer = bytes.slice(d * 16, 16);
if (buffer[0] == 0xf0) if (buffer[0] == 0xf0)
continue; continue;
result.push_back( result.push_back(
std::make_unique<Brother120Dirent>(inode, buffer)); std::make_unique<Brother120Dirent>(inode, buffer));
} }
} }
return result; return result;
} }
std::unique_ptr<Brother120Dirent> findFile(const Path& path) std::unique_ptr<Brother120Dirent> findFile(const Path& path)
{ {
if (path.size() != 1) if (path.size() != 1)
throw BadPathException(); throw BadPathException();
for (auto& dirent : findAllFiles()) for (auto& dirent : findAllFiles())
{ {
if (dirent->filename == path[0]) if (dirent->filename == path[0])
return std::move(dirent); return std::move(dirent);
} }
throw FileNotFoundException(); throw FileNotFoundException();
} }
private: private:
const Brother120FsProto& _config; const Brother120FsProto& _config;

View File

@@ -6,11 +6,11 @@
enum enum
{ {
DEL, DEL,
SEQ, SEQ,
PRG, PRG,
USR, USR,
REL REL
}; };
static std::string fromPetscii(const Bytes& bytes) static std::string fromPetscii(const Bytes& bytes)
@@ -30,25 +30,31 @@ static std::string fromPetscii(const Bytes& bytes)
static std::string toMode(uint8_t cbm_type) static std::string toMode(uint8_t cbm_type)
{ {
std::stringstream ss; std::stringstream ss;
if (cbm_type & 0x40) if (cbm_type & 0x40)
ss << 'L'; ss << 'L';
if (cbm_type & 0x80) if (cbm_type & 0x80)
ss << 'S'; ss << 'S';
return ss.str(); return ss.str();
} }
static std::string toFileType(uint8_t cbm_type) static std::string toFileType(uint8_t cbm_type)
{ {
switch (cbm_type & 0x0f) switch (cbm_type & 0x0f)
{ {
case DEL: return "DEL"; case DEL:
case SEQ: return "SEQ"; return "DEL";
case PRG: return "PRG"; case SEQ:
case USR: return "USR"; return "SEQ";
case REL: return "REL"; case PRG:
default: return fmt::format("[bad type {:x}]", cbm_type & 0x0f); return "PRG";
} case USR:
return "USR";
case REL:
return "REL";
default:
return fmt::format("[bad type {:x}]", cbm_type & 0x0f);
}
} }
class CbmfsDirent : public Dirent class CbmfsDirent : public Dirent
@@ -63,7 +69,7 @@ public:
start_track = br.read_8(); start_track = br.read_8();
start_sector = br.read_8(); start_sector = br.read_8();
auto filenameBytes = br.read(16).split(0xa0)[0]; auto filenameBytes = br.read(16).split(0xa0)[0];
filename = fromPetscii(filenameBytes); filename = fromPetscii(filenameBytes);
side_track = br.read_8(); side_track = br.read_8();
side_sector = br.read_8(); side_sector = br.read_8();
@@ -103,8 +109,8 @@ public:
std::vector<std::unique_ptr<Dirent>> list(const Path& path) std::vector<std::unique_ptr<Dirent>> list(const Path& path)
{ {
if (path.size() != 0) if (path.size() != 0)
throw BadPathException(); throw BadPathException();
std::vector<std::unique_ptr<Dirent>> results; std::vector<std::unique_ptr<Dirent>> results;
uint8_t t = _config.directory_track(); uint8_t t = _config.directory_track();
@@ -131,64 +137,64 @@ public:
std::map<std::string, std::string> getMetadata(const Path& path) std::map<std::string, std::string> getMetadata(const Path& path)
{ {
if (path.size() != 1)
throw BadPathException();
auto de = findFile(unhex(path[0]));
if (!de)
throw FileNotFoundException();
std::map<std::string, std::string> attributes;
attributes["filename"] = de->filename;
attributes["length"] = fmt::format("{}", de->length);
attributes["mode"] = de->mode;
attributes["type"] = "file";
attributes["cbmfs.type"] = toFileType(de->cbm_type);
attributes["cbmfs.start_track"] = fmt::format("{}", de->start_track);
attributes["cbmfs.start_sector"] = fmt::format("{}", de->start_sector);
attributes["cbmfs.side_track"] = fmt::format("{}", de->side_track);
attributes["cbmfs.side_sector"] = fmt::format("{}", de->side_sector);
attributes["cbmfs.recordlen"] = fmt::format("{}", de->recordlen);
attributes["cbmfs.sectors"] = fmt::format("{}", de->sectors);
return attributes;
}
Bytes getFile(const Path& path)
{
if (path.size() != 1) if (path.size() != 1)
throw BadPathException(); throw BadPathException();
auto de = findFile(unhex(path[0])); auto de = findFile(unhex(path[0]));
if (!de) if (!de)
throw FileNotFoundException(); throw FileNotFoundException();
if (de->cbm_type == REL)
throw UnimplementedFilesystemException("cannot read .REL files");
Bytes bytes; std::map<std::string, std::string> attributes;
ByteWriter bw(bytes); attributes["filename"] = de->filename;
attributes["length"] = fmt::format("{}", de->length);
attributes["mode"] = de->mode;
attributes["type"] = "file";
attributes["cbmfs.type"] = toFileType(de->cbm_type);
attributes["cbmfs.start_track"] = fmt::format("{}", de->start_track);
attributes["cbmfs.start_sector"] = fmt::format("{}", de->start_sector);
attributes["cbmfs.side_track"] = fmt::format("{}", de->side_track);
attributes["cbmfs.side_sector"] = fmt::format("{}", de->side_sector);
attributes["cbmfs.recordlen"] = fmt::format("{}", de->recordlen);
attributes["cbmfs.sectors"] = fmt::format("{}", de->sectors);
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 t = de->start_track - 1;
uint8_t s = de->start_sector; uint8_t s = de->start_sector;
for (;;) for (;;)
{ {
auto b = getSector(t, 0, s); auto b = getSector(t, 0, s);
if (b[0]) if (b[0])
bw += b.slice(2); bw += b.slice(2);
else else
{ {
bw += b.slice(2, b[1]); bw += b.slice(2, b[1]);
break; break;
} }
t = b[0] - 1; t = b[0] - 1;
s = b[1]; s = b[1];
} }
return bytes; return bytes;
} }
private: private:
std::unique_ptr<CbmfsDirent> findFile(const std::string& filename) std::unique_ptr<CbmfsDirent> findFile(const std::string& filename)
{ {
uint8_t t = _config.directory_track(); uint8_t t = _config.directory_track();
uint8_t s = 1; uint8_t s = 1;
while (t != 0xff) while (t != 0xff)
@@ -201,17 +207,17 @@ private:
if (dbuf[2] == 0) if (dbuf[2] == 0)
continue; continue;
auto de = std::make_unique<CbmfsDirent>(dbuf); auto de = std::make_unique<CbmfsDirent>(dbuf);
if (de->filename == filename) if (de->filename == filename)
return de; return de;
} }
t = b[0] - 1; t = b[0] - 1;
s = b[1]; s = b[1];
} }
return nullptr; return nullptr;
} }
private: private:
const CbmfsProto& _config; const CbmfsProto& _config;

View File

@@ -116,6 +116,30 @@ public:
return bytes; return bytes;
} }
void putFile(const Path& path, const Bytes& bytes)
{
mount();
auto pathstr = path.to_str();
FIL fil;
FRESULT res =
f_open(&fil, pathstr.c_str(), FA_WRITE | FA_CREATE_ALWAYS);
throwError(res);
unsigned remaining = bytes.size();
char* ptr = (char*)bytes.cbegin();
while (remaining != 0)
{
UINT done;
res = f_write(&fil, ptr, remaining, &done);
throwError(res);
remaining -= done;
ptr += done;
}
f_close(&fil);
}
public: public:
DRESULT diskRead(BYTE* buffer, LBA_t sector, UINT count) DRESULT diskRead(BYTE* buffer, LBA_t sector, UINT count)
{ {
@@ -126,7 +150,9 @@ public:
DRESULT diskWrite(const BYTE* buffer, LBA_t sector, UINT count) DRESULT diskWrite(const BYTE* buffer, LBA_t sector, UINT count)
{ {
return RES_WRPRT; Bytes bytes(buffer, count * getLogicalSectorSize());
putLogicalSector(sector, bytes);
return RES_OK;
} }
DRESULT diskIoctl(BYTE cmd, void* buffer) DRESULT diskIoctl(BYTE cmd, void* buffer)
@@ -163,6 +189,16 @@ private:
case FR_NO_PATH: case FR_NO_PATH:
throw FileNotFoundException(); throw FileNotFoundException();
case FR_INVALID_NAME:
throw BadPathException();
case FR_DENIED:
case FR_EXIST:
case FR_WRITE_PROTECTED:
case FR_MKFS_ABORTED:
case FR_LOCKED:
throw CannotWriteException();
case FR_NO_FILESYSTEM: case FR_NO_FILESYSTEM:
throw BadFilesystemException(); throw BadFilesystemException();

View File

@@ -4,14 +4,20 @@
#include "lib/readerwriter.h" #include "lib/readerwriter.h"
#include "lib/decoders/decoders.h" #include "lib/decoders/decoders.h"
#include "lib/fluxsource/fluxsource.h" #include "lib/fluxsource/fluxsource.h"
#include "lib/layout.h"
#include "lib/proto.h"
#include "lib/mapper.h" #include "lib/mapper.h"
class FluxSectorInterface : public SectorInterface class FluxSectorInterface : public SectorInterface
{ {
public: public:
FluxSectorInterface(std::shared_ptr<FluxSource> fluxSource, FluxSectorInterface(std::shared_ptr<FluxSource> fluxSource,
std::shared_ptr<FluxSink> fluxSink,
std::shared_ptr<AbstractEncoder> encoder,
std::shared_ptr<AbstractDecoder> decoder): std::shared_ptr<AbstractDecoder> decoder):
_fluxSource(fluxSource), _fluxSource(fluxSource),
_fluxSink(fluxSink),
_encoder(encoder),
_decoder(decoder) _decoder(decoder)
{ {
} }
@@ -20,47 +26,124 @@ public:
std::shared_ptr<const Sector> get( std::shared_ptr<const Sector> get(
unsigned track, unsigned side, unsigned sectorId) unsigned track, unsigned side, unsigned sectorId)
{ {
auto it = _changedSectors.get(track, side, sectorId);
if (it)
return it;
trackid_t trackid(track, side); trackid_t trackid(track, side);
if (_loadedtracks.find(trackid) == _loadedtracks.end()) if (_loadedtracks.find(trackid) == _loadedtracks.end())
populateSectors(track, side); populateSectors(track, side);
return _sectorstore.get(track, side, sectorId); return _readSectors.get(track, side, sectorId);
} }
std::shared_ptr<Sector> put( std::shared_ptr<Sector> put(
unsigned track, unsigned side, unsigned sectorId) unsigned track, unsigned side, unsigned sectorId)
{ {
trackid_t trackid(track, side); trackid_t trackid(track, side);
if (_loadedtracks.find(trackid) == _loadedtracks.end()) _changedtracks.insert(trackid);
populateSectors(track, side); return _changedSectors.put(track, side, sectorId);
}
_changedtracks.insert(trackid); void flush()
return _sectorstore.put(track, side, sectorId); {
for (const auto& trackid : _changedtracks)
{
unsigned track = trackid.first;
unsigned side = trackid.second;
auto layoutdata = Layout::getLayoutOfTrack(track, side);
auto sectors = Layout::getSectorsInTrack(layoutdata);
config.mutable_tracks()->Clear();
config.mutable_tracks()->set_start(track);
config.mutable_heads()->Clear();
config.mutable_heads()->set_start(side);
/* Check to see if we have all sectors of this track in the
* changesectors image. */
if (imageContainsAllSectorsOf(
_changedSectors, track, side, sectors))
{
/* Just write directly from the changedsectors image. */
writeDiskCommand(_changedSectors,
*_encoder,
*_fluxSink,
&*_decoder,
&*_fluxSource);
}
else
{
/* Only a few sectors have changed. Do we need to populate the
* track? */
if (_loadedtracks.find(trackid) == _loadedtracks.end())
populateSectors(track, side);
/* Now merge the loaded track with the changed one, and write
* the result back. */
Image image;
for (const unsigned sector : sectors)
{
auto s = image.put(track, side, sector);
if (_changedSectors.contains(track, side, sector))
s->data =
_changedSectors.get(track, side, sector)->data;
else
s->data = _readSectors.get(track, side, sector)->data;
}
writeDiskCommand(
image, *_encoder, *_fluxSink, &*_decoder, &*_fluxSource);
}
}
} }
private: private:
bool imageContainsAllSectorsOf(const Image& image,
unsigned track,
unsigned side,
const std::vector<unsigned>& sectors)
{
for (unsigned sector : sectors)
{
if (!image.contains(track, side, sector))
return false;
}
return true;
}
void populateSectors(unsigned track, unsigned side) void populateSectors(unsigned track, unsigned side)
{ {
auto location = Mapper::computeLocationFor(track, side); auto location = Mapper::computeLocationFor(track, side);
auto trackdata = auto trackdata = readAndDecodeTrack(*_fluxSource, *_decoder, location);
readAndDecodeTrack(*_fluxSource, *_decoder, location);
for (const auto& sector : trackdata->sectors) for (const auto& sector : trackdata->sectors)
*_sectorstore.put(track, side, sector->logicalSector) = *sector; *_readSectors.put(track, side, sector->logicalSector) = *sector;
_loadedtracks.insert(trackid_t(track, side)); _loadedtracks.insert(trackid_t(track, side));
} }
std::shared_ptr<FluxSource> _fluxSource; std::shared_ptr<FluxSource> _fluxSource;
std::shared_ptr<FluxSink> _fluxSink;
std::shared_ptr<AbstractEncoder> _encoder;
std::shared_ptr<AbstractDecoder> _decoder; std::shared_ptr<AbstractDecoder> _decoder;
typedef std::pair<unsigned, unsigned> trackid_t; typedef std::pair<unsigned, unsigned> trackid_t;
Image _sectorstore; Image _readSectors;
Image _changedSectors;
std::set<trackid_t> _loadedtracks; std::set<trackid_t> _loadedtracks;
std::set<trackid_t> _changedtracks; std::set<trackid_t> _changedtracks;
}; };
std::unique_ptr<SectorInterface> SectorInterface::createFluxSectorInterface( std::unique_ptr<SectorInterface> SectorInterface::createFluxSectorInterface(
std::shared_ptr<FluxSource> fluxSource, std::shared_ptr<AbstractDecoder> decoder) std::shared_ptr<FluxSource> fluxSource,
std::shared_ptr<FluxSink> fluxSink,
std::shared_ptr<AbstractEncoder> encoder,
std::shared_ptr<AbstractDecoder> decoder)
{ {
return std::make_unique<FluxSectorInterface>(fluxSource, decoder); return std::make_unique<FluxSectorInterface>(
fluxSource, fluxSink, encoder, decoder);
} }

View File

@@ -5,27 +5,27 @@
class ImageSectorInterface : public SectorInterface class ImageSectorInterface : public SectorInterface
{ {
public: public:
ImageSectorInterface(std::shared_ptr<Image> image): ImageSectorInterface(std::shared_ptr<Image> image): _image(image) {}
_image(image)
{}
public: public:
std::shared_ptr<const Sector> get(unsigned track, unsigned side, unsigned sectorId) std::shared_ptr<const Sector> get(
{ unsigned track, unsigned side, unsigned sectorId)
return _image->get(track, side, sectorId); {
} return _image->get(track, side, sectorId);
}
std::shared_ptr<Sector> put(unsigned track, unsigned side, unsigned sectorId) std::shared_ptr<Sector> put(
{ unsigned track, unsigned side, unsigned sectorId)
return _image->put(track, side, sectorId); {
} return _image->put(track, side, sectorId);
}
private: private:
std::shared_ptr<Image> _image; std::shared_ptr<Image> _image;
}; };
std::unique_ptr<SectorInterface> SectorInterface::createImageSectorInterface(std::shared_ptr<Image> image) std::unique_ptr<SectorInterface> SectorInterface::createImageSectorInterface(
std::shared_ptr<Image> image)
{ {
return std::make_unique<ImageSectorInterface>(image); return std::make_unique<ImageSectorInterface>(image);
} }

View File

@@ -130,8 +130,8 @@ public:
hfsdirent de; hfsdirent de;
hfs_fstat(file, &de); hfs_fstat(file, &de);
a.creator = Bytes(de.u.file.creator); a.creator = Bytes(de.u.file.creator);
a.type = Bytes(de.u.file.type); a.type = Bytes(de.u.file.type);
hfs_setfork(file, 0); hfs_setfork(file, 0);
a.data = readBytes(file); a.data = readBytes(file);
@@ -141,6 +141,38 @@ public:
return a.render(); return a.render();
} }
void putFile(const Path& path, const Bytes& bytes)
{
HfsMount m(this);
if (path.size() == 0)
throw BadPathException();
AppleSingle a;
try
{
a.parse(bytes);
}
catch (const InvalidFileException& e)
{
throw UnimplementedFilesystemException(
"you can only write valid AppleSingle encoded files");
}
auto pathstr = ":" + path.to_str(":");
hfs_delete(_vol, pathstr.c_str());
HfsFile file(hfs_create(_vol,
pathstr.c_str(),
(const char*)a.type.cbegin(),
(const char*)a.creator.cbegin()));
if (!file)
throw CannotWriteException();
hfs_setfork(file, 0);
writeBytes(file, a.data);
hfs_setfork(file, 1);
writeBytes(file, a.rsrc);
}
private: private:
Bytes readBytes(hfsfile* file) Bytes readBytes(hfsfile* file)
{ {
@@ -161,6 +193,17 @@ private:
return bytes; return bytes;
} }
void writeBytes(hfsfile* file, const Bytes& bytes)
{
unsigned pos = 0;
while (pos != bytes.size())
{
unsigned long done =
hfs_write(file, bytes.cbegin() + pos, bytes.size() - pos);
pos += done;
}
}
private: private:
class HfsMount class HfsMount
{ {
@@ -183,23 +226,39 @@ private:
class HfsFile class HfsFile
{ {
public: public:
HfsFile(hfsfile* file): _file(file) {} HfsFile(hfsfile* file): _file(file) {}
~HfsFile() { hfs_close(_file); } ~HfsFile()
{
if (_file)
hfs_close(_file);
}
operator hfsfile*() const
{
return _file;
}
operator hfsfile* () const { return _file; }
private: private:
hfsfile* _file; hfsfile* _file;
}; };
class HfsDir class HfsDir
{ {
public: public:
HfsDir(hfsdir* dir): _dir(dir) {} HfsDir(hfsdir* dir): _dir(dir) {}
~HfsDir() { hfs_closedir(_dir); } ~HfsDir()
{
if (_dir)
hfs_closedir(_dir);
}
operator hfsdir*() const
{
return _dir;
}
operator hfsdir* () const { return _dir; }
private: private:
hfsdir* _dir; hfsdir* _dir;
}; };
private: private:
@@ -227,7 +286,10 @@ private:
void** priv, const void* buffer, unsigned long len); void** priv, const void* buffer, unsigned long len);
unsigned long hfsWrite(const void* buffer, unsigned long len) unsigned long hfsWrite(const void* buffer, unsigned long len)
{ {
return -1; Bytes bytes((const uint8_t*)buffer, len * 512);
putLogicalSector(_seek, bytes);
_seek += len;
return len;
} }
private: private:

View File

@@ -4,7 +4,9 @@
class Image; class Image;
class Sector; class Sector;
class FluxSource; class FluxSource;
class FluxSink;
class AbstractDecoder; class AbstractDecoder;
class AbstractEncoder;
class SectorInterface class SectorInterface
{ {
@@ -21,6 +23,8 @@ public:
std::shared_ptr<Image> image); std::shared_ptr<Image> image);
static std::unique_ptr<SectorInterface> createFluxSectorInterface( static std::unique_ptr<SectorInterface> createFluxSectorInterface(
std::shared_ptr<FluxSource> fluxSource, std::shared_ptr<FluxSource> fluxSource,
std::shared_ptr<FluxSink> fluxSink,
std::shared_ptr<AbstractEncoder> encoder,
std::shared_ptr<AbstractDecoder> decoder); std::shared_ptr<AbstractDecoder> decoder);
}; };

View File

@@ -33,6 +33,57 @@ std::string Path::to_str(const std::string sep) const
return join(*this, sep); return join(*this, sep);
} }
void Filesystem::create()
{
throw UnimplementedFilesystemException();
}
FilesystemStatus Filesystem::check()
{
throw UnimplementedFilesystemException();
}
std::vector<std::unique_ptr<Dirent>> 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::map<std::string, std::string> Filesystem::getMetadata(const Path& path)
{
throw UnimplementedFilesystemException();
}
void Filesystem::putMetadata(
const Path& path, const std::map<std::string, std::string>& metadata)
{
throw UnimplementedFilesystemException();
}
void Filesystem::createDirectory(const Path& path)
{
throw UnimplementedFilesystemException();
}
void Filesystem::deleteFile(const Path& path)
{
throw UnimplementedFilesystemException();
}
void Filesystem::flush()
{
_sectors->flush();
}
Filesystem::Filesystem(std::shared_ptr<SectorInterface> sectors): Filesystem::Filesystem(std::shared_ptr<SectorInterface> sectors):
_sectors(sectors) _sectors(sectors)
{ {
@@ -125,8 +176,19 @@ void Filesystem::putLogicalSector(uint32_t number, const Bytes& data)
if (number >= _locations.size()) if (number >= _locations.size())
throw BadFilesystemException(); throw BadFilesystemException();
auto& i = _locations[number]; unsigned pos = 0;
_sectors->put(std::get<0>(i), std::get<1>(i), std::get<2>(i))->data = data; 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).sector_size();
_sectors->put(track, side, sector)->data = data.slice(pos, sectorSize);
pos += sectorSize;
number++;
}
} }
unsigned Filesystem::getOffsetOfSector( unsigned Filesystem::getOffsetOfSector(

View File

@@ -60,6 +60,12 @@ public:
BadFilesystemException(): FilesystemException("Invalid filesystem") {} BadFilesystemException(): FilesystemException("Invalid filesystem") {}
}; };
class CannotWriteException : public FilesystemException
{
public:
CannotWriteException(): FilesystemException("Cannot write file") {}
};
class ReadOnlyFilesystemException : public FilesystemException class ReadOnlyFilesystemException : public FilesystemException
{ {
public: public:
@@ -95,51 +101,17 @@ public:
class Filesystem class Filesystem
{ {
public: public:
virtual void create() virtual void create();
{ virtual FilesystemStatus check();
throw UnimplementedFilesystemException(); virtual std::vector<std::unique_ptr<Dirent>> list(const Path& path);
} virtual Bytes getFile(const Path& path);
virtual void putFile(const Path& path, const Bytes& data);
virtual FilesystemStatus check() virtual std::map<std::string, std::string> getMetadata(const Path& path);
{
throw UnimplementedFilesystemException();
}
virtual std::vector<std::unique_ptr<Dirent>> list(const Path& path)
{
throw UnimplementedFilesystemException();
}
virtual Bytes getFile(const Path& path)
{
throw UnimplementedFilesystemException();
}
virtual void putFile(const Path& path, const Bytes& data)
{
throw UnimplementedFilesystemException();
}
virtual std::map<std::string, std::string> getMetadata(const Path& path)
{
throw UnimplementedFilesystemException();
}
virtual void putMetadata( virtual void putMetadata(
const Path& path, const std::map<std::string, std::string>& metadata) const Path& path, const std::map<std::string, std::string>& metadata);
{ virtual void createDirectory(const Path& path);
throw UnimplementedFilesystemException(); virtual void deleteFile(const Path& path);
} void flush();
virtual void createDirectory(const Path& path)
{
throw UnimplementedFilesystemException();
}
virtual void deleteFile(const Path& path)
{
throw UnimplementedFilesystemException();
}
protected: protected:
Filesystem(std::shared_ptr<SectorInterface> sectors); Filesystem(std::shared_ptr<SectorInterface> sectors);
@@ -149,7 +121,7 @@ protected:
Bytes getLogicalSector(uint32_t number, uint32_t count = 1); Bytes getLogicalSector(uint32_t number, uint32_t count = 1);
void putLogicalSector(uint32_t number, const Bytes& data); void putLogicalSector(uint32_t number, const Bytes& data);
unsigned getOffsetOfSector(unsigned track, unsigned side, unsigned sector); unsigned getOffsetOfSector(unsigned track, unsigned side, unsigned sector);
unsigned getLogicalSectorCount(); unsigned getLogicalSectorCount();
unsigned getLogicalSectorSize(unsigned track = 0, unsigned side = 0); unsigned getLogicalSectorSize(unsigned track = 0, unsigned side = 0);

View File

@@ -2,60 +2,70 @@ syntax = "proto2";
import "lib/common.proto"; import "lib/common.proto";
message AcornDfsProto { message AcornDfsProto
enum Flavour { {
UNDEFINED = 0; enum Flavour
ACORN_DFS = 1; {
} UNDEFINED = 0;
ACORN_DFS = 1;
}
optional Flavour flavour = 1 [default = ACORN_DFS, (help) = "which flavour of DFS to implement"]; optional Flavour flavour = 1
[ default = ACORN_DFS, (help) = "which flavour of DFS to implement" ];
} }
message Brother120FsProto { message Brother120FsProto {}
message FatFsProto {}
message CpmFsProto
{
message Location
{
optional uint32 track = 1 [ (help) = "track number" ];
optional uint32 side = 2 [ (help) = "side number" ];
optional uint32 sector = 3 [ (help) = "sector ID" ];
}
message Padding
{
optional uint32 amount = 1
[ (help) = "number of sectors of padding to insert" ];
optional uint32 every = 2
[ (help) = "insert padding after this many sectors" ];
}
optional Location filesystem_start = 1
[ (help) = "position of the start of the filesystem" ];
optional int32 block_size = 2 [ (help) = "allocation block size" ];
optional int32 dir_entries = 3
[ (help) = "number of entries in the directory" ];
optional Padding padding = 4
[ (help) = "wasted sectors not considered part of the filesystem" ];
} }
message FatFsProto { message AmigaFfsProto {}
message MacHfsProto {}
message CbmfsProto
{
optional uint32 directory_track = 1 [
default = 17,
(help) = "which track the directory is on (zero-based numbering)"
];
} }
message CpmFsProto { message FilesystemProto
message Location { {
optional uint32 track = 1 [(help) = "track number"]; oneof filesystem
optional uint32 side = 2 [(help) = "side number"]; {
optional uint32 sector = 3 [(help) = "sector ID"]; AcornDfsProto acorndfs = 1;
} Brother120FsProto brother120 = 2;
FatFsProto fatfs = 3;
message Padding { CpmFsProto cpmfs = 4;
optional uint32 amount = 1 [(help) = "number of sectors of padding to insert"]; AmigaFfsProto amigaffs = 5;
optional uint32 every = 2 [(help) = "insert padding after this many sectors"]; MacHfsProto machfs = 6;
} CbmfsProto cbmfs = 7;
}
optional Location filesystem_start = 1 [(help) = "position of the start of the filesystem"];
optional int32 block_size = 2 [(help) = "allocation block size"];
optional int32 dir_entries = 3 [(help) = "number of entries in the directory"];
optional Padding padding = 4 [(help) = "wasted sectors not considered part of the filesystem"];
} }
message AmigaFfsProto {
}
message MacHfsProto {
}
message CbmfsProto {
optional uint32 directory_track = 1
[default = 17,
(help) = "which track the directory is on (zero-based numbering)"];
}
message FilesystemProto {
oneof filesystem {
AcornDfsProto acorndfs = 1;
Brother120FsProto brother120 = 2;
FatFsProto fatfs = 3;
CpmFsProto cpmfs = 4;
AmigaFfsProto amigaffs = 5;
MacHfsProto machfs = 6;
CbmfsProto cbmfs = 7;
}
}

View File

@@ -7,6 +7,7 @@ FLUXENGINE_SRCS = \
src/fe-getfileinfo.cc \ src/fe-getfileinfo.cc \
src/fe-inspect.cc \ src/fe-inspect.cc \
src/fe-ls.cc \ src/fe-ls.cc \
src/fe-putfile.cc \
src/fe-rawread.cc \ src/fe-rawread.cc \
src/fe-rawwrite.cc \ src/fe-rawwrite.cc \
src/fe-read.cc \ src/fe-read.cc \

View File

@@ -18,8 +18,8 @@
static FlagGroup flags({&fileFlags}); static FlagGroup flags({&fileFlags});
static StringFlag directory({"-p", "--path"}, "path to work on", ""); static StringFlag directory({"-p", "--path"}, "disk path to work on", "");
static StringFlag output({"-o", "--output"}, "local filename to write to", ""); static StringFlag output({"-l", "--local"}, "local filename to write to", "");
int mainGetFile(int argc, const char* argv[]) int mainGetFile(int argc, const char* argv[])
{ {

51
src/fe-putfile.cc Normal file
View File

@@ -0,0 +1,51 @@
#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 <google/protobuf/text_format.h>
#include <fstream>
static FlagGroup flags({&fileFlags});
static StringFlag path({"-p", "--path"}, "path to work on", "");
static StringFlag input({"-l", "--local"}, "local filename to read from", "");
int mainPutFile(int argc, const char* argv[])
{
if (argc == 1)
showProfiles("putfile", formats);
flags.parseFlagsWithConfigFiles(argc, argv, formats);
try
{
std::string inputFilename = input;
if (inputFilename.empty())
Error() << "you must supply a local file to read from";
Path outputFilename(path);
if (outputFilename.size() == 0)
Error() << "you must supply a destination path to write to";
auto data = Bytes::readFromFile(inputFilename);
auto filesystem = createFilesystemFromConfig();
filesystem->putFile(outputFilename, data);
filesystem->flush();
}
catch (const FilesystemException& e)
{
Error() << e.message;
}
return 0;
}

View File

@@ -86,7 +86,7 @@ int mainWrite(int argc, const char* argv[])
if (verify && config.has_flux_source() && config.flux_source().has_drive()) if (verify && config.has_flux_source() && config.flux_source().has_drive())
fluxSource = FluxSource::create(config.flux_source()); fluxSource = FluxSource::create(config.flux_source());
writeDiskCommand(image, *encoder, *fluxSink, decoder.get(), fluxSource.get()); writeDiskCommand(*image, *encoder, *fluxSink, decoder.get(), fluxSource.get());
return 0; return 0;
} }

View File

@@ -5,7 +5,9 @@
#include "proto.h" #include "proto.h"
#include "readerwriter.h" #include "readerwriter.h"
#include "lib/decoders/decoders.h" #include "lib/decoders/decoders.h"
#include "lib/encoders/encoders.h"
#include "lib/fluxsource/fluxsource.h" #include "lib/fluxsource/fluxsource.h"
#include "lib/fluxsink/fluxsink.h"
#include "lib/imagereader/imagereader.h" #include "lib/imagereader/imagereader.h"
#include "fmt/format.h" #include "fmt/format.h"
#include "fluxengine.h" #include "fluxengine.h"
@@ -32,6 +34,8 @@ static StringFlag flux({"-f", "--flux"},
{ {
FluxSource::updateConfigForFilename( FluxSource::updateConfigForFilename(
config.mutable_flux_source(), value); config.mutable_flux_source(), value);
FluxSink::updateConfigForFilename(
config.mutable_flux_sink(), value);
}); });
std::unique_ptr<Filesystem> createFilesystemFromConfig() std::unique_ptr<Filesystem> createFilesystemFromConfig()
@@ -40,8 +44,10 @@ std::unique_ptr<Filesystem> createFilesystemFromConfig()
if (config.has_flux_source()) if (config.has_flux_source())
{ {
std::shared_ptr<FluxSource> fluxSource(FluxSource::create(config.flux_source())); std::shared_ptr<FluxSource> fluxSource(FluxSource::create(config.flux_source()));
std::shared_ptr<FluxSink> fluxSink(FluxSink::create(config.flux_sink()));
std::shared_ptr<AbstractEncoder> encoder(AbstractEncoder::create(config.encoder()));
std::shared_ptr<AbstractDecoder> decoder(AbstractDecoder::create(config.decoder())); std::shared_ptr<AbstractDecoder> decoder(AbstractDecoder::create(config.decoder()));
sectorInterface = SectorInterface::createFluxSectorInterface(fluxSource, decoder); sectorInterface = SectorInterface::createFluxSectorInterface(fluxSource, fluxSink, encoder, decoder);
} }
else else
{ {

View File

@@ -10,6 +10,7 @@ extern command_cb mainGetFile;
extern command_cb mainGetFileInfo; extern command_cb mainGetFileInfo;
extern command_cb mainInspect; extern command_cb mainInspect;
extern command_cb mainLs; extern command_cb mainLs;
extern command_cb mainPutFile;
extern command_cb mainRawRead; extern command_cb mainRawRead;
extern command_cb mainRawWrite; extern command_cb mainRawWrite;
extern command_cb mainRead; extern command_cb mainRead;
@@ -40,6 +41,7 @@ static std::vector<Command> commands =
{ "ls", mainLs, "Show files on disk (or image).", }, { "ls", mainLs, "Show files on disk (or image).", },
{ "getfile", mainGetFile, "Read a file off a disk (or image).", }, { "getfile", mainGetFile, "Read a file off a disk (or image).", },
{ "getfileinfo", mainGetFileInfo, "Read file metadata off a disk (or image).", }, { "getfileinfo", mainGetFileInfo, "Read file metadata off a disk (or image).", },
{ "putfile", mainPutFile, "Write a file to disk (or image).", },
{ "rpm", mainRpm, "Measures the disk rotational speed.", }, { "rpm", mainRpm, "Measures the disk rotational speed.", },
{ "seek", mainSeek, "Moves the disk head.", }, { "seek", mainSeek, "Moves the disk head.", },
{ "test", mainTest, "Various testing commands.", }, { "test", mainTest, "Various testing commands.", },

View File

@@ -157,7 +157,7 @@ void MainWindow::OnWriteFluxButton(wxCommandEvent&)
decoder = AbstractDecoder::create(config.decoder()); decoder = AbstractDecoder::create(config.decoder());
fluxSource = FluxSource::create(config.flux_source()); fluxSource = FluxSource::create(config.flux_source());
} }
writeDiskCommand(image, *encoder, *fluxSink, decoder.get(), fluxSource.get()); writeDiskCommand(*image, *encoder, *fluxSink, decoder.get(), fluxSource.get());
}); });
} }
catch (const ErrorException& e) catch (const ErrorException& e)