1 | /* |
2 | * Copyright 2013-present Facebook, Inc. |
3 | * |
4 | * Licensed under the Apache License, Version 2.0 (the "License"); |
5 | * you may not use this file except in compliance with the License. |
6 | * You may obtain a copy of the License at |
7 | * |
8 | * http://www.apache.org/licenses/LICENSE-2.0 |
9 | * |
10 | * Unless required by applicable law or agreed to in writing, software |
11 | * distributed under the License is distributed on an "AS IS" BASIS, |
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
13 | * See the License for the specific language governing permissions and |
14 | * limitations under the License. |
15 | */ |
16 | |
17 | #pragma once |
18 | |
19 | #include <algorithm> |
20 | #include <cerrno> |
21 | |
22 | #include <folly/portability/SysUio.h> |
23 | #include <folly/portability/Unistd.h> |
24 | |
25 | /** |
26 | * Helper functions and templates for FileUtil.cpp. Declared here so |
27 | * they can be unittested. |
28 | */ |
29 | namespace folly { |
30 | namespace fileutil_detail { |
31 | |
32 | // Wrap call to f(args) in loop to retry on EINTR |
33 | template <class F, class... Args> |
34 | ssize_t wrapNoInt(F f, Args... args) { |
35 | ssize_t r; |
36 | do { |
37 | r = f(args...); |
38 | } while (r == -1 && errno == EINTR); |
39 | return r; |
40 | } |
41 | |
42 | inline void incr(ssize_t /* n */) {} |
43 | inline void incr(ssize_t n, off_t& offset) { |
44 | offset += off_t(n); |
45 | } |
46 | |
47 | // Wrap call to read/pread/write/pwrite(fd, buf, count, offset?) to retry on |
48 | // incomplete reads / writes. The variadic argument magic is there to support |
49 | // an additional argument (offset) for pread / pwrite; see the incr() functions |
50 | // above which do nothing if the offset is not present and increment it if it |
51 | // is. |
52 | template <class F, class... Offset> |
53 | ssize_t wrapFull(F f, int fd, void* buf, size_t count, Offset... offset) { |
54 | char* b = static_cast<char*>(buf); |
55 | ssize_t totalBytes = 0; |
56 | ssize_t r; |
57 | do { |
58 | r = f(fd, b, count, offset...); |
59 | if (r == -1) { |
60 | if (errno == EINTR) { |
61 | continue; |
62 | } |
63 | return r; |
64 | } |
65 | |
66 | totalBytes += r; |
67 | b += r; |
68 | count -= r; |
69 | incr(r, offset...); |
70 | } while (r != 0 && count); // 0 means EOF |
71 | |
72 | return totalBytes; |
73 | } |
74 | |
75 | // Wrap call to readv/preadv/writev/pwritev(fd, iov, count, offset?) to |
76 | // retry on incomplete reads / writes. |
77 | template <class F, class... Offset> |
78 | ssize_t wrapvFull(F f, int fd, iovec* iov, int count, Offset... offset) { |
79 | ssize_t totalBytes = 0; |
80 | ssize_t r; |
81 | do { |
82 | r = f(fd, iov, std::min<int>(count, kIovMax), offset...); |
83 | if (r == -1) { |
84 | if (errno == EINTR) { |
85 | continue; |
86 | } |
87 | return r; |
88 | } |
89 | |
90 | if (r == 0) { |
91 | break; // EOF |
92 | } |
93 | |
94 | totalBytes += r; |
95 | incr(r, offset...); |
96 | while (r != 0 && count != 0) { |
97 | if (r >= ssize_t(iov->iov_len)) { |
98 | r -= ssize_t(iov->iov_len); |
99 | ++iov; |
100 | --count; |
101 | } else { |
102 | iov->iov_base = static_cast<char*>(iov->iov_base) + r; |
103 | iov->iov_len -= r; |
104 | r = 0; |
105 | } |
106 | } |
107 | } while (count); |
108 | |
109 | return totalBytes; |
110 | } |
111 | |
112 | } // namespace fileutil_detail |
113 | } // namespace folly |
114 | |