file_win32.ipp 9.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353
  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/core/exchange.hpp>
  14. #include <boost/winapi/access_rights.hpp>
  15. #include <boost/winapi/error_codes.hpp>
  16. #include <boost/winapi/file_management.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::CREATE_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. h_ = ::CreateFileA(
  169. path,
  170. desired_access,
  171. share_mode,
  172. NULL,
  173. creation_disposition,
  174. flags_and_attributes,
  175. NULL);
  176. if(h_ == boost::winapi::INVALID_HANDLE_VALUE_)
  177. ec.assign(boost::winapi::GetLastError(),
  178. system_category());
  179. else
  180. ec = {};
  181. }
  182. std::uint64_t
  183. file_win32::
  184. size(error_code& ec) const
  185. {
  186. if(h_ == boost::winapi::INVALID_HANDLE_VALUE_)
  187. {
  188. ec = make_error_code(errc::bad_file_descriptor);
  189. return 0;
  190. }
  191. boost::winapi::LARGE_INTEGER_ fileSize;
  192. if(! boost::winapi::GetFileSizeEx(h_, &fileSize))
  193. {
  194. ec.assign(boost::winapi::GetLastError(),
  195. system_category());
  196. return 0;
  197. }
  198. ec = {};
  199. return fileSize.QuadPart;
  200. }
  201. std::uint64_t
  202. file_win32::
  203. pos(error_code& ec)
  204. {
  205. if(h_ == boost::winapi::INVALID_HANDLE_VALUE_)
  206. {
  207. ec = make_error_code(errc::bad_file_descriptor);
  208. return 0;
  209. }
  210. boost::winapi::LARGE_INTEGER_ in;
  211. boost::winapi::LARGE_INTEGER_ out;
  212. in.QuadPart = 0;
  213. if(! detail::set_file_pointer_ex(h_, in, &out,
  214. boost::winapi::FILE_CURRENT_))
  215. {
  216. ec.assign(boost::winapi::GetLastError(),
  217. system_category());
  218. return 0;
  219. }
  220. ec = {};
  221. return out.QuadPart;
  222. }
  223. void
  224. file_win32::
  225. seek(std::uint64_t offset, error_code& ec)
  226. {
  227. if(h_ == boost::winapi::INVALID_HANDLE_VALUE_)
  228. {
  229. ec = make_error_code(errc::bad_file_descriptor);
  230. return;
  231. }
  232. boost::winapi::LARGE_INTEGER_ in;
  233. in.QuadPart = offset;
  234. if(! detail::set_file_pointer_ex(h_, in, 0,
  235. boost::winapi::FILE_BEGIN_))
  236. {
  237. ec.assign(boost::winapi::GetLastError(),
  238. system_category());
  239. return;
  240. }
  241. ec = {};
  242. }
  243. std::size_t
  244. file_win32::
  245. read(void* buffer, std::size_t n, error_code& ec)
  246. {
  247. if(h_ == boost::winapi::INVALID_HANDLE_VALUE_)
  248. {
  249. ec = make_error_code(errc::bad_file_descriptor);
  250. return 0;
  251. }
  252. std::size_t nread = 0;
  253. while(n > 0)
  254. {
  255. boost::winapi::DWORD_ amount;
  256. if(n > (std::numeric_limits<
  257. boost::winapi::DWORD_>::max)())
  258. amount = (std::numeric_limits<
  259. boost::winapi::DWORD_>::max)();
  260. else
  261. amount = static_cast<
  262. boost::winapi::DWORD_>(n);
  263. boost::winapi::DWORD_ bytesRead;
  264. if(! ::ReadFile(h_, buffer, amount, &bytesRead, 0))
  265. {
  266. auto const dwError = boost::winapi::GetLastError();
  267. if(dwError != boost::winapi::ERROR_HANDLE_EOF_)
  268. ec.assign(dwError, system_category());
  269. else
  270. ec = {};
  271. return nread;
  272. }
  273. if(bytesRead == 0)
  274. return nread;
  275. n -= bytesRead;
  276. nread += bytesRead;
  277. buffer = static_cast<char*>(buffer) + bytesRead;
  278. }
  279. ec = {};
  280. return nread;
  281. }
  282. std::size_t
  283. file_win32::
  284. write(void const* buffer, std::size_t n, error_code& ec)
  285. {
  286. if(h_ == boost::winapi::INVALID_HANDLE_VALUE_)
  287. {
  288. ec = make_error_code(errc::bad_file_descriptor);
  289. return 0;
  290. }
  291. std::size_t nwritten = 0;
  292. while(n > 0)
  293. {
  294. boost::winapi::DWORD_ amount;
  295. if(n > (std::numeric_limits<
  296. boost::winapi::DWORD_>::max)())
  297. amount = (std::numeric_limits<
  298. boost::winapi::DWORD_>::max)();
  299. else
  300. amount = static_cast<
  301. boost::winapi::DWORD_>(n);
  302. boost::winapi::DWORD_ bytesWritten;
  303. if(! ::WriteFile(h_, buffer, amount, &bytesWritten, 0))
  304. {
  305. auto const dwError = boost::winapi::GetLastError();
  306. if(dwError != boost::winapi::ERROR_HANDLE_EOF_)
  307. ec.assign(dwError, system_category());
  308. else
  309. ec = {};
  310. return nwritten;
  311. }
  312. if(bytesWritten == 0)
  313. return nwritten;
  314. n -= bytesWritten;
  315. nwritten += bytesWritten;
  316. buffer = static_cast<char const*>(buffer) + bytesWritten;
  317. }
  318. ec = {};
  319. return nwritten;
  320. }
  321. } // beast
  322. } // boost
  323. #endif
  324. #endif