template< -> template <
[folly.git] / folly / detail / FileUtilDetail.h
1 /*
2  * Copyright 2017 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 <cerrno>
20
21 #include <folly/portability/SysUio.h>
22 #include <folly/portability/Unistd.h>
23
24 /**
25  * Helper functions and templates for FileUtil.cpp.  Declared here so
26  * they can be unittested.
27  */
28 namespace folly { namespace fileutil_detail {
29
30 // Wrap call to f(args) in loop to retry on EINTR
31 template <class F, class... Args>
32 ssize_t wrapNoInt(F f, Args... args) {
33   ssize_t r;
34   do {
35     r = f(args...);
36   } while (r == -1 && errno == EINTR);
37   return r;
38 }
39
40 inline void incr(ssize_t /* n */) {}
41 inline void incr(ssize_t n, off_t& offset) { offset += off_t(n); }
42
43 // Wrap call to read/pread/write/pwrite(fd, buf, count, offset?) to retry on
44 // incomplete reads / writes.  The variadic argument magic is there to support
45 // an additional argument (offset) for pread / pwrite; see the incr() functions
46 // above which do nothing if the offset is not present and increment it if it
47 // is.
48 template <class F, class... Offset>
49 ssize_t wrapFull(F f, int fd, void* buf, size_t count, Offset... offset) {
50   char* b = static_cast<char*>(buf);
51   ssize_t totalBytes = 0;
52   ssize_t r;
53   do {
54     r = f(fd, b, count, offset...);
55     if (r == -1) {
56       if (errno == EINTR) {
57         continue;
58       }
59       return r;
60     }
61
62     totalBytes += r;
63     b += r;
64     count -= r;
65     incr(r, offset...);
66   } while (r != 0 && count);  // 0 means EOF
67
68   return totalBytes;
69 }
70
71 // Wrap call to readv/preadv/writev/pwritev(fd, iov, count, offset?) to
72 // retry on incomplete reads / writes.
73 template <class F, class... Offset>
74 ssize_t wrapvFull(F f, int fd, iovec* iov, int count, Offset... offset) {
75   ssize_t totalBytes = 0;
76   ssize_t r;
77   do {
78     r = f(fd, iov, std::min<int>(count, kIovMax), offset...);
79     if (r == -1) {
80       if (errno == EINTR) {
81         continue;
82       }
83       return r;
84     }
85
86     if (r == 0) {
87       break;  // EOF
88     }
89
90     totalBytes += r;
91     incr(r, offset...);
92     while (r != 0 && count != 0) {
93       if (r >= ssize_t(iov->iov_len)) {
94         r -= ssize_t(iov->iov_len);
95         ++iov;
96         --count;
97       } else {
98         iov->iov_base = static_cast<char*>(iov->iov_base) + r;
99         iov->iov_len -= r;
100         r = 0;
101       }
102     }
103   } while (count);
104
105   return totalBytes;
106 }
107
108 }}  // namespaces