summaryrefslogtreecommitdiff
path: root/kernel/fs/tarfs.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'kernel/fs/tarfs.cpp')
-rw-r--r--kernel/fs/tarfs.cpp224
1 files changed, 224 insertions, 0 deletions
diff --git a/kernel/fs/tarfs.cpp b/kernel/fs/tarfs.cpp
new file mode 100644
index 0000000..706280e
--- /dev/null
+++ b/kernel/fs/tarfs.cpp
@@ -0,0 +1,224 @@
+#include <mercury/kernel/fs/tarfs.hpp>
+
+//in fs::tarfs_instance, storage::node_id_t refers to the number
+//of bytes into the block device that the info sector is located
+
+namespace mercury::kernel::fs {
+
+ storage::io_result tarfs_mounter(
+ storage::block_device *bd, storage::file_system_instance *&fs_out
+ ) {
+ fs_out = new tarfs_instance(bd);
+ return storage::io_result::success;
+ }
+
+ tarfs_instance::tarfs_instance(storage::block_device *bd) : bd(bd) {}
+
+ storage::io_result tarfs_instance::next_node(storage::node_id_t &node) {
+ uint64_t file_length;
+ storage::io_result result = read_num(node + 124, 12, file_length);
+ if (result != storage::io_result::success)
+ return result;
+ node += ((file_length - 1) / 512 + 2) * 512;
+ return storage::io_result::success;
+ }
+
+ storage::io_result tarfs_instance::read_name(
+ storage::node_id_t node, char *name_buf, size_t &name_len_out
+ ) {
+ name_len_out = 0;
+ storage::io_result result = bd->read_bytes(node + 345, 155, name_buf);
+ if (result != storage::io_result::success)
+ return result;
+ while (name_buf[name_len_out] && name_len_out < 155)
+ ++name_len_out;
+ 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;
+ 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
+ ) {
+
+ //len <= 12
+ char buffer[12];
+ storage::io_result result = bd->read_bytes(offset, len, buffer);
+ out = 0;
+
+ for (size_t i = 0; i < len; ++i) {
+ if (!buffer[i])
+ return i == 0 ? storage::io_result::fs_corrupt
+ : storage::io_result::success;
+ if (buffer[i] < '0' || buffer[i] > '7')
+ return storage::io_result::fs_corrupt;
+ out = out * 8 + buffer[i] - '0';
+ }
+
+ return storage::io_result::success;
+
+ }
+
+#define RETURN_MAYBE_NOT_FOUND(expr) \
+ { \
+ storage::io_result _result = expr; \
+ if (_result == storage::io_result::out_of_bounds) \
+ return storage::io_result::not_found; \
+ 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;
+ 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;
+ RETURN_MAYBE_NOT_FOUND(next_node(out))
+ }
+ }
+
+ storage::io_result tarfs_instance::get_first_child(storage::node_id_t node,
+ storage::node_id_t &out, storage::directory_iter_t &iter_out
+ ) {
+
+ 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)
+ ;
+
+ RETURN_MAYBE_NOT_FOUND(next_node(out))
+
+ }
+
+ }
+
+ storage::io_result tarfs_instance::get_next_child(storage::node_id_t node,
+ storage::node_id_t &out, storage::directory_iter_t &iter
+ ) {
+
+ out = iter;
+ while (true) {
+
+ char name_buf[255];
+ size_t name_len;
+ RETURN_MAYBE_NOT_FOUND(read_name(out, name_buf, name_len))
+
+ //TODO
+ //NOTE: before return, do iter = out.
+ while (1)
+ ;
+
+
+ RETURN_MAYBE_NOT_FOUND(next_node(out))
+
+ }
+
+ }
+
+ storage::io_result tarfs_instance::get_child(storage::node_id_t node,
+ storage::node_id_t &out, const char *name, size_t name_len
+ ) {
+
+ char full_name[255];
+ size_t full_name_len;
+ RETURN_MAYBE_NOT_FOUND(read_name(out, 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)
+ full_name[full_name_len + i] = name[i];
+ full_name_len += name_len;
+
+ out = 0;
+ while (true) {
+
+ char cand_name[255];
+ size_t cand_name_len;
+ RETURN_MAYBE_NOT_FOUND(read_name(out, cand_name, cand_name_len))
+
+ if (cand_name_len != full_name_len)
+ goto next_iter;
+ for (size_t i = 0; i < full_name_len; ++i)
+ if (cand_name[i] != full_name[i])
+ goto next_iter;
+
+ return storage::io_result::success;
+
+ next_iter:
+ RETURN_MAYBE_NOT_FOUND(next_node(out))
+
+ }
+
+ }
+
+ storage::io_result tarfs_instance::get_name_length(
+ storage::node_id_t node, size_t &length_out
+ ) {
+
+ //TODO
+ while (1)
+ ;
+
+ }
+
+ storage::io_result tarfs_instance::get_name(
+ storage::node_id_t node, char *buffer, size_t &length_out
+ ) {
+
+ //TODO
+ while (1)
+ ;
+
+ }
+
+ storage::io_result tarfs_instance::get_file_length(
+ storage::node_id_t node, uint64_t &length_out
+ ) {
+
+ //TODO
+ while (1)
+ ;
+
+ }
+
+ storage::io_result tarfs_instance::get_file_type(
+ storage::node_id_t node, storage::file_type &out
+ ) {
+
+ uint64_t ft;
+ storage::io_result result = read_num(node + 156, 1, ft);
+ if (result != storage::io_result::success)
+ return result;
+
+ switch (ft) {
+ case 0:
+ out = storage::file_type::regular_file;
+ return storage::io_result::success;
+ case 2:
+ out = storage::file_type::symlink;
+ return storage::io_result::success;
+ case 5:
+ out = storage::file_type::directory;
+ return storage::io_result::success;
+ default:
+ return storage::io_result::not_supported;
+ }
+
+ }
+
+
+}