Bitcoin ABC  0.26.3
P2P Digital Currency
fs.h
Go to the documentation of this file.
1 // Copyright (c) 2017 The Bitcoin Core developers
2 // Distributed under the MIT software license, see the accompanying
3 // file COPYING or http://www.opensource.org/licenses/mit-license.php.
4 
5 #ifndef BITCOIN_FS_H
6 #define BITCOIN_FS_H
7 
8 #include <cstdio>
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>
16 #include <tinyformat.h>
17 
19 namespace fs {
20 
21 using namespace boost::filesystem;
22 
33 class path : public boost::filesystem::path {
34 public:
35  using boost::filesystem::path::path;
36  // Allow path objects arguments for compatibility.
37  path(boost::filesystem::path path)
38  : boost::filesystem::path::path(std::move(path)) {}
39  path &operator=(boost::filesystem::path path) {
40  boost::filesystem::path::operator=(std::move(path));
41  return *this;
42  }
43  path &operator/=(boost::filesystem::path path) {
44  boost::filesystem::path::operator/=(std::move(path));
45  return *this;
46  }
47 
48  // Allow literal string arguments, which are safe as long as the literals
49  // are ASCII.
50  path(const char *c) : boost::filesystem::path(c) {}
51  path &operator=(const char *c) {
52  boost::filesystem::path::operator=(c);
53  return *this;
54  }
55  path &operator/=(const char *c) {
56  boost::filesystem::path::operator/=(c);
57  return *this;
58  }
59  path &append(const char *c) {
60  boost::filesystem::path::append(c);
61  return *this;
62  }
63 
64  // Disallow std::string arguments to avoid locale-dependent decoding on
65  // windows.
66  path(std::string) = delete;
67  path &operator=(std::string) = delete;
68  path &operator/=(std::string) = delete;
69  path &append(std::string) = delete;
70 
71  // Disallow std::string conversion method to avoid locale-dependent encoding
72  // on windows.
73  std::string string() const = delete;
74 
75  // Define UTF-8 string conversion method not present in boost::filesystem
76  // but present in std::filesystem.
77  std::string u8string() const { return boost::filesystem::path::string(); }
78 };
79 
80 // Define UTF-8 string conversion function not present in boost::filesystem but
81 // present in std::filesystem.
82 static inline path u8path(const std::string &string) {
83  return boost::filesystem::path(string);
84 }
85 
86 // Disallow implicit std::string conversion for system_complete to avoid
87 // locale-dependent encoding on windows.
88 static inline path system_complete(const path &p) {
90 }
91 
92 // Disallow implicit std::string conversion for exists to avoid
93 // locale-dependent encoding on windows.
94 static inline bool exists(const path &p) {
95  return boost::filesystem::exists(p);
96 }
97 
98 // Allow explicit quoted stream I/O.
99 static inline auto quoted(const std::string &s) {
100  return boost::io::quoted(s, '&');
101 }
102 
103 // Allow safe path append operations.
104 static inline path operator+(path p1, path p2) {
105  p1 += static_cast<boost::filesystem::path &&>(p2);
106  return p1;
107 }
108 
134 static inline std::string PathToString(const path &path) {
135 #ifdef WIN32
136  return path.u8string();
137 #else
138  static_assert(std::is_same<path::string_type, std::string>::value,
139  "PathToString not implemented on this platform");
140  return path.boost::filesystem::path::string();
141 #endif
142 }
143 
147 static inline path PathFromString(const std::string &string) {
148 #ifdef WIN32
149  return u8path(string);
150 #else
151  return boost::filesystem::path(string);
152 #endif
153 }
154 } // namespace fs
155 
157 namespace fsbridge {
158 FILE *fopen(const fs::path &p, const char *mode);
159 FILE *freopen(const fs::path &p, const char *mode, FILE *stream);
160 
171 fs::path AbsPathJoin(const fs::path &base, const fs::path &path);
172 
173 class FileLock {
174 public:
175  FileLock() = delete;
176  FileLock(const FileLock &) = delete;
177  FileLock(FileLock &&) = delete;
178  explicit FileLock(const fs::path &file);
179  ~FileLock();
180  bool TryLock();
181  std::string GetReason() { return reason; }
182 
183 private:
184  std::string reason;
185 #ifndef WIN32
186  int fd = -1;
187 #else
188  // INVALID_HANDLE_VALUE
189  void *hFile = (void *)-1;
190 #endif
191 };
192 
193 std::string get_filesystem_error_message(const fs::filesystem_error &e);
194 
195 // GNU libstdc++ specific workaround for opening UTF-8 paths on Windows.
196 //
197 // On Windows, it is only possible to reliably access multibyte file paths
198 // through `wchar_t` APIs, not `char` APIs. But because the C++ standard doesn't
199 // require ifstream/ofstream `wchar_t` constructors, and the GNU library doesn't
200 // provide them (in contrast to the Microsoft C++ library, see
201 // https://stackoverflow.com/questions/821873/how-to-open-an-stdfstream-ofstream-or-ifstream-with-a-unicode-filename/822032#822032),
202 // Boost is forced to fall back to `char` constructors which may not work
203 // properly.
204 //
205 // Work around this issue by creating stream objects with `_wfopen` in
206 // combination with `__gnu_cxx::stdio_filebuf`. This workaround can be removed
207 // with an upgrade to C++17, where streams can be constructed directly from
208 // `std::filesystem::path` objects.
209 
210 #if defined WIN32 && defined __GLIBCXX__
211 class ifstream : public std::istream {
212 public:
213  ifstream() = default;
214  explicit ifstream(const fs::path &p,
215  std::ios_base::openmode mode = std::ios_base::in) {
216  open(p, mode);
217  }
218  ~ifstream() { close(); }
219  void open(const fs::path &p,
220  std::ios_base::openmode mode = std::ios_base::in);
221  bool is_open() { return m_filebuf.is_open(); }
222  void close();
223 
224 private:
225  __gnu_cxx::stdio_filebuf<char> m_filebuf;
226  FILE *m_file = nullptr;
227 };
228 class ofstream : public std::ostream {
229 public:
230  ofstream() = default;
231  explicit ofstream(const fs::path &p,
232  std::ios_base::openmode mode = std::ios_base::out) {
233  open(p, mode);
234  }
235  ~ofstream() { close(); }
236  void open(const fs::path &p,
237  std::ios_base::openmode mode = std::ios_base::out);
238  bool is_open() { return m_filebuf.is_open(); }
239  void close();
240 
241 private:
242  __gnu_cxx::stdio_filebuf<char> m_filebuf;
243  FILE *m_file = nullptr;
244 };
245 #else // !(WIN32 && __GLIBCXX__)
248 #endif // WIN32 && __GLIBCXX__
249 }; // namespace fsbridge
250 
251 // Disallow path operator<< formatting in tinyformat to avoid locale-dependent
252 // encoding on windows.
253 namespace tinyformat {
254 template <>
255 inline void formatValue(std::ostream &, const char *, const char *, int,
256  const boost::filesystem::path &) = delete;
257 template <>
258 inline void formatValue(std::ostream &, const char *, const char *, int,
259  const fs::path &) = delete;
260 } // namespace tinyformat
261 
262 #endif // BITCOIN_FS_H
Path class wrapper to prepare application code for transition from boost::filesystem library to std::...
Definition: fs.h:33
path & append(const char *c)
Definition: fs.h:59
std::string string() const =delete
std::string u8string() const
Definition: fs.h:77
path & append(std::string)=delete
path & operator=(std::string)=delete
path & operator=(const char *c)
Definition: fs.h:51
path & operator/=(std::string)=delete
path(boost::filesystem::path path)
Definition: fs.h:37
path(std::string)=delete
path & operator/=(const char *c)
Definition: fs.h:55
path & operator/=(boost::filesystem::path path)
Definition: fs.h:43
path & operator=(boost::filesystem::path path)
Definition: fs.h:39
path(const char *c)
Definition: fs.h:50
FileLock(FileLock &&)=delete
FileLock(const FileLock &)=delete
std::string reason
Definition: fs.h:184
std::string GetReason()
Definition: fs.h:181
Filesystem operations and types.
Definition: fs.h:19
static path system_complete(const path &p)
Definition: fs.h:88
static path u8path(const std::string &string)
Definition: fs.h:82
static auto quoted(const std::string &s)
Definition: fs.h:99
static bool exists(const path &p)
Definition: fs.h:94
static std::string PathToString(const path &path)
Convert path object to byte string.
Definition: fs.h:134
static path PathFromString(const std::string &string)
Convert byte string to path object.
Definition: fs.h:147
static path operator+(path p1, path p2)
Definition: fs.h:104
Bridge operations to C stdio.
Definition: fs.cpp:25
fs::ofstream ofstream
Definition: fs.h:247
FILE * fopen(const fs::path &p, const char *mode)
Definition: fs.cpp:27
std::string get_filesystem_error_message(const fs::filesystem_error &e)
Definition: fs.cpp:139
fs::path AbsPathJoin(const fs::path &base, const fs::path &path)
Helper function for joining two paths.
Definition: fs.cpp:36
FILE * freopen(const fs::path &p, const char *mode, FILE *stream)
fs::ifstream ifstream
Definition: fs.h:246
Definition: fs.h:253
void formatValue(std::ostream &, const char *, const char *, int, const fs::path &)=delete