refactor: remove the tr_error** idiom (#6198)

* refactor: remove the tr_error** idiom

* fix: tr_error::message() is only constexpr in c++20 and up

* chore: silence a couple of g++-12 Wshadow warnings
This commit is contained in:
Charles Kerr 2023-11-04 11:39:41 -05:00 committed by GitHub
parent 4d95aa5298
commit a952a0731f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
75 changed files with 1162 additions and 1254 deletions

View File

@ -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;
}
}

View File

@ -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;

View File

@ -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;

View File

@ -165,7 +165,7 @@ static auto constexpr Options = std::array<tr_option, 45>{
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<char>{};
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);
}

View File

@ -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();

View File

@ -67,7 +67,7 @@ public:
BaseObjectType* cast_item,
Glib::RefPtr<Gtk::Builder> const& builder,
tr_metainfo_builder& metainfo_builder,
std::future<tr_error*> future,
std::future<tr_error> future,
std::string_view target,
Glib::RefPtr<Session> const& core);
~MakeProgressDialog() override;
@ -77,7 +77,7 @@ public:
static std::unique_ptr<MakeProgressDialog> create(
std::string_view target,
tr_metainfo_builder& metainfo_builder,
std::future<tr_error*> future,
std::future<tr_error> future,
Glib::RefPtr<Session> const& core);
[[nodiscard]] bool success() const
@ -93,7 +93,7 @@ private:
private:
tr_metainfo_builder& builder_;
std::future<tr_error*> future_;
std::future<tr_error> future_;
std::string const target_;
Glib::RefPtr<Session> 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<Gtk::Builder> const& builder,
tr_metainfo_builder& metainfo_builder,
std::future<tr_error*> future,
std::future<tr_error> future,
std::string_view target,
Glib::RefPtr<Session> const& core)
: Gtk::Dialog(cast_item)
@ -302,7 +301,7 @@ MakeProgressDialog::MakeProgressDialog(
std::unique_ptr<MakeProgressDialog> MakeProgressDialog::create(
std::string_view target,
tr_metainfo_builder& metainfo_builder,
std::future<tr_error*> future,
std::future<tr_error> future,
Glib::RefPtr<Session> const& core)
{
auto const builder = Gtk::Builder::create_from_resource(gtr_get_full_resource_path("MakeProgressDialog.ui"));

View File

@ -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);
}

View File

@ -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;
}
}

View File

@ -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);

View File

@ -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;

View File

@ -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<std::string> announce_to_scrape(std::string_view announce);

View File

@ -440,17 +440,16 @@ void tr_announcerParseHttpAnnounceResponse(tr_announce_response& response, std::
auto stack = transmission::benc::ParserStack<MaxBencDepth>{};
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<MaxBencDepth>{};
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);
}
}

View File

@ -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<ParentType> pop(tr_error** error)
std::optional<ParentType> 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<MaxDepth>& 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<MaxDepth>::ParentType::Array, error) :
stack.push(ParserStack<MaxDepth>::ParentType::Dict, error);
bool ok = benc.front() == 'l' ? stack.push(ParserStack<MaxDepth>::ParentType::Array, *error) :
stack.push(ParserStack<MaxDepth>::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;
}

View File

@ -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> 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)
{

View File

@ -3,95 +3,12 @@
// or any future license endorsed by Mnemosyne LLC.
// License text can be found in the licenses/ folder.
#include <algorithm>
#include <string_view>
#include <fmt/core.h>
#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) : "";
}

View File

@ -5,77 +5,61 @@
#pragma once
#include <string>
#include <string_view>
/**
* @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);
/** @} */

View File

@ -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_capacity> tr_sys_path_get_capacity(std::string_view path, tr_error** error)
std::optional<tr_sys_path_capacity> 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_capacity> 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 {};
}

View File

@ -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_info> tr_sys_path_get_info(std::string_view path, int flags, tr_error** error)
std::optional<tr_sys_path_info> 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_info> 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<char, PATH_MAX>{};
@ -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<int>(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<char>{};
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<DIR*>(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<DIR*>(handle)) != -1;
if (!ret)
if (auto const ret = closedir(static_cast<DIR*>(handle)) != -1; ret)
{
tr_error_set_from_errno(error, errno);
return ret;
}
return ret;
if (error != nullptr)
{
error->set_from_errno(errno);
}
return {};
}

View File

@ -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_path_info> tr_sys_file_get_info_(tr_sys_file_t handle, tr_error** error)
static std::optional<tr_sys_path_info> 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_path_info> tr_sys_file_get_info_(tr_sys_file_t handl
return {};
}
std::optional<tr_sys_path_info> tr_sys_path_get_info(std::string_view path, int flags, tr_error** error)
std::optional<tr_sys_path_info> 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<BY_HANDLE_FILE_INFORMATION> get_file_info(char const* path, tr_error** error)
static std::optional<BY_HANDLE_FILE_INFORMATION> 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<BY_HANDLE_FILE_INFORMATION> 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<tr_sys_file_t*>(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<bool*>(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);

View File

@ -7,6 +7,7 @@
#include <string_view>
#include <vector>
#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<std::string> tr_sys_dir_get_files(
std::string_view folder,
std::function<bool(std::string_view)> const& test,
tr_error** error)
tr_error* error)
{
if (auto const info = tr_sys_path_get_info(folder); !info || !info->isFolder())
{

View File

@ -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_info> 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_capacity> tr_sys_path_get_capacity(std::string_view path, tr_error** error = nullptr);
[[nodiscard]] std::optional<tr_sys_path_capacity> 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<typename T, typename = decltype(&T::c_str)>
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<typename T, typename U, typename = decltype(&T::c_str), typename = decltype(&U::c_str)>
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<typename T, typename U, typename = decltype(&T::c_str), typename = decltype(&U::c_str)>
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<typename T, typename = decltype(&T::c_str)>
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<typename T, typename = decltype(&T::c_str)>
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<std::string> tr_sys_dir_get_files(
std::string_view folder,
std::function<bool(std::string_view name)> const& test = tr_basename_is_not_dotfile,
tr_error** error = nullptr);
tr_error* error = nullptr);
/** @} */
/** @} */

View File

@ -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);
}

View File

@ -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)

View File

@ -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;
}

View File

@ -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;

View File

@ -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 {};
}

View File

@ -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<tr_error*> make_checksums()
// - Resolves with a `tr_error` which is set on failure or empty on success.
std::future<tr_error> 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_;

View File

@ -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<uint8_t, 4096>{};
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_sys_file_t> 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_sys_file_t> 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_sys_file_t> 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_sys_file_t> 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_sys_file_t> 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 {};
}

View File

@ -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 */

View File

@ -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<size_t>(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{})
{

View File

@ -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
{

View File

@ -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()));
}
}

View File

@ -278,10 +278,9 @@ void serve_file(struct evhttp_request* req, tr_rpc_server const* server, std::st
auto content = std::vector<char>{};
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;
}

View File

@ -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 */

View File

@ -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;

View File

@ -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<std::string_view, std::string_view> const& env,
std::string_view work_dir,
tr_error** error)
tr_error* error)
{
static bool sigchld_handler_set = false;

View File

@ -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<std::string_view, std::string_view> const& env,
std::string_view work_dir,
tr_error** error)
tr_error* error)
{
// full_env = current_env + env;
auto full_env = get_current_env();

View File

@ -14,4 +14,4 @@ bool tr_spawn_async(
char const* const* cmd,
std::map<std::string_view, std::string_view> const& env,
std::string_view work_dir,
tr_error** error);
tr_error* error);

View File

@ -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;
}

View File

@ -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 };

View File

@ -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(char const* filename)>;
void remove(std::string_view parent_in, std::string_view tmpdir_prefix, FileFunc const& func) const;

View File

@ -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

View File

@ -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);

View File

@ -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<MaxBencDepth>
@ -368,7 +363,7 @@ struct MetainfoHandler final : public transmission::benc::BasicHandler<MaxBencDe
}
else
{
tr_error_set(context.error, EINVAL, fmt::format("invalid piece size: {}", std::size(value)));
context.error.set(EINVAL, fmt::format("invalid piece size: {}", std::size(value)));
unhandled = true;
}
}
@ -470,7 +465,7 @@ private:
// for hybrid torrents with duplicate info between "file tree" and "files"
if (std::empty(file_subpath_))
{
tr_error_set(context.error, EINVAL, fmt::format("invalid path [{:s}]", file_subpath_));
context.error.set(EINVAL, fmt::format("invalid path [{:s}]", file_subpath_));
ok = false;
}
else
@ -489,7 +484,7 @@ private:
{
if (std::empty(info_dict_begin_))
{
tr_error_set(context.error, EINVAL, "no info_dict found");
context.error.set(EINVAL, "no info_dict found");
return false;
}
@ -536,18 +531,18 @@ private:
// do some sanity checks to make sure the torrent looks sane
if (tm_.file_count() == 0)
{
if (!tr_error_is_set(context.error))
if (!context.error)
{
tr_error_set(context.error, EINVAL, "no files found");
context.error.set(EINVAL, "no files found");
}
return false;
}
if (piece_size_ == 0)
{
if (!tr_error_is_set(context.error))
if (!context.error)
{
tr_error_set(context.error, EINVAL, fmt::format("invalid piece size: {}", piece_size_));
context.error.set(EINVAL, fmt::format("invalid piece size: {}", piece_size_));
}
return false;
}
@ -627,26 +622,24 @@ private:
static constexpr std::string_view XCrossSeedKey = "x_cross_seed"sv;
};
bool tr_torrent_metainfo::parse_benc(std::string_view benc, tr_error** error)
bool tr_torrent_metainfo::parse_benc(std::string_view benc, tr_error* error)
{
auto stack = transmission::benc::ParserStack<MaxBencDepth>{};
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<char>* contents, tr_error** error)
bool tr_torrent_metainfo::parse_torrent_file(std::string_view filename, std::vector<char>* contents, tr_error* error)
{
auto local_contents = std::vector<char>{};

View File

@ -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<char>* contents = nullptr, tr_error** error = nullptr);
bool parse_torrent_file(std::string_view benc_filename, std::vector<char>* 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

View File

@ -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;

View File

@ -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);

View File

@ -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<char*>(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 {};

View File

@ -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);

View File

@ -93,54 +93,56 @@ std::optional<std::locale> tr_locale_set_global(std::locale const& locale) noexc
// ---
bool tr_file_read(std::string_view filename, std::vector<char>& contents, tr_error** error)
bool tr_file_read(std::string_view filename, std::vector<char>& 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<char>& 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;

View File

@ -63,14 +63,14 @@ std::optional<std::locale> 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<char>& contents, tr_error** error = nullptr);
bool tr_file_read(std::string_view filename, std::vector<char>& 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<typename ContiguousRange>
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);
}

View File

@ -239,13 +239,12 @@ std::optional<tr_variant> 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})"),

View File

@ -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> 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;
}

View File

@ -16,11 +16,10 @@
#include <variant>
#include <vector>
#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<Val, std::string_view>)
{
auto const* const str = std::get_if<StringHolder>(&val_);
return str != nullptr ? &str->sv_ : nullptr;
auto const* const val = std::get_if<StringHolder>(&val_);
return val != nullptr ? &val->sv_ : nullptr;
}
else
{
@ -294,8 +293,8 @@ public:
{
if constexpr (Index == StringIndex)
{
auto const* const str = std::get_if<StringIndex>(&val_);
return str != nullptr ? &str->sv_ : nullptr;
auto const* const val = std::get_if<StringIndex>(&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;

View File

@ -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())));
}
}

View File

@ -44,7 +44,7 @@ typedef NS_ENUM(NSUInteger, TrackerSegmentTag) {
@property(nonatomic, readonly) std::shared_ptr<tr_metainfo_builder> fBuilder;
@property(nonatomic, readonly) NSURL* fPath;
@property(nonatomic) std::shared_future<tr_error*> fFuture;
@property(nonatomic) std::shared_future<tr_error> fFuture;
@property(nonatomic) NSURL* fLocation; // path to new torrent file
@property(nonatomic) NSMutableArray<NSString*>* 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<int>(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
{

View File

@ -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;
}
}

View File

@ -38,7 +38,7 @@ public:
MakeProgressDialog(
Session& session,
tr_metainfo_builder& builder,
std::future<tr_error*> future,
std::future<tr_error> future,
QString outfile,
QWidget* parent = nullptr);
@ -49,7 +49,7 @@ private slots:
private:
Session& session_;
tr_metainfo_builder& builder_;
std::future<tr_error*> future_;
std::future<tr_error> future_;
QString const outfile_;
Ui::MakeProgressDialog ui_ = {};
QTimer timer_;
@ -60,7 +60,7 @@ private:
MakeProgressDialog::MakeProgressDialog(
Session& session,
tr_metainfo_builder& builder,
std::future<tr_error*> future,
std::future<tr_error> 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());
}
}

View File

@ -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<char>{};
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{};

View File

@ -26,14 +26,10 @@ TEST_F(BencTest, MalformedBenc)
auto stack = transmission::benc::ParserStack<MaxBencDepth>{};
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<MaxBencDepth>{};
auto handler = ContextHandler{};
tr_error* error = nullptr;
auto error = tr_error{};
transmission::benc::parse(Benc, stack, handler, nullptr, &error);
EXPECT_FALSE(error);
}

View File

@ -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));

View File

@ -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;
}

File diff suppressed because it is too large Load Diff

View File

@ -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());

View File

@ -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)

View File

@ -14,6 +14,7 @@
#include <libtransmission/transmission.h>
#include <libtransmission/crypto-utils.h>
#include <libtransmission/error.h>
#include <libtransmission/file.h>
#include <libtransmission/resume.h>
#include <libtransmission/torrent.h> // 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

View File

@ -86,14 +86,12 @@ TEST_P(SubprocessTest, SpawnAsyncMissingExec)
auto args = std::array<char const*, 2>{ 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<char const*, 4>{ 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<char const*, 4>{ 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<char const*, 4>{ 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(

View File

@ -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<uint8_t const*>(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

View File

@ -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));
}

View File

@ -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<char>{};
@ -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);
}

View File

@ -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<char>{};
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)

View File

@ -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)

View File

@ -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;
}

View File

@ -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;

View File

@ -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)
{