summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--include/mercury/kernel/fs/tarfs.hpp15
-rw-r--r--include/mercury/kernel/storage.hpp19
-rw-r--r--include/mercury/kernel/utility.hpp21
-rw-r--r--kernel/entry.cpp105
-rw-r--r--kernel/fs/tarfs.cpp141
-rw-r--r--kernel/storage.cpp9
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 <class value_t>
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(