diff --git a/daemon/daemon.cc b/daemon/daemon.cc index ff989e066..8d7b39bd1 100644 --- a/daemon/daemon.cc +++ b/daemon/daemon.cc @@ -672,10 +672,8 @@ struct daemon_data bool paused; }; -static void daemon_reconfigure(void* vdata) +static void daemon_reconfigure(void* /*arg*/) { - auto const* const ddata = static_cast(vdata); - if (mySession == nullptr) { tr_logAddInfo(_("Deferring reload until session is fully started.")); @@ -684,6 +682,7 @@ static void daemon_reconfigure(void* vdata) else { tr_variant settings; + char const* configDir; /* reopen the logfile to allow for log rotation */ if (logfileName != nullptr) @@ -691,10 +690,11 @@ static void daemon_reconfigure(void* vdata) 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_variantDictAddBool(&settings, TR_KEY_rpc_enabled, true); - tr_sessionLoadSettings(&settings, ddata->configDir, MyName); + tr_sessionLoadSettings(&settings, configDir, MyName); tr_sessionSet(mySession, &settings); tr_variantFree(&settings); tr_sessionReloadBlocklists(mySession); diff --git a/gtk/Application.cc b/gtk/Application.cc index 3efa104ef..a1b3499be 100644 --- a/gtk/Application.cc +++ b/gtk/Application.cc @@ -156,7 +156,7 @@ private: private: Application& app_; - std::string const config_dir_; + std::string config_dir_; bool start_paused_ = false; bool is_iconified_ = 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_int_set(TR_KEY_peer_port, tr_sessionGetPeerPort(session)); - core_ = Session::create(session, config_dir_); + core_ = Session::create(session); /* init the ui manager */ ui_builder_ = Gtk::Builder::create_from_resource(gtr_get_full_resource_path("transmission-ui.xml"s)); diff --git a/gtk/Session.cc b/gtk/Session.cc index d10fe0a10..87bfc0f60 100644 --- a/gtk/Session.cc +++ b/gtk/Session.cc @@ -84,7 +84,7 @@ private: class Session::Impl { public: - Impl(Session& core, tr_session* session, std::string_view config_dir); + Impl(Session& core, tr_session* session); tr_session* close(); @@ -153,7 +153,6 @@ private: private: Session& core_; - std::string const config_dir_; Glib::RefPtr monitor_; sigc::connection monitor_tag_; @@ -800,23 +799,22 @@ void Session::Impl::on_pref_changed(tr_quark const key) *** **/ -Glib::RefPtr Session::create(tr_session* session, std::string_view config_dir) +Glib::RefPtr 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)) - , impl_(std::make_unique(*this, session, config_dir)) + , impl_(std::make_unique(*this, session)) { } Session::~Session() = default; -Session::Impl::Impl(Session& core, tr_session* session, std::string_view config_dir) - : core_{ core } - , config_dir_{ config_dir } - , session_{ session } +Session::Impl::Impl(Session& core, tr_session* session) + : core_(core) + , session_(session) { raw_model_ = Gtk::ListStore::create(torrent_cols); 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) { + char const* config = tr_sessionGetConfigDir(session_); char const* source = tr_ctorGetSourceFile(ctor); if (source != nullptr) { /* #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) { diff --git a/gtk/Session.h b/gtk/Session.h index a6cb70891..96ecfe1c5 100644 --- a/gtk/Session.h +++ b/gtk/Session.h @@ -32,7 +32,7 @@ public: TR_DISABLE_COPY_MOVE(Session) - static Glib::RefPtr create(tr_session* session, std::string_view config_dir); + static Glib::RefPtr create(tr_session* session); tr_session* close(); @@ -130,7 +130,7 @@ public: sigc::signal& signal_port_tested(); protected: - explicit Session(tr_session* session, std::string_view config_dir); + explicit Session(tr_session* session); private: class Impl; diff --git a/libtransmission/platform.cc b/libtransmission/platform.cc index 48a412a83..0aed8dc02 100644 --- a/libtransmission/platform.cc +++ b/libtransmission/platform.cc @@ -4,11 +4,11 @@ // License text can be found in the licenses/ folder. #include -#include -#include +#include #include #include #include +#include #include #ifdef __HAIKU__ @@ -124,6 +124,33 @@ static std::string xdgConfigHome() 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) { static char const* s = nullptr; @@ -235,13 +262,7 @@ char const* tr_getDefaultDownloadDir() **** ***/ -namespace web_client_dir_helpers -{ - -namespace -{ - -bool isWebClientDir(std::string_view path) +static bool isWebClientDir(std::string_view path) { auto const filename = tr_pathbuf{ path, '/', "index.html"sv }; bool const found = tr_sys_path_exists(filename); @@ -249,147 +270,144 @@ bool isWebClientDir(std::string_view path) 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 -static std::string getPlatformWebClientDir(tr_session const* session) -{ // 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 - auto app_url = CFBundleCopyBundleURL(CFBundleGetMainBundle()); - auto app_ref = CFURLCopyFileSystemPath(app_url, kCFURLPOSIXPathStyle); - auto const buflen = CFStringGetMaximumSizeOfFileSystemRepresentation(app_ref); - auto buf = std::vector(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)) + if (s == nullptr) { - 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(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) -static std::string getPlatformWebClientDir([[maybe_unused]] tr_session const* session) -{ - /* Generally, Web interface should be stored in a Web subdir of - * calling executable dir. */ - - static auto constexpr KnownFolderIds = std::array{ - &FOLDERID_LocalAppData, - &FOLDERID_RoamingAppData, - &FOLDERID_ProgramData, - }; - - for (auto& folder_id : KnownFolderIds) + if (s == nullptr) { - 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); - return std::string{ path }; } - - tr_free(dir); } - /* 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 (s == nullptr) /* check calling module place */ { - 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); - return std::string{ path }; + if (auto const path = tr_pathbuf{ dir, "/Web"sv }; isWebClientDir(path)) + { + s = tr_strvDup(path); + } } + + tr_free(module_path); } - tr_free(module_path); +#else // everyone else, follow the XDG spec - return {}; -} - -#else - -static std::string getPlatformWebClientDir([[maybe_unused]] tr_session const* session) -{ - auto candidates = std::list{}; - - // XDG_DATA_HOME should be the first candidate - if (char* tmp = tr_env_get_string("XDG_DATA_HOME", nullptr); !tr_str_is_empty(tmp)) + if (s == nullptr) { - candidates.emplace_back(tmp); + auto candidates = std::list{}; + + /* 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); - } - else - { - candidates.emplace_back(tr_strvPath(getHomeDir(), ".local"sv, "share"sv)); - } - // 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)) + /* XDG_DATA_DIRS are the backup directories */ { - 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 -} // namespace web_client_dir_helpers - -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); + return s; } std::string tr_getSessionIdDir() diff --git a/libtransmission/platform.h b/libtransmission/platform.h index 9660af5d7..2170e52fa 100644 --- a/libtransmission/platform.h +++ b/libtransmission/platform.h @@ -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 */ -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 */ std::string tr_getSessionIdDir(); diff --git a/libtransmission/resume.cc b/libtransmission/resume.cc index c4e531e69..03a78e87a 100644 --- a/libtransmission/resume.cc +++ b/libtransmission/resume.cc @@ -655,7 +655,7 @@ static auto loadFromFile(tr_torrent* tor, tr_resume::fields_t fieldsToLoad, bool auto const wasDirty = tor->isDirty; auto const migrated = tr_torrent_metainfo::migrateFile( - tor->session->resumeDir(), + tor->session->resume_dir, tor->name(), tor->infoHashString(), ".resume"sv); diff --git a/libtransmission/rpc-server.cc b/libtransmission/rpc-server.cc index 3a3ba1269..9eab37c49 100644 --- a/libtransmission/rpc-server.cc +++ b/libtransmission/rpc-server.cc @@ -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) { - if (std::empty(server->web_client_dir_)) + char const* webClientDir = tr_getWebClientDir(server->session); + + if (tr_str_is_empty(webClientDir)) { send_simple_response( req, @@ -285,7 +287,7 @@ static void handle_web_client(struct evhttp_request* req, tr_rpc_server* server) } 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()); } @@ -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) : compressor{ libdeflate_alloc_compressor(DeflateLevel), libdeflate_free_compressor } - , web_client_dir_{ tr_getWebClientDir(session_in) } , bindAddress(std::make_unique()) , 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))); } } diff --git a/libtransmission/rpc-server.h b/libtransmission/rpc-server.h index d0afb920d..93ad2afc2 100644 --- a/libtransmission/rpc-server.h +++ b/libtransmission/rpc-server.h @@ -122,7 +122,6 @@ public: std::vector hostWhitelist; std::vector whitelist_; - std::string const web_client_dir_; std::string salted_password_; std::string username_; std::string whitelist_str_; diff --git a/libtransmission/rpcimpl.cc b/libtransmission/rpcimpl.cc index 55121e842..85d0cdccc 100644 --- a/libtransmission/rpcimpl.cc +++ b/libtransmission/rpcimpl.cc @@ -1444,7 +1444,7 @@ 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_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)) { tr_idle_function_done( @@ -2171,7 +2171,7 @@ static void addSessionField(tr_session const* s, tr_variant* d, tr_quark key) break; case TR_KEY_config_dir: - tr_variantDictAddStr(d, key, s->configDir()); + tr_variantDictAddStr(d, key, tr_sessionGetConfigDir(s)); break; case TR_KEY_default_trackers: diff --git a/libtransmission/session.cc b/libtransmission/session.cc index eb86bc84f..7b6f903ca 100644 --- a/libtransmission/session.cc +++ b/libtransmission/session.cc @@ -46,6 +46,7 @@ #include "peer-io.h" #include "peer-mgr.h" #include "platform-quota.h" /* tr_device_info_free() */ +#include "platform.h" /* tr_getTorrentDir() */ #include "port-forwarding.h" #include "rpc-server.h" #include "session-id.h" @@ -127,7 +128,7 @@ tr_peer_id_t tr_peerIdInit() std::optional 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)) { @@ -725,7 +726,7 @@ static void tr_sessionInitImpl(init_data* data) tr_logSetQueueEnabled(data->messageQueuingEnabled); - session->initConfigDir(data->config_dir); + tr_setConfigDir(session, data->config_dir); session->peerMgr = tr_peerMgrNew(session); @@ -735,7 +736,7 @@ static void tr_sessionInitImpl(init_data* data) *** 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); TR_ASSERT(tr_isSession(session)); @@ -2035,14 +2036,16 @@ static void sessionLoadTorrents(struct sessionLoadTorrentsData* const data) TR_ASSERT(tr_isSession(data->session)); tr_sys_path_info info; - auto const& dirname = data->session->torrentDir(); - 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_open(dirname.c_str()) : + char const* const dirname = tr_getTorrentDir(data->session); + 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) : TR_BAD_SYS_DIR; auto torrents = std::list{}; if (odir != TR_BAD_SYS_DIR) { + auto const dirname_sv = std::string_view{ dirname }; + char const* name = nullptr; while ((name = tr_sys_dir_read_name(odir)) != nullptr) { @@ -2051,7 +2054,7 @@ static void sessionLoadTorrents(struct sessionLoadTorrentsData* const data) continue; } - auto const path = tr_pathbuf{ dirname, '/', name }; + auto const path = tr_pathbuf{ dirname_sv, "/"sv, name }; // is a magnet link? if (!tr_ctorSetMetainfoFromFile(data->ctor, path.sv(), nullptr)) @@ -2349,7 +2352,7 @@ static void loadBlocklists(tr_session* session) auto const isEnabled = session->useBlocklist(); /* 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); if (odir == TR_BAD_SYS_DIR) @@ -2489,7 +2492,7 @@ size_t tr_blocklistSetContent(tr_session* session, char const* contentFilename) BlocklistFile* b = nullptr; 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(path, session->useBlocklist())); 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); 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); -} diff --git a/libtransmission/session.h b/libtransmission/session.h index 34970660b..75ffe0881 100644 --- a/libtransmission/session.h +++ b/libtransmission/session.h @@ -396,26 +396,13 @@ public: 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 randomPortHigh; + std::string config_dir; + std::string resume_dir; + std::string torrent_dir; + std::vector> blocklists; struct tr_peerMgr* peerMgr = nullptr; struct tr_shared* shared = nullptr; @@ -486,9 +473,6 @@ private: tr_torrents torrents_; std::array scripts_; - std::string config_dir_; - std::string resume_dir_; - std::string torrent_dir_; std::string blocklist_url_; std::string download_dir_; std::string default_trackers_str_; diff --git a/libtransmission/stats.cc b/libtransmission/stats.cc index 99ae2750b..5125d8559 100644 --- a/libtransmission/stats.cc +++ b/libtransmission/stats.cc @@ -34,14 +34,14 @@ static void loadCumulativeStats(tr_session const* session, tr_session_stats* set { 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); if (!loaded) { // maybe the user just upgraded from an old version of Transmission // 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); } @@ -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) { - 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{}; tr_variantInitDict(&top, 5); tr_variantDictAddInt(&top, TR_KEY_downloaded_bytes, s->downloadedBytes); diff --git a/libtransmission/torrent.cc b/libtransmission/torrent.cc index 53183da6a..9913c2836 100644 --- a/libtransmission/torrent.cc +++ b/libtransmission/torrent.cc @@ -766,7 +766,7 @@ static void torrentInit(tr_torrent* tor, tr_ctor const* ctor) 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) { - tr_torrent_metainfo::removeFile(tor->session->torrentDir(), 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->resumeDir(), tor->name(), tor->infoHashString(), ".resume"sv); + tr_torrent_metainfo::removeFile(tor->session->torrent_dir, tor->name(), tor->infoHashString(), ".torrent"sv); + tr_torrent_metainfo::removeFile(tor->session->torrent_dir, tor->name(), tor->infoHashString(), ".magnet"sv); + tr_torrent_metainfo::removeFile(tor->session->resume_dir, tor->name(), tor->infoHashString(), ".resume"sv); } tor->isRunning = false; diff --git a/libtransmission/torrent.h b/libtransmission/torrent.h index 6309a95e6..fdb9644d8 100644 --- a/libtransmission/torrent.h +++ b/libtransmission/torrent.h @@ -450,17 +450,17 @@ public: [[nodiscard]] auto torrentFile() const { - return metainfo_.torrentFile(this->session->torrentDir()); + return metainfo_.torrentFile(this->session->torrent_dir); } [[nodiscard]] auto magnetFile() const { - return metainfo_.magnetFile(this->session->torrentDir()); + return metainfo_.magnetFile(this->session->torrent_dir); } [[nodiscard]] auto resumeFile() const { - return metainfo_.resumeFile(this->session->torrentDir()); + return metainfo_.resumeFile(this->session->resume_dir); } [[nodiscard]] auto magnet() const diff --git a/libtransmission/tr-dht.cc b/libtransmission/tr-dht.cc index c228190bb..3382157a1 100644 --- a/libtransmission/tr-dht.cc +++ b/libtransmission/tr-dht.cc @@ -146,7 +146,7 @@ static void dht_boostrap_from_file(tr_session* session) } // 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()) { return; @@ -292,7 +292,7 @@ int tr_dhtInit(tr_session* ss) } 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()); bool have_id = false; @@ -443,7 +443,7 @@ void tr_dhtUninit(tr_session* ss) 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_variantFree(&benc); } diff --git a/libtransmission/transmission.h b/libtransmission/transmission.h index de7c301e2..b4d273f4e 100644 --- a/libtransmission/transmission.h +++ b/libtransmission/transmission.h @@ -231,6 +231,15 @@ void tr_sessionReloadBlocklists(tr_session* session); @see tr_sessionInit() */ 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. * @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 * from the previous session. */ @@ -1147,7 +1156,7 @@ char* tr_torrentGetTrackerList(tr_torrent const* tor); * URL per line and a blank line between tiers. * * 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); diff --git a/tests/libtransmission/blocklist-test.cc b/tests/libtransmission/blocklist-test.cc index c46c6325c..2065736d1 100644 --- a/tests/libtransmission/blocklist-test.cc +++ b/tests/libtransmission/blocklist-test.cc @@ -18,8 +18,6 @@ #include "test-fixtures.h" -using namespace std::literals; - namespace libtransmission { @@ -71,7 +69,7 @@ TEST_F(BlocklistTest, parsing) EXPECT_EQ(0U, tr_blocklistGetRuleCount(session_)); // 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); tr_sessionReloadBlocklists(session_); EXPECT_TRUE(tr_blocklistExists(session_)); @@ -107,7 +105,7 @@ TEST_F(BlocklistTest, parsing) TEST_F(BlocklistTest, updating) { // 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... EXPECT_EQ(0U, tr_blocklistGetRuleCount(session_)); diff --git a/tests/libtransmission/file-test.cc b/tests/libtransmission/file-test.cc index b9c936887..37f8ebd59 100644 --- a/tests/libtransmission/file-test.cc +++ b/tests/libtransmission/file-test.cc @@ -22,7 +22,6 @@ #include "error.h" #include "file.h" -#include "session.h" #include "tr-macros.h" #include "tr-strbuf.h" @@ -51,7 +50,7 @@ class FileTest : public SessionTest protected: 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); return test_dir; } diff --git a/tests/libtransmission/move-test.cc b/tests/libtransmission/move-test.cc index 32707d4d8..380c0d294 100644 --- a/tests/libtransmission/move-test.cc +++ b/tests/libtransmission/move-test.cc @@ -15,7 +15,6 @@ #include "cache.h" // tr_cacheWriteBlock() #include "file.h" // tr_sys_path_*() -#include "session.h" #include "tr-strbuf.h" #include "utils.h" #include "variant.h" @@ -157,7 +156,7 @@ using MoveTest = SessionTest; 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); // init a torrent.