diff options
author | Benji Dial <benji@benjidial.net> | 2024-05-18 21:53:38 -0400 |
---|---|---|
committer | Benji Dial <benji@benjidial.net> | 2024-05-18 21:53:38 -0400 |
commit | b1a912a8a6ff472a49b2e0a09cfd433adfc2cb24 (patch) | |
tree | 5009d4415ba13e4baa37f3d0271852528130fd3b /kernel/source/vfile.cpp | |
parent | a8a80d326de9550b2a25b1255a2093ab43219ede (diff) | |
download | hilbert-os-b1a912a8a6ff472a49b2e0a09cfd433adfc2cb24.tar.gz |
reorganization, cross compiler
Diffstat (limited to 'kernel/source/vfile.cpp')
-rw-r--r-- | kernel/source/vfile.cpp | 206 |
1 files changed, 206 insertions, 0 deletions
diff --git a/kernel/source/vfile.cpp b/kernel/source/vfile.cpp new file mode 100644 index 0000000..89c95e6 --- /dev/null +++ b/kernel/source/vfile.cpp @@ -0,0 +1,206 @@ +#include <hilbert/kernel/vfile.hpp> + +//TODO: handle symlink loops nicely in vfile::get_child, +// vfile::get_children, and lookup_path. + +namespace hilbert::kernel::vfile { + + 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 utility::string &name, canon_path &out) { + + out.absolute = false; + out.parent_count = 0; + out.segments.count = 0; + + const char *str = name.buffer; + unsigned len = name.count; + + if (len == 0) + return; + + if (len == 1 && str[0] == '/') { + out.absolute = true; + return; + } + + if (str[0] == '/') { + out.absolute = true; + ++str; + --len; + } + + while (len != 0) { + + unsigned segment_len = utility::find(str, len, '/'); + unsigned to_skip = segment_len == len ? segment_len : segment_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(utility::move(segment)); + } + + str += to_skip; + len -= to_skip; + + } + + } + +#define RET_NOT_SUC(expr) \ + { \ + storage::fs_result _result = expr; \ + if (_result != storage::fs_result::success) \ + return _result; \ + } + + storage::fs_result vfile::follow_symlinks(vfile &out) const { + + if (dir_entry.type != storage::file_type::symlink) { + out = *this; + return storage::fs_result::success; + } + + canon_path target_path; + canonize_path(dir_entry.target, target_path); + canon_path full_path = path; + full_path.parent(); + full_path.rel(target_path); + + vfile next; + RET_NOT_SUC(lookup_path(full_path, next, false)) + + next.path = path; + return next.follow_symlinks(out); + + } + + storage::fs_result vfile::get_child( + vfile &out, const utility::string &name + ) const { + + storage::dir_entry entry; + storage::directory_iter_t iter; + + RET_NOT_SUC(bd->mounted_as->get_first_child(dir_entry.node, entry, iter)) + + while (true) { + + if (entry.name == name) { + + vfile vf; + vf.bd = bd; + vf.dir_entry = utility::move(entry); + vf.path = path; + vf.path.segments.add_end(name); + out = utility::move(vf); + return storage::fs_result::success; + + } + + RET_NOT_SUC(bd->mounted_as->get_next_child(dir_entry.node, entry, iter)) + + } + + } + + storage::fs_result vfile::get_children(utility::vector<vfile> &out) const { + + storage::dir_entry entry; + storage::directory_iter_t iter; + + storage::fs_result result = + bd->mounted_as->get_first_child(dir_entry.node, entry, iter); + if (result == storage::fs_result::does_not_exist) + return storage::fs_result::success; + else if (result != storage::fs_result::success) + return result; + + while (true) { + + vfile vf; + vf.bd = bd; + vf.path = path; + vf.path.segments.add_end(entry.name); + vf.dir_entry = utility::move(entry); + out.add_end(utility::move(vf)); + + result = bd->mounted_as->get_next_child(dir_entry.node, entry, iter); + if (result == storage::fs_result::does_not_exist) + return storage::fs_result::success; + else if (result != storage::fs_result::success) + return result; + + } + + } + + storage::fs_result vfile::read_file( + uint64_t start, uint64_t length, void *into + ) const { + return bd->mounted_as->read_bytes_from_file( + dir_entry.node, start, length, into); + } + + //TODO: see comment at top of vfile.hpp. + static const vfile *root; + + void set_root(const vfile &root) { + kernel::vfile::root = new vfile(root); + } + + storage::fs_result lookup_path( + const canon_path &path, vfile &out, bool follow_final_symlink + ) { + + //assume path is absolute. + + out = *root; + for (unsigned i = 0; i < path.segments.count; ++i) { + + vfile result; + RET_NOT_SUC(out.follow_symlinks(result)) + out = utility::move(result); + + RET_NOT_SUC(out.get_child(result, path.segments.buffer[i])) + out = utility::move(result); + + } + + if (follow_final_symlink) { + vfile result; + RET_NOT_SUC(out.follow_symlinks(result)) + out = utility::move(result); + } + + return storage::fs_result::success; + + } + +} |