From a3b79267e02e407d2980451b7bb6d53e194fdcfb Mon Sep 17 00:00:00 2001 From: Kittywhiskers Van Gogh <63189531+kwvg@users.noreply.github.com> Date: Tue, 6 Aug 2024 17:40:56 +0000 Subject: [PATCH] merge bitcoin#20744: Use std::filesystem. Remove Boost Filesystem & System --- build-aux/m4/ax_boost_filesystem.m4 | 118 --------------- build-aux/m4/l_filesystem.m4 | 47 ++++++ ci/test/00_setup_env_native_asan.sh | 2 +- ci/test/00_setup_env_native_fuzz.sh | 2 +- .../00_setup_env_native_fuzz_with_valgrind.sh | 2 +- ci/test/00_setup_env_native_ubsan.sh | 2 +- ci/test/00_setup_env_native_valgrind.sh | 2 +- configure.ac | 7 +- contrib/valgrind.supp | 21 --- depends/packages/boost.mk | 2 +- doc/build-unix.md | 2 +- src/addrdb.cpp | 1 + src/bench/bench.cpp | 3 +- src/fs.cpp | 110 +------------- src/fs.h | 134 +++++------------- src/init.cpp | 9 +- src/logging.cpp | 1 + src/logging.h | 1 + src/net.cpp | 1 + src/qt/guiutil.cpp | 9 +- src/qt/psbtoperationsdialog.cpp | 5 +- src/qt/sendcoinsdialog.cpp | 7 +- src/qt/walletframe.cpp | 5 +- src/rpc/request.cpp | 9 +- src/test/fs_tests.cpp | 18 ++- src/test/fuzz/fuzz.cpp | 6 +- src/test/script_tests.cpp | 3 +- src/test/settings_tests.cpp | 8 +- src/test/streams_tests.cpp | 1 + src/test/util_tests.cpp | 4 + src/util/asmap.cpp | 1 + src/util/settings.cpp | 10 +- src/util/system.cpp | 41 +++--- src/wallet/bdb.cpp | 5 +- src/wallet/db.cpp | 22 +-- src/wallet/dump.cpp | 12 +- src/wallet/dump.h | 3 + src/wallet/load.cpp | 6 +- src/wallet/rpcdump.cpp | 12 +- src/wallet/test/db_tests.cpp | 7 +- src/wallet/test/init_test_fixture.cpp | 9 +- src/wallet/test/init_tests.cpp | 3 + src/wallet/wallet.cpp | 21 ++- src/wallet/walletdb.cpp | 2 +- test/functional/wallet_multiwallet.py | 3 +- test/lint/lint-includes.sh | 2 - 46 files changed, 264 insertions(+), 437 deletions(-) delete mode 100644 build-aux/m4/ax_boost_filesystem.m4 create mode 100644 build-aux/m4/l_filesystem.m4 diff --git a/build-aux/m4/ax_boost_filesystem.m4 b/build-aux/m4/ax_boost_filesystem.m4 deleted file mode 100644 index 12f7bc5e2e..0000000000 --- a/build-aux/m4/ax_boost_filesystem.m4 +++ /dev/null @@ -1,118 +0,0 @@ -# =========================================================================== -# https://www.gnu.org/software/autoconf-archive/ax_boost_filesystem.html -# =========================================================================== -# -# SYNOPSIS -# -# AX_BOOST_FILESYSTEM -# -# DESCRIPTION -# -# Test for Filesystem library from the Boost C++ libraries. The macro -# requires a preceding call to AX_BOOST_BASE. Further documentation is -# available at . -# -# This macro calls: -# -# AC_SUBST(BOOST_FILESYSTEM_LIB) -# -# And sets: -# -# HAVE_BOOST_FILESYSTEM -# -# LICENSE -# -# Copyright (c) 2009 Thomas Porschberg -# Copyright (c) 2009 Michael Tindal -# Copyright (c) 2009 Roman Rybalko -# -# Copying and distribution of this file, with or without modification, are -# permitted in any medium without royalty provided the copyright notice -# and this notice are preserved. This file is offered as-is, without any -# warranty. - -#serial 28 - -AC_DEFUN([AX_BOOST_FILESYSTEM], -[ - AC_ARG_WITH([boost-filesystem], - AS_HELP_STRING([--with-boost-filesystem@<:@=special-lib@:>@], - [use the Filesystem library from boost - it is possible to specify a certain library for the linker - e.g. --with-boost-filesystem=boost_filesystem-gcc-mt ]), - [ - if test "$withval" = "no"; then - want_boost="no" - elif test "$withval" = "yes"; then - want_boost="yes" - ax_boost_user_filesystem_lib="" - else - want_boost="yes" - ax_boost_user_filesystem_lib="$withval" - fi - ], - [want_boost="yes"] - ) - - if test "x$want_boost" = "xyes"; then - AC_REQUIRE([AC_PROG_CC]) - CPPFLAGS_SAVED="$CPPFLAGS" - CPPFLAGS="$CPPFLAGS $BOOST_CPPFLAGS" - export CPPFLAGS - - LDFLAGS_SAVED="$LDFLAGS" - LDFLAGS="$LDFLAGS $BOOST_LDFLAGS" - export LDFLAGS - - LIBS_SAVED=$LIBS - LIBS="$LIBS $BOOST_SYSTEM_LIB" - export LIBS - - AC_CACHE_CHECK(whether the Boost::Filesystem library is available, - ax_cv_boost_filesystem, - [AC_LANG_PUSH([C++]) - AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[@%:@include ]], - [[using namespace boost::filesystem; - path my_path( "foo/bar/data.txt" ); - return 0;]])], - ax_cv_boost_filesystem=yes, ax_cv_boost_filesystem=no) - AC_LANG_POP([C++]) - ]) - if test "x$ax_cv_boost_filesystem" = "xyes"; then - AC_DEFINE(HAVE_BOOST_FILESYSTEM,,[define if the Boost::Filesystem library is available]) - BOOSTLIBDIR=`echo $BOOST_LDFLAGS | sed -e 's/@<:@^\/@:>@*//'` - if test "x$ax_boost_user_filesystem_lib" = "x"; then - for libextension in `ls -r $BOOSTLIBDIR/libboost_filesystem* 2>/dev/null | sed 's,.*/lib,,' | sed 's,\..*,,'` ; do - ax_lib=${libextension} - AC_CHECK_LIB($ax_lib, exit, - [BOOST_FILESYSTEM_LIB="-l$ax_lib"; AC_SUBST(BOOST_FILESYSTEM_LIB) link_filesystem="yes"; break], - [link_filesystem="no"]) - done - if test "x$link_filesystem" != "xyes"; then - for libextension in `ls -r $BOOSTLIBDIR/boost_filesystem* 2>/dev/null | sed 's,.*/,,' | sed -e 's,\..*,,'` ; do - ax_lib=${libextension} - AC_CHECK_LIB($ax_lib, exit, - [BOOST_FILESYSTEM_LIB="-l$ax_lib"; AC_SUBST(BOOST_FILESYSTEM_LIB) link_filesystem="yes"; break], - [link_filesystem="no"]) - done - fi - else - for ax_lib in $ax_boost_user_filesystem_lib boost_filesystem-$ax_boost_user_filesystem_lib; do - AC_CHECK_LIB($ax_lib, exit, - [BOOST_FILESYSTEM_LIB="-l$ax_lib"; AC_SUBST(BOOST_FILESYSTEM_LIB) link_filesystem="yes"; break], - [link_filesystem="no"]) - done - - fi - if test "x$ax_lib" = "x"; then - AC_MSG_ERROR(Could not find a version of the Boost::Filesystem library!) - fi - if test "x$link_filesystem" != "xyes"; then - AC_MSG_ERROR(Could not link against $ax_lib !) - fi - fi - - CPPFLAGS="$CPPFLAGS_SAVED" - LDFLAGS="$LDFLAGS_SAVED" - LIBS="$LIBS_SAVED" - fi -]) diff --git a/build-aux/m4/l_filesystem.m4 b/build-aux/m4/l_filesystem.m4 new file mode 100644 index 0000000000..ca3a0cd41c --- /dev/null +++ b/build-aux/m4/l_filesystem.m4 @@ -0,0 +1,47 @@ +dnl Copyright (c) 2022 The Bitcoin Core developers +dnl Distributed under the MIT software license, see the accompanying +dnl file COPYING or http://www.opensource.org/licenses/mit-license.php. + +# GCC 8.1 and earlier requires -lstdc++fs +# Clang 8.0.0 (libc++) and earlier requires -lc++fs + +m4_define([_CHECK_FILESYSTEM_testbody], [[ + #include + + namespace fs = std::filesystem; + + int main() { + (void)fs::current_path().root_name(); + return 0; + } +]]) + +AC_DEFUN([CHECK_FILESYSTEM], [ + + AC_LANG_PUSH(C++) + + AC_MSG_CHECKING([whether std::filesystem can be used without link library]) + + AC_LINK_IFELSE([AC_LANG_SOURCE([_CHECK_FILESYSTEM_testbody])],[ + AC_MSG_RESULT([yes]) + ],[ + AC_MSG_RESULT([no]) + SAVED_LIBS="$LIBS" + LIBS="$SAVED_LIBS -lstdc++fs" + AC_MSG_CHECKING([whether std::filesystem needs -lstdc++fs]) + AC_LINK_IFELSE([AC_LANG_SOURCE([_CHECK_FILESYSTEM_testbody])],[ + AC_MSG_RESULT([yes]) + ],[ + AC_MSG_RESULT([no]) + AC_MSG_CHECKING([whether std::filesystem needs -lc++fs]) + LIBS="$SAVED_LIBS -lc++fs" + AC_LINK_IFELSE([AC_LANG_SOURCE([_CHECK_FILESYSTEM_testbody])],[ + AC_MSG_RESULT([yes]) + ],[ + AC_MSG_FAILURE([cannot figure out how to use std::filesystem]) + ]) + ]) + ]) + + AC_LANG_POP +]) diff --git a/ci/test/00_setup_env_native_asan.sh b/ci/test/00_setup_env_native_asan.sh index fc143b7e0f..bd8ed03dae 100755 --- a/ci/test/00_setup_env_native_asan.sh +++ b/ci/test/00_setup_env_native_asan.sh @@ -6,7 +6,7 @@ export LC_ALL=C.UTF-8 -export PACKAGES="clang llvm python3-zmq qtbase5-dev qttools5-dev-tools libevent-dev bsdmainutils libboost-dev libboost-filesystem-dev libboost-test-dev libdb5.3++-dev libminiupnpc-dev libzmq3-dev libqrencode-dev" +export PACKAGES="clang llvm python3-zmq qtbase5-dev qttools5-dev-tools libevent-dev bsdmainutils libboost-dev libboost-test-dev libdb5.3++-dev libminiupnpc-dev libzmq3-dev libqrencode-dev" export NO_DEPENDS=1 export TEST_RUNNER_EXTRA="--timeout-factor=4" # Increase timeout because sanitizers slow down export FUNCTIONAL_TESTS_CONFIG="--exclude wallet_multiwallet.py" # Temporarily suppress ASan heap-use-after-free (see issue #14163) diff --git a/ci/test/00_setup_env_native_fuzz.sh b/ci/test/00_setup_env_native_fuzz.sh index ae27e61a0b..dfd311590d 100755 --- a/ci/test/00_setup_env_native_fuzz.sh +++ b/ci/test/00_setup_env_native_fuzz.sh @@ -7,7 +7,7 @@ export LC_ALL=C.UTF-8 export CONTAINER_NAME=ci_native_fuzz -export PACKAGES="clang llvm python3 libevent-dev bsdmainutils libboost-dev libboost-filesystem-dev libboost-test-dev" +export PACKAGES="clang llvm python3 libevent-dev bsdmainutils libboost-dev libboost-test-dev" export DEP_OPTS="NO_UPNP=1 DEBUG=1" export CPPFLAGS="-DDEBUG_LOCKORDER -DARENA_DEBUG" export CXXFLAGS="-Werror -Wno-unused-command-line-argument -Wno-unused-value -Wno-deprecated-builtins" diff --git a/ci/test/00_setup_env_native_fuzz_with_valgrind.sh b/ci/test/00_setup_env_native_fuzz_with_valgrind.sh index 4ba4feea49..94b2de61ed 100755 --- a/ci/test/00_setup_env_native_fuzz_with_valgrind.sh +++ b/ci/test/00_setup_env_native_fuzz_with_valgrind.sh @@ -7,7 +7,7 @@ export LC_ALL=C.UTF-8 export CONTAINER_NAME=ci_native_fuzz_valgrind -export PACKAGES="clang llvm python3 libevent-dev bsdmainutils libboost-dev libboost-system-dev libboost-filesystem-dev libboost-test-dev valgrind" +export PACKAGES="clang llvm python3 libevent-dev bsdmainutils libboost-dev libboost-test-dev valgrind" export NO_DEPENDS=1 export RUN_UNIT_TESTS=false export RUN_FUNCTIONAL_TESTS=false diff --git a/ci/test/00_setup_env_native_ubsan.sh b/ci/test/00_setup_env_native_ubsan.sh index 153bc6a760..4787f4c578 100755 --- a/ci/test/00_setup_env_native_ubsan.sh +++ b/ci/test/00_setup_env_native_ubsan.sh @@ -8,7 +8,7 @@ export LC_ALL=C.UTF-8 export CONTAINER_NAME=ci_native_ubsan -export PACKAGES="clang-16 llvm-16 python3-zmq qtbase5-dev qttools5-dev-tools libevent-dev bsdmainutils libboost-filesystem-dev libboost-test-dev libboost-thread-dev libdb5.3++-dev libminiupnpc-dev libzmq3-dev libqrencode-dev" +export PACKAGES="clang-16 llvm-16 python3-zmq qtbase5-dev qttools5-dev-tools libevent-dev bsdmainutils libboost-test-dev libboost-thread-dev libdb5.3++-dev libminiupnpc-dev libzmq3-dev libqrencode-dev" export DEP_OPTS="NO_UPNP=1 DEBUG=1" export GOAL="install" export BITCOIN_CONFIG="--enable-zmq --enable-reduce-exports --enable-crash-hooks --with-sanitizers=undefined CC=clang-16 CXX=clang++-16" diff --git a/ci/test/00_setup_env_native_valgrind.sh b/ci/test/00_setup_env_native_valgrind.sh index 64dfd64d22..e1a66240d7 100755 --- a/ci/test/00_setup_env_native_valgrind.sh +++ b/ci/test/00_setup_env_native_valgrind.sh @@ -6,7 +6,7 @@ export LC_ALL=C.UTF-8 -export PACKAGES="valgrind clang llvm python3-zmq libevent-dev bsdmainutils libboost-dev libboost-system-dev libboost-filesystem-dev libboost-test-dev libdb5.3++-dev libminiupnpc-dev libzmq3-dev" +export PACKAGES="valgrind clang llvm python3-zmq libevent-dev bsdmainutils libboost-dev libboost-test-dev libdb5.3++-dev libminiupnpc-dev libzmq3-dev" export USE_VALGRIND=1 export NO_DEPENDS=1 export TEST_RUNNER_EXTRA="--exclude rpc_bind --timeout-factor=4" # Excluded for now, see https://github.com/bitcoin/bitcoin/issues/17765#issuecomment-602068547 diff --git a/configure.ac b/configure.ac index 96419244fd..4ffa815080 100644 --- a/configure.ac +++ b/configure.ac @@ -82,6 +82,9 @@ fi dnl Check if -latomic is required for CHECK_ATOMIC +dnl check if additional link flags are required for std::filesystem +CHECK_FILESYSTEM + dnl Unless the user specified OBJCXX, force it to be the same as CXX. This ensures dnl that we get the same -std flags for both. m4_ifdef([AC_PROG_OBJCXX],[ @@ -1472,8 +1475,6 @@ dnl and will generate warnings with newer compilers. dnl See: https://github.com/boostorg/container_hash/issues/22. BOOST_CPPFLAGS="$BOOST_CPPFLAGS -DBOOST_NO_CXX98_FUNCTION_BASE" -AX_BOOST_FILESYSTEM - dnl Opt-in to Boost Process if test "x$boost_process" != xno; then AC_MSG_CHECKING(for Boost Process) @@ -1488,7 +1489,7 @@ if test x$suppress_external_warnings != xno; then BOOST_CPPFLAGS=SUPPRESS_WARNINGS($BOOST_CPPFLAGS) fi -BOOST_LIBS="$BOOST_LDFLAGS $BOOST_SYSTEM_LIB $BOOST_FILESYSTEM_LIB" +BOOST_LIBS="$BOOST_LDFLAGS" fi dnl Check for reduced exports diff --git a/contrib/valgrind.supp b/contrib/valgrind.supp index d2c904743d..5f546b3c4a 100644 --- a/contrib/valgrind.supp +++ b/contrib/valgrind.supp @@ -118,12 +118,6 @@ fun:__wcsnlen_sse4_1 fun:wcsnrtombs } -{ - Suppress wcsnrtombs warning (remove after removing boost::fs) - Memcheck:Cond - ... - fun:_ZN5boost10filesystem6detail11unique_pathERKNS0_4pathEPNS_6system10error_codeE -} { Suppress boost warning Memcheck:Leak @@ -134,21 +128,6 @@ fun:_ZN5boost9unit_test14unit_test_mainEPFbvEiPPc fun:main } -{ - Suppress boost::filesystem warning (fixed in boost 1.70: https://github.com/boostorg/filesystem/commit/bbe9d1771e5d679b3f10c42a58fc81f7e8c024a9) - Memcheck:Cond - fun:_ZN5boost10filesystem6detail28directory_iterator_incrementERNS0_18directory_iteratorEPNS_6system10error_codeE - ... - obj:*/libboost_filesystem.so.* -} -{ - Suppress boost::filesystem warning (could be related: https://stackoverflow.com/questions/9830182/function-boostfilesystemcomplete-being-reported-as-possible-memory-leak-by-v) - Memcheck:Leak - match-leak-kinds: reachable - fun:_Znwm - ... - fun:_ZN5boost10filesystem8absoluteERKNS0_4pathES3_ -} { Suppress boost still reachable memory warning Memcheck:Leak diff --git a/depends/packages/boost.mk b/depends/packages/boost.mk index 2dc955b99f..ce6092e809 100644 --- a/depends/packages/boost.mk +++ b/depends/packages/boost.mk @@ -26,7 +26,7 @@ $(package)_toolset_$(host_os)=clang else $(package)_toolset_$(host_os)=gcc endif -$(package)_config_libraries=filesystem,test +$(package)_config_libraries=test $(package)_cxxflags+=-std=c++11 $(package)_cxxflags_linux=-fPIC $(package)_cxxflags_freebsd=-fPIC diff --git a/doc/build-unix.md b/doc/build-unix.md index 12ee3088a5..cee03262d0 100644 --- a/doc/build-unix.md +++ b/doc/build-unix.md @@ -81,7 +81,7 @@ sudo apt-get install build-essential libtool autotools-dev automake pkg-config b Now, you can either build from self-compiled [depends](/depends/README.md) or install the required dependencies: ```sh -sudo apt-get install libevent-dev libboost-dev libboost-system-dev libboost-filesystem-dev libboost-test-dev +sudo apt-get install libevent-dev libboost-dev libboost-test-dev ``` SQLite is required for the descriptor wallet: diff --git a/src/addrdb.cpp b/src/addrdb.cpp index dbca156cb8..23dd88893c 100644 --- a/src/addrdb.cpp +++ b/src/addrdb.cpp @@ -8,6 +8,7 @@ #include #include #include +#include #include #include #include diff --git a/src/bench/bench.cpp b/src/bench/bench.cpp index 011bed4206..d3de4c62e4 100644 --- a/src/bench/bench.cpp +++ b/src/bench/bench.cpp @@ -10,6 +10,7 @@ #include #include +#include #include #include @@ -23,7 +24,7 @@ void GenerateTemplateResults(const std::vector& bench // 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 { diff --git a/src/fs.cpp b/src/fs.cpp index 0551c95cef..d70da9df5b 100644 --- a/src/fs.cpp +++ b/src/fs.cpp @@ -37,7 +37,7 @@ FILE *fopen(const fs::path& p, const char *mode) 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 @@ -153,112 +153,4 @@ std::string get_filesystem_error_message(const fs::filesystem_error& e) #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 - } // fsbridge diff --git a/src/fs.h b/src/fs.h index 241097124c..7d24346848 100644 --- a/src/fs.h +++ b/src/fs.h @@ -5,46 +5,42 @@ #ifndef BITCOIN_FS_H #define BITCOIN_FS_H -#include -#include -#if defined WIN32 && defined __GLIBCXX__ -#include -#endif - -#include -#include #include +#include +#include +#include +#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)); return *this; } - path& operator/=(boost::filesystem::path path) { boost::filesystem::path::operator/=(std::move(path)); return *this; } + 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/=(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& operator=(const char* c) { boost::filesystem::path::operator=(c); return *this; } - path& operator/=(const char* c) { boost::filesystem::path::operator/=(c); return *this; } - path& append(const char* c) { boost::filesystem::path::append(c); return *this; } + path(const char* c) : std::filesystem::path(c) {} + path& operator=(const char* c) { std::filesystem::path::operator=(c); return *this; } + path& operator/=(const char* c) { std::filesystem::path::operator/=(c); return *this; } + path& append(const char* c) { std::filesystem::path::append(c); return *this; } // Disallow std::string arguments to avoid locale-dependent decoding on windows. path(std::string) = delete; @@ -55,52 +51,48 @@ public: // 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) +static inline path absolute(const path& p) { - return boost::filesystem::system_complete(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 void copy_file(const path& from, const path& to, copy_option options) +static inline bool copy_file(const path& from, const path& to, copy_options options) { - boost::filesystem::copy_file(from, to, 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 @@ -112,7 +104,7 @@ static inline void copy_file(const path& from, const path& to, copy_option optio * appropriate to use in applications requiring UTF-8, where * fs::path::u8string() and fs::u8path() methods should be used instead. Other * applications could require still different encodings. For example, JSON, XML, - * or URI applications might prefer to use higher level escapes (\uXXXX or + * or URI applications might prefer to use higher-level escapes (\uXXXX or * &XXXX; or %XX) instead of multibyte encoding. Rust, Python, Java applications * may require encoding paths with their respective UTF-8 derivatives WTF-8, * PEP-383, and CESU-8 (see https://en.wikipedia.org/wiki/UTF-8#Derivatives). @@ -133,7 +125,7 @@ static inline std::string PathToString(const path& path) 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 } @@ -145,7 +137,7 @@ 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 @@ -186,60 +178,12 @@ namespace fsbridge { }; 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__ }; // 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; +template<> inline void formatValue(std::ostream&, const char*, const char*, int, const std::filesystem::path&) = delete; template<> inline void formatValue(std::ostream&, const char*, const char*, int, const fs::path&) = delete; } // namespace tinyformat diff --git a/src/init.cpp b/src/init.cpp index 6c69b4a4f9..6a57dc4650 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -105,12 +105,15 @@ #include +#include +#include +#include +#include #include #include -#include -#include #include #include +#include #include #include @@ -159,7 +162,7 @@ static fs::path GetPidFile(const ArgsManager& args) [[nodiscard]] static bool CreatePidFile(const ArgsManager& args) { - fsbridge::ofstream file{GetPidFile(args)}; + std::ofstream file{GetPidFile(args)}; if (file) { #ifdef WIN32 tfm::format(file, "%d\n", GetCurrentProcessId()); diff --git a/src/logging.cpp b/src/logging.cpp index 32a3add84a..24f5d4afa7 100644 --- a/src/logging.cpp +++ b/src/logging.cpp @@ -3,6 +3,7 @@ // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. +#include #include #include #include diff --git a/src/logging.h b/src/logging.h index 6cf696f3d0..d71ed5f5e3 100644 --- a/src/logging.h +++ b/src/logging.h @@ -13,6 +13,7 @@ #include #include +#include #include #include #include diff --git a/src/net.cpp b/src/net.cpp index 33a6c2e000..560875b85d 100644 --- a/src/net.cpp +++ b/src/net.cpp @@ -17,6 +17,7 @@ #include #include #include +#include #include #include #include diff --git a/src/qt/guiutil.cpp b/src/qt/guiutil.cpp index ca82f017cb..1ea68d896c 100644 --- a/src/qt/guiutil.cpp +++ b/src/qt/guiutil.cpp @@ -15,6 +15,7 @@ #include #include +#include #include #include #include @@ -77,6 +78,10 @@ #include #include +#include +#include +#include +#include #if defined(Q_OS_MAC) @@ -810,7 +815,7 @@ fs::path static GetAutostartFilePath() bool GetStartOnSystemStartup() { - fsbridge::ifstream optionFile(GetAutostartFilePath()); + std::ifstream optionFile{GetAutostartFilePath()}; if (!optionFile.good()) return false; // Scan through file for "Hidden=true": @@ -842,7 +847,7 @@ bool SetStartOnSystemStartup(bool fAutoStart) fs::create_directories(GetAutostartDir()); - fsbridge::ofstream optionFile(GetAutostartFilePath(), std::ios_base::out | std::ios_base::trunc); + std::ofstream optionFile{GetAutostartFilePath(), std::ios_base::out | std::ios_base::trunc}; if (!optionFile.good()) return false; std::string chain = gArgs.GetChainName(); diff --git a/src/qt/psbtoperationsdialog.cpp b/src/qt/psbtoperationsdialog.cpp index 7c550f274f..bb642d1f1b 100644 --- a/src/qt/psbtoperationsdialog.cpp +++ b/src/qt/psbtoperationsdialog.cpp @@ -5,6 +5,7 @@ #include #include +#include #include #include #include @@ -15,7 +16,9 @@ #include #include +#include #include +#include PSBTOperationsDialog::PSBTOperationsDialog( @@ -150,7 +153,7 @@ void PSBTOperationsDialog::saveTransaction() { if (filename.isEmpty()) { return; } - fsbridge::ofstream out{filename.toLocal8Bit().data(), fsbridge::ofstream::out | fsbridge::ofstream::binary}; + std::ofstream out{filename.toLocal8Bit().data(), std::ofstream::out | std::ofstream::binary}; out << ssTx.str(); out.close(); showStatus(tr("PSBT saved to disk."), StatusLevel::INFO); diff --git a/src/qt/sendcoinsdialog.cpp b/src/qt/sendcoinsdialog.cpp index cab794a071..2e07c40241 100644 --- a/src/qt/sendcoinsdialog.cpp +++ b/src/qt/sendcoinsdialog.cpp @@ -27,9 +27,12 @@ #include #include #include - #include +#include +#include +#include + #include #include #include @@ -521,7 +524,7 @@ void SendCoinsDialog::sendButtonClicked([[maybe_unused]] bool checked) if (filename.isEmpty()) { return; } - fsbridge::ofstream out{filename.toLocal8Bit().data(), fsbridge::ofstream::out | fsbridge::ofstream::binary}; + std::ofstream out{filename.toLocal8Bit().data(), std::ofstream::out | std::ofstream::binary}; out << ssTx.str(); out.close(); Q_EMIT message(tr("PSBT saved"), "PSBT saved to disk", CClientUIInterface::MSG_INFORMATION); diff --git a/src/qt/walletframe.cpp b/src/qt/walletframe.cpp index 7b2a9fa7a9..bc313e2f33 100644 --- a/src/qt/walletframe.cpp +++ b/src/qt/walletframe.cpp @@ -4,6 +4,7 @@ #include +#include #include #include #include @@ -19,6 +20,8 @@ #include #include +#include +#include #include #include @@ -285,7 +288,7 @@ void WalletFrame::gotoLoadPSBT(bool from_clipboard) Q_EMIT message(tr("Error"), tr("PSBT file must be smaller than 100 MiB"), CClientUIInterface::MSG_ERROR); return; } - fsbridge::ifstream in{filename.toLocal8Bit().data(), std::ios::binary}; + std::ifstream in{filename.toLocal8Bit().data(), std::ios::binary}; data = std::string(std::istreambuf_iterator{in}, {}); } diff --git a/src/rpc/request.cpp b/src/rpc/request.cpp index dd83c45a59..773323fc97 100644 --- a/src/rpc/request.cpp +++ b/src/rpc/request.cpp @@ -12,6 +12,11 @@ #include #include +#include +#include +#include +#include + /** * JSON-RPC protocol. Bitcoin speaks version 1.0 for maximum compatibility, * but uses JSON-RPC 1.1/2.0 standards for parts of the 1.0 standard that were @@ -83,7 +88,7 @@ bool GenerateAuthCookie(std::string *cookie_out) /** the umask determines what permissions are used to create this file - * these are set to 077 in init.cpp unless overridden with -sysperms. */ - fsbridge::ofstream file; + std::ofstream file; fs::path filepath_tmp = GetAuthCookieFile(true); file.open(filepath_tmp); if (!file.is_open()) { @@ -107,7 +112,7 @@ bool GenerateAuthCookie(std::string *cookie_out) bool GetAuthCookie(std::string *cookie_out) { - fsbridge::ifstream file; + std::ifstream file; std::string cookie; fs::path filepath = GetAuthCookieFile(); file.open(filepath); diff --git a/src/test/fs_tests.cpp b/src/test/fs_tests.cpp index dc0dc659e2..27ca4c1089 100644 --- a/src/test/fs_tests.cpp +++ b/src/test/fs_tests.cpp @@ -9,6 +9,10 @@ #include +#include +#include +#include + BOOST_FIXTURE_TEST_SUITE(fs_tests, BasicTestingSetup) BOOST_AUTO_TEST_CASE(fsbridge_pathtostring) @@ -45,37 +49,37 @@ BOOST_AUTO_TEST_CASE(fsbridge_fstream) fs::path tmpfile1 = tmpfolder / "fs_tests_∋_🏃"; fs::path tmpfile2 = tmpfolder / "fs_tests_∋_🏃"; { - fsbridge::ofstream file(tmpfile1); + std::ofstream file{tmpfile1}; file << "bitcoin"; } { - fsbridge::ifstream file(tmpfile2); + std::ifstream file{tmpfile2}; std::string input_buffer; file >> input_buffer; BOOST_CHECK_EQUAL(input_buffer, "bitcoin"); } { - fsbridge::ifstream file(tmpfile1, std::ios_base::in | std::ios_base::ate); + std::ifstream file{tmpfile1, std::ios_base::in | std::ios_base::ate}; std::string input_buffer; file >> input_buffer; BOOST_CHECK_EQUAL(input_buffer, ""); } { - fsbridge::ofstream file(tmpfile2, std::ios_base::out | std::ios_base::app); + std::ofstream file{tmpfile2, std::ios_base::out | std::ios_base::app}; file << "tests"; } { - fsbridge::ifstream file(tmpfile1); + std::ifstream file{tmpfile1}; std::string input_buffer; file >> input_buffer; BOOST_CHECK_EQUAL(input_buffer, "bitcointests"); } { - fsbridge::ofstream file(tmpfile2, std::ios_base::out | std::ios_base::trunc); + std::ofstream file{tmpfile2, std::ios_base::out | std::ios_base::trunc}; file << "bitcoin"; } { - fsbridge::ifstream file(tmpfile1); + std::ifstream file{tmpfile1}; std::string input_buffer; file >> input_buffer; BOOST_CHECK_EQUAL(input_buffer, "bitcoin"); diff --git a/src/test/fuzz/fuzz.cpp b/src/test/fuzz/fuzz.cpp index 402d089d05..67b16f970a 100644 --- a/src/test/fuzz/fuzz.cpp +++ b/src/test/fuzz/fuzz.cpp @@ -4,6 +4,7 @@ #include +#include #include #include #include @@ -13,9 +14,10 @@ #include #include -#include #include +#include #include +#include #include #include @@ -59,7 +61,7 @@ void initialize() } if (const char* out_path = std::getenv("WRITE_ALL_FUZZ_TARGETS_AND_ABORT")) { std::cout << "Writing all fuzz target names to '" << out_path << "'." << std::endl; - fsbridge::ofstream out_stream{out_path, std::ios::binary}; + std::ofstream out_stream{out_path, std::ios::binary}; for (const auto& t : FuzzTargets()) { if (std::get<2>(t.second)) continue; out_stream << t.first << std::endl; diff --git a/src/test/script_tests.cpp b/src/test/script_tests.cpp index 4c98149d2e..eb598b6ea4 100644 --- a/src/test/script_tests.cpp +++ b/src/test/script_tests.cpp @@ -20,7 +20,8 @@ #include