summaryrefslogtreecommitdiff
path: root/kernel/source/storage
diff options
context:
space:
mode:
Diffstat (limited to 'kernel/source/storage')
-rw-r--r--kernel/source/storage/bd/memory.cpp21
-rw-r--r--kernel/source/storage/fs/tarfs.cpp238
2 files changed, 259 insertions, 0 deletions
diff --git a/kernel/source/storage/bd/memory.cpp b/kernel/source/storage/bd/memory.cpp
new file mode 100644
index 0000000..d6a6719
--- /dev/null
+++ b/kernel/source/storage/bd/memory.cpp
@@ -0,0 +1,21 @@
+#include <hilbert/kernel/storage/bd/memory.hpp>
+
+namespace hilbert::kernel::storage::bd {
+
+ memory::memory(void *buffer, uint64_t buffer_len)
+ : buffer((uint8_t *)buffer)
+ {
+ block_size = 1;
+ block_count = buffer_len;
+ //block cache will never be used, since the block size is 1.
+ }
+
+ bd_result memory::read_blocks_no_cache(
+ uint64_t start, uint64_t count, void *into
+ ) {
+ for (uint64_t i = 0; i < count; ++i)
+ ((uint8_t *)into)[i] = buffer[start + i];
+ return bd_result::success;
+ }
+
+}
diff --git a/kernel/source/storage/fs/tarfs.cpp b/kernel/source/storage/fs/tarfs.cpp
new file mode 100644
index 0000000..5986f62
--- /dev/null
+++ b/kernel/source/storage/fs/tarfs.cpp
@@ -0,0 +1,238 @@
+#include <hilbert/kernel/storage/fs/tarfs.hpp>
+
+//in tarfs_instance, node_id_t and directory_iter_t refer to the number
+//of bytes into the block device that the info sector is located.
+
+namespace hilbert::kernel::storage::fs {
+
+ #define BD_TO_FS(expr) \
+ { \
+ bd_result _result = expr; \
+ if (_result == bd_result::out_of_bounds) \
+ return fs_result::fs_corrupt; \
+ if (_result == bd_result::device_error) \
+ return fs_result::device_error; \
+ }
+
+ #define FS_TO_FS(expr) \
+ { \
+ fs_result _result = expr; \
+ if (_result != fs_result::success) \
+ return _result; \
+ }
+
+ tarfs_instance::tarfs_instance(block_device *bd) : bd(bd) {}
+
+ fs_result tarfs_instance::next_node(node_id_t node, node_id_t &out) {
+
+ uint64_t bytes;
+ FS_TO_FS(read_num(node + 124, 12, bytes))
+ out = node + ((bytes - 1) / 512 + 2) * 512;
+
+ uint8_t sector[512];
+ BD_TO_FS(bd->read_bytes(node, 512, sector))
+ for (unsigned i = 0; i < 512; ++i)
+ if (sector[i] != 0)
+ return fs_result::success;
+
+ return fs_result::does_not_exist;
+
+ }
+
+ fs_result tarfs_instance::read_full_name(
+ node_id_t node, utility::string &out
+ ) {
+
+ out.count = 0;
+ out.verify_buffer_len(155);
+ BD_TO_FS(bd->read_bytes(node + 345, 155, out.buffer))
+
+ while (out.count < 155 && out.buffer[out.count] != '\0')
+ ++out.count;
+
+ unsigned new_max = out.count + 100;
+ out.verify_buffer_len(new_max);
+ BD_TO_FS(bd->read_bytes(node, 100, out.buffer + out.count))
+
+ while (out.count < 255 && out.buffer[out.count] != '\0')
+ ++out.count;
+
+ return fs_result::success;
+
+ }
+
+ //len <= 12.
+ fs_result tarfs_instance::read_num(
+ uint64_t offset, unsigned len, uint64_t &out
+ ) {
+
+ char buf[12];
+ BD_TO_FS(bd->read_bytes(offset, len, buf))
+
+ out = 0;
+ for (unsigned i = 0; i < len && buf[i] != '\0'; ++i) {
+ if (buf[i] < '0' || buf[i] > '7')
+ return fs_result::fs_corrupt;
+ out = out * 8 + buf[i] - '0';
+ }
+
+ return fs_result::success;
+
+ }
+
+ fs_result tarfs_instance::first_child_starting_at(
+ node_id_t parent, node_id_t start, node_id_t &out
+ ) {
+
+ utility::string parent_full_name;
+ FS_TO_FS(read_full_name(parent, parent_full_name))
+
+ utility::string child_full_name;
+ out = start;
+
+ while (true) {
+
+ FS_TO_FS(read_full_name(out, child_full_name))
+
+ if (child_full_name.count > parent_full_name.count &&
+ child_full_name.starts_with(parent_full_name)
+ ) {
+ if (child_full_name.buffer[child_full_name.count - 1] == '/')
+ --child_full_name.count;
+ for (unsigned i = parent_full_name.count;
+ i < child_full_name.count; ++i)
+ if (child_full_name.buffer[i] == '/')
+ goto next;
+ return fs_result::success;
+ }
+
+ next:
+ FS_TO_FS(next_node(out, out))
+
+ }
+
+ }
+
+ fs_result tarfs_instance::get_dir_entry(node_id_t node, dir_entry &entry) {
+
+ utility::string full_name;
+ read_full_name(node, full_name);
+
+ if (full_name.count == 2)
+ entry.name.count = 0;
+
+ else {
+
+ if (full_name.buffer[full_name.count - 1] == '/')
+ --full_name.count;
+
+ unsigned last_slash =
+ utility::find_last(full_name.buffer, full_name.count, '/');
+ entry.name.count = full_name.count - last_slash - 1;
+ entry.name.verify_buffer_len(entry.name.count);
+
+ for (unsigned i = 0; i < entry.name.count; ++i)
+ entry.name.buffer[i] = full_name.buffer[last_slash + 1 + i];
+
+ }
+
+ entry.node = node;
+
+ char ch;
+ BD_TO_FS(bd->read_bytes(node + 156, 1, &ch));
+ switch (ch) {
+ case '0':
+ entry.type = file_type::regular_file;
+ break;
+ case '2':
+ entry.type = file_type::symlink;
+ break;
+ case '5':
+ entry.type = file_type::directory;
+ break;
+ default:
+ return fs_result::fs_corrupt;
+ }
+
+ if (entry.type == file_type::regular_file) {
+ uint64_t length;
+ FS_TO_FS(read_num(node + 124, 12, length))
+ entry.length = length;
+ }
+
+ else if (entry.type == file_type::symlink) {
+ utility::string target;
+ target.verify_buffer_len(100);
+ BD_TO_FS(bd->read_bytes(node + 157, 100, target.buffer))
+ while (target.count < 100 && target.buffer[target.count] != '\0')
+ ++target.count;
+ entry.target = utility::move(target);
+ }
+
+ return fs_result::success;
+
+ }
+
+ fs_result tarfs_instance::get_root_node(node_id_t &out) {
+
+ utility::string full_name;
+ node_id_t on = 0;
+
+ while (true) {
+
+ FS_TO_FS(read_full_name(on, full_name))
+ if (full_name.count == 2) {
+ out = on;
+ return fs_result::success;
+ }
+ fs_result result = next_node(on, on);
+ if (result == fs_result::does_not_exist)
+ return fs_result::fs_corrupt;
+ FS_TO_FS(result)
+
+ }
+
+ }
+
+ fs_result tarfs_instance::get_first_child(
+ node_id_t node, dir_entry &out, directory_iter_t &iter_out
+ ) {
+
+ node_id_t child;
+ FS_TO_FS(first_child_starting_at(node, 0, child))
+
+ dir_entry entry;
+ FS_TO_FS(get_dir_entry(child, entry))
+ out = utility::move(entry);
+ iter_out = (directory_iter_t)child;
+ return fs_result::success;
+
+ }
+
+ fs_result tarfs_instance::get_next_child(
+ node_id_t node, dir_entry &out, directory_iter_t &iter
+ ) {
+
+ node_id_t start;
+ FS_TO_FS(next_node((node_id_t)iter, start))
+
+ node_id_t child;
+ FS_TO_FS(first_child_starting_at(node, start, child))
+
+ dir_entry entry;
+ FS_TO_FS(get_dir_entry(child, entry))
+ out = utility::move(entry);
+ iter = (directory_iter_t)child;
+ return fs_result::success;
+
+ }
+
+ fs_result tarfs_instance::read_bytes_from_file(
+ node_id_t node, uint64_t start, uint64_t count, void *into
+ ) {
+ BD_TO_FS(bd->read_bytes(node + 512 + start, count, into))
+ return fs_result::success;
+ }
+
+
+}