file_posix.ipp 7.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339
  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_POSIX_IPP
  10. #define BOOST_BEAST_CORE_IMPL_FILE_POSIX_IPP
  11. #include <boost/beast/core/file_posix.hpp>
  12. #if BOOST_BEAST_USE_POSIX_FILE
  13. #include <boost/core/exchange.hpp>
  14. #include <limits>
  15. #include <fcntl.h>
  16. #include <sys/types.h>
  17. #include <sys/uio.h>
  18. #include <sys/stat.h>
  19. #include <unistd.h>
  20. #include <limits.h>
  21. #if ! defined(BOOST_BEAST_NO_POSIX_FADVISE)
  22. # if defined(__APPLE__) || (defined(__ANDROID__) && (__ANDROID_API__ < 21))
  23. # define BOOST_BEAST_NO_POSIX_FADVISE
  24. # endif
  25. #endif
  26. #if ! defined(BOOST_BEAST_USE_POSIX_FADVISE)
  27. # if ! defined(BOOST_BEAST_NO_POSIX_FADVISE)
  28. # define BOOST_BEAST_USE_POSIX_FADVISE 1
  29. # else
  30. # define BOOST_BEAST_USE_POSIX_FADVISE 0
  31. # endif
  32. #endif
  33. namespace boost {
  34. namespace beast {
  35. int
  36. file_posix::
  37. native_close(native_handle_type& fd)
  38. {
  39. /* https://github.com/boostorg/beast/issues/1445
  40. This function is tuned for Linux / Mac OS:
  41. * only calls close() once
  42. * returns the error directly to the caller
  43. * does not loop on EINTR
  44. If this is incorrect for the platform, then the
  45. caller will need to implement their own type
  46. meeting the File requirements and use the correct
  47. behavior.
  48. See:
  49. http://man7.org/linux/man-pages/man2/close.2.html
  50. */
  51. int ev = 0;
  52. if(fd != -1)
  53. {
  54. if(::close(fd) != 0)
  55. ev = errno;
  56. fd = -1;
  57. }
  58. return ev;
  59. }
  60. file_posix::
  61. ~file_posix()
  62. {
  63. native_close(fd_);
  64. }
  65. file_posix::
  66. file_posix(file_posix&& other)
  67. : fd_(boost::exchange(other.fd_, -1))
  68. {
  69. }
  70. file_posix&
  71. file_posix::
  72. operator=(file_posix&& other)
  73. {
  74. if(&other == this)
  75. return *this;
  76. native_close(fd_);
  77. fd_ = other.fd_;
  78. other.fd_ = -1;
  79. return *this;
  80. }
  81. void
  82. file_posix::
  83. native_handle(native_handle_type fd)
  84. {
  85. native_close(fd_);
  86. fd_ = fd;
  87. }
  88. void
  89. file_posix::
  90. close(error_code& ec)
  91. {
  92. auto const ev = native_close(fd_);
  93. if(ev)
  94. ec.assign(ev, system_category());
  95. else
  96. ec = {};
  97. }
  98. void
  99. file_posix::
  100. open(char const* path, file_mode mode, error_code& ec)
  101. {
  102. auto const ev = native_close(fd_);
  103. if(ev)
  104. ec.assign(ev, system_category());
  105. else
  106. ec = {};
  107. int f = 0;
  108. #if BOOST_BEAST_USE_POSIX_FADVISE
  109. int advise = 0;
  110. #endif
  111. switch(mode)
  112. {
  113. default:
  114. case file_mode::read:
  115. f = O_RDONLY;
  116. #if BOOST_BEAST_USE_POSIX_FADVISE
  117. advise = POSIX_FADV_RANDOM;
  118. #endif
  119. break;
  120. case file_mode::scan:
  121. f = O_RDONLY;
  122. #if BOOST_BEAST_USE_POSIX_FADVISE
  123. advise = POSIX_FADV_SEQUENTIAL;
  124. #endif
  125. break;
  126. case file_mode::write:
  127. f = O_RDWR | O_CREAT | O_TRUNC;
  128. #if BOOST_BEAST_USE_POSIX_FADVISE
  129. advise = POSIX_FADV_RANDOM;
  130. #endif
  131. break;
  132. case file_mode::write_new:
  133. f = O_RDWR | O_CREAT | O_EXCL;
  134. #if BOOST_BEAST_USE_POSIX_FADVISE
  135. advise = POSIX_FADV_RANDOM;
  136. #endif
  137. break;
  138. case file_mode::write_existing:
  139. f = O_RDWR | O_EXCL;
  140. #if BOOST_BEAST_USE_POSIX_FADVISE
  141. advise = POSIX_FADV_RANDOM;
  142. #endif
  143. break;
  144. case file_mode::append:
  145. f = O_WRONLY | O_CREAT | O_APPEND;
  146. #if BOOST_BEAST_USE_POSIX_FADVISE
  147. advise = POSIX_FADV_SEQUENTIAL;
  148. #endif
  149. break;
  150. case file_mode::append_existing:
  151. f = O_WRONLY | O_APPEND;
  152. #if BOOST_BEAST_USE_POSIX_FADVISE
  153. advise = POSIX_FADV_SEQUENTIAL;
  154. #endif
  155. break;
  156. }
  157. for(;;)
  158. {
  159. fd_ = ::open(path, f, 0644);
  160. if(fd_ != -1)
  161. break;
  162. auto const ev = errno;
  163. if(ev != EINTR)
  164. {
  165. ec.assign(ev, system_category());
  166. return;
  167. }
  168. }
  169. #if BOOST_BEAST_USE_POSIX_FADVISE
  170. if(::posix_fadvise(fd_, 0, 0, advise))
  171. {
  172. auto const ev = errno;
  173. native_close(fd_);
  174. ec.assign(ev, system_category());
  175. return;
  176. }
  177. #endif
  178. ec = {};
  179. }
  180. std::uint64_t
  181. file_posix::
  182. size(error_code& ec) const
  183. {
  184. if(fd_ == -1)
  185. {
  186. ec = make_error_code(errc::bad_file_descriptor);
  187. return 0;
  188. }
  189. struct stat st;
  190. if(::fstat(fd_, &st) != 0)
  191. {
  192. ec.assign(errno, system_category());
  193. return 0;
  194. }
  195. ec = {};
  196. return st.st_size;
  197. }
  198. std::uint64_t
  199. file_posix::
  200. pos(error_code& ec) const
  201. {
  202. if(fd_ == -1)
  203. {
  204. ec = make_error_code(errc::bad_file_descriptor);
  205. return 0;
  206. }
  207. auto const result = ::lseek(fd_, 0, SEEK_CUR);
  208. if(result == (off_t)-1)
  209. {
  210. ec.assign(errno, system_category());
  211. return 0;
  212. }
  213. ec = {};
  214. return result;
  215. }
  216. void
  217. file_posix::
  218. seek(std::uint64_t offset, error_code& ec)
  219. {
  220. if(fd_ == -1)
  221. {
  222. ec = make_error_code(errc::bad_file_descriptor);
  223. return;
  224. }
  225. auto const result = ::lseek(fd_, offset, SEEK_SET);
  226. if(result == static_cast<off_t>(-1))
  227. {
  228. ec.assign(errno, system_category());
  229. return;
  230. }
  231. ec = {};
  232. }
  233. std::size_t
  234. file_posix::
  235. read(void* buffer, std::size_t n, error_code& ec) const
  236. {
  237. if(fd_ == -1)
  238. {
  239. ec = make_error_code(errc::bad_file_descriptor);
  240. return 0;
  241. }
  242. std::size_t nread = 0;
  243. while(n > 0)
  244. {
  245. // <limits> not required to define SSIZE_MAX so we avoid it
  246. constexpr auto ssmax =
  247. static_cast<std::size_t>((std::numeric_limits<
  248. decltype(::read(fd_, buffer, n))>::max)());
  249. auto const amount = (std::min)(
  250. n, ssmax);
  251. auto const result = ::read(fd_, buffer, amount);
  252. if(result == -1)
  253. {
  254. auto const ev = errno;
  255. if(ev == EINTR)
  256. continue;
  257. ec.assign(ev, system_category());
  258. return nread;
  259. }
  260. if(result == 0)
  261. {
  262. // short read
  263. return nread;
  264. }
  265. n -= result;
  266. nread += result;
  267. buffer = static_cast<char*>(buffer) + result;
  268. }
  269. return nread;
  270. }
  271. std::size_t
  272. file_posix::
  273. write(void const* buffer, std::size_t n, error_code& ec)
  274. {
  275. if(fd_ == -1)
  276. {
  277. ec = make_error_code(errc::bad_file_descriptor);
  278. return 0;
  279. }
  280. std::size_t nwritten = 0;
  281. while(n > 0)
  282. {
  283. // <limits> not required to define SSIZE_MAX so we avoid it
  284. constexpr auto ssmax =
  285. static_cast<std::size_t>((std::numeric_limits<
  286. decltype(::write(fd_, buffer, n))>::max)());
  287. auto const amount = (std::min)(
  288. n, ssmax);
  289. auto const result = ::write(fd_, buffer, amount);
  290. if(result == -1)
  291. {
  292. auto const ev = errno;
  293. if(ev == EINTR)
  294. continue;
  295. ec.assign(ev, system_category());
  296. return nwritten;
  297. }
  298. n -= result;
  299. nwritten += result;
  300. buffer = static_cast<char const*>(buffer) + result;
  301. }
  302. return nwritten;
  303. }
  304. } // beast
  305. } // boost
  306. #endif
  307. #endif