feat: add tr_strvPath() (#2134)

* feat: add tr_strvJoin

* feat: add tr_strvPath
This commit is contained in:
Charles Kerr
2021-11-12 18:10:04 -06:00
committed by GitHub
parent 4091f273fa
commit 6571be2b95
25 changed files with 527 additions and 577 deletions

View File

@@ -231,9 +231,9 @@ static tr_watchdir_status onFileAdded(tr_watchdir_t dir, char const* name, void*
return TR_WATCHDIR_IGNORE;
}
char* filename = tr_buildPath(tr_watchdir_get_path(dir), name, nullptr);
auto filename = tr_strvPath(tr_watchdir_get_path(dir), name);
tr_ctor* ctor = tr_ctorNew(session);
int err = tr_ctorSetMetainfoFromFile(ctor, filename);
int err = tr_ctorSetMetainfoFromFile(ctor, filename.c_str());
if (err == 0)
{
@@ -256,7 +256,7 @@ static tr_watchdir_status onFileAdded(tr_watchdir_t dir, char const* name, void*
tr_logAddInfo("Deleting input .torrent file \"%s\"", name);
if (!tr_sys_path_remove(filename, &error))
if (!tr_sys_path_remove(filename.c_str(), &error))
{
tr_logAddError("Error deleting .torrent file: %s", error->message);
tr_error_free(error);
@@ -264,9 +264,8 @@ static tr_watchdir_status onFileAdded(tr_watchdir_t dir, char const* name, void*
}
else
{
char* new_filename = tr_strdup_printf("%s.added", filename);
tr_sys_path_rename(filename, new_filename, nullptr);
tr_free(new_filename);
auto const new_filename = filename + ".added";
tr_sys_path_rename(filename.c_str(), new_filename.c_str(), nullptr);
}
}
}
@@ -276,7 +275,6 @@ static tr_watchdir_status onFileAdded(tr_watchdir_t dir, char const* name, void*
}
tr_ctorFree(ctor);
tr_free(filename);
return err == TR_PARSE_ERR ? TR_WATCHDIR_RETRY : TR_WATCHDIR_ACCEPT;
}

View File

@@ -91,23 +91,21 @@ static int readOrWriteBytes(
if (err == 0)
{
/* open (and maybe create) the file */
char* filename = tr_buildPath(base, subpath, nullptr);
auto const filename = tr_strvPath(base, subpath);
tr_preallocation_mode const prealloc = (file->dnd || !doWrite) ? TR_PREALLOCATE_NONE :
tor->session->preallocationMode;
fd = tr_fdFileCheckout(session, tor->uniqueId, fileIndex, filename, doWrite, prealloc, file->length);
fd = tr_fdFileCheckout(session, tor->uniqueId, fileIndex, filename.c_str(), doWrite, prealloc, file->length);
if (fd == TR_BAD_SYS_FILE)
{
err = errno;
tr_logAddTorErr(tor, "tr_fdFileCheckout failed for \"%s\": %s", filename, tr_strerror(err));
tr_logAddTorErr(tor, "tr_fdFileCheckout failed for \"%s\": %s", filename.c_str(), tr_strerror(err));
}
else if (doWrite)
{
/* make a note that we just created a file */
tr_statsFileCreated(tor->session);
}
tr_free(filename);
}
tr_free(subpath);
@@ -230,9 +228,8 @@ static int readOrWritePiece(
if (err != 0 && ioMode == TR_IO_WRITE && tor->error != TR_STAT_LOCAL_ERROR)
{
char* path = tr_buildPath(tor->downloadDir, file->name, nullptr);
tr_torrentSetLocalError(tor, "%s (%s)", tr_strerror(err), path);
tr_free(path);
auto const path = tr_strvPath(tor->downloadDir, file->name);
tr_torrentSetLocalError(tor, "%s (%s)", tr_strerror(err), path.c_str());
}
}

View File

@@ -46,20 +46,19 @@ static struct FileList* getFiles(char const* dir, char const* base, struct FileL
return nullptr;
}
char* buf = tr_buildPath(dir, base, nullptr);
(void)tr_sys_path_native_separators(buf);
auto buf = tr_strvPath(dir, base);
tr_sys_path_native_separators(std::data(buf));
tr_sys_path_info info;
tr_error* error = nullptr;
if (!tr_sys_path_get_info(buf, 0, &info, &error))
if (!tr_sys_path_get_info(buf.c_str(), 0, &info, &error))
{
tr_logAddError(_("Torrent Creator is skipping file \"%s\": %s"), buf, error->message);
tr_free(buf);
tr_logAddError(_("Torrent Creator is skipping file \"%s\": %s"), buf.c_str(), error->message);
tr_error_free(error);
return list;
}
tr_sys_dir_t odir = info.type == TR_SYS_PATH_IS_DIRECTORY ? tr_sys_dir_open(buf, nullptr) : TR_BAD_SYS_DIR;
tr_sys_dir_t odir = info.type == TR_SYS_PATH_IS_DIRECTORY ? tr_sys_dir_open(buf.c_str(), nullptr) : TR_BAD_SYS_DIR;
if (odir != TR_BAD_SYS_DIR)
{
@@ -68,7 +67,7 @@ static struct FileList* getFiles(char const* dir, char const* base, struct FileL
{
if (name[0] != '.') /* skip dotfiles */
{
list = getFiles(buf, name, list);
list = getFiles(buf.c_str(), name, list);
}
}
@@ -78,12 +77,11 @@ static struct FileList* getFiles(char const* dir, char const* base, struct FileL
{
struct FileList* node = tr_new(struct FileList, 1);
node->size = info.size;
node->filename = tr_strdup(buf);
node->filename = tr_strvDup(buf);
node->next = list;
list = node;
}
tr_free(buf);
return list;
}

View File

@@ -45,6 +45,8 @@
#include "tr-assert.h"
#include "utils.h"
using namespace std::literals;
/***
**** THREADS
***/
@@ -388,15 +390,14 @@ char const* tr_getDefaultDownloadDir(void)
/* figure out where to look for user-dirs.dirs */
char* const config_home = tr_env_get_string("XDG_CONFIG_HOME", nullptr);
char* const config_file = !tr_str_is_empty(config_home) ?
tr_buildPath(config_home, "user-dirs.dirs", nullptr) :
tr_buildPath(getHomeDir(), ".config", "user-dirs.dirs", nullptr);
auto const config_file = !tr_str_is_empty(config_home) ? tr_strvPath(config_home, "user-dirs.dirs") :
tr_strvPath(getHomeDir(), ".config", "user-dirs.dirs");
tr_free(config_home);
/* read in user-dirs.dirs and look for the download dir entry */
size_t content_len = 0;
char* const content = (char*)tr_loadFile(config_file, &content_len, nullptr);
char* const content = (char*)tr_loadFile(config_file.c_str(), &content_len, nullptr);
if (content != nullptr && content_len > 0)
{
@@ -447,7 +448,6 @@ char const* tr_getDefaultDownloadDir(void)
}
tr_free(content);
tr_free(config_file);
}
return user_dir;
@@ -459,10 +459,9 @@ char const* tr_getDefaultDownloadDir(void)
static bool isWebClientDir(char const* path)
{
char* tmp = tr_buildPath(path, "index.html", nullptr);
bool const ret = tr_sys_path_exists(tmp, nullptr);
tr_logAddInfo(_("Searching for web interface file \"%s\""), tmp);
tr_free(tmp);
auto tmp = tr_strvPath(path, "index.html");
bool const ret = tr_sys_path_exists(tmp.c_str(), nullptr);
tr_logAddInfo(_("Searching for web interface file \"%s\""), tmp.c_str());
return ret;
}
@@ -579,9 +578,7 @@ char const* tr_getWebClientDir([[maybe_unused]] tr_session const* session)
}
else
{
char* dhome = tr_buildPath(getHomeDir(), ".local", "share", nullptr);
candidates.emplace_back(dhome);
tr_free(dhome);
candidates.emplace_back(tr_strvPath(getHomeDir(), ".local"sv, "share"sv));
}
tr_free(tmp);
@@ -639,18 +636,18 @@ char const* tr_getWebClientDir([[maybe_unused]] tr_session const* session)
return s;
}
char* tr_getSessionIdDir(void)
std::string tr_getSessionIdDir()
{
#ifndef _WIN32
return tr_strdup("/tmp");
return std::string{ "/tmp"sv };
#else
char* program_data_dir = win32_get_known_folder_ex(FOLDERID_ProgramData, KF_FLAG_CREATE);
char* result = tr_buildPath(program_data_dir, "Transmission", nullptr);
auto const result = tr_strvPath(program_data_dir, "Transmission");
tr_free(program_data_dir);
tr_sys_dir_create(result, 0, 0, nullptr);
tr_sys_dir_create(result.c_str(), 0, 0, nullptr);
return result;
#endif

View File

@@ -12,8 +12,7 @@
#error only libtransmission should #include this header.
#endif
#define TR_PATH_DELIMITER '/'
#define TR_PATH_DELIMITER_STR "/"
#include <string>
/**
* @addtogroup tr_session Session
@@ -38,7 +37,7 @@ char const* tr_getTorrentDir(tr_session const*);
char const* tr_getWebClientDir(tr_session const*);
/** @brief return the directory where session id lock files are stored */
char* tr_getSessionIdDir(void);
std::string tr_getSessionIdDir();
/** @} */

View File

@@ -23,7 +23,7 @@
#include "session.h"
#include "torrent.h"
#include "tr-assert.h"
#include "utils.h" /* tr_buildPath */
#include "utils.h"
#include "variant.h"
using namespace std::literals;

View File

@@ -1534,12 +1534,12 @@ static void gotNewBlocklist(
stream.avail_in = response_byte_count;
inflateInit2(&stream, windowBits);
char* const filename = tr_buildPath(configDir, "blocklist.tmp.XXXXXX", nullptr);
tr_sys_file_t const fd = tr_sys_file_open_temp(filename, &error);
auto filename = tr_strvPath(configDir, "blocklist.tmp.XXXXXX");
tr_sys_file_t const fd = tr_sys_file_open_temp(std::data(filename), &error);
if (fd == TR_BAD_SYS_FILE)
{
tr_snprintf(result, sizeof(result), _("Couldn't save file \"%1$s\": %2$s"), filename, error->message);
tr_snprintf(result, sizeof(result), _("Couldn't save file \"%1$s\": %2$s"), filename.c_str(), error->message);
tr_error_clear(&error);
}
@@ -1552,7 +1552,7 @@ static void gotNewBlocklist(
if ((stream.avail_out < buflen) && (!tr_sys_file_write(fd, buf, buflen - stream.avail_out, nullptr, &error)))
{
tr_snprintf(result, sizeof(result), _("Couldn't save file \"%1$s\": %2$s"), filename, error->message);
tr_snprintf(result, sizeof(result), _("Couldn't save file \"%1$s\": %2$s"), filename.c_str(), error->message);
tr_error_clear(&error);
break;
}
@@ -1573,7 +1573,7 @@ static void gotNewBlocklist(
if ((err == Z_DATA_ERROR) && // couldn't inflate it... it's probably already uncompressed
!tr_sys_file_write(fd, response, response_byte_count, nullptr, &error))
{
tr_snprintf(result, sizeof(result), _("Couldn't save file \"%1$s\": %2$s"), filename, error->message);
tr_snprintf(result, sizeof(result), _("Couldn't save file \"%1$s\": %2$s"), filename.c_str(), error->message);
tr_error_clear(&error);
}
@@ -1586,13 +1586,12 @@ static void gotNewBlocklist(
else
{
/* feed it to the session and give the client a response */
int const rule_count = tr_blocklistSetContent(session, filename);
int const rule_count = tr_blocklistSetContent(session, filename.c_str());
tr_variantDictAddInt(data->args_out, TR_KEY_blocklist_size, rule_count);
tr_snprintf(result, sizeof(result), "success");
}
tr_sys_path_remove(filename, nullptr);
tr_free(filename);
tr_sys_path_remove(filename.c_str(), nullptr);
tr_free(buf);
}

View File

@@ -23,6 +23,8 @@
#include "session-id.h"
#include "utils.h"
using namespace std::literals;
#define SESSION_ID_SIZE 48
#define SESSION_ID_DURATION_SEC (60 * 60) /* expire in an hour */
@@ -54,12 +56,9 @@ static char* generate_new_session_id_value(void)
return buf;
}
static char* get_session_id_lock_file_path(char const* session_id)
static std::string get_session_id_lock_file_path(std::string_view session_id)
{
char* lock_file_dir = tr_getSessionIdDir();
char* lock_file_path = tr_strdup_printf("%s/tr_session_id_%s", lock_file_dir, session_id);
tr_free(lock_file_dir);
return lock_file_path;
return tr_strvJoin(tr_getSessionIdDir(), TR_PATH_DELIMITER_STR, "tr_session_id_"sv, session_id);
}
static tr_sys_file_t create_session_id_lock_file(char const* session_id)
@@ -69,9 +68,13 @@ static tr_sys_file_t create_session_id_lock_file(char const* session_id)
return TR_BAD_SYS_FILE;
}
char* lock_file_path = get_session_id_lock_file_path(session_id);
auto const lock_file_path = get_session_id_lock_file_path(session_id);
tr_error* error = nullptr;
auto lock_file = tr_sys_file_open(lock_file_path, TR_SYS_FILE_READ | TR_SYS_FILE_WRITE | TR_SYS_FILE_CREATE, 0600, &error);
auto lock_file = tr_sys_file_open(
lock_file_path.c_str(),
TR_SYS_FILE_READ | TR_SYS_FILE_WRITE | TR_SYS_FILE_CREATE,
0600,
&error);
if (lock_file != TR_BAD_SYS_FILE)
{
@@ -95,7 +98,6 @@ static tr_sys_file_t create_session_id_lock_file(char const* session_id)
tr_error_free(error);
}
tr_free(lock_file_path);
return lock_file;
}
@@ -108,9 +110,8 @@ static void destroy_session_id_lock_file(tr_sys_file_t lock_file, char const* se
if (session_id != nullptr)
{
char* lock_file_path = get_session_id_lock_file_path(session_id);
tr_sys_path_remove(lock_file_path, nullptr);
tr_free(lock_file_path);
auto const lock_file_path = get_session_id_lock_file_path(session_id);
tr_sys_path_remove(lock_file_path.c_str(), nullptr);
}
}
@@ -167,9 +168,9 @@ bool tr_session_id_is_local(char const* session_id)
if (session_id != nullptr)
{
char* lock_file_path = get_session_id_lock_file_path(session_id);
auto const lock_file_path = get_session_id_lock_file_path(session_id);
tr_error* error = nullptr;
auto lock_file = tr_sys_file_open(lock_file_path, TR_SYS_FILE_READ, 0, &error);
auto lock_file = tr_sys_file_open(lock_file_path.c_str(), TR_SYS_FILE_READ, 0, &error);
if (lock_file == TR_BAD_SYS_FILE)
{
@@ -199,8 +200,6 @@ bool tr_session_id_is_local(char const* session_id)
tr_logAddError("Unable to open session lock file (%d): %s", error->code, error->message);
tr_error_free(error);
}
tr_free(lock_file_path);
}
return ret;

View File

@@ -65,6 +65,8 @@
#include "version.h"
#include "web.h"
using namespace std::literals;
#ifdef TR_LIGHTWEIGHT
static auto constexpr DefaultCacheSizeMB = int{ 2 };
static auto constexpr DefaultPrefetchEnabled = bool{ false };
@@ -500,10 +502,10 @@ bool tr_sessionLoadSettings(tr_variant* dict, char const* configDir, char const*
/* file settings override the defaults */
auto fileSettings = tr_variant{};
char* const filename = tr_buildPath(configDir, "settings.json", nullptr);
auto const filename = tr_strvPath(configDir, "settings.json"sv);
auto success = bool{};
tr_error* error = nullptr;
if (tr_variantFromFile(&fileSettings, TR_VARIANT_FMT_JSON, filename, &error))
if (tr_variantFromFile(&fileSettings, TR_VARIANT_FMT_JSON, filename.c_str(), &error))
{
tr_variantMergeDicts(dict, &fileSettings);
tr_variantFree(&fileSettings);
@@ -516,7 +518,6 @@ bool tr_sessionLoadSettings(tr_variant* dict, char const* configDir, char const*
}
/* cleanup */
tr_free(filename);
return success;
}
@@ -525,7 +526,7 @@ void tr_sessionSaveSettings(tr_session* session, char const* configDir, tr_varia
TR_ASSERT(tr_variantIsDict(clientSettings));
tr_variant settings;
char* filename = tr_buildPath(configDir, "settings.json", nullptr);
auto const filename = tr_strvPath(configDir, "settings.json"sv);
tr_variantInitDict(&settings, 0);
@@ -533,7 +534,7 @@ void tr_sessionSaveSettings(tr_session* session, char const* configDir, tr_varia
{
tr_variant fileSettings;
if (tr_variantFromFile(&fileSettings, TR_VARIANT_FMT_JSON, filename, nullptr))
if (tr_variantFromFile(&fileSettings, TR_VARIANT_FMT_JSON, filename.c_str(), nullptr))
{
tr_variantMergeDicts(&settings, &fileSettings);
tr_variantFree(&fileSettings);
@@ -553,10 +554,9 @@ void tr_sessionSaveSettings(tr_session* session, char const* configDir, tr_varia
}
/* save the result */
tr_variantToFile(&settings, TR_VARIANT_FMT_JSON, filename);
tr_variantToFile(&settings, TR_VARIANT_FMT_JSON, filename.c_str());
/* cleanup */
tr_free(filename);
tr_variantFree(&settings);
}
@@ -747,9 +747,8 @@ static void tr_sessionInitImpl(void* vdata)
**/
{
char* filename = tr_buildPath(session->configDir, "blocklists", nullptr);
tr_sys_dir_create(filename, TR_SYS_DIR_CREATE_PARENTS, 0777, nullptr);
tr_free(filename);
auto const filename = tr_strvPath(session->configDir, "blocklists"sv);
tr_sys_dir_create(filename.c_str(), TR_SYS_DIR_CREATE_PARENTS, 0777, nullptr);
loadBlocklists(session);
}
@@ -2374,83 +2373,76 @@ static void loadBlocklists(tr_session* session)
auto const isEnabled = session->isBlocklistEnabled;
/* walk the blocklist directory... */
char* const dirname = tr_buildPath(session->configDir, "blocklists", nullptr);
auto const odir = tr_sys_dir_open(dirname, nullptr);
auto const dirname = tr_strvPath(session->configDir, "blocklists"sv);
auto const odir = tr_sys_dir_open(dirname.c_str(), nullptr);
if (odir == TR_BAD_SYS_DIR)
{
tr_free(dirname);
return;
}
char const* name = nullptr;
while ((name = tr_sys_dir_read_name(odir, nullptr)) != nullptr)
{
char* load = nullptr;
auto load = std::string{};
if (name[0] == '.') /* ignore dotfiles */
{
continue;
}
char* const path = tr_buildPath(dirname, name, nullptr);
auto const path = tr_strvPath(dirname, name);
if (tr_stringEndsWith(path, ".bin"))
if (tr_strvEndsWith(path, ".bin"sv))
{
load = tr_strdup(path);
load = path;
}
else
{
tr_sys_path_info path_info;
tr_sys_path_info binname_info;
char* const binname = tr_strdup_printf("%s" TR_PATH_DELIMITER_STR "%s.bin", dirname, name);
auto const binname = tr_strvJoin(dirname, TR_PATH_DELIMITER_STR, name, ".bin"sv);
if (!tr_sys_path_get_info(binname, 0, &binname_info, nullptr)) /* create it */
if (!tr_sys_path_get_info(binname.c_str(), 0, &binname_info, nullptr)) /* create it */
{
tr_blocklistFile* b = tr_blocklistFileNew(binname, isEnabled);
int const n = tr_blocklistFileSetContent(b, path);
tr_blocklistFile* b = tr_blocklistFileNew(binname.c_str(), isEnabled);
int const n = tr_blocklistFileSetContent(b, path.c_str());
if (n > 0)
{
load = tr_strdup(binname);
load = binname;
}
tr_blocklistFileFree(b);
}
else if (
tr_sys_path_get_info(path, 0, &path_info, nullptr) &&
tr_sys_path_get_info(path.c_str(), 0, &path_info, nullptr) &&
path_info.last_modified_at >= binname_info.last_modified_at) /* update it */
{
char* const old = tr_strdup_printf("%s.old", binname);
tr_sys_path_remove(old, nullptr);
tr_sys_path_rename(binname, old, nullptr);
auto* const b = tr_blocklistFileNew(binname, isEnabled);
auto const old = binname + ".old";
tr_sys_path_remove(old.c_str(), nullptr);
tr_sys_path_rename(binname.c_str(), old.c_str(), nullptr);
auto* const b = tr_blocklistFileNew(binname.c_str(), isEnabled);
if (tr_blocklistFileSetContent(b, path) > 0)
if (tr_blocklistFileSetContent(b, path.c_str()) > 0)
{
tr_sys_path_remove(old, nullptr);
tr_sys_path_remove(old.c_str(), nullptr);
}
else
{
tr_sys_path_remove(binname, nullptr);
tr_sys_path_rename(old, binname, nullptr);
tr_sys_path_remove(binname.c_str(), nullptr);
tr_sys_path_rename(old.c_str(), binname.c_str(), nullptr);
}
tr_blocklistFileFree(b);
tr_free(old);
}
}
tr_free(binname);
}
if (load != nullptr)
if (!std::empty(load))
{
loadme.emplace(load);
tr_free(load);
}
tr_free(path);
}
session->blocklists.clear();
@@ -2462,7 +2454,6 @@ static void loadBlocklists(tr_session* session)
/* cleanup */
tr_sys_dir_close(odir, nullptr);
tr_free(dirname);
}
static void closeBlocklists(tr_session* session)
@@ -2533,10 +2524,9 @@ int tr_blocklistSetContent(tr_session* session, char const* contentFilename)
[&name](auto const* blocklist) { return tr_stringEndsWith(tr_blocklistFileGetFilename(blocklist), name); });
if (it == std::end(src))
{
char* path = tr_buildPath(session->configDir, "blocklists", name, nullptr);
b = tr_blocklistFileNew(path, session->isBlocklistEnabled);
auto path = tr_strvJoin(session->configDir, "blocklists"sv, name);
b = tr_blocklistFileNew(path.c_str(), session->isBlocklistEnabled);
src.push_back(b);
tr_free(path);
}
else
{

View File

@@ -11,7 +11,7 @@
#include "log.h"
#include "platform.h" /* tr_sessionGetConfigDir() */
#include "stats.h"
#include "utils.h" /* tr_buildPath */
#include "utils.h"
#include "variant.h"
/***
@@ -27,29 +27,27 @@ struct tr_stats_handle
bool isDirty;
};
static char* getOldFilename(tr_session const* session)
static std::string getOldFilename(tr_session const* session)
{
return tr_buildPath(tr_sessionGetConfigDir(session), "stats.benc", nullptr);
return tr_strvPath(tr_sessionGetConfigDir(session), "stats.benc");
}
static char* getFilename(tr_session const* session)
static std::string getFilename(tr_session const* session)
{
return tr_buildPath(tr_sessionGetConfigDir(session), "stats.json", nullptr);
return tr_strvPath(tr_sessionGetConfigDir(session), "stats.json");
}
static void loadCumulativeStats(tr_session const* session, tr_session_stats* setme)
{
auto top = tr_variant{};
char* filename = getFilename(session);
bool loaded = tr_variantFromFile(&top, TR_VARIANT_FMT_JSON, filename, nullptr);
tr_free(filename);
auto filename = getFilename(session);
bool loaded = tr_variantFromFile(&top, TR_VARIANT_FMT_JSON, filename.c_str(), nullptr);
if (!loaded)
{
filename = getOldFilename(session);
loaded = tr_variantFromFile(&top, TR_VARIANT_FMT_BENC, filename, nullptr);
tr_free(filename);
loaded = tr_variantFromFile(&top, TR_VARIANT_FMT_BENC, filename.c_str(), nullptr);
}
if (loaded)
@@ -95,15 +93,14 @@ static void saveCumulativeStats(tr_session const* session, tr_session_stats cons
tr_variantDictAddInt(&top, TR_KEY_session_count, s->sessionCount);
tr_variantDictAddInt(&top, TR_KEY_uploaded_bytes, s->uploadedBytes);
char* const filename = getFilename(session);
auto const filename = getFilename(session);
if (tr_logGetDeepEnabled())
{
tr_logAddDeep(__FILE__, __LINE__, nullptr, "Saving stats to \"%s\"", filename);
tr_logAddDeep(__FILE__, __LINE__, nullptr, "Saving stats to \"%s\"", filename.c_str());
}
tr_variantToFile(&top, TR_VARIANT_FMT_JSON, filename);
tr_variantToFile(&top, TR_VARIANT_FMT_JSON, filename.c_str());
tr_free(filename);
tr_variantFree(&top);
}

View File

@@ -2756,19 +2756,17 @@ static void removeEmptyFoldersAndJunkFiles(char const* folder)
{
if (strcmp(name, ".") != 0 && strcmp(name, "..") != 0)
{
char* const filename = tr_buildPath(folder, name, nullptr);
auto const filename = tr_strvPath(folder, name);
auto info = tr_sys_path_info{};
if (tr_sys_path_get_info(filename, 0, &info, nullptr) && info.type == TR_SYS_PATH_IS_DIRECTORY)
if (tr_sys_path_get_info(filename.c_str(), 0, &info, nullptr) && info.type == TR_SYS_PATH_IS_DIRECTORY)
{
removeEmptyFoldersAndJunkFiles(filename);
removeEmptyFoldersAndJunkFiles(filename.c_str());
}
else if (isJunkFile(name))
{
tr_sys_path_remove(filename, nullptr);
tr_sys_path_remove(filename.c_str(), nullptr);
}
tr_free(filename);
}
}
@@ -2807,38 +2805,30 @@ static void deleteLocalData(tr_torrent* tor, tr_fileFunc func)
**** Move the local data to a new tmpdir
***/
char* base = tr_strdup_printf("%s__XXXXXX", tr_torrentName(tor));
char* tmpdir = tr_buildPath(top, base, nullptr);
tr_sys_dir_create_temp(tmpdir, nullptr);
tr_free(base);
auto tmpdir = tr_strvPath(top, TR_PATH_DELIMITER_STR, tr_torrentName(tor), "__XXXXXX");
tr_sys_dir_create_temp(std::data(tmpdir), nullptr);
for (tr_file_index_t f = 0; f < tor->info.fileCount; ++f)
{
/* try to find the file, looking in the partial and download dirs */
char* filename = tr_buildPath(top, tor->info.files[f].name, nullptr);
auto filename = tr_strvPath(top, tor->info.files[f].name);
if (!tr_sys_path_exists(filename, nullptr))
if (!tr_sys_path_exists(filename.c_str(), nullptr))
{
char* partial = tr_torrentBuildPartial(tor, f);
tr_free(filename);
filename = tr_buildPath(top, partial, nullptr);
tr_free(partial);
filename += ".part"sv;
if (!tr_sys_path_exists(filename, nullptr))
if (!tr_sys_path_exists(filename.c_str(), nullptr))
{
tr_free(filename);
filename = nullptr;
filename.clear();
}
}
/* if we found the file, move it */
if (filename != nullptr)
if (!std::empty(filename))
{
char* target = tr_buildPath(tmpdir, tor->info.files[f].name, nullptr);
tr_moveFile(filename, target, nullptr);
auto target = tr_strvPath(tmpdir, tor->info.files[f].name);
tr_moveFile(filename.c_str(), target.c_str(), nullptr);
files.emplace_back(target);
tr_free(filename);
tr_free(target);
}
}
@@ -2852,7 +2842,7 @@ static void deleteLocalData(tr_torrent* tor, tr_fileFunc func)
***/
/* try deleting the local data's top-level files & folders */
tr_sys_dir_t const odir = tr_sys_dir_open(tmpdir, nullptr);
tr_sys_dir_t const odir = tr_sys_dir_open(tmpdir.c_str(), nullptr);
if (odir != TR_BAD_SYS_DIR)
{
char const* name = nullptr;
@@ -2860,9 +2850,8 @@ static void deleteLocalData(tr_torrent* tor, tr_fileFunc func)
{
if (strcmp(name, ".") != 0 && strcmp(name, "..") != 0)
{
char* file = tr_buildPath(tmpdir, name, nullptr);
(*func)(file, nullptr);
tr_free(file);
auto const file = tr_strvPath(tmpdir, name);
(*func)(file.c_str(), nullptr);
}
}
@@ -2874,7 +2863,7 @@ static void deleteLocalData(tr_torrent* tor, tr_fileFunc func)
{
char* walk = tr_strvDup(file);
while (tr_sys_path_exists(walk, nullptr) && !tr_sys_path_is_same(tmpdir, walk, nullptr))
while (tr_sys_path_exists(walk, nullptr) && !tr_sys_path_is_same(tmpdir.c_str(), walk, nullptr))
{
char* tmp = tr_sys_path_dirname(walk, nullptr);
(*func)(walk, nullptr);
@@ -2895,10 +2884,8 @@ static void deleteLocalData(tr_torrent* tor, tr_fileFunc func)
for (tr_file_index_t f = 0; f < tor->info.fileCount; ++f)
{
/* get the directory that this file goes in... */
char* const filename = tr_buildPath(top, tor->info.files[f].name, nullptr);
char* dir = tr_sys_path_dirname(filename, nullptr);
tr_free(filename);
auto const filename = tr_strvPath(top, tor->info.files[f].name);
char* dir = tr_sys_path_dirname(filename.c_str(), nullptr);
if (dir == nullptr)
{
continue;
@@ -2933,8 +2920,7 @@ static void deleteLocalData(tr_torrent* tor, tr_fileFunc func)
}
/* cleanup */
tr_sys_path_remove(tmpdir, nullptr);
tr_free(tmpdir);
tr_sys_path_remove(tmpdir.c_str(), nullptr);
}
static void tr_torrentDeleteLocalData(tr_torrent* tor, tr_fileFunc func)
@@ -3000,27 +2986,30 @@ static void setLocation(void* vdata)
char* sub = nullptr;
if (tr_torrentFindFile2(tor, i, &oldbase, &sub, nullptr))
{
char* oldpath = tr_buildPath(oldbase, sub, nullptr);
char* newpath = tr_buildPath(location, sub, nullptr);
auto const oldpath = tr_strvPath(oldbase, sub);
auto const newpath = tr_strvPath(location, sub);
tr_logAddDebug("Found file #%d: %s", (int)i, oldpath);
tr_logAddDebug("Found file #%d: %s", (int)i, oldpath.c_str());
if (do_move && !tr_sys_path_is_same(oldpath, newpath, nullptr))
if (do_move && !tr_sys_path_is_same(oldpath.c_str(), newpath.c_str(), nullptr))
{
tr_error* error = nullptr;
tr_logAddTorInfo(tor, "moving \"%s\" to \"%s\"", oldpath, newpath);
tr_logAddTorInfo(tor, "moving \"%s\" to \"%s\"", oldpath.c_str(), newpath.c_str());
if (!tr_moveFile(oldpath, newpath, &error))
if (!tr_moveFile(oldpath.c_str(), newpath.c_str(), &error))
{
err = true;
tr_logAddTorErr(tor, "error moving \"%s\" to \"%s\": %s", oldpath, newpath, error->message);
tr_logAddTorErr(
tor,
"error moving \"%s\" to \"%s\": %s",
oldpath.c_str(),
newpath.c_str(),
error->message);
tr_error_free(error);
}
}
tr_free(newpath);
tr_free(oldpath);
tr_free(sub);
}
@@ -3148,18 +3137,15 @@ static void tr_torrentFileCompleted(tr_torrent* tor, tr_file_index_t fileIndex)
{
if (strcmp(sub, f->name) != 0)
{
char* oldpath = tr_buildPath(base, sub, nullptr);
char* newpath = tr_buildPath(base, f->name, nullptr);
auto const oldpath = tr_strvPath(base, sub);
auto const newpath = tr_strvPath(base, f->name);
tr_error* error = nullptr;
if (!tr_sys_path_rename(oldpath, newpath, &error))
if (!tr_sys_path_rename(oldpath.c_str(), newpath.c_str(), &error))
{
tr_logAddTorErr(tor, "Error moving \"%s\" to \"%s\": %s", oldpath, newpath, error->message);
tr_logAddTorErr(tor, "Error moving \"%s\" to \"%s\": %s", oldpath.c_str(), newpath.c_str(), error->message);
tr_error_free(error);
}
tr_free(newpath);
tr_free(oldpath);
}
tr_free(sub);
@@ -3523,24 +3509,21 @@ static int renamePath(tr_torrent* tor, char const* oldpath, char const* newname)
char const* const base = !tr_torrentIsSeed(tor) && tor->incompleteDir != nullptr ? tor->incompleteDir : tor->downloadDir;
char* src = tr_buildPath(base, oldpath, nullptr);
auto src = tr_strvPath(base, oldpath);
if (!tr_sys_path_exists(src, nullptr)) /* check for it as a partial */
if (!tr_sys_path_exists(src.c_str(), nullptr)) /* check for it as a partial */
{
char* tmp = tr_strdup_printf("%s.part", src);
tr_free(src);
src = tmp;
src += ".part"sv;
}
if (tr_sys_path_exists(src, nullptr))
if (tr_sys_path_exists(src.c_str(), nullptr))
{
char* parent = tr_sys_path_dirname(src, nullptr);
char* const tgt = tr_str_has_suffix(src, ".part") ?
tr_strdup_printf("%s" TR_PATH_DELIMITER_STR "%s.part", parent, newname) :
tr_buildPath(parent, newname, nullptr);
char* const parent = tr_sys_path_dirname(src.c_str(), nullptr);
auto const tgt = tr_strvEndsWith(src, ".part"sv) ? tr_strvJoin(parent, TR_PATH_DELIMITER_STR, newname, ".part"sv) :
tr_strvPath(parent, newname);
auto tmp = errno;
bool const tgt_exists = tr_sys_path_exists(tgt, nullptr);
bool const tgt_exists = tr_sys_path_exists(tgt.c_str(), nullptr);
errno = tmp;
if (!tgt_exists)
@@ -3549,7 +3532,7 @@ static int renamePath(tr_torrent* tor, char const* oldpath, char const* newname)
tmp = errno;
if (!tr_sys_path_rename(src, tgt, &error))
if (!tr_sys_path_rename(src.c_str(), tgt.c_str(), &error))
{
err = error->code;
tr_error_free(error);
@@ -3558,12 +3541,9 @@ static int renamePath(tr_torrent* tor, char const* oldpath, char const* newname)
errno = tmp;
}
tr_free(tgt);
tr_free(parent);
}
tr_free(src);
return err;
}

View File

@@ -62,6 +62,8 @@
#include "utils.h"
#include "variant.h"
using namespace std::literals;
static struct event* dht_timer = nullptr;
static unsigned char myid[20];
static tr_session* session_ = nullptr;
@@ -215,14 +217,9 @@ static void dht_bootstrap(void* closure)
if (!bootstrap_done(cl->session, 0))
{
tr_sys_file_t f = TR_BAD_SYS_FILE;
auto const bootstrap_file = tr_strvPath(cl->session->configDir, "dht.bootstrap");
char* const bootstrap_file = tr_buildPath(cl->session->configDir, "dht.bootstrap", nullptr);
if (bootstrap_file != nullptr)
{
f = tr_sys_file_open(bootstrap_file, TR_SYS_FILE_READ, 0, nullptr);
}
tr_sys_file_t const f = tr_sys_file_open(bootstrap_file.c_str(), TR_SYS_FILE_READ, 0, nullptr);
if (f != TR_BAD_SYS_FILE)
{
@@ -262,8 +259,6 @@ static void dht_bootstrap(void* closure)
tr_sys_file_close(f, nullptr);
}
tr_free(bootstrap_file);
}
if (!bootstrap_done(cl->session, 0))
@@ -318,10 +313,9 @@ int tr_dhtInit(tr_session* ss)
dht_debug = stderr;
}
char* const dat_file = tr_buildPath(ss->configDir, "dht.dat", nullptr);
auto const dat_file = tr_strvPath(ss->configDir, "dht.dat"sv);
auto benc = tr_variant{};
int rc = tr_variantFromFile(&benc, TR_VARIANT_FMT_BENC, dat_file, nullptr) ? 0 : -1;
tr_free(dat_file);
int rc = tr_variantFromFile(&benc, TR_VARIANT_FMT_BENC, dat_file.c_str(), nullptr) ? 0 : -1;
bool have_id = false;
uint8_t* nodes = nullptr;
@@ -472,10 +466,9 @@ void tr_dhtUninit(tr_session* ss)
tr_variantDictAddRaw(&benc, TR_KEY_nodes6, compact6, out6 - compact6);
}
char* const dat_file = tr_buildPath(ss->configDir, "dht.dat", nullptr);
tr_variantToFile(&benc, TR_VARIANT_FMT_BENC, dat_file);
auto const dat_file = tr_strvPath(ss->configDir, "dht.dat");
tr_variantToFile(&benc, TR_VARIANT_FMT_BENC, dat_file.c_str());
tr_variantFree(&benc);
tr_free(dat_file);
}
dht_uninit();

View File

@@ -110,6 +110,9 @@
****
***/
#define TR_PATH_DELIMITER '/'
#define TR_PATH_DELIMITER_STR "/"
/* Only use this macro to suppress false-positive alignment warnings */
#define TR_DISCARD_ALIGN(ptr, type) ((type)(void*)(ptr))

View File

@@ -257,6 +257,40 @@ char const* tr_strcasestr(char const* haystack, char const* needle);
**** std::string_view utils
***/
template<typename... T, typename std::enable_if_t<(std::is_convertible_v<T, std::string_view> && ...), bool> = true>
std::string tr_strvPath(T... args)
{
auto setme = std::string{};
auto const n_args = sizeof...(args);
auto const n = n_args + (std::size(std::string_view{ args }) + ...);
if (setme.capacity() < n)
{
setme.reserve(n);
}
auto const foo = [](std::string& setme, std::string_view a)
{
setme += a;
setme += TR_PATH_DELIMITER;
};
(foo(setme, args), ...);
setme.resize(setme.size() - 1);
return setme;
}
template<typename... T, typename std::enable_if_t<(std::is_convertible_v<T, std::string_view> && ...), bool> = true>
std::string tr_strvJoin(T... args)
{
auto setme = std::string{};
auto const n = (std::size(std::string_view{ args }) + ...);
if (setme.capacity() < n)
{
setme.reserve(n);
}
((setme += args), ...);
return setme;
}
template<typename T>
constexpr bool tr_strvContains(std::string_view sv, T key) // c++23
{

View File

@@ -41,7 +41,7 @@
#include "file.h"
#include "log.h"
#include "tr-assert.h"
#include "utils.h" /* tr_new(), tr_free() */
#include "utils.h"
#include "variant.h"
#include "variant-common.h"

View File

@@ -54,23 +54,22 @@ struct tr_watchdir
static bool is_regular_file(char const* dir, char const* name)
{
char* const path = tr_buildPath(dir, name, nullptr);
auto const path = tr_strvPath(dir, name);
auto path_info = tr_sys_path_info{};
tr_error* error = nullptr;
bool const ret = tr_sys_path_get_info(path, 0, &path_info, &error) && (path_info.type == TR_SYS_PATH_IS_FILE);
bool const ret = tr_sys_path_get_info(path.c_str(), 0, &path_info, &error) && (path_info.type == TR_SYS_PATH_IS_FILE);
if (error != nullptr)
{
if (!TR_ERROR_IS_ENOENT(error->code))
{
log_error("Failed to get type of \"%s\" (%d): %s", path, error->code, error->message);
log_error("Failed to get type of \"%s\" (%d): %s", path.c_str(), error->code, error->message);
}
tr_error_free(error);
}
tr_free(path);
return ret;
}

View File

@@ -433,12 +433,11 @@ static void tr_webThreadFunc(void* vsession)
tr_logAddNamedInfo("web", "NB: invalid certs will show up as 'Could not connect to tracker' like many other errors");
}
char* const str = tr_buildPath(session->configDir, "cookies.txt", nullptr);
if (tr_sys_path_exists(str, nullptr))
auto const str = tr_strvPath(session->configDir, "cookies.txt");
if (tr_sys_path_exists(str.c_str(), nullptr))
{
web->cookie_filename = tr_strdup(str);
web->cookie_filename = tr_strvDup(str);
}
tr_free(str);
auto* const multi = curl_multi_init();
session->web = web;

View File

@@ -75,7 +75,7 @@ TEST_F(BlocklistTest, parsing)
EXPECT_EQ(0, tr_blocklistGetRuleCount(session_));
// init the blocklist
auto const path = makeString(tr_buildPath(tr_sessionGetConfigDir(session_), "blocklists", "level1", nullptr));
auto const path = tr_strvPath(tr_sessionGetConfigDir(session_), "blocklists", "level1");
createFileWithContents(path, Contents1);
tr_sessionReloadBlocklists(session_);
EXPECT_TRUE(tr_blocklistExists(session_));
@@ -111,7 +111,7 @@ TEST_F(BlocklistTest, parsing)
TEST_F(BlocklistTest, updating)
{
// init the session
char* path = tr_buildPath(tr_sessionGetConfigDir(session_), "blocklists", "level1", nullptr);
auto const path = tr_strvPath(tr_sessionGetConfigDir(session_), "blocklists", "level1");
// no blocklist to start with...
EXPECT_EQ(0, tr_blocklistGetRuleCount(session_));
@@ -137,7 +137,6 @@ TEST_F(BlocklistTest, updating)
EXPECT_EQ(5, tr_blocklistGetRuleCount(session_));
// cleanup
tr_free(path);
}
} // namespace test

View File

@@ -25,7 +25,7 @@ class CopyTest : public SandboxedTest
protected:
void testImpl(char const* filename1, char const* filename2, size_t const file_length)
{
auto const path1 = tr_buildPath(sandboxDir().data(), filename1, nullptr);
auto const path1 = tr_strvPath(sandboxDir(), filename1);
/* Create a file. */
char* file_content = static_cast<char*>(tr_malloc(file_length));
@@ -33,22 +33,19 @@ protected:
createFileWithContents(path1, file_content, file_length);
tr_free(file_content);
auto const path2 = tr_buildPath(sandboxDir().data(), filename2, nullptr);
auto const path2 = tr_strvPath(sandboxDir(), filename2);
tr_error* err = nullptr;
/* Copy it. */
EXPECT_TRUE(tr_sys_path_copy(path1, path2, &err));
EXPECT_TRUE(tr_sys_path_copy(path1.c_str(), path2.c_str(), &err));
EXPECT_EQ(nullptr, err);
tr_error_clear(&err);
EXPECT_TRUE(filesAreIdentical(path1, path2));
EXPECT_TRUE(filesAreIdentical(path1.c_str(), path2.c_str()));
/* Dispose of those files that we created. */
tr_sys_path_remove(path1, nullptr);
tr_free(path1);
tr_sys_path_remove(path2, nullptr);
tr_free(path2);
tr_sys_path_remove(path1.c_str(), nullptr);
tr_sys_path_remove(path2.c_str(), nullptr);
}
private:

File diff suppressed because it is too large Load Diff

View File

@@ -19,6 +19,8 @@
#include <cstring> // strlen()
#include <string>
using namespace std::literals;
namespace libtransmission
{
@@ -40,23 +42,23 @@ protected:
{
// create a single input file
auto input_file = makeString(tr_buildPath(sandboxDir().data(), "test.XXXXXX", nullptr));
auto input_file = tr_strvPath(sandboxDir().data(), "test.XXXXXX");
createTmpfileWithContents(input_file, payload, payloadSize);
tr_sys_path_native_separators(&input_file.front());
tr_sys_path_native_separators(std::data(input_file));
auto* builder = tr_metaInfoBuilderCreate(input_file.c_str());
EXPECT_EQ(tr_file_index_t{ 1 }, builder->fileCount);
EXPECT_STREQ(input_file.c_str(), builder->top);
EXPECT_STREQ(input_file.c_str(), builder->files[0].filename);
EXPECT_EQ(input_file, builder->top);
EXPECT_EQ(input_file, builder->files[0].filename);
EXPECT_EQ(payloadSize, builder->files[0].size);
EXPECT_EQ(payloadSize, builder->totalSize);
EXPECT_FALSE(builder->isFolder);
EXPECT_FALSE(builder->abortFlag);
// have tr_makeMetaInfo() build the .torrent file
auto* torrent_file = tr_strdup_printf("%s.torrent", input_file.data());
tr_makeMetaInfo(builder, torrent_file, trackers, trackerCount, comment, isPrivate, source);
auto const torrent_file = tr_strvJoin(input_file, ".torrent");
tr_makeMetaInfo(builder, torrent_file.c_str(), trackers, trackerCount, comment, isPrivate, source);
EXPECT_EQ(isPrivate, builder->isPrivate);
EXPECT_STREQ(torrent_file, builder->outputFile);
EXPECT_EQ(torrent_file, builder->outputFile);
EXPECT_STREQ(comment, builder->comment);
EXPECT_STREQ(source, builder->source);
EXPECT_EQ(trackerCount, builder->trackerCount);
@@ -69,7 +71,7 @@ protected:
// now let's check our work: parse the .torrent file
auto* ctor = tr_ctorNew(nullptr);
sync();
tr_ctorSetMetainfoFromFile(ctor, torrent_file);
tr_ctorSetMetainfoFromFile(ctor, torrent_file.c_str());
auto const parse_result = tr_torrentParse(ctor, &inf);
EXPECT_EQ(TR_PARSE_OK, parse_result);
@@ -83,7 +85,6 @@ protected:
EXPECT_EQ(trackerCount, inf.trackerCount);
// cleanup
tr_free(torrent_file);
tr_ctorFree(ctor);
tr_metaInfoBuilderFree(builder);
}
@@ -99,9 +100,9 @@ protected:
char const* source)
{
// create the top temp directory
auto* top = tr_buildPath(sandboxDir().data(), "folder.XXXXXX", nullptr);
tr_sys_path_native_separators(top);
tr_sys_dir_create_temp(top, nullptr);
auto top = tr_strvPath(sandboxDir(), "folder.XXXXXX");
tr_sys_path_native_separators(std::data(top));
tr_sys_dir_create_temp(std::data(top), nullptr);
// build the payload files that go into the top temp directory
auto files = std::vector<std::string>{};
@@ -112,9 +113,9 @@ protected:
{
auto tmpl = std::array<char, 16>{};
tr_snprintf(tmpl.data(), tmpl.size(), "file.%04zu%s", i, "XXXXXX");
auto path = makeString(tr_buildPath(top, tmpl.data(), nullptr));
auto path = tr_strvPath(top, std::data(tmpl));
createTmpfileWithContents(path, payloads[i], payload_sizes[i]);
tr_sys_path_native_separators(&path.front());
tr_sys_path_native_separators(std::data(path));
files.push_back(path);
total_size += payload_sizes[i];
}
@@ -122,9 +123,9 @@ protected:
sync();
// init the builder
auto* builder = tr_metaInfoBuilderCreate(top);
auto* builder = tr_metaInfoBuilderCreate(top.c_str());
EXPECT_FALSE(builder->abortFlag);
EXPECT_STREQ(top, builder->top);
EXPECT_EQ(top, builder->top);
EXPECT_EQ(payload_count, builder->fileCount);
EXPECT_EQ(total_size, builder->totalSize);
EXPECT_TRUE(builder->isFolder);
@@ -136,10 +137,10 @@ protected:
}
// build the .torrent file
auto* torrent_file = tr_strdup_printf("%s.torrent", top);
tr_makeMetaInfo(builder, torrent_file, trackers, tracker_count, comment, is_private, source);
auto torrent_file = tr_strvJoin(top, ".torrent"sv);
tr_makeMetaInfo(builder, torrent_file.c_str(), trackers, tracker_count, comment, is_private, source);
EXPECT_EQ(is_private, builder->isPrivate);
EXPECT_STREQ(torrent_file, builder->outputFile);
EXPECT_EQ(torrent_file, builder->outputFile);
EXPECT_STREQ(comment, builder->comment);
EXPECT_STREQ(source, builder->source);
EXPECT_EQ(tracker_count, builder->trackerCount);
@@ -152,14 +153,14 @@ protected:
// now let's check our work: parse the .torrent file
auto* ctor = tr_ctorNew(nullptr);
tr_ctorSetMetainfoFromFile(ctor, torrent_file);
tr_ctorSetMetainfoFromFile(ctor, torrent_file.c_str());
auto inf = tr_info{};
auto parse_result = tr_torrentParse(ctor, &inf);
EXPECT_EQ(TR_PARSE_OK, parse_result);
// quick check of some of the parsed metainfo
EXPECT_EQ(total_size, inf.totalSize);
auto* tmpstr = tr_sys_path_basename(top, nullptr);
auto* tmpstr = tr_sys_path_basename(top.c_str(), nullptr);
EXPECT_STREQ(tmpstr, inf.name);
tr_free(tmpstr);
EXPECT_STREQ(comment, inf.comment);
@@ -170,12 +171,9 @@ protected:
EXPECT_EQ(tracker_count, inf.trackerCount);
// cleanup
tr_free(torrent_file);
tr_ctorFree(ctor);
tr_metainfoFree(&inf);
tr_metaInfoBuilderFree(builder);
tr_free(top);
}
void testSingleDirectoryRandomPayloadImpl(

View File

@@ -53,9 +53,7 @@ TEST_P(IncompleteDirTest, incompleteDir)
EXPECT_EQ(
makeString(tr_strdup_printf("%s/%s.part", incomplete_dir, tor->info.files[0].name)),
makeString(tr_torrentFindFile(tor, 0)));
EXPECT_EQ(
makeString(tr_buildPath(incomplete_dir, tor->info.files[1].name, nullptr)),
makeString(tr_torrentFindFile(tor, 1)));
EXPECT_EQ(tr_strvPath(incomplete_dir, tor->info.files[1].name), makeString(tr_torrentFindFile(tor, 1)));
EXPECT_EQ(tor->info.pieceSize, tr_torrentStat(tor)->leftUntilDone);
// auto constexpr completeness_unset = tr_completeness { -1 };
@@ -129,9 +127,7 @@ TEST_P(IncompleteDirTest, incompleteDir)
for (tr_file_index_t file_index = 0; file_index < tor->info.fileCount; ++file_index)
{
EXPECT_EQ(
makeString(tr_buildPath(download_dir, tor->info.files[file_index].name, nullptr)),
makeString(tr_torrentFindFile(tor, file_index)));
EXPECT_EQ(tr_strvPath(download_dir, tor->info.files[file_index].name), makeString(tr_torrentFindFile(tor, file_index)));
}
// cleanup
@@ -157,7 +153,7 @@ using MoveTest = SessionTest;
TEST_F(MoveTest, setLocation)
{
auto const target_dir = makeString(tr_buildPath(tr_sessionGetConfigDir(session_), "target", nullptr));
auto const target_dir = tr_strvPath(tr_sessionGetConfigDir(session_), "target");
tr_sys_dir_create(target_dir.data(), TR_SYS_DIR_CREATE_PARENTS, 0777, nullptr);
// init a torrent.
@@ -185,7 +181,7 @@ TEST_F(MoveTest, setLocation)
for (tr_file_index_t file_index = 0; file_index < tor->info.fileCount; ++file_index)
{
EXPECT_EQ(
makeString(tr_buildPath(target_dir.data(), tor->info.files[file_index].name, nullptr)),
tr_strvPath(target_dir.data(), tor->info.files[file_index].name),
makeString(tr_torrentFindFile(tor, file_index)));
}

View File

@@ -45,22 +45,22 @@ protected:
void createSingleFileTorrentContents(char const* top)
{
auto const path = makeString(tr_buildPath(top, "hello-world.txt", nullptr));
auto const path = tr_strvPath(top, "hello-world.txt");
createFileWithContents(path, "hello, world!\n");
}
void createMultifileTorrentContents(char const* top)
{
auto path = makeString(tr_buildPath(top, "Felidae", "Felinae", "Acinonyx", "Cheetah", "Chester", nullptr));
auto path = tr_strvPath(top, "Felidae", "Felinae", "Acinonyx", "Cheetah", "Chester");
createFileWithContents(path, "It ain't easy bein' cheesy.\n");
path = makeString(tr_buildPath(top, "Felidae", "Pantherinae", "Panthera", "Tiger", "Tony", nullptr));
path = tr_strvPath(top, "Felidae", "Pantherinae", "Panthera", "Tiger", "Tony");
createFileWithContents(path, "Theyre Grrrrreat!\n");
path = makeString(tr_buildPath(top, "Felidae", "Felinae", "Felis", "catus", "Kyphi", nullptr));
path = tr_strvPath(top, "Felidae", "Felinae", "Felis", "catus", "Kyphi");
createFileWithContents(path, "Inquisitive\n");
path = makeString(tr_buildPath(top, "Felidae", "Felinae", "Felis", "catus", "Saffron", nullptr));
path = tr_strvPath(top, "Felidae", "Felinae", "Felis", "catus", "Saffron");
createFileWithContents(path, "Tough\n");
sync();
@@ -196,7 +196,7 @@ TEST_F(RenameTest, singleFilenameTorrent)
**** Now try a rename that should succeed
***/
auto tmpstr = makeString(tr_buildPath(tor->currentDir, "hello-world.txt", nullptr));
auto tmpstr = tr_strvPath(tor->currentDir, "hello-world.txt");
EXPECT_TRUE(tr_sys_path_exists(tmpstr.c_str(), nullptr));
EXPECT_STREQ("hello-world.txt", tr_torrentName(tor));
EXPECT_EQ(0, torrentRenameAndWait(tor, tor->info.name, "foobar"));
@@ -205,7 +205,7 @@ TEST_F(RenameTest, singleFilenameTorrent)
EXPECT_STREQ("foobar", tr_torrentName(tor)); // confirm the torrent's name is now 'foobar'
EXPECT_STREQ("foobar", tor->info.files[0].name); // confirm the file's name is now 'foobar' in our struct
EXPECT_STREQ(nullptr, strstr(tor->info.torrent, "foobar")); // confirm the name in the .torrent file hasn't changed
tmpstr = makeString(tr_buildPath(tor->currentDir, "foobar", nullptr));
tmpstr = tr_strvPath(tor->currentDir, "foobar");
EXPECT_TRUE(tr_sys_path_exists(tmpstr.c_str(), nullptr)); // confirm the file's name is now 'foobar' on the disk
EXPECT_TRUE(testFileExistsAndConsistsOfThisString(tor, 0, "hello, world!\n")); // confirm the contents are right
@@ -220,7 +220,7 @@ TEST_F(RenameTest, singleFilenameTorrent)
**** ...and rename it back again
***/
tmpstr = makeString(tr_buildPath(tor->currentDir, "foobar", nullptr));
tmpstr = tr_strvPath(tor->currentDir, "foobar");
EXPECT_TRUE(tr_sys_path_exists(tmpstr.c_str(), nullptr));
EXPECT_EQ(0, torrentRenameAndWait(tor, "foobar", "hello-world.txt"));
EXPECT_FALSE(tr_sys_path_exists(tmpstr.c_str(), nullptr));
@@ -521,11 +521,10 @@ TEST_F(RenameTest, partialFile)
for (tr_file_index_t i = 0; i < 3; ++i)
{
char* expected = tr_buildPath(tor->currentDir, strings[i], nullptr);
auto const expected = tr_strvPath(tor->currentDir, strings[i]);
char* path = tr_torrentFindFile(tor, i);
EXPECT_STREQ(expected, path);
EXPECT_EQ(expected, path);
tr_free(path);
tr_free(expected);
}
torrentRemoveAndWait(tor, 0);

View File

@@ -105,9 +105,9 @@ protected:
static std::string create_sandbox(std::string const& parent_dir, std::string const& tmpl)
{
std::string path = makeString(tr_buildPath(parent_dir.data(), tmpl.data(), nullptr));
tr_sys_dir_create_temp(&path.front(), nullptr);
tr_sys_path_native_separators(&path.front());
auto path = tr_strvPath(parent_dir, tmpl);
tr_sys_dir_create_temp(std::data(path), nullptr);
tr_sys_path_native_separators(std::data(path));
return path;
}
@@ -126,7 +126,7 @@ protected:
{
if (strcmp(name, ".") != 0 && strcmp(name, "..") != 0)
{
ret.push_back(makeString(tr_buildPath(path.data(), name, nullptr)));
ret.push_back(tr_strvPath(path, name));
}
}
@@ -302,21 +302,19 @@ private:
// download dir
auto sv = std::string_view{};
auto q = TR_KEY_download_dir;
auto const download_dir = tr_variantDictFindStrView(settings, q, &sv) ?
makeString(tr_strdup_printf("%s/%" TR_PRIsv, sandboxDir().data(), TR_PRIsv_ARG(sv))) :
makeString(tr_buildPath(sandboxDir().data(), "Downloads", nullptr));
auto const download_dir = tr_variantDictFindStrView(settings, q, &sv) ? tr_strvPath(sandboxDir(), sv) :
tr_strvPath(sandboxDir(), "Downloads");
tr_sys_dir_create(download_dir.data(), TR_SYS_DIR_CREATE_PARENTS, 0700, nullptr);
tr_variantDictAddStr(settings, q, download_dir.data());
// incomplete dir
q = TR_KEY_incomplete_dir;
auto const incomplete_dir = tr_variantDictFindStrView(settings, q, &sv) ?
makeString(tr_strdup_printf("%s/%" TR_PRIsv, sandboxDir().data(), TR_PRIsv_ARG(sv))) :
makeString(tr_buildPath(sandboxDir().data(), "Incomplete", nullptr));
auto const incomplete_dir = tr_variantDictFindStrView(settings, q, &sv) ? tr_strvPath(sandboxDir(), sv) :
tr_strvPath(sandboxDir(), "Incomplete");
tr_variantDictAddStr(settings, q, incomplete_dir.data());
// blocklists
auto const blocklist_dir = makeString(tr_buildPath(sandboxDir().data(), "blocklists", nullptr));
auto const blocklist_dir = tr_strvPath(sandboxDir(), "blocklists");
tr_sys_dir_create(blocklist_dir.data(), TR_SYS_DIR_CREATE_PARENTS, 0700, nullptr);
// fill in any missing settings

View File

@@ -49,6 +49,14 @@ TEST_F(UtilsTest, trStripPositionalArgs)
EXPECT_STREQ(expected, out);
}
TEST_F(UtilsTest, trStrvJoin)
{
EXPECT_EQ(""sv, tr_strvJoin(""sv));
EXPECT_EQ("test"sv, tr_strvJoin("test"sv));
EXPECT_EQ("foo/bar"sv, tr_strvJoin("foo"sv, "/", std::string{ "bar" }));
EXPECT_EQ("abcde"sv, tr_strvJoin("a", "b", "c", "d", "e"));
}
TEST_F(UtilsTest, trStrvContains)
{
EXPECT_FALSE(tr_strvContains("a test is this"sv, "TEST"sv));
@@ -148,6 +156,18 @@ TEST_F(UtilsTest, trBuildpath)
EXPECT_EQ(TR_PATH_DELIMITER_STR "foo" TR_PATH_DELIMITER_STR "bar", out);
}
TEST_F(UtilsTest, trStrvPath)
{
EXPECT_EQ("foo" TR_PATH_DELIMITER_STR "bar", tr_strvPath("foo", "bar"));
EXPECT_EQ(TR_PATH_DELIMITER_STR "foo" TR_PATH_DELIMITER_STR "bar", tr_strvPath("", "foo", "bar"));
EXPECT_EQ("", tr_strvPath(""sv));
EXPECT_EQ("foo"sv, tr_strvPath("foo"sv));
EXPECT_EQ(
"foo" TR_PATH_DELIMITER_STR "bar" TR_PATH_DELIMITER_STR "baz" TR_PATH_DELIMITER_STR "mum"sv,
tr_strvPath("foo"sv, "bar", std::string{ "baz" }, "mum"sv));
}
TEST_F(UtilsTest, trUtf8clean)
{
auto in = "hello world"sv;