]>
Commit | Line | Data |
---|---|---|
b32b8144 FG |
1 | // |
2 | // Copyright (c) 2015-2016 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_POSIX_IPP | |
11 | #define BOOST_BEAST_CORE_IMPL_FILE_POSIX_IPP | |
12 | ||
13 | #if ! defined(BOOST_BEAST_NO_POSIX_FADVISE) | |
14 | # if defined(__APPLE__) || (defined(ANDROID) && (__ANDROID_API__ < 21)) | |
15 | # define BOOST_BEAST_NO_POSIX_FADVISE | |
16 | # endif | |
17 | #endif | |
18 | ||
19 | #if ! defined(BOOST_BEAST_USE_POSIX_FADVISE) | |
20 | # if ! defined(BOOST_BEAST_NO_POSIX_FADVISE) | |
21 | # define BOOST_BEAST_USE_POSIX_FADVISE 1 | |
22 | # else | |
23 | # define BOOST_BEAST_USE_POSIX_FADVISE 0 | |
24 | # endif | |
25 | #endif | |
26 | ||
27 | #include <limits> | |
28 | #include <fcntl.h> | |
29 | #include <sys/types.h> | |
30 | #include <sys/uio.h> | |
31 | #include <sys/stat.h> | |
32 | #include <unistd.h> | |
33 | #include <limits.h> | |
34 | ||
35 | namespace boost { | |
36 | namespace beast { | |
37 | ||
38 | namespace detail { | |
39 | ||
40 | inline | |
41 | int | |
42 | file_posix_close(int fd) | |
43 | { | |
44 | for(;;) | |
45 | { | |
46 | if(! ::close(fd)) | |
47 | break; | |
48 | int const ev = errno; | |
49 | if(errno != EINTR) | |
50 | return ev; | |
51 | } | |
52 | return 0; | |
53 | } | |
54 | ||
55 | } // detail | |
56 | ||
57 | inline | |
58 | file_posix:: | |
59 | ~file_posix() | |
60 | { | |
61 | if(fd_ != -1) | |
62 | detail::file_posix_close(fd_); | |
63 | } | |
64 | ||
65 | inline | |
66 | file_posix:: | |
67 | file_posix(file_posix&& other) | |
68 | : fd_(other.fd_) | |
69 | { | |
70 | other.fd_ = -1; | |
71 | } | |
72 | ||
73 | inline | |
74 | file_posix& | |
75 | file_posix:: | |
76 | operator=(file_posix&& other) | |
77 | { | |
78 | if(&other == this) | |
79 | return *this; | |
80 | if(fd_ != -1) | |
81 | detail::file_posix_close(fd_); | |
82 | fd_ = other.fd_; | |
83 | other.fd_ = -1; | |
84 | return *this; | |
85 | } | |
86 | ||
87 | inline | |
88 | void | |
89 | file_posix:: | |
90 | native_handle(native_handle_type fd) | |
91 | { | |
92 | if(fd_ != -1) | |
93 | detail::file_posix_close(fd_); | |
94 | fd_ = fd; | |
95 | } | |
96 | ||
97 | inline | |
98 | void | |
99 | file_posix:: | |
100 | close(error_code& ec) | |
101 | { | |
102 | if(fd_ != -1) | |
103 | { | |
104 | auto const ev = | |
105 | detail::file_posix_close(fd_); | |
106 | if(ev) | |
107 | ec.assign(ev, generic_category()); | |
108 | else | |
109 | ec.assign(0, ec.category()); | |
110 | fd_ = -1; | |
111 | } | |
112 | else | |
113 | { | |
114 | ec.assign(0, ec.category()); | |
115 | } | |
116 | } | |
117 | ||
118 | inline | |
119 | void | |
120 | file_posix:: | |
121 | open(char const* path, file_mode mode, error_code& ec) | |
122 | { | |
123 | if(fd_ != -1) | |
124 | { | |
125 | auto const ev = | |
126 | detail::file_posix_close(fd_); | |
127 | if(ev) | |
128 | ec.assign(ev, generic_category()); | |
129 | else | |
130 | ec.assign(0, ec.category()); | |
131 | fd_ = -1; | |
132 | } | |
133 | int f = 0; | |
134 | #if BOOST_BEAST_USE_POSIX_FADVISE | |
135 | int advise = 0; | |
136 | #endif | |
137 | switch(mode) | |
138 | { | |
139 | default: | |
140 | case file_mode::read: | |
141 | f = O_RDONLY; | |
142 | #if BOOST_BEAST_USE_POSIX_FADVISE | |
143 | advise = POSIX_FADV_RANDOM; | |
144 | #endif | |
145 | break; | |
146 | case file_mode::scan: | |
147 | f = O_RDONLY; | |
148 | #if BOOST_BEAST_USE_POSIX_FADVISE | |
149 | advise = POSIX_FADV_SEQUENTIAL; | |
150 | #endif | |
151 | break; | |
152 | ||
153 | case file_mode::write: | |
154 | f = O_RDWR | O_CREAT | O_TRUNC; | |
155 | #if BOOST_BEAST_USE_POSIX_FADVISE | |
156 | advise = POSIX_FADV_RANDOM; | |
157 | #endif | |
158 | break; | |
159 | ||
160 | case file_mode::write_new: | |
161 | f = O_RDWR | O_CREAT | O_EXCL; | |
162 | #if BOOST_BEAST_USE_POSIX_FADVISE | |
163 | advise = POSIX_FADV_RANDOM; | |
164 | #endif | |
165 | break; | |
166 | ||
167 | case file_mode::write_existing: | |
168 | f = O_RDWR | O_EXCL; | |
169 | #if BOOST_BEAST_USE_POSIX_FADVISE | |
170 | advise = POSIX_FADV_RANDOM; | |
171 | #endif | |
172 | break; | |
173 | ||
174 | case file_mode::append: | |
175 | f = O_RDWR | O_CREAT | O_TRUNC; | |
176 | #if BOOST_BEAST_USE_POSIX_FADVISE | |
177 | advise = POSIX_FADV_SEQUENTIAL; | |
178 | #endif | |
179 | break; | |
180 | ||
181 | case file_mode::append_new: | |
182 | f = O_RDWR | O_CREAT | O_EXCL; | |
183 | #if BOOST_BEAST_USE_POSIX_FADVISE | |
184 | advise = POSIX_FADV_SEQUENTIAL; | |
185 | #endif | |
186 | break; | |
187 | ||
188 | case file_mode::append_existing: | |
189 | f = O_RDWR | O_EXCL; | |
190 | #if BOOST_BEAST_USE_POSIX_FADVISE | |
191 | advise = POSIX_FADV_SEQUENTIAL; | |
192 | #endif | |
193 | break; | |
194 | } | |
195 | for(;;) | |
196 | { | |
197 | fd_ = ::open(path, f, 0644); | |
198 | if(fd_ != -1) | |
199 | break; | |
200 | auto const ev = errno; | |
201 | if(ev != EINTR) | |
202 | { | |
203 | ec.assign(ev, generic_category()); | |
204 | return; | |
205 | } | |
206 | } | |
207 | #if BOOST_BEAST_USE_POSIX_FADVISE | |
208 | if(::posix_fadvise(fd_, 0, 0, advise)) | |
209 | { | |
210 | auto const ev = errno; | |
211 | detail::file_posix_close(fd_); | |
212 | fd_ = -1; | |
213 | ec.assign(ev, generic_category()); | |
214 | return; | |
215 | } | |
216 | #endif | |
217 | ec.assign(0, ec.category()); | |
218 | } | |
219 | ||
220 | inline | |
221 | std::uint64_t | |
222 | file_posix:: | |
223 | size(error_code& ec) const | |
224 | { | |
225 | if(fd_ == -1) | |
226 | { | |
227 | ec.assign(errc::invalid_argument, generic_category()); | |
228 | return 0; | |
229 | } | |
230 | struct stat st; | |
231 | if(::fstat(fd_, &st) != 0) | |
232 | { | |
233 | ec.assign(errno, generic_category()); | |
234 | return 0; | |
235 | } | |
236 | ec.assign(0, ec.category()); | |
237 | return st.st_size; | |
238 | } | |
239 | ||
240 | inline | |
241 | std::uint64_t | |
242 | file_posix:: | |
243 | pos(error_code& ec) const | |
244 | { | |
245 | if(fd_ == -1) | |
246 | { | |
247 | ec.assign(errc::invalid_argument, generic_category()); | |
248 | return 0; | |
249 | } | |
250 | auto const result = ::lseek(fd_, 0, SEEK_CUR); | |
251 | if(result == (off_t)-1) | |
252 | { | |
253 | ec.assign(errno, generic_category()); | |
254 | return 0; | |
255 | } | |
256 | ec.assign(0, ec.category()); | |
257 | return result; | |
258 | } | |
259 | ||
260 | inline | |
261 | void | |
262 | file_posix:: | |
263 | seek(std::uint64_t offset, error_code& ec) | |
264 | { | |
265 | if(fd_ == -1) | |
266 | { | |
267 | ec.assign(errc::invalid_argument, generic_category()); | |
268 | return; | |
269 | } | |
270 | auto const result = ::lseek(fd_, offset, SEEK_SET); | |
271 | if(result == static_cast<off_t>(-1)) | |
272 | { | |
273 | ec.assign(errno, generic_category()); | |
274 | return; | |
275 | } | |
276 | ec.assign(0, ec.category()); | |
277 | } | |
278 | ||
279 | inline | |
280 | std::size_t | |
281 | file_posix:: | |
282 | read(void* buffer, std::size_t n, error_code& ec) const | |
283 | { | |
284 | if(fd_ == -1) | |
285 | { | |
286 | ec.assign(errc::invalid_argument, generic_category()); | |
287 | return 0; | |
288 | } | |
289 | std::size_t nread = 0; | |
290 | while(n > 0) | |
291 | { | |
292 | auto const amount = static_cast<ssize_t>((std::min)( | |
293 | n, static_cast<std::size_t>(SSIZE_MAX))); | |
294 | auto const result = ::read(fd_, buffer, amount); | |
295 | if(result == -1) | |
296 | { | |
297 | auto const ev = errno; | |
298 | if(ev == EINTR) | |
299 | continue; | |
300 | ec.assign(ev, generic_category()); | |
301 | return nread; | |
302 | } | |
303 | if(result == 0) | |
304 | { | |
305 | // short read | |
306 | return nread; | |
307 | } | |
308 | n -= result; | |
309 | nread += result; | |
310 | buffer = reinterpret_cast<char*>(buffer) + result; | |
311 | } | |
312 | return nread; | |
313 | } | |
314 | ||
315 | inline | |
316 | std::size_t | |
317 | file_posix:: | |
318 | write(void const* buffer, std::size_t n, error_code& ec) | |
319 | { | |
320 | if(fd_ == -1) | |
321 | { | |
322 | ec.assign(errc::invalid_argument, generic_category()); | |
323 | return 0; | |
324 | } | |
325 | std::size_t nwritten = 0; | |
326 | while(n > 0) | |
327 | { | |
328 | auto const amount = static_cast<ssize_t>((std::min)( | |
329 | n, static_cast<std::size_t>(SSIZE_MAX))); | |
330 | auto const result = ::write(fd_, buffer, amount); | |
331 | if(result == -1) | |
332 | { | |
333 | auto const ev = errno; | |
334 | if(ev == EINTR) | |
335 | continue; | |
336 | ec.assign(ev, generic_category()); | |
337 | return nwritten; | |
338 | } | |
339 | n -= result; | |
340 | nwritten += result; | |
341 | buffer = reinterpret_cast<char const*>(buffer) + result; | |
342 | } | |
343 | return nwritten; | |
344 | } | |
345 | ||
346 | } // beast | |
347 | } // boost | |
348 | ||
349 | #endif |