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 --- include/mercury/kernel/storage.hpp | 130 +++++++++++++++++++++++++++++++++++++ 1 file changed, 130 insertions(+) create mode 100644 include/mercury/kernel/storage.hpp (limited to 'include/mercury/kernel/storage.hpp') diff --git a/include/mercury/kernel/storage.hpp b/include/mercury/kernel/storage.hpp new file mode 100644 index 0000000..1374766 --- /dev/null +++ b/include/mercury/kernel/storage.hpp @@ -0,0 +1,130 @@ +#ifndef MERCURY_KERNEL_STORAGE_HPP +#define MERCURY_KERNEL_STORAGE_HPP + +#include +#include + +namespace mercury::kernel::storage { + + typedef uint64_t node_id_t; + typedef uint64_t directory_iter_t; + + enum file_type { + regular_file, + directory, + symlink + }; + + enum io_result { + success, + mount_point_already_used, + not_a_directory, + not_supported, + out_of_bounds, + device_error, + fs_corrupt, + not_found, + bad_path, + }; + + class file_system_instance { + + public: + virtual ~file_system_instance() {} + + virtual io_result get_root_node(node_id_t &out) = 0; + + //get_first_child sets iter_out to a "directory iterator" representing the + //first child of this node. get_next_child gets the child after the child + //represented by the value of iter passed in, and changes iter to represent + //that next child. for an empty directory node, get_first_child returns + //io_result::out_of_bounds. when iter represents the last child of a node, + //get_next_child also returns io_result::out_of_bounds. + virtual io_result get_first_child(node_id_t node, node_id_t &out, directory_iter_t &iter_out) = 0; + virtual io_result get_next_child(node_id_t node, node_id_t &out, directory_iter_t &iter) = 0; + virtual io_result get_child(node_id_t node, node_id_t &out, const char *name, size_t name_len) = 0; + + virtual io_result get_name_length(node_id_t node, size_t &length_out) = 0; + //buffer is assumed to be long enough - call get_name_length first. + virtual io_result get_name(node_id_t node, char *buffer, size_t &length_out) = 0; + + virtual io_result get_file_length(node_id_t node, uint64_t &length_out) = 0; + + virtual io_result get_file_type(node_id_t node, file_type &out) = 0; + }; + + class block_device { + + private: + uint8_t *block_cache; + uint64_t block_cache_i; + bool block_cache_dirty; + + io_result load_cache_block(uint64_t i); + + protected: + //implemented in driver, bounds not checked + virtual io_result read_blocks_no_cache(uint64_t start, uint64_t count, void *into) = 0; + virtual io_result write_blocks_no_cache(uint64_t start, uint64_t count, const void *from) = 0; + + //it is assumed that this is only called once, by the driver, after + //block_size and block_count have been set, and before read_bytes or + //write_bytes can be called (e.g. in the derived class's constructor) + void allocate_block_cache(); + + public: + //set by storage component + file_system_instance *mounted_as; + utility::uuid id; + + //set by driver + uint64_t block_size; + uint64_t block_count; + + virtual ~block_device() { + if (block_cache) + delete block_cache; + } + + io_result read_bytes(uint64_t start, uint64_t count, void *into); + io_result write_bytes(uint64_t start, uint64_t count, const void *from); + + }; + + typedef io_result (*file_system_mounter)(block_device *bd, file_system_instance *&fs_out); + + extern utility::list *block_devices; + + void init_storage(); + + //a canon path contains no . or empty directory names, and + //contains no .. except for at the start of a relative path. + struct canon_path { + + bool absolute; + unsigned parent_count; + utility::vector segments; + + void parent(); + void rel(const canon_path &r); + + utility::string to_string(bool trailing_slash) const; + + }; + + void canonize_path(const char *str, size_t len, canon_path &out); + + //path must be absolute. + io_result mount_device(block_device *bd, const canon_path &path, file_system_mounter mounter); + + //path must be absolute. symlinks are always resolved on nodes other than the + //final one. they are resolved on the final node if and only if resolve final + //node is set to true. mount points are always traversed, including on the + //final node. this assumes that the path is under some mount point, and the + //same for any symlinks traversed (e.g. / is mounted). + io_result look_up_absolute_path(const canon_path &path, block_device *&bd_out, + node_id_t &node_out, bool resolve_final_node, canon_path &path_without_symlinks_out); + +} + +#endif -- cgit v1.2.3