summaryrefslogtreecommitdiff
path: root/include/mercury/kernel/storage.hpp
diff options
context:
space:
mode:
Diffstat (limited to 'include/mercury/kernel/storage.hpp')
-rw-r--r--include/mercury/kernel/storage.hpp130
1 files changed, 130 insertions, 0 deletions
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 <mercury/kernel/utility.hpp>
+#include <cstdint>
+
+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_device *> *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<utility::string> 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