diff --git a/cli/cli.cc b/cli/cli.cc index 2640ee2e4..621d1abf9 100644 --- a/cli/cli.cc +++ b/cli/cli.cc @@ -245,12 +245,14 @@ int tr_main(int argc, char* argv[]) if (!tr_sys_path_exists(sz_download_dir)) { - tr_error* error = nullptr; - - if (!tr_sys_dir_create(sz_download_dir, TR_SYS_DIR_CREATE_PARENTS, 0700, &error)) + if (auto error = tr_error{}; !tr_sys_dir_create(sz_download_dir, TR_SYS_DIR_CREATE_PARENTS, 0700, &error) && error) { - fprintf(stderr, "Unable to create download directory \"%s\": %s\n", sz_download_dir.c_str(), error->message); - tr_error_free(error); + auto const errmsg = fmt::format( + "Couldn't create '{path}': {error} ({error_code})", + fmt::arg("path", sz_download_dir), + fmt::arg("error", error.message()), + fmt::arg("error_code", error.code())); + fmt::print(stderr, "{:s}\n", errmsg); return EXIT_FAILURE; } } diff --git a/daemon/daemon-posix.cc b/daemon/daemon-posix.cc index 16a2e15e3..0f6b236b7 100644 --- a/daemon/daemon-posix.cc +++ b/daemon/daemon-posix.cc @@ -24,9 +24,9 @@ #include "daemon.h" -static void set_system_error(tr_error** error, int code, std::string_view message) +static void set_system_error(tr_error& error, int code, std::string_view message) { - tr_error_set(error, code, fmt::format(FMT_STRING("{:s}: {:s} ({:d}"), message, tr_strerror(code), code)); + error.set(code, fmt::format(FMT_STRING("{:s}: {:s} ({:d}"), message, tr_strerror(code), code)); } #ifdef HAVE_SYS_SIGNALFD_H @@ -131,7 +131,7 @@ void tr_daemon::cleanup_signals(struct event* sig_ev) const #endif /* HAVE_SYS_SIGNALFD_H */ } -bool tr_daemon::spawn(bool foreground, int* exit_code, tr_error** error) +bool tr_daemon::spawn(bool foreground, int* exit_code, tr_error& error) { *exit_code = 1; diff --git a/daemon/daemon-win32.cc b/daemon/daemon-win32.cc index 15207cbe2..93b326410 100644 --- a/daemon/daemon-win32.cc +++ b/daemon/daemon-win32.cc @@ -34,10 +34,10 @@ static DWORD current_state = SERVICE_STOPPED; static HANDLE service_thread = nullptr; static HANDLE service_stop_thread = nullptr; -static void set_system_error(tr_error** error, DWORD code, char const* message) +static void set_system_error(tr_error& error, DWORD code, char const* message) { auto const system_message = tr_win32_format_message(code); - tr_error_set(error, code, fmt::format(FMT_STRING("{:s} ({:#08x}): {:s})"), message, code, system_message)); + error.set(code, fmt::format(FMT_STRING("{:s} ({:#08x}): {:s})"), message, code, system_message)); } static void do_log_system_error(char const* file, int line, tr_log_level level, DWORD code, char const* message) @@ -209,7 +209,7 @@ void tr_daemon::cleanup_signals([[maybe_unused]] struct event* sig_ev) const { } -bool tr_daemon::spawn(bool foreground, int* exit_code, tr_error** error) +bool tr_daemon::spawn(bool foreground, int* exit_code, tr_error& error) { daemon = this; diff --git a/daemon/daemon.cc b/daemon/daemon.cc index 14a6136c8..e3a71d9ae 100644 --- a/daemon/daemon.cc +++ b/daemon/daemon.cc @@ -165,7 +165,7 @@ static auto constexpr Options = std::array{ bool tr_daemon::reopen_log_file(char const* filename) { - tr_error* error = nullptr; + auto error = tr_error{}; tr_sys_file_t const old_log_file = logfile_; tr_sys_file_t const new_log_file = tr_sys_file_open( filename, @@ -175,8 +175,12 @@ bool tr_daemon::reopen_log_file(char const* filename) if (new_log_file == TR_BAD_SYS_FILE) { - fprintf(stderr, "Couldn't (re)open log file \"%s\": %s\n", filename, error->message); - tr_error_free(error); + auto const errmsg = fmt::format( + "Couldn't open '{path}': {error} ({error_code})", + fmt::arg("path", filename), + fmt::arg("error", error.message()), + fmt::arg("error_code", error.code())); + fmt::print(stderr, "{:s}\n", errmsg); return false; } @@ -236,15 +240,14 @@ static auto onFileAdded(tr_session const* session, std::string_view dirname, std else // is_magnet { auto content = std::vector{}; - tr_error* error = nullptr; + auto error = tr_error{}; if (!tr_file_read(filename, content, &error)) { tr_logAddWarn(fmt::format( _("Couldn't read '{path}': {error} ({error_code})"), fmt::arg("path", basename), - fmt::arg("error", error->message), - fmt::arg("error_code", error->code))); - tr_error_free(error); + fmt::arg("error", error.message()), + fmt::arg("error_code", error.code()))); retry = true; } else @@ -275,18 +278,15 @@ static auto onFileAdded(tr_session const* session, std::string_view dirname, std if (test && trash) { - tr_error* error = nullptr; - tr_logAddInfo(fmt::format(_("Removing torrent file '{path}'"), fmt::arg("path", basename))); - if (!tr_sys_path_remove(filename, &error)) + if (auto error = tr_error{}; !tr_sys_path_remove(filename, &error)) { tr_logAddError(fmt::format( _("Couldn't remove '{path}': {error} ({error_code})"), fmt::arg("path", basename), - fmt::arg("error", error->message), - fmt::arg("error_code", error->code))); - tr_error_free(error); + fmt::arg("error", error.message()), + fmt::arg("error_code", error.code()))); } } else @@ -736,7 +736,7 @@ int tr_daemon::start([[maybe_unused]] bool foreground) auto const sz_pid_filename = std::string{ sv }; if (!std::empty(sz_pid_filename)) { - tr_error* error = nullptr; + auto error = tr_error{}; tr_sys_file_t fp = tr_sys_file_open( sz_pid_filename.c_str(), TR_SYS_FILE_WRITE | TR_SYS_FILE_CREATE | TR_SYS_FILE_TRUNCATE, @@ -756,9 +756,8 @@ int tr_daemon::start([[maybe_unused]] bool foreground) tr_logAddError(fmt::format( _("Couldn't save '{path}': {error} ({error_code})"), fmt::arg("path", sz_pid_filename), - fmt::arg("error", error->message), - fmt::arg("error_code", error->code))); - tr_error_free(error); + fmt::arg("error", error.message()), + fmt::arg("error_code", error.code()))); } } @@ -939,11 +938,10 @@ EXIT_EARLY: return false; } -void tr_daemon::handle_error(tr_error* error) const +void tr_daemon::handle_error(tr_error const& error) const { - auto const errmsg = fmt::format(FMT_STRING("Couldn't daemonize: {:s} ({:d})"), error->message, error->code); + auto const errmsg = fmt::format("Couldn't daemonize: {:s} ({:d})", error.message(), error.code()); printMessage(logfile_, TR_LOG_ERROR, MyName, errmsg, __FILE__, __LINE__); - tr_error_free(error); } int tr_main(int argc, char* argv[]) @@ -952,16 +950,15 @@ int tr_main(int argc, char* argv[]) tr_locale_set_global(""); - int ret; - tr_daemon daemon; - bool foreground; - tr_error* error = nullptr; - + auto foreground = bool{}; + auto ret = int{}; + auto daemon = tr_daemon{}; if (!daemon.init(argc, argv, &foreground, &ret)) { return ret; } - if (!daemon.spawn(foreground, &ret, &error)) + + if (auto error = tr_error{}; !daemon.spawn(foreground, &ret, error)) { daemon.handle_error(error); } diff --git a/daemon/daemon.h b/daemon/daemon.h index b61c0e58f..d0b751c07 100644 --- a/daemon/daemon.h +++ b/daemon/daemon.h @@ -33,9 +33,9 @@ public: #endif /* signalfd API */ } - bool spawn(bool foreground, int* exit_code, tr_error** error); + bool spawn(bool foreground, int* exit_code, tr_error& error); bool init(int argc, char const* const argv[], bool* foreground, int* ret); - void handle_error(tr_error*) const; + void handle_error(tr_error const&) const; int start(bool foreground); void periodic_update(); void reconfigure(); diff --git a/gtk/MakeDialog.cc b/gtk/MakeDialog.cc index 16bc1d7da..6ce542187 100644 --- a/gtk/MakeDialog.cc +++ b/gtk/MakeDialog.cc @@ -67,7 +67,7 @@ public: BaseObjectType* cast_item, Glib::RefPtr const& builder, tr_metainfo_builder& metainfo_builder, - std::future future, + std::future future, std::string_view target, Glib::RefPtr const& core); ~MakeProgressDialog() override; @@ -77,7 +77,7 @@ public: static std::unique_ptr create( std::string_view target, tr_metainfo_builder& metainfo_builder, - std::future future, + std::future future, Glib::RefPtr const& core); [[nodiscard]] bool success() const @@ -93,7 +93,7 @@ private: private: tr_metainfo_builder& builder_; - std::future future_; + std::future future_; std::string const target_; Glib::RefPtr const core_; bool success_ = false; @@ -190,14 +190,14 @@ bool MakeProgressDialog::onProgressDialogRefresh() } else { - tr_error* error = future_.get(); + auto error = future_.get(); - if (error == nullptr) + if (!error) { builder_.save(target_, &error); } - if (error == nullptr) + if (!error) { str = fmt::format(_("Created '{path}'"), fmt::arg("path", base)); success = true; @@ -207,9 +207,8 @@ bool MakeProgressDialog::onProgressDialogRefresh() str = fmt::format( _("Couldn't create '{path}': {error} ({error_code})"), fmt::arg("path", base), - fmt::arg("error", error->message), - fmt::arg("error_code", error->code)); - tr_error_free(error); + fmt::arg("error", error.message()), + fmt::arg("error_code", error.code())); } } @@ -280,7 +279,7 @@ MakeProgressDialog::MakeProgressDialog( BaseObjectType* cast_item, Glib::RefPtr const& builder, tr_metainfo_builder& metainfo_builder, - std::future future, + std::future future, std::string_view target, Glib::RefPtr const& core) : Gtk::Dialog(cast_item) @@ -302,7 +301,7 @@ MakeProgressDialog::MakeProgressDialog( std::unique_ptr MakeProgressDialog::create( std::string_view target, tr_metainfo_builder& metainfo_builder, - std::future future, + std::future future, Glib::RefPtr const& core) { auto const builder = Gtk::Builder::create_from_resource(gtr_get_full_resource_path("MakeProgressDialog.ui")); diff --git a/gtk/Session.cc b/gtk/Session.cc index 028498832..1d0bc4391 100644 --- a/gtk/Session.cc +++ b/gtk/Session.cc @@ -911,7 +911,7 @@ void Session::remove_torrent(tr_torrent_id_t id, bool delete_files) tr_torrentRemove( &torrent->get_underlying(), delete_files, - [](char const* filename, void* /*user_data*/, tr_error** error) + [](char const* filename, void* /*user_data*/, tr_error* error) { return gtr_file_trash_or_remove(filename, error); }, nullptr); } diff --git a/gtk/Utils.cc b/gtk/Utils.cc index 61c18aad5..44cd27cfe 100644 --- a/gtk/Utils.cc +++ b/gtk/Utils.cc @@ -524,14 +524,18 @@ void setup_item_view_button_event_handling( #endif -bool gtr_file_trash_or_remove(std::string const& filename, tr_error** error) +bool gtr_file_trash_or_remove(std::string const& filename, tr_error* error) { - bool trashed = false; - bool result = true; - g_return_val_if_fail(!filename.empty(), false); + auto local_error = tr_error{}; + if (error == nullptr) + { + error = &local_error; + } + auto const file = Gio::File::create_for_path(filename); + bool trashed = false; if (gtr_pref_flag_get(TR_KEY_trash_can_enabled)) { @@ -541,15 +545,16 @@ bool gtr_file_trash_or_remove(std::string const& filename, tr_error** error) } catch (Glib::Error const& e) { + error->set(e.code(), TR_GLIB_EXCEPTION_WHAT(e)); gtr_message(fmt::format( _("Couldn't move '{path}' to trash: {error} ({error_code})"), fmt::arg("path", filename), - fmt::arg("error", TR_GLIB_EXCEPTION_WHAT(e)), - fmt::arg("error_code", e.code()))); - tr_error_set(error, e.code(), TR_GLIB_EXCEPTION_WHAT(e)); + fmt::arg("error", error->message()), + fmt::arg("error_code", error->code()))); } } + bool result = true; if (!trashed) { try @@ -558,13 +563,12 @@ bool gtr_file_trash_or_remove(std::string const& filename, tr_error** error) } catch (Glib::Error const& e) { + error->set(e.code(), TR_GLIB_EXCEPTION_WHAT(e)); gtr_message(fmt::format( _("Couldn't remove '{path}': {error} ({error_code})"), fmt::arg("path", filename), - fmt::arg("error", TR_GLIB_EXCEPTION_WHAT(e)), - fmt::arg("error_code", e.code()))); - tr_error_clear(error); - tr_error_set(error, e.code(), TR_GLIB_EXCEPTION_WHAT(e)); + fmt::arg("error", error->message()), + fmt::arg("error_code", error->code()))); result = false; } } diff --git a/gtk/Utils.h b/gtk/Utils.h index 548c5164c..e6749dd45 100644 --- a/gtk/Utils.h +++ b/gtk/Utils.h @@ -185,7 +185,7 @@ void setup_item_view_button_event_handling( #endif /* move a file to the trashcan if GIO is available; otherwise, delete it */ -bool gtr_file_trash_or_remove(std::string const& filename, tr_error** error); +bool gtr_file_trash_or_remove(std::string const& filename, tr_error* error = nullptr); void gtr_paste_clipboard_url_into_entry(Gtk::Entry& entry); diff --git a/libtransmission/announce-list.cc b/libtransmission/announce-list.cc index 829125bff..10e76d513 100644 --- a/libtransmission/announce-list.cc +++ b/libtransmission/announce-list.cc @@ -264,14 +264,19 @@ void tr_announce_list::add_to_map(tr_variant::Map& setme) const } } -bool tr_announce_list::save(std::string_view torrent_file, tr_error** error) const +bool tr_announce_list::save(std::string_view torrent_file, tr_error* error) const { // load the torrent file auto serde = tr_variant_serde::benc(); auto ometainfo = serde.parse_file(torrent_file); if (!ometainfo) { - tr_error_propagate(error, &serde.error_); + if (error != nullptr) + { + *error = std::move(serde.error_); + serde.error_ = {}; + } + return false; } auto& metainfo = *ometainfo; diff --git a/libtransmission/announce-list.h b/libtransmission/announce-list.h index 32fe33b36..4ba2a7eda 100644 --- a/libtransmission/announce-list.h +++ b/libtransmission/announce-list.h @@ -127,7 +127,7 @@ public: bool parse(std::string_view text); [[nodiscard]] std::string to_string() const; - bool save(std::string_view torrent_file, tr_error** error = nullptr) const; + bool save(std::string_view torrent_file, tr_error* error = nullptr) const; [[nodiscard]] static std::optional announce_to_scrape(std::string_view announce); diff --git a/libtransmission/announcer-http.cc b/libtransmission/announcer-http.cc index 1d00a4c38..050c5c997 100644 --- a/libtransmission/announcer-http.cc +++ b/libtransmission/announcer-http.cc @@ -440,17 +440,16 @@ void tr_announcerParseHttpAnnounceResponse(tr_announce_response& response, std:: auto stack = transmission::benc::ParserStack{}; auto handler = AnnounceHandler{ response, log_name }; - tr_error* error = nullptr; + auto error = tr_error{}; transmission::benc::parse(benc, stack, handler, nullptr, &error); - if (error != nullptr) + if (error) { tr_logAddWarn( fmt::format( _("Couldn't parse announce response: {error} ({error_code})"), - fmt::arg("error", error->message), - fmt::arg("error_code", error->code)), + fmt::arg("error", error.message()), + fmt::arg("error_code", error.code())), log_name); - tr_error_clear(&error); } } @@ -648,16 +647,15 @@ void tr_announcerParseHttpScrapeResponse(tr_scrape_response& response, std::stri auto stack = transmission::benc::ParserStack{}; auto handler = ScrapeHandler{ response, log_name }; - tr_error* error = nullptr; + auto error = tr_error{}; transmission::benc::parse(benc, stack, handler, nullptr, &error); - if (error != nullptr) + if (error) { tr_logAddWarn( fmt::format( _("Couldn't parse scrape response: {error} ({error_code})"), - fmt::arg("error", error->message), - fmt::arg("error_code", error->code)), + fmt::arg("error", error.message()), + fmt::arg("error_code", error.code())), log_name); - tr_error_clear(&error); } } diff --git a/libtransmission/benc.h b/libtransmission/benc.h index 39749c087..530fc8ba6 100644 --- a/libtransmission/benc.h +++ b/libtransmission/benc.h @@ -33,7 +33,7 @@ struct Handler class Context { public: - constexpr Context(char const* stream_begin_in, tr_error** error_in) + constexpr Context(char const* stream_begin_in, tr_error& error_in) : error{ error_in } , stream_begin_{ stream_begin_in } { @@ -55,7 +55,7 @@ struct Handler token_end_ = token_begin_ + len; } - tr_error** error = nullptr; + tr_error& error; private: char const* token_begin_ = nullptr; @@ -219,17 +219,17 @@ struct ParserStack return stack[depth].parent_type; } - std::optional pop(tr_error** error) + std::optional pop(tr_error& error) { if (depth == 0) { - tr_error_set(error, EILSEQ, "Cannot pop empty stack"); + error.set(EILSEQ, "Cannot pop empty stack"); return {}; } if (stack[depth].parent_type == ParentType::Dict && ((stack[depth].n_children_walked % 2) != 0)) { - tr_error_set(error, EILSEQ, "Premature end-of-dict found. Malformed benc?"); + error.set(EILSEQ, "Premature end-of-dict found. Malformed benc?"); return {}; } @@ -238,11 +238,11 @@ struct ParserStack return ret; } - bool push(ParentType parent_type, tr_error** error) + bool push(ParentType parent_type, tr_error& error) { if (depth + 1 >= std::size(stack)) { - tr_error_set(error, E2BIG, "Max stack depth reached; unable to continue parsing"); + error.set(E2BIG, "Max stack depth reached; unable to continue parsing"); return false; } @@ -258,11 +258,18 @@ bool parse( ParserStack& stack, Handler& handler, char const** setme_end = nullptr, - tr_error** error = nullptr) + tr_error* error = nullptr) { + // ensure `error` isn't a nullptr + auto local_error = tr_error{}; + if (error == nullptr) + { + error = &local_error; + } + stack.clear(); auto const* const stream_begin = std::data(benc); - auto context = Handler::Context(stream_begin, error); + auto context = Handler::Context{ stream_begin, *error }; int err = 0; for (;;) @@ -283,8 +290,8 @@ bool parse( case 'i': // int if (auto const value = impl::ParseInt(&benc); !value) { - tr_error_set(error, err, "Malformed benc? Unable to parse integer"); err = EILSEQ; + error->set(err, "Malformed benc? Unable to parse integer"); } else { @@ -304,8 +311,8 @@ bool parse( case 'l': // list case 'd': // dict { - bool ok = benc.front() == 'l' ? stack.push(ParserStack::ParentType::Array, error) : - stack.push(ParserStack::ParentType::Dict, error); + bool ok = benc.front() == 'l' ? stack.push(ParserStack::ParentType::Array, *error) : + stack.push(ParserStack::ParentType::Dict, *error); if (!ok) { err = EILSEQ; @@ -326,7 +333,7 @@ bool parse( case 'e': // end of list or dict benc.remove_prefix(1); - if (auto const parent_type = stack.pop(error); !parent_type) + if (auto const parent_type = stack.pop(*error); !parent_type) { err = EILSEQ; } @@ -357,7 +364,7 @@ bool parse( if (auto const sv = impl::ParseString(&benc); !sv) { err = EILSEQ; - tr_error_set(error, err, "Malformed benc? Unable to parse string"); + error->set(err, "Malformed benc? Unable to parse string"); } else { @@ -398,7 +405,7 @@ bool parse( if (stack.depth != 0) { err = EILSEQ; - tr_error_set(error, err, "premature end-of-data reached"); + error->set(err, "premature end-of-data reached"); errno = err; return false; } @@ -406,7 +413,7 @@ bool parse( if (stack.stack[0].n_children_walked == 0) { err = EILSEQ; - tr_error_set(error, err, "no bencoded data to parse"); + error->set(err, "no bencoded data to parse"); errno = err; return false; } diff --git a/libtransmission/blocklist.cc b/libtransmission/blocklist.cc index 1192d29e7..0dff6692c 100644 --- a/libtransmission/blocklist.cc +++ b/libtransmission/blocklist.cc @@ -324,16 +324,15 @@ void Blocklists::Blocklist::ensureLoaded() const } // get the file's size - tr_error* error = nullptr; + auto error = tr_error{}; auto const file_info = tr_sys_path_get_info(bin_file_, 0, &error); - if (error != nullptr) + if (error) { tr_logAddWarn(fmt::format( _("Couldn't read '{path}': {error} ({error_code})"), fmt::arg("path", bin_file_), - fmt::arg("error", error->message), - fmt::arg("error_code", error->code))); - tr_error_clear(&error); + fmt::arg("error", error.message()), + fmt::arg("error_code", error.code()))); } if (!file_info) { @@ -460,16 +459,15 @@ std::optional Blocklists::Blocklist::saveNew( // make a copy of `external_file` for our own safekeeping auto const src_file = std::string{ std::data(bin_file), std::size(bin_file) - std::size(BinFileSuffix) }; tr_sys_path_remove(src_file.c_str()); - tr_error* error = nullptr; + auto error = tr_error{}; auto const copied = tr_sys_path_copy(tr_pathbuf{ external_file }, src_file.c_str(), &error); - if (error != nullptr) + if (error) { tr_logAddWarn(fmt::format( _("Couldn't save '{path}': {error} ({error_code})"), fmt::arg("path", src_file), - fmt::arg("error", error->message), - fmt::arg("error_code", error->code))); - tr_error_clear(&error); + fmt::arg("error", error.message()), + fmt::arg("error_code", error.code()))); } if (!copied) { diff --git a/libtransmission/error.cc b/libtransmission/error.cc index 3dcb1d7ef..110bf6c74 100644 --- a/libtransmission/error.cc +++ b/libtransmission/error.cc @@ -3,95 +3,12 @@ // or any future license endorsed by Mnemosyne LLC. // License text can be found in the licenses/ folder. -#include -#include - -#include - #include "libtransmission/error.h" -#include "libtransmission/tr-assert.h" #include "libtransmission/utils.h" -namespace +void tr_error::set_from_errno(int errnum) { -[[nodiscard]] char* tr_strvdup(std::string_view in) -{ - auto const n = std::size(in); - auto* const ret = new char[n + 1]; - std::copy(std::begin(in), std::end(in), ret); - ret[n] = '\0'; - return ret; -} -} // namespace - -void tr_error_free(tr_error* error) -{ - if (error == nullptr) - { - return; - } - - delete[] error->message; - delete error; -} - -void tr_error_set(tr_error** error, int code, std::string_view message) -{ - if (error == nullptr) - { - return; - } - - TR_ASSERT(*error == nullptr); - *error = new tr_error{ code, tr_strvdup(message) }; -} - -void tr_error_set_from_errno(tr_error** error, int errnum) -{ - tr_error_set(error, errnum, tr_strerror(errnum)); -} - -void tr_error_propagate(tr_error** new_error, tr_error** old_error) -{ - TR_ASSERT(old_error != nullptr); - TR_ASSERT(*old_error != nullptr); - - if (new_error != nullptr) - { - TR_ASSERT(*new_error == nullptr); - - *new_error = *old_error; - *old_error = nullptr; - } - else - { - tr_error_clear(old_error); - } -} - -void tr_error_clear(tr_error** error) -{ - if (error == nullptr) - { - return; - } - - tr_error_free(*error); - - *error = nullptr; -} - -void tr_error_prefix(tr_error** error, char const* prefix) -{ - TR_ASSERT(prefix != nullptr); - - if (error == nullptr || *error == nullptr) - { - return; - } - - auto* err = *error; - auto* const new_message = tr_strvdup(fmt::format(FMT_STRING("{:s}{:s}"), prefix, err->message)); - delete[] err->message; - err->message = new_message; + code_ = errnum; + + message_ = errnum != 0 ? tr_strerror(errnum) : ""; } diff --git a/libtransmission/error.h b/libtransmission/error.h index 624f9a8bb..e9a1e8386 100644 --- a/libtransmission/error.h +++ b/libtransmission/error.h @@ -5,77 +5,61 @@ #pragma once +#include #include -/** - * @addtogroup error Error reporting - * @{ - */ +#include "libtransmission/tr-macros.h" /** @brief Structure holding error information. */ struct tr_error { - /** @brief Error code, platform-specific */ - int code; +public: + tr_error() = default; + + tr_error(int code, std::string message) + : message_{ std::move(message) } + , code_{ code } + { + } + + [[nodiscard]] constexpr auto code() const noexcept + { + return code_; + } + + [[nodiscard]] TR_CONSTEXPR20 auto message() const noexcept + { + return std::string_view{ message_ }; + } + + [[nodiscard]] constexpr auto has_value() const noexcept + { + return code_ != 0; + } + + [[nodiscard]] constexpr operator bool() const noexcept + { + return has_value(); + } + + void set(int code, std::string_view message) + { + code_ = code; + message_.assign(message); + } + + void prefix_message(std::string_view prefix) + { + message_.insert(std::begin(message_), std::begin(prefix), std::end(prefix)); + } + + // convenience utility for `set(errno, tr_strerror(errno))` + void set_from_errno(int errnum); + +private: /** @brief Error message */ - char* message; + std::string message_; + + /** @brief Error code, platform-specific */ + int code_ = 0; }; - -/** - * @brief Free memory used by error object. - * - * @param[in] error Error object to be freed. - */ -void tr_error_free(tr_error* error); - -/** - * @brief Create and set new error object using literal error message. - * - * If passed pointer to error object is `nullptr`, do nothing. - * - * @param[in,out] error Pointer to error object to be set. - * @param[in] code Error code (platform-specific). - * @param[in] message Error message. - */ -void tr_error_set(tr_error** error, int code, std::string_view message); - -/** - * @brief shorthand for `tr_error_set(error, errno, tr_strerror(errno))` - */ -void tr_error_set_from_errno(tr_error** error, int errnum); - -/** - * @brief Propagate existing error object upwards. - * - * If passed pointer to new error object is not `nullptr`, copy old error object - * to new error object and free old error object. Otherwise, just free old error - * object. - * - * @param[in,out] new_error Pointer to error object to be set. - * @param[in,out] old_error Error object to be propagated. Cleared on return. - */ -void tr_error_propagate(tr_error** new_error, tr_error** old_error); - -/** - * @brief Clear error object. - * - * Free error object being pointed and set pointer to `nullptr`. If passed - * pointer is `nullptr`, do nothing. - * - * @param[in,out] error Pointer to error object to be cleared. - */ -void tr_error_clear(tr_error** error); - -/** - * @brief Prefix message of existing error object. - * - * If passed pointer to error object is not `nullptr`, prefix its message with - * `printf`-style formatted text. Otherwise, do nothing. - * - * @param[in,out] error Pointer to error object to be set. - * @param[in] prefix_format Prefix format string. - * @param[in] ... Format arguments. - */ -void tr_error_prefix(tr_error** error, char const* prefix); - -/** @} */ diff --git a/libtransmission/file-capacity.cc b/libtransmission/file-capacity.cc index d0399a89f..326b318c5 100644 --- a/libtransmission/file-capacity.cc +++ b/libtransmission/file-capacity.cc @@ -509,9 +509,15 @@ tr_sys_path_capacity tr_device_info_get_disk_space(struct tr_device_info const& } // namespace -std::optional tr_sys_path_get_capacity(std::string_view path, tr_error** error) +std::optional tr_sys_path_get_capacity(std::string_view path, tr_error* error) { - auto const info = tr_sys_path_get_info(path, 0, error); + auto local_error = tr_error{}; + if (error == nullptr) + { + error = &local_error; + } + + auto const info = tr_sys_path_get_info(path, 0, &local_error); if (!info) { return {}; @@ -519,16 +525,15 @@ std::optional tr_sys_path_get_capacity(std::string_view pa if (!info->isFolder()) { - tr_error_set_from_errno(error, ENOTDIR); + error->set_from_errno(ENOTDIR); return {}; } auto const device = tr_device_info_create(path); auto capacity = tr_device_info_get_disk_space(device); - if (capacity.free < 0 || capacity.total < 0) { - tr_error_set_from_errno(error, EINVAL); + error->set_from_errno(EINVAL); return {}; } diff --git a/libtransmission/file-posix.cc b/libtransmission/file-posix.cc index 19095e208..52f2bf5e0 100644 --- a/libtransmission/file-posix.cc +++ b/libtransmission/file-posix.cc @@ -97,14 +97,6 @@ using namespace std::literals; namespace { -void set_system_error_if_file_found(tr_error** error, int code) -{ - if (code != ENOENT) - { - tr_error_set_from_errno(error, code); - } -} - void set_file_for_single_pass(tr_sys_file_t handle) { /* Set hints about the lookahead buffer and caching. It's okay @@ -134,21 +126,21 @@ void set_file_for_single_pass(tr_sys_file_t handle) } } // namespace -bool tr_sys_path_exists(char const* path, tr_error** error) +bool tr_sys_path_exists(char const* path, tr_error* error) { TR_ASSERT(path != nullptr); bool const ret = access(path, F_OK) != -1; - if (!ret) + if (error != nullptr && !ret && errno != ENOENT) { - set_system_error_if_file_found(error, errno); + error->set_from_errno(errno); } return ret; } -std::optional tr_sys_path_get_info(std::string_view path, int flags, tr_error** error) +std::optional tr_sys_path_get_info(std::string_view path, int flags, tr_error* error) { struct stat sb = {}; @@ -166,7 +158,11 @@ std::optional tr_sys_path_get_info(std::string_view path, int if (!ok) { - tr_error_set_from_errno(error, errno); + if (error != nullptr) + { + error->set_from_errno(errno); + } + return {}; } @@ -196,7 +192,7 @@ bool tr_sys_path_is_relative(std::string_view path) return std::empty(path) || path.front() != '/'; } -bool tr_sys_path_is_same(char const* path1, char const* path2, tr_error** error) +bool tr_sys_path_is_same(char const* path1, char const* path2, tr_error* error) { TR_ASSERT(path1 != nullptr); TR_ASSERT(path2 != nullptr); @@ -209,15 +205,15 @@ bool tr_sys_path_is_same(char const* path1, char const* path2, tr_error** error) { ret = sb1.st_dev == sb2.st_dev && sb1.st_ino == sb2.st_ino; } - else + else if (error != nullptr && errno != ENOENT) { - set_system_error_if_file_found(error, errno); + error->set_from_errno(errno); } return ret; } -std::string tr_sys_path_resolve(std::string_view path, tr_error** error) +std::string tr_sys_path_resolve(std::string_view path, tr_error* error) { auto const szpath = tr_pathbuf{ path }; auto buf = std::array{}; @@ -227,11 +223,15 @@ std::string tr_sys_path_resolve(std::string_view path, tr_error** error) return ret; } - tr_error_set_from_errno(error, errno); + if (error != nullptr) + { + error->set_from_errno(errno); + } + return {}; } -std::string_view tr_sys_path_basename(std::string_view path, tr_error** /*error*/) +std::string_view tr_sys_path_basename(std::string_view path, tr_error* /*error*/) { // As per the basename() manpage: // If path [is] an empty string, then basename() return[s] the string "." @@ -305,16 +305,16 @@ std::string_view tr_sys_path_dirname(std::string_view path) return path.substr(0, end); } -bool tr_sys_path_rename(char const* src_path, char const* dst_path, tr_error** error) +bool tr_sys_path_rename(char const* src_path, char const* dst_path, tr_error* error) { TR_ASSERT(src_path != nullptr); TR_ASSERT(dst_path != nullptr); bool const ret = rename(src_path, dst_path) != -1; - if (!ret) + if (error != nullptr && !ret) { - tr_error_set_from_errno(error, errno); + error->set_from_errno(errno); } return ret; @@ -323,15 +323,21 @@ bool tr_sys_path_rename(char const* src_path, char const* dst_path, tr_error** e /* We try to do a fast (in-kernel) copy using a variety of non-portable system * calls. If the current implementation does not support in-kernel copying, we * use a user-space fallback instead. */ -bool tr_sys_path_copy(char const* src_path, char const* dst_path, tr_error** error) +bool tr_sys_path_copy(char const* src_path, char const* dst_path, tr_error* error) { TR_ASSERT(src_path != nullptr); TR_ASSERT(dst_path != nullptr); + auto local_error = tr_error{}; + if (error == nullptr) + { + error = &local_error; + } + #if defined(USE_COPYFILE) if (copyfile(src_path, dst_path, nullptr, COPYFILE_CLONE | COPYFILE_ALL) < 0) { - tr_error_set_from_errno(error, errno); + error->set_from_errno(errno); return false; } @@ -342,7 +348,7 @@ bool tr_sys_path_copy(char const* src_path, char const* dst_path, tr_error** err auto const info = tr_sys_path_get_info(src_path, 0, error); if (!info) { - tr_error_prefix(error, "Unable to get information on source file: "); + error->prefix_message("Unable to get information on source file: "); return false; } @@ -350,7 +356,7 @@ bool tr_sys_path_copy(char const* src_path, char const* dst_path, tr_error** err tr_sys_file_t const in = tr_sys_file_open(src_path, TR_SYS_FILE_READ | TR_SYS_FILE_SEQUENTIAL, 0, error); if (in == TR_BAD_SYS_FILE) { - tr_error_prefix(error, "Unable to open source file: "); + error->prefix_message("Unable to open source file: "); return false; } @@ -361,8 +367,8 @@ bool tr_sys_path_copy(char const* src_path, char const* dst_path, tr_error** err error); if (out == TR_BAD_SYS_FILE) { - tr_error_prefix(error, "Unable to open destination file: "); tr_sys_file_close(in); + error->prefix_message("Unable to open destination file: "); return false; } @@ -387,7 +393,7 @@ bool tr_sys_path_copy(char const* src_path, char const* dst_path, tr_error** err errno_cpy = errno; /* remember me for later */ if (errno != EXDEV) /* EXDEV is expected, don't log error */ { - tr_error_set_from_errno(error, errno); + error->set_from_errno(errno); } if (file_size > 0U) { @@ -423,7 +429,7 @@ bool tr_sys_path_copy(char const* src_path, char const* dst_path, tr_error** err { if (errno_cpy == 0) { - tr_error_set_from_errno(error, errno); + error->set_from_errno(errno); } } else @@ -440,7 +446,7 @@ bool tr_sys_path_copy(char const* src_path, char const* dst_path, tr_error** err /* use sendfile with EINVAL (invalid argument) for falling to user-space copy */ if (errno != EINVAL) /* EINVAL is expected on some 32-bit devices (of Synology), don't log error */ { - tr_error_set_from_errno(error, errno); + error->set_from_errno(errno); } if (file_size > 0U) { @@ -475,7 +481,7 @@ bool tr_sys_path_copy(char const* src_path, char const* dst_path, tr_error** err { if (errno_cpy == 0) { - tr_error_set_from_errno(error, errno); + error->set_from_errno(errno); } } else @@ -511,7 +517,7 @@ bool tr_sys_path_copy(char const* src_path, char const* dst_path, tr_error** err if (file_size != 0) { - tr_error_prefix(error, "Unable to read/write: "); + error->prefix_message("Unable to read/write: "); return false; } @@ -520,15 +526,15 @@ bool tr_sys_path_copy(char const* src_path, char const* dst_path, tr_error** err #endif /* USE_COPYFILE */ } -bool tr_sys_path_remove(char const* path, tr_error** error) +bool tr_sys_path_remove(char const* path, tr_error* error) { TR_ASSERT(path != nullptr); bool const ret = remove(path) != -1; - if (!ret) + if (error != nullptr && !ret) { - tr_error_set_from_errno(error, errno); + error->set_from_errno(errno); } return ret; @@ -539,7 +545,7 @@ char* tr_sys_path_native_separators(char* path) return path; } -tr_sys_file_t tr_sys_file_get_std(tr_std_sys_file_t std_file, tr_error** error) +tr_sys_file_t tr_sys_file_get_std(tr_std_sys_file_t std_file, tr_error* error) { tr_sys_file_t ret = TR_BAD_SYS_FILE; @@ -559,13 +565,18 @@ tr_sys_file_t tr_sys_file_get_std(tr_std_sys_file_t std_file, tr_error** error) default: TR_ASSERT_MSG(false, fmt::format(FMT_STRING("unknown standard file {:d}"), static_cast(std_file))); - tr_error_set_from_errno(error, EINVAL); + + if (error != nullptr) + { + error->set_from_errno(EINVAL); + } + break; } return ret; } -tr_sys_file_t tr_sys_file_open(char const* path, int flags, int permissions, tr_error** error) +tr_sys_file_t tr_sys_file_open(char const* path, int flags, int permissions, tr_error* error) { TR_ASSERT(path != nullptr); TR_ASSERT((flags & (TR_SYS_FILE_READ | TR_SYS_FILE_WRITE)) != 0); @@ -606,23 +617,23 @@ tr_sys_file_t tr_sys_file_open(char const* path, int flags, int permissions, tr_ set_file_for_single_pass(ret); } } - else + else if (error != nullptr) { - tr_error_set_from_errno(error, errno); + error->set_from_errno(errno); } return ret; } -tr_sys_file_t tr_sys_file_open_temp(char* path_template, tr_error** error) +tr_sys_file_t tr_sys_file_open_temp(char* path_template, tr_error* error) { TR_ASSERT(path_template != nullptr); tr_sys_file_t const ret = mkstemp(path_template); - if (ret == TR_BAD_SYS_FILE) + if (error != nullptr && ret == TR_BAD_SYS_FILE) { - tr_error_set_from_errno(error, errno); + error->set_from_errno(errno); } set_file_for_single_pass(ret); @@ -630,21 +641,21 @@ tr_sys_file_t tr_sys_file_open_temp(char* path_template, tr_error** error) return ret; } -bool tr_sys_file_close(tr_sys_file_t handle, tr_error** error) +bool tr_sys_file_close(tr_sys_file_t handle, tr_error* error) { TR_ASSERT(handle != TR_BAD_SYS_FILE); bool const ret = close(handle) != -1; - if (!ret) + if (error != nullptr && !ret) { - tr_error_set_from_errno(error, errno); + error->set_from_errno(errno); } return ret; } -bool tr_sys_file_read(tr_sys_file_t handle, void* buffer, uint64_t size, uint64_t* bytes_read, tr_error** error) +bool tr_sys_file_read(tr_sys_file_t handle, void* buffer, uint64_t size, uint64_t* bytes_read, tr_error* error) { TR_ASSERT(handle != TR_BAD_SYS_FILE); TR_ASSERT(buffer != nullptr || size == 0); @@ -663,9 +674,9 @@ bool tr_sys_file_read(tr_sys_file_t handle, void* buffer, uint64_t size, uint64_ ret = true; } - else + else if (error != nullptr) { - tr_error_set_from_errno(error, errno); + error->set_from_errno(errno); } return ret; @@ -677,7 +688,7 @@ bool tr_sys_file_read_at( uint64_t size, uint64_t offset, uint64_t* bytes_read, - tr_error** error) + tr_error* error) { TR_ASSERT(handle != TR_BAD_SYS_FILE); TR_ASSERT(buffer != nullptr || size == 0); @@ -707,15 +718,15 @@ bool tr_sys_file_read_at( ret = true; } - else if (my_bytes_read == -1) + else if (error != nullptr && my_bytes_read == -1) { - tr_error_set_from_errno(error, errno); + error->set_from_errno(errno); } return ret; } -bool tr_sys_file_write(tr_sys_file_t handle, void const* buffer, uint64_t size, uint64_t* bytes_written, tr_error** error) +bool tr_sys_file_write(tr_sys_file_t handle, void const* buffer, uint64_t size, uint64_t* bytes_written, tr_error* error) { TR_ASSERT(handle != TR_BAD_SYS_FILE); TR_ASSERT(buffer != nullptr || size == 0); @@ -734,9 +745,9 @@ bool tr_sys_file_write(tr_sys_file_t handle, void const* buffer, uint64_t size, ret = true; } - else + else if (error != nullptr) { - tr_error_set_from_errno(error, errno); + error->set_from_errno(errno); } return ret; @@ -748,7 +759,7 @@ bool tr_sys_file_write_at( uint64_t size, uint64_t offset, uint64_t* bytes_written, - tr_error** error) + tr_error* error) { TR_ASSERT(handle != TR_BAD_SYS_FILE); TR_ASSERT(buffer != nullptr || size == 0); @@ -778,29 +789,29 @@ bool tr_sys_file_write_at( ret = true; } - else + else if (error != nullptr) { - tr_error_set_from_errno(error, errno); + error->set_from_errno(errno); } return ret; } -bool tr_sys_file_flush(tr_sys_file_t handle, tr_error** error) +bool tr_sys_file_flush(tr_sys_file_t handle, tr_error* error) { TR_ASSERT(handle != TR_BAD_SYS_FILE); bool const ret = (fsync(handle) != -1); - if (!ret) + if (error != nullptr && !ret) { - tr_error_set_from_errno(error, errno); + error->set_from_errno(errno); } return ret; } -bool tr_sys_file_flush_possible(tr_sys_file_t handle, tr_error** error) +bool tr_sys_file_flush_possible(tr_sys_file_t handle, tr_error* error) { TR_ASSERT(handle != TR_BAD_SYS_FILE); @@ -809,19 +820,23 @@ bool tr_sys_file_flush_possible(tr_sys_file_t handle, tr_error** error) return S_ISREG(statbuf.st_mode); } - tr_error_set_from_errno(error, errno); + if (error != nullptr) + { + error->set_from_errno(errno); + } + return false; } -bool tr_sys_file_truncate(tr_sys_file_t handle, uint64_t size, tr_error** error) +bool tr_sys_file_truncate(tr_sys_file_t handle, uint64_t size, tr_error* error) { TR_ASSERT(handle != TR_BAD_SYS_FILE); bool const ret = ftruncate(handle, size) != -1; - if (!ret) + if (error != nullptr && !ret) { - tr_error_set_from_errno(error, errno); + error->set_from_errno(errno); } return ret; @@ -832,7 +847,7 @@ bool tr_sys_file_advise( [[maybe_unused]] uint64_t offset, [[maybe_unused]] uint64_t size, [[maybe_unused]] tr_sys_file_advice_t advice, - [[maybe_unused]] tr_error** error) + [[maybe_unused]] tr_error* error) { TR_ASSERT(handle != TR_BAD_SYS_FILE); TR_ASSERT(size > 0); @@ -850,7 +865,11 @@ bool tr_sys_file_advise( if (int const code = posix_fadvise(handle, offset, size, native_advice); code != 0) { - tr_error_set_from_errno(error, code); + if (error != nullptr) + { + error->set_from_errno(errno); + } + ret = false; } @@ -864,9 +883,9 @@ bool tr_sys_file_advise( ret = fcntl(handle, F_RDADVISE, &radv) != -1; - if (!ret) + if (error != nullptr && !ret) { - tr_error_set_from_errno(error, errno); + error->set_from_errno(errno); } } @@ -877,7 +896,8 @@ bool tr_sys_file_advise( namespace { - +namespace preallocate_helpers +{ #ifdef HAVE_FALLOCATE64 bool preallocate_fallocate64(tr_sys_file_t handle, uint64_t size) { @@ -938,11 +958,13 @@ bool full_preallocate_posix(tr_sys_file_t handle, uint64_t size) return posix_fallocate(handle, 0, size) == 0; } #endif - +} // namespace preallocate_helpers } // unnamed namespace -bool tr_sys_file_preallocate(tr_sys_file_t handle, uint64_t size, int flags, tr_error** error) +bool tr_sys_file_preallocate(tr_sys_file_t handle, uint64_t size, int flags, tr_error* error) { + using namespace preallocate_helpers; + TR_ASSERT(handle != TR_BAD_SYS_FILE); using prealloc_func = bool (*)(tr_sys_file_t, uint64_t); @@ -992,11 +1014,15 @@ bool tr_sys_file_preallocate(tr_sys_file_t handle, uint64_t size, int flags, tr_ } } - tr_error_set_from_errno(error, errno); + if (error != nullptr) + { + error->set_from_errno(errno ? errno : ENOSYS); + } + return false; } -bool tr_sys_file_lock([[maybe_unused]] tr_sys_file_t handle, [[maybe_unused]] int operation, tr_error** error) +bool tr_sys_file_lock([[maybe_unused]] tr_sys_file_t handle, [[maybe_unused]] int operation, tr_error* error) { TR_ASSERT(handle != TR_BAD_SYS_FILE); TR_ASSERT((operation & ~(TR_SYS_FILE_LOCK_SH | TR_SYS_FILE_LOCK_EX | TR_SYS_FILE_LOCK_NB | TR_SYS_FILE_LOCK_UN)) == 0); @@ -1072,15 +1098,15 @@ bool tr_sys_file_lock([[maybe_unused]] tr_sys_file_t handle, [[maybe_unused]] in #endif - if (!ret) + if (error != nullptr && !ret) { - tr_error_set_from_errno(error, errno); + error->set_from_errno(errno); } return ret; } -std::string tr_sys_dir_get_current(tr_error** error) +std::string tr_sys_dir_get_current(tr_error* error) { auto buf = std::vector{}; buf.resize(PATH_MAX); @@ -1092,20 +1118,25 @@ std::string tr_sys_dir_get_current(tr_error** error) return ret; } - if (errno != ERANGE) + if (errno == ERANGE) { - tr_error_set_from_errno(error, errno); - return {}; + buf.resize(std::size(buf) * 2U); + continue; } - buf.resize(std::size(buf) * 2); + if (error != nullptr) + { + error->set_from_errno(errno); + } + + return {}; } } namespace { #ifndef HAVE_MKDIRP -[[nodiscard]] bool tr_mkdirp_(std::string_view path, int permissions, tr_error** error) +[[nodiscard]] bool tr_mkdirp_(std::string_view path, int permissions, tr_error* error) { auto walk = path.find_first_not_of('/'); // walk past the root auto subpath = tr_pathbuf{}; @@ -1117,12 +1148,20 @@ namespace auto const info = tr_sys_path_get_info(subpath, 0); if (info && !info->isFolder()) { - tr_error_set(error, ENOTDIR, fmt::format(FMT_STRING("File is in the way: {:s}"), path)); + if (error != nullptr) + { + error->set(ENOTDIR, fmt::format(FMT_STRING("File is in the way: {:s}"), path)); + } + return false; } if (!info && mkdir(subpath, permissions) == -1) { - tr_error_set_from_errno(error, errno); + if (error != nullptr) + { + error->set_from_errno(errno); + } + return false; } if (end == std::string_view::npos) @@ -1137,19 +1176,19 @@ namespace #endif } // namespace -bool tr_sys_dir_create(char const* path, int flags, int permissions, tr_error** error) +bool tr_sys_dir_create(char const* path, int flags, int permissions, tr_error* error) { TR_ASSERT(path != nullptr); - bool ret = false; - tr_error* my_error = nullptr; + auto ret = bool{ false }; + auto local_error = tr_error{}; if ((flags & TR_SYS_DIR_CREATE_PARENTS) != 0) { #ifdef HAVE_MKDIRP ret = mkdirp(path, permissions) != -1; #else - ret = tr_mkdirp_(path, permissions, &my_error); + ret = tr_mkdirp_(path, permissions, &local_error); #endif } else @@ -1161,7 +1200,7 @@ bool tr_sys_dir_create(char const* path, int flags, int permissions, tr_error** { if (auto const info = tr_sys_path_get_info(path); info && info->type == TR_SYS_PATH_IS_DIRECTORY) { - tr_error_clear(&my_error); + local_error = {}; ret = true; } else @@ -1170,22 +1209,20 @@ bool tr_sys_dir_create(char const* path, int flags, int permissions, tr_error** } } - if (!ret) + if (error != nullptr && !ret) { - if (my_error != nullptr) + if (!local_error) { - tr_error_propagate(error, &my_error); - } - else - { - tr_error_set_from_errno(error, errno); + local_error.set_from_errno(errno); } + + *error = std::move(local_error); } return ret; } -bool tr_sys_dir_create_temp(char* path_template, tr_error** error) +bool tr_sys_dir_create_temp(char* path_template, tr_error* error) { TR_ASSERT(path_template != nullptr); @@ -1199,57 +1236,61 @@ bool tr_sys_dir_create_temp(char* path_template, tr_error** error) #endif - if (!ret) + if (error != nullptr && !ret) { - tr_error_set_from_errno(error, errno); + error->set_from_errno(errno); } return ret; } -tr_sys_dir_t tr_sys_dir_open(std::string_view path, tr_error** error) +tr_sys_dir_t tr_sys_dir_open(std::string_view path, tr_error* error) { - auto* const ret = opendir(tr_pathbuf{ path }); - - if (ret == nullptr) + if (auto* const ret = opendir(tr_pathbuf{ path }); ret != nullptr) { - tr_error_set_from_errno(error, errno); - return TR_BAD_SYS_DIR; + return (tr_sys_dir_t)ret; } - return (tr_sys_dir_t)ret; + if (error != nullptr) + { + error->set_from_errno(errno); + } + + return TR_BAD_SYS_DIR; } -char const* tr_sys_dir_read_name(tr_sys_dir_t handle, tr_error** error) +char const* tr_sys_dir_read_name(tr_sys_dir_t handle, tr_error* error) { TR_ASSERT(handle != TR_BAD_SYS_DIR); - char const* ret = nullptr; - errno = 0; if (auto const* const entry = readdir(static_cast(handle)); entry != nullptr) { - ret = entry->d_name; - } - else if (errno != 0) - { - tr_error_set_from_errno(error, errno); + return entry->d_name; } - return ret; + if (error != nullptr && errno != 0) + { + error->set_from_errno(errno); + } + + return {}; } -bool tr_sys_dir_close(tr_sys_dir_t handle, tr_error** error) +bool tr_sys_dir_close(tr_sys_dir_t handle, tr_error* error) { TR_ASSERT(handle != TR_BAD_SYS_DIR); - bool const ret = closedir(static_cast(handle)) != -1; - - if (!ret) + if (auto const ret = closedir(static_cast(handle)) != -1; ret) { - tr_error_set_from_errno(error, errno); + return ret; } - return ret; + if (error != nullptr) + { + error->set_from_errno(errno); + } + + return {}; } diff --git a/libtransmission/file-win32.cc b/libtransmission/file-win32.cc index aa2244793..0d1be3e93 100644 --- a/libtransmission/file-win32.cc +++ b/libtransmission/file-win32.cc @@ -46,24 +46,16 @@ struct tr_sys_dir_win32 static auto constexpr NativeLocalPathPrefix = L"\\\\?\\"sv; static auto constexpr NativeUncPathPrefix = L"\\\\?\\UNC\\"sv; -static void set_system_error(tr_error** error, DWORD code) +static void set_system_error(tr_error* error, DWORD code) { - if (error == nullptr) + if (error != nullptr) { - return; - } - - if (auto const message = tr_win32_format_message(code); !std::empty(message)) - { - tr_error_set(error, code, message); - } - else - { - tr_error_set(error, code, fmt::format(FMT_STRING("Unknown error: {:#08x}"), code)); + auto const message = tr_win32_format_message(code); + error->set(code, !std::empty(message) ? message : fmt::format(FMT_STRING("Unknown error: {:#08x}"), code)); } } -static void set_system_error_if_file_found(tr_error** error, DWORD code) +static void set_system_error_if_file_found(tr_error* error, DWORD code) { if (code != ERROR_FILE_NOT_FOUND && code != ERROR_PATH_NOT_FOUND && code != ERROR_NO_MORE_FILES) { @@ -229,7 +221,7 @@ static std::string native_path_to_path(std::wstring_view wide_path) return tr_win32_native_to_utf8(wide_path); } -static tr_sys_file_t open_file(std::string_view path, DWORD access, DWORD disposition, DWORD flags, tr_error** error) +static tr_sys_file_t open_file(std::string_view path, DWORD access, DWORD disposition, DWORD flags, tr_error* error) { tr_sys_file_t ret = TR_BAD_SYS_FILE; @@ -253,7 +245,7 @@ static tr_sys_file_t open_file(std::string_view path, DWORD access, DWORD dispos return ret; } -static bool create_dir(std::string_view path, int flags, int /*permissions*/, bool okay_if_exists, tr_error** error) +static bool create_dir(std::string_view path, int flags, int /*permissions*/, bool okay_if_exists, tr_error* error) { bool ret; DWORD error_code = ERROR_SUCCESS; @@ -300,9 +292,9 @@ static bool create_dir(std::string_view path, int flags, int /*permissions*/, bo static void create_temp_path( char* path_template, - void (*callback)(char const* path, void* param, tr_error** error), + void (*callback)(char const* path, void* param, tr_error* error), void* callback_param, - tr_error** error) + tr_error* error) { TR_ASSERT(path_template != nullptr); TR_ASSERT(callback != nullptr); @@ -312,7 +304,7 @@ static void create_temp_path( TR_ASSERT(path_size > 0); - tr_error* my_error = nullptr; + auto local_error = tr_error{}; for (int attempt = 0; attempt < 100; ++attempt) { @@ -327,27 +319,27 @@ static void create_temp_path( TR_ASSERT(path_size >= i + 6); - tr_error_clear(&my_error); + local_error = {}; - (*callback)(path.c_str(), callback_param, &my_error); + (*callback)(path.c_str(), callback_param, &local_error); - if (my_error == nullptr) + if (!local_error) { break; } } - if (my_error != nullptr) - { - tr_error_propagate(error, &my_error); - } - else + if (!local_error) { std::copy_n(std::begin(path), path_size, path_template); } + else if (error != nullptr) + { + *error = std::move(local_error); + } } -bool tr_sys_path_exists(char const* path, tr_error** error) +bool tr_sys_path_exists(char const* path, tr_error* error) { TR_ASSERT(path != nullptr); @@ -385,7 +377,7 @@ bool tr_sys_path_exists(char const* path, tr_error** error) return ret; } -static std::optional tr_sys_file_get_info_(tr_sys_file_t handle, tr_error** error) +static std::optional tr_sys_file_get_info_(tr_sys_file_t handle, tr_error* error) { TR_ASSERT(handle != TR_BAD_SYS_FILE); @@ -403,7 +395,7 @@ static std::optional tr_sys_file_get_info_(tr_sys_file_t handl return {}; } -std::optional tr_sys_path_get_info(std::string_view path, int flags, tr_error** error) +std::optional tr_sys_path_get_info(std::string_view path, int flags, tr_error* error) { if (auto const wide_path = path_to_native_path(path); std::empty(wide_path)) { @@ -457,7 +449,7 @@ bool tr_sys_path_is_relative(std::string_view path) return true; } -static std::optional get_file_info(char const* path, tr_error** error) +static std::optional get_file_info(char const* path, tr_error* error) { auto const wpath = path_to_native_path(path); if (std::empty(wpath)) @@ -486,7 +478,7 @@ static std::optional get_file_info(char const* path, return info; } -bool tr_sys_path_is_same(char const* path1, char const* path2, tr_error** error) +bool tr_sys_path_is_same(char const* path1, char const* path2, tr_error* error) { TR_ASSERT(path1 != nullptr); TR_ASSERT(path2 != nullptr); @@ -507,7 +499,7 @@ bool tr_sys_path_is_same(char const* path1, char const* path2, tr_error** error) fi1->nFileIndexLow == fi2->nFileIndexLow; } -std::string tr_sys_path_resolve(std::string_view path, tr_error** error) +std::string tr_sys_path_resolve(std::string_view path, tr_error* error) { auto ret = std::string{}; @@ -549,7 +541,7 @@ std::string tr_sys_path_resolve(std::string_view path, tr_error** error) return {}; } -std::string_view tr_sys_path_basename(std::string_view path, tr_error** error) +std::string_view tr_sys_path_basename(std::string_view path, tr_error* error) { if (std::empty(path)) { @@ -705,7 +697,7 @@ std::string_view tr_sys_path_dirname(std::string_view path) return path.substr(0, end); } -bool tr_sys_path_rename(char const* src_path, char const* dst_path, tr_error** error) +bool tr_sys_path_rename(char const* src_path, char const* dst_path, tr_error* error) { TR_ASSERT(src_path != nullptr); TR_ASSERT(dst_path != nullptr); @@ -746,7 +738,7 @@ bool tr_sys_path_rename(char const* src_path, char const* dst_path, tr_error** e return ret; } -bool tr_sys_path_copy(char const* src_path, char const* dst_path, tr_error** error) +bool tr_sys_path_copy(char const* src_path, char const* dst_path, tr_error* error) { TR_ASSERT(src_path != nullptr); TR_ASSERT(dst_path != nullptr); @@ -770,7 +762,7 @@ bool tr_sys_path_copy(char const* src_path, char const* dst_path, tr_error** err return true; } -bool tr_sys_path_remove(char const* path, tr_error** error) +bool tr_sys_path_remove(char const* path, tr_error* error) { TR_ASSERT(path != nullptr); @@ -816,7 +808,7 @@ char* tr_sys_path_native_separators(char* path) return path; } -tr_sys_file_t tr_sys_file_get_std(tr_std_sys_file_t std_file, tr_error** error) +tr_sys_file_t tr_sys_file_get_std(tr_std_sys_file_t std_file, tr_error* error) { tr_sys_file_t ret = TR_BAD_SYS_FILE; @@ -852,7 +844,7 @@ tr_sys_file_t tr_sys_file_get_std(tr_std_sys_file_t std_file, tr_error** error) return ret; } -tr_sys_file_t tr_sys_file_open(char const* path, int flags, int /*permissions*/, tr_error** error) +tr_sys_file_t tr_sys_file_open(char const* path, int flags, int /*permissions*/, tr_error* error) { TR_ASSERT(path != nullptr); TR_ASSERT((flags & (TR_SYS_FILE_READ | TR_SYS_FILE_WRITE)) != 0); @@ -898,10 +890,7 @@ tr_sys_file_t tr_sys_file_open(char const* path, int flags, int /*permissions*/, if (!success) { - if (error == nullptr) - { - set_system_error(error, GetLastError()); - } + set_system_error(error, GetLastError()); CloseHandle(ret); ret = TR_BAD_SYS_FILE; @@ -910,16 +899,16 @@ tr_sys_file_t tr_sys_file_open(char const* path, int flags, int /*permissions*/, return ret; } -static void file_open_temp_callback(char const* path, void* param, tr_error** error) +static void file_open_temp_callback(char const* path, void* param, tr_error* error) { - tr_sys_file_t* result = (tr_sys_file_t*)param; + auto* const result = static_cast(param); TR_ASSERT(result != nullptr); *result = open_file(path, GENERIC_READ | GENERIC_WRITE, CREATE_NEW, FILE_ATTRIBUTE_TEMPORARY, error); } -tr_sys_file_t tr_sys_file_open_temp(char* path_template, tr_error** error) +tr_sys_file_t tr_sys_file_open_temp(char* path_template, tr_error* error) { TR_ASSERT(path_template != nullptr); @@ -930,7 +919,7 @@ tr_sys_file_t tr_sys_file_open_temp(char* path_template, tr_error** error) return ret; } -bool tr_sys_file_close(tr_sys_file_t handle, tr_error** error) +bool tr_sys_file_close(tr_sys_file_t handle, tr_error* error) { TR_ASSERT(handle != TR_BAD_SYS_FILE); @@ -944,7 +933,7 @@ bool tr_sys_file_close(tr_sys_file_t handle, tr_error** error) return ret; } -bool tr_sys_file_read(tr_sys_file_t handle, void* buffer, uint64_t size, uint64_t* bytes_read, tr_error** error) +bool tr_sys_file_read(tr_sys_file_t handle, void* buffer, uint64_t size, uint64_t* bytes_read, tr_error* error) { TR_ASSERT(handle != TR_BAD_SYS_FILE); TR_ASSERT(buffer != nullptr || size == 0); @@ -981,7 +970,7 @@ bool tr_sys_file_read_at( uint64_t size, uint64_t offset, uint64_t* bytes_read, - tr_error** error) + tr_error* error) { TR_ASSERT(handle != TR_BAD_SYS_FILE); TR_ASSERT(buffer != nullptr || size == 0); @@ -1018,7 +1007,7 @@ bool tr_sys_file_read_at( return ret; } -bool tr_sys_file_write(tr_sys_file_t handle, void const* buffer, uint64_t size, uint64_t* bytes_written, tr_error** error) +bool tr_sys_file_write(tr_sys_file_t handle, void const* buffer, uint64_t size, uint64_t* bytes_written, tr_error* error) { TR_ASSERT(handle != TR_BAD_SYS_FILE); TR_ASSERT(buffer != nullptr || size == 0); @@ -1055,7 +1044,7 @@ bool tr_sys_file_write_at( uint64_t size, uint64_t offset, uint64_t* bytes_written, - tr_error** error) + tr_error* error) { TR_ASSERT(handle != TR_BAD_SYS_FILE); TR_ASSERT(buffer != nullptr || size == 0); @@ -1092,7 +1081,7 @@ bool tr_sys_file_write_at( return ret; } -bool tr_sys_file_flush(tr_sys_file_t handle, tr_error** error) +bool tr_sys_file_flush(tr_sys_file_t handle, tr_error* error) { TR_ASSERT(handle != TR_BAD_SYS_FILE); @@ -1106,7 +1095,7 @@ bool tr_sys_file_flush(tr_sys_file_t handle, tr_error** error) return ret; } -bool tr_sys_file_flush_possible(tr_sys_file_t handle, tr_error** error) +bool tr_sys_file_flush_possible(tr_sys_file_t handle, tr_error* error) { TR_ASSERT(handle != TR_BAD_SYS_FILE); @@ -1121,7 +1110,7 @@ bool tr_sys_file_flush_possible(tr_sys_file_t handle, tr_error** error) return type == FILE_TYPE_DISK; } -bool tr_sys_file_truncate(tr_sys_file_t handle, uint64_t size, tr_error** error) +bool tr_sys_file_truncate(tr_sys_file_t handle, uint64_t size, tr_error* error) { TR_ASSERT(handle != TR_BAD_SYS_FILE); @@ -1143,7 +1132,7 @@ bool tr_sys_file_advise( uint64_t /*offset*/, [[maybe_unused]] uint64_t size, [[maybe_unused]] tr_sys_file_advice_t advice, - tr_error** /*error*/) + tr_error* /*error*/) { TR_ASSERT(handle != TR_BAD_SYS_FILE); TR_ASSERT(size > 0); @@ -1156,7 +1145,7 @@ bool tr_sys_file_advise( return ret; } -bool tr_sys_file_preallocate(tr_sys_file_t handle, uint64_t size, int flags, tr_error** error) +bool tr_sys_file_preallocate(tr_sys_file_t handle, uint64_t size, int flags, tr_error* error) { TR_ASSERT(handle != TR_BAD_SYS_FILE); @@ -1174,7 +1163,7 @@ bool tr_sys_file_preallocate(tr_sys_file_t handle, uint64_t size, int flags, tr_ return tr_sys_file_truncate(handle, size, error); } -bool tr_sys_file_lock(tr_sys_file_t handle, int operation, tr_error** error) +bool tr_sys_file_lock(tr_sys_file_t handle, int operation, tr_error* error) { TR_ASSERT(handle != TR_BAD_SYS_FILE); TR_ASSERT((operation & ~(TR_SYS_FILE_LOCK_SH | TR_SYS_FILE_LOCK_EX | TR_SYS_FILE_LOCK_NB | TR_SYS_FILE_LOCK_UN)) == 0); @@ -1213,7 +1202,7 @@ bool tr_sys_file_lock(tr_sys_file_t handle, int operation, tr_error** error) return ret; } -std::string tr_sys_dir_get_current(tr_error** error) +std::string tr_sys_dir_get_current(tr_error* error) { if (auto const size = GetCurrentDirectoryW(0, nullptr); size != 0) { @@ -1231,21 +1220,21 @@ std::string tr_sys_dir_get_current(tr_error** error) return {}; } -bool tr_sys_dir_create(char const* path, int flags, int permissions, tr_error** error) +bool tr_sys_dir_create(char const* path, int flags, int permissions, tr_error* error) { return create_dir(path, flags, permissions, true, error); } -static void dir_create_temp_callback(char const* path, void* param, tr_error** error) +static void dir_create_temp_callback(char const* path, void* param, tr_error* error) { - bool* result = (bool*)param; + auto* const result = static_cast(param); TR_ASSERT(result != nullptr); *result = create_dir(path, 0, 0, false, error); } -bool tr_sys_dir_create_temp(char* path_template, tr_error** error) +bool tr_sys_dir_create_temp(char* path_template, tr_error* error) { TR_ASSERT(path_template != nullptr); @@ -1256,9 +1245,9 @@ bool tr_sys_dir_create_temp(char* path_template, tr_error** error) return ret; } -tr_sys_dir_t tr_sys_dir_open(std::string_view path, tr_error** error) +tr_sys_dir_t tr_sys_dir_open(std::string_view path, tr_error* error) { - TR_ASSERT(path != nullptr); + TR_ASSERT(!std::empty(path)); if (auto const info = tr_sys_path_get_info(path, 0); !info || !info->isFolder()) { @@ -1266,7 +1255,7 @@ tr_sys_dir_t tr_sys_dir_open(std::string_view path, tr_error** error) return TR_BAD_SYS_DIR; } - auto pattern = path_to_native_path(path); + auto const pattern = path_to_native_path(path); if (std::empty(pattern)) { set_system_error(error, GetLastError()); @@ -1279,7 +1268,7 @@ tr_sys_dir_t tr_sys_dir_open(std::string_view path, tr_error** error) return ret; } -char const* tr_sys_dir_read_name(tr_sys_dir_t handle, tr_error** error) +char const* tr_sys_dir_read_name(tr_sys_dir_t handle, tr_error* error) { TR_ASSERT(handle != TR_BAD_SYS_DIR); @@ -1318,7 +1307,7 @@ char const* tr_sys_dir_read_name(tr_sys_dir_t handle, tr_error** error) return nullptr; } -bool tr_sys_dir_close(tr_sys_dir_t handle, tr_error** error) +bool tr_sys_dir_close(tr_sys_dir_t handle, tr_error* error) { TR_ASSERT(handle != TR_BAD_SYS_DIR); diff --git a/libtransmission/file.cc b/libtransmission/file.cc index e9b37018b..b87c22678 100644 --- a/libtransmission/file.cc +++ b/libtransmission/file.cc @@ -7,6 +7,7 @@ #include #include +#include "libtransmission/error.h" #include "libtransmission/file.h" #include "libtransmission/tr-assert.h" @@ -18,7 +19,7 @@ static auto constexpr NativeEol = "\r\n"sv; static auto constexpr NativeEol = "\n"sv; #endif -bool tr_sys_file_write_line(tr_sys_file_t handle, std::string_view buffer, tr_error** error) +bool tr_sys_file_write_line(tr_sys_file_t handle, std::string_view buffer, tr_error* error) { TR_ASSERT(handle != TR_BAD_SYS_FILE); @@ -29,7 +30,7 @@ bool tr_sys_file_write_line(tr_sys_file_t handle, std::string_view buffer, tr_er std::vector tr_sys_dir_get_files( std::string_view folder, std::function const& test, - tr_error** error) + tr_error* error) { if (auto const info = tr_sys_path_get_info(folder); !info || !info->isFolder()) { diff --git a/libtransmission/file.h b/libtransmission/file.h index e82361ff2..51b662185 100644 --- a/libtransmission/file.h +++ b/libtransmission/file.h @@ -146,7 +146,7 @@ struct tr_sys_path_capacity * * @return `True` on success, `false` otherwise (with `error` set accordingly). */ -bool tr_sys_path_copy(char const* src_path, char const* dst_path, struct tr_error** error = nullptr); +bool tr_sys_path_copy(char const* src_path, char const* dst_path, tr_error* error = nullptr); /** * @brief Portability wrapper for `stat()`. @@ -161,7 +161,7 @@ bool tr_sys_path_copy(char const* src_path, char const* dst_path, struct tr_erro [[nodiscard]] std::optional tr_sys_path_get_info( std::string_view path, int flags = 0, - tr_error** error = nullptr); + tr_error* error = nullptr); /** * @brief Get disk capacity and free disk space (in bytes) for the specified folder. @@ -170,7 +170,7 @@ bool tr_sys_path_copy(char const* src_path, char const* dst_path, struct tr_erro * @param[out] error Pointer to error object. Optional, pass `nullptr` if you * are not interested in error details. */ -[[nodiscard]] std::optional tr_sys_path_get_capacity(std::string_view path, tr_error** error = nullptr); +[[nodiscard]] std::optional tr_sys_path_get_capacity(std::string_view path, tr_error* error = nullptr); /** * @brief Portability wrapper for `access()`. @@ -183,10 +183,10 @@ bool tr_sys_path_copy(char const* src_path, char const* dst_path, struct tr_erro * be returned in case of error; if you need to distinguish the two, * check if `error` is `nullptr` afterwards. */ -bool tr_sys_path_exists(char const* path, struct tr_error** error = nullptr); +bool tr_sys_path_exists(char const* path, tr_error* error = nullptr); template -bool tr_sys_path_exists(T const& path, struct tr_error** error = nullptr) +bool tr_sys_path_exists(T const& path, tr_error* error = nullptr) { return tr_sys_path_exists(path.c_str(), error); } @@ -215,10 +215,10 @@ bool tr_sys_path_is_relative(std::string_view path); * if you need to distinguish the two, check if `error` is `nullptr` * afterwards. */ -bool tr_sys_path_is_same(char const* path1, char const* path2, struct tr_error** error = nullptr); +bool tr_sys_path_is_same(char const* path1, char const* path2, tr_error* error = nullptr); template -bool tr_sys_path_is_same(T const& path1, U const& path2, struct tr_error** error = nullptr) +bool tr_sys_path_is_same(T const& path1, U const& path2, tr_error* error = nullptr) { return tr_sys_path_is_same(path1.c_str(), path2.c_str(), error); } @@ -233,7 +233,7 @@ bool tr_sys_path_is_same(T const& path1, U const& path2, struct tr_error** error * @return Full path with symbolic links, `.` and `..` resolved on success, * or an empty string otherwise (with `error` set accordingly). */ -std::string tr_sys_path_resolve(std::string_view path, struct tr_error** error = nullptr); +std::string tr_sys_path_resolve(std::string_view path, tr_error* error = nullptr); /** * @brief Portability wrapper for `basename()`. @@ -245,7 +245,7 @@ std::string tr_sys_path_resolve(std::string_view path, struct tr_error** error = * @return base name (last path component; parent path removed) on success, * or empty string otherwise (with `error` set accordingly). */ -std::string_view tr_sys_path_basename(std::string_view path, struct tr_error** error = nullptr); +std::string_view tr_sys_path_basename(std::string_view path, tr_error* error = nullptr); /** * @brief Portability wrapper for `dirname()`. @@ -269,10 +269,10 @@ std::string_view tr_sys_path_dirname(std::string_view path); * Rename will generally only succeed if both source and destination are * on the same partition. */ -bool tr_sys_path_rename(char const* src_path, char const* dst_path, struct tr_error** error = nullptr); +bool tr_sys_path_rename(char const* src_path, char const* dst_path, tr_error* error = nullptr); template -bool tr_sys_path_rename(T const& src_path, U const& dst_path, struct tr_error** error = nullptr) +bool tr_sys_path_rename(T const& src_path, U const& dst_path, tr_error* error = nullptr) { return tr_sys_path_rename(src_path.c_str(), dst_path.c_str(), error); } @@ -288,10 +288,10 @@ bool tr_sys_path_rename(T const& src_path, U const& dst_path, struct tr_error** * Directory removal will only succeed if it is empty (contains no other * files and directories). */ -bool tr_sys_path_remove(char const* path, struct tr_error** error = nullptr); +bool tr_sys_path_remove(char const* path, tr_error* error = nullptr); template -bool tr_sys_path_remove(T const& path, struct tr_error** error = nullptr) +bool tr_sys_path_remove(T const& path, tr_error* error = nullptr) { return tr_sys_path_remove(path.c_str(), error); } @@ -318,7 +318,7 @@ char* tr_sys_path_native_separators(char* path); * `error` set accordingly). DO NOT pass this descriptor to * @ref tr_sys_file_close (unless you know what you are doing). */ -tr_sys_file_t tr_sys_file_get_std(tr_std_sys_file_t std_file, struct tr_error** error = nullptr); +tr_sys_file_t tr_sys_file_get_std(tr_std_sys_file_t std_file, tr_error* error = nullptr); /** * @brief Portability wrapper for `open()`. @@ -333,7 +333,7 @@ tr_sys_file_t tr_sys_file_get_std(tr_std_sys_file_t std_file, struct tr_error** * @return Opened file descriptor on success, `TR_BAD_SYS_FILE` otherwise (with * `error` set accordingly). */ -tr_sys_file_t tr_sys_file_open(char const* path, int flags, int permissions, struct tr_error** error = nullptr); +tr_sys_file_t tr_sys_file_open(char const* path, int flags, int permissions, tr_error* error = nullptr); /** * @brief Portability wrapper for `mkstemp()`. @@ -349,7 +349,7 @@ tr_sys_file_t tr_sys_file_open(char const* path, int flags, int permissions, str * @return Opened file descriptor on success, `TR_BAD_SYS_FILE` otherwise (with * `error` set accordingly). */ -tr_sys_file_t tr_sys_file_open_temp(char* path_template, struct tr_error** error = nullptr); +tr_sys_file_t tr_sys_file_open_temp(char* path_template, tr_error* error = nullptr); /** * @brief Portability wrapper for `close()`. @@ -360,7 +360,7 @@ tr_sys_file_t tr_sys_file_open_temp(char* path_template, struct tr_error** error * * @return `True` on success, `false` otherwise (with `error` set accordingly). */ -bool tr_sys_file_close(tr_sys_file_t handle, struct tr_error** error = nullptr); +bool tr_sys_file_close(tr_sys_file_t handle, tr_error* error = nullptr); /** * @brief Portability wrapper for `read()`. @@ -375,12 +375,7 @@ bool tr_sys_file_close(tr_sys_file_t handle, struct tr_error** error = nullptr); * * @return `True` on success, `false` otherwise (with `error` set accordingly). */ -bool tr_sys_file_read( - tr_sys_file_t handle, - void* buffer, - uint64_t size, - uint64_t* bytes_read, - struct tr_error** error = nullptr); +bool tr_sys_file_read(tr_sys_file_t handle, void* buffer, uint64_t size, uint64_t* bytes_read, tr_error* error = nullptr); /** * @brief Like `pread()`, except that the position is undefined afterwards. @@ -403,7 +398,7 @@ bool tr_sys_file_read_at( uint64_t size, uint64_t offset, uint64_t* bytes_read, - struct tr_error** error = nullptr); + tr_error* error = nullptr); /** * @brief Portability wrapper for `write()`. @@ -423,7 +418,7 @@ bool tr_sys_file_write( void const* buffer, uint64_t size, uint64_t* bytes_written, - struct tr_error** error = nullptr); + tr_error* error = nullptr); /** * @brief Like `pwrite()`, except that the position is undefined afterwards. @@ -446,7 +441,7 @@ bool tr_sys_file_write_at( uint64_t size, uint64_t offset, uint64_t* bytes_written, - struct tr_error** error = nullptr); + tr_error* error = nullptr); /** * @brief Portability wrapper for `fsync()`. @@ -457,10 +452,10 @@ bool tr_sys_file_write_at( * * @return `True` on success, `false` otherwise (with `error` set accordingly). */ -bool tr_sys_file_flush(tr_sys_file_t handle, struct tr_error** error = nullptr); +bool tr_sys_file_flush(tr_sys_file_t handle, tr_error* error = nullptr); /* @brief Check whether `handle` may be flushed via `tr_sys_file_flush()`. */ -bool tr_sys_file_flush_possible(tr_sys_file_t handle, struct tr_error** error = nullptr); +bool tr_sys_file_flush_possible(tr_sys_file_t handle, tr_error* error = nullptr); /** * @brief Portability wrapper for `ftruncate()`. @@ -472,7 +467,7 @@ bool tr_sys_file_flush_possible(tr_sys_file_t handle, struct tr_error** error = * * @return `True` on success, `false` otherwise (with `error` set accordingly). */ -bool tr_sys_file_truncate(tr_sys_file_t handle, uint64_t size, struct tr_error** error = nullptr); +bool tr_sys_file_truncate(tr_sys_file_t handle, uint64_t size, tr_error* error = nullptr); /** * @brief Tell system to prefetch or discard some part of file which is [not] to be read soon. @@ -490,7 +485,7 @@ bool tr_sys_file_advise( uint64_t offset, uint64_t size, tr_sys_file_advice_t advice, - struct tr_error** error = nullptr); + tr_error* error = nullptr); /** * @brief Preallocate file to specified size in full or sparse mode. @@ -503,7 +498,7 @@ bool tr_sys_file_advise( * * @return `True` on success, `false` otherwise (with `error` set accordingly). */ -bool tr_sys_file_preallocate(tr_sys_file_t handle, uint64_t size, int flags, struct tr_error** error = nullptr); +bool tr_sys_file_preallocate(tr_sys_file_t handle, uint64_t size, int flags, tr_error* error = nullptr); /** * @brief Portability wrapper for `flock()`. @@ -518,7 +513,7 @@ bool tr_sys_file_preallocate(tr_sys_file_t handle, uint64_t size, int flags, str * * @return `True` on success, `false` otherwise (with `error` set accordingly). */ -bool tr_sys_file_lock(tr_sys_file_t handle, int operation, struct tr_error** error = nullptr); +bool tr_sys_file_lock(tr_sys_file_t handle, int operation, tr_error* error = nullptr); /* File-related wrappers (utility) */ @@ -538,7 +533,7 @@ bool tr_sys_file_lock(tr_sys_file_t handle, int operation, struct tr_error** err * * @return `True` on success, `false` otherwise (with `error` set accordingly). */ -bool tr_sys_file_write_line(tr_sys_file_t handle, std::string_view buffer, struct tr_error** error = nullptr); +bool tr_sys_file_write_line(tr_sys_file_t handle, std::string_view buffer, tr_error* error = nullptr); /* Directory-related wrappers */ @@ -551,7 +546,7 @@ bool tr_sys_file_write_line(tr_sys_file_t handle, std::string_view buffer, struc * @return current directory on success, or an empty string otherwise * (with `error` set accordingly). */ -std::string tr_sys_dir_get_current(struct tr_error** error = nullptr); +std::string tr_sys_dir_get_current(tr_error* error = nullptr); /** * @brief Like `mkdir()`, but makes parent directories if needed. @@ -565,10 +560,10 @@ std::string tr_sys_dir_get_current(struct tr_error** error = nullptr); * * @return `True` on success, `false` otherwise (with `error` set accordingly). */ -bool tr_sys_dir_create(char const* path, int flags, int permissions, struct tr_error** error = nullptr); +bool tr_sys_dir_create(char const* path, int flags, int permissions, tr_error* error = nullptr); template -bool tr_sys_dir_create(T const& path, int flags, int permissions, struct tr_error** error = nullptr) +bool tr_sys_dir_create(T const& path, int flags, int permissions, tr_error* error = nullptr) { return tr_sys_dir_create(path.c_str(), flags, permissions, error); } @@ -586,7 +581,7 @@ bool tr_sys_dir_create(T const& path, int flags, int permissions, struct tr_erro * * @return `True` on success, `false` otherwise (with `error` set accordingly). */ -bool tr_sys_dir_create_temp(char* path_template, struct tr_error** error = nullptr); +bool tr_sys_dir_create_temp(char* path_template, tr_error* error = nullptr); /** * @brief Portability wrapper for `opendir()`. @@ -598,7 +593,7 @@ bool tr_sys_dir_create_temp(char* path_template, struct tr_error** error = nullp * @return Opened directory descriptor on success, `TR_BAD_SYS_DIR` otherwise * (with `error` set accordingly). */ -tr_sys_dir_t tr_sys_dir_open(std::string_view path, struct tr_error** error = nullptr); +tr_sys_dir_t tr_sys_dir_open(std::string_view path, tr_error* error = nullptr); /** * @brief Portability wrapper for `readdir()`. @@ -613,7 +608,7 @@ tr_sys_dir_t tr_sys_dir_open(std::string_view path, struct tr_error** error = nu * If you need to distinguish the two, check if `error` is `nullptr` * afterwards. */ -char const* tr_sys_dir_read_name(tr_sys_dir_t handle, struct tr_error** error = nullptr); +char const* tr_sys_dir_read_name(tr_sys_dir_t handle, tr_error* error = nullptr); /** * @brief Portability wrapper for `closedir()`. @@ -624,7 +619,7 @@ char const* tr_sys_dir_read_name(tr_sys_dir_t handle, struct tr_error** error = * * @return `True` on success, `false` otherwise (with `error` set accordingly). */ -bool tr_sys_dir_close(tr_sys_dir_t handle, struct tr_error** error = nullptr); +bool tr_sys_dir_close(tr_sys_dir_t handle, tr_error* error = nullptr); [[nodiscard]] constexpr bool tr_basename_is_not_dotfile(std::string_view sv) { @@ -634,7 +629,7 @@ bool tr_sys_dir_close(tr_sys_dir_t handle, struct tr_error** error = nullptr); [[nodiscard]] std::vector tr_sys_dir_get_files( std::string_view folder, std::function const& test = tr_basename_is_not_dotfile, - tr_error** error = nullptr); + tr_error* error = nullptr); /** @} */ /** @} */ diff --git a/libtransmission/handshake.cc b/libtransmission/handshake.cc index 834e96415..99671f0a9 100644 --- a/libtransmission/handshake.cc +++ b/libtransmission/handshake.cc @@ -632,7 +632,7 @@ void tr_handshake::on_error(tr_peerIo* io, tr_error const& error, void* vhandsha auto const info = handshake->mediator_->torrent(info_hash); /* Don't mark a peer as non-µTP unless it's really a connect failure. */ - if ((error.code == ETIMEDOUT || error.code == ECONNREFUSED) && info) + if ((error.code() == ETIMEDOUT || error.code() == ECONNREFUSED) && info) { handshake->mediator_->set_utp_failed(info_hash, io->socket_address()); } @@ -657,7 +657,7 @@ void tr_handshake::on_error(tr_peerIo* io, tr_error const& error, void* vhandsha return; } - tr_logAddTraceHand(handshake, fmt::format("handshake socket err: {:s} ({:d})", error.message, error.code)); + tr_logAddTraceHand(handshake, fmt::format("handshake socket err: {:s} ({:d})", error.message(), error.code())); handshake->done(false); } diff --git a/libtransmission/inout.cc b/libtransmission/inout.cc index 680b0e3d7..b956d5f77 100644 --- a/libtransmission/inout.cc +++ b/libtransmission/inout.cc @@ -32,7 +32,7 @@ using namespace std::literals; namespace { -bool readEntireBuf(tr_sys_file_t fd, uint64_t file_offset, uint8_t* buf, uint64_t buflen, tr_error** error) +bool readEntireBuf(tr_sys_file_t fd, uint64_t file_offset, uint8_t* buf, uint64_t buflen, tr_error* error) { while (buflen > 0) { @@ -51,7 +51,7 @@ bool readEntireBuf(tr_sys_file_t fd, uint64_t file_offset, uint8_t* buf, uint64_ return true; } -bool writeEntireBuf(tr_sys_file_t fd, uint64_t file_offset, uint8_t const* buf, uint64_t buflen, tr_error** error) +bool writeEntireBuf(tr_sys_file_t fd, uint64_t file_offset, uint8_t const* buf, uint64_t buflen, tr_error* error) { while (buflen > 0) { @@ -106,7 +106,7 @@ void readOrWriteBytes( uint64_t file_offset, uint8_t* buf, size_t buflen, - tr_error** error) + tr_error* error) { TR_ASSERT(file_index < tor->file_count()); @@ -120,6 +120,12 @@ void readOrWriteBytes( return; } + auto local_error = tr_error{}; + if (error == nullptr) + { + error = &local_error; + } + // --- Find the fd auto fd = session->openFiles().get(tor->id(), file_index, do_write); @@ -127,12 +133,13 @@ void readOrWriteBytes( if (!fd && !getFilename(filename, tor, file_index, io_mode)) { auto const err = ENOENT; - auto const msg = fmt::format( - _("Couldn't get '{path}': {error} ({error_code})"), - fmt::arg("path", tor->file_subpath(file_index)), - fmt::arg("error", tr_strerror(err)), - fmt::arg("error_code", err)); - tr_error_set(error, err, msg); + error->set( + err, + fmt::format( + _("Couldn't get '{path}': {error} ({error_code})"), + fmt::arg("path", tor->file_subpath(file_index)), + fmt::arg("error", tr_strerror(err)), + fmt::arg("error_code", err))); return; } @@ -151,45 +158,44 @@ void readOrWriteBytes( if (!fd) // couldn't create/open it either { - auto const err = errno; - auto msg = fmt::format( - _("Couldn't get '{path}': {error} ({error_code})"), - fmt::arg("path", filename), - fmt::arg("error", tr_strerror(err)), - fmt::arg("error_code", err)); - tr_error_set(error, err, msg); - tr_logAddErrorTor(tor, std::move(msg)); + auto const errnum = errno; + error->set( + errnum, + fmt::format( + _("Couldn't get '{path}': {error} ({error_code})"), + fmt::arg("path", filename), + fmt::arg("error", tr_strerror(errnum)), + fmt::arg("error_code", errnum))); + tr_logAddErrorTor(tor, std::string{ error->message() }); return; } switch (io_mode) { case IoMode::Read: - if (tr_error* my_error = nullptr; !readEntireBuf(*fd, file_offset, buf, buflen, &my_error) && my_error != nullptr) + if (!readEntireBuf(*fd, file_offset, buf, buflen, error) && *error) { tr_logAddErrorTor( tor, fmt::format( _("Couldn't read '{path}': {error} ({error_code})"), fmt::arg("path", tor->file_subpath(file_index)), - fmt::arg("error", my_error->message), - fmt::arg("error_code", my_error->code))); - tr_error_propagate(error, &my_error); + fmt::arg("error", error->message()), + fmt::arg("error_code", error->code()))); return; } break; case IoMode::Write: - if (tr_error* my_error = nullptr; !writeEntireBuf(*fd, file_offset, buf, buflen, &my_error) && my_error != nullptr) + if (!writeEntireBuf(*fd, file_offset, buf, buflen, error) && *error) { tr_logAddErrorTor( tor, fmt::format( _("Couldn't save '{path}': {error} ({error_code})"), fmt::arg("path", tor->file_subpath(file_index)), - fmt::arg("error", my_error->message), - fmt::arg("error_code", my_error->code))); - tr_error_propagate(error, &my_error); + fmt::arg("error", error->message()), + fmt::arg("error_code", error->code()))); return; } break; @@ -214,20 +220,17 @@ int readOrWritePiece(tr_torrent* tor, IoMode io_mode, tr_block_info::Location lo { uint64_t const bytes_this_pass = std::min(uint64_t{ buflen }, uint64_t{ tor->file_size(file_index) - file_offset }); - tr_error* error = nullptr; + auto error = tr_error{}; readOrWriteBytes(tor->session, tor, io_mode, file_index, file_offset, buf, bytes_this_pass, &error); - - if (error != nullptr) // if IO failed, set torrent's error if not already set + if (error) // if IO failed, set torrent's error if not already set { if (io_mode == IoMode::Write && tor->error().error_type() != TR_STAT_LOCAL_ERROR) { - tor->error().set_local_error(error->message); + tor->error().set_local_error(error.message()); tr_torrentStop(tor); } - auto const error_code = error->code; - tr_error_clear(&error); - return error_code; + return error.code(); } if (buf != nullptr) diff --git a/libtransmission/magnet-metainfo.cc b/libtransmission/magnet-metainfo.cc index fbe69f3c4..e4d88b8d3 100644 --- a/libtransmission/magnet-metainfo.cc +++ b/libtransmission/magnet-metainfo.cc @@ -208,7 +208,7 @@ void tr_magnet_metainfo::add_webseed(std::string_view webseed) urls.emplace_back(webseed); } -bool tr_magnet_metainfo::parseMagnet(std::string_view magnet_link, tr_error** error) +bool tr_magnet_metainfo::parseMagnet(std::string_view magnet_link, tr_error* error) { magnet_link = tr_strv_strip(magnet_link); if (auto const hash = parseHash(magnet_link); hash) @@ -219,7 +219,11 @@ bool tr_magnet_metainfo::parseMagnet(std::string_view magnet_link, tr_error** er auto const parsed = tr_urlParse(magnet_link); if (!parsed || parsed->scheme != "magnet"sv) { - tr_error_set(error, TR_ERROR_EINVAL, "Error parsing URL"sv); + if (error != nullptr) + { + error->set(TR_ERROR_EINVAL, "Error parsing URL"sv); + } + return false; } diff --git a/libtransmission/magnet-metainfo.h b/libtransmission/magnet-metainfo.h index c9a7bb609..c7b1ec74a 100644 --- a/libtransmission/magnet-metainfo.h +++ b/libtransmission/magnet-metainfo.h @@ -22,7 +22,7 @@ class tr_magnet_metainfo friend struct MetainfoHandler; public: - bool parseMagnet(std::string_view magnet_link, tr_error** error = nullptr); + bool parseMagnet(std::string_view magnet_link, tr_error* error = nullptr); [[nodiscard]] std::string magnet() const; diff --git a/libtransmission/makemeta.cc b/libtransmission/makemeta.cc index afb694729..669b47561 100644 --- a/libtransmission/makemeta.cc +++ b/libtransmission/makemeta.cc @@ -73,16 +73,15 @@ void walkTree(std::string_view const top, std::string_view const subpath, std::s auto path = tr_pathbuf{ top, '/', subpath }; tr_sys_path_native_separators(std::data(path)); - tr_error* error = nullptr; + auto error = tr_error{}; auto const info = tr_sys_path_get_info(path, 0, &error); - if (error != nullptr) + if (error) { tr_logAddWarn(fmt::format( _("Skipping '{path}': {error} ({error_code})"), fmt::arg("path", path), - fmt::arg("error", error->message), - fmt::arg("error_code", error->code))); - tr_error_free(error); + fmt::arg("error", error.message()), + fmt::arg("error_code", error.code()))); } if (!info) { @@ -150,14 +149,18 @@ bool tr_metainfo_builder::set_piece_size(uint32_t piece_size) noexcept return true; } -bool tr_metainfo_builder::blocking_make_checksums(tr_error** error) +bool tr_metainfo_builder::blocking_make_checksums(tr_error* error) { checksum_piece_ = 0; cancel_ = false; if (total_size() == 0U) { - tr_error_set_from_errno(error, ENOENT); + if (error != nullptr) + { + error->set_from_errno(ENOENT); + } + return false; } @@ -246,7 +249,11 @@ bool tr_metainfo_builder::blocking_make_checksums(tr_error** error) if (cancel_) { - tr_error_set_from_errno(error, ECANCELED); + if (error != nullptr) + { + error->set_from_errno(ECANCELED); + } + return false; } @@ -254,7 +261,7 @@ bool tr_metainfo_builder::blocking_make_checksums(tr_error** error) return true; } -std::string tr_metainfo_builder::benc(tr_error** error) const +std::string tr_metainfo_builder::benc(tr_error* error) const { TR_ASSERT_MSG(!std::empty(piece_hashes_), "did you forget to call makeChecksums() first?"); @@ -265,7 +272,11 @@ std::string tr_metainfo_builder::benc(tr_error** error) const if (total_size() == 0) { - tr_error_set_from_errno(error, ENOENT); + if (error != nullptr) + { + error->set_from_errno(ENOENT); + } + return {}; } diff --git a/libtransmission/makemeta.h b/libtransmission/makemeta.h index c716dbec3..e69c9e758 100644 --- a/libtransmission/makemeta.h +++ b/libtransmission/makemeta.h @@ -17,13 +17,12 @@ #include "libtransmission/announce-list.h" #include "libtransmission/block-info.h" +#include "libtransmission/error.h" #include "libtransmission/file.h" #include "libtransmission/torrent-files.h" #include "libtransmission/tr-macros.h" // TR_CONSTEXPR20 #include "libtransmission/utils.h" // for tr_file_save() -struct tr_error; - class tr_metainfo_builder { public: @@ -38,14 +37,14 @@ public: // - This must be done before calling `benc()` or `save()`. // - Runs in a worker thread because it can be time-consuming. // - Can be cancelled with `cancelChecksums()` and polled with `checksumStatus()` - // - Resolves with a `tr_error*` which is set on failure or nullptr on success. - std::future make_checksums() + // - Resolves with a `tr_error` which is set on failure or empty on success. + std::future make_checksums() { return std::async( std::launch::async, [this]() { - tr_error* error = nullptr; + auto error = tr_error{}; blocking_make_checksums(&error); return error; }); @@ -65,10 +64,10 @@ public: } // generate the metainfo - [[nodiscard]] std::string benc(tr_error** error = nullptr) const; + [[nodiscard]] std::string benc(tr_error* error = nullptr) const; // generate the metainfo and save it to a torrent file - bool save(std::string_view filename, tr_error** error = nullptr) const + bool save(std::string_view filename, tr_error* error = nullptr) const { return tr_file_save(filename, benc(error), error); } @@ -193,7 +192,7 @@ public: } private: - bool blocking_make_checksums(tr_error** error = nullptr); + bool blocking_make_checksums(tr_error* error = nullptr); std::string top_; tr_torrent_files files_; diff --git a/libtransmission/open-files.cc b/libtransmission/open-files.cc index ab485e86a..b33f49a52 100644 --- a/libtransmission/open-files.cc +++ b/libtransmission/open-files.cc @@ -30,70 +30,75 @@ namespace return fd != TR_BAD_SYS_FILE; } -bool preallocate_file_sparse(tr_sys_file_t fd, uint64_t length, tr_error** error) +bool preallocate_file_sparse(tr_sys_file_t fd, uint64_t length, tr_error* error) { - tr_error* my_error = nullptr; - if (length == 0) { return true; } - if (tr_sys_file_preallocate(fd, length, TR_SYS_FILE_PREALLOC_SPARSE, &my_error)) + auto local_error = tr_error{}; + + if (tr_sys_file_preallocate(fd, length, TR_SYS_FILE_PREALLOC_SPARSE, &local_error)) { return true; } - tr_logAddDebug(fmt::format("Fast preallocation failed: {} ({})", my_error->message, my_error->code)); + tr_logAddDebug(fmt::format("Fast preallocation failed: {} ({})", local_error.message(), local_error.code())); - if (!TR_ERROR_IS_ENOSPC(my_error->code)) + if (!TR_ERROR_IS_ENOSPC(local_error.code())) { char const zero = '\0'; - tr_error_clear(&my_error); + local_error = {}; /* fallback: the old-style seek-and-write */ - if (tr_sys_file_write_at(fd, &zero, 1, length - 1, nullptr, &my_error) && tr_sys_file_truncate(fd, length, &my_error)) + if (tr_sys_file_write_at(fd, &zero, 1, length - 1, nullptr, &local_error) && + tr_sys_file_truncate(fd, length, &local_error)) { return true; } - tr_logAddDebug(fmt::format("Fast prellocation fallback failed: {} ({})", my_error->message, my_error->code)); + tr_logAddDebug(fmt::format("Fast prellocation fallback failed: {} ({})", local_error.message(), local_error.code())); + } + + if (error != nullptr) + { + *error = std::move(local_error); } - tr_error_propagate(error, &my_error); return false; } -bool preallocate_file_full(tr_sys_file_t fd, uint64_t length, tr_error** error) +bool preallocate_file_full(tr_sys_file_t fd, uint64_t length, tr_error* error) { - tr_error* my_error = nullptr; - if (length == 0) { return true; } - if (tr_sys_file_preallocate(fd, length, 0, &my_error)) + auto local_error = tr_error{}; + + if (tr_sys_file_preallocate(fd, length, 0, &local_error)) { return true; } - tr_logAddDebug(fmt::format("Full preallocation failed: {} ({})", my_error->message, my_error->code)); + tr_logAddDebug(fmt::format("Full preallocation failed: {} ({})", local_error.message(), local_error.code())); - if (!TR_ERROR_IS_ENOSPC(my_error->code)) + if (!TR_ERROR_IS_ENOSPC(local_error.code())) { auto buf = std::array{}; bool success = true; - tr_error_clear(&my_error); + local_error = {}; /* fallback: the old-fashioned way */ while (success && length > 0) { uint64_t const this_pass = std::min(length, uint64_t{ std::size(buf) }); uint64_t bytes_written = 0; - success = tr_sys_file_write(fd, std::data(buf), this_pass, &bytes_written, &my_error); + success = tr_sys_file_write(fd, std::data(buf), this_pass, &bytes_written, &local_error); length -= bytes_written; } @@ -102,10 +107,14 @@ bool preallocate_file_full(tr_sys_file_t fd, uint64_t length, tr_error** error) return true; } - tr_logAddDebug(fmt::format("Full preallocation fallback failed: {} ({})", my_error->message, my_error->code)); + tr_logAddDebug(fmt::format("Full preallocation fallback failed: {} ({})", local_error.message(), local_error.code())); + } + + if (error != nullptr) + { + *error = std::move(local_error); } - tr_error_propagate(error, &my_error); return false; } @@ -150,7 +159,7 @@ std::optional tr_open_files::get( // create subfolders, if any auto const filename = tr_pathbuf{ filename_in }; - tr_error* error = nullptr; + auto error = tr_error{}; if (writable) { auto dir = tr_pathbuf{ filename.sv() }; @@ -160,9 +169,8 @@ std::optional tr_open_files::get( tr_logAddError(fmt::format( _("Couldn't create '{path}': {error} ({error_code})"), fmt::arg("path", dir), - fmt::arg("error", error->message), - fmt::arg("error_code", error->code))); - tr_error_free(error); + fmt::arg("error", error.message()), + fmt::arg("error_code", error.code()))); return {}; } } @@ -183,9 +191,8 @@ std::optional tr_open_files::get( tr_logAddError(fmt::format( _("Couldn't open '{path}': {error} ({error_code})"), fmt::arg("path", filename), - fmt::arg("error", error->message), - fmt::arg("error_code", error->code))); - tr_error_free(error); + fmt::arg("error", error.message()), + fmt::arg("error_code", error.code()))); return {}; } @@ -212,10 +219,9 @@ std::optional tr_open_files::get( tr_logAddError(fmt::format( _("Couldn't preallocate '{path}': {error} ({error_code})"), fmt::arg("path", filename), - fmt::arg("error", error->message), - fmt::arg("error_code", error->code))); + fmt::arg("error", error.message()), + fmt::arg("error_code", error.code()))); tr_sys_file_close(fd); - tr_error_free(error); return {}; } @@ -232,10 +238,9 @@ std::optional tr_open_files::get( tr_logAddWarn(fmt::format( _("Couldn't truncate '{path}': {error} ({error_code})"), fmt::arg("path", filename), - fmt::arg("error", error->message), - fmt::arg("error_code", error->code))); + fmt::arg("error", error.message()), + fmt::arg("error_code", error.code()))); tr_sys_file_close(fd); - tr_error_free(error); return {}; } diff --git a/libtransmission/peer-io.cc b/libtransmission/peer-io.cc index b63e90407..4bb6a9df1 100644 --- a/libtransmission/peer-io.cc +++ b/libtransmission/peer-io.cc @@ -26,7 +26,7 @@ #include "libtransmission/bandwidth.h" #include "libtransmission/block-info.h" // tr_block_info -#include "libtransmission/error.h" // tr_error_clear, tr_error_s... +#include "libtransmission/error.h" #include "libtransmission/log.h" #include "libtransmission/net.h" #include "libtransmission/peer-io.h" @@ -325,22 +325,20 @@ size_t tr_peerIo::try_write(size_t max) return {}; } - tr_error* error = nullptr; + auto error = tr_error{}; auto const n_written = socket_.try_write(buf, max, &error); // enable further writes if there's more data to write - set_enabled(Dir, !std::empty(buf) && (error == nullptr || canRetryFromError(error->code))); + set_enabled(Dir, !std::empty(buf) && (!error || canRetryFromError(error.code()))); - if (error != nullptr) + if (error) { - if (!canRetryFromError(error->code)) + if (!canRetryFromError(error.code())) { tr_logAddTraceIo( this, - fmt::format("try_write err: wrote:{}, errno:{} ({})", n_written, error->code, error->message)); - call_error_callback(*error); + fmt::format("try_write err: wrote:{}, errno:{} ({})", n_written, error.code(), error.message())); + call_error_callback(error); } - - tr_error_clear(&error); } else if (n_written > 0U) { @@ -450,19 +448,17 @@ size_t tr_peerIo::try_read(size_t max) } auto& buf = inbuf_; - tr_error* error = nullptr; + auto error = tr_error{}; auto const n_read = socket_.try_read(buf, max, std::empty(buf), &error); - set_enabled(Dir, error == nullptr || canRetryFromError(error->code)); + set_enabled(Dir, !error || canRetryFromError(error.code())); - if (error != nullptr) + if (error) { - if (!canRetryFromError(error->code)) + if (!canRetryFromError(error.code())) { - tr_logAddTraceIo(this, fmt::format("try_read err: n_read:{} errno:{} ({})", n_read, error->code, error->message)); - call_error_callback(*error); + tr_logAddTraceIo(this, fmt::format("try_read err: n_read:{} errno:{} ({})", n_read, error.code(), error.message())); + call_error_callback(error); } - - tr_error_clear(&error); } else if (!std::empty(buf)) { @@ -672,10 +668,9 @@ void tr_peerIo::on_utp_state_change(int state) } else if (state == UTP_STATE_EOF) { - tr_error* error = nullptr; - tr_error_set_from_errno(&error, ENOTCONN); - call_error_callback(*error); - tr_error_clear(&error); + auto error = tr_error{}; + error.set_from_errno(ENOTCONN); + call_error_callback(error); } else if (state == UTP_STATE_DESTROYING) { @@ -696,23 +691,24 @@ void tr_peerIo::on_utp_error(int errcode) return; } - tr_error* error = nullptr; + auto error = tr_error{}; switch (errcode) { case UTP_ECONNREFUSED: - tr_error_set_from_errno(&error, ECONNREFUSED); + error.set_from_errno(ECONNREFUSED); break; case UTP_ECONNRESET: - tr_error_set_from_errno(&error, ECONNRESET); + error.set_from_errno(ECONNRESET); break; case UTP_ETIMEDOUT: - tr_error_set_from_errno(&error, ETIMEDOUT); + error.set_from_errno(ETIMEDOUT); break; default: - tr_error_set(&error, errcode, utp_error_code_names[errcode]); + error.set(errcode, utp_error_code_names[errcode]); + break; } - call_error_callback(*error); - tr_error_clear(&error); + + call_error_callback(error); } #endif /* #ifdef WITH_UTP */ diff --git a/libtransmission/peer-socket.cc b/libtransmission/peer-socket.cc index 2bcdb0756..08857e72f 100644 --- a/libtransmission/peer-socket.cc +++ b/libtransmission/peer-socket.cc @@ -71,7 +71,7 @@ void tr_peer_socket::close() handle = {}; } -size_t tr_peer_socket::try_write(OutBuf& buf, size_t max, tr_error** error) const +size_t tr_peer_socket::try_write(OutBuf& buf, size_t max, tr_error* error) const { if (max == size_t{}) { @@ -98,9 +98,9 @@ size_t tr_peer_socket::try_write(OutBuf& buf, size_t max, tr_error** error) cons return static_cast(n_written); } - if (n_written < 0 && error_code != 0) + if (error != nullptr && n_written < 0 && error_code != 0) { - tr_error_set_from_errno(error, error_code); + error->set_from_errno(error_code); } } #endif @@ -108,7 +108,7 @@ size_t tr_peer_socket::try_write(OutBuf& buf, size_t max, tr_error** error) cons return {}; } -size_t tr_peer_socket::try_read(InBuf& buf, size_t max, [[maybe_unused]] bool buf_is_empty, tr_error** error) const +size_t tr_peer_socket::try_read(InBuf& buf, size_t max, [[maybe_unused]] bool buf_is_empty, tr_error* error) const { if (max == size_t{}) { diff --git a/libtransmission/peer-socket.h b/libtransmission/peer-socket.h index 30c3add4d..9bed92163 100644 --- a/libtransmission/peer-socket.h +++ b/libtransmission/peer-socket.h @@ -52,8 +52,8 @@ public: } void close(); - size_t try_read(InBuf& buf, size_t max, bool buf_is_empty, tr_error** error) const; - size_t try_write(OutBuf& buf, size_t max, tr_error** error) const; + size_t try_read(InBuf& buf, size_t max, bool buf_is_empty, tr_error* error) const; + size_t try_write(OutBuf& buf, size_t max, tr_error* error) const; [[nodiscard]] constexpr auto const& socket_address() const noexcept { diff --git a/libtransmission/resume.cc b/libtransmission/resume.cc index 488a22351..72fdfe7cd 100644 --- a/libtransmission/resume.cc +++ b/libtransmission/resume.cc @@ -641,7 +641,7 @@ tr_resume::fields_t loadFromFile(tr_torrent* tor, tr_resume::fields_t fields_to_ auto otop = serde.parse_file(filename); if (!otop) { - tr_logAddDebugTor(tor, fmt::format("Couldn't read '{}': {}", filename, serde.error_->message)); + tr_logAddDebugTor(tor, fmt::format("Couldn't read '{}': {}", filename, serde.error_.message())); return {}; } auto& top = *otop; @@ -919,7 +919,7 @@ void save(tr_torrent* tor) auto serde = tr_variant_serde::benc(); if (!serde.to_file(top, tor->resume_file())) { - tor->error().set_local_error(fmt::format("Unable to save resume file: {:s}", serde.error_->message)); + tor->error().set_local_error(fmt::format("Unable to save resume file: {:s}", serde.error_.message())); } } diff --git a/libtransmission/rpc-server.cc b/libtransmission/rpc-server.cc index 0d7a4b1dc..3151646a2 100644 --- a/libtransmission/rpc-server.cc +++ b/libtransmission/rpc-server.cc @@ -278,10 +278,9 @@ void serve_file(struct evhttp_request* req, tr_rpc_server const* server, std::st auto content = std::vector{}; - if (tr_error* error = nullptr; !tr_file_read(filename, content, &error)) + if (auto error = tr_error{}; !tr_file_read(filename, content, &error)) { - send_simple_response(req, HTTP_NOTFOUND, fmt::format("{} ({})", filename, error->message).c_str()); - tr_error_free(error); + send_simple_response(req, HTTP_NOTFOUND, fmt::format("{} ({})", filename, error.message()).c_str()); return; } diff --git a/libtransmission/rpcimpl.cc b/libtransmission/rpcimpl.cc index 1b842f338..827293e37 100644 --- a/libtransmission/rpcimpl.cc +++ b/libtransmission/rpcimpl.cc @@ -1312,16 +1312,15 @@ void onBlocklistFetched(tr_web::FetchResponse const& web_response) // tr_blocklistSetContent needs a source file, // so save content into a tmpfile auto const filename = tr_pathbuf{ session->configDir(), "/blocklist.tmp"sv }; - if (tr_error* error = nullptr; !tr_file_save(filename, content, &error)) + if (auto error = tr_error{}; !tr_file_save(filename, content, &error)) { tr_idle_function_done( data, fmt::format( _("Couldn't save '{path}': {error} ({error_code})"), fmt::arg("path", filename), - fmt::arg("error", error->message), - fmt::arg("error_code", error->code))); - tr_error_clear(&error); + fmt::arg("error", error.message()), + fmt::arg("error_code", error.code()))); return; } @@ -2262,10 +2261,9 @@ char const* freeSpace(tr_session* /*session*/, tr_variant* args_in, tr_variant* /* get the free space */ auto const old_errno = errno; - tr_error* error = nullptr; + auto error = tr_error{}; auto const capacity = tr_sys_path_get_capacity(path, &error); - char const* const err = error != nullptr ? tr_strerror(error->code) : nullptr; - tr_error_clear(&error); + char const* const err = error ? tr_strerror(error.code()) : nullptr; errno = old_errno; /* response */ diff --git a/libtransmission/session-id.cc b/libtransmission/session-id.cc index 742a54d75..50a9f078b 100644 --- a/libtransmission/session-id.cc +++ b/libtransmission/session-id.cc @@ -43,7 +43,7 @@ tr_sys_file_t create_lockfile(std::string_view session_id) auto lockfile_path = tr_pathbuf{}; get_lockfile_path(session_id, lockfile_path); - tr_error* error = nullptr; + auto error = tr_error{}; auto lockfile_fd = tr_sys_file_open(lockfile_path, TR_SYS_FILE_READ | TR_SYS_FILE_WRITE | TR_SYS_FILE_CREATE, 0600, &error); if (lockfile_fd != TR_BAD_SYS_FILE) @@ -62,14 +62,13 @@ tr_sys_file_t create_lockfile(std::string_view session_id) } } - if (error != nullptr) + if (error) { tr_logAddWarn(fmt::format( _("Couldn't create '{path}': {error} ({error_code})"), fmt::arg("path", lockfile_path), - fmt::arg("error", error->message), - fmt::arg("error_code", error->code))); - tr_error_free(error); + fmt::arg("error", error.message()), + fmt::arg("error_code", error.code()))); } return lockfile_fd; @@ -126,33 +125,32 @@ bool tr_session_id::is_local(std::string_view session_id) noexcept auto is_local = bool{ false }; auto lockfile_path = tr_pathbuf{}; get_lockfile_path(session_id, lockfile_path); - tr_error* error = nullptr; + auto error = tr_error{}; if (auto lockfile_fd = tr_sys_file_open(lockfile_path, TR_SYS_FILE_READ, 0, &error); lockfile_fd == TR_BAD_SYS_FILE) { - if (TR_ERROR_IS_ENOENT(error->code)) + if (TR_ERROR_IS_ENOENT(error.code())) { - tr_error_clear(&error); + error = {}; } } else { - if (!tr_sys_file_lock(lockfile_fd, TR_SYS_FILE_LOCK_SH | TR_SYS_FILE_LOCK_NB, &error) && (error->code == WouldBlock)) + if (!tr_sys_file_lock(lockfile_fd, TR_SYS_FILE_LOCK_SH | TR_SYS_FILE_LOCK_NB, &error) && (error.code() == WouldBlock)) { is_local = true; - tr_error_clear(&error); + error = {}; } tr_sys_file_close(lockfile_fd); } - if (error != nullptr) + if (error) { tr_logAddWarn(fmt::format( _("Couldn't open session lock file '{path}': {error} ({error_code})"), fmt::arg("path", lockfile_path), - fmt::arg("error", error->message), - fmt::arg("error_code", error->code))); - tr_error_free(error); + fmt::arg("error", error.message()), + fmt::arg("error_code", error.code()))); } return is_local; diff --git a/libtransmission/subprocess-posix.cc b/libtransmission/subprocess-posix.cc index 6c99f959c..58b86b041 100644 --- a/libtransmission/subprocess-posix.cc +++ b/libtransmission/subprocess-posix.cc @@ -40,14 +40,12 @@ void handle_sigchld(int /*i*/) /* FIXME: Call old handler, if any */ } -void set_system_error(tr_error** error, int code, std::string_view what) +void set_system_error(tr_error* error, int code, std::string_view what) { - if (error == nullptr) + if (error != nullptr) { - return; + error->set(code, fmt::format(FMT_STRING("{:s} failed: {:s} ({:d})"), what, tr_strerror(code), code)); } - - tr_error_set(error, code, fmt::format(FMT_STRING("{:s} failed: {:s} ({:d})"), what, tr_strerror(code), code)); } [[nodiscard]] bool tr_spawn_async_in_child( @@ -82,7 +80,7 @@ void set_system_error(tr_error** error, int code, std::string_view what) return true; } -[[nodiscard]] bool tr_spawn_async_in_parent(int pipe_fd, tr_error** error) +[[nodiscard]] bool tr_spawn_async_in_parent(int pipe_fd, tr_error* error) { int child_errno = 0; ssize_t count = 0; @@ -120,7 +118,7 @@ bool tr_spawn_async( char const* const* cmd, std::map const& env, std::string_view work_dir, - tr_error** error) + tr_error* error) { static bool sigchld_handler_set = false; diff --git a/libtransmission/subprocess-win32.cc b/libtransmission/subprocess-win32.cc index 8626995a6..46b6a45d7 100644 --- a/libtransmission/subprocess-win32.cc +++ b/libtransmission/subprocess-win32.cc @@ -35,7 +35,7 @@ enum class tr_app_type BATCH }; -void set_system_error(tr_error** error, DWORD code, std::string_view what) +void set_system_error(tr_error* error, DWORD code, std::string_view what) { if (error == nullptr) { @@ -44,11 +44,11 @@ void set_system_error(tr_error** error, DWORD code, std::string_view what) if (auto const message = tr_win32_format_message(code); !std::empty(message)) { - tr_error_set(error, code, fmt::format(FMT_STRING("{:s} failed: {:s}"), what, message)); + error->set(code, fmt::format(FMT_STRING("{:s} failed: {:s}"), what, message)); } else { - tr_error_set(error, code, fmt::format(FMT_STRING("{:s} failed: Unknown error: {:#08x}"), what, code)); + error->set(code, fmt::format(FMT_STRING("{:s} failed: Unknown error: {:#08x}"), what, code)); } } @@ -271,7 +271,7 @@ bool tr_spawn_async( char const* const* cmd, std::map const& env, std::string_view work_dir, - tr_error** error) + tr_error* error) { // full_env = current_env + env; auto full_env = get_current_env(); diff --git a/libtransmission/subprocess.h b/libtransmission/subprocess.h index f655e7da4..fc0a0f0df 100644 --- a/libtransmission/subprocess.h +++ b/libtransmission/subprocess.h @@ -14,4 +14,4 @@ bool tr_spawn_async( char const* const* cmd, std::map const& env, std::string_view work_dir, - tr_error** error); + tr_error* error); diff --git a/libtransmission/torrent-ctor.cc b/libtransmission/torrent-ctor.cc index adeeabd9b..472f786e1 100644 --- a/libtransmission/torrent-ctor.cc +++ b/libtransmission/torrent-ctor.cc @@ -84,11 +84,15 @@ tr_torrent::VerifyDoneCallback tr_ctorStealVerifyDoneCallback(tr_ctor* ctor) // --- -bool tr_ctorSetMetainfoFromFile(tr_ctor* ctor, std::string_view filename, tr_error** error) +bool tr_ctorSetMetainfoFromFile(tr_ctor* ctor, std::string_view filename, tr_error* error) { if (std::empty(filename)) { - tr_error_set(error, EINVAL, "no filename specified"sv); + if (error != nullptr) + { + error->set(EINVAL, "no filename specified"sv); + } + return false; } @@ -102,12 +106,12 @@ bool tr_ctorSetMetainfoFromFile(tr_ctor* ctor, std::string_view filename, tr_err return ctor->metainfo.parse_benc(contents_sv, error); } -bool tr_ctorSetMetainfoFromFile(tr_ctor* ctor, char const* filename, tr_error** error) +bool tr_ctorSetMetainfoFromFile(tr_ctor* ctor, char const* filename, tr_error* error) { return tr_ctorSetMetainfoFromFile(ctor, std::string_view{ filename != nullptr ? filename : "" }, error); } -bool tr_ctorSetMetainfo(tr_ctor* ctor, char const* metainfo, size_t len, tr_error** error) +bool tr_ctorSetMetainfo(tr_ctor* ctor, char const* metainfo, size_t len, tr_error* error) { ctor->torrent_filename.clear(); ctor->contents.assign(metainfo, metainfo + len); @@ -115,14 +119,14 @@ bool tr_ctorSetMetainfo(tr_ctor* ctor, char const* metainfo, size_t len, tr_erro return ctor->metainfo.parse_benc(contents_sv, error); } -bool tr_ctorSetMetainfoFromMagnetLink(tr_ctor* ctor, std::string_view magnet_link, tr_error** error) +bool tr_ctorSetMetainfoFromMagnetLink(tr_ctor* ctor, std::string_view magnet_link, tr_error* error) { ctor->torrent_filename.clear(); ctor->metainfo = {}; return ctor->metainfo.parseMagnet(magnet_link, error); } -bool tr_ctorSetMetainfoFromMagnetLink(tr_ctor* ctor, char const* magnet_link, tr_error** error) +bool tr_ctorSetMetainfoFromMagnetLink(tr_ctor* ctor, char const* magnet_link, tr_error* error) { return tr_ctorSetMetainfoFromMagnetLink(ctor, std::string_view{ magnet_link != nullptr ? magnet_link : "" }, error); } @@ -132,14 +136,18 @@ char const* tr_ctorGetSourceFile(tr_ctor const* ctor) return ctor->torrent_filename.c_str(); } -bool tr_ctorSaveContents(tr_ctor const* ctor, std::string_view filename, tr_error** error) +bool tr_ctorSaveContents(tr_ctor const* ctor, std::string_view filename, tr_error* error) { TR_ASSERT(ctor != nullptr); TR_ASSERT(!std::empty(filename)); if (std::empty(ctor->contents)) { - tr_error_set(error, EINVAL, "torrent ctor has no contents to save"sv); + if (error != nullptr) + { + error->set(EINVAL, "torrent ctor has no contents to save"sv); + } + return false; } diff --git a/libtransmission/torrent-files.cc b/libtransmission/torrent-files.cc index 711698c48..677c56cab 100644 --- a/libtransmission/torrent-files.cc +++ b/libtransmission/torrent-files.cc @@ -159,7 +159,7 @@ bool tr_torrent_files::move( std::string_view old_parent_in, std::string_view parent_in, std::string_view parent_name, - tr_error** error) const + tr_error* error) const { auto const old_parent = tr_pathbuf{ old_parent_in }; auto const parent = tr_pathbuf{ parent_in }; diff --git a/libtransmission/torrent-files.h b/libtransmission/torrent-files.h index df875bdee..d7ad0a6c0 100644 --- a/libtransmission/torrent-files.h +++ b/libtransmission/torrent-files.h @@ -114,7 +114,7 @@ public: std::string_view old_parent_in, std::string_view parent_in, std::string_view parent_name = "", - tr_error** error = nullptr) const; + tr_error* error = nullptr) const; using FileFunc = std::function; void remove(std::string_view parent_in, std::string_view tmpdir_prefix, FileFunc const& func) const; diff --git a/libtransmission/torrent-magnet.cc b/libtransmission/torrent-magnet.cc index 7f9ee786d..2871e5be6 100644 --- a/libtransmission/torrent-magnet.cc +++ b/libtransmission/torrent-magnet.cc @@ -128,7 +128,7 @@ bool tr_torrentUseMetainfoFromFile( tr_torrent* tor, tr_torrent_metainfo const* metainfo, char const* filename_in, - tr_error** error) + tr_error* error) { // add .torrent file if (!tr_sys_path_copy(filename_in, tor->torrent_file().c_str(), error)) @@ -202,7 +202,7 @@ tr_variant build_metainfo_except_info_dict(tr_torrent_metainfo const& tm) return tr_variant{ std::move(top) }; } -bool use_new_metainfo(tr_torrent* tor, tr_error** error) +bool use_new_metainfo(tr_torrent* tor, tr_error* error) { auto const& m = tor->incomplete_metadata; TR_ASSERT(m); @@ -218,7 +218,12 @@ bool use_new_metainfo(tr_torrent* tor, tr_error** error) auto info_dict_v = serde.parse(m->metadata); if (!info_dict_v) { - tr_error_propagate(error, &serde.error_); + if (error != nullptr) + { + *error = std::move(serde.error_); + serde.error_ = {}; + } + return false; } @@ -251,7 +256,7 @@ bool use_new_metainfo(tr_torrent* tor, tr_error** error) void on_have_all_metainfo(tr_torrent* tor) { - tr_error* error = nullptr; + auto error = tr_error{}; auto& m = tor->incomplete_metadata; TR_ASSERT(m); if (use_new_metainfo(tor, &error)) @@ -264,7 +269,7 @@ void on_have_all_metainfo(tr_torrent* tor) m->pieces_needed = create_all_needed(n); - char const* const msg = error != nullptr && error->message != nullptr ? error->message : "unknown error"; + auto msg = std::string_view{ error && !std::empty(error.message()) ? error.message() : "unknown error" }; tr_logAddWarnTor( tor, fmt::format( @@ -274,7 +279,6 @@ void on_have_all_metainfo(tr_torrent* tor) n), fmt::arg("error", msg), fmt::arg("piece_count", n))); - tr_error_clear(&error); } } } // namespace set_metadata_piece_helpers diff --git a/libtransmission/torrent-magnet.h b/libtransmission/torrent-magnet.h index 8620f7a7e..58be0499f 100644 --- a/libtransmission/torrent-magnet.h +++ b/libtransmission/torrent-magnet.h @@ -55,8 +55,4 @@ double tr_torrentGetMetadataPercent(tr_torrent const* tor); void tr_torrentMagnetDoIdleWork(tr_torrent* tor); -bool tr_torrentUseMetainfoFromFile( - tr_torrent* tor, - tr_torrent_metainfo const* metainfo, - char const* filename, - tr_error** error); +bool tr_torrentUseMetainfoFromFile(tr_torrent* tor, tr_torrent_metainfo const* metainfo, char const* filename, tr_error* error); diff --git a/libtransmission/torrent-metainfo.cc b/libtransmission/torrent-metainfo.cc index 59a233563..31a1e0bff 100644 --- a/libtransmission/torrent-metainfo.cc +++ b/libtransmission/torrent-metainfo.cc @@ -51,11 +51,6 @@ std::string tr_torrent_metainfo::fix_webseed_url(tr_torrent_metainfo const& tm, namespace { auto constexpr MaxBencDepth = 32; - -bool tr_error_is_set(tr_error const* const* error) -{ - return (error != nullptr) && (*error != nullptr); -} } // namespace struct MetainfoHandler final : public transmission::benc::BasicHandler @@ -368,7 +363,7 @@ struct MetainfoHandler final : public transmission::benc::BasicHandler{}; auto handler = MetainfoHandler{ *this }; - tr_error* my_error = nullptr; - + auto local_error = tr_error{}; if (error == nullptr) { - error = &my_error; + error = &local_error; } + auto const ok = transmission::benc::parse(benc, stack, handler, nullptr, error); - if (tr_error_is_set(error)) + if (*error) { - tr_logAddError(fmt::format("{} ({})", (*error)->message, (*error)->code)); + tr_logAddError(fmt::format("{} ({})", error->message(), error->code())); } - tr_error_clear(&my_error); - if (!ok) { return false; @@ -660,7 +653,7 @@ bool tr_torrent_metainfo::parse_benc(std::string_view benc, tr_error** error) return true; } -bool tr_torrent_metainfo::parse_torrent_file(std::string_view filename, std::vector* contents, tr_error** error) +bool tr_torrent_metainfo::parse_torrent_file(std::string_view filename, std::vector* contents, tr_error* error) { auto local_contents = std::vector{}; diff --git a/libtransmission/torrent-metainfo.h b/libtransmission/torrent-metainfo.h index d8340298c..f555b60e6 100644 --- a/libtransmission/torrent-metainfo.h +++ b/libtransmission/torrent-metainfo.h @@ -28,13 +28,13 @@ public: return std::empty(files_); } - bool parse_benc(std::string_view benc, tr_error** error = nullptr); + bool parse_benc(std::string_view benc, tr_error* error = nullptr); // Helper function wrapper around parseBenc(). // If you're looping through several files, passing in a non-nullptr // `contents` can reduce the number of memory allocations needed to // load multiple files. - bool parse_torrent_file(std::string_view benc_filename, std::vector* contents = nullptr, tr_error** error = nullptr); + bool parse_torrent_file(std::string_view benc_filename, std::vector* contents = nullptr, tr_error* error = nullptr); // FILES @@ -196,7 +196,7 @@ public: private: friend struct MetainfoHandler; - static bool parse_impl(tr_torrent_metainfo& setme, std::string_view benc, tr_error** error); + static bool parse_impl(tr_torrent_metainfo& setme, std::string_view benc, tr_error* error); static std::string fix_webseed_url(tr_torrent_metainfo const& tm, std::string_view url); enum class BasenameFormat diff --git a/libtransmission/torrent.cc b/libtransmission/torrent.cc index 1936b947a..07c6b6c17 100644 --- a/libtransmission/torrent.cc +++ b/libtransmission/torrent.cc @@ -127,18 +127,16 @@ bool tr_torrentSetMetainfoFromFile(tr_torrent* tor, tr_torrent_metainfo const* m return false; } - tr_error* error = nullptr; + auto error = tr_error{}; tr_torrentUseMetainfoFromFile(tor, metainfo, filename, &error); - - if (error != nullptr) + if (error) { tor->error().set_local_error(fmt::format( _("Couldn't use metainfo from '{path}' for '{magnet}': {error} ({error_code})"), fmt::arg("path", filename), fmt::arg("magnet", tor->magnet()), - fmt::arg("error", error->message), - fmt::arg("error_code", error->code))); - tr_error_clear(&error); + fmt::arg("error", error.message()), + fmt::arg("error_code", error.code()))); return false; } @@ -402,8 +400,7 @@ void torrentCallScript(tr_torrent const* tor, std::string const& script) tr_logAddInfoTor(tor, fmt::format(_("Calling script '{path}'"), fmt::arg("path", script))); - tr_error* error = nullptr; - + auto error = tr_error{}; if (!tr_spawn_async(std::data(cmd), env, TR_IF_WIN32("\\", "/"), &error)) { tr_logAddWarnTor( @@ -411,9 +408,8 @@ void torrentCallScript(tr_torrent const* tor, std::string const& script) fmt::format( _("Couldn't call script '{path}': {error} ({error_code})"), fmt::arg("path", script), - fmt::arg("error", error->message), - fmt::arg("error_code", error->code))); - tr_error_free(error); + fmt::arg("error", error.message()), + fmt::arg("error_code", error.code()))); } } } // namespace script_helpers @@ -662,7 +658,7 @@ void torrentStartImpl(tr_torrent* const tor) tor->started_.emit(tor); } -bool removeTorrentFile(char const* filename, void* /*user_data*/, tr_error** error) +bool removeTorrentFile(char const* filename, void* /*user_data*/, tr_error* error) { return tr_sys_path_remove(filename, error); } @@ -1059,7 +1055,7 @@ void tr_torrent::init(tr_ctor const* const ctor) if (is_new_torrent) { - tr_error* error = nullptr; + auto error = tr_error{}; if (has_metainfo()) // torrent file { @@ -1071,14 +1067,13 @@ void tr_torrent::init(tr_ctor const* const ctor) tr_file_save(filename, magnet_link, &error); } - if (error != nullptr) + if (error) { this->error().set_local_error(fmt::format( _("Couldn't save '{path}': {error} ({error_code})"), fmt::arg("path", filename), - fmt::arg("error", error->message), - fmt::arg("error_code", error->code))); - tr_error_clear(&error); + fmt::arg("error", error.message()), + fmt::arg("error_code", error.code()))); } } @@ -1173,18 +1168,17 @@ void setLocationInSessionThread(tr_torrent* tor, std::string const& path, bool m tor->session->closeTorrentFiles(tor); tor->session->verify_remove(tor); - tr_error* error = nullptr; + auto error = tr_error{}; ok = tor->metainfo_.files().move(tor->current_dir(), path, tor->name(), &error); - if (error != nullptr) + if (error) { tor->error().set_local_error(fmt::format( _("Couldn't move '{old_path}' to '{path}': {error} ({error_code})"), fmt::arg("old_path", tor->current_dir()), fmt::arg("path", path), - fmt::arg("error", error->message), - fmt::arg("error_code", error->code))); + fmt::arg("error", error.message()), + fmt::arg("error_code", error.code()))); tr_torrentStop(tor); - tr_error_clear(&error); } } @@ -2029,15 +2023,14 @@ bool tr_torrent::set_tracker_list(std::string_view text) { auto const magnet_file = this->magnet_file(); auto const magnet_link = this->magnet(); - tr_error* save_error = nullptr; + auto save_error = tr_error{}; if (!tr_file_save(magnet_file, magnet_link, &save_error)) { this->error().set_local_error(fmt::format( _("Couldn't save '{path}': {error} ({error_code})"), fmt::arg("path", magnet_file), - fmt::arg("error", save_error->message), - fmt::arg("error_code", save_error->code))); - tr_error_clear(&save_error); + fmt::arg("error", save_error.message()), + fmt::arg("error_code", save_error.code()))); } } @@ -2194,7 +2187,7 @@ void onFileCompleted(tr_torrent* tor, tr_file_index_t i) { auto const& oldpath = found->filename(); auto const newpath = tr_pathbuf{ found->base(), '/', file_subpath }; - tr_error* error = nullptr; + auto error = tr_error{}; if (!tr_sys_path_rename(oldpath, newpath, &error)) { @@ -2204,9 +2197,8 @@ void onFileCompleted(tr_torrent* tor, tr_file_index_t i) _("Couldn't move '{old_path}' to '{path}': {error} ({error_code})"), fmt::arg("old_path", oldpath), fmt::arg("path", newpath), - fmt::arg("error", error->message), - fmt::arg("error_code", error->code))); - tr_error_free(error); + fmt::arg("error", error.message()), + fmt::arg("error_code", error.code()))); } } } @@ -2429,14 +2421,11 @@ int renamePath(tr_torrent const* tor, std::string_view oldpath, std::string_view if (!tgt_exists) { - tr_error* error = nullptr; - tmp = errno; - if (!tr_sys_path_rename(src, tgt, &error)) + if (auto error = tr_error{}; !tr_sys_path_rename(src, tgt, &error)) { - err = error->code; - tr_error_free(error); + err = error.code(); } errno = tmp; diff --git a/libtransmission/torrent.h b/libtransmission/torrent.h index 000ed674f..65f9fb4bd 100644 --- a/libtransmission/torrent.h +++ b/libtransmission/torrent.h @@ -54,7 +54,7 @@ void tr_ctorInitTorrentPriorities(tr_ctor const* ctor, tr_torrent* tor); void tr_ctorInitTorrentWanted(tr_ctor const* ctor, tr_torrent* tor); -bool tr_ctorSaveContents(tr_ctor const* ctor, std::string_view filename, tr_error** error); +bool tr_ctorSaveContents(tr_ctor const* ctor, std::string_view filename, tr_error* error); tr_session* tr_ctorGetSession(tr_ctor const* ctor); @@ -1223,8 +1223,8 @@ void tr_torrentGotBlock(tr_torrent* tor, tr_block_index_t block); tr_torrent_metainfo tr_ctorStealMetainfo(tr_ctor* ctor); -bool tr_ctorSetMetainfoFromFile(tr_ctor* ctor, std::string_view filename, tr_error** error = nullptr); -bool tr_ctorSetMetainfoFromMagnetLink(tr_ctor* ctor, std::string_view magnet_link, tr_error** error = nullptr); +bool tr_ctorSetMetainfoFromFile(tr_ctor* ctor, std::string_view filename, tr_error* error = nullptr); +bool tr_ctorSetMetainfoFromMagnetLink(tr_ctor* ctor, std::string_view magnet_link, tr_error* error = nullptr); void tr_ctorSetLabels(tr_ctor* ctor, tr_torrent::labels_t&& labels); void tr_ctorSetBandwidthPriority(tr_ctor* ctor, tr_priority_t priority); tr_priority_t tr_ctorGetBandwidthPriority(tr_ctor const* ctor); diff --git a/libtransmission/tr-buffer.h b/libtransmission/tr-buffer.h index 7382d4dc5..e16b4f65b 100644 --- a/libtransmission/tr-buffer.h +++ b/libtransmission/tr-buffer.h @@ -100,7 +100,7 @@ public: } // Returns the number of bytes written. Check `error` for error. - size_t to_socket(tr_socket_t sockfd, size_t n_bytes, tr_error** error = nullptr) + size_t to_socket(tr_socket_t sockfd, size_t n_bytes, tr_error* error = nullptr) { n_bytes = std::min(n_bytes, size()); @@ -115,8 +115,12 @@ public: return n_sent; } - auto const err = sockerrno; - tr_error_set(error, err, tr_net_strerror(err)); + if (error != nullptr) + { + auto const err = sockerrno; + error->set(err, tr_net_strerror(err)); + } + return {}; } @@ -210,7 +214,7 @@ public: } } - size_t add_socket(tr_socket_t sockfd, size_t n_bytes, tr_error** error = nullptr) + size_t add_socket(tr_socket_t sockfd, size_t n_bytes, tr_error* error = nullptr) { auto const [buf, buflen] = reserve_space(n_bytes); auto const n_read = recv(sockfd, reinterpret_cast(buf), std::min(n_bytes, buflen), 0); @@ -224,13 +228,16 @@ public: // When a stream socket peer has performed an orderly shutdown, // the return value will be 0 (the traditional "end-of-file" return). - if (n_read == 0) + if (error != nullptr) { - tr_error_set_from_errno(error, ENOTCONN); - } - else - { - tr_error_set(error, err, tr_net_strerror(err)); + if (n_read == 0) + { + error->set_from_errno(ENOTCONN); + } + else + { + error->set(err, tr_net_strerror(err)); + } } return {}; diff --git a/libtransmission/transmission.h b/libtransmission/transmission.h index 1b5ed6263..3495eb3a6 100644 --- a/libtransmission/transmission.h +++ b/libtransmission/transmission.h @@ -764,15 +764,15 @@ bool tr_ctorGetDeleteSource(tr_ctor const* ctor, bool* setme_do_delete); void tr_ctorSetDeleteSource(tr_ctor* ctor, bool delete_source); /** @brief Set the constructor's metainfo from a magnet link */ -bool tr_ctorSetMetainfoFromMagnetLink(tr_ctor* ctor, char const* magnet, tr_error** error); +bool tr_ctorSetMetainfoFromMagnetLink(tr_ctor* ctor, char const* magnet, tr_error* error); tr_torrent_metainfo const* tr_ctorGetMetainfo(tr_ctor const* ctor); /** @brief Set the constructor's metainfo from a raw benc already in memory */ -bool tr_ctorSetMetainfo(tr_ctor* ctor, char const* metainfo, size_t len, tr_error** error); +bool tr_ctorSetMetainfo(tr_ctor* ctor, char const* metainfo, size_t len, tr_error* error); /** @brief Set the constructor's metainfo from a local torrent file */ -bool tr_ctorSetMetainfoFromFile(tr_ctor* ctor, char const* filename, tr_error** error); +bool tr_ctorSetMetainfoFromFile(tr_ctor* ctor, char const* filename, tr_error* error); /** @brief Get this peer constructor's peer limit */ bool tr_ctorGetPeerLimit(tr_ctor const* ctor, tr_ctorMode mode, uint16_t* setme_count); @@ -841,7 +841,7 @@ tr_torrent* tr_torrentNew(tr_ctor* ctor, tr_torrent** setme_duplicate_of); /** @addtogroup tr_torrent Torrents @{ */ -using tr_fileFunc = bool (*)(char const* filename, void* user_data, struct tr_error** error); +using tr_fileFunc = bool (*)(char const* filename, void* user_data, tr_error* error); /** @brief Removes our torrent and .resume files for this torrent */ void tr_torrentRemove(tr_torrent* torrent, bool delete_flag, tr_fileFunc delete_func, void* user_data); diff --git a/libtransmission/utils.cc b/libtransmission/utils.cc index 065efc1de..697b2f5ed 100644 --- a/libtransmission/utils.cc +++ b/libtransmission/utils.cc @@ -93,54 +93,56 @@ std::optional tr_locale_set_global(std::locale const& locale) noexc // --- -bool tr_file_read(std::string_view filename, std::vector& contents, tr_error** error) +bool tr_file_read(std::string_view filename, std::vector& contents, tr_error* error) { auto const szfilename = tr_pathbuf{ filename }; /* try to stat the file */ - tr_error* my_error = nullptr; - auto const info = tr_sys_path_get_info(szfilename, 0, &my_error); - if (my_error != nullptr) + auto local_error = tr_error{}; + if (error == nullptr) + { + error = &local_error; + } + + auto const info = tr_sys_path_get_info(szfilename, 0, error); + if (*error) { tr_logAddError(fmt::format( _("Couldn't read '{path}': {error} ({error_code})"), fmt::arg("path", filename), - fmt::arg("error", my_error->message), - fmt::arg("error_code", my_error->code))); - tr_error_propagate(error, &my_error); + fmt::arg("error", error->message()), + fmt::arg("error_code", error->code()))); return false; } if (!info || !info->isFile()) { tr_logAddError(fmt::format(_("Couldn't read '{path}': Not a regular file"), fmt::arg("path", filename))); - tr_error_set(error, TR_ERROR_EISDIR, "Not a regular file"sv); + error->set(TR_ERROR_EISDIR, "Not a regular file"sv); return false; } /* Load the torrent file into our buffer */ - auto const fd = tr_sys_file_open(szfilename, TR_SYS_FILE_READ | TR_SYS_FILE_SEQUENTIAL, 0, &my_error); + auto const fd = tr_sys_file_open(szfilename, TR_SYS_FILE_READ | TR_SYS_FILE_SEQUENTIAL, 0, error); if (fd == TR_BAD_SYS_FILE) { tr_logAddError(fmt::format( _("Couldn't read '{path}': {error} ({error_code})"), fmt::arg("path", filename), - fmt::arg("error", my_error->message), - fmt::arg("error_code", my_error->code))); - tr_error_propagate(error, &my_error); + fmt::arg("error", error->message()), + fmt::arg("error_code", error->code()))); return false; } contents.resize(info->size); - if (!tr_sys_file_read(fd, std::data(contents), info->size, nullptr, &my_error)) + if (!tr_sys_file_read(fd, std::data(contents), info->size, nullptr, error)) { tr_logAddError(fmt::format( _("Couldn't read '{path}': {error} ({error_code})"), fmt::arg("path", filename), - fmt::arg("error", my_error->message), - fmt::arg("error_code", my_error->code))); + fmt::arg("error", error->message()), + fmt::arg("error_code", error->code()))); tr_sys_file_close(fd); - tr_error_propagate(error, &my_error); return false; } @@ -148,7 +150,7 @@ bool tr_file_read(std::string_view filename, std::vector& contents, tr_err return true; } -bool tr_file_save(std::string_view filename, std::string_view contents, tr_error** error) +bool tr_file_save(std::string_view filename, std::string_view contents, tr_error* error) { // follow symlinks to find the "real" file, to make sure the temporary // we build with tr_sys_file_open_temp() is created on the right partition @@ -561,21 +563,27 @@ std::string tr_strratio(double ratio, char const* infinity) // --- -bool tr_file_move(std::string_view oldpath_in, std::string_view newpath_in, tr_error** error) +bool tr_file_move(std::string_view oldpath_in, std::string_view newpath_in, tr_error* error) { auto const oldpath = tr_pathbuf{ oldpath_in }; auto const newpath = tr_pathbuf{ newpath_in }; + auto local_error = tr_error{}; + if (error == nullptr) + { + error = &local_error; + } + // make sure the old file exists auto const info = tr_sys_path_get_info(oldpath, 0, error); if (!info) { - tr_error_prefix(error, "Unable to get information on old file: "); + error->prefix_message("Unable to get information on old file: "); return false; } if (!info->isFile()) { - tr_error_set(error, TR_ERROR_EINVAL, "Old path does not point to a file."sv); + error->set(TR_ERROR_EINVAL, "Old path does not point to a file."sv); return false; } @@ -584,7 +592,7 @@ bool tr_file_move(std::string_view oldpath_in, std::string_view newpath_in, tr_e newdir.popdir(); if (!tr_sys_dir_create(newdir, TR_SYS_DIR_CREATE_PARENTS, 0777, error)) { - tr_error_prefix(error, "Unable to create directory for new file: "); + error->prefix_message("Unable to create directory for new file: "); return false; } @@ -597,18 +605,17 @@ bool tr_file_move(std::string_view oldpath_in, std::string_view newpath_in, tr_e /* Otherwise, copy the file. */ if (!tr_sys_path_copy(oldpath, newpath, error)) { - tr_error_prefix(error, "Unable to copy: "); + error->prefix_message("Unable to copy: "); return false; } - if (tr_error* my_error = nullptr; !tr_sys_path_remove(oldpath, &my_error)) + if (auto log_error = tr_error{}; !tr_sys_path_remove(oldpath, &log_error)) { tr_logAddError(fmt::format( _("Couldn't remove '{path}': {error} ({error_code})"), fmt::arg("path", oldpath), - fmt::arg("error", my_error->message), - fmt::arg("error_code", my_error->code))); - tr_error_free(my_error); + fmt::arg("error", log_error.message()), + fmt::arg("error_code", log_error.code()))); } return true; diff --git a/libtransmission/utils.h b/libtransmission/utils.h index 4c5351445..d31590e08 100644 --- a/libtransmission/utils.h +++ b/libtransmission/utils.h @@ -63,14 +63,14 @@ std::optional tr_locale_set_global(std::locale const& locale) noexc [[nodiscard]] std::string_view tr_get_mime_type_for_filename(std::string_view filename); -bool tr_file_read(std::string_view filename, std::vector& contents, tr_error** error = nullptr); +bool tr_file_read(std::string_view filename, std::vector& contents, tr_error* error = nullptr); -bool tr_file_move(std::string_view oldpath, std::string_view newpath, struct tr_error** error = nullptr); +bool tr_file_move(std::string_view oldpath, std::string_view newpath, tr_error* error = nullptr); -bool tr_file_save(std::string_view filename, std::string_view contents, tr_error** error = nullptr); +bool tr_file_save(std::string_view filename, std::string_view contents, tr_error* error = nullptr); template -constexpr auto tr_file_save(std::string_view filename, ContiguousRange const& x, tr_error** error = nullptr) +constexpr auto tr_file_save(std::string_view filename, ContiguousRange const& x, tr_error* error = nullptr) { return tr_file_save(filename, std::string_view{ std::data(x), std::size(x) }, error); } diff --git a/libtransmission/variant-json.cc b/libtransmission/variant-json.cc index 580457942..effe3a701 100644 --- a/libtransmission/variant-json.cc +++ b/libtransmission/variant-json.cc @@ -239,13 +239,12 @@ std::optional tr_variant_serde::parse_json(std::string_view input) if (auto err_code = reader.GetParseErrorCode(); err_code == rapidjson::kParseErrorDocumentEmpty) { - tr_error_set(&error_, EINVAL, "No content"); + error_.set(EINVAL, "No content"); } else { auto const err_offset = reader.GetErrorOffset(); - tr_error_set( - &error_, + error_.set( EILSEQ, fmt::format( _("Couldn't parse JSON at position {position} '{text}': {error} ({error_code})"), diff --git a/libtransmission/variant.cc b/libtransmission/variant.cc index 723e35fd0..975e4f134 100644 --- a/libtransmission/variant.cc +++ b/libtransmission/variant.cc @@ -850,14 +850,9 @@ void tr_variantMergeDicts(tr_variant* const tgt, tr_variant const* const src) // --- -tr_variant_serde::~tr_variant_serde() -{ - tr_error_clear(&error_); -} - std::optional tr_variant_serde::parse(std::string_view input) { - tr_error_clear(&error_); + error_ = {}; return type_ == Type::Json ? parse_json(input) : parse_benc(input); } @@ -883,13 +878,13 @@ bool tr_variant_serde::to_file(tr_variant const& var, std::string_view filename) { tr_file_save(filename, to_string(var), &error_); - if (error_ != nullptr) + if (error_) { tr_logAddError(fmt::format( _("Couldn't save '{path}': {error} ({error_code})"), fmt::arg("path", filename), - fmt::arg("error", error_->message), - fmt::arg("error_code", error_->code))); + fmt::arg("error", error_.message()), + fmt::arg("error_code", error_.code()))); return false; } diff --git a/libtransmission/variant.h b/libtransmission/variant.h index aa9cbbfc9..fb72fab7c 100644 --- a/libtransmission/variant.h +++ b/libtransmission/variant.h @@ -16,11 +16,10 @@ #include #include +#include "libtransmission/error.h" #include "libtransmission/quark.h" #include "libtransmission/tr-macros.h" // TR_CONSTEXPR20 -struct tr_error; - /** * A variant that holds typical benc/json types: bool, int, * double, string, vectors of variants, and maps of variants. @@ -274,8 +273,8 @@ public: { if constexpr (std::is_same_v) { - auto const* const str = std::get_if(&val_); - return str != nullptr ? &str->sv_ : nullptr; + auto const* const val = std::get_if(&val_); + return val != nullptr ? &val->sv_ : nullptr; } else { @@ -294,8 +293,8 @@ public: { if constexpr (Index == StringIndex) { - auto const* const str = std::get_if(&val_); - return str != nullptr ? &str->sv_ : nullptr; + auto const* const val = std::get_if(&val_); + return val != nullptr ? &val->sv_ : nullptr; } else { @@ -468,8 +467,6 @@ void tr_variantMergeDicts(tr_variant* tgt, tr_variant const* src); class tr_variant_serde { public: - ~tr_variant_serde(); - [[nodiscard]] static tr_variant_serde benc() noexcept { return tr_variant_serde{ Type::Benc }; @@ -523,7 +520,7 @@ public: // --- // Tracks errors when parsing / saving - tr_error* error_ = nullptr; + tr_error error_ = {}; private: friend tr_variant; diff --git a/libtransmission/watchdir.cc b/libtransmission/watchdir.cc index ab1738ab8..76471a01c 100644 --- a/libtransmission/watchdir.cc +++ b/libtransmission/watchdir.cc @@ -44,20 +44,15 @@ namespace { auto const path = tr_pathbuf{ dir, '/', name }; - tr_error* error = nullptr; + auto error = tr_error{}; auto const info = tr_sys_path_get_info(path, 0, &error); - if (error != nullptr) + if (error && !TR_ERROR_IS_ENOENT(error.code())) { - if (!TR_ERROR_IS_ENOENT(error->code)) - { - tr_logAddWarn(fmt::format( - _("Skipping '{path}': {error} ({error_code})"), - fmt::arg("path", path), - fmt::arg("error", error->message), - fmt::arg("error_code", error->code))); - } - - tr_error_free(error); + tr_logAddWarn(fmt::format( + _("Skipping '{path}': {error} ({error_code})"), + fmt::arg("path", path), + fmt::arg("error", error.message()), + fmt::arg("error_code", error.code()))); } return info && info->isFile(); @@ -110,21 +105,20 @@ void BaseWatchdir::processFile(std::string_view basename) void BaseWatchdir::scan() { - tr_error* error = nullptr; + auto error = tr_error{}; for (auto const& file : tr_sys_dir_get_files(dirname_, tr_basename_is_not_dotfile, &error)) { processFile(file); } - if (error != nullptr) + if (error) { tr_logAddWarn(fmt::format( _("Couldn't read '{path}': {error} ({error_code})"), fmt::arg("path", dirname()), - fmt::arg("error", error->message), - fmt::arg("error_code", error->code))); - tr_error_free(error); + fmt::arg("error", error.message()), + fmt::arg("error_code", error.code()))); } } diff --git a/macosx/CreatorWindowController.mm b/macosx/CreatorWindowController.mm index 23c9b2405..f4f662628 100644 --- a/macosx/CreatorWindowController.mm +++ b/macosx/CreatorWindowController.mm @@ -44,7 +44,7 @@ typedef NS_ENUM(NSUInteger, TrackerSegmentTag) { @property(nonatomic, readonly) std::shared_ptr fBuilder; @property(nonatomic, readonly) NSURL* fPath; -@property(nonatomic) std::shared_future fFuture; +@property(nonatomic) std::shared_future fFuture; @property(nonatomic) NSURL* fLocation; // path to new torrent file @property(nonatomic) NSMutableArray* fTrackers; @@ -667,13 +667,13 @@ NSMutableSet* creatorWindowControllerSet = nil; [self.fTimer invalidate]; self.fTimer = nil; - tr_error* error = self.fFuture.get(); - if (error == nullptr) + auto error = self.fFuture.get(); + if (!error) { self.fBuilder->save(self.fLocation.path.UTF8String, &error); } - if (error != nullptr) + if (error) { auto* const alert = [[NSAlert alloc] init]; [alert addButtonWithTitle:NSLocalizedString(@"OK", "Create torrent -> failed -> button")]; @@ -681,11 +681,11 @@ NSMutableSet* creatorWindowControllerSet = nil; self.fLocation.lastPathComponent]; alert.alertStyle = NSAlertStyleWarning; - alert.informativeText = [NSString stringWithFormat:@"%s (%d)", error->message, error->code]; + alert.informativeText = [NSString + stringWithFormat:@"%.*s (%d)", static_cast(std::size(error.message())), std::data(error.message()), error.code()]; [alert beginSheetModalForWindow:self.window completionHandler:^(NSModalResponse /*returnCode*/) { [self.window close]; }]; - tr_error_free(error); } else { diff --git a/macosx/Torrent.mm b/macosx/Torrent.mm index 6de82b6b2..ff9aeaf17 100644 --- a/macosx/Torrent.mm +++ b/macosx/Torrent.mm @@ -76,7 +76,7 @@ void renameCallback(tr_torrent* /*torrent*/, char const* oldPathCharString, char } } -bool trashDataFile(char const* filename, void* /*user_data*/, tr_error** error) +bool trashDataFile(char const* filename, void* /*user_data*/, tr_error* error) { if (filename == NULL) { @@ -88,7 +88,7 @@ bool trashDataFile(char const* filename, void* /*user_data*/, tr_error** error) NSError* localError; if (![Torrent trashFile:@(filename) error:&localError]) { - tr_error_set(error, localError.code, localError.description.UTF8String); + error->set(localError.code, localError.description.UTF8String); return false; } } diff --git a/qt/MakeDialog.cc b/qt/MakeDialog.cc index 385e3d572..ab253c0d6 100644 --- a/qt/MakeDialog.cc +++ b/qt/MakeDialog.cc @@ -38,7 +38,7 @@ public: MakeProgressDialog( Session& session, tr_metainfo_builder& builder, - std::future future, + std::future future, QString outfile, QWidget* parent = nullptr); @@ -49,7 +49,7 @@ private slots: private: Session& session_; tr_metainfo_builder& builder_; - std::future future_; + std::future future_; QString const outfile_; Ui::MakeProgressDialog ui_ = {}; QTimer timer_; @@ -60,7 +60,7 @@ private: MakeProgressDialog::MakeProgressDialog( Session& session, tr_metainfo_builder& builder, - std::future future, + std::future future, QString outfile, QWidget* parent) : BaseDialog{ parent } @@ -128,22 +128,22 @@ void MakeProgressDialog::onProgress() } else { - tr_error* error = future_.get(); + auto error = future_.get(); - if (error == nullptr) + if (!error) { builder_.save(outfile_.toStdString(), &error); } - if (error == nullptr) + if (!error) { str = tr("Created \"%1\"!").arg(base); success = true; } else { - str = tr("Couldn't create \"%1\": %2 (%3)").arg(base).arg(QString::fromUtf8(error->message)).arg(error->code); - tr_error_free(error); + auto err_msg = QString::fromUtf8(std::data(error.message()), std::size(error.message())); + str = tr("Couldn't create \"%1\": %2 (%3)").arg(base).arg(err_msg).arg(error.code()); } } diff --git a/tests/libtransmission/announce-list-test.cc b/tests/libtransmission/announce-list-test.cc index 2b9263088..5707c54c2 100644 --- a/tests/libtransmission/announce-list-test.cc +++ b/tests/libtransmission/announce-list-test.cc @@ -356,11 +356,11 @@ TEST_F(AnnounceListTest, save) auto constexpr* const OriginalFile = LIBTRANSMISSION_TEST_ASSETS_DIR "/Android-x86 8.1 r6 iso.torrent"; auto original_content = std::vector{}; auto const test_file = tr_pathbuf{ ::testing::TempDir(), "transmission-announce-list-test.torrent"sv }; - tr_error* error = nullptr; + auto error = tr_error{}; EXPECT_TRUE(tr_file_read(OriginalFile, original_content, &error)); - EXPECT_EQ(nullptr, error) << *error; + EXPECT_FALSE(error) << error; EXPECT_TRUE(tr_file_save(test_file.sv(), original_content, &error)); - EXPECT_EQ(nullptr, error) << *error; + EXPECT_FALSE(error) << error; // make an announce_list for it auto announce_list = tr_announce_list(); @@ -370,13 +370,13 @@ TEST_F(AnnounceListTest, save) // try saving to a nonexistent torrent file EXPECT_FALSE(announce_list.save("/this/path/does/not/exist", &error)); - EXPECT_NE(nullptr, error); - EXPECT_NE(0, error->code); - tr_error_clear(&error); + EXPECT_TRUE(error); + EXPECT_NE(0, error.code()); + error = {}; // now save to a real torrent file EXPECT_TRUE(announce_list.save(std::string{ test_file.sv() }, &error)); - EXPECT_EQ(nullptr, error) << *error; + EXPECT_FALSE(error) << error; // load the original auto original_tm = tr_torrent_metainfo{}; diff --git a/tests/libtransmission/benc-test.cc b/tests/libtransmission/benc-test.cc index 7f66bba82..a21214eb6 100644 --- a/tests/libtransmission/benc-test.cc +++ b/tests/libtransmission/benc-test.cc @@ -26,14 +26,10 @@ TEST_F(BencTest, MalformedBenc) auto stack = transmission::benc::ParserStack{}; auto handler = TestHandler{}; - tr_error* error = nullptr; + auto error = tr_error{}; EXPECT_FALSE(transmission::benc::parse(Benc, stack, handler, nullptr, &error)); - EXPECT_NE(nullptr, error); - if (error != nullptr) - { - EXPECT_NE(nullptr, error->message); - } - tr_error_clear(&error); + EXPECT_TRUE(error); + EXPECT_NE(""sv, error.message()); } TEST_F(BencTest, ContextTokenIsCorrect) @@ -98,6 +94,7 @@ TEST_F(BencTest, ContextTokenIsCorrect) auto stack = transmission::benc::ParserStack{}; auto handler = ContextHandler{}; - tr_error* error = nullptr; + auto error = tr_error{}; transmission::benc::parse(Benc, stack, handler, nullptr, &error); + EXPECT_FALSE(error); } diff --git a/tests/libtransmission/copy-test.cc b/tests/libtransmission/copy-test.cc index e6f285223..1dd6d0dac 100644 --- a/tests/libtransmission/copy-test.cc +++ b/tests/libtransmission/copy-test.cc @@ -36,11 +36,10 @@ protected: auto const path2 = tr_pathbuf{ sandboxDir(), '/', filename2 }; - tr_error* err = nullptr; /* Copy it. */ - EXPECT_TRUE(tr_sys_path_copy(path1, path2, &err)); - EXPECT_EQ(nullptr, err) << ' ' << *err; - tr_error_clear(&err); + auto error = tr_error{}; + EXPECT_TRUE(tr_sys_path_copy(path1, path2, &error)); + EXPECT_FALSE(error) << error; EXPECT_TRUE(filesAreIdentical(path1, path2)); diff --git a/tests/libtransmission/error-test.cc b/tests/libtransmission/error-test.cc index 6056e550d..db32f959d 100644 --- a/tests/libtransmission/error-test.cc +++ b/tests/libtransmission/error-test.cc @@ -15,40 +15,23 @@ using namespace std::literals; TEST(Error, errorSet) { - tr_error* err = nullptr; + auto error = tr_error{}; - tr_error_prefix(&err, "error: "); - EXPECT_EQ(nullptr, err) << *err; + EXPECT_FALSE(error) << error; + EXPECT_FALSE(error.has_value()) << error; + error.set(2, "oops"sv); + EXPECT_TRUE(error); + EXPECT_TRUE(error.has_value()) << error; + EXPECT_EQ(2, error.code()); + EXPECT_EQ("oops"sv, error.message()); - tr_error_set(&err, 2, "oops"sv); - EXPECT_NE(nullptr, err); - EXPECT_EQ(2, err->code); - EXPECT_STREQ("oops", err->message); + error.prefix_message("error: "); + EXPECT_TRUE(error); + EXPECT_TRUE(error.has_value()) << error; + EXPECT_EQ(2, error.code()); + EXPECT_EQ("error: oops"sv, error.message()); - tr_error_prefix(&err, "error: "); - EXPECT_NE(nullptr, err); - EXPECT_EQ(2, err->code); - EXPECT_STREQ("error: oops", err->message); - - tr_error_free(err); -} - -TEST(Error, propagate) -{ - tr_error* err = nullptr; - tr_error* err2 = nullptr; - auto constexpr Code = int{ 1 }; - - tr_error_set(&err, Code, "oops"sv); - EXPECT_NE(nullptr, err); - EXPECT_EQ(Code, err->code); - EXPECT_STREQ("oops", err->message); - - tr_error_propagate(&err2, &err); - EXPECT_NE(nullptr, err2); - EXPECT_EQ(Code, err2->code); - EXPECT_STREQ("oops", err2->message); - EXPECT_EQ(nullptr, err) << *err; - - tr_error_clear(&err2); + error = {}; + EXPECT_FALSE(error) << error; + EXPECT_FALSE(error.has_value()) << error; } diff --git a/tests/libtransmission/file-test.cc b/tests/libtransmission/file-test.cc index 1a4c7936d..9a4284a86 100644 --- a/tests/libtransmission/file-test.cc +++ b/tests/libtransmission/file-test.cc @@ -153,25 +153,24 @@ protected: static void testPathXname( XnameTestData const* data, size_t data_size, - std::string_view (*func)(std::string_view, tr_error**)) + std::string_view (*func)(std::string_view, tr_error*)) { for (size_t i = 0; i < data_size; ++i) { - tr_error* err = nullptr; + auto error = tr_error{}; auto const& [input, output] = data[i]; - auto const name = func(input, &err); + auto const name = func(input, &error); if (!std::empty(data[i].output)) { EXPECT_NE(""sv, name); - EXPECT_EQ(nullptr, err) << *err; + EXPECT_FALSE(error) << error; EXPECT_EQ(output, name) << " in [" << input << ']'; } else { EXPECT_EQ(""sv, name) << " in [" << input << ']'; - EXPECT_NE(nullptr, err); - tr_error_clear(&err); + EXPECT_TRUE(error); } } } @@ -180,10 +179,10 @@ protected: { *have1 = *have2 = false; - tr_error* err = nullptr; + auto err = tr_error{}; auto dd = tr_sys_dir_open(path, &err); EXPECT_NE(TR_BAD_SYS_DIR, dd); - EXPECT_EQ(nullptr, err) << *err; + EXPECT_FALSE(err) << err; for (;;) { @@ -193,7 +192,7 @@ protected: break; } - EXPECT_EQ(nullptr, err) << *err; + EXPECT_FALSE(err) << err; if (strcmp(name, ".") == 0 || strcmp(name, "..") == 0) { @@ -214,10 +213,10 @@ protected: } } - EXPECT_EQ(nullptr, err) << *err; + EXPECT_FALSE(err) << err; EXPECT_TRUE(tr_sys_dir_close(dd, &err)); - EXPECT_EQ(nullptr, err) << *err; + EXPECT_FALSE(err) << err; } }; @@ -229,11 +228,11 @@ TEST_F(FileTest, getInfo) auto const path2 = tr_pathbuf{ test_dir, "/b"sv }; // Can't get info of non-existent file/directory - tr_error* err = nullptr; + auto err = tr_error{}; auto info = tr_sys_path_get_info(path1, 0, &err); EXPECT_FALSE(info.has_value()); - EXPECT_NE(nullptr, err); - tr_error_clear(&err); + EXPECT_TRUE(err); + err = {}; auto t = time(nullptr); createFileWithContents(path1, "test"); @@ -242,7 +241,7 @@ TEST_F(FileTest, getInfo) info = tr_sys_path_get_info(path1, 0, &err); EXPECT_TRUE(info.has_value()); assert(info.has_value()); - EXPECT_EQ(nullptr, err) << *err; + EXPECT_FALSE(err) << err; EXPECT_EQ(TR_SYS_PATH_IS_FILE, info->type); EXPECT_EQ(4U, info->size); EXPECT_GE(info->last_modified_at, t - 1); @@ -256,7 +255,7 @@ TEST_F(FileTest, getInfo) info = tr_sys_path_get_info(path1, 0, &err); EXPECT_TRUE(info.has_value()); assert(info.has_value()); - EXPECT_EQ(nullptr, err) << *err; + EXPECT_FALSE(err) << err; EXPECT_EQ(TR_SYS_PATH_IS_DIRECTORY, info->type); EXPECT_NE(uint64_t(-1), info->size); EXPECT_GE(info->last_modified_at, t - 1); @@ -268,8 +267,8 @@ TEST_F(FileTest, getInfo) // Can't get info of non-existent file/directory info = tr_sys_path_get_info(path1, 0, &err); EXPECT_FALSE(info.has_value()); - EXPECT_NE(nullptr, err); - tr_error_clear(&err); + EXPECT_TRUE(err); + err = {}; t = time(nullptr); createFileWithContents(path2, "test"); @@ -278,7 +277,7 @@ TEST_F(FileTest, getInfo) info = tr_sys_path_get_info(path1, 0, &err); EXPECT_TRUE(info.has_value()); assert(info.has_value()); - EXPECT_EQ(nullptr, err) << *err; + EXPECT_FALSE(err) << err; EXPECT_EQ(TR_SYS_PATH_IS_FILE, info->type); EXPECT_EQ(4, info->size); EXPECT_GE(info->last_modified_at, t - 1); @@ -288,7 +287,7 @@ TEST_F(FileTest, getInfo) info = tr_sys_path_get_info(path1, TR_SYS_PATH_NO_FOLLOW, &err); EXPECT_TRUE(info.has_value()); assert(info.has_value()); - EXPECT_EQ(nullptr, err) << *err; + EXPECT_FALSE(err) << err; EXPECT_EQ(TR_SYS_PATH_IS_OTHER, info->type); tr_sys_path_remove(path2); @@ -301,7 +300,7 @@ TEST_F(FileTest, getInfo) info = tr_sys_path_get_info(path1, 0, &err); EXPECT_TRUE(info.has_value()); assert(info.has_value()); - EXPECT_EQ(nullptr, err) << *err; + EXPECT_FALSE(err) << err; EXPECT_EQ(TR_SYS_PATH_IS_DIRECTORY, info->type); EXPECT_NE(uint64_t(-1), info->size); EXPECT_GE(info->last_modified_at, t - 1); @@ -325,24 +324,24 @@ TEST_F(FileTest, readFile) createFileWithContents(path, Contents); auto n_read = uint64_t{}; - tr_error* err = nullptr; auto buf = std::array{}; auto fd = tr_sys_file_open(path, TR_SYS_FILE_READ, 0); EXPECT_NE(TR_BAD_SYS_FILE, fd); // successful read - EXPECT_TRUE(tr_sys_file_read(fd, std::data(buf), std::size(buf), &n_read, &err)); + auto error = tr_error{}; + EXPECT_TRUE(tr_sys_file_read(fd, std::data(buf), std::size(buf), &n_read, &error)); EXPECT_EQ(Contents, std::string_view(std::data(buf), n_read)); EXPECT_EQ(std::size(Contents), n_read); - EXPECT_EQ(nullptr, err) << *err; + EXPECT_FALSE(error) << error; // successful read_at auto const offset = 1U; - EXPECT_TRUE(tr_sys_file_read_at(fd, std::data(buf), std::size(buf), offset, &n_read, &err)); + EXPECT_TRUE(tr_sys_file_read_at(fd, std::data(buf), std::size(buf), offset, &n_read, &error)); auto constexpr Expected = Contents.substr(offset); EXPECT_EQ(Expected, std::string_view(std::data(buf), n_read)); EXPECT_EQ(std::size(Expected), n_read); - EXPECT_EQ(nullptr, err) << *err; + EXPECT_FALSE(error) << error; tr_sys_file_close(fd); } @@ -355,34 +354,34 @@ TEST_F(FileTest, pathExists) auto const path2 = tr_pathbuf{ test_dir, "/b"sv }; // Non-existent file does not exist - tr_error* err = nullptr; - EXPECT_FALSE(tr_sys_path_exists(path1, &err)); - EXPECT_EQ(nullptr, err) << *err; + auto error = tr_error{}; + EXPECT_FALSE(tr_sys_path_exists(path1, &error)); + EXPECT_FALSE(error) << error; // Create file and see that it exists createFileWithContents(path1, "test"); - EXPECT_TRUE(tr_sys_path_exists(path1, &err)); - EXPECT_EQ(nullptr, err) << *err; + EXPECT_TRUE(tr_sys_path_exists(path1, &error)); + EXPECT_FALSE(error) << error; tr_sys_path_remove(path1); // Create directory and see that it exists tr_sys_dir_create(path1, 0, 0777); - EXPECT_TRUE(tr_sys_path_exists(path1, &err)); - EXPECT_EQ(nullptr, err) << *err; + EXPECT_TRUE(tr_sys_path_exists(path1, &error)); + EXPECT_FALSE(error) << error; tr_sys_path_remove(path1); if (createSymlink(path1, path2, false)) { // Non-existent file does not exist (via symlink) - EXPECT_FALSE(tr_sys_path_exists(path1, &err)); - EXPECT_EQ(nullptr, err) << *err; + EXPECT_FALSE(tr_sys_path_exists(path1, &error)); + EXPECT_FALSE(error) << error; // Create file and see that it exists (via symlink) createFileWithContents(path2, "test"); - EXPECT_TRUE(tr_sys_path_exists(path1, &err)); - EXPECT_EQ(nullptr, err) << *err; + EXPECT_TRUE(tr_sys_path_exists(path1, &error)); + EXPECT_FALSE(error) << error; tr_sys_path_remove(path2); tr_sys_path_remove(path1); @@ -390,8 +389,8 @@ TEST_F(FileTest, pathExists) /* Create directory and see that it exists (via symlink) */ tr_sys_dir_create(path2, 0, 0777); EXPECT_TRUE(createSymlink(path1, path2, true)); /* Win32: directory and file symlinks differ :( */ - EXPECT_TRUE(tr_sys_path_exists(path1, &err)); - EXPECT_EQ(nullptr, err) << *err; + EXPECT_TRUE(tr_sys_path_exists(path1, &error)); + EXPECT_FALSE(error) << error; tr_sys_path_remove(path2); tr_sys_path_remove(path1); @@ -459,47 +458,47 @@ TEST_F(FileTest, pathIsSame) auto path3 = tr_pathbuf{ path2, "/c"sv }; /* Two non-existent files are not the same */ - tr_error* err = nullptr; - EXPECT_FALSE(tr_sys_path_is_same(path1, path1, &err)); - EXPECT_EQ(nullptr, err) << *err; - EXPECT_FALSE(tr_sys_path_is_same(path1, path2, &err)); - EXPECT_EQ(nullptr, err) << *err; + auto error = tr_error{}; + EXPECT_FALSE(tr_sys_path_is_same(path1, path1, &error)); + EXPECT_FALSE(error) << error; + EXPECT_FALSE(tr_sys_path_is_same(path1, path2, &error)); + EXPECT_FALSE(error) << error; /* Two same files are the same */ createFileWithContents(path1, "test"); - EXPECT_TRUE(tr_sys_path_is_same(path1, path1, &err)); - EXPECT_EQ(nullptr, err) << *err; + EXPECT_TRUE(tr_sys_path_is_same(path1, path1, &error)); + EXPECT_FALSE(error) << error; /* Existent and non-existent files are not the same */ - EXPECT_FALSE(tr_sys_path_is_same(path1, path2, &err)); - EXPECT_EQ(nullptr, err) << *err; - EXPECT_FALSE(tr_sys_path_is_same(path2, path1, &err)); - EXPECT_EQ(nullptr, err) << *err; + EXPECT_FALSE(tr_sys_path_is_same(path1, path2, &error)); + EXPECT_FALSE(error) << error; + EXPECT_FALSE(tr_sys_path_is_same(path2, path1, &error)); + EXPECT_FALSE(error) << error; /* Two separate files (even with same content) are not the same */ createFileWithContents(path2, "test"); - EXPECT_FALSE(tr_sys_path_is_same(path1, path2, &err)); - EXPECT_EQ(nullptr, err) << *err; + EXPECT_FALSE(tr_sys_path_is_same(path1, path2, &error)); + EXPECT_FALSE(error) << error; tr_sys_path_remove(path1); /* Two same directories are the same */ tr_sys_dir_create(path1, 0, 0777); - EXPECT_TRUE(tr_sys_path_is_same(path1, path1, &err)); - EXPECT_EQ(nullptr, err) << *err; + EXPECT_TRUE(tr_sys_path_is_same(path1, path1, &error)); + EXPECT_FALSE(error) << error; /* File and directory are not the same */ - EXPECT_FALSE(tr_sys_path_is_same(path1, path2, &err)); - EXPECT_EQ(nullptr, err) << *err; - EXPECT_FALSE(tr_sys_path_is_same(path2, path1, &err)); - EXPECT_EQ(nullptr, err) << *err; + EXPECT_FALSE(tr_sys_path_is_same(path1, path2, &error)); + EXPECT_FALSE(error) << error; + EXPECT_FALSE(tr_sys_path_is_same(path2, path1, &error)); + EXPECT_FALSE(error) << error; tr_sys_path_remove(path2); /* Two separate directories are not the same */ tr_sys_dir_create(path2, 0, 0777); - EXPECT_FALSE(tr_sys_path_is_same(path1, path2, &err)); - EXPECT_EQ(nullptr, err) << *err; + EXPECT_FALSE(tr_sys_path_is_same(path1, path2, &error)); + EXPECT_FALSE(error) << error; tr_sys_path_remove(path1); tr_sys_path_remove(path2); @@ -507,88 +506,88 @@ TEST_F(FileTest, pathIsSame) if (createSymlink(path1, ".", true)) { /* Directory and symlink pointing to it are the same */ - EXPECT_TRUE(tr_sys_path_is_same(path1, test_dir.data(), &err)); - EXPECT_EQ(nullptr, err) << *err; - EXPECT_TRUE(tr_sys_path_is_same(test_dir.data(), path1, &err)); - EXPECT_EQ(nullptr, err) << *err; + EXPECT_TRUE(tr_sys_path_is_same(path1, test_dir.data(), &error)); + EXPECT_FALSE(error) << error; + EXPECT_TRUE(tr_sys_path_is_same(test_dir.data(), path1, &error)); + EXPECT_FALSE(error) << error; /* Non-existent file and symlink are not the same */ - EXPECT_FALSE(tr_sys_path_is_same(path1, path2, &err)); - EXPECT_EQ(nullptr, err) << *err; - EXPECT_FALSE(tr_sys_path_is_same(path2, path1, &err)); - EXPECT_EQ(nullptr, err) << *err; + EXPECT_FALSE(tr_sys_path_is_same(path1, path2, &error)); + EXPECT_FALSE(error) << error; + EXPECT_FALSE(tr_sys_path_is_same(path2, path1, &error)); + EXPECT_FALSE(error) << error; /* Symlinks pointing to different directories are not the same */ createSymlink(path2, "..", true); - EXPECT_FALSE(tr_sys_path_is_same(path1, path2, &err)); - EXPECT_EQ(nullptr, err) << *err; - EXPECT_FALSE(tr_sys_path_is_same(path2, path1, &err)); - EXPECT_EQ(nullptr, err) << *err; + EXPECT_FALSE(tr_sys_path_is_same(path1, path2, &error)); + EXPECT_FALSE(error) << error; + EXPECT_FALSE(tr_sys_path_is_same(path2, path1, &error)); + EXPECT_FALSE(error) << error; tr_sys_path_remove(path2); /* Symlinks pointing to same directory are the same */ createSymlink(path2, ".", true); - EXPECT_TRUE(tr_sys_path_is_same(path1, path2, &err)); - EXPECT_EQ(nullptr, err) << *err; + EXPECT_TRUE(tr_sys_path_is_same(path1, path2, &error)); + EXPECT_FALSE(error) << error; tr_sys_path_remove(path2); /* Directory and symlink pointing to another directory are not the same */ tr_sys_dir_create(path2, 0, 0777); - EXPECT_FALSE(tr_sys_path_is_same(path1, path2, &err)); - EXPECT_EQ(nullptr, err) << *err; - EXPECT_FALSE(tr_sys_path_is_same(path2, path1, &err)); - EXPECT_EQ(nullptr, err) << *err; + EXPECT_FALSE(tr_sys_path_is_same(path1, path2, &error)); + EXPECT_FALSE(error) << error; + EXPECT_FALSE(tr_sys_path_is_same(path2, path1, &error)); + EXPECT_FALSE(error) << error; /* Symlinks pointing to same directory are the same */ createSymlink(path3, "..", true); - EXPECT_TRUE(tr_sys_path_is_same(path1, path3, &err)); - EXPECT_EQ(nullptr, err) << *err; + EXPECT_TRUE(tr_sys_path_is_same(path1, path3, &error)); + EXPECT_FALSE(error) << error; tr_sys_path_remove(path1); /* File and symlink pointing to directory are not the same */ createFileWithContents(path1, "test"); - EXPECT_FALSE(tr_sys_path_is_same(path1, path3, &err)); - EXPECT_EQ(nullptr, err) << *err; - EXPECT_FALSE(tr_sys_path_is_same(path3, path1, &err)); - EXPECT_EQ(nullptr, err) << *err; + EXPECT_FALSE(tr_sys_path_is_same(path1, path3, &error)); + EXPECT_FALSE(error) << error; + EXPECT_FALSE(tr_sys_path_is_same(path3, path1, &error)); + EXPECT_FALSE(error) << error; tr_sys_path_remove(path3); /* File and symlink pointing to same file are the same */ createSymlink(path3, path1, false); - EXPECT_TRUE(tr_sys_path_is_same(path1, path3, &err)); - EXPECT_EQ(nullptr, err) << *err; - EXPECT_TRUE(tr_sys_path_is_same(path3, path1, &err)); - EXPECT_EQ(nullptr, err) << *err; + EXPECT_TRUE(tr_sys_path_is_same(path1, path3, &error)); + EXPECT_FALSE(error) << error; + EXPECT_TRUE(tr_sys_path_is_same(path3, path1, &error)); + EXPECT_FALSE(error) << error; /* Symlinks pointing to non-existent files are not the same */ tr_sys_path_remove(path1); createSymlink(path1, "missing", false); tr_sys_path_remove(path3); createSymlink(path3, "missing", false); - EXPECT_FALSE(tr_sys_path_is_same(path1, path3, &err)); - EXPECT_EQ(nullptr, err) << *err; - EXPECT_FALSE(tr_sys_path_is_same(path3, path1, &err)); - EXPECT_EQ(nullptr, err) << *err; + EXPECT_FALSE(tr_sys_path_is_same(path1, path3, &error)); + EXPECT_FALSE(error) << error; + EXPECT_FALSE(tr_sys_path_is_same(path3, path1, &error)); + EXPECT_FALSE(error) << error; tr_sys_path_remove(path3); /* Symlinks pointing to same non-existent file are not the same */ createSymlink(path3.c_str(), ".." NATIVE_PATH_SEP "missing", false); - EXPECT_FALSE(tr_sys_path_is_same(path1, path3, &err)); - EXPECT_EQ(nullptr, err) << *err; - EXPECT_FALSE(tr_sys_path_is_same(path3, path1, &err)); - EXPECT_EQ(nullptr, err) << *err; + EXPECT_FALSE(tr_sys_path_is_same(path1, path3, &error)); + EXPECT_FALSE(error) << error; + EXPECT_FALSE(tr_sys_path_is_same(path3, path1, &error)); + EXPECT_FALSE(error) << error; /* Non-existent file and symlink pointing to non-existent file are not the same */ tr_sys_path_remove(path3); - EXPECT_FALSE(tr_sys_path_is_same(path1, path3, &err)); - EXPECT_EQ(nullptr, err) << *err; - EXPECT_FALSE(tr_sys_path_is_same(path3, path1, &err)); - EXPECT_EQ(nullptr, err) << *err; + EXPECT_FALSE(tr_sys_path_is_same(path1, path3, &error)); + EXPECT_FALSE(error) << error; + EXPECT_FALSE(tr_sys_path_is_same(path3, path1, &error)); + EXPECT_FALSE(error) << error; tr_sys_path_remove(path2); tr_sys_path_remove(path1); @@ -605,30 +604,30 @@ TEST_F(FileTest, pathIsSame) if (createHardlink(path2, path1)) { /* File and hardlink to it are the same */ - EXPECT_TRUE(tr_sys_path_is_same(path1, path2, &err)); - EXPECT_EQ(nullptr, err) << *err; + EXPECT_TRUE(tr_sys_path_is_same(path1, path2, &error)); + EXPECT_FALSE(error) << error; /* Two hardlinks to the same file are the same */ createHardlink(path3, path2); - EXPECT_TRUE(tr_sys_path_is_same(path2, path3, &err)); - EXPECT_EQ(nullptr, err) << *err; - EXPECT_TRUE(tr_sys_path_is_same(path1, path3, &err)); - EXPECT_EQ(nullptr, err) << *err; + EXPECT_TRUE(tr_sys_path_is_same(path2, path3, &error)); + EXPECT_FALSE(error) << error; + EXPECT_TRUE(tr_sys_path_is_same(path1, path3, &error)); + EXPECT_FALSE(error) << error; tr_sys_path_remove(path2); - EXPECT_TRUE(tr_sys_path_is_same(path1, path3, &err)); - EXPECT_EQ(nullptr, err) << *err; + EXPECT_TRUE(tr_sys_path_is_same(path1, path3, &error)); + EXPECT_FALSE(error) << error; tr_sys_path_remove(path3); /* File and hardlink to another file are not the same */ createFileWithContents(path3, "test"); createHardlink(path2, path3); - EXPECT_FALSE(tr_sys_path_is_same(path1, path2, &err)); - EXPECT_EQ(nullptr, err) << *err; - EXPECT_FALSE(tr_sys_path_is_same(path2, path1, &err)); - EXPECT_EQ(nullptr, err) << *err; + EXPECT_FALSE(tr_sys_path_is_same(path1, path2, &error)); + EXPECT_FALSE(error) << error; + EXPECT_FALSE(tr_sys_path_is_same(path2, path1, &error)); + EXPECT_FALSE(error) << error; tr_sys_path_remove(path3); tr_sys_path_remove(path2); @@ -640,8 +639,8 @@ TEST_F(FileTest, pathIsSame) if (createSymlink(path2, path1, false) && createHardlink(path3, path1)) { - EXPECT_TRUE(tr_sys_path_is_same(path2, path3, &err)); - EXPECT_EQ(nullptr, err) << *err; + EXPECT_TRUE(tr_sys_path_is_same(path2, path3, &error)); + EXPECT_FALSE(error) << error; } else { @@ -659,7 +658,7 @@ TEST_F(FileTest, pathResolve) { auto const test_dir = createTestDir(currentTestName()); - tr_error* err = nullptr; + auto error = tr_error{}; auto const path1 = tr_pathbuf{ test_dir, "/a"sv }; auto const path2 = tr_pathbuf{ test_dir, "/b"sv }; @@ -667,8 +666,8 @@ TEST_F(FileTest, pathResolve) if (createSymlink(path2, path1, false)) { - auto resolved = tr_sys_path_resolve(path2, &err); - EXPECT_EQ(nullptr, err) << *err; + auto resolved = tr_sys_path_resolve(path2, &error); + EXPECT_FALSE(error) << error; EXPECT_TRUE(pathContainsNoSymlinks(resolved.c_str())); tr_sys_path_remove(path2); @@ -676,8 +675,8 @@ TEST_F(FileTest, pathResolve) tr_sys_dir_create(path1, 0, 0755); EXPECT_TRUE(createSymlink(path2, path1, true)); /* Win32: directory and file symlinks differ :( */ - resolved = tr_sys_path_resolve(path2, &err); - EXPECT_EQ(nullptr, err) << *err; + resolved = tr_sys_path_resolve(path2, &error); + EXPECT_FALSE(error) << error; EXPECT_TRUE(pathContainsNoSymlinks(resolved.c_str())); } else @@ -690,15 +689,15 @@ TEST_F(FileTest, pathResolve) #ifdef _WIN32 - auto resolved = tr_sys_path_resolve("\\\\127.0.0.1\\NonExistent"sv, &err); + auto resolved = tr_sys_path_resolve("\\\\127.0.0.1\\NonExistent"sv, &error); EXPECT_EQ(""sv, resolved); - EXPECT_NE(nullptr, err); - tr_error_clear(&err); + EXPECT_TRUE(error); + error = {}; - resolved = tr_sys_path_resolve("\\\\127.0.0.1\\ADMIN$\\NonExistent"sv, &err); + resolved = tr_sys_path_resolve("\\\\127.0.0.1\\ADMIN$\\NonExistent"sv, &error); EXPECT_EQ(""sv, resolved); - EXPECT_NE(nullptr, err); - tr_error_clear(&err); + EXPECT_TRUE(error); + error = {}; for (auto const& input : { "\\\\127.0.0.1\\ADMIN$\\System32"sv, "\\\\127.0.0.1\\ADMIN$\\\\System32"sv, @@ -706,9 +705,9 @@ TEST_F(FileTest, pathResolve) "\\\\127.0.0.1\\\\ADMIN$\\\\System32"sv, "\\\\127.0.0.1\\ADMIN$/System32"sv }) { - resolved = tr_sys_path_resolve(input, &err); + resolved = tr_sys_path_resolve(input, &error); EXPECT_EQ("\\\\127.0.0.1\\ADMIN$\\System32"sv, resolved); - EXPECT_EQ(nullptr, err) << *err; + EXPECT_FALSE(error) << error; } #endif @@ -887,48 +886,48 @@ TEST_F(FileTest, pathRename) EXPECT_FALSE(tr_sys_path_exists(path2)); /* Forward rename works */ - tr_error* err = nullptr; - EXPECT_TRUE(tr_sys_path_rename(path1, path2, &err)); + auto error = tr_error{}; + EXPECT_TRUE(tr_sys_path_rename(path1, path2, &error)); EXPECT_FALSE(tr_sys_path_exists(path1)); EXPECT_TRUE(tr_sys_path_exists(path2)); - EXPECT_EQ(nullptr, err) << *err; + EXPECT_FALSE(error) << error; /* Backward rename works */ - EXPECT_TRUE(tr_sys_path_rename(path2, path1, &err)); + EXPECT_TRUE(tr_sys_path_rename(path2, path1, &error)); EXPECT_TRUE(tr_sys_path_exists(path1)); EXPECT_FALSE(tr_sys_path_exists(path2)); - EXPECT_EQ(nullptr, err) << *err; + EXPECT_FALSE(error) << error; /* Another backward rename [of non-existent file] does not work */ - EXPECT_FALSE(tr_sys_path_rename(path2, path1, &err)); - EXPECT_NE(nullptr, err); - tr_error_clear(&err); + EXPECT_FALSE(tr_sys_path_rename(path2, path1, &error)); + EXPECT_TRUE(error); + error = {}; /* Rename to file which couldn't be created does not work */ - EXPECT_FALSE(tr_sys_path_rename(path1, path3, &err)); - EXPECT_NE(nullptr, err); - tr_error_clear(&err); + EXPECT_FALSE(tr_sys_path_rename(path1, path3, &error)); + EXPECT_TRUE(error); + error = {}; /* Rename of non-existent file does not work */ - EXPECT_FALSE(tr_sys_path_rename(path3, path2, &err)); - EXPECT_NE(nullptr, err); - tr_error_clear(&err); + EXPECT_FALSE(tr_sys_path_rename(path3, path2, &error)); + EXPECT_TRUE(error); + error = {}; createFileWithContents(path2, "test"); /* Renaming file does overwrite existing file */ - EXPECT_TRUE(tr_sys_path_rename(path2, path1, &err)); - EXPECT_EQ(nullptr, err) << *err; + EXPECT_TRUE(tr_sys_path_rename(path2, path1, &error)); + EXPECT_FALSE(error) << error; tr_sys_dir_create(path2, 0, 0777); /* Renaming file does not overwrite existing directory, and vice versa */ - EXPECT_FALSE(tr_sys_path_rename(path1, path2, &err)); - EXPECT_NE(nullptr, err); - tr_error_clear(&err); - EXPECT_FALSE(tr_sys_path_rename(path2, path1, &err)); - EXPECT_NE(nullptr, err); - tr_error_clear(&err); + EXPECT_FALSE(tr_sys_path_rename(path1, path2, &error)); + EXPECT_TRUE(error); + error = {}; + EXPECT_FALSE(tr_sys_path_rename(path2, path1, &error)); + EXPECT_TRUE(error); + error = {}; tr_sys_path_remove(path2); @@ -942,8 +941,8 @@ TEST_F(FileTest, pathRename) EXPECT_TRUE(tr_sys_path_is_same(path1, path2)); /* Rename of symlink works, files stay the same */ - EXPECT_TRUE(tr_sys_path_rename(path2, path3, &err)); - EXPECT_EQ(nullptr, err) << *err; + EXPECT_TRUE(tr_sys_path_rename(path2, path3, &error)); + EXPECT_FALSE(error) << error; EXPECT_FALSE(tr_sys_path_exists(path2)); EXPECT_TRUE(tr_sys_path_exists(path3)); EXPECT_TRUE(tr_sys_path_is_same(path1, path3)); @@ -963,8 +962,8 @@ TEST_F(FileTest, pathRename) EXPECT_TRUE(tr_sys_path_is_same(path1, path2)); /* Rename of hardlink works, files stay the same */ - EXPECT_TRUE(tr_sys_path_rename(path2, path3, &err)); - EXPECT_EQ(nullptr, err) << *err; + EXPECT_TRUE(tr_sys_path_rename(path2, path3, &error)); + EXPECT_FALSE(error) << error; EXPECT_FALSE(tr_sys_path_exists(path2)); EXPECT_TRUE(tr_sys_path_exists(path3)); EXPECT_TRUE(tr_sys_path_is_same(path1, path3)); @@ -989,24 +988,24 @@ TEST_F(FileTest, pathRemove) /* Can't remove non-existent file/directory */ EXPECT_FALSE(tr_sys_path_exists(path1)); - tr_error* err = nullptr; - EXPECT_FALSE(tr_sys_path_remove(path1, &err)); - EXPECT_NE(nullptr, err); + auto error = tr_error{}; + EXPECT_FALSE(tr_sys_path_remove(path1, &error)); + EXPECT_TRUE(error); EXPECT_FALSE(tr_sys_path_exists(path1)); - tr_error_clear(&err); + error = {}; /* Removing file works */ createFileWithContents(path1, "test"); EXPECT_TRUE(tr_sys_path_exists(path1)); - EXPECT_TRUE(tr_sys_path_remove(path1, &err)); - EXPECT_EQ(nullptr, err) << *err; + EXPECT_TRUE(tr_sys_path_remove(path1, &error)); + EXPECT_FALSE(error) << error; EXPECT_FALSE(tr_sys_path_exists(path1)); /* Removing empty directory works */ tr_sys_dir_create(path1, 0, 0777); EXPECT_TRUE(tr_sys_path_exists(path1)); - EXPECT_TRUE(tr_sys_path_remove(path1, &err)); - EXPECT_EQ(nullptr, err) << *err; + EXPECT_TRUE(tr_sys_path_remove(path1, &error)); + EXPECT_FALSE(error) << error; EXPECT_FALSE(tr_sys_path_exists(path1)); /* Removing non-empty directory fails */ @@ -1014,11 +1013,11 @@ TEST_F(FileTest, pathRemove) createFileWithContents(path3, "test"); EXPECT_TRUE(tr_sys_path_exists(path2)); EXPECT_TRUE(tr_sys_path_exists(path3)); - EXPECT_FALSE(tr_sys_path_remove(path2, &err)); - EXPECT_NE(nullptr, err); + EXPECT_FALSE(tr_sys_path_remove(path2, &error)); + EXPECT_TRUE(error); EXPECT_TRUE(tr_sys_path_exists(path2)); EXPECT_TRUE(tr_sys_path_exists(path3)); - tr_error_clear(&err); + error = {}; tr_sys_path_remove(path3); tr_sys_path_remove(path2); @@ -1052,29 +1051,29 @@ TEST_F(FileTest, fileCopy) auto constexpr Contents = "hello, world!"sv; // no source file - tr_error* err = nullptr; - EXPECT_FALSE(tr_sys_path_copy(path1, path2, &err)); - EXPECT_NE(nullptr, err); - tr_error_clear(&err); + auto error = tr_error{}; + EXPECT_FALSE(tr_sys_path_copy(path1, path2, &error)); + EXPECT_TRUE(error); + error = {}; createFileWithContents(path1, Contents); // source file exists but is inaccessible (void)chmod(path1, 0); - EXPECT_FALSE(tr_sys_path_copy(path1, test_dir, &err)); - EXPECT_NE(nullptr, err); - tr_error_clear(&err); + EXPECT_FALSE(tr_sys_path_copy(path1, test_dir, &error)); + EXPECT_TRUE(error); + error = {}; (void)chmod(path1, 0600); // source file exists but target is invalid - EXPECT_FALSE(tr_sys_path_copy(path1, test_dir, &err)); - EXPECT_NE(nullptr, err); - tr_error_clear(&err); + EXPECT_FALSE(tr_sys_path_copy(path1, test_dir, &error)); + EXPECT_TRUE(error); + error = {}; // source and target are valid createFileWithContents(path1, Contents); - EXPECT_TRUE(tr_sys_path_copy(path1, path2, &err)); - EXPECT_EQ(nullptr, err); + EXPECT_TRUE(tr_sys_path_copy(path1, path2, &error)); + EXPECT_FALSE(error) << error; } TEST_F(FileTest, fileOpen) @@ -1084,47 +1083,47 @@ TEST_F(FileTest, fileOpen) // can't open non-existent file auto const path1 = tr_pathbuf{ test_dir, "/a"sv }; EXPECT_FALSE(tr_sys_path_exists(path1)); - tr_error* err = nullptr; - EXPECT_EQ(TR_BAD_SYS_FILE, tr_sys_file_open(path1, TR_SYS_FILE_READ, 0600, &err)); - EXPECT_NE(nullptr, err); + auto error = tr_error{}; + EXPECT_EQ(TR_BAD_SYS_FILE, tr_sys_file_open(path1, TR_SYS_FILE_READ, 0600, &error)); + EXPECT_TRUE(error); EXPECT_FALSE(tr_sys_path_exists(path1)); - tr_error_clear(&err); - EXPECT_EQ(TR_BAD_SYS_FILE, tr_sys_file_open(path1, TR_SYS_FILE_WRITE, 0600, &err)); - EXPECT_NE(nullptr, err); + error = {}; + EXPECT_EQ(TR_BAD_SYS_FILE, tr_sys_file_open(path1, TR_SYS_FILE_WRITE, 0600, &error)); + EXPECT_TRUE(error); EXPECT_FALSE(tr_sys_path_exists(path1)); - tr_error_clear(&err); + error = {}; // can't open directory tr_sys_dir_create(path1, 0, 0777); #ifdef _WIN32 // this works on *NIX - EXPECT_EQ(TR_BAD_SYS_FILE, tr_sys_file_open(path1, TR_SYS_FILE_READ, 0600, &err)); - EXPECT_NE(nullptr, err); - tr_error_clear(&err); + EXPECT_EQ(TR_BAD_SYS_FILE, tr_sys_file_open(path1, TR_SYS_FILE_READ, 0600, &error)); + EXPECT_TRUE(error); + error = {}; #endif - EXPECT_EQ(TR_BAD_SYS_FILE, tr_sys_file_open(path1, TR_SYS_FILE_WRITE, 0600, &err)); - EXPECT_NE(nullptr, err); - tr_error_clear(&err); + EXPECT_EQ(TR_BAD_SYS_FILE, tr_sys_file_open(path1, TR_SYS_FILE_WRITE, 0600, &error)); + EXPECT_TRUE(error); + error = {}; tr_sys_path_remove(path1); // can create non-existent file - auto fd = tr_sys_file_open(path1, TR_SYS_FILE_WRITE | TR_SYS_FILE_CREATE, 0640, &err); + auto fd = tr_sys_file_open(path1, TR_SYS_FILE_WRITE | TR_SYS_FILE_CREATE, 0640, &error); EXPECT_NE(TR_BAD_SYS_FILE, fd); - EXPECT_EQ(nullptr, err) << *err; + EXPECT_FALSE(error) << error; tr_sys_file_close(fd); EXPECT_TRUE(tr_sys_path_exists(path1)); EXPECT_TRUE(validatePermissions(path1, 0640)); // can open existing file EXPECT_TRUE(tr_sys_path_exists(path1)); - fd = tr_sys_file_open(path1, TR_SYS_FILE_READ, 0600, &err); + fd = tr_sys_file_open(path1, TR_SYS_FILE_READ, 0600, &error); EXPECT_NE(TR_BAD_SYS_FILE, fd); - EXPECT_EQ(nullptr, err) << *err; + EXPECT_FALSE(error) << error; tr_sys_file_close(fd); - fd = tr_sys_file_open(path1, TR_SYS_FILE_WRITE, 0600, &err); + fd = tr_sys_file_open(path1, TR_SYS_FILE_WRITE, 0600, &error); EXPECT_NE(TR_BAD_SYS_FILE, fd); - EXPECT_EQ(nullptr, err) << *err; + EXPECT_FALSE(error) << error; tr_sys_file_close(fd); tr_sys_path_remove(path1); @@ -1135,9 +1134,9 @@ TEST_F(FileTest, fileOpen) EXPECT_TRUE(info.has_value()); assert(info.has_value()); EXPECT_EQ(4U, info->size); - fd = tr_sys_file_open(path1, TR_SYS_FILE_WRITE | TR_SYS_FILE_APPEND, 0600, &err); + fd = tr_sys_file_open(path1, TR_SYS_FILE_WRITE | TR_SYS_FILE_APPEND, 0600, &error); EXPECT_NE(TR_BAD_SYS_FILE, fd); - EXPECT_EQ(nullptr, err) << *err; + EXPECT_FALSE(error) << error; tr_sys_file_write(fd, "s", 1, nullptr); /* On *NIX, pointer is positioned on each write but not initially */ tr_sys_file_close(fd); @@ -1146,9 +1145,9 @@ TEST_F(FileTest, fileOpen) EXPECT_TRUE(info.has_value()); assert(info.has_value()); EXPECT_EQ(5U, info->size); - fd = tr_sys_file_open(path1, TR_SYS_FILE_WRITE | TR_SYS_FILE_TRUNCATE, 0600, &err); + fd = tr_sys_file_open(path1, TR_SYS_FILE_WRITE | TR_SYS_FILE_TRUNCATE, 0600, &error); EXPECT_NE(TR_BAD_SYS_FILE, fd); - EXPECT_EQ(nullptr, err) << *err; + EXPECT_FALSE(error) << error; info = tr_sys_path_get_info(path1); EXPECT_TRUE(info.has_value()); assert(info.has_value()); @@ -1171,30 +1170,30 @@ TEST_F(FileTest, fileTruncate) auto const path = tr_pathbuf{ test_dir, "/a"sv }; auto fd = tr_sys_file_open(path, TR_SYS_FILE_WRITE | TR_SYS_FILE_CREATE, 0600); - tr_error* err = nullptr; - EXPECT_TRUE(tr_sys_file_truncate(fd, 10, &err)); - EXPECT_EQ(nullptr, err) << *err; + auto error = tr_error{}; + EXPECT_TRUE(tr_sys_file_truncate(fd, 10, &error)); + EXPECT_FALSE(error) << error; auto info = tr_sys_path_get_info(path); EXPECT_TRUE(info.has_value()); assert(info.has_value()); EXPECT_EQ(10U, info->size); - EXPECT_TRUE(tr_sys_file_truncate(fd, 20, &err)); - EXPECT_EQ(nullptr, err) << *err; + EXPECT_TRUE(tr_sys_file_truncate(fd, 20, &error)); + EXPECT_FALSE(error) << error; info = tr_sys_path_get_info(path); EXPECT_TRUE(info.has_value()); assert(info.has_value()); EXPECT_EQ(20U, info->size); - EXPECT_TRUE(tr_sys_file_truncate(fd, 0, &err)); - EXPECT_EQ(nullptr, err) << *err; + EXPECT_TRUE(tr_sys_file_truncate(fd, 0, &error)); + EXPECT_FALSE(error) << error; info = tr_sys_path_get_info(path); EXPECT_TRUE(info.has_value()); assert(info.has_value()); EXPECT_EQ(0U, info->size); - EXPECT_TRUE(tr_sys_file_truncate(fd, 50, &err)); - EXPECT_EQ(nullptr, err) << *err; + EXPECT_TRUE(tr_sys_file_truncate(fd, 50, &error)); + EXPECT_FALSE(error) << error; tr_sys_file_close(fd); @@ -1205,8 +1204,8 @@ TEST_F(FileTest, fileTruncate) fd = tr_sys_file_open(path, TR_SYS_FILE_WRITE | TR_SYS_FILE_CREATE, 0600); - EXPECT_TRUE(tr_sys_file_truncate(fd, 25, &err)); - EXPECT_EQ(nullptr, err) << *err; + EXPECT_TRUE(tr_sys_file_truncate(fd, 25, &error)); + EXPECT_FALSE(error) << error; tr_sys_file_close(fd); @@ -1216,9 +1215,9 @@ TEST_F(FileTest, fileTruncate) EXPECT_EQ(25U, info->size); // try to truncate a closed file - EXPECT_FALSE(tr_sys_file_truncate(fd, 10, &err)); // coverity[USE_AFTER_FREE] - EXPECT_NE(nullptr, err); - tr_error_clear(&err); + EXPECT_FALSE(tr_sys_file_truncate(fd, 10, &error)); // coverity[USE_AFTER_FREE] + EXPECT_TRUE(error); + error = {}; tr_sys_path_remove(path); } @@ -1230,11 +1229,11 @@ TEST_F(FileTest, filePreallocate) auto const path1 = tr_pathbuf{ test_dir, "/a"sv }; auto fd = tr_sys_file_open(path1, TR_SYS_FILE_WRITE | TR_SYS_FILE_CREATE, 0600); - tr_error* err = nullptr; + auto error = tr_error{}; auto prealloc_size = size_t{ 50 }; - if (tr_sys_file_preallocate(fd, prealloc_size, 0, &err)) + if (tr_sys_file_preallocate(fd, prealloc_size, 0, &error)) { - EXPECT_EQ(nullptr, err) << *err; + EXPECT_FALSE(error) << error; auto info = tr_sys_path_get_info(path1); EXPECT_TRUE(info.has_value()); assert(info.has_value()); @@ -1242,14 +1241,14 @@ TEST_F(FileTest, filePreallocate) } else { - EXPECT_NE(nullptr, err); + EXPECT_TRUE(error); fmt::print( stderr, "WARNING: [{:s}] unable to preallocate file (full): {:s} ({:d})\n", __FUNCTION__, - err->message, - err->code); - tr_error_clear(&err); + error.message(), + error.code()); + error = {}; } tr_sys_file_close(fd); @@ -1259,9 +1258,9 @@ TEST_F(FileTest, filePreallocate) fd = tr_sys_file_open(path1, TR_SYS_FILE_WRITE | TR_SYS_FILE_CREATE, 0600); prealloc_size = size_t{ 500U } * 1024U * 1024U; - if (tr_sys_file_preallocate(fd, prealloc_size, TR_SYS_FILE_PREALLOC_SPARSE, &err)) + if (tr_sys_file_preallocate(fd, prealloc_size, TR_SYS_FILE_PREALLOC_SPARSE, &error)) { - EXPECT_EQ(nullptr, err) << *err; + EXPECT_FALSE(error) << error; auto info = tr_sys_path_get_info(path1); EXPECT_TRUE(info.has_value()); assert(info.has_value()); @@ -1269,14 +1268,14 @@ TEST_F(FileTest, filePreallocate) } else { - EXPECT_NE(nullptr, err) << *err; + EXPECT_TRUE(error); fmt::print( stderr, "WARNING: [{:s}] unable to preallocate file (sparse): {:s} ({:d})\n", __FUNCTION__, - err->message, - err->code); - tr_error_clear(&err); + error.message(), + error.code()); + error = {}; } tr_sys_file_close(fd); @@ -1292,9 +1291,9 @@ TEST_F(FileTest, dirCreate) auto const path2 = tr_pathbuf{ path1, "/b"sv }; // Can create directory which has parent - tr_error* err = nullptr; - EXPECT_TRUE(tr_sys_dir_create(path1, 0, 0700, &err)); - EXPECT_EQ(nullptr, err) << *err; + auto error = tr_error{}; + EXPECT_TRUE(tr_sys_dir_create(path1, 0, 0700, &error)); + EXPECT_FALSE(error) << error; EXPECT_TRUE(tr_sys_path_exists(path1)); EXPECT_TRUE(validatePermissions(path1, 0700)); @@ -1302,34 +1301,34 @@ TEST_F(FileTest, dirCreate) createFileWithContents(path1, "test"); // Can't create directory where file already exists - EXPECT_FALSE(tr_sys_dir_create(path1, 0, 0700, &err)); - EXPECT_NE(nullptr, err); - tr_error_clear(&err); - EXPECT_FALSE(tr_sys_dir_create(path1, TR_SYS_DIR_CREATE_PARENTS, 0700, &err)); - EXPECT_NE(nullptr, err); - tr_error_clear(&err); + EXPECT_FALSE(tr_sys_dir_create(path1, 0, 0700, &error)); + EXPECT_TRUE(error); + error = {}; + EXPECT_FALSE(tr_sys_dir_create(path1, TR_SYS_DIR_CREATE_PARENTS, 0700, &error)); + EXPECT_TRUE(error); + error = {}; tr_sys_path_remove(path1); // Can't create directory which has no parent - EXPECT_FALSE(tr_sys_dir_create(path2, 0, 0700, &err)); - EXPECT_NE(nullptr, err); + EXPECT_FALSE(tr_sys_dir_create(path2, 0, 0700, &error)); + EXPECT_TRUE(error); EXPECT_FALSE(tr_sys_path_exists(path2)); - tr_error_clear(&err); + error = {}; // Can create directory with parent directories - EXPECT_TRUE(tr_sys_dir_create(path2, TR_SYS_DIR_CREATE_PARENTS, 0751, &err)); - EXPECT_EQ(nullptr, err) << *err; + EXPECT_TRUE(tr_sys_dir_create(path2, TR_SYS_DIR_CREATE_PARENTS, 0751, &error)); + EXPECT_FALSE(error) << error; EXPECT_TRUE(tr_sys_path_exists(path1)); EXPECT_TRUE(tr_sys_path_exists(path2)); EXPECT_TRUE(validatePermissions(path1, 0751)); EXPECT_TRUE(validatePermissions(path2, 0751)); // Can create existing directory (no-op) - EXPECT_TRUE(tr_sys_dir_create(path1, 0, 0700, &err)); - EXPECT_EQ(nullptr, err) << *err; - EXPECT_TRUE(tr_sys_dir_create(path1, TR_SYS_DIR_CREATE_PARENTS, 0700, &err)); - EXPECT_EQ(nullptr, err) << *err; + EXPECT_TRUE(tr_sys_dir_create(path1, 0, 0700, &error)); + EXPECT_FALSE(error) << error; + EXPECT_TRUE(tr_sys_dir_create(path1, TR_SYS_DIR_CREATE_PARENTS, 0700, &error)); + EXPECT_FALSE(error) << error; tr_sys_path_remove(path2); tr_sys_path_remove(path1); @@ -1339,16 +1338,15 @@ TEST_F(FileTest, dirCreateTemp) { auto const test_dir = createTestDir(currentTestName()); - tr_error* err = nullptr; + auto error = tr_error{}; auto path = tr_pathbuf{ test_dir, "/test-XXXXXX" }; - EXPECT_TRUE(tr_sys_dir_create_temp(std::data(path), &err)); - EXPECT_EQ(nullptr, err) << *err; + EXPECT_TRUE(tr_sys_dir_create_temp(std::data(path), &error)); + EXPECT_FALSE(error) << error; tr_sys_path_remove(path); path.assign(test_dir, "/path-does-not-exist/test-XXXXXX"); - EXPECT_FALSE(tr_sys_dir_create_temp(std::data(path), &err)); - EXPECT_NE(nullptr, err); - tr_error_clear(&err); + EXPECT_FALSE(tr_sys_dir_create_temp(std::data(path), &error)); + EXPECT_TRUE(error); } TEST_F(FileTest, dirRead) @@ -1389,21 +1387,22 @@ TEST_F(FileTest, dirOpen) createFileWithContents(file, std::data(Contents), std::size(Contents)); // path does not exist - tr_error* err = nullptr; + auto err = tr_error{}; auto odir = tr_sys_dir_open("/no/such/path", &err); EXPECT_EQ(TR_BAD_SYS_DIR, odir); - EXPECT_NE(err, nullptr); - tr_error_clear(&err); + EXPECT_TRUE(err); + err = {}; // path is not a directory odir = tr_sys_dir_open(file, &err); EXPECT_EQ(TR_BAD_SYS_DIR, odir); - EXPECT_NE(err, nullptr); - tr_error_clear(&err); + EXPECT_TRUE(err); + err = {}; // path exists and is readable - odir = tr_sys_dir_open(test_dir); + odir = tr_sys_dir_open(test_dir, &err); EXPECT_NE(TR_BAD_SYS_DIR, odir); + EXPECT_FALSE(err); auto files = std::set{}; for (;;) { @@ -1414,10 +1413,10 @@ TEST_F(FileTest, dirOpen) } files.insert(filename); } - EXPECT_EQ(3U, files.size()); - EXPECT_EQ(nullptr, err) << *err; + EXPECT_EQ(3U, std::size(files)); + EXPECT_FALSE(err) << err; EXPECT_TRUE(tr_sys_dir_close(odir, &err)); - EXPECT_EQ(nullptr, err) << *err; + EXPECT_FALSE(err) << err; } } // namespace libtransmission::test diff --git a/tests/libtransmission/makemeta-test.cc b/tests/libtransmission/makemeta-test.cc index 76e398b98..e8aff8b92 100644 --- a/tests/libtransmission/makemeta-test.cc +++ b/tests/libtransmission/makemeta-test.cc @@ -26,8 +26,6 @@ #include "gtest/gtest.h" #include "test-fixtures.h" -struct tr_error; - using namespace std::literals; namespace libtransmission::test @@ -69,8 +67,8 @@ protected: static auto testBuilder(tr_metainfo_builder& builder) { - tr_error* error = builder.make_checksums().get(); - EXPECT_EQ(error, nullptr) << *error; + auto error = builder.make_checksums().get(); + EXPECT_FALSE(error) << error; auto metainfo = tr_torrent_metainfo{}; EXPECT_TRUE(metainfo.parse_benc(builder.benc())); @@ -233,7 +231,7 @@ TEST_F(MakemetaTest, announceSingleTracker) builder.set_announce_list(std::move(trackers)); // generate the torrent and parse it as a variant - EXPECT_EQ(nullptr, builder.make_checksums().get()); + EXPECT_FALSE(builder.make_checksums().get().has_value()); auto top = tr_variant_serde::benc().parse(builder.benc()); EXPECT_TRUE(top.has_value()); @@ -261,7 +259,7 @@ TEST_F(MakemetaTest, announceMultiTracker) builder.set_announce_list(std::move(trackers)); // generate the torrent and parse it as a variant - EXPECT_EQ(nullptr, builder.make_checksums().get()); + EXPECT_FALSE(builder.make_checksums().get().has_value()); auto top = tr_variant_serde::benc().parse(builder.benc()); EXPECT_TRUE(top.has_value()); diff --git a/tests/libtransmission/open-files-test.cc b/tests/libtransmission/open-files-test.cc index cf6ca1a71..a824745ee 100644 --- a/tests/libtransmission/open-files-test.cc +++ b/tests/libtransmission/open-files-test.cc @@ -104,15 +104,14 @@ TEST_F(OpenFilesTest, opensInReadOnlyUnlessWritableIsRequested) createFileWithContents(filename, Contents); // cache a file read-only mode - tr_error* error = nullptr; auto fd = session_->openFiles().get(0, 0, false, filename, TR_PREALLOCATE_FULL, std::size(Contents)); EXPECT_TRUE(fd.has_value()); assert(fd.has_value()); // confirm that writing to it fails + auto error = tr_error{}; EXPECT_FALSE(tr_sys_file_write(*fd, std::data(Contents), std::size(Contents), nullptr, &error)); - EXPECT_NE(0, error->code); - tr_error_clear(&error); + EXPECT_TRUE(error); } TEST_F(OpenFilesTest, createsMissingFileIfWriteRequested) diff --git a/tests/libtransmission/rename-test.cc b/tests/libtransmission/rename-test.cc index 72853a06e..4a61367b4 100644 --- a/tests/libtransmission/rename-test.cc +++ b/tests/libtransmission/rename-test.cc @@ -14,6 +14,7 @@ #include #include +#include #include #include #include // tr_isTorrent() @@ -24,7 +25,6 @@ #include "test-fixtures.h" struct tr_ctor; -struct tr_error; using namespace std::literals; @@ -74,9 +74,9 @@ protected: // create the torrent ctor auto const benc = tr_base64_decode(benc_base64); EXPECT_LT(0U, std::size(benc)); - tr_error* error = nullptr; + auto error = tr_error{}; EXPECT_TRUE(tr_ctorSetMetainfo(ctor, std::data(benc), std::size(benc), &error)); - EXPECT_EQ(nullptr, error) << *error; + EXPECT_FALSE(error) << error; tr_ctorSetPaused(ctor, TR_FORCE, true); // create the torrent diff --git a/tests/libtransmission/subprocess-test.cc b/tests/libtransmission/subprocess-test.cc index 5305ecd1d..014f554e2 100644 --- a/tests/libtransmission/subprocess-test.cc +++ b/tests/libtransmission/subprocess-test.cc @@ -86,14 +86,12 @@ TEST_P(SubprocessTest, SpawnAsyncMissingExec) auto args = std::array{ missing_exe_path.data(), nullptr }; - tr_error* error = nullptr; + auto error = tr_error{}; auto const ret = tr_spawn_async(std::data(args), {}, {}, &error); EXPECT_FALSE(ret); - EXPECT_NE(nullptr, error); - EXPECT_NE(0, error->code); - EXPECT_NE(nullptr, error->message); - - tr_error_clear(&error); + EXPECT_TRUE(error); + EXPECT_NE(0, error.code()); + EXPECT_NE(""sv, error.message()); } TEST_P(SubprocessTest, SpawnAsyncArgs) @@ -115,10 +113,10 @@ TEST_P(SubprocessTest, SpawnAsyncArgs) allow_batch_metachars ? test_arg4.data() : nullptr, nullptr }; - tr_error* error = nullptr; + auto error = tr_error{}; bool const ret = tr_spawn_async(std::data(args), {}, {}, &error); EXPECT_TRUE(ret) << args[0] << ' ' << args[1]; - EXPECT_EQ(nullptr, error) << *error; + EXPECT_FALSE(error) << error; waitForFileToBeReadable(result_path); @@ -184,10 +182,10 @@ TEST_P(SubprocessTest, SpawnAsyncEnv) setenv("FOO", "bar", 1 /*true*/); // inherited setenv("ZOO", "tar", 1 /*true*/); // overridden - tr_error* error = nullptr; + auto error = tr_error{}; bool const ret = tr_spawn_async(std::data(args), env, {}, &error); EXPECT_TRUE(ret); - EXPECT_EQ(nullptr, error) << *error; + EXPECT_FALSE(error) << error; waitForFileToBeReadable(result_path); @@ -223,10 +221,10 @@ TEST_P(SubprocessTest, SpawnAsyncCwdExplicit) auto const args = std::array{ self_path_.c_str(), result_path.c_str(), arg_dump_cwd_.c_str(), nullptr }; - tr_error* error = nullptr; + auto error = tr_error{}; bool const ret = tr_spawn_async(std::data(args), {}, test_dir, &error); EXPECT_TRUE(ret); - EXPECT_EQ(nullptr, error) << *error; + EXPECT_FALSE(error) << error; waitForFileToBeReadable(result_path); @@ -251,10 +249,10 @@ TEST_P(SubprocessTest, SpawnAsyncCwdInherit) auto const args = std::array{ self_path_.c_str(), result_path.data(), arg_dump_cwd_.data(), nullptr }; - tr_error* error = nullptr; + auto error = tr_error{}; auto const ret = tr_spawn_async(std::data(args), {}, {}, &error); EXPECT_TRUE(ret); - EXPECT_EQ(nullptr, error) << *error; + EXPECT_FALSE(error) << error; waitForFileToBeReadable(result_path); @@ -276,13 +274,12 @@ TEST_P(SubprocessTest, SpawnAsyncCwdMissing) auto const args = std::array{ self_path_.c_str(), result_path.data(), arg_dump_cwd_.data(), nullptr }; - tr_error* error = nullptr; + auto error = tr_error{}; auto const ret = tr_spawn_async(std::data(args), {}, TR_IF_WIN32("C:\\", "/") "tr-missing-test-work-dir", &error); EXPECT_FALSE(ret); - EXPECT_NE(nullptr, error); - EXPECT_NE(0, error->code); - EXPECT_NE(nullptr, error->message); - tr_error_clear(&error); + EXPECT_TRUE(error); + EXPECT_NE(0, error.code()); + EXPECT_NE(""sv, error.message()); } INSTANTIATE_TEST_SUITE_P( diff --git a/tests/libtransmission/test-fixtures.h b/tests/libtransmission/test-fixtures.h index ebb937d03..3fcbfd72b 100644 --- a/tests/libtransmission/test-fixtures.h +++ b/tests/libtransmission/test-fixtures.h @@ -33,7 +33,7 @@ using namespace std::literals; inline std::ostream& operator<<(std::ostream& os, tr_error const& err) { - os << err.message << ' ' << err.code; + os << err.message() << ' ' << err.code(); return os; } @@ -148,13 +148,8 @@ protected: return path; } - tr_error* error = nullptr; - auto path = tr_sys_dir_get_current(&error); - if (error != nullptr) - { - tr_error_free(error); - } - return path; + auto error = tr_error{}; + return tr_sys_dir_get_current(&error); } static std::string create_sandbox(std::string const& parent_dir, std::string const& tmpl) @@ -210,29 +205,30 @@ protected: dir.popdir(); if (auto const info = tr_sys_path_get_info(path); !info) { - tr_error* error = nullptr; + auto error = tr_error{}; tr_sys_dir_create(dir, TR_SYS_DIR_CREATE_PARENTS, 0700, &error); - EXPECT_EQ(nullptr, error) << "path[" << path << "] dir[" << dir << "] " << *error; - tr_error_clear(&error); + EXPECT_FALSE(error) << "path[" << path << "] dir[" << dir << "] " << error; } errno = tmperr; } - static void blockingFileWrite(tr_sys_file_t fd, void const* data, size_t data_len, tr_error** error = nullptr) + static void blockingFileWrite(tr_sys_file_t fd, void const* data, size_t data_len, tr_error* error = nullptr) { + auto local_error = tr_error{}; + if (error == nullptr) + { + error = &local_error; + } + uint64_t n_left = data_len; auto const* left = static_cast(data); - while (n_left > 0) { uint64_t n = {}; - tr_error* local_error = nullptr; - if (!tr_sys_file_write(fd, left, n_left, &n, &local_error)) + if (!tr_sys_file_write(fd, left, n_left, &n, error)) { - fprintf(stderr, "Error writing file: '%s'\n", local_error->message); - tr_error_propagate(error, &local_error); - tr_error_free(local_error); + fmt::print(stderr, "Error writing file: '{:s}'\n", error->message()); break; } @@ -247,20 +243,19 @@ protected: buildParentDir(tmpl); - tr_error* error = nullptr; + auto error = tr_error{}; auto const fd = tr_sys_file_open_temp(tmpl, &error); blockingFileWrite(fd, payload, n, &error); tr_sys_file_flush(fd, &error); tr_sys_file_flush(fd, &error); tr_sys_file_close(fd, &error); - if (error != nullptr) + if (error) { fmt::print( "Couldn't create '{path}': {error} ({error_code})\n", fmt::arg("path", tmpl), - fmt::arg("error", error->message), - fmt::arg("error_code", error->code)); - tr_error_free(error); + fmt::arg("error", error.message()), + fmt::arg("error_code", error.code())); } sync(); @@ -401,7 +396,7 @@ protected: ctor, [this](tr_torrent* const tor) { - auto verified_lock = std::lock_guard{ verified_mutex_ }; + auto lambda_verified_lock = std::lock_guard{ verified_mutex_ }; verified_.emplace_back(tor); verified_cv_.notify_one(); }); @@ -446,9 +441,9 @@ protected: auto const benc = tr_base64_decode(benc_base64); EXPECT_LT(0U, std::size(benc)); auto* ctor = tr_ctorNew(session_); - tr_error* error = nullptr; + auto error = tr_error{}; EXPECT_TRUE(tr_ctorSetMetainfo(ctor, std::data(benc), std::size(benc), &error)); - EXPECT_EQ(nullptr, error) << *error; + EXPECT_FALSE(error) << error; tr_ctorSetPaused(ctor, TR_FORCE, true); // maybe create the files diff --git a/tests/libtransmission/torrent-magnet-test.cc b/tests/libtransmission/torrent-magnet-test.cc index bf954f689..ac20c173e 100644 --- a/tests/libtransmission/torrent-magnet-test.cc +++ b/tests/libtransmission/torrent-magnet-test.cc @@ -43,10 +43,9 @@ TEST_F(TorrentMagnetTest, getMetadataPiece) EXPECT_EQ(tor->info_dict_size(), info_dict_size); auto torrent_metainfo = tr_torrent_metainfo{}; - tr_error* error = nullptr; + auto error = tr_error{}; EXPECT_TRUE(torrent_metainfo.parse_benc(benc, &error)); - EXPECT_EQ(nullptr, error) << error->message; - tr_error_clear(&error); + EXPECT_FALSE(error) << error.message(); EXPECT_EQ(tor->piece_hash(0), torrent_metainfo.piece_hash(0)); } diff --git a/tests/libtransmission/torrent-metainfo-test.cc b/tests/libtransmission/torrent-metainfo-test.cc index 0cb882d23..9fe3a0dce 100644 --- a/tests/libtransmission/torrent-metainfo-test.cc +++ b/tests/libtransmission/torrent-metainfo-test.cc @@ -178,9 +178,9 @@ TEST_F(TorrentMetainfoTest, AndroidTorrent) auto const filename = tr_pathbuf{ LIBTRANSMISSION_TEST_ASSETS_DIR, "/Android-x86 8.1 r6 iso.torrent"sv }; auto* ctor = tr_ctorNew(session_); - tr_error* error = nullptr; + auto error = tr_error{}; EXPECT_TRUE(tr_ctorSetMetainfoFromFile(ctor, filename.c_str(), &error)); - EXPECT_EQ(nullptr, error) << *error; + EXPECT_FALSE(error) << error; auto const* const metainfo = tr_ctorGetMetainfo(ctor); EXPECT_NE(nullptr, metainfo); EXPECT_EQ(336, metainfo->info_dict_offset()); @@ -196,20 +196,17 @@ TEST_F(TorrentMetainfoTest, ctorSaveContents) // try saving without passing any metainfo. auto* ctor = tr_ctorNew(session_); - tr_error* error = nullptr; + auto error = tr_error{}; EXPECT_FALSE(tr_ctorSaveContents(ctor, tgt_filename.sv(), &error)); - EXPECT_NE(nullptr, error); - if (error != nullptr) - { - EXPECT_EQ(EINVAL, error->code); - tr_error_clear(&error); - } + EXPECT_TRUE(error); + EXPECT_EQ(EINVAL, error.code()); + error = {}; // now try saving _with_ metainfo EXPECT_TRUE(tr_ctorSetMetainfoFromFile(ctor, src_filename.c_str(), &error)); - EXPECT_EQ(nullptr, error) << *error; + EXPECT_FALSE(error) << error; EXPECT_TRUE(tr_ctorSaveContents(ctor, tgt_filename.sv(), &error)); - EXPECT_EQ(nullptr, error) << *error; + EXPECT_FALSE(error) << error; // the saved contents should match the source file's contents auto src_contents = std::vector{}; @@ -220,8 +217,7 @@ TEST_F(TorrentMetainfoTest, ctorSaveContents) // cleanup EXPECT_TRUE(tr_sys_path_remove(tgt_filename, &error)); - EXPECT_EQ(nullptr, error) << *error; - tr_error_clear(&error); + EXPECT_FALSE(error) << error; tr_ctorFree(ctor); } diff --git a/tests/libtransmission/utils-test.cc b/tests/libtransmission/utils-test.cc index 4e9e15720..9db1caf92 100644 --- a/tests/libtransmission/utils-test.cc +++ b/tests/libtransmission/utils-test.cc @@ -319,27 +319,26 @@ TEST_F(UtilsTest, saveFile) // save a file to GoogleTest's temp dir filename.assign(::testing::TempDir(), "filename.txt"sv); auto contents = "these are the contents"sv; - tr_error* error = nullptr; + auto error = tr_error{}; EXPECT_TRUE(tr_file_save(filename.sv(), contents, &error)); - EXPECT_EQ(nullptr, error) << *error; + EXPECT_FALSE(error) << error; // now read the file back in and confirm the contents are the same auto buf = std::vector{}; EXPECT_TRUE(tr_file_read(filename.sv(), buf, &error)); - EXPECT_EQ(nullptr, error) << *error; + EXPECT_FALSE(error) << error; auto sv = std::string_view{ std::data(buf), std::size(buf) }; EXPECT_EQ(contents, sv); // remove the tempfile EXPECT_TRUE(tr_sys_path_remove(filename, &error)); - EXPECT_EQ(nullptr, error) << *error; + EXPECT_FALSE(error) << error; // try saving a file to a path that doesn't exist filename = "/this/path/does/not/exist/foo.txt"; EXPECT_FALSE(tr_file_save(filename.sv(), contents, &error)); - ASSERT_NE(nullptr, error); - EXPECT_NE(0, error->code); - tr_error_clear(&error); + ASSERT_TRUE(error); + EXPECT_NE(0, error.code()); } TEST_F(UtilsTest, ratioToString) diff --git a/tests/libtransmission/variant-test.cc b/tests/libtransmission/variant-test.cc index 49ac58b37..8f1b89f36 100644 --- a/tests/libtransmission/variant-test.cc +++ b/tests/libtransmission/variant-test.cc @@ -420,8 +420,8 @@ TEST_F(VariantTest, stackSmash) auto serde = tr_variant_serde::benc(); auto var = serde.inplace().parse(in); EXPECT_FALSE(var.has_value()); - EXPECT_NE(nullptr, serde.error_); - EXPECT_EQ(E2BIG, serde.error_ != nullptr ? serde.error_->code : 0); + EXPECT_TRUE(serde.error_); + EXPECT_EQ(E2BIG, serde.error_.code()); } TEST_F(VariantTest, boolAndIntRecast) diff --git a/utils/create.cc b/utils/create.cc index 3c52e1eae..180d95386 100644 --- a/utils/create.cc +++ b/utils/create.cc @@ -132,19 +132,6 @@ int parseCommandLine(app_options& options, int argc, char const* const* argv) return 0; } - -std::string tr_getcwd() -{ - tr_error* error = nullptr; - auto cur = tr_sys_dir_get_current(&error); - if (error != nullptr) - { - fprintf(stderr, "getcwd error: \"%s\"", error->message); - tr_error_free(error); - } - return cur; -} - } // namespace int tr_main(int argc, char* argv[]) @@ -178,16 +165,32 @@ int tr_main(int argc, char* argv[]) if (std::empty(options.outfile)) { - tr_error* error = nullptr; + auto error = tr_error{}; auto const base = tr_sys_path_basename(options.infile, &error); - - if (std::empty(base)) + if (error) { - fprintf(stderr, "ERROR: Cannot deduce output path from input path: %s\n", error->message); + auto const errmsg = fmt::format( + "Couldn't use '{path}': {error} ({error_code})", + fmt::arg("path", options.infile), + fmt::arg("error", error.message()), + fmt::arg("error_code", error.code())); + fmt::print(stderr, "{:s}\n", errmsg); return EXIT_FAILURE; } - options.outfile = fmt::format("{:s}/{:s}.torrent"sv, tr_getcwd(), base); + auto const cur = tr_sys_dir_get_current(&error); + if (error) + { + auto const errmsg = fmt::format( + "Couldn't create '{path}': {error} ({error_code})", + fmt::arg("path", base), + fmt::arg("error", error.message()), + fmt::arg("error_code", error.code())); + fmt::print(stderr, "{:s}\n", errmsg); + return EXIT_FAILURE; + } + + options.outfile = fmt::format("{:s}/{:s}.torrent"sv, cur, base); } if (std::empty(options.trackers)) @@ -274,17 +277,20 @@ int tr_main(int argc, char* argv[]) fmt::print(" "); - if (tr_error* error = future.get(); error != nullptr) + if (auto error = future.get(); error) { - fmt::print("ERROR: {:s} {:d}\n", error->message, error->code); - tr_error_free(error); + fmt::print("ERROR: {:s} {:d}\n", error.message(), error.code()); return EXIT_FAILURE; } - if (tr_error* error = nullptr; !builder.save(options.outfile, &error)) + if (auto error = tr_error{}; !builder.save(options.outfile, &error)) { - fmt::print("ERROR: could not save \"{:s}\": {:s} {:d}\n", options.outfile, error->message, error->code); - tr_error_free(error); + auto const errmsg = fmt::format( + "Couldn't save '{path}': {error} ({error_code})", + fmt::arg("path", options.outfile), + fmt::arg("error", error.message()), + fmt::arg("error_code", error.code())); + fmt::print(stderr, "{:s}\n", errmsg); return EXIT_FAILURE; } diff --git a/utils/edit.cc b/utils/edit.cc index 70644103b..e5b6b2922 100644 --- a/utils/edit.cc +++ b/utils/edit.cc @@ -366,7 +366,7 @@ int tr_main(int argc, char* argv[]) auto otop = serde.parse_file(filename); if (!otop) { - fmt::print("\tError reading file: {:s}\n", serde.error_->message); + fmt::print("\tError reading file: {:s}\n", serde.error_.message()); continue; } auto& top = *otop; diff --git a/utils/show.cc b/utils/show.cc index 0de4b6e99..5a6a99680 100644 --- a/utils/show.cc +++ b/utils/show.cc @@ -436,12 +436,11 @@ int tr_main(int argc, char* argv[]) /* try to parse the torrent file */ auto metainfo = tr_torrent_metainfo{}; - tr_error* error = nullptr; + auto error = tr_error{}; auto const parsed = metainfo.parse_torrent_file(opts.filename, nullptr, &error); - if (error != nullptr) + if (error) { - fmt::print(stderr, "Error parsing torrent file '{:s}': {:s} ({:d})\n", opts.filename, error->message, error->code); - tr_error_clear(&error); + fmt::print(stderr, "Error parsing torrent file '{:s}': {:s} ({:d})\n", opts.filename, error.message(), error.code()); } if (!parsed) {