Bitcoin Core  24.99.0
P2P Digital Currency
fs.h
Go to the documentation of this file.
1 // Copyright (c) 2017-2022 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 <tinyformat.h>
9 
10 #include <cstdio>
11 #include <filesystem>
12 #include <functional>
13 #include <iomanip>
14 #include <ios>
15 #include <ostream>
16 #include <string>
17 #include <utility>
18 
20 namespace fs {
21 
22 using namespace std::filesystem;
23 
30 class path : public std::filesystem::path
31 {
32 public:
33  using std::filesystem::path::path;
34 
35  // Allow path objects arguments for compatibility.
36  path(std::filesystem::path path) : std::filesystem::path::path(std::move(path)) {}
37  path& operator=(std::filesystem::path path) { std::filesystem::path::operator=(std::move(path)); return *this; }
38  path& operator/=(std::filesystem::path path) { std::filesystem::path::operator/=(path); return *this; }
39 
40  // Allow literal string arguments, which are safe as long as the literals are ASCII.
41  path(const char* c) : std::filesystem::path(c) {}
42  path& operator=(const char* c) { std::filesystem::path::operator=(c); return *this; }
43  path& operator/=(const char* c) { std::filesystem::path::operator/=(c); return *this; }
44  path& append(const char* c) { std::filesystem::path::append(c); return *this; }
45 
46  // Disallow std::string arguments to avoid locale-dependent decoding on windows.
47  path(std::string) = delete;
48  path& operator=(std::string) = delete;
49  path& operator/=(std::string) = delete;
50  path& append(std::string) = delete;
51 
52  // Disallow std::string conversion method to avoid locale-dependent encoding on windows.
53  std::string string() const = delete;
54 
55  std::string u8string() const
56  {
57  const auto& utf8_str{std::filesystem::path::u8string()};
58  // utf8_str might either be std::string (C++17) or std::u8string
59  // (C++20). Convert both to std::string. This method can be removed
60  // after switching to C++20.
61  return std::string{utf8_str.begin(), utf8_str.end()};
62  }
63 
64  // Required for path overloads in <fstream>.
65  // See https://gcc.gnu.org/git/?p=gcc.git;a=commit;h=96e0367ead5d8dcac3bec2865582e76e2fbab190
66  path& make_preferred() { std::filesystem::path::make_preferred(); return *this; }
67  path filename() const { return std::filesystem::path::filename(); }
68 };
69 
70 static inline path u8path(const std::string& utf8_str)
71 {
72 #if __cplusplus < 202002L
73  return std::filesystem::u8path(utf8_str);
74 #else
75  return std::filesystem::path(std::u8string{utf8_str.begin(), utf8_str.end()});
76 #endif
77 }
78 
79 // Disallow implicit std::string conversion for absolute to avoid
80 // locale-dependent encoding on windows.
81 static inline path absolute(const path& p)
82 {
83  return std::filesystem::absolute(p);
84 }
85 
86 // Disallow implicit std::string conversion for exists to avoid
87 // locale-dependent encoding on windows.
88 static inline bool exists(const path& p)
89 {
90  return std::filesystem::exists(p);
91 }
92 
93 // Allow explicit quoted stream I/O.
94 static inline auto quoted(const std::string& s)
95 {
96  return std::quoted(s, '"', '&');
97 }
98 
99 // Allow safe path append operations.
100 static inline path operator/(path p1, path p2)
101 {
102  p1 /= std::move(p2);
103  return p1;
104 }
105 static inline path operator/(path p1, const char* p2)
106 {
107  p1 /= p2;
108  return p1;
109 }
110 static inline path operator+(path p1, const char* p2)
111 {
112  p1 += p2;
113  return p1;
114 }
115 static inline path operator+(path p1, path::value_type p2)
116 {
117  p1 += p2;
118  return p1;
119 }
120 
121 // Disallow unsafe path append operations.
122 template<typename T> static inline path operator/(path p1, T p2) = delete;
123 template<typename T> static inline path operator+(path p1, T p2) = delete;
124 
125 // Disallow implicit std::string conversion for copy_file
126 // to avoid locale-dependent encoding on Windows.
127 static inline bool copy_file(const path& from, const path& to, copy_options options)
128 {
129  return std::filesystem::copy_file(from, to, options);
130 }
131 
150 static inline std::string PathToString(const path& path)
151 {
152  // Implementation note: On Windows, the std::filesystem::path(string)
153  // constructor and std::filesystem::path::string() method are not safe to
154  // use here, because these methods encode the path using C++'s narrow
155  // multibyte encoding, which on Windows corresponds to the current "code
156  // page", which is unpredictable and typically not able to represent all
157  // valid paths. So fs::path::u8string() and
158  // fs::u8path() functions are used instead on Windows. On
159  // POSIX, u8string/u8path functions are not safe to use because paths are
160  // not always valid UTF-8, so plain string methods which do not transform
161  // the path there are used.
162 #ifdef WIN32
163  return path.u8string();
164 #else
165  static_assert(std::is_same<path::string_type, std::string>::value, "PathToString not implemented on this platform");
166  return path.std::filesystem::path::string();
167 #endif
168 }
169 
173 static inline path PathFromString(const std::string& string)
174 {
175 #ifdef WIN32
176  return u8path(string);
177 #else
178  return std::filesystem::path(string);
179 #endif
180 }
181 
188 static inline bool create_directories(const std::filesystem::path& p)
189 {
190  if (std::filesystem::is_symlink(p) && std::filesystem::is_directory(p)) {
191  return false;
192  }
194 }
195 
201 bool create_directories(const std::filesystem::path& p, std::error_code& ec) = delete;
202 
203 } // namespace fs
204 
206 namespace fsbridge {
207  using FopenFn = std::function<FILE*(const fs::path&, const char*)>;
208  FILE *fopen(const fs::path& p, const char *mode);
209 
219  fs::path AbsPathJoin(const fs::path& base, const fs::path& path);
220 
221  class FileLock
222  {
223  public:
224  FileLock() = delete;
225  FileLock(const FileLock&) = delete;
226  FileLock(FileLock&&) = delete;
227  explicit FileLock(const fs::path& file);
228  ~FileLock();
229  bool TryLock();
230  std::string GetReason() { return reason; }
231 
232  private:
233  std::string reason;
234 #ifndef WIN32
235  int fd = -1;
236 #else
237  void* hFile = (void*)-1; // INVALID_HANDLE_VALUE
238 #endif
239  };
240 
241  std::string get_filesystem_error_message(const fs::filesystem_error& e);
242 };
243 
244 // Disallow path operator<< formatting in tinyformat to avoid locale-dependent
245 // encoding on windows.
246 namespace tinyformat {
247 template<> inline void formatValue(std::ostream&, const char*, const char*, int, const std::filesystem::path&) = delete;
248 template<> inline void formatValue(std::ostream&, const char*, const char*, int, const fs::path&) = delete;
249 } // namespace tinyformat
250 
251 #endif // BITCOIN_FS_H
Path class wrapper to block calls to the fs::path(std::string) implicit constructor and the fs::path:...
Definition: fs.h:31
path & append(const char *c)
Definition: fs.h:44
path(std::filesystem::path path)
Definition: fs.h:36
path & make_preferred()
Definition: fs.h:66
std::string string() const =delete
std::string u8string() const
Definition: fs.h:55
path & append(std::string)=delete
path & operator=(std::string)=delete
path & operator=(std::filesystem::path path)
Definition: fs.h:37
path & operator=(const char *c)
Definition: fs.h:42
path & operator/=(std::string)=delete
path(std::string)=delete
path & operator/=(const char *c)
Definition: fs.h:43
path filename() const
Definition: fs.h:67
path & operator/=(std::filesystem::path path)
Definition: fs.h:38
path(const char *c)
Definition: fs.h:41
FileLock(FileLock &&)=delete
FileLock(const FileLock &)=delete
std::string reason
Definition: fs.h:233
std::string GetReason()
Definition: fs.h:230
Filesystem operations and types.
Definition: fs.h:20
bool create_directories(const std::filesystem::path &p, std::error_code &ec)=delete
This variant is not used.
static path absolute(const path &p)
Definition: fs.h:81
static path u8path(const std::string &utf8_str)
Definition: fs.h:70
static bool create_directories(const std::filesystem::path &p)
Create directory (and if necessary its parents), unless the leaf directory already exists or is a sym...
Definition: fs.h:188
static auto quoted(const std::string &s)
Definition: fs.h:94
static bool exists(const path &p)
Definition: fs.h:88
static bool copy_file(const path &from, const path &to, copy_options options)
Definition: fs.h:127
static std::string PathToString(const path &path)
Convert path object to a byte string.
Definition: fs.h:150
static path PathFromString(const std::string &string)
Convert byte string to path object.
Definition: fs.h:173
static path operator+(path p1, const char *p2)
Definition: fs.h:110
static path operator/(path p1, path p2)
Definition: fs.h:100
Bridge operations to C stdio.
Definition: fs.cpp:23
FILE * fopen(const fs::path &p, const char *mode)
Definition: fs.cpp:25
std::string get_filesystem_error_message(const fs::filesystem_error &e)
Definition: fs.cpp:122
fs::path AbsPathJoin(const fs::path &base, const fs::path &path)
Helper function for joining two paths.
Definition: fs.cpp:35
std::function< FILE *(const fs::path &, const char *)> FopenFn
Definition: fs.h:207
Definition: fs.h:246
void formatValue(std::ostream &, const char *, const char *, int, const fs::path &)=delete