From 15e62510104bc0e2b9180b66e5845d985cac03cc Mon Sep 17 00:00:00 2001 From: Benji Dial Date: Wed, 10 Jan 2024 00:17:29 -0500 Subject: partial (largely untested) memory block device and tar file system support --- kernel/fs/tarfs.cpp | 224 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 224 insertions(+) create mode 100644 kernel/fs/tarfs.cpp (limited to 'kernel/fs') diff --git a/kernel/fs/tarfs.cpp b/kernel/fs/tarfs.cpp new file mode 100644 index 0000000..706280e --- /dev/null +++ b/kernel/fs/tarfs.cpp @@ -0,0 +1,224 @@ +#include + +//in fs::tarfs_instance, storage::node_id_t refers to the number +//of bytes into the block device that the info sector is located + +namespace mercury::kernel::fs { + + storage::io_result tarfs_mounter( + storage::block_device *bd, storage::file_system_instance *&fs_out + ) { + fs_out = new tarfs_instance(bd); + return storage::io_result::success; + } + + tarfs_instance::tarfs_instance(storage::block_device *bd) : bd(bd) {} + + storage::io_result tarfs_instance::next_node(storage::node_id_t &node) { + uint64_t file_length; + storage::io_result result = read_num(node + 124, 12, file_length); + if (result != storage::io_result::success) + return result; + node += ((file_length - 1) / 512 + 2) * 512; + return storage::io_result::success; + } + + storage::io_result tarfs_instance::read_name( + storage::node_id_t node, char *name_buf, size_t &name_len_out + ) { + name_len_out = 0; + storage::io_result result = bd->read_bytes(node + 345, 155, name_buf); + if (result != storage::io_result::success) + return result; + while (name_buf[name_len_out] && name_len_out < 155) + ++name_len_out; + result = bd->read_bytes(node, 100, name_buf + name_len_out); + if (result != storage::io_result::success) + return result; + size_t new_limit = name_len_out + 100; + while (name_buf[name_len_out] && name_len_out < new_limit) + ++name_len_out; + return storage::io_result::success; + } + + storage::io_result tarfs_instance::read_num( + uint64_t offset, size_t len, uint64_t &out + ) { + + //len <= 12 + char buffer[12]; + storage::io_result result = bd->read_bytes(offset, len, buffer); + out = 0; + + for (size_t i = 0; i < len; ++i) { + if (!buffer[i]) + return i == 0 ? storage::io_result::fs_corrupt + : storage::io_result::success; + if (buffer[i] < '0' || buffer[i] > '7') + return storage::io_result::fs_corrupt; + out = out * 8 + buffer[i] - '0'; + } + + return storage::io_result::success; + + } + +#define RETURN_MAYBE_NOT_FOUND(expr) \ + { \ + storage::io_result _result = expr; \ + if (_result == storage::io_result::out_of_bounds) \ + return storage::io_result::not_found; \ + if (_result != storage::io_result::success) \ + return _result; \ + } + + storage::io_result tarfs_instance::get_root_node(storage::node_id_t &out) { + out = 0; + while (true) { + char name_buf[255]; + size_t name_len; + RETURN_MAYBE_NOT_FOUND(read_name(out, name_buf, name_len)) + if (name_len == 2 && name_buf[0] == '.' && name_buf[1] == '/') + return storage::io_result::success; + RETURN_MAYBE_NOT_FOUND(next_node(out)) + } + } + + storage::io_result tarfs_instance::get_first_child(storage::node_id_t node, + storage::node_id_t &out, storage::directory_iter_t &iter_out + ) { + + out = 0; + while (true) { + + char name_buf[255]; + size_t name_len; + RETURN_MAYBE_NOT_FOUND(read_name(out, name_buf, name_len)) + + //TODO + while (1) + ; + + RETURN_MAYBE_NOT_FOUND(next_node(out)) + + } + + } + + storage::io_result tarfs_instance::get_next_child(storage::node_id_t node, + storage::node_id_t &out, storage::directory_iter_t &iter + ) { + + out = iter; + while (true) { + + char name_buf[255]; + size_t name_len; + RETURN_MAYBE_NOT_FOUND(read_name(out, name_buf, name_len)) + + //TODO + //NOTE: before return, do iter = out. + while (1) + ; + + + RETURN_MAYBE_NOT_FOUND(next_node(out)) + + } + + } + + storage::io_result tarfs_instance::get_child(storage::node_id_t node, + storage::node_id_t &out, const char *name, size_t name_len + ) { + + char full_name[255]; + size_t full_name_len; + RETURN_MAYBE_NOT_FOUND(read_name(out, full_name, full_name_len)) + + if (full_name_len + name_len > 255) + return storage::io_result::not_supported; + + for (size_t i = 0; i < name_len; ++i) + full_name[full_name_len + i] = name[i]; + full_name_len += name_len; + + out = 0; + while (true) { + + char cand_name[255]; + size_t cand_name_len; + RETURN_MAYBE_NOT_FOUND(read_name(out, cand_name, cand_name_len)) + + if (cand_name_len != full_name_len) + goto next_iter; + for (size_t i = 0; i < full_name_len; ++i) + if (cand_name[i] != full_name[i]) + goto next_iter; + + return storage::io_result::success; + + next_iter: + RETURN_MAYBE_NOT_FOUND(next_node(out)) + + } + + } + + storage::io_result tarfs_instance::get_name_length( + storage::node_id_t node, size_t &length_out + ) { + + //TODO + while (1) + ; + + } + + storage::io_result tarfs_instance::get_name( + storage::node_id_t node, char *buffer, size_t &length_out + ) { + + //TODO + while (1) + ; + + } + + storage::io_result tarfs_instance::get_file_length( + storage::node_id_t node, uint64_t &length_out + ) { + + //TODO + while (1) + ; + + } + + storage::io_result tarfs_instance::get_file_type( + storage::node_id_t node, storage::file_type &out + ) { + + uint64_t ft; + storage::io_result result = read_num(node + 156, 1, ft); + if (result != storage::io_result::success) + return result; + + switch (ft) { + case 0: + out = storage::file_type::regular_file; + return storage::io_result::success; + case 2: + out = storage::file_type::symlink; + return storage::io_result::success; + case 5: + out = storage::file_type::directory; + return storage::io_result::success; + default: + return storage::io_result::not_supported; + } + + } + + +} -- cgit v1.2.3