Bitcoin Core  0.19.99
P2P Digital Currency
fs.cpp
Go to the documentation of this file.
1 // Copyright (c) 2017-2019 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 #include <fs.h>
6 
7 #ifndef WIN32
8 #include <fcntl.h>
9 #else
10 #ifndef NOMINMAX
11 #define NOMINMAX
12 #endif
13 #include <codecvt>
14 #include <windows.h>
15 #endif
16 
17 namespace fsbridge {
18 
19 FILE *fopen(const fs::path& p, const char *mode)
20 {
21 #ifndef WIN32
22  return ::fopen(p.string().c_str(), mode);
23 #else
24  std::wstring_convert<std::codecvt_utf8_utf16<wchar_t>,wchar_t> utf8_cvt;
25  return ::_wfopen(p.wstring().c_str(), utf8_cvt.from_bytes(mode).c_str());
26 #endif
27 }
28 
29 #ifndef WIN32
30 
31 static std::string GetErrorReason() {
32  return std::strerror(errno);
33 }
34 
35 FileLock::FileLock(const fs::path& file)
36 {
37  fd = open(file.string().c_str(), O_RDWR);
38  if (fd == -1) {
40  }
41 }
42 
44 {
45  if (fd != -1) {
46  close(fd);
47  }
48 }
49 
51 {
52  if (fd == -1) {
53  return false;
54  }
55  struct flock lock;
56  lock.l_type = F_WRLCK;
57  lock.l_whence = SEEK_SET;
58  lock.l_start = 0;
59  lock.l_len = 0;
60  if (fcntl(fd, F_SETLK, &lock) == -1) {
62  return false;
63  }
64  return true;
65 }
66 #else
67 
68 static std::string GetErrorReason() {
69  wchar_t* err;
70  FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
71  nullptr, GetLastError(), MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), reinterpret_cast<WCHAR*>(&err), 0, nullptr);
72  std::wstring err_str(err);
73  LocalFree(err);
74  return std::wstring_convert<std::codecvt_utf8_utf16<wchar_t>>().to_bytes(err_str);
75 }
76 
77 FileLock::FileLock(const fs::path& file)
78 {
79  hFile = CreateFileW(file.wstring().c_str(), GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
80  nullptr, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, nullptr);
81  if (hFile == INVALID_HANDLE_VALUE) {
83  }
84 }
85 
87 {
88  if (hFile != INVALID_HANDLE_VALUE) {
89  CloseHandle(hFile);
90  }
91 }
92 
93 bool FileLock::TryLock()
94 {
95  if (hFile == INVALID_HANDLE_VALUE) {
96  return false;
97  }
98  _OVERLAPPED overlapped = {0};
99  if (!LockFileEx(hFile, LOCKFILE_EXCLUSIVE_LOCK | LOCKFILE_FAIL_IMMEDIATELY, 0, std::numeric_limits<DWORD>::max(), std::numeric_limits<DWORD>::max(), &overlapped)) {
101  return false;
102  }
103  return true;
104 }
105 #endif
106 
107 std::string get_filesystem_error_message(const fs::filesystem_error& e)
108 {
109 #ifndef WIN32
110  return e.what();
111 #else
112  // Convert from Multi Byte to utf-16
113  std::string mb_string(e.what());
114  int size = MultiByteToWideChar(CP_ACP, 0, mb_string.data(), mb_string.size(), nullptr, 0);
115 
116  std::wstring utf16_string(size, L'\0');
117  MultiByteToWideChar(CP_ACP, 0, mb_string.data(), mb_string.size(), &*utf16_string.begin(), size);
118  // Convert from utf-16 to utf-8
119  return std::wstring_convert<std::codecvt_utf8_utf16<wchar_t>, wchar_t>().to_bytes(utf16_string);
120 #endif
121 }
122 
123 #ifdef WIN32
124 #ifdef __GLIBCXX__
125 
126 // reference: https://github.com/gcc-mirror/gcc/blob/gcc-7_3_0-release/libstdc%2B%2B-v3/include/std/fstream#L270
127 
128 static std::string openmodeToStr(std::ios_base::openmode mode)
129 {
130  switch (mode & ~std::ios_base::ate) {
131  case std::ios_base::out:
132  case std::ios_base::out | std::ios_base::trunc:
133  return "w";
134  case std::ios_base::out | std::ios_base::app:
135  case std::ios_base::app:
136  return "a";
137  case std::ios_base::in:
138  return "r";
139  case std::ios_base::in | std::ios_base::out:
140  return "r+";
141  case std::ios_base::in | std::ios_base::out | std::ios_base::trunc:
142  return "w+";
143  case std::ios_base::in | std::ios_base::out | std::ios_base::app:
144  case std::ios_base::in | std::ios_base::app:
145  return "a+";
146  case std::ios_base::out | std::ios_base::binary:
147  case std::ios_base::out | std::ios_base::trunc | std::ios_base::binary:
148  return "wb";
149  case std::ios_base::out | std::ios_base::app | std::ios_base::binary:
150  case std::ios_base::app | std::ios_base::binary:
151  return "ab";
152  case std::ios_base::in | std::ios_base::binary:
153  return "rb";
154  case std::ios_base::in | std::ios_base::out | std::ios_base::binary:
155  return "r+b";
156  case std::ios_base::in | std::ios_base::out | std::ios_base::trunc | std::ios_base::binary:
157  return "w+b";
158  case std::ios_base::in | std::ios_base::out | std::ios_base::app | std::ios_base::binary:
159  case std::ios_base::in | std::ios_base::app | std::ios_base::binary:
160  return "a+b";
161  default:
162  return std::string();
163  }
164 }
165 
166 void ifstream::open(const fs::path& p, std::ios_base::openmode mode)
167 {
168  close();
169  mode |= std::ios_base::in;
170  m_file = fsbridge::fopen(p, openmodeToStr(mode).c_str());
171  if (m_file == nullptr) {
172  return;
173  }
174  m_filebuf = __gnu_cxx::stdio_filebuf<char>(m_file, mode);
175  rdbuf(&m_filebuf);
176  if (mode & std::ios_base::ate) {
177  seekg(0, std::ios_base::end);
178  }
179 }
180 
181 void ifstream::close()
182 {
183  if (m_file != nullptr) {
184  m_filebuf.close();
185  fclose(m_file);
186  }
187  m_file = nullptr;
188 }
189 
190 void ofstream::open(const fs::path& p, std::ios_base::openmode mode)
191 {
192  close();
193  mode |= std::ios_base::out;
194  m_file = fsbridge::fopen(p, openmodeToStr(mode).c_str());
195  if (m_file == nullptr) {
196  return;
197  }
198  m_filebuf = __gnu_cxx::stdio_filebuf<char>(m_file, mode);
199  rdbuf(&m_filebuf);
200  if (mode & std::ios_base::ate) {
201  seekp(0, std::ios_base::end);
202  }
203 }
204 
205 void ofstream::close()
206 {
207  if (m_file != nullptr) {
208  m_filebuf.close();
209  fclose(m_file);
210  }
211  m_file = nullptr;
212 }
213 #else // __GLIBCXX__
214 
215 static_assert(sizeof(*fs::path().BOOST_FILESYSTEM_C_STR) == sizeof(wchar_t),
216  "Warning: This build is using boost::filesystem ofstream and ifstream "
217  "implementations which will fail to open paths containing multibyte "
218  "characters. You should delete this static_assert to ignore this warning, "
219  "or switch to a different C++ standard library like the Microsoft C++ "
220  "Standard Library (where boost uses non-standard extensions to construct "
221  "stream objects with wide filenames), or the GNU libstdc++ library (where "
222  "a more complicated workaround has been implemented above).");
223 
224 #endif // __GLIBCXX__
225 #endif // WIN32
226 
227 } // fsbridge
FILE * fopen(const fs::path &p, const char *mode)
Definition: fs.cpp:19
std::string reason
Definition: fs.h:36
Filesystem operations and types.
Definition: fs.cpp:17
static std::string GetErrorReason()
Definition: fs.cpp:31
std::string get_filesystem_error_message(const fs::filesystem_error &e)
Definition: fs.cpp:107
bool TryLock()
Definition: fs.cpp:50