mirror of
https://github.com/holub/mame
synced 2025-04-16 13:34:55 +03:00
fs: Add full jasmin read support
This commit is contained in:
parent
7ae546e0b6
commit
e72e97b174
@ -1,7 +1,7 @@
|
||||
// license:BSD-3-Clause
|
||||
// copyright-holders:Olivier Galibert
|
||||
|
||||
// Creation of Apple Oric_Jasmin floppy images
|
||||
// Management of Oric Jasmin floppy images
|
||||
|
||||
#include "emu.h"
|
||||
#include "fs_oric_jasmin.h"
|
||||
@ -29,7 +29,7 @@
|
||||
// offset 04+ : 14 file entries, 18 bytes each
|
||||
// offset 00-01: reference to the first sector of the inode, (ff, xx) when no entry
|
||||
// offset 02 : U/L for (U)nlocked or (L)ocked file
|
||||
// offset 03-0e: filename.ext, space padiing between filename and '.'
|
||||
// offset 03-0e: filename.ext, space padding between filename and '.'
|
||||
// offset 0f : S/D for (S)equential (normal) or (D)irect-access files
|
||||
// offset 10-11: number of sectors used by the file, including inode, little-endian
|
||||
//
|
||||
@ -67,11 +67,6 @@ bool fs_oric_jasmin::can_write() const
|
||||
return false;
|
||||
}
|
||||
|
||||
bool fs_oric_jasmin::has_subdirectories() const
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
std::vector<fs_meta_description> fs_oric_jasmin::volume_meta_description() const
|
||||
{
|
||||
std::vector<fs_meta_description> res;
|
||||
@ -125,22 +120,15 @@ void fs_oric_jasmin::impl::format(const fs_meta_data &meta)
|
||||
auto fmap = m_blockdev.get(bblk);
|
||||
u32 off = 0;
|
||||
for(u32 blk = 0; blk != blocks; blk += 17) {
|
||||
if(blk == bblk) {
|
||||
fmap.w8(off , 0xff);
|
||||
fmap.w8(off + 1, 0x7f);
|
||||
fmap.w8(off + 2, 0x00);
|
||||
} else {
|
||||
fmap.w8(off , 0xff);
|
||||
fmap.w8(off + 1, 0xff);
|
||||
fmap.w8(off + 2, 0x01);
|
||||
}
|
||||
if(blk == bblk)
|
||||
fmap.w24l(off, 0x07fff);
|
||||
else
|
||||
fmap.w24l(off, 0x1ffff);
|
||||
off += 3;
|
||||
}
|
||||
|
||||
for(u32 blk = blocks; blk != 17*42*2; blk += 17) {
|
||||
fmap.w8(off , 0x00);
|
||||
fmap.w8(off + 1, 0x00);
|
||||
fmap.w8(off + 2, 0x80);
|
||||
fmap.w24l(off, 0x800000);
|
||||
off += 3;
|
||||
}
|
||||
|
||||
@ -155,4 +143,287 @@ void fs_oric_jasmin::impl::format(const fs_meta_data &meta)
|
||||
bdir.w16l(2, 0x0000);
|
||||
}
|
||||
|
||||
fs_oric_jasmin::impl::impl(fsblk_t &blockdev) : filesystem_t(blockdev, 256), m_root(true)
|
||||
{
|
||||
}
|
||||
|
||||
bool fs_oric_jasmin::impl::ref_valid(u16 ref)
|
||||
{
|
||||
u8 track = ref >> 8;
|
||||
u8 sector = ref & 0xff;
|
||||
if(sector < 1 || sector > 17)
|
||||
return false;
|
||||
if(track >= m_blockdev.block_count()/17)
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
u32 fs_oric_jasmin::impl::cs_to_block(u16 ref)
|
||||
{
|
||||
u8 track = ref >> 8;
|
||||
u8 sector = ref & 0xff;
|
||||
return track * 17 + sector - 1;
|
||||
}
|
||||
|
||||
u16 fs_oric_jasmin::impl::block_to_cs(u32 block)
|
||||
{
|
||||
u8 track = block / 17;
|
||||
u8 sector = (block % 17) + 1;
|
||||
return (track << 8) | sector;
|
||||
}
|
||||
|
||||
std::string fs_oric_jasmin::impl::read_file_name(const u8 *p)
|
||||
{
|
||||
int main_len;
|
||||
for(main_len = 8; main_len > 0; main_len--)
|
||||
if(p[main_len - 1] != ' ')
|
||||
break;
|
||||
int ext_len;
|
||||
for(ext_len = 4; ext_len > 0; ext_len--)
|
||||
if(p[ext_len + 8 - 1] != ' ')
|
||||
break;
|
||||
std::string name;
|
||||
for(int i=0; i != main_len; i++)
|
||||
name += char(p[i]);
|
||||
for(int i=0; i != ext_len; i++)
|
||||
name += char(p[8 + i]);
|
||||
return name;
|
||||
}
|
||||
|
||||
|
||||
filesystem_t::dir_t fs_oric_jasmin::impl::root()
|
||||
{
|
||||
if(!m_root)
|
||||
m_root = new root_dir(*this);
|
||||
return m_root.strong();
|
||||
}
|
||||
|
||||
void fs_oric_jasmin::impl::drop_root_ref()
|
||||
{
|
||||
m_root = nullptr;
|
||||
}
|
||||
|
||||
void fs_oric_jasmin::impl::root_dir::drop_weak_references()
|
||||
{
|
||||
m_fs.drop_root_ref();
|
||||
}
|
||||
|
||||
fs_meta_data fs_oric_jasmin::impl::root_dir::metadata()
|
||||
{
|
||||
return fs_meta_data();
|
||||
}
|
||||
|
||||
std::vector<fs_dir_entry> fs_oric_jasmin::impl::root_dir::contents()
|
||||
{
|
||||
std::vector<fs_dir_entry> res;
|
||||
|
||||
auto bdir = m_fs.m_blockdev.get(20*17+1);
|
||||
uint64_t id = 0;
|
||||
for(;;) {
|
||||
for(u32 i = 0; i != 14; i ++) {
|
||||
u32 off = 4 + i*18;
|
||||
u16 ref = bdir.r16b(off);
|
||||
std::string fname = read_file_name(bdir.rodata()+off+3);
|
||||
bool system = ref == 0 && id == 0 && bdir.r32b(off+0xb) == 0x2e535953;
|
||||
if(system)
|
||||
res.emplace_back(fs_dir_entry(fname, fs_dir_entry_type::system_file, 0));
|
||||
|
||||
else if(m_fs.ref_valid(ref))
|
||||
res.emplace_back(fs_dir_entry(fname, fs_dir_entry_type::file, id));
|
||||
|
||||
id++;
|
||||
}
|
||||
u16 ref = bdir.r16b(2);
|
||||
if(!ref || !m_fs.ref_valid(ref))
|
||||
break;
|
||||
bdir = m_fs.m_blockdev.get(cs_to_block(ref));
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
std::pair<fsblk_t::block_t, u32> fs_oric_jasmin::impl::root_dir::get_dir_block(uint64_t key)
|
||||
{
|
||||
auto bdir = m_fs.m_blockdev.get(20*17+1);
|
||||
while(key >= 14) {
|
||||
u16 ref = bdir.r16b(2);
|
||||
if(!ref || !m_fs.ref_valid(ref))
|
||||
fatalerror("Incorrect file key\n");
|
||||
bdir = m_fs.m_blockdev.get(cs_to_block(ref));
|
||||
key -= 14;
|
||||
}
|
||||
return std::pair<fsblk_t::block_t, u32>(bdir, 4 + key * 18);
|
||||
}
|
||||
|
||||
filesystem_t::file_t fs_oric_jasmin::impl::root_dir::file_get(uint64_t key)
|
||||
{
|
||||
uint64_t rkey = key;
|
||||
auto [bdir, off] = get_dir_block(rkey);
|
||||
u16 ref = bdir.r16b(off);
|
||||
bool system = ref == 0 && key == 0 && bdir.r32b(off+0xb) == 0x2e535953;
|
||||
if(system)
|
||||
return file_t(new system_file(m_fs, bdir.rodata() + off));
|
||||
|
||||
if(!m_fs.ref_valid(ref))
|
||||
fatalerror("Key to deleted/non-existent file\n");
|
||||
return file_t(new file(m_fs, bdir.rodata() + off, key));
|
||||
}
|
||||
|
||||
filesystem_t::dir_t fs_oric_jasmin::impl::root_dir::dir_get(uint64_t key)
|
||||
{
|
||||
fatalerror("Directories not supported\n");
|
||||
}
|
||||
|
||||
fs_oric_jasmin::impl::file::file(impl &fs, const u8 *entry, u16 key) : m_fs(fs), m_key(key)
|
||||
{
|
||||
memcpy(m_entry, entry, 18);
|
||||
(void)m_key;
|
||||
}
|
||||
|
||||
void fs_oric_jasmin::impl::file::drop_weak_references()
|
||||
{
|
||||
}
|
||||
|
||||
fs_meta_data fs_oric_jasmin::impl::file::metadata()
|
||||
{
|
||||
fs_meta_data res;
|
||||
|
||||
res[fs_meta_name::name] = read_file_name(m_entry + 3);
|
||||
res[fs_meta_name::locked] = m_entry[2] == 'L';
|
||||
res[fs_meta_name::sequential] = m_entry[0xf] == 'S';
|
||||
res[fs_meta_name::size_in_blocks] = uint64_t(m_entry[0x10] | (m_entry[0x11] << 8));
|
||||
|
||||
u16 ref = (m_entry[0] << 8) | m_entry[1];
|
||||
auto dblk = m_fs.m_blockdev.get(cs_to_block(ref));
|
||||
res[fs_meta_name::loading_address] = uint64_t(dblk.r16l(2));
|
||||
res[fs_meta_name::length] = uint64_t(dblk.r16l(4));
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
std::vector<u8> fs_oric_jasmin::impl::file::read_all()
|
||||
{
|
||||
auto [sect, length] = build_data_sector_table();
|
||||
std::vector<u8> data(length);
|
||||
u32 pos = 0;
|
||||
for(u16 ref : sect) {
|
||||
u32 npos = pos + 256;
|
||||
if(npos > length)
|
||||
npos = length;
|
||||
if(npos > pos) {
|
||||
auto dblk = m_fs.m_blockdev.get(cs_to_block(ref));
|
||||
memcpy(data.data() + pos, dblk.rodata(), npos - pos);
|
||||
} else
|
||||
break;
|
||||
pos = npos;
|
||||
}
|
||||
return data;
|
||||
}
|
||||
|
||||
std::vector<u8> fs_oric_jasmin::impl::file::read(u64 start, u64 length)
|
||||
{
|
||||
auto [sect, rlength] = build_data_sector_table();
|
||||
length += start;
|
||||
if(length > rlength)
|
||||
length = rlength;
|
||||
|
||||
if(rlength < start)
|
||||
return std::vector<u8>();
|
||||
|
||||
std::vector<u8> data(length - start);
|
||||
u32 pos = 0;
|
||||
for(u16 ref : sect) {
|
||||
u32 npos = pos + 256;
|
||||
if(npos > length)
|
||||
npos = length;
|
||||
if(npos > pos) {
|
||||
if(npos > start) {
|
||||
u32 off = pos < start ? start & 0xff : 0;
|
||||
auto dblk = m_fs.m_blockdev.get(cs_to_block(ref));
|
||||
memcpy(data.data() + pos + off - start, dblk.rodata() + off, npos - pos - off);
|
||||
}
|
||||
} else
|
||||
break;
|
||||
pos = npos;
|
||||
}
|
||||
return data;
|
||||
}
|
||||
|
||||
std::pair<std::vector<u16>, u32> fs_oric_jasmin::impl::file::build_data_sector_table()
|
||||
{
|
||||
std::pair<std::vector<u16>, u32> res;
|
||||
u16 ref = (m_entry[0] << 8) | m_entry[1];
|
||||
auto iblk = m_fs.m_blockdev.get(cs_to_block(ref));
|
||||
u32 length = iblk.r16l(4);
|
||||
while(m_fs.ref_valid(ref)) {
|
||||
for(u32 pos = 6; pos != 256; pos += 2) {
|
||||
u16 dref = iblk.r16b(pos);
|
||||
if(!m_fs.ref_valid(dref))
|
||||
goto done;
|
||||
res.first.push_back(dref);
|
||||
}
|
||||
ref = iblk.r16b(2);
|
||||
if(!m_fs.ref_valid(ref))
|
||||
break;
|
||||
iblk = m_fs.m_blockdev.get(cs_to_block(ref));
|
||||
}
|
||||
done:
|
||||
if(length > 256 * res.first.size())
|
||||
length = 256 * res.first.size();
|
||||
res.second = length;
|
||||
return res;
|
||||
}
|
||||
|
||||
fs_oric_jasmin::impl::system_file::system_file(impl &fs, const u8 *entry) : m_fs(fs)
|
||||
{
|
||||
memcpy(m_entry, entry, 18);
|
||||
}
|
||||
|
||||
void fs_oric_jasmin::impl::system_file::drop_weak_references()
|
||||
{
|
||||
}
|
||||
|
||||
fs_meta_data fs_oric_jasmin::impl::system_file::metadata()
|
||||
{
|
||||
fs_meta_data res;
|
||||
|
||||
res[fs_meta_name::name] = read_file_name(m_entry + 3);
|
||||
res[fs_meta_name::locked] = m_entry[2] == 'L';
|
||||
res[fs_meta_name::sequential] = m_entry[0xf] == 'S';
|
||||
res[fs_meta_name::size_in_blocks] = uint64_t(m_entry[0x10] | (m_entry[0x11] << 8));
|
||||
res[fs_meta_name::length] = uint64_t(0x3e00);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
std::vector<u8> fs_oric_jasmin::impl::system_file::read_all()
|
||||
{
|
||||
std::vector<u8> data(0x3e00);
|
||||
for(u32 i = 0; i != 62; i++) {
|
||||
auto dblk = m_fs.m_blockdev.get(i);
|
||||
memcpy(data.data() + 256 * i, dblk.rodata(), 256);
|
||||
}
|
||||
return data;
|
||||
}
|
||||
|
||||
std::vector<u8> fs_oric_jasmin::impl::system_file::read(u64 start, u64 length)
|
||||
{
|
||||
if(start >= 0x3e00)
|
||||
return std::vector<u8>();
|
||||
length += start;
|
||||
if(length > 0x3e00)
|
||||
length = 0x3e00;
|
||||
std::vector<u8> data(length - start);
|
||||
|
||||
for(u32 i = start / 256; i <= (length - 1) / 256; i++) {
|
||||
u32 pos = i * 256;
|
||||
u32 off = i * 256 < start ? start & 0xff : 0;
|
||||
u32 len = i * 256 > length ? length & 0xff : 0x100;
|
||||
auto dblk = m_fs.m_blockdev.get(i);
|
||||
memcpy(data.data() + pos + off - start, dblk.rodata() + off, len);
|
||||
}
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
|
||||
const filesystem_manager_type FS_ORIC_JASMIN = &filesystem_manager_creator<fs_oric_jasmin>;;
|
||||
|
@ -1,7 +1,7 @@
|
||||
// license:BSD-3-Clause
|
||||
// copyright-holders:Olivier Galibert
|
||||
|
||||
// Creation of Oric Jasmin floppy images
|
||||
// Management of Oric Jasmin floppy images
|
||||
|
||||
#ifndef MAME_FORMATS_FS_ORIC_JASMIN_H
|
||||
#define MAME_FORMATS_FS_ORIC_JASMIN_H
|
||||
@ -14,11 +14,75 @@ class fs_oric_jasmin : public filesystem_manager_t {
|
||||
public:
|
||||
class impl : public filesystem_t {
|
||||
public:
|
||||
impl(fsblk_t &blockdev) : filesystem_t(blockdev, 256) {}
|
||||
class root_dir : public idir_t {
|
||||
public:
|
||||
root_dir(impl &i) : m_fs(i) {}
|
||||
virtual ~root_dir() = default;
|
||||
|
||||
virtual void drop_weak_references() override;
|
||||
|
||||
virtual fs_meta_data metadata() override;
|
||||
virtual std::vector<fs_dir_entry> contents() override;
|
||||
virtual file_t file_get(uint64_t key) override;
|
||||
virtual dir_t dir_get(uint64_t key) override;
|
||||
|
||||
private:
|
||||
impl &m_fs;
|
||||
|
||||
std::pair<fsblk_t::block_t, u32> get_dir_block(uint64_t key);
|
||||
};
|
||||
|
||||
class file : public ifile_t {
|
||||
public:
|
||||
file(impl &fs, const u8 *entry, u16 key);
|
||||
virtual ~file() = default;
|
||||
|
||||
virtual void drop_weak_references() override;
|
||||
|
||||
virtual fs_meta_data metadata() override;
|
||||
virtual std::vector<u8> read_all() override;
|
||||
virtual std::vector<u8> read(u64 start, u64 length) override;
|
||||
|
||||
private:
|
||||
impl &m_fs;
|
||||
u16 m_key;
|
||||
u8 m_entry[18];
|
||||
|
||||
std::pair<std::vector<u16>, u32> build_data_sector_table();
|
||||
};
|
||||
|
||||
class system_file : public ifile_t {
|
||||
public:
|
||||
system_file(impl &fs, const u8 *entry);
|
||||
virtual ~system_file() = default;
|
||||
|
||||
virtual void drop_weak_references() override;
|
||||
|
||||
virtual fs_meta_data metadata() override;
|
||||
virtual std::vector<u8> read_all() override;
|
||||
virtual std::vector<u8> read(u64 start, u64 length) override;
|
||||
|
||||
private:
|
||||
impl &m_fs;
|
||||
u8 m_entry[18];
|
||||
};
|
||||
|
||||
impl(fsblk_t &blockdev);
|
||||
virtual ~impl() = default;
|
||||
|
||||
virtual void format(const fs_meta_data &meta) override;
|
||||
virtual fs_meta_data metadata() override;
|
||||
virtual dir_t root() override;
|
||||
|
||||
static u32 cs_to_block(u16 ref);
|
||||
static u16 block_to_cs(u32 block);
|
||||
|
||||
bool ref_valid(u16 ref);
|
||||
static std::string read_file_name(const u8 *p);
|
||||
void drop_root_ref();
|
||||
|
||||
private:
|
||||
dir_t m_root;
|
||||
};
|
||||
|
||||
fs_oric_jasmin() : filesystem_manager_t() {}
|
||||
@ -29,7 +93,6 @@ public:
|
||||
virtual bool can_format() const override;
|
||||
virtual bool can_read() const override;
|
||||
virtual bool can_write() const override;
|
||||
virtual bool has_subdirectories() const override;
|
||||
|
||||
virtual std::vector<fs_meta_description> volume_meta_description() const override;
|
||||
virtual std::vector<fs_meta_description> file_meta_description() const override;
|
||||
|
@ -70,9 +70,9 @@ bool fs_prodos::can_write() const
|
||||
return false;
|
||||
}
|
||||
|
||||
bool fs_prodos::has_subdirectories() const
|
||||
char fs_prodos::directory_separator() const
|
||||
{
|
||||
return true;
|
||||
return '/';
|
||||
}
|
||||
|
||||
std::vector<fs_meta_description> fs_prodos::volume_meta_description() const
|
||||
|
@ -31,7 +31,7 @@ public:
|
||||
virtual bool can_format() const override;
|
||||
virtual bool can_read() const override;
|
||||
virtual bool can_write() const override;
|
||||
virtual bool has_subdirectories() const override;
|
||||
virtual char directory_separator() const override;
|
||||
|
||||
virtual std::vector<fs_meta_description> volume_meta_description() const override;
|
||||
virtual std::vector<fs_meta_description> file_meta_description() const override;
|
||||
|
@ -116,9 +116,4 @@ bool fs_unformatted::can_write() const
|
||||
return false;
|
||||
}
|
||||
|
||||
bool fs_unformatted::has_subdirectories() const
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
const filesystem_manager_type FS_UNFORMATTED = &filesystem_manager_creator<fs_unformatted>;
|
||||
|
@ -46,7 +46,6 @@ public:
|
||||
virtual bool can_format() const override;
|
||||
virtual bool can_read() const override;
|
||||
virtual bool can_write() const override;
|
||||
virtual bool has_subdirectories() const override;
|
||||
};
|
||||
|
||||
extern const filesystem_manager_type FS_UNFORMATTED;
|
||||
|
@ -8,17 +8,17 @@
|
||||
#include "emu.h"
|
||||
#include "fsmgr.h"
|
||||
|
||||
void fsblk_t::iblock_t::ref()
|
||||
void fs_refcounted_inner::ref()
|
||||
{
|
||||
m_ref ++;
|
||||
}
|
||||
|
||||
void fsblk_t::iblock_t::ref_weak()
|
||||
void fs_refcounted_inner::ref_weak()
|
||||
{
|
||||
m_weak_ref ++;
|
||||
}
|
||||
|
||||
void fsblk_t::iblock_t::unref()
|
||||
void fs_refcounted_inner::unref()
|
||||
{
|
||||
m_ref --;
|
||||
if(m_ref == 0) {
|
||||
@ -31,7 +31,7 @@ void fsblk_t::iblock_t::unref()
|
||||
}
|
||||
}
|
||||
|
||||
void fsblk_t::iblock_t::unref_weak()
|
||||
void fs_refcounted_inner::unref_weak()
|
||||
{
|
||||
m_weak_ref --;
|
||||
if(m_weak_ref == 0 && m_ref == 0)
|
||||
@ -39,6 +39,7 @@ void fsblk_t::iblock_t::unref_weak()
|
||||
}
|
||||
|
||||
|
||||
|
||||
void filesystem_manager_t::enumerate_f(floppy_enumerator &fe, uint32_t form_factor, const std::vector<uint32_t> &variants) const
|
||||
{
|
||||
}
|
||||
@ -89,6 +90,11 @@ std::vector<fs_meta_description> filesystem_manager_t::directory_meta_descriptio
|
||||
return res;
|
||||
}
|
||||
|
||||
char filesystem_manager_t::directory_separator() const
|
||||
{
|
||||
return 0; // Subdirectories not supported by default
|
||||
}
|
||||
|
||||
void filesystem_t::format(const fs_meta_data &meta)
|
||||
{
|
||||
fatalerror("format called on a filesystem not supporting it.\n");
|
||||
@ -126,44 +132,52 @@ const uint8_t *fsblk_t::iblock_t::rooffset(const char *function, uint32_t off, u
|
||||
|
||||
void fsblk_t::block_t::copy(u32 offset, const uint8_t *src, u32 size)
|
||||
{
|
||||
uint8_t *blk = m_block->offset("copy", offset, size);
|
||||
uint8_t *blk = m_object->offset("copy", offset, size);
|
||||
memcpy(blk, src, size);
|
||||
}
|
||||
|
||||
void fsblk_t::block_t::fill(u32 offset, uint8_t data, u32 size)
|
||||
{
|
||||
uint8_t *blk = m_block->offset("fill", offset, size);
|
||||
uint8_t *blk = m_object->offset("fill", offset, size);
|
||||
memset(blk, data, size);
|
||||
}
|
||||
|
||||
void fsblk_t::block_t::fill(uint8_t data)
|
||||
{
|
||||
uint8_t *blk = m_block->data();
|
||||
memset(blk, data, m_block->size());
|
||||
uint8_t *blk = m_object->data();
|
||||
memset(blk, data, m_object->size());
|
||||
}
|
||||
|
||||
void fsblk_t::block_t::wstr(u32 offset, const std::string &str)
|
||||
{
|
||||
uint8_t *blk = m_block->offset("wstr", offset, str.size());
|
||||
uint8_t *blk = m_object->offset("wstr", offset, str.size());
|
||||
memcpy(blk, str.data(), str.size());
|
||||
}
|
||||
|
||||
void fsblk_t::block_t::w8(u32 offset, uint8_t data)
|
||||
{
|
||||
uint8_t *blk = m_block->offset("w8", offset, 1);
|
||||
uint8_t *blk = m_object->offset("w8", offset, 1);
|
||||
blk[0] = data;
|
||||
}
|
||||
|
||||
void fsblk_t::block_t::w16b(u32 offset, u16 data)
|
||||
{
|
||||
uint8_t *blk = m_block->offset("w16b", offset, 2);
|
||||
uint8_t *blk = m_object->offset("w16b", offset, 2);
|
||||
blk[0] = data >> 8;
|
||||
blk[1] = data;
|
||||
}
|
||||
|
||||
void fsblk_t::block_t::w24b(u32 offset, u32 data)
|
||||
{
|
||||
uint8_t *blk = m_object->offset("w24b", offset, 3);
|
||||
blk[0] = data >> 16;
|
||||
blk[1] = data >> 8;
|
||||
blk[2] = data;
|
||||
}
|
||||
|
||||
void fsblk_t::block_t::w32b(u32 offset, u32 data)
|
||||
{
|
||||
uint8_t *blk = m_block->offset("w32b", offset, 4);
|
||||
uint8_t *blk = m_object->offset("w32b", offset, 4);
|
||||
blk[0] = data >> 24;
|
||||
blk[1] = data >> 16;
|
||||
blk[2] = data >> 8;
|
||||
@ -172,14 +186,22 @@ void fsblk_t::block_t::w32b(u32 offset, u32 data)
|
||||
|
||||
void fsblk_t::block_t::w16l(u32 offset, u16 data)
|
||||
{
|
||||
uint8_t *blk = m_block->offset("w16l", offset, 2);
|
||||
uint8_t *blk = m_object->offset("w16l", offset, 2);
|
||||
blk[0] = data;
|
||||
blk[1] = data >> 8;
|
||||
}
|
||||
|
||||
void fsblk_t::block_t::w24l(u32 offset, u32 data)
|
||||
{
|
||||
uint8_t *blk = m_object->offset("w24l", offset, 3);
|
||||
blk[0] = data;
|
||||
blk[1] = data >> 8;
|
||||
blk[2] = data >> 16;
|
||||
}
|
||||
|
||||
void fsblk_t::block_t::w32l(u32 offset, u32 data)
|
||||
{
|
||||
uint8_t *blk = m_block->offset("w32l", offset, 4);
|
||||
uint8_t *blk = m_object->offset("w32l", offset, 4);
|
||||
blk[0] = data;
|
||||
blk[1] = data >> 8;
|
||||
blk[2] = data >> 16;
|
||||
@ -188,13 +210,55 @@ void fsblk_t::block_t::w32l(u32 offset, u32 data)
|
||||
|
||||
std::string fsblk_t::block_t::rstr(u32 offset, u32 size)
|
||||
{
|
||||
const u8 *d = m_block->rooffset("rstr", offset, size);
|
||||
const u8 *d = m_object->rooffset("rstr", offset, size);
|
||||
std::string res;
|
||||
for(u32 i=0; i != size; i++)
|
||||
res += char(*d++);
|
||||
return res;
|
||||
}
|
||||
|
||||
uint8_t fsblk_t::block_t::r8(u32 offset)
|
||||
{
|
||||
const uint8_t *blk = m_object->offset("r8", offset, 1);
|
||||
return blk[0];
|
||||
}
|
||||
|
||||
uint16_t fsblk_t::block_t::r16b(u32 offset)
|
||||
{
|
||||
const uint8_t *blk = m_object->offset("r16b", offset, 2);
|
||||
return (blk[0] << 8) | blk[1];
|
||||
}
|
||||
|
||||
uint32_t fsblk_t::block_t::r24b(u32 offset)
|
||||
{
|
||||
const uint8_t *blk = m_object->offset("r24b", offset, 3);
|
||||
return (blk[0] << 16) | (blk[1] << 8) | blk[2];
|
||||
}
|
||||
|
||||
uint32_t fsblk_t::block_t::r32b(u32 offset)
|
||||
{
|
||||
const uint8_t *blk = m_object->offset("r32b", offset, 4);
|
||||
return (blk[0] << 24) | (blk[1] << 16) | (blk[2] << 8) | blk[3];
|
||||
}
|
||||
|
||||
uint16_t fsblk_t::block_t::r16l(u32 offset)
|
||||
{
|
||||
const uint8_t *blk = m_object->offset("r16l", offset, 2);
|
||||
return blk[0] | (blk[1] << 8);
|
||||
}
|
||||
|
||||
uint32_t fsblk_t::block_t::r24l(u32 offset)
|
||||
{
|
||||
const uint8_t *blk = m_object->offset("r24l", offset, 3);
|
||||
return blk[0] | (blk[1] << 8) | (blk[2] << 16);
|
||||
}
|
||||
|
||||
uint32_t fsblk_t::block_t::r32l(u32 offset)
|
||||
{
|
||||
const uint8_t *blk = m_object->offset("r32l", offset, 4);
|
||||
return blk[0] | (blk[1] << 8) | (blk[2] << 16) | (blk[3] << 24);
|
||||
}
|
||||
|
||||
const char *fs_meta_get_name(fs_meta_name name)
|
||||
{
|
||||
switch(name) {
|
||||
|
@ -31,6 +31,12 @@ enum class fs_meta_type {
|
||||
flag,
|
||||
};
|
||||
|
||||
enum class fs_dir_entry_type {
|
||||
dir,
|
||||
file,
|
||||
system_file,
|
||||
};
|
||||
|
||||
using fs_meta = std::variant<std::string, uint64_t, bool>;
|
||||
using fs_meta_data = std::unordered_map<fs_meta_name, fs_meta>;
|
||||
|
||||
@ -38,6 +44,77 @@ const char *fs_meta_get_name(fs_meta_name name);
|
||||
std::string fs_meta_to_string(fs_meta_type type, const fs_meta &m);
|
||||
fs_meta fs_meta_from_string(fs_meta_type type, std::string value);
|
||||
|
||||
template<typename T> class fs_refcounted_outer {
|
||||
public:
|
||||
fs_refcounted_outer(bool weak = false) : m_object(nullptr), m_is_weak_ref(weak) {}
|
||||
fs_refcounted_outer(T *object, bool weak = false) : m_object(object), m_is_weak_ref(weak) {
|
||||
ref();
|
||||
}
|
||||
|
||||
fs_refcounted_outer(const fs_refcounted_outer &cref) {
|
||||
m_object = cref.m_object;
|
||||
m_is_weak_ref = cref.m_is_weak_ref;
|
||||
ref();
|
||||
}
|
||||
|
||||
fs_refcounted_outer(fs_refcounted_outer &&cref) {
|
||||
m_object = cref.m_object;
|
||||
m_is_weak_ref = cref.m_is_weak_ref;
|
||||
cref.m_object = nullptr;
|
||||
}
|
||||
|
||||
~fs_refcounted_outer() {
|
||||
unref();
|
||||
}
|
||||
|
||||
fs_refcounted_outer<T> &operator =(T *dir) {
|
||||
unref();
|
||||
m_object = dir;
|
||||
ref();
|
||||
return *this;
|
||||
}
|
||||
|
||||
fs_refcounted_outer<T> &operator =(const fs_refcounted_outer<T> &cref) {
|
||||
unref();
|
||||
m_object = cref.m_object;
|
||||
m_is_weak_ref = cref.m_is_weak_ref;
|
||||
ref();
|
||||
return *this;
|
||||
}
|
||||
|
||||
fs_refcounted_outer<T> &operator =(fs_refcounted_outer<T> &&cref) {
|
||||
m_object = cref.m_object;
|
||||
m_is_weak_ref = cref.m_is_weak_ref;
|
||||
cref.m_object = nullptr;
|
||||
return *this;
|
||||
}
|
||||
|
||||
operator bool() const { return m_object != nullptr; }
|
||||
|
||||
protected:
|
||||
T *m_object;
|
||||
bool m_is_weak_ref;
|
||||
|
||||
private:
|
||||
void ref() {
|
||||
if(m_object) {
|
||||
if(m_is_weak_ref)
|
||||
m_object->ref_weak();
|
||||
else
|
||||
m_object->ref();
|
||||
}
|
||||
}
|
||||
|
||||
void unref() {
|
||||
if(m_object) {
|
||||
if(m_is_weak_ref)
|
||||
m_object->unref_weak();
|
||||
else
|
||||
m_object->unref();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
struct fs_meta_description {
|
||||
fs_meta_name m_name;
|
||||
@ -56,111 +133,82 @@ struct fs_meta_description {
|
||||
{}
|
||||
};
|
||||
|
||||
class fs_refcounted_inner {
|
||||
public:
|
||||
fs_refcounted_inner() : m_ref(0), m_weak_ref(0) {}
|
||||
virtual ~fs_refcounted_inner() = default;
|
||||
|
||||
void ref();
|
||||
void ref_weak();
|
||||
void unref();
|
||||
void unref_weak();
|
||||
|
||||
virtual void drop_weak_references() = 0;
|
||||
|
||||
private:
|
||||
uint32_t m_ref, m_weak_ref;
|
||||
};
|
||||
|
||||
struct fs_dir_entry {
|
||||
std::string m_name;
|
||||
fs_dir_entry_type m_type;
|
||||
uint64_t m_key;
|
||||
|
||||
fs_dir_entry(const std::string &name, fs_dir_entry_type type, uint64_t key) : m_name(name), m_type(type), m_key(key) {}
|
||||
};
|
||||
|
||||
class fsblk_t {
|
||||
protected:
|
||||
class iblock_t {
|
||||
class iblock_t : public fs_refcounted_inner {
|
||||
public:
|
||||
iblock_t(uint32_t size) : m_ref(0), m_weak_ref(0), m_size(size) {}
|
||||
iblock_t(uint32_t size) : fs_refcounted_inner(), m_size(size) {}
|
||||
virtual ~iblock_t() = default;
|
||||
|
||||
void ref();
|
||||
void ref_weak();
|
||||
void unref();
|
||||
void unref_weak();
|
||||
|
||||
uint32_t size() const { return m_size; }
|
||||
|
||||
virtual void drop_weak_references() = 0;
|
||||
|
||||
virtual const uint8_t *rodata() = 0;
|
||||
virtual uint8_t *data() = 0;
|
||||
uint8_t *offset(const char *function, uint32_t off, uint32_t size);
|
||||
const uint8_t *rooffset(const char *function, uint32_t off, uint32_t size);
|
||||
|
||||
protected:
|
||||
uint32_t m_ref, m_weak_ref;
|
||||
uint32_t m_size;
|
||||
};
|
||||
|
||||
|
||||
public:
|
||||
class block_t {
|
||||
class block_t : public fs_refcounted_outer<iblock_t> {
|
||||
public:
|
||||
block_t(iblock_t *block, bool weak = false) : m_block(block), m_is_weak_ref(weak) {
|
||||
ref();
|
||||
}
|
||||
block_t(bool weak = false) : fs_refcounted_outer<iblock_t>(weak) {}
|
||||
block_t(iblock_t *block, bool weak = false) : fs_refcounted_outer(block, weak) {}
|
||||
virtual ~block_t() = default;
|
||||
|
||||
block_t(const block_t &cref) {
|
||||
m_block = cref.m_block;
|
||||
m_is_weak_ref = cref.m_is_weak_ref;
|
||||
ref();
|
||||
}
|
||||
block_t strong() { return block_t(m_object, false); }
|
||||
block_t weak() { return block_t(m_object, true); }
|
||||
|
||||
block_t(block_t &&cref) {
|
||||
m_block = cref.m_block;
|
||||
m_is_weak_ref = cref.m_is_weak_ref;
|
||||
cref.m_block = nullptr;
|
||||
}
|
||||
|
||||
~block_t() {
|
||||
unref();
|
||||
}
|
||||
|
||||
block_t &operator =(const block_t &cref) {
|
||||
m_block = cref.m_block;
|
||||
m_is_weak_ref = cref.m_is_weak_ref;
|
||||
ref();
|
||||
return *this;
|
||||
}
|
||||
|
||||
block_t &operator =(block_t &&cref) {
|
||||
m_block = cref.m_block;
|
||||
m_is_weak_ref = cref.m_is_weak_ref;
|
||||
cref.m_block = nullptr;
|
||||
return *this;
|
||||
}
|
||||
|
||||
const uint8_t *rodata() {
|
||||
return m_block ? m_block->rodata() : nullptr;
|
||||
}
|
||||
|
||||
uint8_t *data() {
|
||||
return m_block ? m_block->data() : nullptr;
|
||||
}
|
||||
const uint8_t *rodata() { return m_object->rodata(); }
|
||||
uint8_t *data() { return m_object->data(); }
|
||||
|
||||
void copy(uint32_t offset, const uint8_t *src, uint32_t size);
|
||||
void fill( uint8_t data);
|
||||
void fill( uint8_t data);
|
||||
void fill(uint32_t offset, uint8_t data, uint32_t size);
|
||||
void wstr(uint32_t offset, const std::string &str);
|
||||
void w8( uint32_t offset, uint8_t data);
|
||||
void w16b(uint32_t offset, u16 data);
|
||||
void w16b(uint32_t offset, uint16_t data);
|
||||
void w24b(uint32_t offset, uint32_t data);
|
||||
void w32b(uint32_t offset, uint32_t data);
|
||||
void w16l(uint32_t offset, u16 data);
|
||||
void w16l(uint32_t offset, uint16_t data);
|
||||
void w24l(uint32_t offset, uint32_t data);
|
||||
void w32l(uint32_t offset, uint32_t data);
|
||||
|
||||
std::string rstr(uint32_t offset, uint32_t size);
|
||||
|
||||
private:
|
||||
iblock_t *m_block;
|
||||
bool m_is_weak_ref;
|
||||
|
||||
void ref() {
|
||||
if(m_block) {
|
||||
if(m_is_weak_ref)
|
||||
m_block->ref_weak();
|
||||
else
|
||||
m_block->ref();
|
||||
}
|
||||
}
|
||||
|
||||
void unref() {
|
||||
if(m_block) {
|
||||
if(m_is_weak_ref)
|
||||
m_block->unref_weak();
|
||||
else
|
||||
m_block->unref();
|
||||
}
|
||||
}
|
||||
uint8_t r8( uint32_t offset);
|
||||
uint16_t r16b(uint32_t offset);
|
||||
uint32_t r24b(uint32_t offset);
|
||||
uint32_t r32b(uint32_t offset);
|
||||
uint16_t r16l(uint32_t offset);
|
||||
uint32_t r24l(uint32_t offset);
|
||||
uint32_t r32l(uint32_t offset);
|
||||
};
|
||||
|
||||
fsblk_t() : m_block_size(0) {}
|
||||
@ -177,148 +225,61 @@ protected:
|
||||
|
||||
|
||||
class filesystem_t {
|
||||
public:
|
||||
class dir_t;
|
||||
class file_t;
|
||||
|
||||
protected:
|
||||
class idir_t {
|
||||
class idir_t : public fs_refcounted_inner {
|
||||
public:
|
||||
virtual ~idir_t();
|
||||
idir_t() : fs_refcounted_inner() {}
|
||||
virtual ~idir_t() = default;
|
||||
|
||||
void ref();
|
||||
void ref_weak();
|
||||
void unref();
|
||||
void unref_weak();
|
||||
|
||||
virtual void drop_weak_references();
|
||||
virtual fs_meta_data metadata() = 0;
|
||||
virtual std::vector<fs_dir_entry> contents() = 0;
|
||||
virtual file_t file_get(uint64_t key) = 0;
|
||||
virtual dir_t dir_get(uint64_t key) = 0;
|
||||
};
|
||||
|
||||
class ifile_t {
|
||||
class ifile_t : public fs_refcounted_inner {
|
||||
public:
|
||||
virtual ~ifile_t();
|
||||
ifile_t() : fs_refcounted_inner() {}
|
||||
virtual ~ifile_t() = default;
|
||||
|
||||
void ref();
|
||||
void ref_weak();
|
||||
void unref();
|
||||
void unref_weak();
|
||||
|
||||
virtual void drop_weak_references();
|
||||
virtual fs_meta_data metadata() = 0;
|
||||
virtual std::vector<u8> read_all() = 0;
|
||||
virtual std::vector<u8> read(u64 start, u64 length) = 0;
|
||||
};
|
||||
|
||||
public:
|
||||
class dir_t {
|
||||
class dir_t : public fs_refcounted_outer<idir_t> {
|
||||
public:
|
||||
dir_t(idir_t *dir, bool weak = false) : m_dir(dir), m_is_weak_ref(weak) {
|
||||
ref();
|
||||
}
|
||||
dir_t(bool weak = false) : fs_refcounted_outer<idir_t>(weak) {}
|
||||
dir_t(idir_t *dir, bool weak = false) : fs_refcounted_outer(dir, weak) {}
|
||||
virtual ~dir_t() = default;
|
||||
|
||||
dir_t(const dir_t &cref) {
|
||||
m_dir = cref.m_dir;
|
||||
m_is_weak_ref = cref.m_is_weak_ref;
|
||||
ref();
|
||||
}
|
||||
dir_t strong() { return dir_t(m_object, false); }
|
||||
dir_t weak() { return dir_t(m_object, true); }
|
||||
|
||||
dir_t(dir_t &&cref) {
|
||||
m_dir = cref.m_dir;
|
||||
m_is_weak_ref = cref.m_is_weak_ref;
|
||||
cref.m_dir = nullptr;
|
||||
}
|
||||
|
||||
~dir_t() {
|
||||
unref();
|
||||
}
|
||||
|
||||
dir_t &operator =(const dir_t &cref) {
|
||||
m_dir = cref.m_dir;
|
||||
m_is_weak_ref = cref.m_is_weak_ref;
|
||||
ref();
|
||||
return *this;
|
||||
}
|
||||
|
||||
dir_t &operator =(dir_t &&cref) {
|
||||
m_dir = cref.m_dir;
|
||||
m_is_weak_ref = cref.m_is_weak_ref;
|
||||
cref.m_dir = nullptr;
|
||||
return *this;
|
||||
}
|
||||
|
||||
private:
|
||||
idir_t *m_dir;
|
||||
bool m_is_weak_ref;
|
||||
|
||||
void ref() {
|
||||
if(m_dir) {
|
||||
if(m_is_weak_ref)
|
||||
m_dir->ref_weak();
|
||||
else
|
||||
m_dir->ref();
|
||||
}
|
||||
}
|
||||
|
||||
void unref() {
|
||||
if(m_dir) {
|
||||
if(m_is_weak_ref)
|
||||
m_dir->unref_weak();
|
||||
else
|
||||
m_dir->unref();
|
||||
}
|
||||
}
|
||||
fs_meta_data metadata() { return m_object->metadata(); }
|
||||
std::vector<fs_dir_entry> contents() { return m_object->contents(); }
|
||||
file_t file_get(uint64_t key) { return m_object->file_get(key); }
|
||||
dir_t dir_get(uint64_t key) { return m_object->dir_get(key); }
|
||||
};
|
||||
|
||||
class file_t {
|
||||
class file_t : public fs_refcounted_outer<ifile_t> {
|
||||
public:
|
||||
file_t(ifile_t *file, bool weak = false) : m_file(file), m_is_weak_ref(weak) {
|
||||
ref();
|
||||
}
|
||||
file_t(bool weak = false) : fs_refcounted_outer<ifile_t>(weak) {}
|
||||
file_t(ifile_t *file, bool weak = false) : fs_refcounted_outer(file, weak) {}
|
||||
virtual ~file_t() = default;
|
||||
|
||||
file_t(const file_t &cref) {
|
||||
m_file = cref.m_file;
|
||||
m_is_weak_ref = cref.m_is_weak_ref;
|
||||
ref();
|
||||
}
|
||||
file_t strong() { return file_t(m_object, false); }
|
||||
file_t weak() { return file_t(m_object, true); }
|
||||
|
||||
file_t(file_t &&cref) {
|
||||
m_file = cref.m_file;
|
||||
m_is_weak_ref = cref.m_is_weak_ref;
|
||||
cref.m_file = nullptr;
|
||||
}
|
||||
fs_meta_data metadata() { return m_object->metadata(); }
|
||||
|
||||
~file_t() {
|
||||
unref();
|
||||
}
|
||||
|
||||
file_t &operator =(const file_t &cref) {
|
||||
m_file = cref.m_file;
|
||||
m_is_weak_ref = cref.m_is_weak_ref;
|
||||
ref();
|
||||
return *this;
|
||||
}
|
||||
|
||||
file_t &operator =(file_t &&cref) {
|
||||
m_file = cref.m_file;
|
||||
m_is_weak_ref = cref.m_is_weak_ref;
|
||||
cref.m_file = nullptr;
|
||||
return *this;
|
||||
}
|
||||
|
||||
private:
|
||||
ifile_t *m_file;
|
||||
bool m_is_weak_ref;
|
||||
|
||||
void ref() {
|
||||
if(m_file) {
|
||||
if(m_is_weak_ref)
|
||||
m_file->ref_weak();
|
||||
else
|
||||
m_file->ref();
|
||||
}
|
||||
}
|
||||
|
||||
void unref() {
|
||||
if(m_file) {
|
||||
if(m_is_weak_ref)
|
||||
m_file->unref_weak();
|
||||
else
|
||||
m_file->unref();
|
||||
}
|
||||
}
|
||||
std::vector<u8> read_all() { return m_object->read_all(); }
|
||||
std::vector<u8> read(u32 start, u32 length) { return m_object->read(start, length); }
|
||||
};
|
||||
|
||||
filesystem_t(fsblk_t &blockdev, u32 size) : m_blockdev(blockdev) {
|
||||
@ -368,7 +329,9 @@ public:
|
||||
virtual bool can_format() const = 0;
|
||||
virtual bool can_read() const = 0;
|
||||
virtual bool can_write() const = 0;
|
||||
virtual bool has_subdirectories() const = 0;
|
||||
virtual char directory_separator() const;
|
||||
|
||||
bool has_subdirectories() const { return directory_separator() != 0; }
|
||||
|
||||
virtual std::vector<fs_meta_description> volume_meta_description() const;
|
||||
virtual std::vector<fs_meta_description> file_meta_description() const;
|
||||
|
@ -277,7 +277,8 @@ static void display_usage()
|
||||
fprintf(stderr, " floptool.exe identify <inputfile> [<inputfile> ...]\n");
|
||||
fprintf(stderr, " floptool.exe convert [input_format|auto] output_format <inputfile> <outputfile>\n");
|
||||
fprintf(stderr, " floptool.exe create output_format filesystem <outputfile>\n");
|
||||
fprintf(stderr, " floptool.exe dir input_format filesystem <inputfile>\n");
|
||||
fprintf(stderr, " floptool.exe dir input_format filesystem <image>\n");
|
||||
fprintf(stderr, " floptool.exe read input_format filesystem <image> <path> <outputfile>\n");
|
||||
}
|
||||
|
||||
static void display_formats()
|
||||
@ -502,6 +503,51 @@ static int create(int argc, char *argv[])
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void dir_scan(u32 depth, filesystem_t::dir_t dir, std::vector<std::vector<std::string>> &entries, const std::unordered_map<fs_meta_name, size_t> &nmap, size_t nc, const std::vector<fs_meta_description> &dmetad, const std::vector<fs_meta_description> &fmetad)
|
||||
{
|
||||
std::string head;
|
||||
for(u32 i = 0; i != depth; i++)
|
||||
head += " ";
|
||||
auto contents = dir.contents();
|
||||
for(const auto &c : contents) {
|
||||
size_t id = entries.size();
|
||||
entries.resize(id+1);
|
||||
entries[id].resize(nc);
|
||||
switch(c.m_type) {
|
||||
case fs_dir_entry_type::dir: {
|
||||
auto subdir = dir.dir_get(c.m_key);
|
||||
auto meta = subdir.metadata();
|
||||
for(const auto &m : dmetad) {
|
||||
if(meta.find(m.m_name) == meta.end())
|
||||
continue;
|
||||
size_t slot = nmap.find(m.m_name)->second;
|
||||
std::string val = fs_meta_to_string(m.m_type, meta.find(m.m_name)->second);
|
||||
if(slot == 0)
|
||||
val = head + "dir " + val;
|
||||
entries[id][slot] = val;
|
||||
}
|
||||
dir_scan(depth+1, subdir, entries, nmap, nc, dmetad, fmetad);
|
||||
break;
|
||||
}
|
||||
case fs_dir_entry_type::file:
|
||||
case fs_dir_entry_type::system_file: {
|
||||
auto file = dir.file_get(c.m_key);
|
||||
auto meta = file.metadata();
|
||||
for(const auto &m : fmetad) {
|
||||
if(meta.find(m.m_name) == meta.end())
|
||||
continue;
|
||||
size_t slot = nmap.find(m.m_name)->second;
|
||||
std::string val = fs_meta_to_string(m.m_type, meta.find(m.m_name)->second);
|
||||
if(slot == 0)
|
||||
val = head + (c.m_type == fs_dir_entry_type::system_file ? "sys " : "file ") + val;
|
||||
entries[id][slot] = val;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static int dir(int argc, char *argv[])
|
||||
{
|
||||
if (argc!=5) {
|
||||
@ -555,15 +601,169 @@ static int dir(int argc, char *argv[])
|
||||
fsblk_vec_t blockdev(img);
|
||||
auto load_fs = fs->m_manager->mount(blockdev);
|
||||
auto vmetad = fs->m_manager->volume_meta_description();
|
||||
auto vmeta = load_fs->metadata();
|
||||
auto fmetad = fs->m_manager->file_meta_description();
|
||||
auto dmetad = fs->m_manager->directory_meta_description();
|
||||
|
||||
auto vmeta = load_fs->metadata();
|
||||
if(!vmeta.empty()) {
|
||||
std::string vinf = "Volume:";
|
||||
for(const auto &e : vmetad)
|
||||
vinf += util::string_format(" %s=%s", fs_meta_get_name(e.m_name), fs_meta_to_string(e.m_type, vmeta[e.m_name]));
|
||||
printf("%s\n", vinf.c_str());
|
||||
printf("%s\n\n", vinf.c_str());
|
||||
}
|
||||
|
||||
std::vector<fs_meta_name> names;
|
||||
names.push_back(fs_meta_name::name);
|
||||
for(const auto &e : fmetad)
|
||||
if(e.m_name != fs_meta_name::name)
|
||||
names.push_back(e.m_name);
|
||||
for(const auto &e : dmetad)
|
||||
if(std::find(names.begin(), names.end(), e.m_name) == names.end())
|
||||
names.push_back(e.m_name);
|
||||
|
||||
std::unordered_map<fs_meta_name, size_t> nmap;
|
||||
for(size_t i = 0; i != names.size(); i++)
|
||||
nmap[names[i]] = i;
|
||||
|
||||
auto root = load_fs->root();
|
||||
std::vector<std::vector<std::string>> entries;
|
||||
|
||||
entries.resize(1);
|
||||
for(fs_meta_name n : names)
|
||||
entries[0].push_back(fs_meta_get_name(n));
|
||||
|
||||
dir_scan(0, root, entries, nmap, names.size(), dmetad, fmetad);
|
||||
|
||||
std::vector<u32> sizes(names.size());
|
||||
|
||||
for(const auto &e : entries)
|
||||
for(unsigned int i=0; i != names.size(); i++)
|
||||
sizes[i] = std::max<u32>(sizes[i], e[i].size());
|
||||
|
||||
for(const auto &e : entries) {
|
||||
std::string l;
|
||||
for(unsigned int i=0; i != names.size(); i++) {
|
||||
if(i)
|
||||
l += ' ';
|
||||
l += util::string_format("%-*s", sizes[i], e[i]);
|
||||
}
|
||||
printf("%s\n", l.c_str());
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int doread(int argc, char *argv[])
|
||||
{
|
||||
if (argc!=7) {
|
||||
fprintf(stderr, "Incorrect number of arguments.\n\n");
|
||||
display_usage();
|
||||
return 1;
|
||||
}
|
||||
|
||||
auto format = find_format_by_name(argv[2]);
|
||||
if(!format) {
|
||||
fprintf(stderr, "Error: Format '%s' unknown\n", argv[3]);
|
||||
return 1;
|
||||
}
|
||||
|
||||
auto fs = find_fs_by_name(argv[3]);
|
||||
if(!fs) {
|
||||
fprintf(stderr, "Error: Filesystem '%s' unknown\n", argv[2]);
|
||||
return 1;
|
||||
}
|
||||
|
||||
if(!fs->m_manager || !fs->m_manager->can_read()) {
|
||||
fprintf(stderr, "Error: Filesystem '%s' does not implement reading\n", argv[2]);
|
||||
return 1;
|
||||
}
|
||||
|
||||
char msg[4096];
|
||||
sprintf(msg, "Error opening %s for reading", argv[4]);
|
||||
FILE *f = fopen(argv[4], "rb");
|
||||
if (!f) {
|
||||
perror(msg);
|
||||
return 1;
|
||||
}
|
||||
io_generic io;
|
||||
io.file = f;
|
||||
io.procs = &stdio_ioprocs_noclose;
|
||||
io.filler = 0xff;
|
||||
|
||||
floppy_image image(84, 2, floppy_image::FF_UNKNOWN);
|
||||
if(!format->load(&io, floppy_image::FF_UNKNOWN, variants, &image)) {
|
||||
fprintf(stderr, "Error: parsing input file as '%s' failed\n", format->name());
|
||||
return 1;
|
||||
}
|
||||
|
||||
std::vector<u8> img;
|
||||
auto iog = ram_open(img);
|
||||
auto load_format = fs->m_type();
|
||||
load_format->save(iog, variants, &image);
|
||||
delete load_format;
|
||||
delete iog;
|
||||
|
||||
fsblk_vec_t blockdev(img);
|
||||
auto load_fs = fs->m_manager->mount(blockdev);
|
||||
|
||||
std::string opath = argv[5];
|
||||
std::vector<std::string> path;
|
||||
if(fs->m_manager->has_subdirectories()) {
|
||||
abort();
|
||||
|
||||
} else
|
||||
path.push_back(opath);
|
||||
|
||||
auto dir = load_fs->root();
|
||||
std::string apath;
|
||||
for(unsigned int i = 0; i < path.size() - 1; i++) {
|
||||
auto c = dir.contents();
|
||||
unsigned int j;
|
||||
for(j = 0; j != c.size(); j++)
|
||||
if(c[j].m_name == path[i])
|
||||
break;
|
||||
if(j == c.size()) {
|
||||
fprintf(stderr, "Error: directory %s%c%s not found\n", apath.c_str(), fs->m_manager->directory_separator(), path[i].c_str());
|
||||
return 1;
|
||||
}
|
||||
if(c[j].m_type != fs_dir_entry_type::dir) {
|
||||
fprintf(stderr, "Error: %s%c%s is not a directory\n", apath.c_str(), fs->m_manager->directory_separator(), path[i].c_str());
|
||||
return 1;
|
||||
}
|
||||
dir = dir.dir_get(c[j].m_key);
|
||||
apath += fs->m_manager->directory_separator() + path[i];
|
||||
}
|
||||
|
||||
auto c = dir.contents();
|
||||
unsigned int j;
|
||||
for(j = 0; j != c.size(); j++)
|
||||
if(c[j].m_name == path.back())
|
||||
break;
|
||||
if(j == c.size()) {
|
||||
fprintf(stderr, "Error: file %s%c%s not found\n", apath.c_str(), fs->m_manager->directory_separator(), path.back().c_str());
|
||||
return 1;
|
||||
}
|
||||
auto file = dir.file_get(c[j].m_key);
|
||||
auto meta = file.metadata();
|
||||
|
||||
if(meta.find(fs_meta_name::length) == meta.end()) {
|
||||
fprintf(stderr, "Error: %s%c%s is not a readable file\n", apath.c_str(), fs->m_manager->directory_separator(), path.back().c_str());
|
||||
return 1;
|
||||
}
|
||||
|
||||
auto filedata = file.read_all();
|
||||
|
||||
sprintf(msg, "Error opening %s for writing", argv[6]);
|
||||
auto fo = fopen(argv[6], "wb");
|
||||
if (!fo) {
|
||||
perror(msg);
|
||||
return 1;
|
||||
}
|
||||
|
||||
fwrite(filedata.data(), filedata.size(), 1, fo);
|
||||
fclose(fo);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -585,6 +785,8 @@ int CLIB_DECL main(int argc, char *argv[])
|
||||
return create(argc, argv);
|
||||
else if (!core_stricmp("dir", argv[1]))
|
||||
return dir(argc, argv);
|
||||
else if (!core_stricmp("read", argv[1]))
|
||||
return doread(argc, argv);
|
||||
else {
|
||||
fprintf(stderr, "Unknown command '%s'\n\n", argv[1]);
|
||||
display_usage();
|
||||
|
Loading…
Reference in New Issue
Block a user