// // detail/impl/win_iocp_file_service.ipp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2023 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) // #ifndef ASIO_DETAIL_IMPL_WIN_IOCP_FILE_SERVICE_IPP #define ASIO_DETAIL_IMPL_WIN_IOCP_FILE_SERVICE_IPP #if defined(_MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include "asio/detail/config.hpp" #if defined(ASIO_HAS_FILE) \ && defined(ASIO_HAS_WINDOWS_RANDOM_ACCESS_HANDLE) #include #include #include "asio/detail/win_iocp_file_service.hpp" #include "asio/detail/push_options.hpp" namespace asio { namespace detail { win_iocp_file_service::win_iocp_file_service( execution_context& context) : execution_context_service_base(context), handle_service_(context), nt_flush_buffers_file_ex_(0) { if (FARPROC nt_flush_buffers_file_ex_ptr = ::GetProcAddress( ::GetModuleHandleA("NTDLL"), "NtFlushBuffersFileEx")) { nt_flush_buffers_file_ex_ = reinterpret_cast( reinterpret_cast(nt_flush_buffers_file_ex_ptr)); } } void win_iocp_file_service::shutdown() { handle_service_.shutdown(); } asio::error_code win_iocp_file_service::open( win_iocp_file_service::implementation_type& impl, const char* path, file_base::flags open_flags, asio::error_code& ec) { if (is_open(impl)) { ec = asio::error::already_open; ASIO_ERROR_LOCATION(ec); return ec; } DWORD access = 0; if ((open_flags & file_base::read_only) != 0) access = GENERIC_READ; else if ((open_flags & file_base::write_only) != 0) access = GENERIC_WRITE; else if ((open_flags & file_base::read_write) != 0) access = GENERIC_READ | GENERIC_WRITE; DWORD share = FILE_SHARE_READ | FILE_SHARE_WRITE; DWORD disposition = 0; if ((open_flags & file_base::create) != 0) { if ((open_flags & file_base::exclusive) != 0) disposition = CREATE_NEW; else disposition = OPEN_ALWAYS; } else { if ((open_flags & file_base::truncate) != 0) disposition = TRUNCATE_EXISTING; else disposition = OPEN_EXISTING; } DWORD flags = FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED; if (impl.is_stream_) flags |= FILE_FLAG_SEQUENTIAL_SCAN; else flags |= FILE_FLAG_RANDOM_ACCESS; if ((open_flags & file_base::sync_all_on_write) != 0) flags |= FILE_FLAG_WRITE_THROUGH; HANDLE handle = ::CreateFileA(path, access, share, 0, disposition, flags, 0); if (handle != INVALID_HANDLE_VALUE) { if (disposition == OPEN_ALWAYS && (open_flags & file_base::truncate) != 0) { if (!::SetEndOfFile(handle)) { DWORD last_error = ::GetLastError(); ::CloseHandle(handle); ec.assign(last_error, asio::error::get_system_category()); ASIO_ERROR_LOCATION(ec); return ec; } } handle_service_.assign(impl, handle, ec); if (ec) ::CloseHandle(handle); impl.offset_ = 0; ASIO_ERROR_LOCATION(ec); return ec; } else { DWORD last_error = ::GetLastError(); ec.assign(last_error, asio::error::get_system_category()); ASIO_ERROR_LOCATION(ec); return ec; } } uint64_t win_iocp_file_service::size( const win_iocp_file_service::implementation_type& impl, asio::error_code& ec) const { LARGE_INTEGER result; if (::GetFileSizeEx(native_handle(impl), &result)) { asio::error::clear(ec); return static_cast(result.QuadPart); } else { DWORD last_error = ::GetLastError(); ec.assign(last_error, asio::error::get_system_category()); ASIO_ERROR_LOCATION(ec); return 0; } } asio::error_code win_iocp_file_service::resize( win_iocp_file_service::implementation_type& impl, uint64_t n, asio::error_code& ec) { LARGE_INTEGER distance; distance.QuadPart = n; if (::SetFilePointerEx(native_handle(impl), distance, 0, FILE_BEGIN)) { BOOL result = ::SetEndOfFile(native_handle(impl)); DWORD last_error = ::GetLastError(); distance.QuadPart = static_cast(impl.offset_); if (!::SetFilePointerEx(native_handle(impl), distance, 0, FILE_BEGIN)) { result = FALSE; last_error = ::GetLastError(); } if (result) asio::error::clear(ec); else ec.assign(last_error, asio::error::get_system_category()); ASIO_ERROR_LOCATION(ec); return ec; } else { DWORD last_error = ::GetLastError(); ec.assign(last_error, asio::error::get_system_category()); ASIO_ERROR_LOCATION(ec); return ec; } } asio::error_code win_iocp_file_service::sync_all( win_iocp_file_service::implementation_type& impl, asio::error_code& ec) { BOOL result = ::FlushFileBuffers(native_handle(impl)); if (result) { asio::error::clear(ec); return ec; } else { DWORD last_error = ::GetLastError(); ec.assign(last_error, asio::error::get_system_category()); ASIO_ERROR_LOCATION(ec); return ec; } } asio::error_code win_iocp_file_service::sync_data( win_iocp_file_service::implementation_type& impl, asio::error_code& ec) { if (nt_flush_buffers_file_ex_) { io_status_block status = {}; if (!nt_flush_buffers_file_ex_(native_handle(impl), flush_flags_file_data_sync_only, 0, 0, &status)) { asio::error::clear(ec); return ec; } } return sync_all(impl, ec); } uint64_t win_iocp_file_service::seek( win_iocp_file_service::implementation_type& impl, int64_t offset, file_base::seek_basis whence, asio::error_code& ec) { DWORD method; switch (whence) { case file_base::seek_set: method = FILE_BEGIN; break; case file_base::seek_cur: method = FILE_BEGIN; offset = static_cast(impl.offset_) + offset; break; case file_base::seek_end: method = FILE_END; break; default: ec = asio::error::invalid_argument; ASIO_ERROR_LOCATION(ec); return 0; } LARGE_INTEGER distance, new_offset; distance.QuadPart = offset; if (::SetFilePointerEx(native_handle(impl), distance, &new_offset, method)) { impl.offset_ = new_offset.QuadPart; asio::error::clear(ec); return impl.offset_; } else { DWORD last_error = ::GetLastError(); ec.assign(last_error, asio::error::get_system_category()); ASIO_ERROR_LOCATION(ec); return 0; } } } // namespace detail } // namespace asio #include "asio/detail/pop_options.hpp" #endif // defined(ASIO_HAS_FILE) // && defined(ASIO_HAS_WINDOWS_RANDOM_ACCESS_HANDLE) #endif // ASIO_DETAIL_IMPL_WIN_IOCP_FILE_SERVICE_IPP