flock locks in folly::File, FileUtil, Exception.h fixes and tests
[folly.git] / folly / FileUtil.cpp
1 /*
2  * Copyright 2013 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 #include "folly/FileUtil.h"
18
19 #include <cerrno>
20
21 namespace folly {
22
23 int closeNoInt(int fd) {
24   int r = close(fd);
25   // Ignore EINTR.  On Linux, close() may only return EINTR after the file
26   // descriptor has been closed, so you must not retry close() on EINTR --
27   // in the best case, you'll get EBADF, and in the worst case, you'll end up
28   // closing a different file (one opened from another thread).
29   //
30   // Interestingly enough, the Single Unix Specification says that the state
31   // of the file descriptor is unspecified if close returns EINTR.  In that
32   // case, the safe thing to do is also not to retry close() -- leaking a file
33   // descriptor is probably better than closing the wrong file.
34   if (r == -1 && errno == EINTR) {
35     r = 0;
36   }
37   return r;
38 }
39
40 namespace {
41
42 // Wrap call to f(args) in loop to retry on EINTR
43 template<typename F, typename... Args>
44 ssize_t wrapNoInt(F f, Args... args) {
45   ssize_t r;
46   do {
47     r = f(args...);
48   } while (r == -1 && errno == EINTR);
49   return r;
50 }
51
52 }  // namespace
53
54 ssize_t readNoInt(int fd, void* buf, size_t count) {
55   return wrapNoInt(read, fd, buf, count);
56 }
57
58 ssize_t preadNoInt(int fd, void* buf, size_t count, off_t offset) {
59   return wrapNoInt(pread, fd, buf, count, offset);
60 }
61
62 ssize_t readvNoInt(int fd, const struct iovec* iov, int count) {
63   return wrapNoInt(writev, fd, iov, count);
64 }
65
66 ssize_t writeNoInt(int fd, const void* buf, size_t count) {
67   return wrapNoInt(write, fd, buf, count);
68 }
69
70 ssize_t pwriteNoInt(int fd, const void* buf, size_t count, off_t offset) {
71   return wrapNoInt(pwrite, fd, buf, count, offset);
72 }
73
74 ssize_t writevNoInt(int fd, const struct iovec* iov, int count) {
75   return wrapNoInt(writev, fd, iov, count);
76 }
77
78 ssize_t readFull(int fd, void* buf, size_t count) {
79   char* b = static_cast<char*>(buf);
80   ssize_t totalBytes = 0;
81   ssize_t r;
82   do {
83     r = read(fd, b, count);
84     if (r == -1) {
85       if (errno == EINTR) {
86         continue;
87       }
88       return r;
89     }
90
91     totalBytes += r;
92     b += r;
93     count -= r;
94   } while (r != 0 && count);  // 0 means EOF
95
96   return totalBytes;
97 }
98
99 ssize_t preadFull(int fd, void* buf, size_t count, off_t offset) {
100   char* b = static_cast<char*>(buf);
101   ssize_t totalBytes = 0;
102   ssize_t r;
103   do {
104     r = pread(fd, b, count, offset);
105     if (r == -1) {
106       if (errno == EINTR) {
107         continue;
108       }
109       return r;
110     }
111
112     totalBytes += r;
113     b += r;
114     offset += r;
115     count -= r;
116   } while (r != 0 && count);  // 0 means EOF
117
118   return totalBytes;
119 }
120
121 ssize_t writeFull(int fd, const void* buf, size_t count) {
122   const char* b = static_cast<const char*>(buf);
123   ssize_t totalBytes = 0;
124   ssize_t r;
125   do {
126     r = write(fd, b, count);
127     if (r == -1) {
128       if (errno == EINTR) {
129         continue;
130       }
131       return r;
132     }
133
134     totalBytes += r;
135     b += r;
136     count -= r;
137   } while (r != 0 && count);  // 0 means EOF
138
139   return totalBytes;
140 }
141
142 ssize_t pwriteFull(int fd, const void* buf, size_t count, off_t offset) {
143   const char* b = static_cast<const char*>(buf);
144   ssize_t totalBytes = 0;
145   ssize_t r;
146   do {
147     r = pwrite(fd, b, count, offset);
148     if (r == -1) {
149       if (errno == EINTR) {
150         continue;
151       }
152       return r;
153     }
154
155     totalBytes += r;
156     b += r;
157     offset += r;
158     count -= r;
159   } while (r != 0 && count);  // 0 means EOF
160
161   return totalBytes;
162 }
163
164 }  // namespaces
165