refactor: tr_loadFile() tr_saveFile() take a std::string_view filename arg (#2822)

* refactor: tr_saveFile takes a string_view

* refactor: tr_saveFile, tr_loadFile take string_view filename
This commit is contained in:
Charles Kerr 2022-03-25 19:31:27 -05:00 committed by GitHub
parent 1051160b99
commit 977b2a1bab
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
15 changed files with 102 additions and 86 deletions

View File

@ -210,7 +210,7 @@ bool tr_sys_path_is_same(char const* path1, char const* path2, struct tr_error**
* when no longer needed), `nullptr` otherwise (with `error` set
* accordingly).
*/
char* tr_sys_path_resolve(char const* path, struct tr_error** error);
char* tr_sys_path_resolve(char const* path, struct tr_error** error = nullptr);
/**
* @brief Portability wrapper for `basename()`.

View File

@ -250,7 +250,7 @@ static std::string getUserDirsFilename()
static std::string getXdgEntryFromUserDirs(std::string_view key)
{
auto content = std::vector<char>{};
if (!tr_loadFile(content, getUserDirsFilename()) && std::empty(content))
if (!tr_loadFile(getUserDirsFilename(), content) && std::empty(content))
{
return {};
}

View File

@ -675,7 +675,7 @@ static auto loadFromFile(tr_torrent* tor, tr_resume::fields_t fieldsToLoad, bool
auto buf = std::vector<char>{};
tr_error* error = nullptr;
auto top = tr_variant{};
if (!tr_loadFile(buf, filename, &error) ||
if (!tr_loadFile(filename, buf, &error) ||
!tr_variantFromBuf(
&top,
TR_VARIANT_PARSE_BENC | TR_VARIANT_PARSE_INPLACE,

View File

@ -4,6 +4,7 @@
// License text can be found in the licenses/ folder.
#include <algorithm>
#include <array>
#include <cerrno>
#include <cstring> /* memcpy */
#include <ctime>
@ -43,6 +44,7 @@
#include "session-id.h"
#include "session.h"
#include "tr-assert.h"
#include "tr-strbuf.h"
#include "trevent.h"
#include "utils.h"
#include "variant.h"
@ -137,29 +139,24 @@ static void send_simple_response(struct evhttp_request* req, int code, char cons
****
***/
static char const* mimetype_guess(char const* path)
static char const* mimetype_guess(std::string_view path)
{
struct
{
char const* suffix;
char const* mime_type;
} const types[] = {
/* these are the ones we need for serving the web client's files... */
{ "css", "text/css" },
{ "gif", "image/gif" },
{ "html", "text/html" },
{ "ico", "image/vnd.microsoft.icon" },
{ "js", "application/javascript" },
{ "png", "image/png" },
{ "svg", "image/svg+xml" },
};
char const* dot = strrchr(path, '.');
// these are the ones we need for serving the web client's files...
static auto constexpr Types = std::array<std::pair<std::string_view, char const*>, 7>{ {
{ ".css"sv, "text/css" },
{ ".gif"sv, "image/gif" },
{ ".html"sv, "text/html" },
{ ".ico"sv, "image/vnd.microsoft.icon" },
{ ".js"sv, "application/javascript" },
{ ".png"sv, "image/png" },
{ ".svg"sv, "image/svg+xml" },
} };
for (unsigned int i = 0; dot != nullptr && i < TR_N_ELEMENTS(types); ++i)
for (auto const& [suffix, mime_type] : Types)
{
if (strcmp(dot + 1, types[i].suffix) == 0)
if (tr_strvEndsWith(path, suffix))
{
return types[i].mime_type;
return mime_type;
}
}
@ -222,7 +219,7 @@ static void evbuffer_ref_cleanup_tr_free(void const* /*data*/, size_t /*datalen*
tr_free(extra);
}
static void serve_file(struct evhttp_request* req, tr_rpc_server* server, char const* filename)
static void serve_file(struct evhttp_request* req, tr_rpc_server* server, std::string_view filename)
{
if (req->type != EVHTTP_REQ_GET)
{
@ -294,11 +291,8 @@ static void handle_web_client(struct evhttp_request* req, tr_rpc_server* server)
}
else
{
auto const filename = tr_strvJoin(
webClientDir,
TR_PATH_DELIMITER_STR,
tr_str_is_empty(subpath) ? "index.html" : subpath);
serve_file(req, server, filename.c_str());
auto const filename = tr_pathbuf{ webClientDir, "/"sv, tr_str_is_empty(subpath) ? "index.html" : subpath };
serve_file(req, server, filename.sv());
}
tr_free(subpath);

View File

@ -34,6 +34,7 @@
#include "torrent.h"
#include "tr-assert.h"
#include "tr-macros.h"
#include "tr-strbuf.h"
#include "utils.h"
#include "variant.h"
#include "version.h"
@ -1439,11 +1440,17 @@ static void onBlocklistFetched(tr_web::FetchResponse const& web_response)
// tr_blocklistSetContent needs a source file,
// so save content into a tmpfile
auto const filename = tr_strvJoin(tr_sessionGetConfigDir(session), "blocklist.tmp");
auto const filename = tr_pathbuf{ session->config_dir, "/blocklist.tmp"sv };
tr_error* error = nullptr;
if (!tr_saveFile(filename, std::string_view{ std::data(content), std::size(content) }, &error))
if (!tr_saveFile(filename.sv(), content, &error))
{
tr_snprintf(result, sizeof(result), _("Couldn't save file \"%1$s\": %2$s"), filename.c_str(), error->message);
fmt::format_to_n(
result,
sizeof(result),
_("Couldn't save '{path}': {error} ({error_code})"),
fmt::arg("path", filename.sv()),
fmt::arg("error", error->message),
fmt::arg("error_code", error->code));
tr_error_clear(&error);
tr_idle_function_done(data, result);
return;

View File

@ -56,6 +56,7 @@
#include "tr-assert.h"
#include "tr-dht.h" /* tr_dhtUpkeep() */
#include "tr-lpd.h"
#include "tr-strbuf.h"
#include "tr-udp.h"
#include "tr-utp.h"
#include "trevent.h"
@ -2020,7 +2021,6 @@ static void sessionLoadTorrents(struct sessionLoadTorrentsData* const data)
if (odir != TR_BAD_SYS_DIR)
{
auto const dirname_sv = std::string_view{ dirname };
auto path = std::string{};
char const* name = nullptr;
while ((name = tr_sys_dir_read_name(odir, nullptr)) != nullptr)
@ -2030,12 +2030,12 @@ static void sessionLoadTorrents(struct sessionLoadTorrentsData* const data)
continue;
}
tr_buildBuf(path, dirname_sv, "/", name);
auto const path = tr_pathbuf{ dirname_sv, "/"sv, name };
// is a magnet link?
if (!tr_ctorSetMetainfoFromFile(data->ctor, path, nullptr))
if (!tr_ctorSetMetainfoFromFile(data->ctor, std::string{ path.sv() }, nullptr))
{
if (auto buf = std::vector<char>{}; tr_loadFile(buf, path))
if (auto buf = std::vector<char>{}; tr_loadFile(path.sv(), buf))
{
tr_ctorSetMetainfoFromMagnetLink(
data->ctor,

View File

@ -74,7 +74,7 @@ bool tr_ctorSetMetainfoFromFile(tr_ctor* ctor, std::string const& filename, tr_e
return false;
}
if (!tr_loadFile(ctor->contents, filename, error))
if (!tr_loadFile(filename, ctor->contents, error))
{
return false;
}
@ -124,7 +124,7 @@ bool tr_ctorSaveContents(tr_ctor const* ctor, std::string const& filename, tr_er
return false;
}
return tr_saveFile(filename, { std::data(ctor->contents), std::size(ctor->contents) }, error);
return tr_saveFile(filename, ctor->contents, error);
}
bool tr_ctorSaveMagnetContents(tr_torrent* tor, std::string const& filename, tr_error** error)

View File

@ -493,8 +493,7 @@ bool tr_torrent_metainfo::parseTorrentFile(std::string_view filename, std::vecto
contents = &local_contents;
}
auto const sz_filename = std::string{ filename };
return tr_loadFile(*contents, sz_filename, error) && parseBenc({ std::data(*contents), std::size(*contents) }, error);
return tr_loadFile(filename, *contents, error) && parseBenc({ std::data(*contents), std::size(*contents) }, error);
}
tr_sha1_digest_t const& tr_torrent_metainfo::pieceHash(tr_piece_index_t piece) const

View File

@ -49,6 +49,7 @@
#include "net.h" // ntohl()
#include "platform-quota.h" /* tr_device_info_create(), tr_device_info_get_disk_space(), tr_device_info_free() */
#include "tr-assert.h"
#include "tr-strbuf.h"
#include "utils.h"
#include "variant.h"
@ -226,16 +227,18 @@ void tr_timerAddMsec(struct event* timer, int msec)
***
**/
uint8_t* tr_loadFile(char const* path, size_t* size, tr_error** error)
uint8_t* tr_loadFile(std::string_view path_in, size_t* size, tr_error** error)
{
auto const path = tr_pathbuf{ path_in };
/* try to stat the file */
auto info = tr_sys_path_info{};
tr_error* my_error = nullptr;
if (!tr_sys_path_get_info(path, 0, &info, &my_error))
if (!tr_sys_path_get_info(path.c_str(), 0, &info, &my_error))
{
tr_logAddError(fmt::format(
_("Couldn't read '{path}': {error} ({error_code})"),
fmt::arg("path", path),
fmt::arg("path", path.sv()),
fmt::arg("error", my_error->message),
fmt::arg("error_code", my_error->code)));
tr_error_propagate(error, &my_error);
@ -244,7 +247,7 @@ uint8_t* tr_loadFile(char const* path, size_t* size, tr_error** error)
if (info.type != TR_SYS_PATH_IS_FILE)
{
tr_logAddError(fmt::format(_("Couldn't read '{path}': Not a regular file"), fmt::arg("path", path)));
tr_logAddError(fmt::format(_("Couldn't read '{path}': Not a regular file"), fmt::arg("path", path.sv())));
tr_error_set(error, TR_ERROR_EISDIR, "Not a regular file"sv);
return nullptr;
}
@ -256,12 +259,12 @@ uint8_t* tr_loadFile(char const* path, size_t* size, tr_error** error)
}
/* Load the torrent file into our buffer */
auto const fd = tr_sys_file_open(path, TR_SYS_FILE_READ | TR_SYS_FILE_SEQUENTIAL, 0, &my_error);
auto const fd = tr_sys_file_open(path.c_str(), TR_SYS_FILE_READ | TR_SYS_FILE_SEQUENTIAL, 0, &my_error);
if (fd == TR_BAD_SYS_FILE)
{
tr_logAddError(fmt::format(
_("Couldn't read '{path}': {error} ({error_code})"),
fmt::arg("path", path),
fmt::arg("path", path.sv()),
fmt::arg("error", my_error->message),
fmt::arg("error_code", my_error->code)));
tr_error_propagate(error, &my_error);
@ -273,7 +276,7 @@ uint8_t* tr_loadFile(char const* path, size_t* size, tr_error** error)
{
tr_logAddError(fmt::format(
_("Couldn't read '{path}': {error} ({error_code})"),
fmt::arg("path", path),
fmt::arg("path", path.sv()),
fmt::arg("error", my_error->message),
fmt::arg("error_code", my_error->code)));
tr_sys_file_close(fd, nullptr);
@ -288,18 +291,18 @@ uint8_t* tr_loadFile(char const* path, size_t* size, tr_error** error)
return buf;
}
bool tr_loadFile(std::vector<char>& setme, std::string const& path, tr_error** error)
bool tr_loadFile(std::string_view path_in, std::vector<char>& setme, tr_error** error)
{
auto const* const path_sz = path.c_str();
auto const path = tr_pathbuf{ path_in };
/* try to stat the file */
auto info = tr_sys_path_info{};
tr_error* my_error = nullptr;
if (!tr_sys_path_get_info(path_sz, 0, &info, &my_error))
if (!tr_sys_path_get_info(path.c_str(), 0, &info, &my_error))
{
tr_logAddError(fmt::format(
_("Couldn't read '{path}': {error} ({error_code})"),
fmt::arg("path", path),
fmt::arg("path", path.sv()),
fmt::arg("error", my_error->message),
fmt::arg("error_code", my_error->code)));
tr_error_propagate(error, &my_error);
@ -308,18 +311,18 @@ bool tr_loadFile(std::vector<char>& setme, std::string const& path, tr_error** e
if (info.type != TR_SYS_PATH_IS_FILE)
{
tr_logAddError(fmt::format(_("Couldn't read '{path}': Not a regular file"), fmt::arg("path", path)));
tr_logAddError(fmt::format(_("Couldn't read '{path}': Not a regular file"), fmt::arg("path", path.sv())));
tr_error_set(error, TR_ERROR_EISDIR, "Not a regular file"sv);
return false;
}
/* Load the torrent file into our buffer */
auto const fd = tr_sys_file_open(path_sz, TR_SYS_FILE_READ | TR_SYS_FILE_SEQUENTIAL, 0, &my_error);
auto const fd = tr_sys_file_open(path.c_str(), TR_SYS_FILE_READ | TR_SYS_FILE_SEQUENTIAL, 0, &my_error);
if (fd == TR_BAD_SYS_FILE)
{
tr_logAddError(fmt::format(
_("Couldn't read '{path}': {error} ({error_code})"),
fmt::arg("path", path),
fmt::arg("path", path.sv()),
fmt::arg("error", my_error->message),
fmt::arg("error_code", my_error->code)));
tr_error_propagate(error, &my_error);
@ -331,7 +334,7 @@ bool tr_loadFile(std::vector<char>& setme, std::string const& path, tr_error** e
{
tr_logAddError(fmt::format(
_("Couldn't read '{path}': {error} ({error_code})"),
fmt::arg("path", path),
fmt::arg("path", path.sv()),
fmt::arg("error", my_error->message),
fmt::arg("error_code", my_error->code)));
tr_sys_file_close(fd, nullptr);
@ -343,24 +346,26 @@ bool tr_loadFile(std::vector<char>& setme, std::string const& path, tr_error** e
return true;
}
bool tr_saveFile(std::string const& filename, std::string_view contents, tr_error** error)
bool tr_saveFile(std::string_view filename_in, std::string_view contents, tr_error** error)
{
auto const filename = tr_pathbuf{ filename_in };
// 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
if (char* const real_filename_c_str = tr_sys_path_resolve(filename.c_str(), nullptr); real_filename_c_str != nullptr)
if (char* const real_filename = tr_sys_path_resolve(filename.c_str()); real_filename != nullptr)
{
auto const real_filename = std::string{ real_filename_c_str };
tr_free(real_filename_c_str);
if (real_filename != filename)
if (filename_in != real_filename)
{
return tr_saveFile(real_filename, contents, error);
auto const saved = tr_saveFile(real_filename, contents, error);
tr_free(real_filename);
return saved;
}
tr_free(real_filename);
}
// Write it to a temp file first.
// This is a safeguard against edge cases, e.g. disk full, crash while writing, etc.
auto tmp = tr_strvJoin(filename, ".tmp.XXXXXX"sv);
auto tmp = tr_pathbuf{ filename.sv(), ".tmp.XXXXXX"sv };
auto const fd = tr_sys_file_open_temp(std::data(tmp), error);
if (fd == TR_BAD_SYS_FILE)
{
@ -386,7 +391,7 @@ bool tr_saveFile(std::string const& filename, std::string_view contents, tr_erro
return false;
}
tr_logAddTrace(fmt::format("Saved '{}'", filename));
tr_logAddTrace(fmt::format("Saved '{}'", filename.sv()));
return true;
}

View File

@ -79,11 +79,17 @@ bool tr_wildmat(char const* text, char const* pattern) TR_GNUC_NONNULL(1, 2);
* @brief Loads a file and returns its contents.
* On failure, NULL is returned and errno is set.
*/
uint8_t* tr_loadFile(char const* filename, size_t* size, struct tr_error** error) TR_GNUC_MALLOC TR_GNUC_NONNULL(1);
uint8_t* tr_loadFile(std::string_view filename, size_t* size, struct tr_error** error) TR_GNUC_MALLOC;
bool tr_loadFile(std::vector<char>& setme, std::string const& filename, tr_error** error = nullptr);
bool tr_loadFile(std::string_view filename, std::vector<char>& contents, tr_error** error = nullptr);
bool tr_saveFile(std::string const& filename, std::string_view contents, tr_error** error = nullptr);
bool tr_saveFile(std::string_view filename, std::string_view contents, tr_error** error = nullptr);
template<typename ContiguousRange>
constexpr auto tr_saveFile(std::string_view filename, ContiguousRange const& x, tr_error** error = nullptr)
{
return tr_saveFile(filename, std::string_view{ std::data(x), std::size(x) }, error);
}
template<typename... T, typename std::enable_if_t<(std::is_convertible_v<T, std::string_view> && ...), bool> = true>
std::string& tr_buildBuf(std::string& setme, T... args)

View File

@ -1212,7 +1212,7 @@ int tr_variantToFile(tr_variant const* v, tr_variant_fmt fmt, std::string const&
auto const contents = tr_variantToStr(v, fmt);
tr_error* error = nullptr;
tr_saveFile(filename, { std::data(contents), std::size(contents) }, &error);
tr_saveFile(filename, contents, &error);
if (error != nullptr)
{
tr_logAddError(fmt::format(
@ -1268,7 +1268,7 @@ bool tr_variantFromFile(tr_variant* setme, tr_variant_parse_opts opts, std::stri
TR_ASSERT((opts & TR_VARIANT_PARSE_INPLACE) == 0);
auto buf = std::vector<char>{};
if (!tr_loadFile(buf, filename, error))
if (!tr_loadFile(filename, buf, error))
{
return false;
}

View File

@ -14,6 +14,7 @@
#include "announce-list.h"
#include "error.h"
#include "torrent-metainfo.h"
#include "tr-strbuf.h"
#include "utils.h"
#include "variant.h"
@ -343,11 +344,11 @@ TEST_F(AnnounceListTest, save)
// first, set up a scratch torrent
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_strvJoin(::testing::TempDir(), "transmission-announce-list-test.torrent"sv);
auto const test_file = tr_pathbuf{ ::testing::TempDir(), "transmission-announce-list-test.torrent"sv };
tr_error* error = nullptr;
EXPECT_TRUE(tr_loadFile(original_content, OriginalFile, &error));
EXPECT_TRUE(tr_loadFile(OriginalFile, original_content, &error));
EXPECT_EQ(nullptr, error) << *error;
EXPECT_TRUE(tr_saveFile(test_file, { std::data(original_content), std::size(original_content) }, &error));
EXPECT_TRUE(tr_saveFile(test_file.sv(), original_content, &error));
EXPECT_EQ(nullptr, error) << *error;
// make an announce_list for it
@ -363,7 +364,7 @@ TEST_F(AnnounceListTest, save)
tr_error_clear(&error);
// now save to a real torrent file
EXPECT_TRUE(announce_list.save(test_file, &error));
EXPECT_TRUE(announce_list.save(std::string{ test_file.sv() }, &error));
EXPECT_EQ(nullptr, error) << *error;
// load the original
@ -372,7 +373,7 @@ TEST_F(AnnounceListTest, save)
// load the scratch that we saved to
auto modified_tm = tr_torrent_metainfo{};
EXPECT_TRUE(modified_tm.parseTorrentFile(test_file));
EXPECT_TRUE(modified_tm.parseTorrentFile(test_file.sv()));
// test that non-announce parts of the metainfo are the same
EXPECT_EQ(original_tm.name(), modified_tm.name());

View File

@ -13,6 +13,7 @@
#include "error.h"
#include "torrent-metainfo.h"
#include "torrent.h"
#include "tr-strbuf.h"
#include "utils.h"
#include "test-fixtures.h"
@ -159,13 +160,13 @@ TEST_F(TorrentMetainfoTest, AndroidTorrent)
TEST_F(TorrentMetainfoTest, ctorSaveContents)
{
auto const src_filename = tr_strvJoin(LIBTRANSMISSION_TEST_ASSETS_DIR, "/Android-x86 8.1 r6 iso.torrent"sv);
auto const tgt_filename = tr_strvJoin(::testing::TempDir(), "save-contents-test.torrent");
auto const src_filename = tr_pathbuf{ LIBTRANSMISSION_TEST_ASSETS_DIR, "/Android-x86 8.1 r6 iso.torrent"sv };
auto const tgt_filename = tr_pathbuf{ ::testing::TempDir(), "save-contents-test.torrent" };
// try saving without passing any metainfo.
auto* ctor = tr_ctorNew(session_);
tr_error* error = nullptr;
EXPECT_FALSE(tr_ctorSaveContents(ctor, tgt_filename, &error));
EXPECT_FALSE(tr_ctorSaveContents(ctor, tgt_filename.c_str(), &error));
EXPECT_NE(nullptr, error);
if (error != nullptr)
{
@ -176,14 +177,14 @@ TEST_F(TorrentMetainfoTest, ctorSaveContents)
// now try saving _with_ metainfo
EXPECT_TRUE(tr_ctorSetMetainfoFromFile(ctor, src_filename.c_str(), &error));
EXPECT_EQ(nullptr, error) << *error;
EXPECT_TRUE(tr_ctorSaveContents(ctor, tgt_filename, &error));
EXPECT_TRUE(tr_ctorSaveContents(ctor, tgt_filename.c_str(), &error));
EXPECT_EQ(nullptr, error) << *error;
// the saved contents should match the source file's contents
auto src_contents = std::vector<char>{};
EXPECT_TRUE(tr_loadFile(src_contents, src_filename, &error));
EXPECT_TRUE(tr_loadFile(src_filename.sv(), src_contents, &error));
auto tgt_contents = std::vector<char>{};
EXPECT_TRUE(tr_loadFile(tgt_contents, tgt_filename, &error));
EXPECT_TRUE(tr_loadFile(tgt_filename.sv(), tgt_contents, &error));
EXPECT_EQ(src_contents, tgt_contents);
// cleanup

View File

@ -16,6 +16,7 @@
#include "crypto-utils.h" // tr_rand_int_weak()
#include "platform.h"
#include "ptrarray.h"
#include "tr-strbuf.h"
#include "utils.h"
#include "test-fixtures.h"
@ -461,16 +462,18 @@ TEST_F(UtilsTest, mimeTypes)
TEST_F(UtilsTest, saveFile)
{
auto filename = tr_pathbuf{};
// save a file to GoogleTest's temp dir
auto filename = tr_strvJoin(::testing::TempDir(), "filename.txt");
filename.assign(::testing::TempDir(), "filename.txt"sv);
auto contents = "these are the contents"sv;
tr_error* error = nullptr;
EXPECT_TRUE(tr_saveFile(filename, contents, &error));
EXPECT_TRUE(tr_saveFile(filename.sv(), contents, &error));
EXPECT_EQ(nullptr, error) << *error;
// now read the file back in and confirm the contents are the same
auto buf = std::vector<char>{};
EXPECT_TRUE(tr_loadFile(buf, filename, &error));
EXPECT_TRUE(tr_loadFile(filename.sv(), buf, &error));
EXPECT_EQ(nullptr, error) << *error;
auto sv = std::string_view{ std::data(buf), std::size(buf) };
EXPECT_EQ(contents, sv);
@ -481,7 +484,7 @@ TEST_F(UtilsTest, saveFile)
// try saving a file to a path that doesn't exist
filename = "/this/path/does/not/exist/foo.txt";
EXPECT_FALSE(tr_saveFile(filename, contents, &error));
EXPECT_FALSE(tr_saveFile(filename.sv(), contents, &error));
ASSERT_NE(nullptr, error);
EXPECT_NE(0, error->code);
tr_error_clear(&error);

View File

@ -552,10 +552,10 @@ static char* netrc = nullptr;
static char* session_id = nullptr;
static bool UseSSL = false;
static std::string getEncodedMetainfo(char const* filename)
static std::string getEncodedMetainfo(std::string_view filename)
{
auto contents = std::vector<char>{};
if (tr_loadFile(contents, filename))
if (tr_loadFile(filename, contents))
{
return tr_base64_encode({ std::data(contents), std::size(contents) });
}
@ -2386,7 +2386,7 @@ static int processArgs(char const* rpcurl, int argc, char const* const* argv)
if (tadd != nullptr)
{
tr_variant* args = tr_variantDictFind(tadd, Arguments);
std::string const tmp = getEncodedMetainfo(optarg);
auto const tmp = getEncodedMetainfo(optarg);
if (!std::empty(tmp))
{