Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-07-02 08:06:24

0001 //
0002 // detail/impl/win_iocp_file_service.ipp
0003 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
0004 //
0005 // Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com)
0006 //
0007 // Distributed under the Boost Software License, Version 1.0. (See accompanying
0008 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
0009 //
0010 
0011 #ifndef BOOST_ASIO_DETAIL_IMPL_WIN_IOCP_FILE_SERVICE_IPP
0012 #define BOOST_ASIO_DETAIL_IMPL_WIN_IOCP_FILE_SERVICE_IPP
0013 
0014 #if defined(_MSC_VER) && (_MSC_VER >= 1200)
0015 # pragma once
0016 #endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
0017 
0018 #include <boost/asio/detail/config.hpp>
0019 
0020 #if defined(BOOST_ASIO_HAS_FILE) \
0021   && defined(BOOST_ASIO_HAS_WINDOWS_RANDOM_ACCESS_HANDLE)
0022 
0023 #include <cstring>
0024 #include <sys/stat.h>
0025 #include <boost/asio/detail/win_iocp_file_service.hpp>
0026 
0027 #include <boost/asio/detail/push_options.hpp>
0028 
0029 namespace boost {
0030 namespace asio {
0031 namespace detail {
0032 
0033 win_iocp_file_service::win_iocp_file_service(
0034     execution_context& context)
0035   : execution_context_service_base<win_iocp_file_service>(context),
0036     handle_service_(context),
0037     nt_flush_buffers_file_ex_(0)
0038 {
0039   if (FARPROC nt_flush_buffers_file_ex_ptr = ::GetProcAddress(
0040         ::GetModuleHandleA("NTDLL"), "NtFlushBuffersFileEx"))
0041   {
0042     nt_flush_buffers_file_ex_ = reinterpret_cast<nt_flush_buffers_file_ex_fn>(
0043         reinterpret_cast<void*>(nt_flush_buffers_file_ex_ptr));
0044   }
0045 }
0046 
0047 void win_iocp_file_service::shutdown()
0048 {
0049   handle_service_.shutdown();
0050 }
0051 
0052 boost::system::error_code win_iocp_file_service::open(
0053     win_iocp_file_service::implementation_type& impl,
0054     const char* path, file_base::flags open_flags,
0055     boost::system::error_code& ec)
0056 {
0057   if (is_open(impl))
0058   {
0059     ec = boost::asio::error::already_open;
0060     BOOST_ASIO_ERROR_LOCATION(ec);
0061     return ec;
0062   }
0063 
0064   DWORD access = 0;
0065   if ((open_flags & file_base::read_only) != 0)
0066     access = GENERIC_READ;
0067   else if ((open_flags & file_base::write_only) != 0)
0068     access = GENERIC_WRITE;
0069   else if ((open_flags & file_base::read_write) != 0)
0070     access = GENERIC_READ | GENERIC_WRITE;
0071 
0072   DWORD share = FILE_SHARE_READ | FILE_SHARE_WRITE;
0073 
0074   DWORD disposition = 0;
0075   if ((open_flags & file_base::create) != 0)
0076   {
0077     if ((open_flags & file_base::exclusive) != 0)
0078       disposition = CREATE_NEW;
0079     else
0080       disposition = OPEN_ALWAYS;
0081   }
0082   else
0083   {
0084     if ((open_flags & file_base::truncate) != 0)
0085       disposition = TRUNCATE_EXISTING;
0086     else
0087       disposition = OPEN_EXISTING;
0088   }
0089 
0090   DWORD flags = FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED;
0091   if (impl.is_stream_)
0092     flags |= FILE_FLAG_SEQUENTIAL_SCAN;
0093   else
0094     flags |= FILE_FLAG_RANDOM_ACCESS;
0095   if ((open_flags & file_base::sync_all_on_write) != 0)
0096     flags |= FILE_FLAG_WRITE_THROUGH;
0097 
0098   impl.offset_ = 0;
0099   HANDLE handle = ::CreateFileA(path, access, share, 0, disposition, flags, 0);
0100   if (handle != INVALID_HANDLE_VALUE)
0101   {
0102     if (disposition == OPEN_ALWAYS)
0103     {
0104       if ((open_flags & file_base::truncate) != 0)
0105       {
0106         if (!::SetEndOfFile(handle))
0107         {
0108           DWORD last_error = ::GetLastError();
0109           ::CloseHandle(handle);
0110           ec.assign(last_error, boost::asio::error::get_system_category());
0111           BOOST_ASIO_ERROR_LOCATION(ec);
0112           return ec;
0113         }
0114       }
0115     }
0116     if (disposition == OPEN_ALWAYS || disposition == OPEN_EXISTING)
0117     {
0118       if ((open_flags & file_base::append) != 0)
0119       {
0120         LARGE_INTEGER distance, new_offset;
0121         distance.QuadPart = 0;
0122         if (::SetFilePointerEx(handle, distance, &new_offset, FILE_END))
0123         {
0124           impl.offset_ = static_cast<uint64_t>(new_offset.QuadPart);
0125         }
0126         else
0127         {
0128           DWORD last_error = ::GetLastError();
0129           ::CloseHandle(handle);
0130           ec.assign(last_error, boost::asio::error::get_system_category());
0131           BOOST_ASIO_ERROR_LOCATION(ec);
0132           return ec;
0133         }
0134       }
0135     }
0136 
0137     handle_service_.assign(impl, handle, ec);
0138     if (ec)
0139       ::CloseHandle(handle);
0140     BOOST_ASIO_ERROR_LOCATION(ec);
0141     return ec;
0142   }
0143   else
0144   {
0145     DWORD last_error = ::GetLastError();
0146     ec.assign(last_error, boost::asio::error::get_system_category());
0147     BOOST_ASIO_ERROR_LOCATION(ec);
0148     return ec;
0149   }
0150 }
0151 
0152 uint64_t win_iocp_file_service::size(
0153     const win_iocp_file_service::implementation_type& impl,
0154     boost::system::error_code& ec) const
0155 {
0156   LARGE_INTEGER result;
0157   if (::GetFileSizeEx(native_handle(impl), &result))
0158   {
0159     boost::asio::error::clear(ec);
0160     return static_cast<uint64_t>(result.QuadPart);
0161   }
0162   else
0163   {
0164     DWORD last_error = ::GetLastError();
0165     ec.assign(last_error, boost::asio::error::get_system_category());
0166     BOOST_ASIO_ERROR_LOCATION(ec);
0167     return 0;
0168   }
0169 }
0170 
0171 boost::system::error_code win_iocp_file_service::resize(
0172     win_iocp_file_service::implementation_type& impl,
0173     uint64_t n, boost::system::error_code& ec)
0174 {
0175   LARGE_INTEGER distance;
0176   distance.QuadPart = n;
0177   if (::SetFilePointerEx(native_handle(impl), distance, 0, FILE_BEGIN))
0178   {
0179     BOOL result = ::SetEndOfFile(native_handle(impl));
0180     DWORD last_error = ::GetLastError();
0181 
0182     distance.QuadPart = static_cast<LONGLONG>(impl.offset_);
0183     if (!::SetFilePointerEx(native_handle(impl), distance, 0, FILE_BEGIN))
0184     {
0185       result = FALSE;
0186       last_error = ::GetLastError();
0187     }
0188 
0189     if (result)
0190       boost::asio::error::clear(ec);
0191     else
0192       ec.assign(last_error, boost::asio::error::get_system_category());
0193     BOOST_ASIO_ERROR_LOCATION(ec);
0194     return ec;
0195   }
0196   else
0197   {
0198     DWORD last_error = ::GetLastError();
0199     ec.assign(last_error, boost::asio::error::get_system_category());
0200     BOOST_ASIO_ERROR_LOCATION(ec);
0201     return ec;
0202   }
0203 }
0204 
0205 boost::system::error_code win_iocp_file_service::sync_all(
0206     win_iocp_file_service::implementation_type& impl,
0207     boost::system::error_code& ec)
0208 {
0209   BOOL result = ::FlushFileBuffers(native_handle(impl));
0210   if (result)
0211   {
0212     boost::asio::error::clear(ec);
0213     return ec;
0214   }
0215   else
0216   {
0217     DWORD last_error = ::GetLastError();
0218     ec.assign(last_error, boost::asio::error::get_system_category());
0219     BOOST_ASIO_ERROR_LOCATION(ec);
0220     return ec;
0221   }
0222 }
0223 
0224 boost::system::error_code win_iocp_file_service::sync_data(
0225     win_iocp_file_service::implementation_type& impl,
0226     boost::system::error_code& ec)
0227 {
0228   if (nt_flush_buffers_file_ex_)
0229   {
0230     io_status_block status = {};
0231     if (!nt_flush_buffers_file_ex_(native_handle(impl),
0232           flush_flags_file_data_sync_only, 0, 0, &status))
0233     {
0234       boost::asio::error::clear(ec);
0235       return ec;
0236     }
0237   }
0238   return sync_all(impl, ec);
0239 }
0240 
0241 uint64_t win_iocp_file_service::seek(
0242     win_iocp_file_service::implementation_type& impl, int64_t offset,
0243     file_base::seek_basis whence, boost::system::error_code& ec)
0244 {
0245   DWORD method;
0246   switch (whence)
0247   {
0248   case file_base::seek_set:
0249     method = FILE_BEGIN;
0250     break;
0251   case file_base::seek_cur:
0252     method = FILE_BEGIN;
0253     offset = static_cast<int64_t>(impl.offset_) + offset;
0254     break;
0255   case file_base::seek_end:
0256     method = FILE_END;
0257     break;
0258   default:
0259     ec = boost::asio::error::invalid_argument;
0260     BOOST_ASIO_ERROR_LOCATION(ec);
0261     return 0;
0262   }
0263 
0264   LARGE_INTEGER distance, new_offset;
0265   distance.QuadPart = offset;
0266   if (::SetFilePointerEx(native_handle(impl), distance, &new_offset, method))
0267   {
0268     impl.offset_ = new_offset.QuadPart;
0269     boost::asio::error::clear(ec);
0270     return impl.offset_;
0271   }
0272   else
0273   {
0274     DWORD last_error = ::GetLastError();
0275     ec.assign(last_error, boost::asio::error::get_system_category());
0276     BOOST_ASIO_ERROR_LOCATION(ec);
0277     return 0;
0278   }
0279 }
0280 
0281 } // namespace detail
0282 } // namespace asio
0283 } // namespace boost
0284 
0285 #include <boost/asio/detail/pop_options.hpp>
0286 
0287 #endif // defined(BOOST_ASIO_HAS_FILE)
0288        //   && defined(BOOST_ASIO_HAS_WINDOWS_RANDOM_ACCESS_HANDLE)
0289 
0290 #endif // BOOST_ASIO_DETAIL_IMPL_WIN_IOCP_FILE_SERVICE_IPP