win_iocp_file_service.ipp 7.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267
  1. //
  2. // detail/impl/win_iocp_file_service.ipp
  3. // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  4. //
  5. // Copyright (c) 2003-2023 Christopher M. Kohlhoff (chris at kohlhoff dot com)
  6. //
  7. // Distributed under the Boost Software License, Version 1.0. (See accompanying
  8. // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
  9. //
  10. #ifndef BOOST_ASIO_DETAIL_IMPL_WIN_IOCP_FILE_SERVICE_IPP
  11. #define BOOST_ASIO_DETAIL_IMPL_WIN_IOCP_FILE_SERVICE_IPP
  12. #if defined(_MSC_VER) && (_MSC_VER >= 1200)
  13. # pragma once
  14. #endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
  15. #include <boost/asio/detail/config.hpp>
  16. #if defined(BOOST_ASIO_HAS_FILE) \
  17. && defined(BOOST_ASIO_HAS_WINDOWS_RANDOM_ACCESS_HANDLE)
  18. #include <cstring>
  19. #include <sys/stat.h>
  20. #include <boost/asio/detail/win_iocp_file_service.hpp>
  21. #include <boost/asio/detail/push_options.hpp>
  22. namespace boost {
  23. namespace asio {
  24. namespace detail {
  25. win_iocp_file_service::win_iocp_file_service(
  26. execution_context& context)
  27. : execution_context_service_base<win_iocp_file_service>(context),
  28. handle_service_(context),
  29. nt_flush_buffers_file_ex_(0)
  30. {
  31. if (FARPROC nt_flush_buffers_file_ex_ptr = ::GetProcAddress(
  32. ::GetModuleHandleA("NTDLL"), "NtFlushBuffersFileEx"))
  33. {
  34. nt_flush_buffers_file_ex_ = reinterpret_cast<nt_flush_buffers_file_ex_fn>(
  35. reinterpret_cast<void*>(nt_flush_buffers_file_ex_ptr));
  36. }
  37. }
  38. void win_iocp_file_service::shutdown()
  39. {
  40. handle_service_.shutdown();
  41. }
  42. boost::system::error_code win_iocp_file_service::open(
  43. win_iocp_file_service::implementation_type& impl,
  44. const char* path, file_base::flags open_flags,
  45. boost::system::error_code& ec)
  46. {
  47. if (is_open(impl))
  48. {
  49. ec = boost::asio::error::already_open;
  50. BOOST_ASIO_ERROR_LOCATION(ec);
  51. return ec;
  52. }
  53. DWORD access = 0;
  54. if ((open_flags & file_base::read_only) != 0)
  55. access = GENERIC_READ;
  56. else if ((open_flags & file_base::write_only) != 0)
  57. access = GENERIC_WRITE;
  58. else if ((open_flags & file_base::read_write) != 0)
  59. access = GENERIC_READ | GENERIC_WRITE;
  60. DWORD share = FILE_SHARE_READ | FILE_SHARE_WRITE;
  61. DWORD disposition = 0;
  62. if ((open_flags & file_base::create) != 0)
  63. {
  64. if ((open_flags & file_base::exclusive) != 0)
  65. disposition = CREATE_NEW;
  66. else
  67. disposition = OPEN_ALWAYS;
  68. }
  69. else
  70. {
  71. if ((open_flags & file_base::truncate) != 0)
  72. disposition = TRUNCATE_EXISTING;
  73. else
  74. disposition = OPEN_EXISTING;
  75. }
  76. DWORD flags = FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED;
  77. if (impl.is_stream_)
  78. flags |= FILE_FLAG_SEQUENTIAL_SCAN;
  79. else
  80. flags |= FILE_FLAG_RANDOM_ACCESS;
  81. if ((open_flags & file_base::sync_all_on_write) != 0)
  82. flags |= FILE_FLAG_WRITE_THROUGH;
  83. HANDLE handle = ::CreateFileA(path, access, share, 0, disposition, flags, 0);
  84. if (handle != INVALID_HANDLE_VALUE)
  85. {
  86. if (disposition == OPEN_ALWAYS && (open_flags & file_base::truncate) != 0)
  87. {
  88. if (!::SetEndOfFile(handle))
  89. {
  90. DWORD last_error = ::GetLastError();
  91. ::CloseHandle(handle);
  92. ec.assign(last_error, boost::asio::error::get_system_category());
  93. BOOST_ASIO_ERROR_LOCATION(ec);
  94. return ec;
  95. }
  96. }
  97. handle_service_.assign(impl, handle, ec);
  98. if (ec)
  99. ::CloseHandle(handle);
  100. impl.offset_ = 0;
  101. BOOST_ASIO_ERROR_LOCATION(ec);
  102. return ec;
  103. }
  104. else
  105. {
  106. DWORD last_error = ::GetLastError();
  107. ec.assign(last_error, boost::asio::error::get_system_category());
  108. BOOST_ASIO_ERROR_LOCATION(ec);
  109. return ec;
  110. }
  111. }
  112. uint64_t win_iocp_file_service::size(
  113. const win_iocp_file_service::implementation_type& impl,
  114. boost::system::error_code& ec) const
  115. {
  116. LARGE_INTEGER result;
  117. if (::GetFileSizeEx(native_handle(impl), &result))
  118. {
  119. boost::asio::error::clear(ec);
  120. return static_cast<uint64_t>(result.QuadPart);
  121. }
  122. else
  123. {
  124. DWORD last_error = ::GetLastError();
  125. ec.assign(last_error, boost::asio::error::get_system_category());
  126. BOOST_ASIO_ERROR_LOCATION(ec);
  127. return 0;
  128. }
  129. }
  130. boost::system::error_code win_iocp_file_service::resize(
  131. win_iocp_file_service::implementation_type& impl,
  132. uint64_t n, boost::system::error_code& ec)
  133. {
  134. LARGE_INTEGER distance;
  135. distance.QuadPart = n;
  136. if (::SetFilePointerEx(native_handle(impl), distance, 0, FILE_BEGIN))
  137. {
  138. BOOL result = ::SetEndOfFile(native_handle(impl));
  139. DWORD last_error = ::GetLastError();
  140. distance.QuadPart = static_cast<LONGLONG>(impl.offset_);
  141. if (!::SetFilePointerEx(native_handle(impl), distance, 0, FILE_BEGIN))
  142. {
  143. result = FALSE;
  144. last_error = ::GetLastError();
  145. }
  146. if (result)
  147. boost::asio::error::clear(ec);
  148. else
  149. ec.assign(last_error, boost::asio::error::get_system_category());
  150. BOOST_ASIO_ERROR_LOCATION(ec);
  151. return ec;
  152. }
  153. else
  154. {
  155. DWORD last_error = ::GetLastError();
  156. ec.assign(last_error, boost::asio::error::get_system_category());
  157. BOOST_ASIO_ERROR_LOCATION(ec);
  158. return ec;
  159. }
  160. }
  161. boost::system::error_code win_iocp_file_service::sync_all(
  162. win_iocp_file_service::implementation_type& impl,
  163. boost::system::error_code& ec)
  164. {
  165. BOOL result = ::FlushFileBuffers(native_handle(impl));
  166. if (result)
  167. {
  168. boost::asio::error::clear(ec);
  169. return ec;
  170. }
  171. else
  172. {
  173. DWORD last_error = ::GetLastError();
  174. ec.assign(last_error, boost::asio::error::get_system_category());
  175. BOOST_ASIO_ERROR_LOCATION(ec);
  176. return ec;
  177. }
  178. }
  179. boost::system::error_code win_iocp_file_service::sync_data(
  180. win_iocp_file_service::implementation_type& impl,
  181. boost::system::error_code& ec)
  182. {
  183. if (nt_flush_buffers_file_ex_)
  184. {
  185. io_status_block status = {};
  186. if (!nt_flush_buffers_file_ex_(native_handle(impl),
  187. flush_flags_file_data_sync_only, 0, 0, &status))
  188. {
  189. boost::asio::error::clear(ec);
  190. return ec;
  191. }
  192. }
  193. return sync_all(impl, ec);
  194. }
  195. uint64_t win_iocp_file_service::seek(
  196. win_iocp_file_service::implementation_type& impl, int64_t offset,
  197. file_base::seek_basis whence, boost::system::error_code& ec)
  198. {
  199. DWORD method;
  200. switch (whence)
  201. {
  202. case file_base::seek_set:
  203. method = FILE_BEGIN;
  204. break;
  205. case file_base::seek_cur:
  206. method = FILE_BEGIN;
  207. offset = static_cast<int64_t>(impl.offset_) + offset;
  208. break;
  209. case file_base::seek_end:
  210. method = FILE_END;
  211. break;
  212. default:
  213. ec = boost::asio::error::invalid_argument;
  214. BOOST_ASIO_ERROR_LOCATION(ec);
  215. return 0;
  216. }
  217. LARGE_INTEGER distance, new_offset;
  218. distance.QuadPart = offset;
  219. if (::SetFilePointerEx(native_handle(impl), distance, &new_offset, method))
  220. {
  221. impl.offset_ = new_offset.QuadPart;
  222. boost::asio::error::clear(ec);
  223. return impl.offset_;
  224. }
  225. else
  226. {
  227. DWORD last_error = ::GetLastError();
  228. ec.assign(last_error, boost::asio::error::get_system_category());
  229. BOOST_ASIO_ERROR_LOCATION(ec);
  230. return 0;
  231. }
  232. }
  233. } // namespace detail
  234. } // namespace asio
  235. } // namespace boost
  236. #include <boost/asio/detail/pop_options.hpp>
  237. #endif // defined(BOOST_ASIO_HAS_FILE)
  238. // && defined(BOOST_ASIO_HAS_WINDOWS_RANDOM_ACCESS_HANDLE)
  239. #endif // BOOST_ASIO_DETAIL_IMPL_WIN_IOCP_FILE_SERVICE_IPP