From 2313460b3e62e724f9135f18efa1c5b381e67bdd Mon Sep 17 00:00:00 2001 From: Tim Schumacher Date: Sat, 14 Jan 2023 13:07:30 +0100 Subject: pro: Use `Core::Stream` for writing contents to the output We also have to do a little dance with file descriptor numbers, since we can't just `freopen` a `FILE` struct anymore to redirect to the correct file. --- Userland/Utilities/pro.cpp | 80 ++++++++++++++++++++++++++-------------------- 1 file changed, 45 insertions(+), 35 deletions(-) (limited to 'Userland/Utilities') diff --git a/Userland/Utilities/pro.cpp b/Userland/Utilities/pro.cpp index 7ab62ff5c1..8019570204 100644 --- a/Userland/Utilities/pro.cpp +++ b/Userland/Utilities/pro.cpp @@ -102,52 +102,47 @@ private: bool m_might_be_wrong { false }; }; +/// Wraps a stream to silently ignore writes when the condition isn't true. template -class ConditionalOutputFileStream final : public OutputFileStream { +class ConditionalOutputStream final : public Core::Stream::Stream { public: - template - ConditionalOutputFileStream(ConditionT&& condition, Args... args) - : OutputFileStream(args...) + ConditionalOutputStream(ConditionT&& condition, Core::Stream::Handle stream) + : m_stream(move(stream)) , m_condition(condition) { } - ~ConditionalOutputFileStream() + virtual ErrorOr read(Bytes) override { - if (!m_condition()) - return; - - if (!m_buffer.is_empty()) { - OutputFileStream::write(m_buffer); - m_buffer.clear(); - } + return Error::from_errno(EBADF); } -private: - size_t write(ReadonlyBytes bytes) override + virtual ErrorOr write(ReadonlyBytes bytes) override { - if (!m_condition()) { - write_to_buffer:; - // FIXME: Propagate errors. - if (m_buffer.try_append(bytes.data(), bytes.size()).is_error()) - return 0; + // Pretend that we wrote the whole buffer if the condition is untrue. + if (!m_condition()) return bytes.size(); - } - if (!m_buffer.is_empty()) { - auto size = OutputFileStream::write(m_buffer); - // FIXME: Propagate errors. - m_buffer = MUST(m_buffer.slice(size, m_buffer.size() - size)); - } + return m_stream->write(bytes); + } - if (!m_buffer.is_empty()) - goto write_to_buffer; + virtual bool is_eof() const override + { + return true; + } - return OutputFileStream::write(bytes); + virtual bool is_open() const override + { + return m_stream->is_open(); } + virtual void close() override + { + } + +private: + Core::Stream::Handle m_stream; ConditionT m_condition; - ByteBuffer m_buffer; }; ErrorOr serenity_main(Main::Arguments arguments) @@ -210,6 +205,10 @@ ErrorOr serenity_main(Main::Arguments arguments) args_parser.add_positional_argument(url_str, "URL to download from", "url"); args_parser.parse(arguments); + // If writing to a file was requested, we'll open a new file descriptor with the same number later. + // Until then, we just clone the stdout file descriptor, because we shouldn't be reopening the actual stdout. + int const output_fd = TRY(Core::System::dup(STDOUT_FILENO)); + if (!method_override.is_empty()) { method = method_override; } else if (data) { @@ -243,7 +242,7 @@ ErrorOr serenity_main(Main::Arguments arguments) RefPtr request; auto protocol_client = TRY(Protocol::RequestClient::try_create()); - auto output_stream = ConditionalOutputFileStream { [&] { return should_save_stream_data; }, stdout }; + auto output_stream = ConditionalOutputStream { [&] { return should_save_stream_data; }, TRY(Core::Stream::File::adopt_fd(output_fd, Core::Stream::OpenMode::Write)) }; // https://httpwg.org/specs/rfc9110.html#authentication auto const has_credentials = !credentials.is_empty(); @@ -343,8 +342,21 @@ ErrorOr serenity_main(Main::Arguments arguments) } while (Core::File::exists(output_name)); } - if (freopen(output_name.characters(), "w", stdout) == nullptr) { - perror("freopen"); + int target_file_fd = open(output_name.characters(), O_WRONLY | O_CREAT | O_TRUNC, 0644); + if (target_file_fd < 0) { + perror("target file open"); + loop.quit(1); + return; + } + + if (dup2(target_file_fd, output_fd) < 0) { + perror("target file dup2"); + loop.quit(1); + return; + } + + if (close(target_file_fd) < 0) { + perror("target file close"); loop.quit(1); return; } @@ -394,7 +406,5 @@ ErrorOr serenity_main(Main::Arguments arguments) dbgln("started request with id {}", request->id()); - auto rc = loop.exec(); - fflush(stdout); - return rc; + return loop.exec(); } -- cgit v1.2.3