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];
}
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
{
start += _low;

View File

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

View File

@@ -15,6 +15,17 @@ Image::Image(std::set<std::shared_ptr<const Sector>>& sectors)
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
{
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;
}
void Image::erase(unsigned track, unsigned side, unsigned sectorid)
{
key_t key = std::make_tuple(track, side, sectorid);
_sectors.erase(key);
}
void Image::calculateSize()
{
_geometry = {};

View File

@@ -39,8 +39,11 @@ public:
public:
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<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 end() const { return const_iterator(_sectors.cend()); }

View File

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

View File

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

View File

@@ -16,8 +16,10 @@ public:
this->inode = inode;
start_sector = ((bytes1[6] & 0x03) << 8) | bytes1[7];
load_address = ((bytes1[6] & 0x0c) << 14) | (bytes1[1] << 8) | bytes1[0];
exec_address = ((bytes1[6] & 0xc0) << 10) | (bytes1[3] << 8) | bytes1[2];
load_address =
((bytes1[6] & 0x0c) << 14) | (bytes1[1] << 8) | bytes1[0];
exec_address =
((bytes1[6] & 0xc0) << 10) | (bytes1[3] << 8) | bytes1[2];
locked = bytes0[7] & 0x80;
length = ((bytes1[6] & 0x30) << 12) | (bytes1[5] << 8) | bytes1[4];
file_type = TYPE_FILE;
@@ -86,9 +88,12 @@ public:
attributes["type"] = "file";
attributes["mode"] = dirent->mode;
attributes["acorndfs.inode"] = fmt::format("{}", dirent->inode);
attributes["acorndfs.start_sector"] = fmt::format("{}", dirent->start_sector);
attributes["acorndfs.load_address"] = fmt::format("0x{:x}", dirent->load_address);
attributes["acorndfs.exec_address"] = fmt::format("0x{:x}", dirent->exec_address);
attributes["acorndfs.start_sector"] =
fmt::format("{}", dirent->start_sector);
attributes["acorndfs.load_address"] =
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;
@@ -110,7 +115,8 @@ private:
auto bytes0 = sector0.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;

View File

@@ -147,6 +147,30 @@ public:
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:
class AdfEntry
{
@@ -270,6 +294,8 @@ public:
RETCODE adfNativeWriteSector(
struct Device* dev, int32_t sector, int size, uint8_t* buffer)
{
Bytes bytes(buffer, size);
putLogicalSector(sector, bytes);
return RC_OK;
}

View File

@@ -50,8 +50,8 @@ public:
class Brother120Filesystem : public Filesystem
{
public:
Brother120Filesystem(
const Brother120FsProto& config, std::shared_ptr<SectorInterface> sectors):
Brother120Filesystem(const Brother120FsProto& config,
std::shared_ptr<SectorInterface> sectors):
Filesystem(sectors),
_config(config)
{
@@ -101,7 +101,8 @@ public:
attributes["type"] = "file";
attributes["mode"] = dirent->mode;
attributes["brother120.inode"] = fmt::format("{}", dirent->inode);
attributes["brother120.start_sector"] = fmt::format("{}", dirent->start_sector);
attributes["brother120.start_sector"] =
fmt::format("{}", dirent->start_sector);
attributes["brother120.type"] = fmt::format("{}", dirent->brother_type);
return attributes;
@@ -128,9 +129,9 @@ private:
for (int block = 0; block < DIRECTORY_SECTORS; 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)
continue;

View File

@@ -42,12 +42,18 @@ static std::string toFileType(uint8_t cbm_type)
{
switch (cbm_type & 0x0f)
{
case DEL: return "DEL";
case SEQ: return "SEQ";
case PRG: return "PRG";
case USR: return "USR";
case REL: return "REL";
default: return fmt::format("[bad type {:x}]", cbm_type & 0x0f);
case DEL:
return "DEL";
case SEQ:
return "SEQ";
case PRG:
return "PRG";
case USR:
return "USR";
case REL:
return "REL";
default:
return fmt::format("[bad type {:x}]", cbm_type & 0x0f);
}
}

View File

@@ -116,6 +116,30 @@ public:
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:
DRESULT diskRead(BYTE* buffer, LBA_t sector, UINT count)
{
@@ -126,7 +150,9 @@ public:
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)
@@ -163,6 +189,16 @@ private:
case FR_NO_PATH:
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:
throw BadFilesystemException();

View File

@@ -4,14 +4,20 @@
#include "lib/readerwriter.h"
#include "lib/decoders/decoders.h"
#include "lib/fluxsource/fluxsource.h"
#include "lib/layout.h"
#include "lib/proto.h"
#include "lib/mapper.h"
class FluxSectorInterface : public SectorInterface
{
public:
FluxSectorInterface(std::shared_ptr<FluxSource> fluxSource,
std::shared_ptr<FluxSink> fluxSink,
std::shared_ptr<AbstractEncoder> encoder,
std::shared_ptr<AbstractDecoder> decoder):
_fluxSource(fluxSource),
_fluxSink(fluxSink),
_encoder(encoder),
_decoder(decoder)
{
}
@@ -20,47 +26,124 @@ public:
std::shared_ptr<const Sector> get(
unsigned track, unsigned side, unsigned sectorId)
{
auto it = _changedSectors.get(track, side, sectorId);
if (it)
return it;
trackid_t trackid(track, side);
if (_loadedtracks.find(trackid) == _loadedtracks.end())
populateSectors(track, side);
return _sectorstore.get(track, side, sectorId);
return _readSectors.get(track, side, sectorId);
}
std::shared_ptr<Sector> put(
unsigned track, unsigned side, unsigned sectorId)
{
trackid_t trackid(track, side);
_changedtracks.insert(trackid);
return _changedSectors.put(track, side, sectorId);
}
void flush()
{
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);
_changedtracks.insert(trackid);
return _sectorstore.put(track, side, sectorId);
/* 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:
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)
{
auto location = Mapper::computeLocationFor(track, side);
auto trackdata =
readAndDecodeTrack(*_fluxSource, *_decoder, location);
auto trackdata = readAndDecodeTrack(*_fluxSource, *_decoder, location);
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));
}
std::shared_ptr<FluxSource> _fluxSource;
std::shared_ptr<FluxSink> _fluxSink;
std::shared_ptr<AbstractEncoder> _encoder;
std::shared_ptr<AbstractDecoder> _decoder;
typedef std::pair<unsigned, unsigned> trackid_t;
Image _sectorstore;
Image _readSectors;
Image _changedSectors;
std::set<trackid_t> _loadedtracks;
std::set<trackid_t> _changedtracks;
};
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,17 +5,17 @@
class ImageSectorInterface : public SectorInterface
{
public:
ImageSectorInterface(std::shared_ptr<Image> image):
_image(image)
{}
ImageSectorInterface(std::shared_ptr<Image> image): _image(image) {}
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);
}
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);
}
@@ -24,8 +24,8 @@ private:
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);
}

View File

@@ -141,6 +141,38 @@ public:
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:
Bytes readBytes(hfsfile* file)
{
@@ -161,6 +193,17 @@ private:
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:
class HfsMount
{
@@ -184,9 +227,17 @@ private:
{
public:
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:
hfsfile* _file;
};
@@ -195,9 +246,17 @@ private:
{
public:
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:
hfsdir* _dir;
};
@@ -227,7 +286,10 @@ private:
void** priv, 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:

View File

@@ -4,7 +4,9 @@
class Image;
class Sector;
class FluxSource;
class FluxSink;
class AbstractDecoder;
class AbstractEncoder;
class SectorInterface
{
@@ -21,6 +23,8 @@ public:
std::shared_ptr<Image> image);
static std::unique_ptr<SectorInterface> createFluxSectorInterface(
std::shared_ptr<FluxSource> fluxSource,
std::shared_ptr<FluxSink> fluxSink,
std::shared_ptr<AbstractEncoder> encoder,
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);
}
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):
_sectors(sectors)
{
@@ -125,8 +176,19 @@ void Filesystem::putLogicalSector(uint32_t number, const Bytes& data)
if (number >= _locations.size())
throw BadFilesystemException();
auto& i = _locations[number];
_sectors->put(std::get<0>(i), std::get<1>(i), std::get<2>(i))->data = data;
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).sector_size();
_sectors->put(track, side, sector)->data = data.slice(pos, sectorSize);
pos += sectorSize;
number++;
}
}
unsigned Filesystem::getOffsetOfSector(

View File

@@ -60,6 +60,12 @@ public:
BadFilesystemException(): FilesystemException("Invalid filesystem") {}
};
class CannotWriteException : public FilesystemException
{
public:
CannotWriteException(): FilesystemException("Cannot write file") {}
};
class ReadOnlyFilesystemException : public FilesystemException
{
public:
@@ -95,51 +101,17 @@ public:
class Filesystem
{
public:
virtual void create()
{
throw UnimplementedFilesystemException();
}
virtual FilesystemStatus check()
{
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 create();
virtual FilesystemStatus check();
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 std::map<std::string, std::string> getMetadata(const Path& path);
virtual void putMetadata(
const Path& path, const std::map<std::string, std::string>& metadata)
{
throw UnimplementedFilesystemException();
}
virtual void createDirectory(const Path& path)
{
throw UnimplementedFilesystemException();
}
virtual void deleteFile(const Path& path)
{
throw UnimplementedFilesystemException();
}
const Path& path, const std::map<std::string, std::string>& metadata);
virtual void createDirectory(const Path& path);
virtual void deleteFile(const Path& path);
void flush();
protected:
Filesystem(std::shared_ptr<SectorInterface> sectors);

View File

@@ -2,53 +2,64 @@ syntax = "proto2";
import "lib/common.proto";
message AcornDfsProto {
enum Flavour {
message AcornDfsProto
{
enum Flavour
{
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 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 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"];
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"];
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 AmigaFfsProto {}
message MacHfsProto {}
message CbmfsProto
{
optional uint32 directory_track = 1 [
default = 17,
(help) = "which track the directory is on (zero-based numbering)"
];
}
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 {
message FilesystemProto
{
oneof filesystem
{
AcornDfsProto acorndfs = 1;
Brother120FsProto brother120 = 2;
FatFsProto fatfs = 3;
@@ -58,4 +69,3 @@ message FilesystemProto {
CbmfsProto cbmfs = 7;
}
}

View File

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

View File

@@ -18,8 +18,8 @@
static FlagGroup flags({&fileFlags});
static StringFlag directory({"-p", "--path"}, "path to work on", "");
static StringFlag output({"-o", "--output"}, "local filename to write to", "");
static StringFlag directory({"-p", "--path"}, "disk path to work on", "");
static StringFlag output({"-l", "--local"}, "local filename to write to", "");
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())
fluxSource = FluxSource::create(config.flux_source());
writeDiskCommand(image, *encoder, *fluxSink, decoder.get(), fluxSource.get());
writeDiskCommand(*image, *encoder, *fluxSink, decoder.get(), fluxSource.get());
return 0;
}

View File

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

View File

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

View File

@@ -157,7 +157,7 @@ void MainWindow::OnWriteFluxButton(wxCommandEvent&)
decoder = AbstractDecoder::create(config.decoder());
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)