aboutsummaryrefslogtreecommitdiff
path: root/src/fs.h
diff options
context:
space:
mode:
Diffstat (limited to 'src/fs.h')
-rw-r--r--src/fs.h154
1 files changed, 60 insertions, 94 deletions
diff --git a/src/fs.h b/src/fs.h
index 9f18794539..00b786453c 100644
--- a/src/fs.h
+++ b/src/fs.h
@@ -5,46 +5,42 @@
#ifndef BITCOIN_FS_H
#define BITCOIN_FS_H
-#include <stdio.h>
-#include <string>
-#if defined WIN32 && defined __GLIBCXX__
-#include <ext/stdio_filebuf.h>
-#endif
-
-#include <boost/filesystem.hpp>
-#include <boost/filesystem/fstream.hpp>
#include <tinyformat.h>
+#include <cstdio>
+#include <filesystem>
+#include <iomanip>
+#include <ios>
+#include <ostream>
+#include <string>
+#include <utility>
+
/** 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,34 +51,30 @@ 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 <fstream>.
+ // 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.
@@ -94,13 +86,13 @@ static inline path operator+(path p1, path p2)
// 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<path::string_type, std::string>::value, "PathToString not implemented on this platform");
- return path.boost::filesystem::path::string();
+ return path.std::filesystem::path::string();
#endif
}
@@ -145,9 +137,31 @@ 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
}
+
+/**
+ * Create directory (and if necessary its parents), unless the leaf directory
+ * already exists or is a symlink to an existing directory.
+ * This is a temporary workaround for an issue in libstdc++ that has been fixed
+ * upstream [PR101510].
+ */
+static inline bool create_directories(const std::filesystem::path& p)
+{
+ if (std::filesystem::is_symlink(p) && std::filesystem::is_directory(p)) {
+ return false;
+ }
+ return std::filesystem::create_directories(p);
+}
+
+/**
+ * This variant is not used. Delete it to prevent it from accidentally working
+ * around the workaround. If it is needed, add a workaround in the same pattern
+ * as above.
+ */
+bool create_directories(const std::filesystem::path& p, std::error_code& ec) = delete;
+
} // namespace fs
/** Bridge operations to C stdio */
@@ -186,60 +200,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<char> 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<char> 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