fix: 3508 location invalidation (#3511)
* Revert "refactor: remove tr_sessionGetConfigDir() (#3506)" This reverts commitc50da43ae0
. * Revert "fix: do not leak in tr_getWebClientDir() (#3502)" This reverts commit5a75e37033
.
This commit is contained in:
parent
c50da43ae0
commit
0da1cbb6ec
|
@ -672,10 +672,8 @@ struct daemon_data
|
||||||
bool paused;
|
bool paused;
|
||||||
};
|
};
|
||||||
|
|
||||||
static void daemon_reconfigure(void* vdata)
|
static void daemon_reconfigure(void* /*arg*/)
|
||||||
{
|
{
|
||||||
auto const* const ddata = static_cast<daemon_data const*>(vdata);
|
|
||||||
|
|
||||||
if (mySession == nullptr)
|
if (mySession == nullptr)
|
||||||
{
|
{
|
||||||
tr_logAddInfo(_("Deferring reload until session is fully started."));
|
tr_logAddInfo(_("Deferring reload until session is fully started."));
|
||||||
|
@ -684,6 +682,7 @@ static void daemon_reconfigure(void* vdata)
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
tr_variant settings;
|
tr_variant settings;
|
||||||
|
char const* configDir;
|
||||||
|
|
||||||
/* reopen the logfile to allow for log rotation */
|
/* reopen the logfile to allow for log rotation */
|
||||||
if (logfileName != nullptr)
|
if (logfileName != nullptr)
|
||||||
|
@ -691,10 +690,11 @@ static void daemon_reconfigure(void* vdata)
|
||||||
reopen_log_file(logfileName);
|
reopen_log_file(logfileName);
|
||||||
}
|
}
|
||||||
|
|
||||||
tr_logAddInfo(fmt::format(_("Reloading settings from '{path}'"), fmt::arg("path", ddata->configDir)));
|
configDir = tr_sessionGetConfigDir(mySession);
|
||||||
|
tr_logAddInfo(fmt::format(_("Reloading settings from '{path}'"), fmt::arg("path", configDir)));
|
||||||
tr_variantInitDict(&settings, 0);
|
tr_variantInitDict(&settings, 0);
|
||||||
tr_variantDictAddBool(&settings, TR_KEY_rpc_enabled, true);
|
tr_variantDictAddBool(&settings, TR_KEY_rpc_enabled, true);
|
||||||
tr_sessionLoadSettings(&settings, ddata->configDir, MyName);
|
tr_sessionLoadSettings(&settings, configDir, MyName);
|
||||||
tr_sessionSet(mySession, &settings);
|
tr_sessionSet(mySession, &settings);
|
||||||
tr_variantFree(&settings);
|
tr_variantFree(&settings);
|
||||||
tr_sessionReloadBlocklists(mySession);
|
tr_sessionReloadBlocklists(mySession);
|
||||||
|
|
|
@ -156,7 +156,7 @@ private:
|
||||||
private:
|
private:
|
||||||
Application& app_;
|
Application& app_;
|
||||||
|
|
||||||
std::string const config_dir_;
|
std::string config_dir_;
|
||||||
bool start_paused_ = false;
|
bool start_paused_ = false;
|
||||||
bool is_iconified_ = false;
|
bool is_iconified_ = false;
|
||||||
bool is_closing_ = false;
|
bool is_closing_ = false;
|
||||||
|
@ -555,7 +555,7 @@ void Application::Impl::on_startup()
|
||||||
|
|
||||||
gtr_pref_flag_set(TR_KEY_alt_speed_enabled, tr_sessionUsesAltSpeed(session));
|
gtr_pref_flag_set(TR_KEY_alt_speed_enabled, tr_sessionUsesAltSpeed(session));
|
||||||
gtr_pref_int_set(TR_KEY_peer_port, tr_sessionGetPeerPort(session));
|
gtr_pref_int_set(TR_KEY_peer_port, tr_sessionGetPeerPort(session));
|
||||||
core_ = Session::create(session, config_dir_);
|
core_ = Session::create(session);
|
||||||
|
|
||||||
/* init the ui manager */
|
/* init the ui manager */
|
||||||
ui_builder_ = Gtk::Builder::create_from_resource(gtr_get_full_resource_path("transmission-ui.xml"s));
|
ui_builder_ = Gtk::Builder::create_from_resource(gtr_get_full_resource_path("transmission-ui.xml"s));
|
||||||
|
|
|
@ -84,7 +84,7 @@ private:
|
||||||
class Session::Impl
|
class Session::Impl
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
Impl(Session& core, tr_session* session, std::string_view config_dir);
|
Impl(Session& core, tr_session* session);
|
||||||
|
|
||||||
tr_session* close();
|
tr_session* close();
|
||||||
|
|
||||||
|
@ -153,7 +153,6 @@ private:
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Session& core_;
|
Session& core_;
|
||||||
std::string const config_dir_;
|
|
||||||
|
|
||||||
Glib::RefPtr<Gio::FileMonitor> monitor_;
|
Glib::RefPtr<Gio::FileMonitor> monitor_;
|
||||||
sigc::connection monitor_tag_;
|
sigc::connection monitor_tag_;
|
||||||
|
@ -800,23 +799,22 @@ void Session::Impl::on_pref_changed(tr_quark const key)
|
||||||
***
|
***
|
||||||
**/
|
**/
|
||||||
|
|
||||||
Glib::RefPtr<Session> Session::create(tr_session* session, std::string_view config_dir)
|
Glib::RefPtr<Session> Session::create(tr_session* session)
|
||||||
{
|
{
|
||||||
return Glib::make_refptr_for_instance(new Session(session, config_dir));
|
return Glib::make_refptr_for_instance(new Session(session));
|
||||||
}
|
}
|
||||||
|
|
||||||
Session::Session(tr_session* session, std::string_view config_dir)
|
Session::Session(tr_session* session)
|
||||||
: Glib::ObjectBase(typeid(Session))
|
: Glib::ObjectBase(typeid(Session))
|
||||||
, impl_(std::make_unique<Impl>(*this, session, config_dir))
|
, impl_(std::make_unique<Impl>(*this, session))
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
Session::~Session() = default;
|
Session::~Session() = default;
|
||||||
|
|
||||||
Session::Impl::Impl(Session& core, tr_session* session, std::string_view config_dir)
|
Session::Impl::Impl(Session& core, tr_session* session)
|
||||||
: core_{ core }
|
: core_(core)
|
||||||
, config_dir_{ config_dir }
|
, session_(session)
|
||||||
, session_{ session }
|
|
||||||
{
|
{
|
||||||
raw_model_ = Gtk::ListStore::create(torrent_cols);
|
raw_model_ = Gtk::ListStore::create(torrent_cols);
|
||||||
sorted_model_ = Gtk::TreeModelSort::create(raw_model_);
|
sorted_model_ = Gtk::TreeModelSort::create(raw_model_);
|
||||||
|
@ -1013,12 +1011,13 @@ tr_torrent* Session::Impl::create_new_torrent(tr_ctor* ctor)
|
||||||
|
|
||||||
if (tor != nullptr && do_trash)
|
if (tor != nullptr && do_trash)
|
||||||
{
|
{
|
||||||
|
char const* config = tr_sessionGetConfigDir(session_);
|
||||||
char const* source = tr_ctorGetSourceFile(ctor);
|
char const* source = tr_ctorGetSourceFile(ctor);
|
||||||
|
|
||||||
if (source != nullptr)
|
if (source != nullptr)
|
||||||
{
|
{
|
||||||
/* #1294: don't delete the .torrent file if it's our internal copy */
|
/* #1294: don't delete the .torrent file if it's our internal copy */
|
||||||
bool const is_internal = strstr(source, config_dir_.c_str()) == source;
|
bool const is_internal = strstr(source, config) == source;
|
||||||
|
|
||||||
if (!is_internal)
|
if (!is_internal)
|
||||||
{
|
{
|
||||||
|
|
|
@ -32,7 +32,7 @@ public:
|
||||||
|
|
||||||
TR_DISABLE_COPY_MOVE(Session)
|
TR_DISABLE_COPY_MOVE(Session)
|
||||||
|
|
||||||
static Glib::RefPtr<Session> create(tr_session* session, std::string_view config_dir);
|
static Glib::RefPtr<Session> create(tr_session* session);
|
||||||
|
|
||||||
tr_session* close();
|
tr_session* close();
|
||||||
|
|
||||||
|
@ -130,7 +130,7 @@ public:
|
||||||
sigc::signal<void(bool)>& signal_port_tested();
|
sigc::signal<void(bool)>& signal_port_tested();
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
explicit Session(tr_session* session, std::string_view config_dir);
|
explicit Session(tr_session* session);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
class Impl;
|
class Impl;
|
||||||
|
|
|
@ -4,11 +4,11 @@
|
||||||
// License text can be found in the licenses/ folder.
|
// License text can be found in the licenses/ folder.
|
||||||
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <array>
|
#include <cstring>
|
||||||
#include <iterator>
|
|
||||||
#include <list>
|
#include <list>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <string_view>
|
#include <string_view>
|
||||||
|
#include <thread>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
#ifdef __HAIKU__
|
#ifdef __HAIKU__
|
||||||
|
@ -124,6 +124,33 @@ static std::string xdgConfigHome()
|
||||||
return tr_strvPath(getHomeDir(), ".config"sv);
|
return tr_strvPath(getHomeDir(), ".config"sv);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void tr_setConfigDir(tr_session* session, std::string_view config_dir)
|
||||||
|
{
|
||||||
|
#if defined(__APPLE__) || defined(_WIN32)
|
||||||
|
auto constexpr ResumeSubdir = "Resume"sv;
|
||||||
|
auto constexpr TorrentSubdir = "Torrents"sv;
|
||||||
|
#else
|
||||||
|
auto constexpr ResumeSubdir = "resume"sv;
|
||||||
|
auto constexpr TorrentSubdir = "torrents"sv;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
session->config_dir = config_dir;
|
||||||
|
session->resume_dir = tr_strvPath(config_dir, ResumeSubdir);
|
||||||
|
session->torrent_dir = tr_strvPath(config_dir, TorrentSubdir);
|
||||||
|
tr_sys_dir_create(session->resume_dir, TR_SYS_DIR_CREATE_PARENTS, 0777);
|
||||||
|
tr_sys_dir_create(session->torrent_dir, TR_SYS_DIR_CREATE_PARENTS, 0777);
|
||||||
|
}
|
||||||
|
|
||||||
|
char const* tr_sessionGetConfigDir(tr_session const* session)
|
||||||
|
{
|
||||||
|
return session->config_dir.c_str();
|
||||||
|
}
|
||||||
|
|
||||||
|
char const* tr_getTorrentDir(tr_session const* session)
|
||||||
|
{
|
||||||
|
return session->torrent_dir.c_str();
|
||||||
|
}
|
||||||
|
|
||||||
char const* tr_getDefaultConfigDir(char const* appname)
|
char const* tr_getDefaultConfigDir(char const* appname)
|
||||||
{
|
{
|
||||||
static char const* s = nullptr;
|
static char const* s = nullptr;
|
||||||
|
@ -235,13 +262,7 @@ char const* tr_getDefaultDownloadDir()
|
||||||
****
|
****
|
||||||
***/
|
***/
|
||||||
|
|
||||||
namespace web_client_dir_helpers
|
static bool isWebClientDir(std::string_view path)
|
||||||
{
|
|
||||||
|
|
||||||
namespace
|
|
||||||
{
|
|
||||||
|
|
||||||
bool isWebClientDir(std::string_view path)
|
|
||||||
{
|
{
|
||||||
auto const filename = tr_pathbuf{ path, '/', "index.html"sv };
|
auto const filename = tr_pathbuf{ path, '/', "index.html"sv };
|
||||||
bool const found = tr_sys_path_exists(filename);
|
bool const found = tr_sys_path_exists(filename);
|
||||||
|
@ -249,147 +270,144 @@ bool isWebClientDir(std::string_view path)
|
||||||
return found;
|
return found;
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace
|
char const* tr_getWebClientDir([[maybe_unused]] tr_session const* session)
|
||||||
|
{
|
||||||
|
static char const* s = nullptr;
|
||||||
|
|
||||||
|
if (s == nullptr)
|
||||||
|
{
|
||||||
|
s = tr_env_get_string("CLUTCH_HOME", nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (s == nullptr)
|
||||||
|
{
|
||||||
|
s = tr_env_get_string("TRANSMISSION_WEB_HOME", nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
#ifdef BUILD_MAC_CLIENT
|
#ifdef BUILD_MAC_CLIENT
|
||||||
|
|
||||||
static std::string getPlatformWebClientDir(tr_session const* session)
|
|
||||||
{
|
|
||||||
// look in the Application Support folder
|
// look in the Application Support folder
|
||||||
if (auto path = tr_pathbuf{ session->configDir(), "/public_html"sv }; isWebClientDir(path))
|
if (s == nullptr)
|
||||||
{
|
{
|
||||||
return std::string{ path };
|
if (auto path = tr_pathbuf{ session->config_dir, "/public_html"sv }; isWebClientDir(path))
|
||||||
|
{
|
||||||
|
s = tr_strvDup(path);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// look in the resource bundle
|
// look in the resource bundle
|
||||||
auto app_url = CFBundleCopyBundleURL(CFBundleGetMainBundle());
|
if (s == nullptr)
|
||||||
auto app_ref = CFURLCopyFileSystemPath(app_url, kCFURLPOSIXPathStyle);
|
|
||||||
auto const buflen = CFStringGetMaximumSizeOfFileSystemRepresentation(app_ref);
|
|
||||||
auto buf = std::vector<char>(buflen, '\0');
|
|
||||||
bool const success = CFStringGetFileSystemRepresentation(app_ref, std::data(buf), std::size(buf));
|
|
||||||
TR_ASSERT(success);
|
|
||||||
CFRelease(app_url);
|
|
||||||
CFRelease(app_ref);
|
|
||||||
if (auto const path = tr_pathbuf{ std::string_view{ std::data(buf) }, "/Contents/Resources/public_html"sv };
|
|
||||||
isWebClientDir(path))
|
|
||||||
{
|
{
|
||||||
return std::string{ path };
|
auto app_url = CFBundleCopyBundleURL(CFBundleGetMainBundle());
|
||||||
}
|
auto app_ref = CFURLCopyFileSystemPath(app_url, kCFURLPOSIXPathStyle);
|
||||||
|
auto const buflen = CFStringGetMaximumSizeOfFileSystemRepresentation(app_ref);
|
||||||
|
auto buf = std::vector<char>(buflen, '\0');
|
||||||
|
bool const success = CFStringGetFileSystemRepresentation(app_ref, std::data(buf), std::size(buf));
|
||||||
|
TR_ASSERT(success);
|
||||||
|
CFRelease(app_url);
|
||||||
|
CFRelease(app_ref);
|
||||||
|
|
||||||
return {};
|
if (auto const path = tr_pathbuf{ std::string_view{ std::data(buf) }, "/Contents/Resources/public_html"sv };
|
||||||
}
|
isWebClientDir(path))
|
||||||
|
{
|
||||||
|
s = tr_strvDup(path);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#elif defined(_WIN32)
|
#elif defined(_WIN32)
|
||||||
|
|
||||||
static std::string getPlatformWebClientDir([[maybe_unused]] tr_session const* session)
|
if (s == nullptr)
|
||||||
{
|
|
||||||
/* Generally, Web interface should be stored in a Web subdir of
|
|
||||||
* calling executable dir. */
|
|
||||||
|
|
||||||
static auto constexpr KnownFolderIds = std::array<KNOWNFOLDERID const* const, 3>{
|
|
||||||
&FOLDERID_LocalAppData,
|
|
||||||
&FOLDERID_RoamingAppData,
|
|
||||||
&FOLDERID_ProgramData,
|
|
||||||
};
|
|
||||||
|
|
||||||
for (auto& folder_id : KnownFolderIds)
|
|
||||||
{
|
{
|
||||||
char* dir = win32_get_known_folder(*folder_id);
|
/* Generally, Web interface should be stored in a Web subdir of
|
||||||
|
* calling executable dir. */
|
||||||
|
|
||||||
if (auto const path = tr_pathbuf{ std::string_view{ dir }, "/Transmission/Web"sv }; isWebClientDir(path))
|
static KNOWNFOLDERID const* const known_folder_ids[] = {
|
||||||
|
&FOLDERID_LocalAppData,
|
||||||
|
&FOLDERID_RoamingAppData,
|
||||||
|
&FOLDERID_ProgramData,
|
||||||
|
};
|
||||||
|
|
||||||
|
for (size_t i = 0; s == nullptr && i < TR_N_ELEMENTS(known_folder_ids); ++i)
|
||||||
{
|
{
|
||||||
|
char* dir = win32_get_known_folder(*known_folder_ids[i]);
|
||||||
|
|
||||||
|
if (auto const path = tr_pathbuf{ std::string_view{ dir }, "/Transmission/Web"sv }; isWebClientDir(path))
|
||||||
|
{
|
||||||
|
s = tr_strvDup(path);
|
||||||
|
}
|
||||||
|
|
||||||
tr_free(dir);
|
tr_free(dir);
|
||||||
return std::string{ path };
|
|
||||||
}
|
}
|
||||||
|
|
||||||
tr_free(dir);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* check calling module place */
|
if (s == nullptr) /* check calling module place */
|
||||||
wchar_t wide_module_path[MAX_PATH];
|
|
||||||
GetModuleFileNameW(nullptr, wide_module_path, TR_N_ELEMENTS(wide_module_path));
|
|
||||||
char* const module_path = tr_win32_native_to_utf8(wide_module_path, -1);
|
|
||||||
|
|
||||||
if (auto const dir = tr_sys_path_dirname(module_path); !std::empty(dir))
|
|
||||||
{
|
{
|
||||||
if (auto const path = tr_pathbuf{ dir, "/Web"sv }; isWebClientDir(path))
|
wchar_t wide_module_path[MAX_PATH];
|
||||||
|
GetModuleFileNameW(nullptr, wide_module_path, TR_N_ELEMENTS(wide_module_path));
|
||||||
|
char* module_path = tr_win32_native_to_utf8(wide_module_path, -1);
|
||||||
|
|
||||||
|
if (auto const dir = tr_sys_path_dirname(module_path); !std::empty(dir))
|
||||||
{
|
{
|
||||||
tr_free(module_path);
|
if (auto const path = tr_pathbuf{ dir, "/Web"sv }; isWebClientDir(path))
|
||||||
return std::string{ path };
|
{
|
||||||
|
s = tr_strvDup(path);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
tr_free(module_path);
|
||||||
}
|
}
|
||||||
|
|
||||||
tr_free(module_path);
|
#else // everyone else, follow the XDG spec
|
||||||
|
|
||||||
return {};
|
if (s == nullptr)
|
||||||
}
|
|
||||||
|
|
||||||
#else
|
|
||||||
|
|
||||||
static std::string getPlatformWebClientDir([[maybe_unused]] tr_session const* session)
|
|
||||||
{
|
|
||||||
auto candidates = std::list<std::string>{};
|
|
||||||
|
|
||||||
// XDG_DATA_HOME should be the first candidate
|
|
||||||
if (char* tmp = tr_env_get_string("XDG_DATA_HOME", nullptr); !tr_str_is_empty(tmp))
|
|
||||||
{
|
{
|
||||||
candidates.emplace_back(tmp);
|
auto candidates = std::list<std::string>{};
|
||||||
|
|
||||||
|
/* XDG_DATA_HOME should be the first in the list of candidates */
|
||||||
|
char* tmp = tr_env_get_string("XDG_DATA_HOME", nullptr);
|
||||||
|
if (!tr_str_is_empty(tmp))
|
||||||
|
{
|
||||||
|
candidates.emplace_back(tmp);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
candidates.emplace_back(tr_strvPath(getHomeDir(), ".local"sv, "share"sv));
|
||||||
|
}
|
||||||
tr_free(tmp);
|
tr_free(tmp);
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
candidates.emplace_back(tr_strvPath(getHomeDir(), ".local"sv, "share"sv));
|
|
||||||
}
|
|
||||||
|
|
||||||
// XDG_DATA_DIRS are the backup directories
|
/* XDG_DATA_DIRS are the backup directories */
|
||||||
char const* const pkg = PACKAGE_DATA_DIR;
|
|
||||||
auto* xdg = tr_env_get_string("XDG_DATA_DIRS", "");
|
|
||||||
auto const buf = fmt::format(FMT_STRING("{:s}:{:s}:/usr/local/share:/usr/share"), pkg, xdg);
|
|
||||||
tr_free(xdg);
|
|
||||||
auto sv = std::string_view{ buf };
|
|
||||||
auto token = std::string_view{};
|
|
||||||
while (tr_strvSep(&sv, &token, ':'))
|
|
||||||
{
|
|
||||||
token = tr_strvStrip(token);
|
|
||||||
if (!std::empty(token))
|
|
||||||
{
|
{
|
||||||
candidates.emplace_back(token);
|
char const* const pkg = PACKAGE_DATA_DIR;
|
||||||
|
auto* xdg = tr_env_get_string("XDG_DATA_DIRS", "");
|
||||||
|
auto const buf = fmt::format(FMT_STRING("{:s}:{:s}:/usr/local/share:/usr/share"), pkg, xdg);
|
||||||
|
tr_free(xdg);
|
||||||
|
|
||||||
|
auto sv = std::string_view{ buf };
|
||||||
|
auto token = std::string_view{};
|
||||||
|
while (tr_strvSep(&sv, &token, ':'))
|
||||||
|
{
|
||||||
|
token = tr_strvStrip(token);
|
||||||
|
if (!std::empty(token))
|
||||||
|
{
|
||||||
|
candidates.emplace_back(token);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* walk through the candidates & look for a match */
|
||||||
|
for (auto const& dir : candidates)
|
||||||
|
{
|
||||||
|
if (auto const path = tr_pathbuf{ dir, "/transmission/public_html"sv }; isWebClientDir(path))
|
||||||
|
{
|
||||||
|
s = tr_strvDup(path);
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// walk through the candidates & look for a match
|
|
||||||
for (auto const& dir : candidates)
|
|
||||||
{
|
|
||||||
if (auto const path = tr_pathbuf{ dir, "/transmission/public_html"sv }; isWebClientDir(path))
|
|
||||||
{
|
|
||||||
return std::string{ path };
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
} // namespace web_client_dir_helpers
|
return s;
|
||||||
|
|
||||||
std::string tr_getWebClientDir([[maybe_unused]] tr_session const* session)
|
|
||||||
{
|
|
||||||
if (auto* const dir = tr_env_get_string("CLUTCH_HOME", nullptr); dir != nullptr)
|
|
||||||
{
|
|
||||||
auto ret = std::string{ dir };
|
|
||||||
tr_free(dir);
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (auto* const dir = tr_env_get_string("TRANSMISSION_WEB_HOME", nullptr); dir != nullptr)
|
|
||||||
{
|
|
||||||
auto ret = std::string{ dir };
|
|
||||||
tr_free(dir);
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
return web_client_dir_helpers::getPlatformWebClientDir(session);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string tr_getSessionIdDir()
|
std::string tr_getSessionIdDir()
|
||||||
|
|
|
@ -19,8 +19,19 @@ struct tr_session;
|
||||||
* @{
|
* @{
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief invoked by tr_sessionInit() to set up the locations of the resume, torrent, and clutch directories.
|
||||||
|
* @see tr_getResumeDir()
|
||||||
|
* @see tr_getTorrentDir()
|
||||||
|
* @see tr_getWebClientDir()
|
||||||
|
*/
|
||||||
|
void tr_setConfigDir(tr_session* session, std::string_view config_dir);
|
||||||
|
|
||||||
|
/** @brief return the directory where torrent files are stored */
|
||||||
|
char const* tr_getTorrentDir(tr_session const*);
|
||||||
|
|
||||||
/** @brief return the directory where the Web Client's web ui files are kept */
|
/** @brief return the directory where the Web Client's web ui files are kept */
|
||||||
std::string tr_getWebClientDir(tr_session const*);
|
char const* tr_getWebClientDir(tr_session const*);
|
||||||
|
|
||||||
/** @brief return the directory where session id lock files are stored */
|
/** @brief return the directory where session id lock files are stored */
|
||||||
std::string tr_getSessionIdDir();
|
std::string tr_getSessionIdDir();
|
||||||
|
|
|
@ -655,7 +655,7 @@ static auto loadFromFile(tr_torrent* tor, tr_resume::fields_t fieldsToLoad, bool
|
||||||
auto const wasDirty = tor->isDirty;
|
auto const wasDirty = tor->isDirty;
|
||||||
|
|
||||||
auto const migrated = tr_torrent_metainfo::migrateFile(
|
auto const migrated = tr_torrent_metainfo::migrateFile(
|
||||||
tor->session->resumeDir(),
|
tor->session->resume_dir,
|
||||||
tor->name(),
|
tor->name(),
|
||||||
tor->infoHashString(),
|
tor->infoHashString(),
|
||||||
".resume"sv);
|
".resume"sv);
|
||||||
|
|
|
@ -256,7 +256,9 @@ static void serve_file(struct evhttp_request* req, tr_rpc_server* server, std::s
|
||||||
|
|
||||||
static void handle_web_client(struct evhttp_request* req, tr_rpc_server* server)
|
static void handle_web_client(struct evhttp_request* req, tr_rpc_server* server)
|
||||||
{
|
{
|
||||||
if (std::empty(server->web_client_dir_))
|
char const* webClientDir = tr_getWebClientDir(server->session);
|
||||||
|
|
||||||
|
if (tr_str_is_empty(webClientDir))
|
||||||
{
|
{
|
||||||
send_simple_response(
|
send_simple_response(
|
||||||
req,
|
req,
|
||||||
|
@ -285,7 +287,7 @@ static void handle_web_client(struct evhttp_request* req, tr_rpc_server* server)
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
auto const filename = tr_pathbuf{ server->web_client_dir_, '/', tr_str_is_empty(subpath) ? "index.html" : subpath };
|
auto const filename = tr_pathbuf{ webClientDir, "/"sv, tr_str_is_empty(subpath) ? "index.html" : subpath };
|
||||||
serve_file(req, server, filename.sv());
|
serve_file(req, server, filename.sv());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -938,7 +940,6 @@ static void missing_settings_key(tr_quark const q)
|
||||||
|
|
||||||
tr_rpc_server::tr_rpc_server(tr_session* session_in, tr_variant* settings)
|
tr_rpc_server::tr_rpc_server(tr_session* session_in, tr_variant* settings)
|
||||||
: compressor{ libdeflate_alloc_compressor(DeflateLevel), libdeflate_free_compressor }
|
: compressor{ libdeflate_alloc_compressor(DeflateLevel), libdeflate_free_compressor }
|
||||||
, web_client_dir_{ tr_getWebClientDir(session_in) }
|
|
||||||
, bindAddress(std::make_unique<struct tr_rpc_address>())
|
, bindAddress(std::make_unique<struct tr_rpc_address>())
|
||||||
, session{ session_in }
|
, session{ session_in }
|
||||||
{
|
{
|
||||||
|
@ -1144,9 +1145,10 @@ tr_rpc_server::tr_rpc_server(tr_session* session_in, tr_variant* settings)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!std::empty(web_client_dir_))
|
char const* webClientDir = tr_getWebClientDir(this->session);
|
||||||
|
if (!tr_str_is_empty(webClientDir))
|
||||||
{
|
{
|
||||||
tr_logAddInfo(fmt::format(_("Serving RPC and Web requests from '{path}'"), fmt::arg("path", web_client_dir_)));
|
tr_logAddInfo(fmt::format(_("Serving RPC and Web requests from '{path}'"), fmt::arg("path", webClientDir)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -122,7 +122,6 @@ public:
|
||||||
|
|
||||||
std::vector<std::string> hostWhitelist;
|
std::vector<std::string> hostWhitelist;
|
||||||
std::vector<std::string> whitelist_;
|
std::vector<std::string> whitelist_;
|
||||||
std::string const web_client_dir_;
|
|
||||||
std::string salted_password_;
|
std::string salted_password_;
|
||||||
std::string username_;
|
std::string username_;
|
||||||
std::string whitelist_str_;
|
std::string whitelist_str_;
|
||||||
|
|
|
@ -1444,7 +1444,7 @@ static void onBlocklistFetched(tr_web::FetchResponse const& web_response)
|
||||||
|
|
||||||
// tr_blocklistSetContent needs a source file,
|
// tr_blocklistSetContent needs a source file,
|
||||||
// so save content into a tmpfile
|
// so save content into a tmpfile
|
||||||
auto const filename = tr_pathbuf{ session->configDir(), "/blocklist.tmp"sv };
|
auto const filename = tr_pathbuf{ session->config_dir, "/blocklist.tmp"sv };
|
||||||
if (tr_error* error = nullptr; !tr_saveFile(filename, content, &error))
|
if (tr_error* error = nullptr; !tr_saveFile(filename, content, &error))
|
||||||
{
|
{
|
||||||
tr_idle_function_done(
|
tr_idle_function_done(
|
||||||
|
@ -2171,7 +2171,7 @@ static void addSessionField(tr_session const* s, tr_variant* d, tr_quark key)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case TR_KEY_config_dir:
|
case TR_KEY_config_dir:
|
||||||
tr_variantDictAddStr(d, key, s->configDir());
|
tr_variantDictAddStr(d, key, tr_sessionGetConfigDir(s));
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case TR_KEY_default_trackers:
|
case TR_KEY_default_trackers:
|
||||||
|
|
|
@ -46,6 +46,7 @@
|
||||||
#include "peer-io.h"
|
#include "peer-io.h"
|
||||||
#include "peer-mgr.h"
|
#include "peer-mgr.h"
|
||||||
#include "platform-quota.h" /* tr_device_info_free() */
|
#include "platform-quota.h" /* tr_device_info_free() */
|
||||||
|
#include "platform.h" /* tr_getTorrentDir() */
|
||||||
#include "port-forwarding.h"
|
#include "port-forwarding.h"
|
||||||
#include "rpc-server.h"
|
#include "rpc-server.h"
|
||||||
#include "session-id.h"
|
#include "session-id.h"
|
||||||
|
@ -127,7 +128,7 @@ tr_peer_id_t tr_peerIdInit()
|
||||||
|
|
||||||
std::optional<std::string> tr_session::WebMediator::cookieFile() const
|
std::optional<std::string> tr_session::WebMediator::cookieFile() const
|
||||||
{
|
{
|
||||||
auto const path = tr_pathbuf{ session_->configDir(), "/cookies.txt"sv };
|
auto const path = tr_pathbuf{ session_->config_dir, "/cookies.txt" };
|
||||||
|
|
||||||
if (!tr_sys_path_exists(path))
|
if (!tr_sys_path_exists(path))
|
||||||
{
|
{
|
||||||
|
@ -725,7 +726,7 @@ static void tr_sessionInitImpl(init_data* data)
|
||||||
|
|
||||||
tr_logSetQueueEnabled(data->messageQueuingEnabled);
|
tr_logSetQueueEnabled(data->messageQueuingEnabled);
|
||||||
|
|
||||||
session->initConfigDir(data->config_dir);
|
tr_setConfigDir(session, data->config_dir);
|
||||||
|
|
||||||
session->peerMgr = tr_peerMgrNew(session);
|
session->peerMgr = tr_peerMgrNew(session);
|
||||||
|
|
||||||
|
@ -735,7 +736,7 @@ static void tr_sessionInitImpl(init_data* data)
|
||||||
*** Blocklist
|
*** Blocklist
|
||||||
**/
|
**/
|
||||||
|
|
||||||
tr_sys_dir_create(tr_pathbuf{ session->configDir(), "/blocklists"sv }, TR_SYS_DIR_CREATE_PARENTS, 0777);
|
tr_sys_dir_create(tr_pathbuf{ session->config_dir, "/blocklists"sv }, TR_SYS_DIR_CREATE_PARENTS, 0777);
|
||||||
loadBlocklists(session);
|
loadBlocklists(session);
|
||||||
|
|
||||||
TR_ASSERT(tr_isSession(session));
|
TR_ASSERT(tr_isSession(session));
|
||||||
|
@ -2035,14 +2036,16 @@ static void sessionLoadTorrents(struct sessionLoadTorrentsData* const data)
|
||||||
TR_ASSERT(tr_isSession(data->session));
|
TR_ASSERT(tr_isSession(data->session));
|
||||||
|
|
||||||
tr_sys_path_info info;
|
tr_sys_path_info info;
|
||||||
auto const& dirname = data->session->torrentDir();
|
char const* const dirname = tr_getTorrentDir(data->session);
|
||||||
tr_sys_dir_t odir = (tr_sys_path_get_info(dirname.c_str(), 0, &info) && info.type == TR_SYS_PATH_IS_DIRECTORY) ?
|
tr_sys_dir_t odir = (tr_sys_path_get_info(dirname, 0, &info) && info.type == TR_SYS_PATH_IS_DIRECTORY) ?
|
||||||
tr_sys_dir_open(dirname.c_str()) :
|
tr_sys_dir_open(dirname) :
|
||||||
TR_BAD_SYS_DIR;
|
TR_BAD_SYS_DIR;
|
||||||
|
|
||||||
auto torrents = std::list<tr_torrent*>{};
|
auto torrents = std::list<tr_torrent*>{};
|
||||||
if (odir != TR_BAD_SYS_DIR)
|
if (odir != TR_BAD_SYS_DIR)
|
||||||
{
|
{
|
||||||
|
auto const dirname_sv = std::string_view{ dirname };
|
||||||
|
|
||||||
char const* name = nullptr;
|
char const* name = nullptr;
|
||||||
while ((name = tr_sys_dir_read_name(odir)) != nullptr)
|
while ((name = tr_sys_dir_read_name(odir)) != nullptr)
|
||||||
{
|
{
|
||||||
|
@ -2051,7 +2054,7 @@ static void sessionLoadTorrents(struct sessionLoadTorrentsData* const data)
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto const path = tr_pathbuf{ dirname, '/', name };
|
auto const path = tr_pathbuf{ dirname_sv, "/"sv, name };
|
||||||
|
|
||||||
// is a magnet link?
|
// is a magnet link?
|
||||||
if (!tr_ctorSetMetainfoFromFile(data->ctor, path.sv(), nullptr))
|
if (!tr_ctorSetMetainfoFromFile(data->ctor, path.sv(), nullptr))
|
||||||
|
@ -2349,7 +2352,7 @@ static void loadBlocklists(tr_session* session)
|
||||||
auto const isEnabled = session->useBlocklist();
|
auto const isEnabled = session->useBlocklist();
|
||||||
|
|
||||||
/* walk the blocklist directory... */
|
/* walk the blocklist directory... */
|
||||||
auto const dirname = tr_pathbuf{ session->configDir(), "/blocklists"sv };
|
auto const dirname = tr_pathbuf{ session->config_dir, "/blocklists"sv };
|
||||||
auto const odir = tr_sys_dir_open(dirname);
|
auto const odir = tr_sys_dir_open(dirname);
|
||||||
|
|
||||||
if (odir == TR_BAD_SYS_DIR)
|
if (odir == TR_BAD_SYS_DIR)
|
||||||
|
@ -2489,7 +2492,7 @@ size_t tr_blocklistSetContent(tr_session* session, char const* contentFilename)
|
||||||
BlocklistFile* b = nullptr;
|
BlocklistFile* b = nullptr;
|
||||||
if (it == std::end(src))
|
if (it == std::end(src))
|
||||||
{
|
{
|
||||||
auto path = tr_pathbuf{ session->configDir(), "/blocklists/"sv, name };
|
auto path = tr_pathbuf{ session->config_dir, "/blocklists/"sv, name };
|
||||||
src.push_back(std::make_unique<BlocklistFile>(path, session->useBlocklist()));
|
src.push_back(std::make_unique<BlocklistFile>(path, session->useBlocklist()));
|
||||||
b = std::rbegin(src)->get();
|
b = std::rbegin(src)->get();
|
||||||
}
|
}
|
||||||
|
@ -2951,24 +2954,3 @@ void tr_session::closeTorrentFile(tr_torrent* tor, tr_file_index_t file_num) noe
|
||||||
this->cache->flushFile(tor, file_num);
|
this->cache->flushFile(tor, file_num);
|
||||||
openFiles().closeFile(tor->id(), file_num);
|
openFiles().closeFile(tor->id(), file_num);
|
||||||
}
|
}
|
||||||
|
|
||||||
///
|
|
||||||
|
|
||||||
void tr_session::initConfigDir(std::string_view config_dir)
|
|
||||||
{
|
|
||||||
TR_ASSERT(std::empty(config_dir_));
|
|
||||||
|
|
||||||
#if defined(__APPLE__) || defined(_WIN32)
|
|
||||||
auto constexpr ResumeSubdir = "Resume"sv;
|
|
||||||
auto constexpr TorrentSubdir = "Torrents"sv;
|
|
||||||
#else
|
|
||||||
auto constexpr ResumeSubdir = "resume"sv;
|
|
||||||
auto constexpr TorrentSubdir = "torrents"sv;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
config_dir_ = config_dir;
|
|
||||||
resume_dir_ = tr_strvPath(config_dir, ResumeSubdir);
|
|
||||||
torrent_dir_ = tr_strvPath(config_dir, TorrentSubdir);
|
|
||||||
tr_sys_dir_create(resume_dir_, TR_SYS_DIR_CREATE_PARENTS, 0777);
|
|
||||||
tr_sys_dir_create(torrent_dir_, TR_SYS_DIR_CREATE_PARENTS, 0777);
|
|
||||||
}
|
|
||||||
|
|
|
@ -396,26 +396,13 @@ public:
|
||||||
public_peer_port = port;
|
public_peer_port = port;
|
||||||
}
|
}
|
||||||
|
|
||||||
[[nodiscard]] constexpr auto const& configDir() const noexcept
|
|
||||||
{
|
|
||||||
return config_dir_;
|
|
||||||
}
|
|
||||||
|
|
||||||
void initConfigDir(std::string_view config_dir);
|
|
||||||
|
|
||||||
[[nodiscard]] constexpr auto const& resumeDir() const noexcept
|
|
||||||
{
|
|
||||||
return resume_dir_;
|
|
||||||
}
|
|
||||||
|
|
||||||
[[nodiscard]] constexpr auto const& torrentDir() const noexcept
|
|
||||||
{
|
|
||||||
return torrent_dir_;
|
|
||||||
}
|
|
||||||
|
|
||||||
tr_port randomPortLow;
|
tr_port randomPortLow;
|
||||||
tr_port randomPortHigh;
|
tr_port randomPortHigh;
|
||||||
|
|
||||||
|
std::string config_dir;
|
||||||
|
std::string resume_dir;
|
||||||
|
std::string torrent_dir;
|
||||||
|
|
||||||
std::vector<std::unique_ptr<BlocklistFile>> blocklists;
|
std::vector<std::unique_ptr<BlocklistFile>> blocklists;
|
||||||
struct tr_peerMgr* peerMgr = nullptr;
|
struct tr_peerMgr* peerMgr = nullptr;
|
||||||
struct tr_shared* shared = nullptr;
|
struct tr_shared* shared = nullptr;
|
||||||
|
@ -486,9 +473,6 @@ private:
|
||||||
tr_torrents torrents_;
|
tr_torrents torrents_;
|
||||||
|
|
||||||
std::array<std::string, TR_SCRIPT_N_TYPES> scripts_;
|
std::array<std::string, TR_SCRIPT_N_TYPES> scripts_;
|
||||||
std::string config_dir_;
|
|
||||||
std::string resume_dir_;
|
|
||||||
std::string torrent_dir_;
|
|
||||||
std::string blocklist_url_;
|
std::string blocklist_url_;
|
||||||
std::string download_dir_;
|
std::string download_dir_;
|
||||||
std::string default_trackers_str_;
|
std::string default_trackers_str_;
|
||||||
|
|
|
@ -34,14 +34,14 @@ static void loadCumulativeStats(tr_session const* session, tr_session_stats* set
|
||||||
{
|
{
|
||||||
auto top = tr_variant{};
|
auto top = tr_variant{};
|
||||||
|
|
||||||
auto filename = tr_pathbuf{ session->configDir(), "/stats.json"sv };
|
auto filename = tr_pathbuf{ session->config_dir, "/stats.json"sv };
|
||||||
bool loaded = tr_variantFromFile(&top, TR_VARIANT_PARSE_JSON, filename.sv(), nullptr);
|
bool loaded = tr_variantFromFile(&top, TR_VARIANT_PARSE_JSON, filename.sv(), nullptr);
|
||||||
|
|
||||||
if (!loaded)
|
if (!loaded)
|
||||||
{
|
{
|
||||||
// maybe the user just upgraded from an old version of Transmission
|
// maybe the user just upgraded from an old version of Transmission
|
||||||
// that was still using stats.benc
|
// that was still using stats.benc
|
||||||
filename.assign(session->configDir(), "/stats.benc"sv);
|
filename.assign(session->config_dir, "/stats.benc");
|
||||||
loaded = tr_variantFromFile(&top, TR_VARIANT_PARSE_BENC, filename.sv(), nullptr);
|
loaded = tr_variantFromFile(&top, TR_VARIANT_PARSE_BENC, filename.sv(), nullptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -80,7 +80,7 @@ static void loadCumulativeStats(tr_session const* session, tr_session_stats* set
|
||||||
|
|
||||||
static void saveCumulativeStats(tr_session const* session, tr_session_stats const* s)
|
static void saveCumulativeStats(tr_session const* session, tr_session_stats const* s)
|
||||||
{
|
{
|
||||||
auto const filename = tr_pathbuf{ session->configDir(), "/stats.json"sv };
|
auto const filename = tr_pathbuf{ session->config_dir, "/stats.json"sv };
|
||||||
auto top = tr_variant{};
|
auto top = tr_variant{};
|
||||||
tr_variantInitDict(&top, 5);
|
tr_variantInitDict(&top, 5);
|
||||||
tr_variantDictAddInt(&top, TR_KEY_downloaded_bytes, s->downloadedBytes);
|
tr_variantDictAddInt(&top, TR_KEY_downloaded_bytes, s->downloadedBytes);
|
||||||
|
|
|
@ -766,7 +766,7 @@ static void torrentInit(tr_torrent* tor, tr_ctor const* ctor)
|
||||||
|
|
||||||
if (resume_file_was_migrated)
|
if (resume_file_was_migrated)
|
||||||
{
|
{
|
||||||
tr_torrent_metainfo::migrateFile(session->torrentDir(), tor->name(), tor->infoHashString(), ".torrent"sv);
|
tr_torrent_metainfo::migrateFile(session->torrent_dir, tor->name(), tor->infoHashString(), ".torrent"sv);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1624,9 +1624,9 @@ static void closeTorrent(tr_torrent* const tor)
|
||||||
|
|
||||||
if (tor->isDeleting)
|
if (tor->isDeleting)
|
||||||
{
|
{
|
||||||
tr_torrent_metainfo::removeFile(tor->session->torrentDir(), tor->name(), tor->infoHashString(), ".torrent"sv);
|
tr_torrent_metainfo::removeFile(tor->session->torrent_dir, tor->name(), tor->infoHashString(), ".torrent"sv);
|
||||||
tr_torrent_metainfo::removeFile(tor->session->torrentDir(), tor->name(), tor->infoHashString(), ".magnet"sv);
|
tr_torrent_metainfo::removeFile(tor->session->torrent_dir, tor->name(), tor->infoHashString(), ".magnet"sv);
|
||||||
tr_torrent_metainfo::removeFile(tor->session->resumeDir(), tor->name(), tor->infoHashString(), ".resume"sv);
|
tr_torrent_metainfo::removeFile(tor->session->resume_dir, tor->name(), tor->infoHashString(), ".resume"sv);
|
||||||
}
|
}
|
||||||
|
|
||||||
tor->isRunning = false;
|
tor->isRunning = false;
|
||||||
|
|
|
@ -450,17 +450,17 @@ public:
|
||||||
|
|
||||||
[[nodiscard]] auto torrentFile() const
|
[[nodiscard]] auto torrentFile() const
|
||||||
{
|
{
|
||||||
return metainfo_.torrentFile(this->session->torrentDir());
|
return metainfo_.torrentFile(this->session->torrent_dir);
|
||||||
}
|
}
|
||||||
|
|
||||||
[[nodiscard]] auto magnetFile() const
|
[[nodiscard]] auto magnetFile() const
|
||||||
{
|
{
|
||||||
return metainfo_.magnetFile(this->session->torrentDir());
|
return metainfo_.magnetFile(this->session->torrent_dir);
|
||||||
}
|
}
|
||||||
|
|
||||||
[[nodiscard]] auto resumeFile() const
|
[[nodiscard]] auto resumeFile() const
|
||||||
{
|
{
|
||||||
return metainfo_.resumeFile(this->session->torrentDir());
|
return metainfo_.resumeFile(this->session->resume_dir);
|
||||||
}
|
}
|
||||||
|
|
||||||
[[nodiscard]] auto magnet() const
|
[[nodiscard]] auto magnet() const
|
||||||
|
|
|
@ -146,7 +146,7 @@ static void dht_boostrap_from_file(tr_session* session)
|
||||||
}
|
}
|
||||||
|
|
||||||
// check for a manual bootstrap file.
|
// check for a manual bootstrap file.
|
||||||
auto in = std::ifstream{ tr_pathbuf{ session->configDir(), "/dht.bootstrap"sv } };
|
auto in = std::ifstream{ tr_pathbuf{ session->config_dir, "/dht.bootstrap"sv } };
|
||||||
if (!in.is_open())
|
if (!in.is_open())
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
|
@ -292,7 +292,7 @@ int tr_dhtInit(tr_session* ss)
|
||||||
}
|
}
|
||||||
|
|
||||||
auto benc = tr_variant{};
|
auto benc = tr_variant{};
|
||||||
auto const dat_file = tr_pathbuf{ ss->configDir(), "/dht.dat"sv };
|
auto const dat_file = tr_pathbuf{ ss->config_dir, "/dht.dat"sv };
|
||||||
auto const ok = tr_variantFromFile(&benc, TR_VARIANT_PARSE_BENC, dat_file.sv());
|
auto const ok = tr_variantFromFile(&benc, TR_VARIANT_PARSE_BENC, dat_file.sv());
|
||||||
|
|
||||||
bool have_id = false;
|
bool have_id = false;
|
||||||
|
@ -443,7 +443,7 @@ void tr_dhtUninit(tr_session* ss)
|
||||||
tr_variantDictAddRaw(&benc, TR_KEY_nodes6, compact6, out6 - compact6);
|
tr_variantDictAddRaw(&benc, TR_KEY_nodes6, compact6, out6 - compact6);
|
||||||
}
|
}
|
||||||
|
|
||||||
auto const dat_file = tr_pathbuf{ ss->configDir(), "/dht.dat"sv };
|
auto const dat_file = tr_pathbuf{ ss->config_dir, "/dht.dat" };
|
||||||
tr_variantToFile(&benc, TR_VARIANT_FMT_BENC, dat_file.sv());
|
tr_variantToFile(&benc, TR_VARIANT_FMT_BENC, dat_file.sv());
|
||||||
tr_variantFree(&benc);
|
tr_variantFree(&benc);
|
||||||
}
|
}
|
||||||
|
|
|
@ -231,6 +231,15 @@ void tr_sessionReloadBlocklists(tr_session* session);
|
||||||
@see tr_sessionInit() */
|
@see tr_sessionInit() */
|
||||||
void tr_sessionClose(tr_session*);
|
void tr_sessionClose(tr_session*);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Return the session's configuration directory.
|
||||||
|
*
|
||||||
|
* This is where transmission stores its torrent files, .resume files,
|
||||||
|
* blocklists, etc. It's set in tr_transmissionInit() and is immutable
|
||||||
|
* during the session.
|
||||||
|
*/
|
||||||
|
char const* tr_sessionGetConfigDir(tr_session const*);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Set the per-session default download folder for new torrents.
|
* @brief Set the per-session default download folder for new torrents.
|
||||||
* @see tr_sessionInit()
|
* @see tr_sessionInit()
|
||||||
|
@ -694,7 +703,7 @@ void tr_torrentSetQueueStartCallback(tr_torrent* torrent, void (*callback)(tr_to
|
||||||
***/
|
***/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Load all the torrents in the session's torrent folder.
|
* Load all the torrents in tr_getTorrentDir().
|
||||||
* This can be used at startup to kickstart all the torrents
|
* This can be used at startup to kickstart all the torrents
|
||||||
* from the previous session.
|
* from the previous session.
|
||||||
*/
|
*/
|
||||||
|
@ -1147,7 +1156,7 @@ char* tr_torrentGetTrackerList(tr_torrent const* tor);
|
||||||
* URL per line and a blank line between tiers.
|
* URL per line and a blank line between tiers.
|
||||||
*
|
*
|
||||||
* This updates both the `torrent' object's tracker list
|
* This updates both the `torrent' object's tracker list
|
||||||
* and the metainfo file in the session config dir's torrent subdirectory.
|
* and the metainfo file in tr_sessionGetConfigDir()'s torrent subdirectory.
|
||||||
*/
|
*/
|
||||||
bool tr_torrentSetTrackerList(tr_torrent* tor, char const* text);
|
bool tr_torrentSetTrackerList(tr_torrent* tor, char const* text);
|
||||||
|
|
||||||
|
|
|
@ -18,8 +18,6 @@
|
||||||
|
|
||||||
#include "test-fixtures.h"
|
#include "test-fixtures.h"
|
||||||
|
|
||||||
using namespace std::literals;
|
|
||||||
|
|
||||||
namespace libtransmission
|
namespace libtransmission
|
||||||
{
|
{
|
||||||
|
|
||||||
|
@ -71,7 +69,7 @@ TEST_F(BlocklistTest, parsing)
|
||||||
EXPECT_EQ(0U, tr_blocklistGetRuleCount(session_));
|
EXPECT_EQ(0U, tr_blocklistGetRuleCount(session_));
|
||||||
|
|
||||||
// init the blocklist
|
// init the blocklist
|
||||||
auto const path = tr_pathbuf{ session_->configDir(), "/blocklists/level1"sv };
|
auto const path = tr_pathbuf{ tr_sessionGetConfigDir(session_), "/blocklists/level1" };
|
||||||
createFileWithContents(path, Contents1);
|
createFileWithContents(path, Contents1);
|
||||||
tr_sessionReloadBlocklists(session_);
|
tr_sessionReloadBlocklists(session_);
|
||||||
EXPECT_TRUE(tr_blocklistExists(session_));
|
EXPECT_TRUE(tr_blocklistExists(session_));
|
||||||
|
@ -107,7 +105,7 @@ TEST_F(BlocklistTest, parsing)
|
||||||
TEST_F(BlocklistTest, updating)
|
TEST_F(BlocklistTest, updating)
|
||||||
{
|
{
|
||||||
// init the session
|
// init the session
|
||||||
auto const path = tr_pathbuf{ session_->configDir(), "/blocklists/level1"sv };
|
auto const path = tr_pathbuf{ tr_sessionGetConfigDir(session_), "/blocklists/level1" };
|
||||||
|
|
||||||
// no blocklist to start with...
|
// no blocklist to start with...
|
||||||
EXPECT_EQ(0U, tr_blocklistGetRuleCount(session_));
|
EXPECT_EQ(0U, tr_blocklistGetRuleCount(session_));
|
||||||
|
|
|
@ -22,7 +22,6 @@
|
||||||
|
|
||||||
#include "error.h"
|
#include "error.h"
|
||||||
#include "file.h"
|
#include "file.h"
|
||||||
#include "session.h"
|
|
||||||
#include "tr-macros.h"
|
#include "tr-macros.h"
|
||||||
#include "tr-strbuf.h"
|
#include "tr-strbuf.h"
|
||||||
|
|
||||||
|
@ -51,7 +50,7 @@ class FileTest : public SessionTest
|
||||||
protected:
|
protected:
|
||||||
auto createTestDir(std::string const& child_name)
|
auto createTestDir(std::string const& child_name)
|
||||||
{
|
{
|
||||||
auto test_dir = tr_pathbuf{ session_->configDir(), '/', child_name };
|
auto test_dir = tr_pathbuf{ tr_sessionGetConfigDir(session_), '/', child_name };
|
||||||
tr_sys_dir_create(test_dir, 0, 0777);
|
tr_sys_dir_create(test_dir, 0, 0777);
|
||||||
return test_dir;
|
return test_dir;
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,7 +15,6 @@
|
||||||
|
|
||||||
#include "cache.h" // tr_cacheWriteBlock()
|
#include "cache.h" // tr_cacheWriteBlock()
|
||||||
#include "file.h" // tr_sys_path_*()
|
#include "file.h" // tr_sys_path_*()
|
||||||
#include "session.h"
|
|
||||||
#include "tr-strbuf.h"
|
#include "tr-strbuf.h"
|
||||||
#include "utils.h"
|
#include "utils.h"
|
||||||
#include "variant.h"
|
#include "variant.h"
|
||||||
|
@ -157,7 +156,7 @@ using MoveTest = SessionTest;
|
||||||
|
|
||||||
TEST_F(MoveTest, setLocation)
|
TEST_F(MoveTest, setLocation)
|
||||||
{
|
{
|
||||||
auto const target_dir = tr_pathbuf{ session_->configDir(), "/target"sv };
|
auto const target_dir = tr_pathbuf{ tr_sessionGetConfigDir(session_), "/target"sv };
|
||||||
tr_sys_dir_create(target_dir.data(), TR_SYS_DIR_CREATE_PARENTS, 0777, nullptr);
|
tr_sys_dir_create(target_dir.data(), TR_SYS_DIR_CREATE_PARENTS, 0777, nullptr);
|
||||||
|
|
||||||
// init a torrent.
|
// init a torrent.
|
||||||
|
|
Loading…
Reference in New Issue