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