From bb9617994f7c979a343d63b38282570ee8d895b3 Mon Sep 17 00:00:00 2001 From: kayomn Date: Tue, 28 Feb 2023 01:16:19 +0000 Subject: [PATCH] Replace coral::fs walker closure with coral::file_walker --- source/coral/files.cpp | 56 +++++++++++---------- source/oar.cpp | 111 +++++++++++++++++++++++------------------ 2 files changed, 91 insertions(+), 76 deletions(-) diff --git a/source/coral/files.cpp b/source/coral/files.cpp index 1d218bf..2c5b8d4 100755 --- a/source/coral/files.cpp +++ b/source/coral/files.cpp @@ -123,6 +123,24 @@ export namespace coral { virtual expected tell() = 0; }; + /** + * Enumerator a file tree recursively, returning the absolute path of each file within. + */ + struct file_walker { + virtual ~file_walker() {} + + /** + * Returns `true` if there are paths pending enumeration, otherwise `false`. + */ + virtual bool has_next() = 0; + + /** + * Attempts to enumerate over the next absolute [path] in the file tree, returning it or an [io_error] if the + * operation failed for whatever reason. + */ + virtual expected next() = 0; + }; + /** * [writer] that has a known range of data and may attempt to traverse it freely. */ @@ -144,47 +162,31 @@ export namespace coral { * Platform-generalized file system interface. */ struct fs { - /** - * Errors that may occur while trying to walk a file tree. - * - * [walk_error::end_of_walk] reports that there are no more paths left in the file tree that to traverse. - * - * [walk_error::io_unavailable] indicates that an implementation-defined I/O error has occured during traversal - * of the file tree and failed to recover the next file tree path as a result. - */ - enum class walk_error { - end_of_walk, - io_unavailable, - }; - - /** - * Supplier of file paths from a file tree walking context created by calling [walk_files]. - * - * Each subsequent invocation will produce either a valid path in the file tree from `target_path` or a - * [walk_error], with [walk_error::end_of_walk] signalling that there are no more paths left in the file tree to - * traverse. See [walk_error] for more details on potential errors. - */ - using walker = closure()>; - virtual ~fs() {}; /** * Attempts to read the file in `target_path`, calling `then` if it was successfully opened for reading and * passing the [file_reader] context along. + * + * See [file_reader] for more information on how to read from the file. */ virtual void read_file(path const & target_path, closure const & then) {} /** * Attempts to walk the file tree from `target_path`, calling `then` if it was successfully opened for walking - * and passing the [walker] context along. + * and passing the [file_walker] context along. * - * See [walker] for more information on how to use it to traverse the file tree. + * See [file_walker] for more information on how to traverse the file tree. */ - virtual void walk_files(path const & target_path, closure const & then) {} + virtual void walk_files(path const & target_path, closure const & then) {} /** - * Attempts to write the file in the file system located at `target_path`, calling `then` if it was successfully - * opened for writing and passing the [file_writer] context along. + * Attempts to write a file in the file system located at `target_path`, calling `then` if it was successfully + * created and / or opened for writing and passing the [file_writer] context along. + * + * See [file_writer] for more information on how to write to the file. + * + * *Note*: Any file already existing at `target_path` will be overwritten to create a new file for writing. */ virtual void write_file(path const & target_path, closure const & then) {} }; diff --git a/source/oar.cpp b/source/oar.cpp index ac7c456..74cb933 100755 --- a/source/oar.cpp +++ b/source/oar.cpp @@ -9,6 +9,7 @@ import coral.stack; using coral::closure; using coral::expected; using coral::file_reader; +using coral::file_walker; using coral::fs; using coral::io_error; using coral::path; @@ -86,7 +87,7 @@ static_assert(block::is_sizeof(512)); /** * Archive entry access interface. */ -struct entry : public file_reader { +struct entry final : public file_reader { /** * Results of a find operation performed on an [archive_file]. * @@ -213,6 +214,50 @@ struct entry : public file_reader { u64 data_cursor {0}; }; +struct walker final : public file_walker { + entry & archive_entry; + + u64 index {0}; + + u64 count {0}; + + walker(entry & archive_entry) : archive_entry{archive_entry} {} + + bool has_next() override { + return this->index < this->count; + } + + expected next() override { + constexpr usize path_size {sizeof(path)}; + u8 path_buffer[path_size] {0}; + + // Read verify integrity. + { + expected const data_read {archive_entry.read(path_buffer)}; + + if (data_read.is_error()) return this->error(); + + switch (*data_read.ok()) { + case path_size: break; + case 0: return path{}; + default: return this->error(); + } + } + + // Verify existence of zero terminator in path. + if (!coral::find_last(path_buffer, 0).has_value()) return this->error(); + + return path{}.joined(coral::slice{path_buffer}.as_chars()); + } + + private: + io_error error() { + this->index = this->count; + + return io_error::unavailable; + } +}; + export namespace oar { struct archive : public fs { archive(fs * backing_fs, path const & archive_path) { @@ -223,34 +268,15 @@ export namespace oar { /** * See [fs::walk_files]. */ - void walk_files(path const & target_path, closure const & then) override { + void walk_files(path const & target_path, closure const & then) override { this->backing_fs->read_file(this->archive_path, [&](file_reader & archive_reader) { entry archive_entry{&archive_reader}; if (archive_entry.find(entry_kind::directory, target_path) != entry::find_result::ok) return; - then([&]() -> expected { - constexpr usize path_size {sizeof(path)}; - u8 path_buffer[path_size] {0}; + walker archive_walker {archive_entry}; - // Read verify integrity. - { - expected const data_read {archive_entry.read(path_buffer)}; - - if (data_read.is_error()) return walk_error::io_unavailable; - - switch (*data_read.ok()) { - case path_size: break; - case 0: return walk_error::end_of_walk; - default: return walk_error::io_unavailable; - } - } - - // Verify existence of zero terminator in path. - if (!coral::find_last(path_buffer, 0).has_value()) return walk_error::io_unavailable; - - return {*reinterpret_cast(path_buffer)}; - }); + then(archive_walker); }); } @@ -293,35 +319,22 @@ export namespace oar { bool has_io_error {false}; bool is_out_of_memory {false}; - input_fs.walk_files(input_path, [&](fs::walker const & walk) { - coral::expected walked_path {walk()}; + input_fs.walk_files(input_path, [&](file_walker & walker) { + while (walker.has_next()) { + coral::expected const walked_path {walker.next()}; - while (walked_path.is_ok()) { - is_out_of_memory = archive_blocks.push({.layout = { - .path = *walked_path.ok() - }}) != coral::push_result::ok; + if (walked_path.is_error()) { + has_io_error = true; - if (is_out_of_memory) return; - - file_count += 1; - walked_path = walk(); - } - - walked_path.error().and_then([&](fs::walk_error walk_error) { - switch (walk_error) { - case fs::walk_error::io_unavailable: { - has_io_error = true; - - return; - } - - case fs::walk_error::end_of_walk: { - has_io_error = true; - - return; - } + return; } - }); + + if (archive_blocks.push({.layout = {.path = *walked_path.ok()}}) != coral::push_result::ok) { + is_out_of_memory = true; + + return; + } + } }); if (has_io_error) return bundle_result::io_error;