win_iocp_file_service.ipp 7.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290
  1. //
  2. // detail/impl/win_iocp_file_service.ipp
  3. // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  4. //
  5. // Copyright (c) 2003-2024 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. impl.offset_ = 0;
  84. HANDLE handle = ::CreateFileA(path, access, share, 0, disposition, flags, 0);
  85. if (handle != INVALID_HANDLE_VALUE)
  86. {
  87. if (disposition == OPEN_ALWAYS)
  88. {
  89. if ((open_flags & file_base::truncate) != 0)
  90. {
  91. if (!::SetEndOfFile(handle))
  92. {
  93. DWORD last_error = ::GetLastError();
  94. ::CloseHandle(handle);
  95. ec.assign(last_error, boost::asio::error::get_system_category());
  96. BOOST_ASIO_ERROR_LOCATION(ec);
  97. return ec;
  98. }
  99. }
  100. }
  101. if (disposition == OPEN_ALWAYS || disposition == OPEN_EXISTING)
  102. {
  103. if ((open_flags & file_base::append) != 0)
  104. {
  105. LARGE_INTEGER distance, new_offset;
  106. distance.QuadPart = 0;
  107. if (::SetFilePointerEx(handle, distance, &new_offset, FILE_END))
  108. {
  109. impl.offset_ = static_cast<uint64_t>(new_offset.QuadPart);
  110. }
  111. else
  112. {
  113. DWORD last_error = ::GetLastError();
  114. ::CloseHandle(handle);
  115. ec.assign(last_error, boost::asio::error::get_system_category());
  116. BOOST_ASIO_ERROR_LOCATION(ec);
  117. return ec;
  118. }
  119. }
  120. }
  121. handle_service_.assign(impl, handle, ec);
  122. if (ec)
  123. ::CloseHandle(handle);
  124. BOOST_ASIO_ERROR_LOCATION(ec);
  125. return ec;
  126. }
  127. else
  128. {
  129. DWORD last_error = ::GetLastError();
  130. ec.assign(last_error, boost::asio::error::get_system_category());
  131. BOOST_ASIO_ERROR_LOCATION(ec);
  132. return ec;
  133. }
  134. }
  135. uint64_t win_iocp_file_service::size(
  136. const win_iocp_file_service::implementation_type& impl,
  137. boost::system::error_code& ec) const
  138. {
  139. LARGE_INTEGER result;
  140. if (::GetFileSizeEx(native_handle(impl), &result))
  141. {
  142. boost::asio::error::clear(ec);
  143. return static_cast<uint64_t>(result.QuadPart);
  144. }
  145. else
  146. {
  147. DWORD last_error = ::GetLastError();
  148. ec.assign(last_error, boost::asio::error::get_system_category());
  149. BOOST_ASIO_ERROR_LOCATION(ec);
  150. return 0;
  151. }
  152. }
  153. boost::system::error_code win_iocp_file_service::resize(
  154. win_iocp_file_service::implementation_type& impl,
  155. uint64_t n, boost::system::error_code& ec)
  156. {
  157. LARGE_INTEGER distance;
  158. distance.QuadPart = n;
  159. if (::SetFilePointerEx(native_handle(impl), distance, 0, FILE_BEGIN))
  160. {
  161. BOOL result = ::SetEndOfFile(native_handle(impl));
  162. DWORD last_error = ::GetLastError();
  163. distance.QuadPart = static_cast<LONGLONG>(impl.offset_);
  164. if (!::SetFilePointerEx(native_handle(impl), distance, 0, FILE_BEGIN))
  165. {
  166. result = FALSE;
  167. last_error = ::GetLastError();
  168. }
  169. if (result)
  170. boost::asio::error::clear(ec);
  171. else
  172. ec.assign(last_error, boost::asio::error::get_system_category());
  173. BOOST_ASIO_ERROR_LOCATION(ec);
  174. return ec;
  175. }
  176. else
  177. {
  178. DWORD last_error = ::GetLastError();
  179. ec.assign(last_error, boost::asio::error::get_system_category());
  180. BOOST_ASIO_ERROR_LOCATION(ec);
  181. return ec;
  182. }
  183. }
  184. boost::system::error_code win_iocp_file_service::sync_all(
  185. win_iocp_file_service::implementation_type& impl,
  186. boost::system::error_code& ec)
  187. {
  188. BOOL result = ::FlushFileBuffers(native_handle(impl));
  189. if (result)
  190. {
  191. boost::asio::error::clear(ec);
  192. return ec;
  193. }
  194. else
  195. {
  196. DWORD last_error = ::GetLastError();
  197. ec.assign(last_error, boost::asio::error::get_system_category());
  198. BOOST_ASIO_ERROR_LOCATION(ec);
  199. return ec;
  200. }
  201. }
  202. boost::system::error_code win_iocp_file_service::sync_data(
  203. win_iocp_file_service::implementation_type& impl,
  204. boost::system::error_code& ec)
  205. {
  206. if (nt_flush_buffers_file_ex_)
  207. {
  208. io_status_block status = {};
  209. if (!nt_flush_buffers_file_ex_(native_handle(impl),
  210. flush_flags_file_data_sync_only, 0, 0, &status))
  211. {
  212. boost::asio::error::clear(ec);
  213. return ec;
  214. }
  215. }
  216. return sync_all(impl, ec);
  217. }
  218. uint64_t win_iocp_file_service::seek(
  219. win_iocp_file_service::implementation_type& impl, int64_t offset,
  220. file_base::seek_basis whence, boost::system::error_code& ec)
  221. {
  222. DWORD method;
  223. switch (whence)
  224. {
  225. case file_base::seek_set:
  226. method = FILE_BEGIN;
  227. break;
  228. case file_base::seek_cur:
  229. method = FILE_BEGIN;
  230. offset = static_cast<int64_t>(impl.offset_) + offset;
  231. break;
  232. case file_base::seek_end:
  233. method = FILE_END;
  234. break;
  235. default:
  236. ec = boost::asio::error::invalid_argument;
  237. BOOST_ASIO_ERROR_LOCATION(ec);
  238. return 0;
  239. }
  240. LARGE_INTEGER distance, new_offset;
  241. distance.QuadPart = offset;
  242. if (::SetFilePointerEx(native_handle(impl), distance, &new_offset, method))
  243. {
  244. impl.offset_ = new_offset.QuadPart;
  245. boost::asio::error::clear(ec);
  246. return impl.offset_;
  247. }
  248. else
  249. {
  250. DWORD last_error = ::GetLastError();
  251. ec.assign(last_error, boost::asio::error::get_system_category());
  252. BOOST_ASIO_ERROR_LOCATION(ec);
  253. return 0;
  254. }
  255. }
  256. } // namespace detail
  257. } // namespace asio
  258. } // namespace boost
  259. #include <boost/asio/detail/pop_options.hpp>
  260. #endif // defined(BOOST_ASIO_HAS_FILE)
  261. // && defined(BOOST_ASIO_HAS_WINDOWS_RANDOM_ACCESS_HANDLE)
  262. #endif // BOOST_ASIO_DETAIL_IMPL_WIN_IOCP_FILE_SERVICE_IPP