diff options
Diffstat (limited to 'src/util')
-rw-r--r-- | src/util/asmap.cpp | 1 | ||||
-rw-r--r-- | src/util/overflow.h | 1 | ||||
-rw-r--r-- | src/util/settings.cpp | 12 | ||||
-rw-r--r-- | src/util/strencodings.cpp | 3 | ||||
-rw-r--r-- | src/util/syscall_sandbox.cpp | 8 | ||||
-rw-r--r-- | src/util/system.cpp | 91 | ||||
-rw-r--r-- | src/util/system.h | 16 |
7 files changed, 80 insertions, 52 deletions
diff --git a/src/util/asmap.cpp b/src/util/asmap.cpp index ffa2755970..ceb8379c1c 100644 --- a/src/util/asmap.cpp +++ b/src/util/asmap.cpp @@ -6,6 +6,7 @@ #include <clientversion.h> #include <crypto/common.h> +#include <fs.h> #include <logging.h> #include <streams.h> diff --git a/src/util/overflow.h b/src/util/overflow.h index 5982af8d04..c70a8b663e 100644 --- a/src/util/overflow.h +++ b/src/util/overflow.h @@ -6,6 +6,7 @@ #define BITCOIN_UTIL_OVERFLOW_H #include <limits> +#include <optional> #include <type_traits> template <class T> diff --git a/src/util/settings.cpp b/src/util/settings.cpp index 442a55ffb0..26439b010b 100644 --- a/src/util/settings.cpp +++ b/src/util/settings.cpp @@ -2,11 +2,17 @@ // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. +#include <fs.h> #include <util/settings.h> #include <tinyformat.h> #include <univalue.h> +#include <fstream> +#include <map> +#include <string> +#include <vector> + namespace util { namespace { @@ -63,7 +69,7 @@ bool ReadSettings(const fs::path& path, std::map<std::string, SettingsValue>& va // Ok for file to not exist if (!fs::exists(path)) return true; - fsbridge::ifstream file; + std::ifstream file; file.open(path); if (!file.is_open()) { errors.emplace_back(strprintf("%s. Please check permissions.", fs::PathToString(path))); @@ -106,13 +112,13 @@ bool WriteSettings(const fs::path& path, for (const auto& value : values) { out.__pushKV(value.first, value.second); } - fsbridge::ofstream file; + std::ofstream file; file.open(path); if (file.fail()) { errors.emplace_back(strprintf("Error: Unable to open settings file %s for writing", fs::PathToString(path))); return false; } - file << out.write(/* prettyIndent= */ 1, /* indentLevel= */ 4) << std::endl; + file << out.write(/* prettyIndent= */ 4, /* indentLevel= */ 1) << std::endl; file.close(); return true; } diff --git a/src/util/strencodings.cpp b/src/util/strencodings.cpp index a386f2b7b3..940fa90da2 100644 --- a/src/util/strencodings.cpp +++ b/src/util/strencodings.cpp @@ -113,7 +113,7 @@ void SplitHostPort(std::string in, uint16_t& portOut, std::string& hostOut) // if a : is found, and it either follows a [...], or no other : is in the string, treat it as port separator bool fHaveColon = colon != in.npos; bool fBracketed = fHaveColon && (in[0] == '[' && in[colon - 1] == ']'); // if there is a colon, and in[0]=='[', colon is not 0, so in[colon-1] is safe - bool fMultiColon = fHaveColon && (in.find_last_of(':', colon - 1) != in.npos); + bool fMultiColon{fHaveColon && colon != 0 && (in.find_last_of(':', colon - 1) != in.npos)}; if (fHaveColon && (colon == 0 || fBracketed || !fMultiColon)) { uint16_t n; if (ParseUInt16(in.substr(colon + 1), &n)) { @@ -328,6 +328,7 @@ bool ParseUInt64(const std::string& str, uint64_t* out) std::string FormatParagraph(const std::string& in, size_t width, size_t indent) { + assert(width >= indent); std::stringstream out; size_t ptr = 0; size_t indented = 0; diff --git a/src/util/syscall_sandbox.cpp b/src/util/syscall_sandbox.cpp index 3c250b7704..f2a9cf664d 100644 --- a/src/util/syscall_sandbox.cpp +++ b/src/util/syscall_sandbox.cpp @@ -68,6 +68,10 @@ bool g_syscall_sandbox_log_violation_before_terminating{false}; #define __NR_copy_file_range 326 #endif +#ifndef __NR_rseq +#define __NR_rseq 334 +#endif + // This list of syscalls in LINUX_SYSCALLS is only used to map syscall numbers to syscall names in // order to be able to print user friendly error messages which include the syscall name in addition // to the syscall number. @@ -327,6 +331,7 @@ const std::map<uint32_t, std::string> LINUX_SYSCALLS{ {__NR_request_key, "request_key"}, {__NR_restart_syscall, "restart_syscall"}, {__NR_rmdir, "rmdir"}, + {__NR_rseq, "rseq"}, {__NR_rt_sigaction, "rt_sigaction"}, {__NR_rt_sigpending, "rt_sigpending"}, {__NR_rt_sigprocmask, "rt_sigprocmask"}, @@ -595,10 +600,12 @@ public: allowed_syscalls.insert(__NR_readlink); // read value of a symbolic link allowed_syscalls.insert(__NR_rename); // change the name or location of a file allowed_syscalls.insert(__NR_rmdir); // delete a directory + allowed_syscalls.insert(__NR_sendfile); // transfer data between file descriptors allowed_syscalls.insert(__NR_stat); // get file status allowed_syscalls.insert(__NR_statfs); // get filesystem statistics allowed_syscalls.insert(__NR_statx); // get file status (extended) allowed_syscalls.insert(__NR_unlink); // delete a name and possibly the file it refers to + allowed_syscalls.insert(__NR_unlinkat); // delete relative to a directory file descriptor } void AllowFutex() @@ -721,6 +728,7 @@ public: allowed_syscalls.insert(__NR_fork); // create a child process allowed_syscalls.insert(__NR_tgkill); // send a signal to a thread allowed_syscalls.insert(__NR_wait4); // wait for process to change state, BSD style + allowed_syscalls.insert(__NR_rseq); // register restartable sequence for thread } void AllowScheduling() diff --git a/src/util/system.cpp b/src/util/system.cpp index 8f35b7b6c6..69811a751b 100644 --- a/src/util/system.cpp +++ b/src/util/system.cpp @@ -6,15 +6,11 @@ #include <util/system.h> #ifdef ENABLE_EXTERNAL_SIGNER -#if defined(WIN32) && !defined(__kernel_entry) -// A workaround for boost 1.71 incompatibility with mingw-w64 compiler. -// For details see https://github.com/bitcoin/bitcoin/pull/22348. -#define __kernel_entry -#endif #include <boost/process.hpp> #endif // ENABLE_EXTERNAL_SIGNER #include <chainparamsbase.h> +#include <fs.h> #include <sync.h> #include <util/check.h> #include <util/getuniquepath.h> @@ -71,10 +67,16 @@ #endif #include <boost/algorithm/string/replace.hpp> +#include <univalue.h> + +#include <fstream> +#include <map> +#include <memory> #include <optional> +#include <string> +#include <system_error> #include <thread> #include <typeinfo> -#include <univalue.h> // Application startup time (used for uptime calculation) const int64_t nStartupTime = GetTime(); @@ -151,7 +153,7 @@ bool CheckDiskSpace(const fs::path& dir, uint64_t additional_bytes) } std::streampos GetFileSize(const char* path, std::streamsize max) { - std::ifstream file(path, std::ios::binary); + std::ifstream file{path, std::ios::binary}; file.ignore(max); return file.gcount(); } @@ -244,19 +246,6 @@ static std::optional<util::SettingsValue> InterpretValue(const KeyInfo& key, con return value; } -namespace { -fs::path StripRedundantLastElementsOfPath(const fs::path& path) -{ - auto result = path; - while (fs::PathToString(result.filename()) == ".") { - result = result.parent_path(); - } - - assert(fs::equivalent(result, path)); - return result; -} -} // namespace - // Define default constructor and destructor that are not inline, so code instantiating this class doesn't need to // #include class definitions for all members. // For example, m_settings has an internal dependency on univalue. @@ -398,6 +387,13 @@ std::optional<unsigned int> ArgsManager::GetArgFlags(const std::string& name) co return std::nullopt; } +fs::path ArgsManager::GetPathArg(std::string pathlike_arg) const +{ + auto result = fs::PathFromString(GetArg(pathlike_arg, "")).lexically_normal(); + // Remove trailing slash, if present. + return result.has_filename() ? result : result.parent_path(); +} + const fs::path& ArgsManager::GetBlocksDirPath() const { LOCK(cs_args); @@ -408,7 +404,7 @@ const fs::path& ArgsManager::GetBlocksDirPath() const if (!path.empty()) return path; if (IsArgSet("-blocksdir")) { - path = fs::system_complete(fs::PathFromString(GetArg("-blocksdir", ""))); + path = fs::absolute(GetPathArg("-blocksdir")); if (!fs::is_directory(path)) { path = ""; return path; @@ -420,7 +416,6 @@ const fs::path& ArgsManager::GetBlocksDirPath() const path /= fs::PathFromString(BaseParams().DataDir()); path /= "blocks"; fs::create_directories(path); - path = StripRedundantLastElementsOfPath(path); return path; } @@ -433,9 +428,9 @@ const fs::path& ArgsManager::GetDataDir(bool net_specific) const // this function if (!path.empty()) return path; - std::string datadir = GetArg("-datadir", ""); + const fs::path datadir{GetPathArg("-datadir")}; if (!datadir.empty()) { - path = fs::system_complete(fs::PathFromString(datadir)); + path = fs::absolute(datadir); if (!fs::is_directory(path)) { path = ""; return path; @@ -443,15 +438,18 @@ const fs::path& ArgsManager::GetDataDir(bool net_specific) const } else { path = GetDefaultDataDir(); } - if (net_specific) - path /= fs::PathFromString(BaseParams().DataDir()); - if (fs::create_directories(path)) { - // This is the first run, create wallets subdirectory too + if (!fs::exists(path)) { fs::create_directories(path / "wallets"); } - path = StripRedundantLastElementsOfPath(path); + if (net_specific && !BaseParams().DataDir().empty()) { + path /= fs::PathFromString(BaseParams().DataDir()); + if (!fs::exists(path)) { + fs::create_directories(path / "wallets"); + } + } + return path; } @@ -812,8 +810,8 @@ fs::path GetDefaultDataDir() bool CheckDataDirOption() { - std::string datadir = gArgs.GetArg("-datadir", ""); - return datadir.empty() || fs::is_directory(fs::system_complete(fs::PathFromString(datadir))); + const fs::path datadir{gArgs.GetPathArg("-datadir")}; + return datadir.empty() || fs::is_directory(fs::absolute(datadir)); } fs::path GetConfigFile(const std::string& confPath) @@ -903,7 +901,7 @@ bool ArgsManager::ReadConfigFiles(std::string& error, bool ignore_invalid_keys) } const std::string confPath = GetArg("-conf", BITCOIN_CONF_FILENAME); - fsbridge::ifstream stream(GetConfigFile(confPath)); + std::ifstream stream{GetConfigFile(confPath)}; // not ok to have a config file specified that cannot be opened if (IsArgSet("-conf") && !stream.good()) { @@ -950,7 +948,7 @@ bool ArgsManager::ReadConfigFiles(std::string& error, bool ignore_invalid_keys) const size_t default_includes = add_includes({}); for (const std::string& conf_file_name : conf_file_names) { - fsbridge::ifstream conf_file_stream(GetConfigFile(conf_file_name)); + std::ifstream conf_file_stream{GetConfigFile(conf_file_name)}; if (conf_file_stream.good()) { if (!ReadConfigStream(conf_file_stream, conf_file_name, error, ignore_invalid_keys)) { return false; @@ -1064,17 +1062,24 @@ void ArgsManager::LogArgs() const bool RenameOver(fs::path src, fs::path dest) { -#ifdef WIN32 +#ifdef __MINGW64__ + // This is a workaround for a bug in libstdc++ which + // implements std::filesystem::rename with _wrename function. + // This bug has been fixed in upstream: + // - GCC 10.3: 8dd1c1085587c9f8a21bb5e588dfe1e8cdbba79e + // - GCC 11.1: 1dfd95f0a0ca1d9e6cbc00e6cbfd1fa20a98f312 + // For more details see the commits mentioned above. return MoveFileExW(src.wstring().c_str(), dest.wstring().c_str(), MOVEFILE_REPLACE_EXISTING) != 0; #else - int rc = std::rename(src.c_str(), dest.c_str()); - return (rc == 0); -#endif /* WIN32 */ + std::error_code error; + fs::rename(src, dest, error); + return !error; +#endif } /** - * Ignores exceptions thrown by Boost's create_directories if the requested directory exists. + * Ignores exceptions thrown by create_directories if the requested directory exists. * Specifically handles case where path p exists, but it wasn't possible for the user to * write to the parent directory. */ @@ -1318,16 +1323,6 @@ void SetupEnvironment() SetConsoleCP(CP_UTF8); SetConsoleOutputCP(CP_UTF8); #endif - // The path locale is lazy initialized and to avoid deinitialization errors - // in multithreading environments, it is set explicitly by the main thread. - // A dummy locale is used to extract the internal default locale, used by - // fs::path, which is then used to explicitly imbue the path. - std::locale loc = fs::path::imbue(std::locale::classic()); -#ifndef WIN32 - fs::path::imbue(loc); -#else - fs::path::imbue(std::locale(loc, new std::codecvt_utf8_utf16<wchar_t>())); -#endif } bool SetupNetworking() diff --git a/src/util/system.h b/src/util/system.h index a8fd21fcaa..a72ba3f3ed 100644 --- a/src/util/system.h +++ b/src/util/system.h @@ -69,7 +69,13 @@ void DirectoryCommit(const fs::path &dirname); bool TruncateFile(FILE *file, unsigned int length); int RaiseFileDescriptorLimit(int nMinFD); void AllocateFileRange(FILE *file, unsigned int offset, unsigned int length); + +/** + * Rename src to dest. + * @return true if the rename was successful. + */ [[nodiscard]] bool RenameOver(fs::path src, fs::path dest); + bool LockDirectory(const fs::path& directory, const std::string lockfile_name, bool probe_only=false); void UnlockDirectory(const fs::path& directory, const std::string& lockfile_name); bool DirIsWritable(const fs::path& directory); @@ -265,6 +271,16 @@ protected: std::optional<const Command> GetCommand() const; /** + * Get a normalized path from a specified pathlike argument + * + * It is guaranteed that the returned path has no trailing slashes. + * + * @param pathlike_arg Pathlike argument to get a path from (e.g., "-datadir", "-blocksdir" or "-walletdir") + * @return Normalized path which is get from a specified pathlike argument + */ + fs::path GetPathArg(std::string pathlike_arg) const; + + /** * Get blocks directory path * * @return Blocks path which is network specific |