mirror of
https://github.com/bitcoin/bitcoin.git
synced 2025-12-18 08:32:30 +01:00
Fix windows libc++ fs::path fstream compile errors
As reported by hebasto in https://github.com/bitcoin/bitcoin/issues/33545, newer libc++ versions implementing https://wg21.link/lwg3430 will no longer implicitly convert `fs::path` objects to `std::filesystem::path` objects when constructing `std::ifstream` and `std::ofstream` types. This is not a problem in Unix systems since `fs::path` objects use `std::string` as their native string type, but it causes compile errors on Windows which use `std::wstring` as their string type, since `fstream`s can't be constructed from `wstring`s. Fix the windows libc++ compile errors by adding a new `fs::path::std_path()` method and using it construct `fstream`s more portably. Additionally, delete `fs::path`'s implicit `native_string` conversion so these errors will not go undetected in the future, even though there is not currently a CI job testing Windows libc++ builds.
This commit is contained in:
@@ -56,7 +56,7 @@ void GenerateTemplateResults(const std::vector<ankerl::nanobench::Result>& bench
|
||||
// nothing to write, bail out
|
||||
return;
|
||||
}
|
||||
std::ofstream fout{file};
|
||||
std::ofstream fout{file.std_path()};
|
||||
if (fout.is_open()) {
|
||||
ankerl::nanobench::render(tpl, benchmarkResults, fout);
|
||||
std::cout << "Created " << file << std::endl;
|
||||
|
||||
@@ -135,7 +135,7 @@ bool ArgsManager::ReadConfigFiles(std::string& error, bool ignore_invalid_keys)
|
||||
error = strprintf("Config file \"%s\" is a directory.", fs::PathToString(conf_path));
|
||||
return false;
|
||||
}
|
||||
stream = std::ifstream{conf_path};
|
||||
stream = std::ifstream{conf_path.std_path()};
|
||||
// If the file is explicitly specified, it must be readable
|
||||
if (IsArgSet("-conf") && !stream.good()) {
|
||||
error = strprintf("specified config file \"%s\" could not be opened.", fs::PathToString(conf_path));
|
||||
@@ -187,7 +187,7 @@ bool ArgsManager::ReadConfigFiles(std::string& error, bool ignore_invalid_keys)
|
||||
error = strprintf("Included config file \"%s\" is a directory.", fs::PathToString(include_conf_path));
|
||||
return false;
|
||||
}
|
||||
std::ifstream conf_file_stream{include_conf_path};
|
||||
std::ifstream conf_file_stream{include_conf_path.std_path()};
|
||||
if (conf_file_stream.good()) {
|
||||
if (!ReadConfigStream(conf_file_stream, conf_file_name, error, ignore_invalid_keys)) {
|
||||
return false;
|
||||
|
||||
@@ -179,7 +179,7 @@ static fs::path GetPidFile(const ArgsManager& args)
|
||||
{
|
||||
if (args.IsArgNegated("-pid")) return true;
|
||||
|
||||
std::ofstream file{GetPidFile(args)};
|
||||
std::ofstream file{GetPidFile(args).std_path()};
|
||||
if (file) {
|
||||
#ifdef WIN32
|
||||
tfm::format(file, "%d\n", GetCurrentProcessId());
|
||||
|
||||
@@ -447,7 +447,7 @@ bool openBitcoinConf()
|
||||
fs::path pathConfig = gArgs.GetConfigFilePath();
|
||||
|
||||
/* Create the file */
|
||||
std::ofstream configFile{pathConfig, std::ios_base::app};
|
||||
std::ofstream configFile{pathConfig.std_path(), std::ios_base::app};
|
||||
|
||||
if (!configFile.good())
|
||||
return false;
|
||||
@@ -607,7 +607,7 @@ fs::path static GetAutostartFilePath()
|
||||
|
||||
bool GetStartOnSystemStartup()
|
||||
{
|
||||
std::ifstream optionFile{GetAutostartFilePath()};
|
||||
std::ifstream optionFile{GetAutostartFilePath().std_path()};
|
||||
if (!optionFile.good())
|
||||
return false;
|
||||
// Scan through file for "Hidden=true":
|
||||
@@ -639,7 +639,7 @@ bool SetStartOnSystemStartup(bool fAutoStart)
|
||||
|
||||
fs::create_directories(GetAutostartDir());
|
||||
|
||||
std::ofstream optionFile{GetAutostartFilePath(), std::ios_base::out | std::ios_base::trunc};
|
||||
std::ofstream optionFile{GetAutostartFilePath().std_path(), std::ios_base::out | std::ios_base::trunc};
|
||||
if (!optionFile.good())
|
||||
return false;
|
||||
ChainType chain = gArgs.GetChainType();
|
||||
|
||||
@@ -70,7 +70,7 @@ void OptionTests::migrateSettings()
|
||||
QVERIFY(!settings.contains("fUseSeparateProxyTor"));
|
||||
QVERIFY(!settings.contains("addrSeparateProxyTor"));
|
||||
|
||||
std::ifstream file(gArgs.GetDataDirNet() / "settings.json");
|
||||
std::ifstream file((gArgs.GetDataDirNet() / "settings.json").std_path());
|
||||
std::string default_warning = strprintf("This file is automatically generated and updated by %s. Please do not edit this file while the node "
|
||||
"is running, as any changes might be ignored or overwritten.",
|
||||
CLIENT_NAME);
|
||||
|
||||
@@ -51,37 +51,37 @@ BOOST_AUTO_TEST_CASE(fsbridge_fstream)
|
||||
fs::path tmpfile1 = tmpfolder / fs::u8path("fs_tests_₿_🏃");
|
||||
fs::path tmpfile2 = tmpfolder / fs::path(u8"fs_tests_₿_🏃");
|
||||
{
|
||||
std::ofstream file{tmpfile1};
|
||||
std::ofstream file{tmpfile1.std_path()};
|
||||
file << "bitcoin";
|
||||
}
|
||||
{
|
||||
std::ifstream file{tmpfile2};
|
||||
std::ifstream file{tmpfile2.std_path()};
|
||||
std::string input_buffer;
|
||||
file >> input_buffer;
|
||||
BOOST_CHECK_EQUAL(input_buffer, "bitcoin");
|
||||
}
|
||||
{
|
||||
std::ifstream file{tmpfile1, std::ios_base::in | std::ios_base::ate};
|
||||
std::ifstream file{tmpfile1.std_path(), std::ios_base::in | std::ios_base::ate};
|
||||
std::string input_buffer;
|
||||
file >> input_buffer;
|
||||
BOOST_CHECK_EQUAL(input_buffer, "");
|
||||
}
|
||||
{
|
||||
std::ofstream file{tmpfile2, std::ios_base::out | std::ios_base::app};
|
||||
std::ofstream file{tmpfile2.std_path(), std::ios_base::out | std::ios_base::app};
|
||||
file << "tests";
|
||||
}
|
||||
{
|
||||
std::ifstream file{tmpfile1};
|
||||
std::ifstream file{tmpfile1.std_path()};
|
||||
std::string input_buffer;
|
||||
file >> input_buffer;
|
||||
BOOST_CHECK_EQUAL(input_buffer, "bitcointests");
|
||||
}
|
||||
{
|
||||
std::ofstream file{tmpfile2, std::ios_base::out | std::ios_base::trunc};
|
||||
std::ofstream file{tmpfile2.std_path(), std::ios_base::out | std::ios_base::trunc};
|
||||
file << "bitcoin";
|
||||
}
|
||||
{
|
||||
std::ifstream file{tmpfile1};
|
||||
std::ifstream file{tmpfile1.std_path()};
|
||||
std::string input_buffer;
|
||||
file >> input_buffer;
|
||||
BOOST_CHECK_EQUAL(input_buffer, "bitcoin");
|
||||
@@ -116,12 +116,12 @@ BOOST_AUTO_TEST_CASE(rename)
|
||||
const std::string path2_contents{"2222"};
|
||||
|
||||
{
|
||||
std::ofstream file{path1};
|
||||
std::ofstream file{path1.std_path()};
|
||||
file << path1_contents;
|
||||
}
|
||||
|
||||
{
|
||||
std::ofstream file{path2};
|
||||
std::ofstream file{path2.std_path()};
|
||||
file << path2_contents;
|
||||
}
|
||||
|
||||
@@ -131,7 +131,7 @@ BOOST_AUTO_TEST_CASE(rename)
|
||||
BOOST_CHECK(!fs::exists(path1));
|
||||
|
||||
{
|
||||
std::ifstream file{path2};
|
||||
std::ifstream file{path2.std_path()};
|
||||
std::string contents;
|
||||
file >> contents;
|
||||
BOOST_CHECK_EQUAL(contents, path1_contents);
|
||||
|
||||
@@ -40,7 +40,7 @@ static void ResetLogger()
|
||||
static std::vector<std::string> ReadDebugLogLines()
|
||||
{
|
||||
std::vector<std::string> lines;
|
||||
std::ifstream ifs{LogInstance().m_file_path};
|
||||
std::ifstream ifs{LogInstance().m_file_path.std_path()};
|
||||
for (std::string line; std::getline(ifs, line);) {
|
||||
lines.push_back(std::move(line));
|
||||
}
|
||||
@@ -421,7 +421,7 @@ void TestLogFromLocation(Location location, const std::string& message,
|
||||
using Status = BCLog::LogRateLimiter::Status;
|
||||
if (!suppressions_active) assert(status == Status::UNSUPPRESSED); // developer error
|
||||
|
||||
std::ofstream ofs(LogInstance().m_file_path, std::ios::out | std::ios::trunc); // clear debug log
|
||||
std::ofstream ofs(LogInstance().m_file_path.std_path(), std::ios::out | std::ios::trunc); // clear debug log
|
||||
LogFromLocation(location, message);
|
||||
auto log_lines{ReadDebugLogLines()};
|
||||
BOOST_TEST_INFO_SCOPE(log_lines.size() << " log_lines read: \n" << util::Join(log_lines, "\n"));
|
||||
|
||||
@@ -159,7 +159,7 @@ BOOST_AUTO_TEST_CASE(script_assets_test)
|
||||
bool exists = fs::exists(path);
|
||||
BOOST_WARN_MESSAGE(exists, "File $DIR_UNIT_TEST_DATA/script_assets_test.json not found, skipping script_assets_test");
|
||||
if (!exists) return;
|
||||
std::ifstream file{path};
|
||||
std::ifstream file{path.std_path()};
|
||||
BOOST_CHECK(file.is_open());
|
||||
file.seekg(0, std::ios::end);
|
||||
size_t length = file.tellg();
|
||||
|
||||
@@ -1619,7 +1619,7 @@ BOOST_AUTO_TEST_CASE(util_ReadBinaryFile)
|
||||
expected_text += "0123456789";
|
||||
}
|
||||
{
|
||||
std::ofstream file{tmpfile};
|
||||
std::ofstream file{tmpfile.std_path()};
|
||||
file << expected_text;
|
||||
}
|
||||
{
|
||||
@@ -1650,7 +1650,7 @@ BOOST_AUTO_TEST_CASE(util_WriteBinaryFile)
|
||||
std::string expected_text = "bitcoin";
|
||||
auto valid = WriteBinaryFile(tmpfile, expected_text);
|
||||
std::string actual_text;
|
||||
std::ifstream file{tmpfile};
|
||||
std::ifstream file{tmpfile.std_path()};
|
||||
file >> actual_text;
|
||||
BOOST_CHECK(valid);
|
||||
BOOST_CHECK_EQUAL(actual_text, expected_text);
|
||||
|
||||
@@ -34,6 +34,10 @@ class path : public std::filesystem::path
|
||||
public:
|
||||
using std::filesystem::path::path;
|
||||
|
||||
// Convenience method for accessing standard path type without needing a cast.
|
||||
std::filesystem::path& std_path() { return *this; }
|
||||
const std::filesystem::path& std_path() const { return *this; }
|
||||
|
||||
// Allow path objects arguments for compatibility.
|
||||
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; }
|
||||
@@ -54,6 +58,12 @@ public:
|
||||
// Disallow std::string conversion method to avoid locale-dependent encoding on windows.
|
||||
std::string string() const = delete;
|
||||
|
||||
// Disallow implicit string conversion to ensure code is portable.
|
||||
// `string_type` may be `string` or `wstring` depending on the platform, so
|
||||
// using this conversion could result in code that compiles on unix but
|
||||
// fails to compile on windows, or vice versa.
|
||||
operator string_type() const = delete;
|
||||
|
||||
/**
|
||||
* Return a UTF-8 representation of the path as a std::string, for
|
||||
* compatibility with code using std::string. For code using the newer
|
||||
|
||||
@@ -102,7 +102,7 @@ bool IsBDBFile(const fs::path& path)
|
||||
if (ec) LogWarning("Error reading file_size: %s [%s]", ec.message(), fs::PathToString(path));
|
||||
if (size < 4096) return false;
|
||||
|
||||
std::ifstream file{path, std::ios::binary};
|
||||
std::ifstream file{path.std_path(), std::ios::binary};
|
||||
if (!file.is_open()) return false;
|
||||
|
||||
file.seekg(12, std::ios::beg); // Magic bytes start at offset 12
|
||||
@@ -126,7 +126,7 @@ bool IsSQLiteFile(const fs::path& path)
|
||||
if (ec) LogWarning("Error reading file_size: %s [%s]", ec.message(), fs::PathToString(path));
|
||||
if (size < 512) return false;
|
||||
|
||||
std::ifstream file{path, std::ios::binary};
|
||||
std::ifstream file{path.std_path(), std::ios::binary};
|
||||
if (!file.is_open()) return false;
|
||||
|
||||
// Magic is at beginning and is 16 bytes long
|
||||
|
||||
@@ -134,7 +134,7 @@ bool CreateFromDump(const ArgsManager& args, const std::string& name, const fs::
|
||||
error = strprintf(_("Dump file %s does not exist."), fs::PathToString(dump_path));
|
||||
return false;
|
||||
}
|
||||
std::ifstream dump_file{dump_path};
|
||||
std::ifstream dump_file{dump_path.std_path()};
|
||||
|
||||
// Compute the checksum
|
||||
HashWriter hasher{};
|
||||
|
||||
@@ -36,7 +36,7 @@ InitWalletDirTestingSetup::InitWalletDirTestingSetup(const ChainType chainType)
|
||||
fs::create_directories(m_walletdir_path_cases["default"]);
|
||||
fs::create_directories(m_walletdir_path_cases["custom"]);
|
||||
fs::create_directories(m_walletdir_path_cases["relative"]);
|
||||
std::ofstream f{m_walletdir_path_cases["file"]};
|
||||
std::ofstream f{m_walletdir_path_cases["file"].std_path()};
|
||||
f.close();
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user