Replace coral::fs walker closure with coral::file_walker
Some checks failed
continuous-integration/drone/push Build is failing
Some checks failed
continuous-integration/drone/push Build is failing
This commit is contained in:
parent
2b23424744
commit
bb9617994f
@ -123,6 +123,24 @@ export namespace coral {
|
|||||||
virtual expected<u64, io_error> tell() = 0;
|
virtual expected<u64, io_error> 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<path, io_error> next() = 0;
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* [writer] that has a known range of data and may attempt to traverse it freely.
|
* [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.
|
* Platform-generalized file system interface.
|
||||||
*/
|
*/
|
||||||
struct fs {
|
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<expected<path, walk_error>()>;
|
|
||||||
|
|
||||||
virtual ~fs() {};
|
virtual ~fs() {};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Attempts to read the file in `target_path`, calling `then` if it was successfully opened for reading and
|
* Attempts to read the file in `target_path`, calling `then` if it was successfully opened for reading and
|
||||||
* passing the [file_reader] context along.
|
* 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<void(file_reader &)> const & then) {}
|
virtual void read_file(path const & target_path, closure<void(file_reader &)> const & then) {}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Attempts to walk the file tree from `target_path`, calling `then` if it was successfully opened for walking
|
* 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<void(walker const &)> const & then) {}
|
virtual void walk_files(path const & target_path, closure<void(file_walker &)> const & then) {}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Attempts to write the file in the file system located at `target_path`, calling `then` if it was successfully
|
* Attempts to write a 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.
|
* 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<void(file_writer &)> const & then) {}
|
virtual void write_file(path const & target_path, closure<void(file_writer &)> const & then) {}
|
||||||
};
|
};
|
||||||
|
111
source/oar.cpp
111
source/oar.cpp
@ -9,6 +9,7 @@ import coral.stack;
|
|||||||
using coral::closure;
|
using coral::closure;
|
||||||
using coral::expected;
|
using coral::expected;
|
||||||
using coral::file_reader;
|
using coral::file_reader;
|
||||||
|
using coral::file_walker;
|
||||||
using coral::fs;
|
using coral::fs;
|
||||||
using coral::io_error;
|
using coral::io_error;
|
||||||
using coral::path;
|
using coral::path;
|
||||||
@ -86,7 +87,7 @@ static_assert(block::is_sizeof(512));
|
|||||||
/**
|
/**
|
||||||
* Archive entry access interface.
|
* 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].
|
* Results of a find operation performed on an [archive_file].
|
||||||
*
|
*
|
||||||
@ -213,6 +214,50 @@ struct entry : public file_reader {
|
|||||||
u64 data_cursor {0};
|
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<path, io_error> 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 {
|
export namespace oar {
|
||||||
struct archive : public fs {
|
struct archive : public fs {
|
||||||
archive(fs * backing_fs, path const & archive_path) {
|
archive(fs * backing_fs, path const & archive_path) {
|
||||||
@ -223,34 +268,15 @@ export namespace oar {
|
|||||||
/**
|
/**
|
||||||
* See [fs::walk_files].
|
* See [fs::walk_files].
|
||||||
*/
|
*/
|
||||||
void walk_files(path const & target_path, closure<void(walker const &)> const & then) override {
|
void walk_files(path const & target_path, closure<void(file_walker &)> const & then) override {
|
||||||
this->backing_fs->read_file(this->archive_path, [&](file_reader & archive_reader) {
|
this->backing_fs->read_file(this->archive_path, [&](file_reader & archive_reader) {
|
||||||
entry archive_entry{&archive_reader};
|
entry archive_entry{&archive_reader};
|
||||||
|
|
||||||
if (archive_entry.find(entry_kind::directory, target_path) != entry::find_result::ok) return;
|
if (archive_entry.find(entry_kind::directory, target_path) != entry::find_result::ok) return;
|
||||||
|
|
||||||
then([&]() -> expected<path, walk_error> {
|
walker archive_walker {archive_entry};
|
||||||
constexpr usize path_size {sizeof(path)};
|
|
||||||
u8 path_buffer[path_size] {0};
|
|
||||||
|
|
||||||
// Read verify integrity.
|
then(archive_walker);
|
||||||
{
|
|
||||||
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 const *>(path_buffer)};
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -293,35 +319,22 @@ export namespace oar {
|
|||||||
bool has_io_error {false};
|
bool has_io_error {false};
|
||||||
bool is_out_of_memory {false};
|
bool is_out_of_memory {false};
|
||||||
|
|
||||||
input_fs.walk_files(input_path, [&](fs::walker const & walk) {
|
input_fs.walk_files(input_path, [&](file_walker & walker) {
|
||||||
coral::expected walked_path {walk()};
|
while (walker.has_next()) {
|
||||||
|
coral::expected const walked_path {walker.next()};
|
||||||
|
|
||||||
while (walked_path.is_ok()) {
|
if (walked_path.is_error()) {
|
||||||
is_out_of_memory = archive_blocks.push({.layout = {
|
has_io_error = true;
|
||||||
.path = *walked_path.ok()
|
|
||||||
}}) != coral::push_result::ok;
|
|
||||||
|
|
||||||
if (is_out_of_memory) return;
|
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;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
});
|
|
||||||
|
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;
|
if (has_io_error) return bundle_result::io_error;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user