1// 2// Copyright (c) 2015-2019 Vinnie Falco (vinnie dot falco at gmail dot com) 3// 4// Distributed under the Boost Software License, Version 1.0. (See accompanying 5// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) 6// 7// Official repository: https://github.com/boostorg/beast 8// 9 10#ifndef BOOST_BEAST_CORE_IMPL_FILE_STDIO_IPP 11#define BOOST_BEAST_CORE_IMPL_FILE_STDIO_IPP 12 13#include <boost/beast/core/file_stdio.hpp> 14#include <boost/beast/core/detail/win32_unicode_path.hpp> 15#include <boost/config/workaround.hpp> 16#include <boost/core/exchange.hpp> 17#include <limits> 18 19namespace boost { 20namespace beast { 21 22file_stdio:: 23~file_stdio() 24{ 25 if(f_) 26 fclose(f_); 27} 28 29file_stdio:: 30file_stdio(file_stdio&& other) 31 : f_(boost::exchange(other.f_, nullptr)) 32{ 33} 34 35file_stdio& 36file_stdio:: 37operator=(file_stdio&& other) 38{ 39 if(&other == this) 40 return *this; 41 if(f_) 42 fclose(f_); 43 f_ = other.f_; 44 other.f_ = nullptr; 45 return *this; 46} 47 48void 49file_stdio:: 50native_handle(std::FILE* f) 51{ 52 if(f_) 53 fclose(f_); 54 f_ = f; 55} 56 57void 58file_stdio:: 59close(error_code& ec) 60{ 61 if(f_) 62 { 63 int failed = fclose(f_); 64 f_ = nullptr; 65 if(failed) 66 { 67 ec.assign(errno, generic_category()); 68 return; 69 } 70 } 71 ec = {}; 72} 73 74void 75file_stdio:: 76open(char const* path, file_mode mode, error_code& ec) 77{ 78 if(f_) 79 { 80 fclose(f_); 81 f_ = nullptr; 82 } 83 ec = {}; 84#ifdef BOOST_MSVC 85 boost::winapi::WCHAR_ const* s; 86 detail::win32_unicode_path unicode_path(path, ec); 87 if (ec) 88 return; 89#else 90 char const* s; 91#endif 92 switch(mode) 93 { 94 default: 95 case file_mode::read: 96 #ifdef BOOST_MSVC 97 s = L"rb"; 98 #else 99 s = "rb"; 100 #endif 101 break; 102 103 case file_mode::scan: 104 #ifdef BOOST_MSVC 105 s = L"rbS"; 106 #else 107 s = "rb"; 108 #endif 109 break; 110 111 case file_mode::write: 112 #ifdef BOOST_MSVC 113 s = L"wb+"; 114 #else 115 s = "wb+"; 116 #endif 117 break; 118 119 case file_mode::write_new: 120 { 121#if BOOST_WORKAROUND(BOOST_MSVC, < 1910) 122 std::FILE* f0; 123 auto const ev = ::_wfopen_s(&f0, unicode_path.c_str(), L"rb"); 124 if(! ev) 125 { 126 std::fclose(f0); 127 ec = make_error_code(errc::file_exists); 128 return; 129 } 130 else if(ev != 131 errc::no_such_file_or_directory) 132 { 133 ec.assign(ev, generic_category()); 134 return; 135 } 136 s = L"wb"; 137#elif defined(BOOST_MSVC) 138 s = L"wbx"; 139#else 140 s = "wbx"; 141#endif 142 break; 143 } 144 145 case file_mode::write_existing: 146 #ifdef BOOST_MSVC 147 s = L"rb+"; 148 #else 149 s = "rb+"; 150 #endif 151 break; 152 153 case file_mode::append: 154 #ifdef BOOST_MSVC 155 s = L"ab"; 156 #else 157 s = "ab"; 158 #endif 159 break; 160 161 case file_mode::append_existing: 162 { 163#ifdef BOOST_MSVC 164 std::FILE* f0; 165 auto const ev = 166 ::_wfopen_s(&f0, unicode_path.c_str(), L"rb+"); 167 if(ev) 168 { 169 ec.assign(ev, generic_category()); 170 return; 171 } 172#else 173 auto const f0 = 174 std::fopen(path, "rb+"); 175 if(! f0) 176 { 177 ec.assign(errno, generic_category()); 178 return; 179 } 180#endif 181 std::fclose(f0); 182 #ifdef BOOST_MSVC 183 s = L"ab"; 184 #else 185 s = "ab"; 186 #endif 187 break; 188 } 189 } 190 191#ifdef BOOST_MSVC 192 auto const ev = ::_wfopen_s(&f_, unicode_path.c_str(), s); 193 if(ev) 194 { 195 f_ = nullptr; 196 ec.assign(ev, generic_category()); 197 return; 198 } 199#else 200 f_ = std::fopen(path, s); 201 if(! f_) 202 { 203 ec.assign(errno, generic_category()); 204 return; 205 } 206#endif 207} 208 209std::uint64_t 210file_stdio:: 211size(error_code& ec) const 212{ 213 if(! f_) 214 { 215 ec = make_error_code(errc::bad_file_descriptor); 216 return 0; 217 } 218 long pos = std::ftell(f_); 219 if(pos == -1L) 220 { 221 ec.assign(errno, generic_category()); 222 return 0; 223 } 224 int result = std::fseek(f_, 0, SEEK_END); 225 if(result != 0) 226 { 227 ec.assign(errno, generic_category()); 228 return 0; 229 } 230 long size = std::ftell(f_); 231 if(size == -1L) 232 { 233 ec.assign(errno, generic_category()); 234 std::fseek(f_, pos, SEEK_SET); 235 return 0; 236 } 237 result = std::fseek(f_, pos, SEEK_SET); 238 if(result != 0) 239 ec.assign(errno, generic_category()); 240 else 241 ec = {}; 242 return size; 243} 244 245std::uint64_t 246file_stdio:: 247pos(error_code& ec) const 248{ 249 if(! f_) 250 { 251 ec = make_error_code(errc::bad_file_descriptor); 252 return 0; 253 } 254 long pos = std::ftell(f_); 255 if(pos == -1L) 256 { 257 ec.assign(errno, generic_category()); 258 return 0; 259 } 260 ec = {}; 261 return pos; 262} 263 264void 265file_stdio:: 266seek(std::uint64_t offset, error_code& ec) 267{ 268 if(! f_) 269 { 270 ec = make_error_code(errc::bad_file_descriptor); 271 return; 272 } 273 if(offset > static_cast<std::uint64_t>((std::numeric_limits<long>::max)())) 274 { 275 ec = make_error_code(errc::invalid_seek); 276 return; 277 } 278 int result = std::fseek(f_, 279 static_cast<long>(offset), SEEK_SET); 280 if(result != 0) 281 ec.assign(errno, generic_category()); 282 else 283 ec = {}; 284} 285 286std::size_t 287file_stdio:: 288read(void* buffer, std::size_t n, error_code& ec) const 289{ 290 if(! f_) 291 { 292 ec = make_error_code(errc::bad_file_descriptor); 293 return 0; 294 } 295 auto nread = std::fread(buffer, 1, n, f_); 296 if(std::ferror(f_)) 297 { 298 ec.assign(errno, generic_category()); 299 return 0; 300 } 301 return nread; 302} 303 304std::size_t 305file_stdio:: 306write(void const* buffer, std::size_t n, error_code& ec) 307{ 308 if(! f_) 309 { 310 ec = make_error_code(errc::bad_file_descriptor); 311 return 0; 312 } 313 auto nwritten = std::fwrite(buffer, 1, n, f_); 314 if(std::ferror(f_)) 315 { 316 ec.assign(errno, generic_category()); 317 return 0; 318 } 319 return nwritten; 320} 321 322} // beast 323} // boost 324 325#endif 326