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