diff --git a/src/test/util_tests.cpp b/src/test/util_tests.cpp index a1ac9ead69..76ffdc598a 100644 --- a/src/test/util_tests.cpp +++ b/src/test/util_tests.cpp @@ -1143,21 +1143,23 @@ BOOST_AUTO_TEST_CASE(util_ReadWriteSettings) { // Test writing setting. TestArgsManager args1; + args1.ForceSetArg("-datadir", m_path_root.string()); args1.LockSettings([&](util::Settings& settings) { settings.rw_settings["name"] = "value"; }); args1.WriteSettingsFile(); // Test reading setting. TestArgsManager args2; + args2.ForceSetArg("-datadir", m_path_root.string()); args2.ReadSettingsFile(); args2.LockSettings([&](util::Settings& settings) { BOOST_CHECK_EQUAL(settings.rw_settings["name"].get_str(), "value"); }); // Test error logging, and remove previously written setting. { ASSERT_DEBUG_LOG("Failed renaming settings file"); - fs::remove(GetDataDir() / "settings.json"); - fs::create_directory(GetDataDir() / "settings.json"); + fs::remove(args1.GetDataDirPath() / "settings.json"); + fs::create_directory(args1.GetDataDirPath() / "settings.json"); args2.WriteSettingsFile(); - fs::remove(GetDataDir() / "settings.json"); + fs::remove(args1.GetDataDirPath() / "settings.json"); } } diff --git a/src/util/system.cpp b/src/util/system.cpp index 702cfdf1e4..0a2ece7b10 100644 --- a/src/util/system.cpp +++ b/src/util/system.cpp @@ -388,6 +388,45 @@ std::optional ArgsManager::GetArgFlags(const std::string& name) co return std::nullopt; } +const fs::path& ArgsManager::GetDataDirPath(bool net_specific) const +{ + LOCK(cs_args); + fs::path& path = net_specific ? m_cached_network_datadir_path : m_cached_datadir_path; + + // Cache the path to avoid calling fs::create_directories on every call of + // this function + if (!path.empty()) return path; + + std::string datadir = GetArg("-datadir", ""); + if (!datadir.empty()) { + path = fs::system_complete(datadir); + if (!fs::is_directory(path)) { + path = ""; + return path; + } + } else { + path = GetDefaultDataDir(); + } + if (net_specific) + path /= BaseParams().DataDir(); + + if (fs::create_directories(path)) { + // This is the first run, create wallets subdirectory too + fs::create_directories(path / "wallets"); + } + + path = StripRedundantLastElementsOfPath(path); + return path; +} + +void ArgsManager::ClearDatadirPathCache() +{ + LOCK(cs_args); + + m_cached_datadir_path = fs::path(); + m_cached_network_datadir_path = fs::path(); +} + std::optional ArgsManager::GetCommand() const { Command ret; @@ -447,7 +486,7 @@ bool ArgsManager::GetSettingsPath(fs::path* filepath, bool temp) const } if (filepath) { std::string settings = GetArg("-settings", BITCOIN_SETTINGS_FILENAME); - *filepath = fsbridge::AbsPathJoin(GetDataDir(/* net_specific= */ true), temp ? settings + ".tmp" : settings); + *filepath = fsbridge::AbsPathJoin(GetDataDirPath(/* net_specific= */ true), temp ? settings + ".tmp" : settings); } return true; } @@ -737,8 +776,6 @@ fs::path GetDefaultDataDir() } static fs::path g_blocks_path_cache_net_specific; -static fs::path pathCached; -static fs::path pathCachedNetSpecific; static RecursiveMutex csPathCached; const fs::path &GetBlocksDir() @@ -769,33 +806,7 @@ const fs::path &GetBlocksDir() const fs::path &GetDataDir(bool fNetSpecific) { - LOCK(csPathCached); - fs::path &path = fNetSpecific ? pathCachedNetSpecific : pathCached; - - // Cache the path to avoid calling fs::create_directories on every call of - // this function - if (!path.empty()) return path; - - std::string datadir = gArgs.GetArg("-datadir", ""); - if (!datadir.empty()) { - path = fs::system_complete(datadir); - if (!fs::is_directory(path)) { - path = ""; - return path; - } - } else { - path = GetDefaultDataDir(); - } - if (fNetSpecific) - path /= BaseParams().DataDir(); - - if (fs::create_directories(path)) { - // This is the first run, create wallets subdirectory too - fs::create_directories(path / "wallets"); - } - - path = StripRedundantLastElementsOfPath(path); - return path; + return gArgs.GetDataDirPath(fNetSpecific); } bool CheckDataDirOption() @@ -806,10 +817,7 @@ bool CheckDataDirOption() void ClearDatadirCache() { - LOCK(csPathCached); - - pathCached = fs::path(); - pathCachedNetSpecific = fs::path(); + gArgs.ClearDatadirPathCache(); g_blocks_path_cache_net_specific = fs::path(); } diff --git a/src/util/system.h b/src/util/system.h index 29657e56e2..a49055b891 100644 --- a/src/util/system.h +++ b/src/util/system.h @@ -200,6 +200,8 @@ protected: std::map> m_available_args GUARDED_BY(cs_args); bool m_accept_any_command GUARDED_BY(cs_args){true}; std::list m_config_sections GUARDED_BY(cs_args); + mutable fs::path m_cached_datadir_path GUARDED_BY(cs_args); + mutable fs::path m_cached_network_datadir_path GUARDED_BY(cs_args); [[nodiscard]] bool ReadConfigStream(std::istream& stream, const std::string& filepath, std::string& error, bool ignore_invalid_keys = false); @@ -263,6 +265,20 @@ public: */ std::optional GetCommand() const; + /** + * Get data directory path + * + * @param net_specific Append network identifier to the returned path + * @return Absolute path on success, otherwise an empty path when a non-directory path would be returned + * @post Returned directory path is created unless it is empty + */ + const fs::path& GetDataDirPath(bool net_specific = true) const; + + /** + * For testing + */ + void ClearDatadirPathCache(); + /** * Return a vector of strings of the given argument *