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