Skip to content

Commit 41d7166

Browse files
kiminuoryanofskyhebasto
authored andcommitted
refactor: replace boost::filesystem with std::filesystem
Warning: Replacing fs::system_complete calls with fs::absolute calls in this commit may cause minor changes in behaviour because fs::absolute no longer strips trailing slashes; however these changes are believed to be safe. Co-authored-by: Russell Yanofsky <[email protected]> Co-authored-by: Hennadii Stepanov <[email protected]>
1 parent ffc89d1 commit 41d7166

37 files changed

+195
-287
lines changed

src/addrdb.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
#include <chainparams.h>
1010
#include <clientversion.h>
1111
#include <cstdint>
12+
#include <fs.h>
1213
#include <hash.h>
1314
#include <logging/timer.h>
1415
#include <netbase.h>

src/bench/bench.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
#include <test/util/setup_common.h>
99

1010
#include <chrono>
11+
#include <fstream>
1112
#include <functional>
1213
#include <iostream>
1314
#include <map>
@@ -29,7 +30,7 @@ void GenerateTemplateResults(const std::vector<ankerl::nanobench::Result>& bench
2930
// nothing to write, bail out
3031
return;
3132
}
32-
fsbridge::ofstream fout{fs::PathFromString(filename)};
33+
std::ofstream fout{fs::PathFromString(filename)};
3334
if (fout.is_open()) {
3435
ankerl::nanobench::render(tpl, benchmarkResults, fout);
3536
} else {

src/fs.cpp

Lines changed: 1 addition & 115 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ FILE *fopen(const fs::path& p, const char *mode)
3737
fs::path AbsPathJoin(const fs::path& base, const fs::path& path)
3838
{
3939
assert(base.is_absolute());
40-
return fs::absolute(path, base);
40+
return path.empty() ? base : fs::path(base / path);
4141
}
4242

4343
#ifndef WIN32
@@ -153,118 +153,4 @@ std::string get_filesystem_error_message(const fs::filesystem_error& e)
153153
#endif
154154
}
155155

156-
#ifdef WIN32
157-
#ifdef __GLIBCXX__
158-
159-
// reference: https://github.com/gcc-mirror/gcc/blob/gcc-7_3_0-release/libstdc%2B%2B-v3/include/std/fstream#L270
160-
#if defined(__GNUC__) && !defined(__clang__)
161-
#pragma GCC diagnostic push
162-
#pragma GCC diagnostic ignored "-Wswitch"
163-
#endif
164-
static std::string openmodeToStr(std::ios_base::openmode mode)
165-
{
166-
switch (mode & ~std::ios_base::ate) {
167-
case std::ios_base::out:
168-
case std::ios_base::out | std::ios_base::trunc:
169-
return "w";
170-
case std::ios_base::out | std::ios_base::app:
171-
case std::ios_base::app:
172-
return "a";
173-
case std::ios_base::in:
174-
return "r";
175-
case std::ios_base::in | std::ios_base::out:
176-
return "r+";
177-
case std::ios_base::in | std::ios_base::out | std::ios_base::trunc:
178-
return "w+";
179-
case std::ios_base::in | std::ios_base::out | std::ios_base::app:
180-
case std::ios_base::in | std::ios_base::app:
181-
return "a+";
182-
case std::ios_base::out | std::ios_base::binary:
183-
case std::ios_base::out | std::ios_base::trunc | std::ios_base::binary:
184-
return "wb";
185-
case std::ios_base::out | std::ios_base::app | std::ios_base::binary:
186-
case std::ios_base::app | std::ios_base::binary:
187-
return "ab";
188-
case std::ios_base::in | std::ios_base::binary:
189-
return "rb";
190-
case std::ios_base::in | std::ios_base::out | std::ios_base::binary:
191-
return "r+b";
192-
case std::ios_base::in | std::ios_base::out | std::ios_base::trunc | std::ios_base::binary:
193-
return "w+b";
194-
case std::ios_base::in | std::ios_base::out | std::ios_base::app | std::ios_base::binary:
195-
case std::ios_base::in | std::ios_base::app | std::ios_base::binary:
196-
return "a+b";
197-
default:
198-
return std::string();
199-
}
200-
}
201-
#if defined(__GNUC__) && !defined(__clang__)
202-
#pragma GCC diagnostic pop
203-
#endif
204-
205-
void ifstream::open(const fs::path& p, std::ios_base::openmode mode)
206-
{
207-
close();
208-
mode |= std::ios_base::in;
209-
m_file = fsbridge::fopen(p, openmodeToStr(mode).c_str());
210-
if (m_file == nullptr) {
211-
return;
212-
}
213-
m_filebuf = __gnu_cxx::stdio_filebuf<char>(m_file, mode);
214-
rdbuf(&m_filebuf);
215-
if (mode & std::ios_base::ate) {
216-
seekg(0, std::ios_base::end);
217-
}
218-
}
219-
220-
void ifstream::close()
221-
{
222-
if (m_file != nullptr) {
223-
m_filebuf.close();
224-
fclose(m_file);
225-
}
226-
m_file = nullptr;
227-
}
228-
229-
void ofstream::open(const fs::path& p, std::ios_base::openmode mode)
230-
{
231-
close();
232-
mode |= std::ios_base::out;
233-
m_file = fsbridge::fopen(p, openmodeToStr(mode).c_str());
234-
if (m_file == nullptr) {
235-
return;
236-
}
237-
m_filebuf = __gnu_cxx::stdio_filebuf<char>(m_file, mode);
238-
rdbuf(&m_filebuf);
239-
if (mode & std::ios_base::ate) {
240-
seekp(0, std::ios_base::end);
241-
}
242-
}
243-
244-
void ofstream::close()
245-
{
246-
if (m_file != nullptr) {
247-
m_filebuf.close();
248-
fclose(m_file);
249-
}
250-
m_file = nullptr;
251-
}
252-
#else // __GLIBCXX__
253-
254-
#if BOOST_VERSION >= 107700
255-
static_assert(sizeof(*BOOST_FILESYSTEM_C_STR(boost::filesystem::path())) == sizeof(wchar_t),
256-
#else
257-
static_assert(sizeof(*boost::filesystem::path().BOOST_FILESYSTEM_C_STR) == sizeof(wchar_t),
258-
#endif // BOOST_VERSION >= 107700
259-
"Warning: This build is using boost::filesystem ofstream and ifstream "
260-
"implementations which will fail to open paths containing multibyte "
261-
"characters. You should delete this static_assert to ignore this warning, "
262-
"or switch to a different C++ standard library like the Microsoft C++ "
263-
"Standard Library (where boost uses non-standard extensions to construct "
264-
"stream objects with wide filenames), or the GNU libstdc++ library (where "
265-
"a more complicated workaround has been implemented above).");
266-
267-
#endif // __GLIBCXX__
268-
#endif // WIN32
269-
270156
} // fsbridge

src/fs.h

Lines changed: 39 additions & 95 deletions
Original file line numberDiff line numberDiff line change
@@ -5,46 +5,42 @@
55
#ifndef BITCOIN_FS_H
66
#define BITCOIN_FS_H
77

8-
#include <stdio.h>
9-
#include <string>
10-
#if defined WIN32 && defined __GLIBCXX__
11-
#include <ext/stdio_filebuf.h>
12-
#endif
13-
14-
#include <boost/filesystem.hpp>
15-
#include <boost/filesystem/fstream.hpp>
168
#include <tinyformat.h>
179

10+
#include <cstdio>
11+
#include <filesystem>
12+
#include <iomanip>
13+
#include <ios>
14+
#include <ostream>
15+
#include <string>
16+
#include <utility>
17+
1818
/** Filesystem operations and types */
1919
namespace fs {
2020

21-
using namespace boost::filesystem;
21+
using namespace std::filesystem;
2222

2323
/**
24-
* Path class wrapper to prepare application code for transition from
25-
* boost::filesystem library to std::filesystem implementation. The main
26-
* purpose of the class is to define fs::path::u8string() and fs::u8path()
27-
* functions not present in boost. It also blocks calls to the
28-
* fs::path(std::string) implicit constructor and the fs::path::string()
29-
* method, which worked well in the boost::filesystem implementation, but have
30-
* unsafe and unpredictable behavior on Windows in the std::filesystem
31-
* implementation (see implementation note in \ref PathToString for details).
24+
* Path class wrapper to block calls to the fs::path(std::string) implicit
25+
* constructor and the fs::path::string() method, which have unsafe and
26+
* unpredictable behavior on Windows (see implementation note in
27+
* \ref PathToString for details)
3228
*/
33-
class path : public boost::filesystem::path
29+
class path : public std::filesystem::path
3430
{
3531
public:
36-
using boost::filesystem::path::path;
32+
using std::filesystem::path::path;
3733

3834
// Allow path objects arguments for compatibility.
39-
path(boost::filesystem::path path) : boost::filesystem::path::path(std::move(path)) {}
40-
path& operator=(boost::filesystem::path path) { boost::filesystem::path::operator=(std::move(path)); return *this; }
41-
path& operator/=(boost::filesystem::path path) { boost::filesystem::path::operator/=(std::move(path)); return *this; }
35+
path(std::filesystem::path path) : std::filesystem::path::path(std::move(path)) {}
36+
path& operator=(std::filesystem::path path) { std::filesystem::path::operator=(std::move(path)); return *this; }
37+
path& operator/=(std::filesystem::path path) { std::filesystem::path::operator/=(std::move(path)); return *this; }
4238

4339
// Allow literal string arguments, which are safe as long as the literals are ASCII.
44-
path(const char* c) : boost::filesystem::path(c) {}
45-
path& operator=(const char* c) { boost::filesystem::path::operator=(c); return *this; }
46-
path& operator/=(const char* c) { boost::filesystem::path::operator/=(c); return *this; }
47-
path& append(const char* c) { boost::filesystem::path::append(c); return *this; }
40+
path(const char* c) : std::filesystem::path(c) {}
41+
path& operator=(const char* c) { std::filesystem::path::operator=(c); return *this; }
42+
path& operator/=(const char* c) { std::filesystem::path::operator/=(c); return *this; }
43+
path& append(const char* c) { std::filesystem::path::append(c); return *this; }
4844

4945
// Disallow std::string arguments to avoid locale-dependent decoding on windows.
5046
path(std::string) = delete;
@@ -55,52 +51,48 @@ class path : public boost::filesystem::path
5551
// Disallow std::string conversion method to avoid locale-dependent encoding on windows.
5652
std::string string() const = delete;
5753

58-
// Define UTF-8 string conversion method not present in boost::filesystem but present in std::filesystem.
59-
std::string u8string() const { return boost::filesystem::path::string(); }
54+
// Required for path overloads in <fstream>.
55+
// See https://gcc.gnu.org/git/?p=gcc.git;a=commit;h=96e0367ead5d8dcac3bec2865582e76e2fbab190
56+
path& make_preferred() { std::filesystem::path::make_preferred(); return *this; }
57+
path filename() const { return std::filesystem::path::filename(); }
6058
};
6159

62-
// Define UTF-8 string conversion function not present in boost::filesystem but present in std::filesystem.
63-
static inline path u8path(const std::string& string)
64-
{
65-
return boost::filesystem::path(string);
66-
}
67-
68-
// Disallow implicit std::string conversion for system_complete to avoid
60+
// Disallow implicit std::string conversion for absolute to avoid
6961
// locale-dependent encoding on windows.
70-
static inline path system_complete(const path& p)
62+
static inline path absolute(const path& p)
7163
{
72-
return boost::filesystem::system_complete(p);
64+
return std::filesystem::absolute(p);
7365
}
7466

7567
// Disallow implicit std::string conversion for exists to avoid
7668
// locale-dependent encoding on windows.
7769
static inline bool exists(const path& p)
7870
{
79-
return boost::filesystem::exists(p);
71+
return std::filesystem::exists(p);
8072
}
8173

8274
// Allow explicit quoted stream I/O.
8375
static inline auto quoted(const std::string& s)
8476
{
85-
return boost::io::quoted(s, '&');
77+
return std::quoted(s, '"', '&');
8678
}
8779

8880
// Allow safe path append operations.
8981
static inline path operator+(path p1, path p2)
9082
{
91-
p1 += static_cast<boost::filesystem::path&&>(p2);
83+
p1 += std::move(p2);
9284
return p1;
9385
}
9486

9587
// Disallow implicit std::string conversion for copy_file
9688
// to avoid locale-dependent encoding on Windows.
97-
static inline void copy_file(const path& from, const path& to, copy_option options)
89+
static inline bool copy_file(const path& from, const path& to, copy_options options)
9890
{
99-
boost::filesystem::copy_file(from, to, options);
91+
return std::filesystem::copy_file(from, to, options);
10092
}
10193

10294
/**
103-
* Convert path object to byte string. On POSIX, paths natively are byte
95+
* Convert path object to a byte string. On POSIX, paths natively are byte
10496
* strings, so this is trivial. On Windows, paths natively are Unicode, so an
10597
* encoding step is necessary. The inverse of \ref PathToString is \ref
10698
* 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
112104
* appropriate to use in applications requiring UTF-8, where
113105
* fs::path::u8string() and fs::u8path() methods should be used instead. Other
114106
* applications could require still different encodings. For example, JSON, XML,
115-
* or URI applications might prefer to use higher level escapes (\uXXXX or
107+
* or URI applications might prefer to use higher-level escapes (\uXXXX or
116108
* &XXXX; or %XX) instead of multibyte encoding. Rust, Python, Java applications
117109
* may require encoding paths with their respective UTF-8 derivatives WTF-8,
118110
* 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)
133125
return path.u8string();
134126
#else
135127
static_assert(std::is_same<path::string_type, std::string>::value, "PathToString not implemented on this platform");
136-
return path.boost::filesystem::path::string();
128+
return path.std::filesystem::path::string();
137129
#endif
138130
}
139131

@@ -145,7 +137,7 @@ static inline path PathFromString(const std::string& string)
145137
#ifdef WIN32
146138
return u8path(string);
147139
#else
148-
return boost::filesystem::path(string);
140+
return std::filesystem::path(string);
149141
#endif
150142
}
151143
} // namespace fs
@@ -186,60 +178,12 @@ namespace fsbridge {
186178
};
187179

188180
std::string get_filesystem_error_message(const fs::filesystem_error& e);
189-
190-
// GNU libstdc++ specific workaround for opening UTF-8 paths on Windows.
191-
//
192-
// On Windows, it is only possible to reliably access multibyte file paths through
193-
// `wchar_t` APIs, not `char` APIs. But because the C++ standard doesn't
194-
// require ifstream/ofstream `wchar_t` constructors, and the GNU library doesn't
195-
// provide them (in contrast to the Microsoft C++ library, see
196-
// https://stackoverflow.com/questions/821873/how-to-open-an-stdfstream-ofstream-or-ifstream-with-a-unicode-filename/822032#822032),
197-
// Boost is forced to fall back to `char` constructors which may not work properly.
198-
//
199-
// Work around this issue by creating stream objects with `_wfopen` in
200-
// combination with `__gnu_cxx::stdio_filebuf`. This workaround can be removed
201-
// with an upgrade to C++17, where streams can be constructed directly from
202-
// `std::filesystem::path` objects.
203-
204-
#if defined WIN32 && defined __GLIBCXX__
205-
class ifstream : public std::istream
206-
{
207-
public:
208-
ifstream() = default;
209-
explicit ifstream(const fs::path& p, std::ios_base::openmode mode = std::ios_base::in) { open(p, mode); }
210-
~ifstream() { close(); }
211-
void open(const fs::path& p, std::ios_base::openmode mode = std::ios_base::in);
212-
bool is_open() { return m_filebuf.is_open(); }
213-
void close();
214-
215-
private:
216-
__gnu_cxx::stdio_filebuf<char> m_filebuf;
217-
FILE* m_file = nullptr;
218-
};
219-
class ofstream : public std::ostream
220-
{
221-
public:
222-
ofstream() = default;
223-
explicit ofstream(const fs::path& p, std::ios_base::openmode mode = std::ios_base::out) { open(p, mode); }
224-
~ofstream() { close(); }
225-
void open(const fs::path& p, std::ios_base::openmode mode = std::ios_base::out);
226-
bool is_open() { return m_filebuf.is_open(); }
227-
void close();
228-
229-
private:
230-
__gnu_cxx::stdio_filebuf<char> m_filebuf;
231-
FILE* m_file = nullptr;
232-
};
233-
#else // !(WIN32 && __GLIBCXX__)
234-
typedef fs::ifstream ifstream;
235-
typedef fs::ofstream ofstream;
236-
#endif // WIN32 && __GLIBCXX__
237181
};
238182

239183
// Disallow path operator<< formatting in tinyformat to avoid locale-dependent
240184
// encoding on windows.
241185
namespace tinyformat {
242-
template<> inline void formatValue(std::ostream&, const char*, const char*, int, const boost::filesystem::path&) = delete;
186+
template<> inline void formatValue(std::ostream&, const char*, const char*, int, const std::filesystem::path&) = delete;
243187
template<> inline void formatValue(std::ostream&, const char*, const char*, int, const fs::path&) = delete;
244188
} // namespace tinyformat
245189

0 commit comments

Comments
 (0)