diff --git a/src/addrdb.cpp b/src/addrdb.cpp index 854d46f6e..3cda947a5 100644 --- a/src/addrdb.cpp +++ b/src/addrdb.cpp @@ -1,232 +1,233 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto // Copyright (c) 2009-2016 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. #include #include #include #include +#include #include #include #include #include #include #include #include #include namespace { class DbNotFoundError : public std::exception { using std::exception::exception; }; template bool SerializeDB(const CChainParams &chainParams, Stream &stream, const Data &data) { // Write and commit header, data try { CHashWriter hasher(SER_DISK, CLIENT_VERSION); stream << chainParams.DiskMagic() << data; hasher << chainParams.DiskMagic() << data; stream << hasher.GetHash(); } catch (const std::exception &e) { return error("%s: Serialize or I/O error - %s", __func__, e.what()); } return true; } template bool SerializeFileDB(const CChainParams &chainParams, const std::string &prefix, const fs::path &path, const Data &data) { // Generate random temporary filename uint16_t randv = 0; GetRandBytes((uint8_t *)&randv, sizeof(randv)); std::string tmpfn = strprintf("%s.%04x", prefix, randv); // open temp output file, and associate with CAutoFile fs::path pathTmp = gArgs.GetDataDirNet() / tmpfn; FILE *file = fsbridge::fopen(pathTmp, "wb"); CAutoFile fileout(file, SER_DISK, CLIENT_VERSION); if (fileout.IsNull()) { fileout.fclose(); remove(pathTmp); return error("%s: Failed to open file %s", __func__, fs::PathToString(pathTmp)); } // Serialize if (!SerializeDB(chainParams, fileout, data)) { fileout.fclose(); remove(pathTmp); return false; } if (!FileCommit(fileout.Get())) { fileout.fclose(); remove(pathTmp); return error("%s: Failed to flush file %s", __func__, fs::PathToString(pathTmp)); } fileout.fclose(); // replace existing file, if any, with new file if (!RenameOver(pathTmp, path)) { remove(pathTmp); return error("%s: Rename-into-place failed", __func__); } return true; } template void DeserializeDB(const CChainParams &chainParams, Stream &stream, Data &data, bool fCheckSum = true) { CHashVerifier verifier(&stream); // de-serialize file header (network specific magic number) and .. uint8_t pchMsgTmp[4]; verifier >> pchMsgTmp; // ... verify the network matches ours if (memcmp(pchMsgTmp, std::begin(chainParams.DiskMagic()), sizeof(pchMsgTmp))) { throw std::runtime_error{"Invalid network magic number"}; } // de-serialize data verifier >> data; // verify checksum if (fCheckSum) { uint256 hashTmp; stream >> hashTmp; if (hashTmp != verifier.GetHash()) { throw std::runtime_error{"Checksum mismatch, data corrupted"}; } } } template void DeserializeFileDB(const CChainParams &chainParams, const fs::path &path, Data &data) { // open input file, and associate with CAutoFile FILE *file = fsbridge::fopen(path, "rb"); CAutoFile filein(file, SER_DISK, CLIENT_VERSION); if (filein.IsNull()) { throw DbNotFoundError{}; } DeserializeDB(chainParams, filein, data); } } // namespace CBanDB::CBanDB(fs::path ban_list_path, const CChainParams &_chainParams) : m_ban_list_path(std::move(ban_list_path)), chainParams(_chainParams) {} bool CBanDB::Write(const banmap_t &banSet) { return SerializeFileDB(chainParams, "banlist", m_ban_list_path, banSet); } bool CBanDB::Read(banmap_t &banSet) { // TODO: this needs to be reworked after banlist.dat is deprecated (in // favor of banlist.json). See: // - https://github.com/bitcoin/bitcoin/pull/20966 // - https://github.com/bitcoin/bitcoin/pull/22570 try { DeserializeFileDB(chainParams, m_ban_list_path, banSet); } catch (const std::exception &) { LogPrintf("Missing or invalid file %s\n", fs::quoted(fs::PathToString(m_ban_list_path))); return false; } return true; } bool DumpPeerAddresses(const CChainParams &chainParams, const ArgsManager &args, const AddrMan &addr) { const auto pathAddr = args.GetDataDirNet() / "peers.dat"; return SerializeFileDB(chainParams, "peers", pathAddr, addr); } void ReadFromStream(const CChainParams &chainParams, AddrMan &addr, CDataStream &ssPeers) { DeserializeDB(chainParams, ssPeers, addr, false); } std::optional LoadAddrman(const CChainParams &chainparams, const std::vector &asmap, const ArgsManager &args, std::unique_ptr &addrman) { auto check_addrman = std::clamp( args.GetIntArg("-checkaddrman", DEFAULT_ADDRMAN_CONSISTENCY_CHECKS), 0, 1000000); addrman = std::make_unique( asmap, /* consistency_check_ratio= */ check_addrman); int64_t nStart = GetTimeMillis(); const auto path_addr{args.GetDataDirNet() / "peers.dat"}; try { DeserializeFileDB(chainparams, path_addr, *addrman); LogPrintf("Loaded %i addresses from peers.dat %dms\n", addrman->size(), GetTimeMillis() - nStart); } catch (const DbNotFoundError &) { // Addrman can be in an inconsistent state after failure, reset it addrman = std::make_unique( asmap, /* consistency_check_ratio= */ check_addrman); LogPrintf("Creating peers.dat because the file was not found (%s)\n", fs::quoted(fs::PathToString(path_addr))); DumpPeerAddresses(chainparams, args, *addrman); } catch (const InvalidAddrManVersionError &) { if (!RenameOver(path_addr, fs::path(path_addr) + ".bak")) { addrman = nullptr; return strprintf(_("Failed to rename invalid peers.dat file. " "Please move or delete it and try again.")); } // Addrman can be in an inconsistent state after failure, reset it addrman = std::make_unique( asmap, /* consistency_check_ratio= */ check_addrman); LogPrintf("Creating new peers.dat because the file version was not " "compatible (%s). Original backed up to peers.dat.bak\n", fs::quoted(fs::PathToString(path_addr))); DumpPeerAddresses(chainparams, args, *addrman); } catch (const std::exception &e) { addrman = nullptr; return strprintf( _("Invalid or corrupt peers.dat (%s). If you believe this is a " "bug, please report it to %s. As a workaround, you can move the " "file (%s) out of the way (rename, move, or delete) to have a " "new one created on the next start."), e.what(), PACKAGE_BUGREPORT, fs::quoted(fs::PathToString(path_addr))); } return std::nullopt; } void DumpAnchors(const CChainParams &chainParams, const fs::path &anchors_db_path, const std::vector &anchors) { LOG_TIME_SECONDS(strprintf( "Flush %d outbound block-relay-only peer addresses to anchors.dat", anchors.size())); SerializeFileDB(chainParams, "anchors", anchors_db_path, anchors); } std::vector ReadAnchors(const CChainParams &chainParams, const fs::path &anchors_db_path) { std::vector anchors; try { DeserializeFileDB(chainParams, anchors_db_path, anchors); LogPrintf("Loaded %i addresses from %s\n", anchors.size(), fs::quoted(fs::PathToString(anchors_db_path.filename()))); } catch (const std::exception &) { anchors.clear(); } fs::remove(anchors_db_path); return anchors; } diff --git a/src/bench/bench.cpp b/src/bench/bench.cpp index 50c1c6e47..ed1dfe15a 100644 --- a/src/bench/bench.cpp +++ b/src/bench/bench.cpp @@ -1,97 +1,97 @@ // Copyright (c) 2015-2019 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. #include #include #include #include #include #include #include #include #include #include using namespace std::chrono_literals; namespace { void GenerateTemplateResults( const std::vector &benchmarkResults, const std::string &filename, const char *tpl) { if (benchmarkResults.empty() || filename.empty()) { // nothing to write, bail out return; } - fsbridge::ofstream fout{fs::PathFromString(filename)}; + std::ofstream fout{fs::PathFromString(filename)}; if (fout.is_open()) { ankerl::nanobench::render(tpl, benchmarkResults, fout); } else { std::cout << "Could write to file '" << filename << "'" << std::endl; } std::cout << "Created '" << filename << "'" << std::endl; } } // namespace benchmark::BenchRunner::BenchmarkMap &benchmark::BenchRunner::benchmarks() { static std::map benchmarks_map; return benchmarks_map; } benchmark::BenchRunner::BenchRunner(std::string name, benchmark::BenchFunction func) { benchmarks().insert(std::make_pair(name, func)); } void benchmark::BenchRunner::RunAll(const Args &args) { std::regex reFilter(args.regex_filter); std::smatch baseMatch; std::vector benchmarkResults; for (const auto &p : benchmarks()) { if (!std::regex_match(p.first, baseMatch, reFilter)) { continue; } if (args.is_list_only) { std::cout << p.first << std::endl; continue; } Bench bench; bench.name(p.first); if (args.min_time > 0ms) { // convert to nanos before dividing to reduce rounding errors std::chrono::nanoseconds min_time_ns = args.min_time; bench.minEpochTime(min_time_ns / bench.epochs()); } if (args.asymptote.empty()) { p.second(bench); } else { for (auto n : args.asymptote) { bench.complexityN(n); p.second(bench); } std::cout << bench.complexityBigO() << std::endl; } benchmarkResults.push_back(bench.results().back()); } GenerateTemplateResults( benchmarkResults, args.output_csv, "# Benchmark, evals, iterations, total, min, max, median\n" "{{#result}}{{name}}, {{epochs}}, {{average(iterations)}}, " "{{sumProduct(iterations, elapsed)}}, {{minimum(elapsed)}}, " "{{maximum(elapsed)}}, {{median(elapsed)}}\n" "{{/result}}"); GenerateTemplateResults(benchmarkResults, args.output_json, ankerl::nanobench::templates::json()); } diff --git a/src/fs.cpp b/src/fs.cpp index e523d5d42..33168fc24 100644 --- a/src/fs.cpp +++ b/src/fs.cpp @@ -1,281 +1,171 @@ // Copyright (c) 2017 The Bitcoin Core developers // Copyright (c) 2019 The Bitcoin developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. #include #ifndef WIN32 #include #include #include #include #include #else #ifndef NOMINMAX #define NOMINMAX #endif #include #include #endif #include #include #include namespace fsbridge { FILE *fopen(const fs::path &p, const char *mode) { #ifndef WIN32 return ::fopen(p.c_str(), mode); #else std::wstring_convert, wchar_t> utf8_cvt; return ::_wfopen(p.wstring().c_str(), utf8_cvt.from_bytes(mode).c_str()); #endif } fs::path AbsPathJoin(const fs::path &base, const fs::path &path) { assert(base.is_absolute()); - return fs::absolute(path, base); + return path.empty() ? base : fs::path(base / path); } #ifndef WIN32 static std::string GetErrorReason() { return std::strerror(errno); } FileLock::FileLock(const fs::path &file) { fd = open(file.c_str(), O_RDWR); if (fd == -1) { reason = GetErrorReason(); } } FileLock::~FileLock() { if (fd != -1) { close(fd); } } static bool IsWSL() { struct utsname uname_data; return uname(&uname_data) == 0 && std::string(uname_data.version).find("Microsoft") != std::string::npos; } bool FileLock::TryLock() { if (fd == -1) { return false; } // Exclusive file locking is broken on WSL using fcntl (issue #18622) // This workaround can be removed once the bug on WSL is fixed static const bool is_wsl = IsWSL(); if (is_wsl) { if (flock(fd, LOCK_EX | LOCK_NB) == -1) { reason = GetErrorReason(); return false; } } else { struct flock lock; lock.l_type = F_WRLCK; lock.l_whence = SEEK_SET; lock.l_start = 0; lock.l_len = 0; if (fcntl(fd, F_SETLK, &lock) == -1) { reason = GetErrorReason(); return false; } } return true; } #else static std::string GetErrorReason() { wchar_t *err; FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, nullptr, GetLastError(), MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), reinterpret_cast(&err), 0, nullptr); std::wstring err_str(err); LocalFree(err); return std::wstring_convert>().to_bytes( err_str); } FileLock::FileLock(const fs::path &file) { hFile = CreateFileW(file.wstring().c_str(), GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, nullptr, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, nullptr); if (hFile == INVALID_HANDLE_VALUE) { reason = GetErrorReason(); } } FileLock::~FileLock() { if (hFile != INVALID_HANDLE_VALUE) { CloseHandle(hFile); } } bool FileLock::TryLock() { if (hFile == INVALID_HANDLE_VALUE) { return false; } _OVERLAPPED overlapped = {0}; if (!LockFileEx(hFile, LOCKFILE_EXCLUSIVE_LOCK | LOCKFILE_FAIL_IMMEDIATELY, 0, std::numeric_limits::max(), std::numeric_limits::max(), &overlapped)) { reason = GetErrorReason(); return false; } return true; } #endif std::string get_filesystem_error_message(const fs::filesystem_error &e) { #ifndef WIN32 return e.what(); #else // Convert from Multi Byte to utf-16 std::string mb_string(e.what()); int size = MultiByteToWideChar(CP_ACP, 0, mb_string.data(), mb_string.size(), nullptr, 0); std::wstring utf16_string(size, L'\0'); MultiByteToWideChar(CP_ACP, 0, mb_string.data(), mb_string.size(), &*utf16_string.begin(), size); // Convert from utf-16 to utf-8 return std::wstring_convert, wchar_t>() .to_bytes(utf16_string); #endif } -#ifdef WIN32 -#ifdef __GLIBCXX__ - -// reference: -// https://github.com/gcc-mirror/gcc/blob/gcc-7_3_0-release/libstdc%2B%2B-v3/include/std/fstream#L270 - -static std::string openmodeToStr(std::ios_base::openmode mode) { - switch (mode & ~std::ios_base::ate) { - case std::ios_base::out: - case std::ios_base::out | std::ios_base::trunc: - return "w"; - case std::ios_base::out | std::ios_base::app: - case std::ios_base::app: - return "a"; - case std::ios_base::in: - return "r"; - case std::ios_base::in | std::ios_base::out: - return "r+"; - case std::ios_base::in | std::ios_base::out | std::ios_base::trunc: - return "w+"; - case std::ios_base::in | std::ios_base::out | std::ios_base::app: - case std::ios_base::in | std::ios_base::app: - return "a+"; - case std::ios_base::out | std::ios_base::binary: - case std::ios_base::out | std::ios_base::trunc | std::ios_base::binary: - return "wb"; - case std::ios_base::out | std::ios_base::app | std::ios_base::binary: - case std::ios_base::app | std::ios_base::binary: - return "ab"; - case std::ios_base::in | std::ios_base::binary: - return "rb"; - case std::ios_base::in | std::ios_base::out | std::ios_base::binary: - return "r+b"; - case std::ios_base::in | std::ios_base::out | std::ios_base::trunc | - std::ios_base::binary: - return "w+b"; - case std::ios_base::in | std::ios_base::out | std::ios_base::app | - std::ios_base::binary: - case std::ios_base::in | std::ios_base::app | std::ios_base::binary: - return "a+b"; - default: - return std::string(); - } -} - -void ifstream::open(const fs::path &p, std::ios_base::openmode mode) { - close(); - mode |= std::ios_base::in; - m_file = fsbridge::fopen(p, openmodeToStr(mode).c_str()); - if (m_file == nullptr) { - return; - } - m_filebuf = __gnu_cxx::stdio_filebuf(m_file, mode); - rdbuf(&m_filebuf); - if (mode & std::ios_base::ate) { - seekg(0, std::ios_base::end); - } -} - -void ifstream::close() { - if (m_file != nullptr) { - m_filebuf.close(); - fclose(m_file); - } - m_file = nullptr; -} - -void ofstream::open(const fs::path &p, std::ios_base::openmode mode) { - close(); - mode |= std::ios_base::out; - m_file = fsbridge::fopen(p, openmodeToStr(mode).c_str()); - if (m_file == nullptr) { - return; - } - m_filebuf = __gnu_cxx::stdio_filebuf(m_file, mode); - rdbuf(&m_filebuf); - if (mode & std::ios_base::ate) { - seekp(0, std::ios_base::end); - } -} - -void ofstream::close() { - if (m_file != nullptr) { - m_filebuf.close(); - fclose(m_file); - } - m_file = nullptr; -} -#else // __GLIBCXX__ - -#if BOOST_VERSION >= 107700 -static_assert( - sizeof(*BOOST_FILESYSTEM_C_STR(boost::filesystem::path())) == - sizeof(wchar_t), -#else -static_assert( - sizeof(*boost::filesystem::path().BOOST_FILESYSTEM_C_STR) == - sizeof(wchar_t), -#endif // BOOST_VERSION >= 107700 - "Warning: This build is using boost::filesystem ofstream and ifstream " - "implementations which will fail to open paths containing multibyte " - "characters. You should delete this static_assert to ignore this warning, " - "or switch to a different C++ standard library like the Microsoft C++ " - "Standard Library (where boost uses non-standard extensions to construct " - "stream objects with wide filenames), or the GNU libstdc++ library (where " - "a more complicated workaround has been implemented above)."); - -#endif // __GLIBCXX__ -#endif // WIN32 - fs::path GetTempDirectoryPath() { #ifndef WIN32 return fs::temp_directory_path(); #else wchar_t dirPathWchars[MAX_PATH]; GetTempPathW(MAX_PATH, dirPathWchars); std::wstring dirPathWstring(dirPathWchars); return fs::PathFromString( std::wstring_convert>().to_bytes( dirPathWstring)); #endif } } // namespace fsbridge diff --git a/src/fs.h b/src/fs.h index c13d0acbc..8dd7401b2 100644 --- a/src/fs.h +++ b/src/fs.h @@ -1,264 +1,211 @@ // Copyright (c) 2017 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. #ifndef BITCOIN_FS_H #define BITCOIN_FS_H +#include + #include +#include +#include +#include +#include #include -#if defined WIN32 && defined __GLIBCXX__ -#include -#endif - -#include -#include -#include +#include /** Filesystem operations and types */ namespace fs { -using namespace boost::filesystem; +using namespace std::filesystem; /** - * Path class wrapper to prepare application code for transition from - * boost::filesystem library to std::filesystem implementation. The main - * purpose of the class is to define fs::path::u8string() and fs::u8path() - * functions not present in boost. It also blocks calls to the - * fs::path(std::string) implicit constructor and the fs::path::string() - * method, which worked well in the boost::filesystem implementation, but have - * unsafe and unpredictable behavior on Windows in the std::filesystem - * implementation (see implementation note in \ref PathToString for details). + * Path class wrapper to block calls to the fs::path(std::string) implicit + * constructor and the fs::path::string() method, which have unsafe and + * unpredictable behavior on Windows (see implementation note in + * \ref PathToString for details) */ -class path : public boost::filesystem::path { +class path : public std::filesystem::path { public: - using boost::filesystem::path::path; + using std::filesystem::path::path; // Allow path objects arguments for compatibility. - path(boost::filesystem::path path) - : boost::filesystem::path::path(std::move(path)) {} - path &operator=(boost::filesystem::path path) { - boost::filesystem::path::operator=(std::move(path)); + path(std::filesystem::path path) + : std::filesystem::path::path(std::move(path)) {} + path &operator=(std::filesystem::path path) { + std::filesystem::path::operator=(std::move(path)); return *this; } - path &operator/=(boost::filesystem::path path) { - boost::filesystem::path::operator/=(std::move(path)); + path &operator/=(std::filesystem::path path) { + std::filesystem::path::operator/=(std::move(path)); return *this; } // Allow literal string arguments, which are safe as long as the literals // are ASCII. - path(const char *c) : boost::filesystem::path(c) {} + path(const char *c) : std::filesystem::path(c) {} path &operator=(const char *c) { - boost::filesystem::path::operator=(c); + std::filesystem::path::operator=(c); return *this; } path &operator/=(const char *c) { - boost::filesystem::path::operator/=(c); + std::filesystem::path::operator/=(c); return *this; } path &append(const char *c) { - boost::filesystem::path::append(c); + std::filesystem::path::append(c); return *this; } // Disallow std::string arguments to avoid locale-dependent decoding on // windows. path(std::string) = delete; path &operator=(std::string) = delete; path &operator/=(std::string) = delete; path &append(std::string) = delete; // Disallow std::string conversion method to avoid locale-dependent encoding // on windows. std::string string() const = delete; - // Define UTF-8 string conversion method not present in boost::filesystem - // but present in std::filesystem. - std::string u8string() const { return boost::filesystem::path::string(); } + // Required for path overloads in . + // See + // https://gcc.gnu.org/git/?p=gcc.git;a=commit;h=96e0367ead5d8dcac3bec2865582e76e2fbab190 + path &make_preferred() { + std::filesystem::path::make_preferred(); + return *this; + } + path filename() const { return std::filesystem::path::filename(); } }; -// Define UTF-8 string conversion function not present in boost::filesystem but -// present in std::filesystem. -static inline path u8path(const std::string &string) { - return boost::filesystem::path(string); -} - -// Disallow implicit std::string conversion for system_complete to avoid +// Disallow implicit std::string conversion for absolute to avoid // locale-dependent encoding on windows. -static inline path system_complete(const path &p) { - return boost::filesystem::system_complete(p); +static inline path absolute(const path &p) { + return std::filesystem::absolute(p); } // Disallow implicit std::string conversion for exists to avoid // locale-dependent encoding on windows. static inline bool exists(const path &p) { - return boost::filesystem::exists(p); + return std::filesystem::exists(p); } // Allow explicit quoted stream I/O. static inline auto quoted(const std::string &s) { - return boost::io::quoted(s, '&'); + return std::quoted(s, '"', '&'); } // Allow safe path append operations. static inline path operator+(path p1, path p2) { - p1 += static_cast(p2); + p1 += std::move(p2); return p1; } +// Disallow implicit std::string conversion for copy_file +// to avoid locale-dependent encoding on Windows. +static inline bool copy_file(const path &from, const path &to, + copy_options options) { + return std::filesystem::copy_file(from, to, options); +} + /** - * Convert path object to byte string. On POSIX, paths natively are byte + * Convert path object to a byte string. On POSIX, paths natively are byte * strings so this is trivial. On Windows, paths natively are Unicode, so an * encoding step is necessary. * * The inverse of \ref PathToString is \ref PathFromString. The strings * returned and parsed by these functions can be used to call POSIX APIs, and * for roundtrip conversion, logging, and debugging. But they are not * guaranteed to be valid UTF-8, and are generally meant to be used internally, * not externally. When communicating with external programs and libraries that * require UTF-8, fs::path::u8string() and fs::u8path() methods can be used. * For other applications, if support for non UTF-8 paths is required, or if * higher-level JSON or XML or URI or C-style escapes are preferred, it may be * also be appropriate to use different path encoding functions. * * Implementation note: On Windows, the std::filesystem::path(string) * constructor and std::filesystem::path::string() method are not safe to use * here, because these methods encode the path using C++'s narrow multibyte * encoding, which on Windows corresponds to the current "code page", which is * unpredictable and typically not able to represent all valid paths. So * std::filesystem::path::u8string() and std::filesystem::u8path() functions * are used instead on Windows. On POSIX, u8string/u8path functions are not * safe to use because paths are not always valid UTF-8, so plain string * methods which do not transform the path there are used. */ static inline std::string PathToString(const path &path) { #ifdef WIN32 return path.u8string(); #else static_assert(std::is_same::value, "PathToString not implemented on this platform"); - return path.boost::filesystem::path::string(); + return path.std::filesystem::path::string(); #endif } /** * Convert byte string to path object. Inverse of \ref PathToString. */ static inline path PathFromString(const std::string &string) { #ifdef WIN32 return u8path(string); #else - return boost::filesystem::path(string); + return std::filesystem::path(string); #endif } } // namespace fs /** Bridge operations to C stdio */ namespace fsbridge { FILE *fopen(const fs::path &p, const char *mode); FILE *freopen(const fs::path &p, const char *mode, FILE *stream); /** * Helper function for joining two paths * * @param[in] base Base path * @param[in] path Path to combine with base * @returns path unchanged if it is an absolute path, otherwise returns base * joined with path. Returns base unchanged if path is empty. * @pre Base path must be absolute * @post Returned path will always be absolute */ fs::path AbsPathJoin(const fs::path &base, const fs::path &path); class FileLock { public: FileLock() = delete; FileLock(const FileLock &) = delete; FileLock(FileLock &&) = delete; explicit FileLock(const fs::path &file); ~FileLock(); bool TryLock(); std::string GetReason() { return reason; } private: std::string reason; #ifndef WIN32 int fd = -1; #else // INVALID_HANDLE_VALUE void *hFile = (void *)-1; #endif }; std::string get_filesystem_error_message(const fs::filesystem_error &e); -// GNU libstdc++ specific workaround for opening UTF-8 paths on Windows. -// -// On Windows, it is only possible to reliably access multibyte file paths -// through `wchar_t` APIs, not `char` APIs. But because the C++ standard doesn't -// require ifstream/ofstream `wchar_t` constructors, and the GNU library doesn't -// provide them (in contrast to the Microsoft C++ library, see -// https://stackoverflow.com/questions/821873/how-to-open-an-stdfstream-ofstream-or-ifstream-with-a-unicode-filename/822032#822032), -// Boost is forced to fall back to `char` constructors which may not work -// properly. -// -// Work around this issue by creating stream objects with `_wfopen` in -// combination with `__gnu_cxx::stdio_filebuf`. This workaround can be removed -// with an upgrade to C++17, where streams can be constructed directly from -// `std::filesystem::path` objects. - -#if defined WIN32 && defined __GLIBCXX__ -class ifstream : public std::istream { -public: - ifstream() = default; - explicit ifstream(const fs::path &p, - std::ios_base::openmode mode = std::ios_base::in) { - open(p, mode); - } - ~ifstream() { close(); } - void open(const fs::path &p, - std::ios_base::openmode mode = std::ios_base::in); - bool is_open() { return m_filebuf.is_open(); } - void close(); - -private: - __gnu_cxx::stdio_filebuf m_filebuf; - FILE *m_file = nullptr; -}; -class ofstream : public std::ostream { -public: - ofstream() = default; - explicit ofstream(const fs::path &p, - std::ios_base::openmode mode = std::ios_base::out) { - open(p, mode); - } - ~ofstream() { close(); } - void open(const fs::path &p, - std::ios_base::openmode mode = std::ios_base::out); - bool is_open() { return m_filebuf.is_open(); } - void close(); - -private: - __gnu_cxx::stdio_filebuf m_filebuf; - FILE *m_file = nullptr; -}; -#else // !(WIN32 && __GLIBCXX__) -typedef fs::ifstream ifstream; -typedef fs::ofstream ofstream; -#endif // WIN32 && __GLIBCXX__ - fs::path GetTempDirectoryPath(); }; // namespace fsbridge // Disallow path operator<< formatting in tinyformat to avoid locale-dependent // encoding on windows. namespace tinyformat { template <> inline void formatValue(std::ostream &, const char *, const char *, int, - const boost::filesystem::path &) = delete; + const std::filesystem::path &) = delete; template <> inline void formatValue(std::ostream &, const char *, const char *, int, const fs::path &) = delete; } // namespace tinyformat #endif // BITCOIN_FS_H diff --git a/src/init.cpp b/src/init.cpp index 124858ce9..846c4a57b 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -1,2987 +1,2990 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto // Copyright (c) 2009-2018 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. #if defined(HAVE_CONFIG_H) #include #endif #include #include #include #include #include // For AVALANCHE_LEGACY_PROOF_DEFAULT #include #include // For AVALANCHE_VOTE_STALE_* #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include