file_win32.ipp 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374
  1. //
  2. // Copyright (c) 2015-2019 Vinnie Falco (vinnie dot falco at gmail dot com)
  3. //
  4. // Distributed under the Boost Software License, Version 1.0. (See accompanying
  5. // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
  6. //
  7. // Official repository: https://github.com/boostorg/beast
  8. //
  9. #ifndef BOOST_BEAST_CORE_IMPL_FILE_WIN32_IPP
  10. #define BOOST_BEAST_CORE_IMPL_FILE_WIN32_IPP
  11. #include <boost/beast/core/file_win32.hpp>
  12. #if BOOST_BEAST_USE_WIN32_FILE
  13. #include <boost/beast/core/detail/win32_unicode_path.hpp>
  14. #include <boost/core/exchange.hpp>
  15. #include <boost/winapi/access_rights.hpp>
  16. #include <boost/winapi/error_codes.hpp>
  17. #include <boost/winapi/get_last_error.hpp>
  18. #include <limits>
  19. #include <utility>
  20. namespace boost {
  21. namespace beast {
  22. namespace detail {
  23. // VFALCO Can't seem to get boost/detail/winapi to work with
  24. // this so use the non-Ex version for now.
  25. BOOST_BEAST_DECL
  26. boost::winapi::BOOL_
  27. set_file_pointer_ex(
  28. boost::winapi::HANDLE_ hFile,
  29. boost::winapi::LARGE_INTEGER_ lpDistanceToMove,
  30. boost::winapi::PLARGE_INTEGER_ lpNewFilePointer,
  31. boost::winapi::DWORD_ dwMoveMethod)
  32. {
  33. auto dwHighPart = lpDistanceToMove.u.HighPart;
  34. auto dwLowPart = boost::winapi::SetFilePointer(
  35. hFile,
  36. lpDistanceToMove.u.LowPart,
  37. &dwHighPart,
  38. dwMoveMethod);
  39. if(dwLowPart == boost::winapi::INVALID_SET_FILE_POINTER_)
  40. return 0;
  41. if(lpNewFilePointer)
  42. {
  43. lpNewFilePointer->u.LowPart = dwLowPart;
  44. lpNewFilePointer->u.HighPart = dwHighPart;
  45. }
  46. return 1;
  47. }
  48. } // detail
  49. file_win32::
  50. ~file_win32()
  51. {
  52. if(h_ != boost::winapi::INVALID_HANDLE_VALUE_)
  53. boost::winapi::CloseHandle(h_);
  54. }
  55. file_win32::
  56. file_win32(file_win32&& other)
  57. : h_(boost::exchange(other.h_,
  58. boost::winapi::INVALID_HANDLE_VALUE_))
  59. {
  60. }
  61. file_win32&
  62. file_win32::
  63. operator=(file_win32&& other)
  64. {
  65. if(&other == this)
  66. return *this;
  67. if(h_)
  68. boost::winapi::CloseHandle(h_);
  69. h_ = other.h_;
  70. other.h_ = boost::winapi::INVALID_HANDLE_VALUE_;
  71. return *this;
  72. }
  73. void
  74. file_win32::
  75. native_handle(native_handle_type h)
  76. {
  77. if(h_ != boost::winapi::INVALID_HANDLE_VALUE_)
  78. boost::winapi::CloseHandle(h_);
  79. h_ = h;
  80. }
  81. void
  82. file_win32::
  83. close(error_code& ec)
  84. {
  85. if(h_ != boost::winapi::INVALID_HANDLE_VALUE_)
  86. {
  87. if(! boost::winapi::CloseHandle(h_))
  88. ec.assign(boost::winapi::GetLastError(),
  89. system_category());
  90. else
  91. ec = {};
  92. h_ = boost::winapi::INVALID_HANDLE_VALUE_;
  93. }
  94. else
  95. {
  96. ec = {};
  97. }
  98. }
  99. void
  100. file_win32::
  101. open(char const* path, file_mode mode, error_code& ec)
  102. {
  103. if(h_ != boost::winapi::INVALID_HANDLE_VALUE_)
  104. {
  105. boost::winapi::CloseHandle(h_);
  106. h_ = boost::winapi::INVALID_HANDLE_VALUE_;
  107. }
  108. boost::winapi::DWORD_ share_mode = 0;
  109. boost::winapi::DWORD_ desired_access = 0;
  110. boost::winapi::DWORD_ creation_disposition = 0;
  111. boost::winapi::DWORD_ flags_and_attributes = 0;
  112. /*
  113. | When the file...
  114. This argument: | Exists Does not exist
  115. -------------------------+------------------------------------------------------
  116. CREATE_ALWAYS | Truncates Creates
  117. CREATE_NEW +-----------+ Fails Creates
  118. OPEN_ALWAYS ===| does this |===> Opens Creates
  119. OPEN_EXISTING +-----------+ Opens Fails
  120. TRUNCATE_EXISTING | Truncates Fails
  121. */
  122. switch(mode)
  123. {
  124. default:
  125. case file_mode::read:
  126. desired_access = boost::winapi::GENERIC_READ_;
  127. share_mode = boost::winapi::FILE_SHARE_READ_;
  128. creation_disposition = boost::winapi::OPEN_EXISTING_;
  129. flags_and_attributes = 0x10000000; // FILE_FLAG_RANDOM_ACCESS
  130. break;
  131. case file_mode::scan:
  132. desired_access = boost::winapi::GENERIC_READ_;
  133. share_mode = boost::winapi::FILE_SHARE_READ_;
  134. creation_disposition = boost::winapi::OPEN_EXISTING_;
  135. flags_and_attributes = 0x08000000; // FILE_FLAG_SEQUENTIAL_SCAN
  136. break;
  137. case file_mode::write:
  138. desired_access = boost::winapi::GENERIC_READ_ |
  139. boost::winapi::GENERIC_WRITE_;
  140. creation_disposition = boost::winapi::CREATE_ALWAYS_;
  141. flags_and_attributes = 0x10000000; // FILE_FLAG_RANDOM_ACCESS
  142. break;
  143. case file_mode::write_new:
  144. desired_access = boost::winapi::GENERIC_READ_ |
  145. boost::winapi::GENERIC_WRITE_;
  146. creation_disposition = boost::winapi::CREATE_NEW_;
  147. flags_and_attributes = 0x10000000; // FILE_FLAG_RANDOM_ACCESS
  148. break;
  149. case file_mode::write_existing:
  150. desired_access = boost::winapi::GENERIC_READ_ |
  151. boost::winapi::GENERIC_WRITE_;
  152. creation_disposition = boost::winapi::OPEN_EXISTING_;
  153. flags_and_attributes = 0x10000000; // FILE_FLAG_RANDOM_ACCESS
  154. break;
  155. case file_mode::append:
  156. desired_access = boost::winapi::GENERIC_READ_ |
  157. boost::winapi::GENERIC_WRITE_;
  158. creation_disposition = boost::winapi::OPEN_ALWAYS_;
  159. flags_and_attributes = 0x08000000; // FILE_FLAG_SEQUENTIAL_SCAN
  160. break;
  161. case file_mode::append_existing:
  162. desired_access = boost::winapi::GENERIC_READ_ |
  163. boost::winapi::GENERIC_WRITE_;
  164. creation_disposition = boost::winapi::OPEN_EXISTING_;
  165. flags_and_attributes = 0x08000000; // FILE_FLAG_SEQUENTIAL_SCAN
  166. break;
  167. }
  168. detail::win32_unicode_path unicode_path(path, ec);
  169. if (ec)
  170. return;
  171. h_ = ::CreateFileW(
  172. unicode_path.c_str(),
  173. desired_access,
  174. share_mode,
  175. NULL,
  176. creation_disposition,
  177. flags_and_attributes,
  178. NULL);
  179. if (h_ == boost::winapi::INVALID_HANDLE_VALUE_)
  180. {
  181. ec.assign(boost::winapi::GetLastError(),
  182. system_category());
  183. return;
  184. }
  185. if (mode == file_mode::append ||
  186. mode == file_mode::append_existing)
  187. {
  188. boost::winapi::LARGE_INTEGER_ in;
  189. in.QuadPart = 0;
  190. if (!detail::set_file_pointer_ex(h_, in, 0,
  191. boost::winapi::FILE_END_))
  192. {
  193. ec.assign(boost::winapi::GetLastError(),
  194. system_category());
  195. boost::winapi::CloseHandle(h_);
  196. h_ = boost::winapi::INVALID_HANDLE_VALUE_;
  197. return;
  198. }
  199. }
  200. ec = {};
  201. }
  202. std::uint64_t
  203. file_win32::
  204. size(error_code& ec) const
  205. {
  206. if(h_ == boost::winapi::INVALID_HANDLE_VALUE_)
  207. {
  208. ec = make_error_code(errc::bad_file_descriptor);
  209. return 0;
  210. }
  211. boost::winapi::LARGE_INTEGER_ fileSize;
  212. if(! boost::winapi::GetFileSizeEx(h_, &fileSize))
  213. {
  214. ec.assign(boost::winapi::GetLastError(),
  215. system_category());
  216. return 0;
  217. }
  218. ec = {};
  219. return fileSize.QuadPart;
  220. }
  221. std::uint64_t
  222. file_win32::
  223. pos(error_code& ec)
  224. {
  225. if(h_ == boost::winapi::INVALID_HANDLE_VALUE_)
  226. {
  227. ec = make_error_code(errc::bad_file_descriptor);
  228. return 0;
  229. }
  230. boost::winapi::LARGE_INTEGER_ in;
  231. boost::winapi::LARGE_INTEGER_ out;
  232. in.QuadPart = 0;
  233. if(! detail::set_file_pointer_ex(h_, in, &out,
  234. boost::winapi::FILE_CURRENT_))
  235. {
  236. ec.assign(boost::winapi::GetLastError(),
  237. system_category());
  238. return 0;
  239. }
  240. ec = {};
  241. return out.QuadPart;
  242. }
  243. void
  244. file_win32::
  245. seek(std::uint64_t offset, error_code& ec)
  246. {
  247. if(h_ == boost::winapi::INVALID_HANDLE_VALUE_)
  248. {
  249. ec = make_error_code(errc::bad_file_descriptor);
  250. return;
  251. }
  252. boost::winapi::LARGE_INTEGER_ in;
  253. in.QuadPart = offset;
  254. if(! detail::set_file_pointer_ex(h_, in, 0,
  255. boost::winapi::FILE_BEGIN_))
  256. {
  257. ec.assign(boost::winapi::GetLastError(),
  258. system_category());
  259. return;
  260. }
  261. ec = {};
  262. }
  263. std::size_t
  264. file_win32::
  265. read(void* buffer, std::size_t n, error_code& ec)
  266. {
  267. if(h_ == boost::winapi::INVALID_HANDLE_VALUE_)
  268. {
  269. ec = make_error_code(errc::bad_file_descriptor);
  270. return 0;
  271. }
  272. std::size_t nread = 0;
  273. while(n > 0)
  274. {
  275. boost::winapi::DWORD_ amount;
  276. if(n > (std::numeric_limits<
  277. boost::winapi::DWORD_>::max)())
  278. amount = (std::numeric_limits<
  279. boost::winapi::DWORD_>::max)();
  280. else
  281. amount = static_cast<
  282. boost::winapi::DWORD_>(n);
  283. boost::winapi::DWORD_ bytesRead;
  284. if(! ::ReadFile(h_, buffer, amount, &bytesRead, 0))
  285. {
  286. auto const dwError = boost::winapi::GetLastError();
  287. if(dwError != boost::winapi::ERROR_HANDLE_EOF_)
  288. ec.assign(dwError, system_category());
  289. else
  290. ec = {};
  291. return nread;
  292. }
  293. if(bytesRead == 0)
  294. return nread;
  295. n -= bytesRead;
  296. nread += bytesRead;
  297. buffer = static_cast<char*>(buffer) + bytesRead;
  298. }
  299. ec = {};
  300. return nread;
  301. }
  302. std::size_t
  303. file_win32::
  304. write(void const* buffer, std::size_t n, error_code& ec)
  305. {
  306. if(h_ == boost::winapi::INVALID_HANDLE_VALUE_)
  307. {
  308. ec = make_error_code(errc::bad_file_descriptor);
  309. return 0;
  310. }
  311. std::size_t nwritten = 0;
  312. while(n > 0)
  313. {
  314. boost::winapi::DWORD_ amount;
  315. if(n > (std::numeric_limits<
  316. boost::winapi::DWORD_>::max)())
  317. amount = (std::numeric_limits<
  318. boost::winapi::DWORD_>::max)();
  319. else
  320. amount = static_cast<
  321. boost::winapi::DWORD_>(n);
  322. boost::winapi::DWORD_ bytesWritten;
  323. if(! ::WriteFile(h_, buffer, amount, &bytesWritten, 0))
  324. {
  325. auto const dwError = boost::winapi::GetLastError();
  326. if(dwError != boost::winapi::ERROR_HANDLE_EOF_)
  327. ec.assign(dwError, system_category());
  328. else
  329. ec = {};
  330. return nwritten;
  331. }
  332. if(bytesWritten == 0)
  333. return nwritten;
  334. n -= bytesWritten;
  335. nwritten += bytesWritten;
  336. buffer = static_cast<char const*>(buffer) + bytesWritten;
  337. }
  338. ec = {};
  339. return nwritten;
  340. }
  341. } // beast
  342. } // boost
  343. #endif
  344. #endif