diff --git a/repos/gems/src/app/trace_recorder/ctf/backend.cc b/repos/gems/src/app/trace_recorder/ctf/backend.cc index ad1188d4fd..b639b7c0c2 100644 --- a/repos/gems/src/app/trace_recorder/ctf/backend.cc +++ b/repos/gems/src/app/trace_recorder/ctf/backend.cc @@ -23,12 +23,12 @@ void Writer::start_iteration(Directory &root, _file_path = Directory::join(path, info.thread_name()); try { - _dst_file.construct(root, _file_path, true); + _dst_file.construct(root, _file_path); /* initialise packet header */ _packet_buffer.init_header(info); } - catch (New_file::Create_failed) { + catch (Append_file::Create_failed) { error("Could not create file."); } } diff --git a/repos/gems/src/app/trace_recorder/ctf/backend.h b/repos/gems/src/app/trace_recorder/ctf/backend.h index 77dd6596d1..c4ee82eee8 100644 --- a/repos/gems/src/app/trace_recorder/ctf/backend.h +++ b/repos/gems/src/app/trace_recorder/ctf/backend.h @@ -27,7 +27,7 @@ namespace Ctf { using namespace Trace_recorder; using Genode::Directory; - using Genode::New_file; + using Genode::Append_file; using Buffer = Write_buffer<32*1024>; @@ -39,9 +39,9 @@ namespace Ctf { class Ctf::Writer : public Trace_recorder::Writer_base { private: - Buffer &_packet_buffer; - Constructible _dst_file { }; - Directory::Path _file_path { }; + Buffer &_packet_buffer; + Constructible _dst_file { }; + Directory::Path _file_path { }; public: Writer(Genode::Registry ®istry, Buffer &packet_buffer) diff --git a/repos/gems/src/app/trace_recorder/ctf/write_buffer.h b/repos/gems/src/app/trace_recorder/ctf/write_buffer.h index 5ee76f3122..490f236425 100644 --- a/repos/gems/src/app/trace_recorder/ctf/write_buffer.h +++ b/repos/gems/src/app/trace_recorder/ctf/write_buffer.h @@ -64,12 +64,12 @@ class Ctf::Write_buffer }); } - void write_to_file(Genode::New_file &dst, Genode::Directory::Path const &path) + void write_to_file(Genode::Append_file &dst, Genode::Directory::Path const &path) { if (_header().empty()) return; - if (dst.append(_buffer, _header().total_length_bytes()) != New_file::Append_result::OK) + if (dst.append(_buffer, _header().total_length_bytes()) != Append_file::Append_result::OK) error("Write error for ", path); _header().reset(); diff --git a/repos/gems/src/app/trace_recorder/pcapng/backend.cc b/repos/gems/src/app/trace_recorder/pcapng/backend.cc index 20f5da2ca2..9014ebed18 100644 --- a/repos/gems/src/app/trace_recorder/pcapng/backend.cc +++ b/repos/gems/src/app/trace_recorder/pcapng/backend.cc @@ -35,14 +35,14 @@ void Writer::start_iteration(Directory &root, /* append to file */ try { - _dst_file.construct(root, _file_path, true); + _dst_file.construct(root, _file_path); _interface_registry.clear(); _buffer.clear(); _buffer.append(); _empty_section = true; } - catch (New_file::Create_failed) { + catch (Append_file::Create_failed) { error("Could not create file."); } } diff --git a/repos/gems/src/app/trace_recorder/pcapng/backend.h b/repos/gems/src/app/trace_recorder/pcapng/backend.h index 957b6d1590..392bcffd72 100644 --- a/repos/gems/src/app/trace_recorder/pcapng/backend.h +++ b/repos/gems/src/app/trace_recorder/pcapng/backend.h @@ -27,7 +27,7 @@ namespace Pcapng { using namespace Trace_recorder; using Genode::Directory; - using Genode::New_file; + using Genode::Append_file; using Buffer = Write_buffer<32*1024>; @@ -42,7 +42,7 @@ class Pcapng::Writer : public Trace_recorder::Writer_base Interface_registry &_interface_registry; Buffer &_buffer; Timestamp_calibrator const &_ts_calibrator; - Constructible _dst_file { }; + Constructible _dst_file { }; Directory::Path _file_path { }; bool _empty_section { false }; diff --git a/repos/gems/src/app/trace_recorder/pcapng/write_buffer.h b/repos/gems/src/app/trace_recorder/pcapng/write_buffer.h index e7c0f34bd8..349092daea 100644 --- a/repos/gems/src/app/trace_recorder/pcapng/write_buffer.h +++ b/repos/gems/src/app/trace_recorder/pcapng/write_buffer.h @@ -62,12 +62,12 @@ class Pcapng::Write_buffer return Append_ok(); } - void write_to_file(Genode::New_file &dst, Directory::Path const &path) + void write_to_file(Genode::Append_file &dst, Directory::Path const &path) { if (_total_length == 0) return; - if (dst.append(_buffer, _total_length) != New_file::Append_result::OK) + if (dst.append(_buffer, _total_length) != Append_file::Append_result::OK) error("Write error for ", path); clear(); diff --git a/repos/os/include/os/vfs.h b/repos/os/include/os/vfs.h index 0fe34ee528..59dceef48f 100644 --- a/repos/os/include/os/vfs.h +++ b/repos/os/include/os/vfs.h @@ -27,6 +27,8 @@ namespace Genode { struct File; class Readonly_file; class File_content; + class Writeable_file; + class Append_file; class New_file; class Watcher; template @@ -124,6 +126,8 @@ struct Genode::Directory : Noncopyable, Interface friend class Readonly_file; friend class Root_directory; friend class Watcher; + friend class Writeable_file; + friend class Append_file; friend class New_file; /* @@ -668,24 +672,21 @@ class Genode::File_content /** - * Utility for writing data to a file via the Genode VFS library + * Base class of `New_file` and `Append_file` providing open for write, sync, + * and append functionality. */ -class Genode::New_file : Noncopyable +class Genode::Writeable_file : Noncopyable { public: struct Create_failed : Exception { }; - private: + enum class Append_result { OK, WRITE_ERROR }; - Entrypoint &_ep; - Allocator &_alloc; - Vfs::File_system &_fs; - Vfs::Vfs_handle &_handle; + protected: - Vfs::Vfs_handle &_init_handle(Directory &dir, - Directory::Path const &rel_path, - bool append) + static Vfs::Vfs_handle &_init_handle(Directory &dir, + Directory::Path const &rel_path) { /* create compound directory */ { @@ -703,43 +704,24 @@ class Genode::New_file : Noncopyable Vfs::Vfs_handle *handle_ptr = nullptr; Vfs::Directory_service::Open_result const res = - _fs.open(path.string(), mode, &handle_ptr, _alloc); + dir._fs.open(path.string(), mode, &handle_ptr, dir._alloc); if (res != Vfs::Directory_service::OPEN_OK || (handle_ptr == nullptr)) { - error("failed to create file '", path, "', res=", (int)res); + error("failed to create/open file '", path, "' for writing, res=", (int)res); throw Create_failed(); } - Vfs::Directory_service::Stat stat { }; - if (!append) - handle_ptr->fs().ftruncate(handle_ptr, 0); - else if (handle_ptr->ds().stat(path.string(), stat) == Vfs::Directory_service::STAT_OK) - handle_ptr->seek(stat.size); - return *handle_ptr; } - public: - - /** - * Constructor - * - * \throw Create_failed - */ - New_file(Directory &dir, Directory::Path const &path, bool append = false) - : - _ep(dir._ep), _alloc(dir._alloc), _fs(dir._fs), - _handle(_init_handle(dir, path, append)) - { } - - ~New_file() + static void _sync(Vfs::Vfs_handle &handle, Entrypoint &ep) { - while (_handle.fs().queue_sync(&_handle) == false) - _ep.wait_and_dispatch_one_io_signal(); + while (handle.fs().queue_sync(&handle) == false) + ep.wait_and_dispatch_one_io_signal(); for (bool sync_done = false; !sync_done; ) { - switch (_handle.fs().complete_sync(&_handle)) { + switch (handle.fs().complete_sync(&handle)) { case Vfs::File_io_service::SYNC_QUEUED: break; @@ -755,14 +737,12 @@ class Genode::New_file : Noncopyable } if (!sync_done) - _ep.wait_and_dispatch_one_io_signal(); + ep.wait_and_dispatch_one_io_signal(); } - _handle.ds().close(&_handle); } - enum class Append_result { OK, WRITE_ERROR }; - - Append_result append(char const *src, size_t size) + static Append_result _append(Vfs::Vfs_handle &handle, Entrypoint &ep, + char const *src, size_t size) { bool write_error = false; @@ -777,7 +757,7 @@ class Genode::New_file : Noncopyable using Write_result = Vfs::File_io_service::Write_result; - switch (_handle.fs().write(&_handle, src, remaining_bytes, + switch (handle.fs().write(&handle, src, remaining_bytes, out_count)) { case Write_result::WRITE_ERR_AGAIN: @@ -795,7 +775,7 @@ class Genode::New_file : Noncopyable out_count = min((Vfs::file_size)remaining_bytes, out_count); remaining_bytes -= (size_t)out_count; src += out_count; - _handle.advance_seek(out_count); + handle.advance_seek(out_count); break; }; } @@ -803,7 +783,7 @@ class Genode::New_file : Noncopyable stalled = true; } if (stalled) - _ep.wait_and_dispatch_one_io_signal(); + ep.wait_and_dispatch_one_io_signal(); } return write_error ? Append_result::WRITE_ERROR : Append_result::OK; @@ -811,6 +791,81 @@ class Genode::New_file : Noncopyable }; +/** + * Utility for appending data to an existing file via the Genode VFS library + */ +class Genode::Append_file : public Writeable_file +{ + private: + + Entrypoint &_ep; + Vfs::Vfs_handle &_handle; + + public: + + /** + * Constructor + * + * \throw Create_failed + */ + Append_file(Directory &dir, Directory::Path const &path) + : + _ep(dir._ep), + _handle(_init_handle(dir, path)) + { + Vfs::Directory_service::Stat stat { }; + if (_handle.ds().stat(path.string(), stat) == Vfs::Directory_service::STAT_OK) + _handle.seek(stat.size); + } + + ~Append_file() + { + _sync(_handle, _ep); + _handle.ds().close(&_handle); + } + + Append_result append(char const *src, size_t size) { + return _append(_handle, _ep, src, size); } +}; + + +/** + * Utility for writing data to a new file via the Genode VFS library + */ +class Genode::New_file : public Writeable_file +{ + private: + + Entrypoint &_ep; + Vfs::Vfs_handle &_handle; + + public: + + using Writeable_file::Append_result; + using Writeable_file::Create_failed; + + /** + * Constructor + * + * \throw Create_failed + */ + New_file(Directory &dir, Directory::Path const &path) + : + _ep(dir._ep), + _handle(_init_handle(dir, path)) + { _handle.fs().ftruncate(&_handle, 0); } + + ~New_file() + { + _sync(_handle, _ep); + _handle.ds().close(&_handle); + } + + Append_result append(char const *src, size_t size) { + return _append(_handle, _ep, src, size); } +}; + + class Genode::Watcher { private: