This repository has been archived on 2025-02-26. You can view files and clone it, but cannot push or open issues or pull requests.
hilbert-os/kernel/storage.cpp

246 lines
6.1 KiB
C++

#include <mercury/kernel/storage.hpp>
#define RETURN_IF_NOT_SUCCESS(expr) \
{ \
io_result _result = expr; \
if (_result != io_result::success) \
return _result; \
}
namespace mercury::kernel::storage {
io_result block_device::load_cache_block(uint64_t i) {
if (block_cache_i == i)
return io_result::success;
if (block_cache_dirty) {
RETURN_IF_NOT_SUCCESS(
write_blocks_no_cache(block_cache_i, 1, block_cache))
block_cache_dirty = false;
}
io_result result = read_blocks_no_cache(i, 1, block_cache);
if (result != io_result::success) {
block_cache_i = block_count;
return result;
}
block_cache_i = i;
return io_result::success;
}
io_result block_device::read_bytes(
uint64_t start, uint64_t count, void *into
) {
if (start + count > block_size * block_count)
return io_result::out_of_bounds;
uint8_t *into_u8 = (uint8_t *)into;
if (start % block_size != 0) {
uint64_t prefix_len = block_size - start % block_size;
RETURN_IF_NOT_SUCCESS(load_cache_block(start / block_size))
for (uint64_t i = 0; i < prefix_len; ++i)
into_u8[i] = block_cache[start % block_size + i];
into_u8 += prefix_len;
start += prefix_len;
count -= prefix_len;
}
uint64_t postfix_start = ((start + count) / block_size) * block_size;
if (postfix_start != start) {
RETURN_IF_NOT_SUCCESS(read_blocks_no_cache(
start / block_size, (postfix_start - start) / block_size, into_u8))
count -= postfix_start - start;
into_u8 += postfix_start - start;
start = postfix_start;
}
if (count != 0) {
RETURN_IF_NOT_SUCCESS(load_cache_block(start / block_size))
for (uint64_t i = 0; i < count; ++i)
into_u8[i] = block_cache[i];
}
return io_result::success;
}
utility::list<block_device *> *block_devices;
static utility::trie<utility::string, block_device *> *mounted_devices;
void init_storage() {
block_devices = new utility::list<block_device *>();
mounted_devices = new utility::trie<utility::string, block_device *>();
}
void canon_path::parent() {
if (segments.count != 0)
--segments.count;
else if (!absolute)
++parent_count;
}
void canon_path::rel(const canon_path &r) {
if (r.absolute) {
segments.count = 0;
absolute = true;
parent_count = 0;
}
for (unsigned i = 0; i < r.parent_count; ++i)
parent();
for (unsigned i = 0; i < r.segments.count; ++i)
segments.add_end(r.segments.buffer[i]);
}
void canonize_path(const char *str, size_t len, canon_path &out) {
out.absolute = false;
out.parent_count = 0;
out.segments.count = 0;
if (len == 0)
return;
if (len == 1 && str[0] == '/') {
out.absolute = true;
return;
}
if (str[0] == '/') {
out.absolute = true;
++str;
--len;
}
while (len != 0) {
size_t segment_len = utility::find(str, len, '/');
size_t to_skip = segment_len == len ? len : len + 1;
if (segment_len == 0)
;
else if (segment_len == 1 && str[0] == '.')
;
else if (segment_len == 2 && str[0] == '.' && str[1] == '.')
out.parent();
else {
utility::string segment(str, segment_len);
out.segments.add_end(std::move(segment));
}
str += to_skip;
len -= to_skip;
}
}
io_result mount_device(
block_device *bd, const canon_path &path, file_system_mounter mounter
) {
if (!path.absolute)
return io_result::bad_path;
if (mounted_devices->has_key(path.segments))
return io_result::mount_point_already_used;
file_system_instance *fs;
RETURN_IF_NOT_SUCCESS(mounter(bd, fs));
bd->mounted_as = fs;
mounted_devices->try_insert(path.segments, bd);
return io_result::success;
}
static io_result symlink_contents(
block_device *bd, node_id_t node, canon_path &out
) {
//TODO
while (1)
;
}
static io_result resolve_symlinks(
block_device *&bd, node_id_t &node, canon_path &path
) {
file_type ft;
RETURN_IF_NOT_SUCCESS(bd->mounted_as->get_file_type(node, ft))
if (ft != file_type::symlink)
return io_result::success;
canon_path contents;
RETURN_IF_NOT_SUCCESS(symlink_contents(bd, node, contents))
path.parent();
path.rel(contents);
return look_up_absolute_path(path, bd, node, true, path);
}
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
) {
if (!path.absolute)
return io_result::bad_path;
unsigned prefix_length;
bd_out =
*mounted_devices->longest_prefix_with_value(path.segments, prefix_length)
.value_here;
RETURN_IF_NOT_SUCCESS(bd_out->mounted_as->get_root_node(node_out))
path_without_symlinks_out.absolute = true;
path_without_symlinks_out.parent_count = 0;
path_without_symlinks_out.segments.count = 0;
for (unsigned i = 0; i < prefix_length; ++i)
path_without_symlinks_out.segments.add_end(path.segments.buffer[i]);
for (unsigned i = prefix_length; i < path.segments.count - 1; ++i) {
path_without_symlinks_out.segments.add_end(path.segments.buffer[i]);
RETURN_IF_NOT_SUCCESS(bd_out->mounted_as->get_child(node_out, node_out,
path.segments.buffer[i].buffer, path.segments.buffer[i].count))
RETURN_IF_NOT_SUCCESS(resolve_symlinks(
bd_out, node_out, path_without_symlinks_out))
file_type ft;
RETURN_IF_NOT_SUCCESS(bd_out->mounted_as->get_file_type(node_out, ft))
if (ft != file_type::directory)
return io_result::not_a_directory;
}
const utility::string &last_segment =
path.segments.buffer[path.segments.count - 1];
path_without_symlinks_out.segments.add_end(last_segment);
RETURN_IF_NOT_SUCCESS(bd_out->mounted_as->get_child(
node_out, node_out, last_segment.buffer, last_segment.count))
if (resolve_final_node)
RETURN_IF_NOT_SUCCESS(resolve_symlinks(
bd_out, node_out, path_without_symlinks_out))
return io_result::success;
}
}