diff --git a/programs/boot.vc5asm b/programs/boot.vc5asm index f125185..287e7bc 100644 --- a/programs/boot.vc5asm +++ b/programs/boot.vc5asm @@ -48,24 +48,24 @@ _start: mov r0, 0 mov [counter], r0 - mov r1, 0 -.loop_body: - mov r2, r1 - add r2, 32 - - add rsp, 4 - mov [rsp-4], r1 - mov [rsp-2], r2 - call term_putc - mov r1, [rsp-4] - sub rsp, 4 - - add r1, 1 -.loop_cond: - cmp r1, 127 - 32 - mov r0, rfl - and r0, fl_lt - jnz r0, .loop_body +; mov r1, 0 +;.loop_body: +; mov r2, r1 +; add r2, 32 +; +; add rsp, 4 +; mov [rsp-4], r1 +; mov [rsp-2], r2 +; call term_putc +; mov r1, [rsp-4] +; sub rsp, 4 +; +; add r1, 1 +;.loop_cond: +; cmp r1, 127 - 32 +; mov r0, rfl +; and r0, fl_lt +; jnz r0, .loop_body main_loop: hlt diff --git a/src/fs.cpp b/src/fs.cpp index 0c31133..88184c8 100644 --- a/src/fs.cpp +++ b/src/fs.cpp @@ -62,25 +62,50 @@ auto Fs::init_new(u16 volume_id, u16 block_count) -> Result return {}; } -auto Fs::make_file(u16 dir_inode_id, std::string_view name) -> Result +auto Fs::init_from_existing() -> Result +{ + return sync_from_disk(); +} + +auto Fs::make_file(u16 parent_inode_id, std::string_view name) -> Result +{ + return make_inode(parent_inode_id, name, INodeType::Dir); +} + +auto Fs::make_directory(u16 parent_inode_id, std::string_view name) + -> Result +{ + return make_inode(parent_inode_id, name, INodeType::Dir); +} + +auto Fs::write(u16 inode_id, const void* data, u16 size) -> Result +{ + auto inode_result = read_inode(inode_id); + if (not inode_result) + return std::unexpected(inode_result.error()); + auto& inode = *inode_result; + + if (auto result = inode_for_each_block_id(inode, + [&](u16& block_id) { + deallocate_block(block_id); + block_id = 0; + }); + not result) + return std::unexpected(result.error()); +} + +auto Fs::make_inode(u16 parent_inode_id, std::string_view name, INodeType type) + -> Result { 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), + .mode = inode_mode(type), .blocks_count = 0, .links_count = 0, .last_block_size = 0, @@ -97,27 +122,45 @@ auto Fs::make_file(u16 dir_inode_id, std::string_view name) -> Result std::memcpy(entry.name.data(), name.data(), name.size()); - if (auto result = append_to_directory(dir_inode, entry); not result) + if (auto result = append_to_directory(parent_inode_id, entry); not result) return std::unexpected(result.error()); + + if (auto result = write_inode(*inode_id, inode); not result) + return std::unexpected(result.error()); + + return inode_id; } -auto Fs::init_from_existing() -> Result -{ - return sync_from_disk(); -} - -auto Fs::append_to_directory(INode& dir_inode, const DirEntry& entry) +auto Fs::append_to_directory(u16 dir_inode_id, const DirEntry& entry) -> Result { + 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; - for (u16 i = 0; i < inode_ndir_blocks; ++i) { - auto dir_entry_block = dir_inode.blocks[i]; + if (inode_mode_type(dir_inode.mode) != INodeType::Dir) + return std::unexpected("incorrect inode type"); - auto block = read_block>(dir_entry_block); - if (not block) - return std::unexpected(block.error()); + if (dir_inode.blocks_count == inode_last_block + && entry.size() > block_size - dir_inode.last_block_size) { + return std::unexpected("inode at capacity"); } + auto last_block_id = inode_last_block_id(dir_inode); + if (not last_block_id) + return std::unexpected(last_block_id.error()); + + if (auto result = write_block_part( + *last_block_id, entry, dir_inode.last_block_size, entry.size()); + not result) + return std::unexpected(result.error()); + + dir_inode.last_block_size += entry.size(); + + if (auto result = write_inode(dir_inode_id, dir_inode); not result) + return std::unexpected(result.error()); + return {}; } @@ -159,29 +202,27 @@ auto Fs::inode_last_block_id(const INode& inode) -> Result return ind_block->data[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>(first_block_id); - if (not first_ind_block) - return std::unexpected(first_ind_block.error()); - - auto second_block_id - = first_ind_block->data[inode.blocks_count - inode_dind_block]; - - auto second_ind_block = read_block>(second_block_id); - if (not second_ind_block) - return std::unexpected(second_ind_block.error()); - - return second_ind_block->data[inode.blocks_count - inode_dind_block]; - } else { - return std::unexpected("inode at capacity"); + return std::unexpected("invalid inode"); + } +} + +template +auto Fs::inode_for_each_block_id(const INode& inode, Func func) -> Result +{ + for (u16 i = 0; i < inode.blocks_count && i < inode_ndir_blocks; ++i) { + func(inode.blocks[i]); + } + + auto block_id = inode.blocks[inode_ind_block]; + assert(block_id != 0); + + auto ind_block = read_block>(block_id); + if (not ind_block) + return std::unexpected(ind_block.error()); + + for (u16 i = 0; i < inode.blocks_count - inode_ndir_blocks; ++i) { + func(inode.blocks[i]); } } @@ -269,6 +310,11 @@ auto Fs::allocate_block() -> Result return block_id; } +void Fs::deallocate_block(u16 block_id) +{ + m_blocks_bitmap.bitmap[block_id] = false; +} + auto Fs::sync_from_disk() -> Result { auto superblock = read_block(sb_loc); @@ -352,7 +398,7 @@ public: { v = 0; for (std::size_t i = 0; i < sizeof(Int); ++i) { - v |= *m_data << (sizeof(Int) - i - 1) * 8; + v |= *m_data << (sizeof(Int) - i - 1) * 8 & 0xff; m_data++; } return *this; @@ -388,32 +434,40 @@ using BlockData = std::array; template requires(sizeof(Data) <= block_size) -auto Fs::read_block_part(u16 block_id, u16 offset) -> Result +auto Fs::read_block_part(u16 block_id, u16 offset, u16 size) -> Result { - assert(sizeof(Data) + offset <= block_size); + assert(size + offset <= block_size); - BlockData block = {}; + auto block = BlockData {}; m_disk->read(block.data(), block_id); + auto raw_data = BlockData {}; + std::memcpy(raw_data.data(), block.data() + offset, size); + + auto reader = BeReader(raw_data.data()); + Data data; - std::memcpy( - reinterpret_cast(&data) + offset, block.data(), sizeof(Data)); + data.read(reader); return data; } template requires(sizeof(Data) <= block_size) -auto Fs::write_block_part(u16 block_id, const Data& data, u16 offset) +auto Fs::write_block_part(u16 block_id, const Data& data, u16 offset, u16 size) -> Result { - assert(sizeof(Data) + offset <= block_size); + assert(size + offset <= block_size); - BlockData block = {}; + auto raw_data = BlockData {}; + + auto writer = BeWriter(raw_data.data()); + data.write(writer); + + auto block = BlockData {}; m_disk->read(block.data(), block_id); - auto writer = BeWriter(block.data() + offset); - data.write(writer); + std::memcpy(block.data() + offset, raw_data.data(), size); m_disk->write(block.data(), block_id); @@ -424,7 +478,7 @@ template requires(sizeof(Data) <= block_size) auto Fs::read_block(u16 block_id) -> Result { - BlockData block = {}; + auto block = BlockData {}; m_disk->read(block.data(), block_id); auto reader = BeReader(block.data()); @@ -439,7 +493,7 @@ template requires(sizeof(Data) <= block_size) auto Fs::write_block(const Data& data, u16 block_id) -> Result { - BlockData block = {}; + auto block = BlockData {}; auto writer = BeWriter(block.data()); data.write(writer); diff --git a/src/fs.hpp b/src/fs.hpp index 8a99ed6..e94180c 100644 --- a/src/fs.hpp +++ b/src/fs.hpp @@ -31,6 +31,12 @@ struct DirEntry { { r >> inode >> next >> name_len >> name; } + + auto size() const -> u16 + { + return sizeof(inode) + sizeof(next) + sizeof(name_len) + + sizeof(char) * name_len; + } }; constexpr u16 inode_size = 32; @@ -45,10 +51,11 @@ enum class INodeType : u16 { constexpr u16 inode_type_bitoffset = 0; constexpr u16 inode_type_bitmask = 0b11; -constexpr u16 inode_ndir_blocks = 8; +constexpr u16 inode_ndir_blocks = 9; 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; +constexpr u16 inode_blocks_count = inode_ind_block + 1; + +constexpr u16 inode_last_block = inode_ndir_blocks + block_size; struct INode { u16 mode; @@ -167,23 +174,34 @@ public: return m_superblock.root_inode; } - auto make_file(u16 dir_inode_id, std::string_view name) -> Result; + auto make_file(u16 parent_inode_id, std::string_view name) -> Result; + auto make_directory(u16 parent_inode_id, std::string_view name) + -> Result; + + auto write(u16 inode_id, const void* data, u16 size) -> Result; private: auto init_new(u16 volume_id, u16 block_count) -> Result; auto init_from_existing() -> Result; - auto append_to_directory(INode& dir_inode, const DirEntry& entry) + auto make_inode(u16 parent_inode_id, std::string_view name, INodeType type) + -> Result; + + auto append_to_directory(u16 dir_inode_id, const DirEntry& entry) -> Result; auto make_directory_inode() -> Result; auto inode_last_block_id(const INode& inode) -> Result; + template + auto inode_for_each_block_id(const INode& inode, Func func) -> Result; + auto write_inode(u16 inode_id, const INode& inode) -> Result; auto read_inode(u16 inode_id) -> Result; auto allocate_inode() -> Result; auto allocate_block() -> Result; + void deallocate_block(u16 block_id); auto sync_from_disk() -> Result; auto sync_to_disk() -> Result; @@ -192,10 +210,12 @@ private: template requires(sizeof(Data) <= block_size) - auto read_block_part(u16 block_id, u16 offset) -> Result; + auto read_block_part(u16 block_id, u16 offset, u16 size = sizeof(Data)) + -> Result; template requires(sizeof(Data) <= block_size) - auto write_block_part(u16 block_id, const Data& data, u16 offset) + auto write_block_part( + u16 block_id, const Data& data, u16 offset, u16 size = sizeof(Data)) -> Result; template diff --git a/src/vm_main.cpp b/src/vm_main.cpp index da05d4f..d89c958 100644 --- a/src/vm_main.cpp +++ b/src/vm_main.cpp @@ -41,6 +41,8 @@ int main(int argc, char** argv) auto root = fs.root_inode_id().value(); + auto file = fs.make_file(root, "test"); + } catch (std::bad_expected_access& ex) { std::println(stderr, "error: {}", ex.error()); return EXIT_FAILURE;