diff --git a/gtk/FreeSpaceLabel.cc b/gtk/FreeSpaceLabel.cc index 83db14085..cd075c8a6 100644 --- a/gtk/FreeSpaceLabel.cc +++ b/gtk/FreeSpaceLabel.cc @@ -53,10 +53,9 @@ bool FreeSpaceLabel::Impl::on_freespace_timer() return false; } - auto ec = std::error_code{}; - auto const capacity = std::filesystem::space(tr_u8path(dir_), ec); - auto const text = !ec ? - fmt::format(fmt::runtime(_("{disk_space} free")), fmt::arg("disk_space", tr_strlsize(capacity.available))) : + auto const capacity = tr_sys_path_get_capacity(std::string_view{ dir_ }); + auto const text = capacity ? + fmt::format(fmt::runtime(_("{disk_space} free")), fmt::arg("disk_space", tr_strlsize(capacity->available))) : _("Error"); label_.set_markup(fmt::format("{:s}", text)); diff --git a/libtransmission/file.cc b/libtransmission/file.cc index d6dcbfd70..aac39efaf 100644 --- a/libtransmission/file.cc +++ b/libtransmission/file.cc @@ -11,7 +11,6 @@ #include "libtransmission/error.h" #include "libtransmission/file.h" -#include "libtransmission/tr-assert.h" std::string tr_sys_path_resolve(std::string_view path, tr_error* error) { @@ -65,3 +64,19 @@ std::vector tr_sys_dir_get_files( } } } + +std::optional tr_sys_path_get_capacity(std::filesystem::path const& path, tr_error* error) +{ + auto ec = std::error_code{}; + auto space = std::filesystem::space(path, ec); + if (!ec) + { + return space; + } + + if (error != nullptr) + { + error->set(ec.value(), ec.message()); + } + return {}; +} diff --git a/libtransmission/file.h b/libtransmission/file.h index bf18be751..de8e05173 100644 --- a/libtransmission/file.h +++ b/libtransmission/file.h @@ -102,6 +102,28 @@ struct tr_sys_path_info } }; +/** + * Temporary replacement of deprecated `std::filesystem::u8path()` while we migrate + * from char to char8_t strings. + * + * https://stackoverflow.com/a/57635139/11390656 + * @{ + */ + +template +[[nodiscard]] std::filesystem::path tr_u8path(InputIt begin, InputIt end) +{ + auto const view = std::ranges::subrange(begin, end) | std::views::transform([](char const c) -> char8_t { return c; }); + return { view.begin(), view.end() }; +} + +[[nodiscard]] inline std::filesystem::path tr_u8path(std::string_view path) +{ + return tr_u8path(path.begin(), path.end()); +} + +/// @} + /** * @name Platform-specific wrapper functions * @@ -144,6 +166,23 @@ bool tr_sys_path_copy(std::string_view src_path, std::string_view dst_path, tr_e int flags = 0, tr_error* error = nullptr); +/** + * @brief Get disk capacity and free disk space (in bytes) for the specified folder. + * + * @param[in] path Path to directory. + * @param[out] error Pointer to error object. Optional, pass `nullptr` if you + * are not interested in error details. + */ +[[nodiscard]] std::optional tr_sys_path_get_capacity( + std::filesystem::path const& path, + tr_error* error = nullptr); +[[nodiscard]] inline std::optional tr_sys_path_get_capacity( + std::string_view path, + tr_error* error = nullptr) +{ + return tr_sys_path_get_capacity(tr_u8path(path), error); +} + /** * @brief Portability wrapper for `access()`. * @@ -510,25 +549,3 @@ bool tr_sys_dir_close(tr_sys_dir_t handle, tr_error* error = nullptr); /** @} */ /** @} */ - -/** - * Temporary replacement of deprecated `std::filesystem::u8path()` while we migrate - * from char to char8_t strings. - * - * https://stackoverflow.com/a/57635139/11390656 - * @{ - */ - -template -[[nodiscard]] std::filesystem::path tr_u8path(InputIt begin, InputIt end) -{ - auto const view = std::ranges::subrange(begin, end) | std::views::transform([](char const c) -> char8_t { return c; }); - return { view.begin(), view.end() }; -} - -[[nodiscard]] inline std::filesystem::path tr_u8path(std::string_view path) -{ - return tr_u8path(path.begin(), path.end()); -} - -/// @} diff --git a/libtransmission/rpcimpl.cc b/libtransmission/rpcimpl.cc index 9b3993f8e..3ca2081a7 100644 --- a/libtransmission/rpcimpl.cc +++ b/libtransmission/rpcimpl.cc @@ -2231,9 +2231,12 @@ using SessionAccessors = std::pair; TR_KEY_download_dir_free_space, [](tr_session const& src) -> tr_variant { - auto ec = std::error_code{}; - auto const space = std::filesystem::space(tr_u8path(src.downloadDir()), ec); - return !ec ? space.available : tr_variant{ -1 }; + // TODO(C++23): use std::optional::transform() instead + if (auto const space = tr_sys_path_get_capacity(std::string_view{ src.downloadDir() })) + { + return space->available; + } + return -1; }, nullptr); @@ -2736,17 +2739,17 @@ using SessionAccessors = std::pair; } // get the free space - auto ec = std::error_code{}; - auto const capacity = std::filesystem::space(tr_u8path(*path), ec); + auto error = tr_error{}; + auto const capacity = tr_sys_path_get_capacity(*path, &error); // response args_out.try_emplace(TR_KEY_path, *path); - args_out.try_emplace(TR_KEY_size_bytes, !ec ? capacity.available : tr_variant{ -1 }); - args_out.try_emplace(TR_KEY_total_size, !ec ? capacity.capacity : tr_variant{ -1 }); + args_out.try_emplace(TR_KEY_size_bytes, capacity ? capacity->available : tr_variant{ -1 }); + args_out.try_emplace(TR_KEY_total_size, capacity ? capacity->capacity : tr_variant{ -1 }); - if (ec) + if (error) { - return { Error::SYSTEM_ERROR, ec.message() }; + return { Error::SYSTEM_ERROR, std::string{ error.message() } }; } return { Error::SUCCESS, {} }; }