diff --git a/libtransmission/platform.cc b/libtransmission/platform.cc index d0ae55d32..8fe73cbf4 100644 --- a/libtransmission/platform.cc +++ b/libtransmission/platform.cc @@ -118,33 +118,6 @@ static std::string xdgConfigHome() return fmt::format("{:s}/.config"sv, getHomeDir()); } -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 = fmt::format("{:s}/{:s}"sv, config_dir, ResumeSubdir); - session->torrent_dir = fmt::format("{:s}/{:s}"sv, 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* tr_getDefaultConfigDir(char const* appname) { if (auto* dir = tr_env_get_string("TRANSMISSION_HOME", nullptr); dir != nullptr) @@ -265,7 +238,7 @@ std::string tr_getWebClientDir([[maybe_unused]] tr_session const* session) #ifdef BUILD_MAC_CLIENT // look in the Application Support folder - if (auto path = tr_pathbuf{ session->config_dir, "/public_html"sv }; isWebClientDir(path)) + if (auto path = tr_pathbuf{ session->configDir(), "/public_html"sv }; isWebClientDir(path)) { return std::string{ path }; } diff --git a/libtransmission/platform.h b/libtransmission/platform.h index e3115207f..0e74b75b0 100644 --- a/libtransmission/platform.h +++ b/libtransmission/platform.h @@ -10,32 +10,11 @@ #endif #include -#include struct tr_session; -/** - * @addtogroup tr_session 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*); /** @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 03a78e87a..c4e531e69 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->resume_dir, + tor->session->resumeDir(), tor->name(), tor->infoHashString(), ".resume"sv); diff --git a/libtransmission/rpcimpl.cc b/libtransmission/rpcimpl.cc index 85d0cdccc..55121e842 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->config_dir, "/blocklist.tmp"sv }; + auto const filename = tr_pathbuf{ session->configDir(), "/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, tr_sessionGetConfigDir(s)); + tr_variantDictAddStr(d, key, s->configDir()); break; case TR_KEY_default_trackers: diff --git a/libtransmission/session.cc b/libtransmission/session.cc index 46d3c57cf..e15a95a7a 100644 --- a/libtransmission/session.cc +++ b/libtransmission/session.cc @@ -46,7 +46,6 @@ #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" @@ -128,7 +127,7 @@ tr_peer_id_t tr_peerIdInit() std::optional tr_session::WebMediator::cookieFile() const { - auto const path = tr_pathbuf{ session_->config_dir, "/cookies.txt" }; + auto const path = tr_pathbuf{ session_->configDir(), "/cookies.txt"sv }; if (!tr_sys_path_exists(path)) { @@ -740,7 +739,7 @@ static void tr_sessionInitImpl(init_data* data) tr_logSetQueueEnabled(data->messageQueuingEnabled); - tr_setConfigDir(session, data->config_dir); + session->initConfigDir(data->config_dir); session->peerMgr = tr_peerMgrNew(session); @@ -750,7 +749,7 @@ static void tr_sessionInitImpl(init_data* data) *** Blocklist **/ - tr_sys_dir_create(tr_pathbuf{ session->config_dir, "/blocklists"sv }, TR_SYS_DIR_CREATE_PARENTS, 0777); + tr_sys_dir_create(tr_pathbuf{ session->configDir(), "/blocklists"sv }, TR_SYS_DIR_CREATE_PARENTS, 0777); loadBlocklists(session); TR_ASSERT(tr_isSession(session)); @@ -1205,6 +1204,13 @@ char const* tr_sessionGetDownloadDir(tr_session const* session) return session->downloadDir().c_str(); } +char const* tr_sessionGetConfigDir(tr_session const* session) +{ + TR_ASSERT(tr_isSession(session)); + + return session->configDir().c_str(); +} + /*** **** ***/ @@ -2050,16 +2056,14 @@ static void sessionLoadTorrents(struct sessionLoadTorrentsData* const data) TR_ASSERT(tr_isSession(data->session)); tr_sys_path_info info; - 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) : + 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()) : 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) { @@ -2068,7 +2072,7 @@ static void sessionLoadTorrents(struct sessionLoadTorrentsData* const data) continue; } - auto const path = tr_pathbuf{ dirname_sv, "/"sv, name }; + auto const path = tr_pathbuf{ dirname, '/', name }; // is a magnet link? if (!tr_ctorSetMetainfoFromFile(data->ctor, path.sv(), nullptr)) @@ -2366,7 +2370,7 @@ static void loadBlocklists(tr_session* session) auto const isEnabled = session->useBlocklist(); /* walk the blocklist directory... */ - auto const dirname = tr_pathbuf{ session->config_dir, "/blocklists"sv }; + auto const dirname = tr_pathbuf{ session->configDir(), "/blocklists"sv }; auto const odir = tr_sys_dir_open(dirname); if (odir == TR_BAD_SYS_DIR) @@ -2506,7 +2510,7 @@ size_t tr_blocklistSetContent(tr_session* session, char const* contentFilename) BlocklistFile* b = nullptr; if (it == std::end(src)) { - auto path = tr_pathbuf{ session->config_dir, "/blocklists/"sv, name }; + auto path = tr_pathbuf{ session->configDir(), "/blocklists/"sv, name }; src.push_back(std::make_unique(path, session->useBlocklist())); b = std::rbegin(src)->get(); } @@ -2886,7 +2890,7 @@ int tr_sessionCountQueueFreeSlots(tr_session* session, tr_direction dir) static void bandwidthGroupRead(tr_session* session, std::string_view config_dir) { - auto const filename = tr_pathbuf{ config_dir, "/"sv, BandwidthGroupsFilename }; + auto const filename = tr_pathbuf{ config_dir, '/', BandwidthGroupsFilename }; auto groups_dict = tr_variant{}; if (!tr_sys_path_exists(filename) || !tr_variantFromFile(&groups_dict, TR_VARIANT_PARSE_JSON, filename, nullptr) || !tr_variantIsDict(&groups_dict)) @@ -2949,7 +2953,7 @@ static int bandwidthGroupWrite(tr_session const* session, std::string_view confi tr_variantDictAddBool(dict, TR_KEY_honorsSessionLimits, group->areParentLimitsHonored(TR_UP)); } - auto const filename = tr_pathbuf{ config_dir, "/"sv, BandwidthGroupsFilename }; + auto const filename = tr_pathbuf{ config_dir, '/', BandwidthGroupsFilename }; auto const ret = tr_variantToFile(&groups_dict, TR_VARIANT_FMT_JSON, filename); tr_variantFree(&groups_dict); return ret; @@ -2995,3 +2999,21 @@ void tr_sessionSetCompletenessCallback(tr_session* session, tr_torrent_completen { session->setTorrentCompletenessCallback(cb, user_data); } + +/// + +void tr_session::initConfigDir(std::string_view config_dir) +{ + TR_ASSERT(std::empty(config_dir_)); + config_dir_ = config_dir; + +#if defined(__APPLE__) || defined(_WIN32) + resume_dir_ = fmt::format("{:s}/Resume"sv, config_dir); + torrent_dir_ = fmt::format("{:s}/Torrents"sv, config_dir); +#else + resume_dir_ = fmt::format("{:s}/resume"sv, config_dir); + torrent_dir_ = fmt::format("{:s}/torrents"sv, config_dir); +#endif + 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 5884d4399..913d5d0a6 100644 --- a/libtransmission/session.h +++ b/libtransmission/session.h @@ -130,7 +130,24 @@ public: return is_closing_; } - // download dir + // paths + + void initConfigDir(std::string_view config_dir); + + [[nodiscard]] constexpr auto const& configDir() const noexcept + { + return config_dir_; + } + + [[nodiscard]] constexpr auto const& torrentDir() const noexcept + { + return torrent_dir_; + } + + [[nodiscard]] constexpr auto const& resumeDir() const noexcept + { + return resume_dir_; + } [[nodiscard]] constexpr auto const& downloadDir() const noexcept { @@ -473,10 +490,6 @@ public: 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; @@ -547,11 +560,17 @@ private: tr_torrents torrents_; std::array scripts_; - std::string blocklist_url_; + + std::string config_dir_; std::string download_dir_; - std::string default_trackers_str_; std::string incomplete_dir_; + std::string resume_dir_; + std::string torrent_dir_; + + std::string blocklist_url_; + std::string default_trackers_str_; std::string peer_congestion_algorithm_; + std::optional external_ip_; queue_start_callback_t queue_start_callback_ = nullptr; diff --git a/libtransmission/stats.cc b/libtransmission/stats.cc index 5125d8559..99433f41b 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->config_dir, "/stats.json"sv }; + auto filename = tr_pathbuf{ session->configDir(), "/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->config_dir, "/stats.benc"); + filename.assign(session->configDir(), "/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->config_dir, "/stats.json"sv }; + auto const filename = tr_pathbuf{ session->configDir(), "/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 dac3e662b..042c15c61 100644 --- a/libtransmission/torrent.cc +++ b/libtransmission/torrent.cc @@ -753,7 +753,7 @@ static void torrentInit(tr_torrent* tor, tr_ctor const* ctor) if (resume_file_was_migrated) { - tr_torrent_metainfo::migrateFile(session->torrent_dir, tor->name(), tor->infoHashString(), ".torrent"sv); + tr_torrent_metainfo::migrateFile(session->torrentDir(), tor->name(), tor->infoHashString(), ".torrent"sv); } } @@ -1611,9 +1611,9 @@ static void closeTorrent(tr_torrent* const tor) if (tor->isDeleting) { - 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); + 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); } tor->isRunning = false; diff --git a/libtransmission/torrent.h b/libtransmission/torrent.h index c96881f1d..b00ef0f7f 100644 --- a/libtransmission/torrent.h +++ b/libtransmission/torrent.h @@ -450,17 +450,17 @@ public: [[nodiscard]] auto torrentFile() const { - return metainfo_.torrentFile(this->session->torrent_dir); + return metainfo_.torrentFile(session->torrentDir()); } [[nodiscard]] auto magnetFile() const { - return metainfo_.magnetFile(this->session->torrent_dir); + return metainfo_.magnetFile(session->torrentDir()); } [[nodiscard]] auto resumeFile() const { - return metainfo_.resumeFile(this->session->resume_dir); + return metainfo_.resumeFile(session->resumeDir()); } [[nodiscard]] auto magnet() const diff --git a/libtransmission/tr-dht.cc b/libtransmission/tr-dht.cc index 3382157a1..c228190bb 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->config_dir, "/dht.bootstrap"sv } }; + auto in = std::ifstream{ tr_pathbuf{ session->configDir(), "/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->config_dir, "/dht.dat"sv }; + auto const dat_file = tr_pathbuf{ ss->configDir(), "/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->config_dir, "/dht.dat" }; + auto const dat_file = tr_pathbuf{ ss->configDir(), "/dht.dat"sv }; tr_variantToFile(&benc, TR_VARIANT_FMT_BENC, dat_file.sv()); tr_variantFree(&benc); } diff --git a/libtransmission/transmission.h b/libtransmission/transmission.h index 4808a6c98..aa2de3653 100644 --- a/libtransmission/transmission.h +++ b/libtransmission/transmission.h @@ -704,7 +704,7 @@ void tr_sessionSetQueueStartCallback(tr_session*, void (*callback)(tr_session*, ***/ /** - * Load all the torrents in tr_getTorrentDir(). + * Load all the torrents in the session's torrent folder. * This can be used at startup to kickstart all the torrents * from the previous session. */ diff --git a/tests/libtransmission/blocklist-test.cc b/tests/libtransmission/blocklist-test.cc index 2065736d1..980c75624 100644 --- a/tests/libtransmission/blocklist-test.cc +++ b/tests/libtransmission/blocklist-test.cc @@ -69,7 +69,7 @@ TEST_F(BlocklistTest, parsing) EXPECT_EQ(0U, tr_blocklistGetRuleCount(session_)); // init the blocklist - auto const path = tr_pathbuf{ tr_sessionGetConfigDir(session_), "/blocklists/level1" }; + auto const path = tr_pathbuf{ session_->configDir(), "/blocklists/level1"sv }; createFileWithContents(path, Contents1); tr_sessionReloadBlocklists(session_); EXPECT_TRUE(tr_blocklistExists(session_)); @@ -105,7 +105,7 @@ TEST_F(BlocklistTest, parsing) TEST_F(BlocklistTest, updating) { // init the session - auto const path = tr_pathbuf{ tr_sessionGetConfigDir(session_), "/blocklists/level1" }; + auto const path = tr_pathbuf{ session_->configDir(), "/blocklists/level1"sv }; // 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 37f8ebd59..c9755c517 100644 --- a/tests/libtransmission/file-test.cc +++ b/tests/libtransmission/file-test.cc @@ -50,7 +50,7 @@ class FileTest : public SessionTest protected: auto createTestDir(std::string const& child_name) { - auto test_dir = tr_pathbuf{ tr_sessionGetConfigDir(session_), '/', child_name }; + auto test_dir = tr_pathbuf{ session_->configDir(), '/', 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 14fa412c8..def274125 100644 --- a/tests/libtransmission/move-test.cc +++ b/tests/libtransmission/move-test.cc @@ -156,7 +156,7 @@ using MoveTest = SessionTest; TEST_F(MoveTest, setLocation) { - auto const target_dir = tr_pathbuf{ tr_sessionGetConfigDir(session_), "/target"sv }; + auto const target_dir = tr_pathbuf{ session_->configDir(), "/target"sv }; tr_sys_dir_create(target_dir.data(), TR_SYS_DIR_CREATE_PARENTS, 0777, nullptr); // init a torrent. diff --git a/tests/libtransmission/open-files-test.cc b/tests/libtransmission/open-files-test.cc index acee35cab..5fa2471b4 100644 --- a/tests/libtransmission/open-files-test.cc +++ b/tests/libtransmission/open-files-test.cc @@ -170,7 +170,7 @@ TEST_F(OpenFilesTest, closesLeastRecentlyUsedFile) // supplant older ones. for (int i = 0; i < LargerThanCacheLimit; ++i) { - auto filename = tr_pathbuf{ sandboxDir(), fmt::format("/file-{:d}.txt", i) }; + auto filename = tr_pathbuf{ sandboxDir(), fmt::format("/file-{:d}.txt"sv, i) }; EXPECT_TRUE(session_->openFiles().get(TorId, i, true, filename, TR_PREALLOCATE_FULL, std::size(Contents))); } @@ -182,7 +182,7 @@ TEST_F(OpenFilesTest, closesLeastRecentlyUsedFile) auto sorted = std::array{}; for (int i = 0; i < LargerThanCacheLimit; ++i) { - auto filename = tr_pathbuf{ sandboxDir(), fmt::format("/file-{:d}.txt", i) }; + auto filename = tr_pathbuf{ sandboxDir(), fmt::format("/file-{:d}.txt"sv, i) }; results[i] = !!session_->openFiles().get(TorId, i, false); } sorted = results; diff --git a/tests/libtransmission/remove-test.cc b/tests/libtransmission/remove-test.cc index 396e114b7..59ae0e3ef 100644 --- a/tests/libtransmission/remove-test.cc +++ b/tests/libtransmission/remove-test.cc @@ -246,7 +246,7 @@ TEST_F(RemoveTest, RemovesLeftoverJunk) EXPECT_EQ(expected_tree, getSubtreeContents(parent)); // add a junk file *inside of* the torrent's top directory. - auto const junk_file = tr_pathbuf{ parent, "/alice_in_wonderland_librivox/", JunkBasename }; + auto const junk_file = tr_pathbuf{ parent, "/alice_in_wonderland_librivox/"sv, JunkBasename }; createFileWithContents(junk_file, std::data(Content), std::size(Content)); expected_tree.emplace(junk_file); EXPECT_EQ(expected_tree, getSubtreeContents(parent)); @@ -295,7 +295,7 @@ TEST_F(RemoveTest, LeavesNonJunkAlone) EXPECT_EQ(expected_tree, getSubtreeContents(parent)); // add a non-junk file. - auto const nonjunk_file = tr_pathbuf{ parent, "/alice_in_wonderland_librivox/", NonJunkBasename }; + auto const nonjunk_file = tr_pathbuf{ parent, "/alice_in_wonderland_librivox/"sv, NonJunkBasename }; createFileWithContents(nonjunk_file, std::data(Content), std::size(Content)); expected_tree.emplace(nonjunk_file); EXPECT_EQ(expected_tree, getSubtreeContents(parent));