more fs
This commit is contained in:
parent
39dae2aa6b
commit
29ccd43c7a
@ -1,4 +1,5 @@
|
||||
#include "block_device.hpp"
|
||||
#include <cassert>
|
||||
#include <cstdint>
|
||||
#include <cstring>
|
||||
#include <fstream>
|
||||
@ -20,6 +21,7 @@ auto FileDisk::block_count() -> uint16_t
|
||||
{
|
||||
m_file.seekg(0, std::ios_base::end);
|
||||
std::streamsize location = m_file.tellg();
|
||||
assert(location != -1);
|
||||
return location / block_size & 0xffff;
|
||||
}
|
||||
|
||||
@ -27,10 +29,12 @@ void FileDisk::read(uint8_t* data, uint16_t block)
|
||||
{
|
||||
m_file.seekg(block * block_size);
|
||||
m_file.read(reinterpret_cast<char*>(data), block_size);
|
||||
assert(m_file.good());
|
||||
}
|
||||
|
||||
void FileDisk::write(const uint8_t* data, uint16_t block)
|
||||
{
|
||||
m_file.seekg(block * block_size);
|
||||
m_file.write(reinterpret_cast<const char*>(data), block_size);
|
||||
assert(m_file.good());
|
||||
}
|
||||
|
||||
371
src/fs.cpp
371
src/fs.cpp
@ -1,75 +1,360 @@
|
||||
#include "fs.hpp"
|
||||
#include <cassert>
|
||||
#include <cstdint>
|
||||
#include <cstring>
|
||||
#include <optional>
|
||||
#include <string_view>
|
||||
#include <tuple>
|
||||
|
||||
namespace vc5::filesys {
|
||||
|
||||
constexpr auto Ok = Status::Ok;
|
||||
using BlockData = std::array<u8, block_size>;
|
||||
|
||||
using BlockData = std::array<uint8_t, block_size>;
|
||||
namespace {
|
||||
|
||||
void Fs::init()
|
||||
{
|
||||
m_super = SuperBlockData {
|
||||
.block_bitmap = {},
|
||||
.inode_bitmap = {},
|
||||
.inode_blocks = {},
|
||||
};
|
||||
write_superblock();
|
||||
}
|
||||
|
||||
Status Fs::make_directory()
|
||||
{
|
||||
uint16_t id;
|
||||
if (auto result = next_inode_id(id); result != Ok) {
|
||||
return result;
|
||||
auto inode_mode(INodeType type) -> u16
|
||||
{
|
||||
u16 mode = 0;
|
||||
mode |= std::to_underlying(type) << inode_type_bitoffset;
|
||||
return mode;
|
||||
}
|
||||
|
||||
auto node = INodeData {
|
||||
.id = id,
|
||||
.flags = static_cast<uint16_t>(INodeType::Directory),
|
||||
auto inode_mode_type(u16 mode) -> INodeType
|
||||
{
|
||||
return static_cast<INodeType>(
|
||||
mode >> inode_type_bitoffset & inode_type_bitmask);
|
||||
}
|
||||
|
||||
auto unwrap_inode_id(u16 inode_id) -> std::tuple<u16, u16>
|
||||
{
|
||||
u16 inode_block_idx = inode_id / inodes_per_block;
|
||||
u16 block_offset = inode_id % inodes_per_block * inode_size;
|
||||
|
||||
assert(inode_block_idx * inodes_per_block + block_offset / inode_size
|
||||
== inode_id
|
||||
&& "calculation wrong");
|
||||
|
||||
return { inode_block_idx, block_offset };
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
auto Fs::init_new(u16 volume_id, u16 block_count) -> Result<void>
|
||||
{
|
||||
m_superblock = Superblock {
|
||||
.volume_id = volume_id,
|
||||
.fs_version = 1,
|
||||
.blocks_count = block_count,
|
||||
.blocks_free = block_count,
|
||||
.root_inode = 0,
|
||||
.inode_blocks_count = 0,
|
||||
.iblocks = {},
|
||||
.inode_bitmap = {},
|
||||
};
|
||||
|
||||
auto root_inode_id = make_directory_inode();
|
||||
if (not root_inode_id)
|
||||
return std::unexpected(root_inode_id.error());
|
||||
|
||||
m_superblock.root_inode = *root_inode_id;
|
||||
|
||||
if (auto result = sync_to_disk(); not result)
|
||||
return result;
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
auto Fs::make_file(u16 dir_inode_id, std::string_view name) -> Result<u16>
|
||||
{
|
||||
if (name.size() > name_max_len)
|
||||
return std::unexpected("invalid filename");
|
||||
|
||||
auto dir_inode_result = read_inode(dir_inode_id);
|
||||
if (not dir_inode_result)
|
||||
return std::unexpected(dir_inode_result.error());
|
||||
auto& dir_inode = *dir_inode_result;
|
||||
|
||||
if (inode_mode_type(dir_inode.mode) != INodeType::Dir)
|
||||
return std::unexpected("incorrect inode type");
|
||||
|
||||
auto inode_id = allocate_inode();
|
||||
if (not inode_id)
|
||||
return inode_id;
|
||||
|
||||
auto inode = INode {
|
||||
.mode = inode_mode(INodeType::File),
|
||||
.blocks_count = 0,
|
||||
.links_count = 0,
|
||||
.last_block_size = 0,
|
||||
.size = 0,
|
||||
.blocks = {},
|
||||
};
|
||||
|
||||
auto entry = DirEntry {
|
||||
.inode = *inode_id,
|
||||
.next = 0,
|
||||
.name_len = static_cast<u16>(name.size()),
|
||||
.name = {},
|
||||
};
|
||||
|
||||
std::memcpy(entry.name.data(), name.data(), name.size());
|
||||
|
||||
if (auto result = append_to_directory(dir_inode, entry); not result)
|
||||
return std::unexpected(result.error());
|
||||
}
|
||||
|
||||
Status Fs::write_new_inode(INodeData& data)
|
||||
auto Fs::init_from_existing() -> Result<void>
|
||||
{
|
||||
uint16_t block_id = data.id / inodes_per_block;
|
||||
uint16_t offset = data.id % inodes_per_block * inode_size;
|
||||
|
||||
BlockData block;
|
||||
m_disk->read(&block[0], block_id);
|
||||
return sync_from_disk();
|
||||
}
|
||||
|
||||
Status Fs::next_inode_id(uint16_t& id)
|
||||
auto Fs::append_to_directory(INode& dir_inode, const DirEntry& entry)
|
||||
-> Result<void>
|
||||
{
|
||||
for (uint16_t map_idx = 0; map_idx < sb_inode_bitmap_count; ++map_idx) {
|
||||
auto& map = m_super.inode_bitmap[map_idx];
|
||||
|
||||
for (uint16_t bit_idx = 0; bit_idx < 16; ++bit_idx) {
|
||||
for (u16 i = 0; i < inode_ndir_blocks; ++i) {
|
||||
auto dir_entry_block = dir_inode.blocks[i];
|
||||
|
||||
if ((map >> bit_idx & 1) == 0) {
|
||||
id = map_idx * sb_inode_bitmap_count + bit_idx;
|
||||
return Ok;
|
||||
auto block = read_block<BlockData>(dir_entry_block);
|
||||
if (not block)
|
||||
return std::unexpected(block.error());
|
||||
}
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
auto Fs::make_directory_inode() -> Result<u16>
|
||||
{
|
||||
auto inode_id = allocate_inode();
|
||||
if (not inode_id)
|
||||
return inode_id;
|
||||
|
||||
auto inode = INode {
|
||||
.mode = inode_mode(INodeType::Dir),
|
||||
.blocks_count = 0,
|
||||
.links_count = 0,
|
||||
.last_block_size = 0,
|
||||
.size = 0,
|
||||
.blocks = {},
|
||||
};
|
||||
|
||||
if (auto result = write_inode(*inode_id, inode); not result)
|
||||
return std::unexpected(result.error());
|
||||
|
||||
return inode_id;
|
||||
}
|
||||
|
||||
auto Fs::inode_last_block_id(const INode& inode) -> Result<u16>
|
||||
{
|
||||
if (inode.blocks_count < inode_ndir_blocks) {
|
||||
return inode.blocks_count - 1;
|
||||
|
||||
} else if (inode.blocks_count >= inode_ind_block
|
||||
&& inode.blocks_count <= inode_ind_block + block_size) {
|
||||
|
||||
auto block_id = inode.blocks[inode_ind_block];
|
||||
assert(block_id != 0);
|
||||
|
||||
auto ind_block = read_block<BlockData>(block_id);
|
||||
if (not ind_block)
|
||||
return std::unexpected(ind_block.error());
|
||||
|
||||
return ind_block.value()[inode.blocks_count - inode_ind_block];
|
||||
|
||||
} else if (inode.blocks_count == inode_dind_block) {
|
||||
|
||||
u16 first_id = inode_dind_block;
|
||||
u16 second_id = inode.blocks_count - inode_dind_block;
|
||||
|
||||
auto first_block_id = inode.blocks[inode_dind_block];
|
||||
assert(first_block_id != 0);
|
||||
|
||||
auto first_ind_block = read_block<BlockData>(first_block_id);
|
||||
if (not first_ind_block)
|
||||
return std::unexpected(first_ind_block.error());
|
||||
|
||||
auto second_block_id
|
||||
= first_ind_block.value()[inode.blocks_count - inode_dind_block];
|
||||
|
||||
auto second_ind_block = read_block<BlockData>(second_block_id);
|
||||
if (not second_ind_block)
|
||||
return std::unexpected(second_ind_block.error());
|
||||
|
||||
return second_ind_block.value()[inode.blocks_count - inode_dind_block];
|
||||
|
||||
} else {
|
||||
return std::unexpected("inode at capacity");
|
||||
}
|
||||
}
|
||||
|
||||
auto Fs::read_inode(u16 inode_id) -> Result<INode>
|
||||
{
|
||||
auto [inode_block_idx, block_offset] = unwrap_inode_id(inode_id);
|
||||
|
||||
if (inode_block_idx >= m_superblock.inode_blocks_count)
|
||||
return std::unexpected("inode lookup failed");
|
||||
|
||||
auto block_id = m_superblock.iblocks[inode_block_idx];
|
||||
|
||||
struct INodeData {
|
||||
u16 mode;
|
||||
u16 blocks_count;
|
||||
u16 links_count;
|
||||
u16 last_block_size;
|
||||
u32 size;
|
||||
std::array<u16, inode_blocks_count> blocks;
|
||||
};
|
||||
static_assert(sizeof(INodeData) == sizeof(INode));
|
||||
|
||||
return read_block_part<INode>(block_id, block_offset);
|
||||
}
|
||||
|
||||
auto Fs::write_inode(u16 inode_id, const INode& inode) -> Result<void>
|
||||
{
|
||||
auto [inode_block_idx, block_offset] = unwrap_inode_id(inode_id);
|
||||
|
||||
if (inode_block_idx >= m_superblock.inode_blocks_count)
|
||||
return std::unexpected("inode lookup failed");
|
||||
|
||||
auto block_id = m_superblock.iblocks[inode_block_idx];
|
||||
|
||||
if (auto result = write_block_part(block_id, inode, block_offset);
|
||||
not result)
|
||||
return result;
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
auto Fs::allocate_inode() -> Result<u16>
|
||||
{
|
||||
auto inode_id = std::optional<u16>();
|
||||
auto& sb = m_superblock;
|
||||
for (u16 i = 0; i < sb.inode_blocks_count * 16; ++i) {
|
||||
if (sb.inode_bitmap[i]) {
|
||||
inode_id = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (not inode_id) {
|
||||
if (sb.inode_blocks_count >= iblocks_max_count) {
|
||||
return std::unexpected("inode allocate failed");
|
||||
}
|
||||
return Status::INodeAllocFail;
|
||||
auto new_block_id = allocate_block();
|
||||
if (not new_block_id)
|
||||
return new_block_id;
|
||||
|
||||
sb.iblocks[sb.inode_blocks_count] = *new_block_id;
|
||||
inode_id = sb.inode_blocks_count * 16;
|
||||
sb.inode_blocks_count += 1;
|
||||
}
|
||||
|
||||
sb.inode_bitmap[*inode_id] = true;
|
||||
return *inode_id;
|
||||
}
|
||||
|
||||
Status Fs::read_superblock()
|
||||
auto Fs::allocate_block() -> Result<u16>
|
||||
{
|
||||
BlockData block;
|
||||
m_disk->read(&block[0], super_block_location);
|
||||
m_super = *reinterpret_cast<SuperBlockData*>(&block[0]);
|
||||
return Ok;
|
||||
u16 block_id = 0;
|
||||
|
||||
// data/inode blocks start at 4
|
||||
for (u16 i = 4; i < blocks_max_count; ++i) {
|
||||
if (not m_blocks_bitmap.bitmap[i]) {
|
||||
block_id = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (block_id == 0) {
|
||||
return std::unexpected("allocate block failed");
|
||||
}
|
||||
m_blocks_bitmap.bitmap[block_id] = true;
|
||||
return block_id;
|
||||
}
|
||||
|
||||
Status Fs::write_superblock()
|
||||
auto Fs::sync_from_disk() -> Result<void>
|
||||
{
|
||||
m_disk->write(
|
||||
reinterpret_cast<const uint8_t*>(&m_super), super_block_location);
|
||||
return Ok;
|
||||
auto superblock = read_block<Superblock>(sb_loc);
|
||||
if (not superblock)
|
||||
return std::unexpected(superblock.error());
|
||||
|
||||
auto blocks_bitmap = read_block<BlocksBitmap>(blocks_bitmap_loc);
|
||||
if (not blocks_bitmap)
|
||||
return std::unexpected(superblock.error());
|
||||
|
||||
m_superblock = *superblock;
|
||||
m_blocks_bitmap = *blocks_bitmap;
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
auto Fs::sync_to_disk() -> Result<void>
|
||||
{
|
||||
if (auto result = write_block(m_superblock, sb_loc); not result)
|
||||
return result;
|
||||
|
||||
if (auto result = write_block(m_blocks_bitmap, blocks_bitmap_loc);
|
||||
not result)
|
||||
return result;
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
template <typename Data>
|
||||
requires(sizeof(Data) <= block_size)
|
||||
auto Fs::read_block_part(u16 block_id, u16 offset) -> Result<Data>
|
||||
{
|
||||
assert(sizeof(Data) + offset <= block_size);
|
||||
|
||||
BlockData block = {};
|
||||
m_disk->read(block.data(), block_id);
|
||||
|
||||
Data data;
|
||||
std::memcpy(
|
||||
reinterpret_cast<uint8_t*>(&data) + offset, block.data(), sizeof(Data));
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
template <typename Data>
|
||||
requires(sizeof(Data) <= block_size)
|
||||
auto Fs::write_block_part(u16 block_id, const Data& data, u16 offset)
|
||||
-> Result<void>
|
||||
{
|
||||
assert(sizeof(Data) + offset <= block_size);
|
||||
|
||||
BlockData block = {};
|
||||
m_disk->read(block.data(), block_id);
|
||||
|
||||
std::memcpy(block.data(),
|
||||
reinterpret_cast<const uint8_t*>(&data) + offset,
|
||||
sizeof(Data));
|
||||
m_disk->write(block.data(), block_id);
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
template <typename Data>
|
||||
requires(sizeof(Data) <= block_size)
|
||||
auto Fs::read_block(u16 block_id) -> Result<Data>
|
||||
{
|
||||
BlockData block = {};
|
||||
m_disk->read(block.data(), block_id);
|
||||
|
||||
Data data;
|
||||
std::memcpy(reinterpret_cast<uint8_t*>(&data), block.data(), sizeof(Data));
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
template <typename Data>
|
||||
requires(sizeof(Data) <= block_size)
|
||||
auto Fs::write_block(const Data& data, u16 block_id) -> Result<void>
|
||||
{
|
||||
BlockData block = {};
|
||||
std::memcpy(
|
||||
block.data(), reinterpret_cast<const uint8_t*>(&data), sizeof(Data));
|
||||
m_disk->write(block.data(), block_id);
|
||||
return {};
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
199
src/fs.hpp
199
src/fs.hpp
@ -1,53 +1,80 @@
|
||||
#pragma once
|
||||
|
||||
#include "block_device.hpp"
|
||||
#include "types.hpp"
|
||||
#include <bitset>
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
#include <expected>
|
||||
#include <string_view>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
|
||||
namespace vc5::filesys {
|
||||
|
||||
enum class Status : uint16_t {
|
||||
Ok,
|
||||
INodeAllocFail,
|
||||
constexpr u16 block_size = 0x200;
|
||||
|
||||
constexpr u16 name_max_len = 256;
|
||||
|
||||
struct DirEntry {
|
||||
u16 inode;
|
||||
u16 next;
|
||||
u16 name_len;
|
||||
std::array<char, name_max_len> name;
|
||||
};
|
||||
|
||||
constexpr uint16_t block_size = 0x200;
|
||||
constexpr uint16_t name_max_len = 255;
|
||||
constexpr u16 inode_size = 32;
|
||||
constexpr u16 inodes_per_block = block_size / inode_size;
|
||||
|
||||
struct DirEntryData {
|
||||
uint16_t inode;
|
||||
uint16_t name_len;
|
||||
std::array<uint8_t, name_max_len> name;
|
||||
};
|
||||
|
||||
enum class INodeType : uint16_t {
|
||||
enum class INodeType : u16 {
|
||||
File = 0,
|
||||
Directory = 1,
|
||||
Symlink = 2,
|
||||
Dir = 1,
|
||||
Link = 2,
|
||||
};
|
||||
|
||||
constexpr uint16_t inode_size = 32;
|
||||
constexpr uint16_t inodes_per_block = block_size / inode_size;
|
||||
constexpr uint16_t inode_blocks_count = 8;
|
||||
constexpr u16 inode_type_bitoffset = 0;
|
||||
constexpr u16 inode_type_bitmask = 0b11;
|
||||
|
||||
struct INodeData {
|
||||
uint16_t id;
|
||||
uint16_t flags;
|
||||
uint16_t blocks_count;
|
||||
std::array<uint16_t, inode_blocks_count> blocks;
|
||||
constexpr u16 inode_ndir_blocks = 8;
|
||||
constexpr u16 inode_ind_block = inode_ndir_blocks;
|
||||
constexpr u16 inode_dind_block = inode_ind_block + 1;
|
||||
constexpr u16 inode_blocks_count = inode_dind_block + 1;
|
||||
|
||||
struct INode {
|
||||
u16 mode;
|
||||
u16 blocks_count;
|
||||
u16 links_count;
|
||||
u16 last_block_size;
|
||||
u32 size;
|
||||
std::array<u16, inode_blocks_count> blocks;
|
||||
};
|
||||
|
||||
constexpr uint16_t super_block_location = 0x400;
|
||||
constexpr uint16_t sb_block_bitmap_count = 8;
|
||||
constexpr uint16_t sb_inode_bitmap_count = 8;
|
||||
constexpr uint16_t sb_inode_blocks_count = 16;
|
||||
static_assert(sizeof(INode) <= inode_size);
|
||||
|
||||
struct SuperBlockData {
|
||||
std::array<uint16_t, sb_block_bitmap_count> block_bitmap;
|
||||
std::array<uint16_t, sb_inode_bitmap_count> inode_bitmap;
|
||||
std::array<uint16_t, sb_inode_blocks_count> inode_blocks;
|
||||
constexpr u16 sb_loc = 3;
|
||||
constexpr u16 blocks_bitmap_loc = 4;
|
||||
constexpr u16 blocks_max_count = block_size * 8;
|
||||
constexpr u16 iblocks_max_count = 32;
|
||||
constexpr u16 inodes_max_count = block_size / inode_size * iblocks_max_count;
|
||||
|
||||
struct Superblock {
|
||||
u16 volume_id;
|
||||
u16 fs_version;
|
||||
u16 blocks_count;
|
||||
u16 blocks_free;
|
||||
u16 root_inode;
|
||||
u16 inode_blocks_count;
|
||||
std::array<u16, iblocks_max_count> iblocks;
|
||||
std::bitset<inodes_max_count> inode_bitmap;
|
||||
};
|
||||
|
||||
static_assert(sizeof(Superblock) <= block_size);
|
||||
|
||||
struct BlocksBitmap {
|
||||
std::bitset<blocks_max_count> bitmap;
|
||||
};
|
||||
|
||||
static_assert(sizeof(BlocksBitmap) <= block_size);
|
||||
|
||||
class Fs {
|
||||
public:
|
||||
explicit Fs(BlockDevice& disk)
|
||||
@ -55,19 +82,115 @@ public:
|
||||
{
|
||||
}
|
||||
|
||||
void init();
|
||||
template <typename T> using Result = std::expected<T, std::string_view>;
|
||||
|
||||
static auto init_new(BlockDevice& disk, u16 volume_id, u16 block_count)
|
||||
-> Result<Fs>
|
||||
{
|
||||
auto fs = Fs(disk);
|
||||
if (auto result = fs.init_new(volume_id, block_count); not result)
|
||||
return std::unexpected(result.error());
|
||||
return fs;
|
||||
}
|
||||
|
||||
static auto load(BlockDevice& disk) -> Result<Fs>
|
||||
{
|
||||
auto fs = Fs(disk);
|
||||
if (auto result = fs.init_from_existing(); not result)
|
||||
return std::unexpected(result.error());
|
||||
return fs;
|
||||
}
|
||||
|
||||
auto root_inode_id() const -> Result<u16>
|
||||
{
|
||||
return m_superblock.root_inode;
|
||||
}
|
||||
|
||||
auto make_file(u16 dir_inode_id, std::string_view name) -> Result<u16>;
|
||||
|
||||
private:
|
||||
Status make_directory();
|
||||
auto init_new(u16 volume_id, u16 block_count) -> Result<void>;
|
||||
auto init_from_existing() -> Result<void>;
|
||||
|
||||
Status write_new_inode(INodeData& data);
|
||||
Status next_inode_id(uint16_t& id);
|
||||
auto append_to_directory(INode& dir_inode, const DirEntry& entry)
|
||||
-> Result<void>;
|
||||
auto make_directory_inode() -> Result<u16>;
|
||||
|
||||
Status read_superblock();
|
||||
Status write_superblock();
|
||||
auto inode_last_block_id(const INode& inode) -> Result<u16>;
|
||||
|
||||
auto write_inode(u16 inode_id, const INode& inode) -> Result<void>;
|
||||
auto read_inode(u16 inode_id) -> Result<INode>;
|
||||
auto allocate_inode() -> Result<u16>;
|
||||
|
||||
auto allocate_block() -> Result<u16>;
|
||||
|
||||
auto sync_from_disk() -> Result<void>;
|
||||
auto sync_to_disk() -> Result<void>;
|
||||
|
||||
// templates declared here to get private access
|
||||
|
||||
template <typename Data>
|
||||
requires(sizeof(Data) <= block_size)
|
||||
auto read_block_part(u16 block_id, u16 offset) -> Result<Data>;
|
||||
template <typename Data>
|
||||
requires(sizeof(Data) <= block_size)
|
||||
auto write_block_part(u16 block_id, const Data& data, u16 offset)
|
||||
-> Result<void>;
|
||||
|
||||
template <typename Data>
|
||||
requires(sizeof(Data) <= block_size)
|
||||
auto read_block(u16 block_id) -> Result<Data>;
|
||||
template <typename Data>
|
||||
requires(sizeof(Data) <= block_size)
|
||||
auto write_block(const Data& data, u16 block_id) -> Result<void>;
|
||||
|
||||
BlockDevice* m_disk;
|
||||
SuperBlockData m_super;
|
||||
Superblock m_superblock = {};
|
||||
BlocksBitmap m_blocks_bitmap = {};
|
||||
};
|
||||
|
||||
class ByteReader {
|
||||
public:
|
||||
template <typename Data>
|
||||
ByteReader(const Data* data)
|
||||
: m_data(reinterpret_cast<const u8*>(data)) {};
|
||||
|
||||
template <typename Data>
|
||||
requires std::is_integral_v<Data>
|
||||
auto operator>>(Data& v) -> ByteReader&
|
||||
{
|
||||
v = 0;
|
||||
for (std::size_t i = 0; i < sizeof(Data); ++i) {
|
||||
v |= *m_data << (sizeof(Data) - i - 1) * 8;
|
||||
m_data++;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
private:
|
||||
const u8* m_data;
|
||||
};
|
||||
|
||||
class ByteWriter {
|
||||
public:
|
||||
template <typename Data>
|
||||
ByteWriter(Data* data)
|
||||
: m_data(reinterpret_cast<u8*>(data)) {};
|
||||
|
||||
template <typename Data>
|
||||
requires std::is_integral_v<Data>
|
||||
auto operator>>(Data& v) -> ByteWriter&
|
||||
{
|
||||
v = 0;
|
||||
for (std::size_t i = 0; i < sizeof(Data); ++i) {
|
||||
*m_data = v >> (sizeof(Data) - i - 1) * 8 & 0xff;
|
||||
m_data++;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
private:
|
||||
u8* m_data;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
17
src/types.hpp
Normal file
17
src/types.hpp
Normal file
@ -0,0 +1,17 @@
|
||||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
namespace vc5 {
|
||||
|
||||
using u8 = std::uint8_t;
|
||||
using u16 = std::uint16_t;
|
||||
using u32 = std::uint32_t;
|
||||
using u64 = std::uint64_t;
|
||||
|
||||
using i8 = std::int8_t;
|
||||
using i16 = std::int16_t;
|
||||
using i32 = std::int32_t;
|
||||
using i64 = std::int64_t;
|
||||
|
||||
}
|
||||
@ -1,12 +1,16 @@
|
||||
#include "block_device.hpp"
|
||||
#include "builder.hpp"
|
||||
#include "fs.hpp"
|
||||
#include "io_device.hpp"
|
||||
#include "types.hpp"
|
||||
#include "vm.hpp"
|
||||
#include <SDL2/SDL_main.h>
|
||||
#include <array>
|
||||
#include <cstdint>
|
||||
#include <cstdlib>
|
||||
#include <print>
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
|
||||
using namespace std::chrono_literals;
|
||||
|
||||
@ -22,7 +26,25 @@ int main(int argc, char** argv)
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
auto disk = FileDisk(argv[1]);
|
||||
auto file_disk = FileDisk(argv[1]);
|
||||
auto disk = MemoryDisk(128);
|
||||
|
||||
auto block = std::array<uint8_t, 512> {};
|
||||
|
||||
for (u16 i = 0; i < 2; ++i) {
|
||||
file_disk.read(block.data(), i);
|
||||
disk.write(block.data(), i);
|
||||
}
|
||||
|
||||
try {
|
||||
auto fs = filesys::Fs::init_new(disk, 0, 128).value();
|
||||
|
||||
auto root = fs.root_inode_id().value();
|
||||
|
||||
} catch (std::bad_expected_access<std::string_view>& ex) {
|
||||
std::println(stderr, "error: {}", ex.error());
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
auto vm = VM(*device, disk);
|
||||
vm.run();
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user