file_stdio.ipp 5.3 KB

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