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