From c4ab2f6f440f060b1686991b24379a4998aa55a9 Mon Sep 17 00:00:00 2001 From: Benji Dial Date: Thu, 11 Jan 2024 23:53:57 -0500 Subject: file reading, tarfs directory listing --- include/mercury/kernel/fs/tarfs.hpp | 15 ++-- include/mercury/kernel/storage.hpp | 19 +++-- include/mercury/kernel/utility.hpp | 21 ++++++ kernel/entry.cpp | 105 ++++++++++++++++++++------- kernel/fs/tarfs.cpp | 141 ++++++++++++++++++++++++++---------- kernel/storage.cpp | 9 ++- 6 files changed, 229 insertions(+), 81 deletions(-) diff --git a/include/mercury/kernel/fs/tarfs.hpp b/include/mercury/kernel/fs/tarfs.hpp index 41773ee..64ee481 100644 --- a/include/mercury/kernel/fs/tarfs.hpp +++ b/include/mercury/kernel/fs/tarfs.hpp @@ -12,9 +12,9 @@ namespace mercury::kernel::fs { storage::io_result next_node(storage::node_id_t &node); //name_buf must be at least 255 chars long. - storage::io_result read_name(storage::node_id_t node, char *name_buf, size_t &name_len_out); + storage::io_result read_name(storage::node_id_t node, char *name_buf, unsigned &name_len_out); //len <= 12 - storage::io_result read_num(uint64_t offset, size_t len, uint64_t &out); + storage::io_result read_num(uint64_t offset, unsigned len, uint64_t &out); public: tarfs_instance(storage::block_device *bd); @@ -25,11 +25,16 @@ namespace mercury::kernel::fs { storage::io_result get_next_child( storage::node_id_t node, storage::node_id_t &out, storage::directory_iter_t &iter) override; storage::io_result get_child( - storage::node_id_t node, storage::node_id_t &out, const char *name, size_t name_len) override; - storage::io_result get_name_length(storage::node_id_t node, size_t &length_out) override; - storage::io_result get_name(storage::node_id_t node, char *buffer, size_t &length_out) override; + storage::node_id_t node, storage::node_id_t &out, const char *name, unsigned name_len) override; + storage::io_result get_name_length(storage::node_id_t node, unsigned &length_out) override; + storage::io_result get_name(storage::node_id_t node, char *buffer, unsigned &length_out) override; storage::io_result get_file_length(storage::node_id_t node, uint64_t &length_out) override; storage::io_result get_file_type(storage::node_id_t node, storage::file_type &out) override; + storage::io_result resize_file(storage::node_id_t node, uint64_t new_length) override; + storage::io_result read_bytes_from_file( + storage::node_id_t node, uint64_t start, uint64_t count, void *into) override; + storage::io_result write_bytes_into_file( + storage::node_id_t node, uint64_t start, uint64_t count, const void *from) override; }; diff --git a/include/mercury/kernel/storage.hpp b/include/mercury/kernel/storage.hpp index 1374766..0df0829 100644 --- a/include/mercury/kernel/storage.hpp +++ b/include/mercury/kernel/storage.hpp @@ -38,19 +38,22 @@ namespace mercury::kernel::storage { //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. + //io_result::not_found. when iter represents the last child of a node, + //get_next_child also returns io_result::not_found. 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_child(node_id_t node, node_id_t &out, const char *name, unsigned name_len) = 0; - virtual io_result get_name_length(node_id_t node, size_t &length_out) = 0; + virtual io_result get_name_length(node_id_t node, unsigned &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_name(node_id_t node, char *buffer, unsigned &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; + + virtual io_result resize_file(node_id_t node, uint64_t new_length) = 0; + virtual io_result read_bytes_from_file(node_id_t node, uint64_t start, uint64_t count, void *into) = 0; + virtual io_result write_bytes_into_file(node_id_t node, uint64_t start, uint64_t count, const void *from) = 0; + }; class block_device { @@ -112,7 +115,7 @@ namespace mercury::kernel::storage { }; - void canonize_path(const char *str, size_t len, canon_path &out); + void canonize_path(const char *str, unsigned len, canon_path &out); //path must be absolute. io_result mount_device(block_device *bd, const canon_path &path, file_system_mounter mounter); diff --git a/include/mercury/kernel/utility.hpp b/include/mercury/kernel/utility.hpp index f12101a..1648e67 100644 --- a/include/mercury/kernel/utility.hpp +++ b/include/mercury/kernel/utility.hpp @@ -29,6 +29,27 @@ namespace mercury::kernel::utility { return len; } + //if c appears in str, this returns the index of the last time it appears. + //otherwise, this returns len. + static inline unsigned find_last(const char *str, unsigned len, char c) { + for (unsigned i = len; i > 0; --i) + if (str[i - 1] == c) + return i - 1; + return len; + } + + //str1 starts with str2 + static inline bool starts_with( + const char *str1, unsigned str1_len, const char *str2, unsigned str2_len + ) { + if (str1_len < str2_len) + return false; + for (unsigned i = 0; i < str2_len; ++i) + if (str1[i] != str2[i]) + return false; + return true; + } + template struct list { diff --git a/kernel/entry.cpp b/kernel/entry.cpp index 915bc8b..aa6568a 100644 --- a/kernel/entry.cpp +++ b/kernel/entry.cpp @@ -179,33 +179,84 @@ extern "C" [[noreturn]] void entry() { } -[[noreturn]] static void halt() { +[[noreturn]] static void print_and_halt(const char *msg) { + terminal::put_string_sz(msg); while (1) ; } -static void find_file(const char *path, size_t path_len) { +static void dir_tree( + storage::block_device *bd, storage::node_id_t node, unsigned indent +) { + + storage::node_id_t child_node; + storage::directory_iter_t dir_iter; + storage::io_result result = + bd->mounted_as->get_first_child(node, child_node, dir_iter); + if (result == storage::io_result::not_found) { + for (unsigned i = 0; i < indent; ++i) + terminal::put_char(' '); + terminal::put_string_sz("[empty]\n"); + return; + } + else if (result) + print_and_halt("error getting first child."); + + while (true) { + + unsigned name_len; + if (bd->mounted_as->get_name_length(child_node, name_len)) + print_and_halt("failed to get name length."); + char *name_buf = new char[name_len]; + if (bd->mounted_as->get_name(child_node, name_buf, name_len)) + print_and_halt("failed to get name."); + + for (unsigned i = 0; i < indent; ++i) + terminal::put_char(' '); + terminal::put_string(name_buf, name_len); + terminal::put_string(":\n", 2); + + delete[] name_buf; + + storage::file_type type; + if (bd->mounted_as->get_file_type(child_node, type)) + print_and_halt("failed to get type."); + + if (type == storage::file_type::directory) + dir_tree(bd, child_node, indent + 2); + + else { + uint64_t len; + if (bd->mounted_as->get_file_length(child_node, len)) + print_and_halt("failed to get length."); + char *contents = new char[len]; + if (bd->mounted_as->read_bytes_from_file(child_node, 0, len, contents)) + print_and_halt("failed to read file."); + + if (contents[len - 1] == '\n') + len--; + + for (unsigned i = 0; i < indent + 2; ++i) + terminal::put_char(' '); + if (len == 0) + terminal::put_string_sz("[empty]\n"); + else { + terminal::put_string(contents, len); + terminal::put_char('\n'); + } - storage::canon_path cp; - storage::canonize_path(path, path_len, cp); + delete[] contents; + } - storage::block_device *bd; - storage::node_id_t node_id; - storage::canon_path cp_without_symlinks; + storage::io_result result + = bd->mounted_as->get_next_child(node, child_node, dir_iter); + if (result == storage::io_result::not_found) + return; + else if (result) + print_and_halt("error getting next child."); - if (storage::look_up_absolute_path(cp, bd, node_id, true, - cp_without_symlinks) != storage::io_result::success) { - terminal::put_string_sz("failed to look up "); - terminal::put_string(path, path_len); - terminal::put_string_sz(" in vfs."); - halt(); } - terminal::put_string(path, path_len); - terminal::put_string_sz(" has node id "); - terminal::put_int_decimal(node_id); - terminal::put_string_sz(" in its file system.\n"); - } [[noreturn]] static void with_kernel_p4() { @@ -219,11 +270,8 @@ static void find_file(const char *path, size_t path_len) { storage::canon_path root; storage::canonize_path("/", 1, root); - if (storage::mount_device(initfs_bd, root, &fs::tarfs_mounter) != - storage::io_result::success) { - terminal::put_string_sz("failed to mount initfs."); - halt(); - } + if (storage::mount_device(initfs_bd, root, &fs::tarfs_mounter)) + print_and_halt("failed to mount initfs."); terminal::put_string_sz("kernel initialization complete.\n"); @@ -235,11 +283,12 @@ static void find_file(const char *path, size_t path_len) { terminal::put_int_decimal(free_pram_kib); terminal::put_string_sz(" kiB physical memory free.\n"); - find_file("/", 1); - find_file("/test.txt", 9); - find_file("/dir", 4); - find_file("/dir/dir2", 9); + storage::node_id_t root_node; + if (initfs_bd->mounted_as->get_root_node(root_node)) + print_and_halt("failed to get root initfs node."); - halt(); + terminal::put_string_sz("initfs:\n"); + dir_tree(initfs_bd, root_node, 2); + print_and_halt("halting."); } diff --git a/kernel/fs/tarfs.cpp b/kernel/fs/tarfs.cpp index 7ab0de5..7508c03 100644 --- a/kernel/fs/tarfs.cpp +++ b/kernel/fs/tarfs.cpp @@ -20,11 +20,18 @@ namespace mercury::kernel::fs { if (result != storage::io_result::success) return result; node += ((file_length - 1) / 512 + 2) * 512; - return storage::io_result::success; + uint8_t sector[512]; + result = bd->read_bytes(node, 512, sector); + if (result != storage::io_result::success) + return result; + for (unsigned i = 0; i < 512; ++i) + if (sector[i] != 0) + return storage::io_result::success; + return storage::io_result::out_of_bounds; } storage::io_result tarfs_instance::read_name( - storage::node_id_t node, char *name_buf, size_t &name_len_out + storage::node_id_t node, char *name_buf, unsigned &name_len_out ) { name_len_out = 0; storage::io_result result = bd->read_bytes(node + 345, 155, name_buf); @@ -35,14 +42,14 @@ namespace mercury::kernel::fs { 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; + unsigned 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 + uint64_t offset, unsigned len, uint64_t &out ) { //len <= 12 @@ -52,7 +59,7 @@ namespace mercury::kernel::fs { return result; out = 0; - for (size_t i = 0; i < len; ++i) { + for (unsigned i = 0; i < len; ++i) { if (!buffer[i]) return i == 0 ? storage::io_result::fs_corrupt : storage::io_result::success; @@ -74,11 +81,18 @@ namespace mercury::kernel::fs { return _result; \ } +#define RETURN_NOT_SUCCESS(expr) \ + { \ + storage::io_result _result = expr; \ + 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; + unsigned 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; @@ -90,16 +104,28 @@ namespace mercury::kernel::fs { storage::node_id_t &out, storage::directory_iter_t &iter_out ) { + char name_buf[255]; + unsigned name_len; + RETURN_NOT_SUCCESS(read_name(node, name_buf, name_len)) + 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) - ; + char cand_name_buf[255]; + unsigned cand_name_len; + RETURN_MAYBE_NOT_FOUND(read_name(out, cand_name_buf, cand_name_len)) + + if (cand_name_len > name_len && utility::starts_with( + cand_name_buf, cand_name_len, name_buf, name_len + )) { + const char *rem = cand_name_buf + name_len; + unsigned rem_len = cand_name_len - name_len; + unsigned slash = utility::find(rem, rem_len, '/'); + if (slash == rem_len - 1 || slash == rem_len) { + iter_out = out; + return storage::io_result::success; + } + } RETURN_MAYBE_NOT_FOUND(next_node(out)) @@ -111,18 +137,31 @@ namespace mercury::kernel::fs { storage::node_id_t &out, storage::directory_iter_t &iter ) { + char name_buf[255]; + unsigned name_len; + RETURN_NOT_SUCCESS(read_name(node, name_buf, name_len)) + out = iter; - while (true) { - char name_buf[255]; - size_t name_len; - RETURN_MAYBE_NOT_FOUND(read_name(out, name_buf, name_len)) + RETURN_MAYBE_NOT_FOUND(next_node(out)) - //TODO - //NOTE: before return, do iter = out. - while (1) - ; + while (true) { + char cand_name_buf[255]; + unsigned cand_name_len; + RETURN_MAYBE_NOT_FOUND(read_name(out, cand_name_buf, cand_name_len)) + + if (cand_name_len > name_len && utility::starts_with( + cand_name_buf, cand_name_len, name_buf, name_len + )) { + const char *rem = cand_name_buf + name_len; + unsigned rem_len = cand_name_len - name_len; + unsigned slash = utility::find(rem, rem_len, '/'); + if (slash == rem_len - 1 || slash == rem_len) { + iter = out; + return storage::io_result::success; + } + } RETURN_MAYBE_NOT_FOUND(next_node(out)) @@ -131,17 +170,17 @@ namespace mercury::kernel::fs { } storage::io_result tarfs_instance::get_child(storage::node_id_t node, - storage::node_id_t &out, const char *name, size_t name_len + storage::node_id_t &out, const char *name, unsigned name_len ) { char full_name[255]; - size_t full_name_len; + unsigned full_name_len; RETURN_MAYBE_NOT_FOUND(read_name(node, 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) + for (unsigned i = 0; i < name_len; ++i) full_name[full_name_len + i] = name[i]; full_name_len += name_len; @@ -149,12 +188,12 @@ namespace mercury::kernel::fs { while (true) { char cand_name[255]; - size_t cand_name_len; + unsigned cand_name_len; RETURN_MAYBE_NOT_FOUND(read_name(out, cand_name, cand_name_len)) if (cand_name_len != full_name_len && cand_name_len != full_name_len + 1) goto next_iter; - for (size_t i = 0; i < full_name_len; ++i) + for (unsigned i = 0; i < full_name_len; ++i) if (cand_name[i] != full_name[i]) goto next_iter; if (cand_name_len == full_name_len + 1 && @@ -171,22 +210,33 @@ namespace mercury::kernel::fs { } storage::io_result tarfs_instance::get_name_length( - storage::node_id_t node, size_t &length_out + storage::node_id_t node, unsigned &length_out ) { - //TODO - while (1) - ; + char name_buf[255]; + return get_name(node, name_buf, length_out); } storage::io_result tarfs_instance::get_name( - storage::node_id_t node, char *buffer, size_t &length_out + storage::node_id_t node, char *buffer, unsigned &length_out ) { - //TODO - while (1) - ; + unsigned full_length; + char full_buffer[255]; + RETURN_NOT_SUCCESS(read_name(node, full_buffer, full_length)) + if (full_length == 2) { + //full buffer must be ./ + length_out = 0; + return storage::io_result::success; + } + if (full_buffer[full_length - 1] == '/') + --full_length; + unsigned start = utility::find_last(full_buffer, full_length, '/') + 1; + length_out = full_length - start; + for (unsigned i = 0; i < length_out; ++i) + buffer[i] = full_buffer[start + i]; + return storage::io_result::success; } @@ -194,9 +244,7 @@ namespace mercury::kernel::fs { storage::node_id_t node, uint64_t &length_out ) { - //TODO - while (1) - ; + return read_num(node + 124, 12, length_out); } @@ -225,5 +273,24 @@ namespace mercury::kernel::fs { } + storage::io_result tarfs_instance::resize_file( + storage::node_id_t, uint64_t + ) { + //TODO: support resize if sector count isn't changed? + return storage::io_result::not_supported; + } + + storage::io_result tarfs_instance::read_bytes_from_file( + storage::node_id_t node, uint64_t start, uint64_t count, void *into + ) { + return bd->read_bytes(node + 512 + start, count, into); + } + + storage::io_result tarfs_instance::write_bytes_into_file( + storage::node_id_t, uint64_t, uint64_t, const void * + ) { + //TODO: support this. + return storage::io_result::not_supported; + } } diff --git a/kernel/storage.cpp b/kernel/storage.cpp index 29ae6cf..97d89aa 100644 --- a/kernel/storage.cpp +++ b/kernel/storage.cpp @@ -99,7 +99,7 @@ namespace mercury::kernel::storage { segments.add_end(r.segments.buffer[i]); } - void canonize_path(const char *str, size_t len, canon_path &out) { + void canonize_path(const char *str, unsigned len, canon_path &out) { out.absolute = false; out.parent_count = 0; @@ -121,8 +121,8 @@ namespace mercury::kernel::storage { while (len != 0) { - size_t segment_len = utility::find(str, len, '/'); - size_t to_skip = segment_len == len ? segment_len : segment_len + 1; + unsigned segment_len = utility::find(str, len, '/'); + unsigned to_skip = segment_len == len ? segment_len : segment_len + 1; if (segment_len == 0) ; @@ -169,6 +169,9 @@ namespace mercury::kernel::storage { //TODO while (1) ; + (void)bd; + (void)node; + (void)out; } static io_result resolve_symlinks( -- cgit v1.2.3