File indexing completed on 2025-07-02 08:06:24
0001
0002
0003
0004
0005
0006
0007
0008
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
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 }
0282 }
0283 }
0284
0285 #include <boost/asio/detail/pop_options.hpp>
0286
0287 #endif
0288
0289
0290 #endif