]> git.proxmox.com Git - ceph.git/blob - ceph/src/common/safe_io.c
import ceph quincy 17.2.4
[ceph.git] / ceph / src / common / safe_io.c
1 // -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
2 // vim: ts=8 sw=2 smarttab
3 /*
4 * Ceph - scalable distributed file system
5 *
6 * Copyright (C) 2011 New Dream Network
7 *
8 * This is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License version 2.1, as published by the Free Software
11 * Foundation. See file COPYING.
12 *
13 */
14
15 #include "common/safe_io.h"
16 #include "include/compat.h"
17
18 #include <stdio.h>
19 #include <string.h>
20 #include <unistd.h>
21 #include <errno.h>
22 #include <fcntl.h>
23 #include <limits.h>
24 #include <sys/socket.h>
25
26 ssize_t safe_read(int fd, void *buf, size_t count)
27 {
28 size_t cnt = 0;
29
30 while (cnt < count) {
31 ssize_t r = read(fd, buf, count - cnt);
32 if (r <= 0) {
33 if (r == 0) {
34 // EOF
35 return cnt;
36 }
37 if (errno == EINTR)
38 continue;
39 return -errno;
40 }
41 cnt += r;
42 buf = (char *)buf + r;
43 }
44 return cnt;
45 }
46
47 #ifdef _WIN32
48 // "read" doesn't work with Windows sockets.
49 ssize_t safe_recv(int fd, void *buf, size_t count)
50 {
51 size_t cnt = 0;
52
53 while (cnt < count) {
54 ssize_t r = recv(fd, (SOCKOPT_VAL_TYPE)buf, count - cnt, 0);
55 if (r <= 0) {
56 if (r == 0) {
57 // EOF
58 return cnt;
59 }
60 int err = ceph_sock_errno();
61 if (err == EAGAIN || err == EINTR) {
62 continue;
63 }
64 return -err;
65 }
66 cnt += r;
67 buf = (char *)buf + r;
68 }
69 return cnt;
70 }
71 #else
72 ssize_t safe_recv(int fd, void *buf, size_t count)
73 {
74 // We'll use "safe_read" so that this can work with any type of
75 // file descriptor.
76 return safe_read(fd, buf, count);
77 }
78 #endif /* _WIN32 */
79
80 ssize_t safe_read_exact(int fd, void *buf, size_t count)
81 {
82 ssize_t ret = safe_read(fd, buf, count);
83 if (ret < 0)
84 return ret;
85 if ((size_t)ret != count)
86 return -EDOM;
87 return 0;
88 }
89
90 ssize_t safe_recv_exact(int fd, void *buf, size_t count)
91 {
92 ssize_t ret = safe_recv(fd, buf, count);
93 if (ret < 0)
94 return ret;
95 if ((size_t)ret != count)
96 return -EDOM;
97 return 0;
98 }
99
100 ssize_t safe_write(int fd, const void *buf, size_t count)
101 {
102 while (count > 0) {
103 ssize_t r = write(fd, buf, count);
104 if (r < 0) {
105 if (errno == EINTR)
106 continue;
107 return -errno;
108 }
109 count -= r;
110 buf = (char *)buf + r;
111 }
112 return 0;
113 }
114
115 #ifdef _WIN32
116 ssize_t safe_send(int fd, const void *buf, size_t count)
117 {
118 while (count > 0) {
119 ssize_t r = send(fd, (SOCKOPT_VAL_TYPE)buf, count, 0);
120 if (r < 0) {
121 int err = ceph_sock_errno();
122 if (err == EINTR || err == EAGAIN) {
123 continue;
124 }
125 return -err;
126 }
127 count -= r;
128 buf = (char *)buf + r;
129 }
130 return 0;
131 }
132 #else
133 ssize_t safe_send(int fd, const void *buf, size_t count)
134 {
135 return safe_write(fd, buf, count);
136 }
137 #endif /* _WIN32 */
138
139 ssize_t safe_pread(int fd, void *buf, size_t count, off_t offset)
140 {
141 size_t cnt = 0;
142 char *b = (char*)buf;
143
144 while (cnt < count) {
145 ssize_t r = pread(fd, b + cnt, count - cnt, offset + cnt);
146 if (r <= 0) {
147 if (r == 0) {
148 // EOF
149 return cnt;
150 }
151 if (errno == EINTR)
152 continue;
153 return -errno;
154 }
155
156 cnt += r;
157 }
158 return cnt;
159 }
160
161 ssize_t safe_pread_exact(int fd, void *buf, size_t count, off_t offset)
162 {
163 ssize_t ret = safe_pread(fd, buf, count, offset);
164 if (ret < 0)
165 return ret;
166 if ((size_t)ret != count)
167 return -EDOM;
168 return 0;
169 }
170
171 ssize_t safe_pwrite(int fd, const void *buf, size_t count, off_t offset)
172 {
173 while (count > 0) {
174 ssize_t r = pwrite(fd, buf, count, offset);
175 if (r < 0) {
176 if (errno == EINTR)
177 continue;
178 return -errno;
179 }
180 count -= r;
181 buf = (char *)buf + r;
182 offset += r;
183 }
184 return 0;
185 }
186
187 #ifdef CEPH_HAVE_SPLICE
188 ssize_t safe_splice(int fd_in, off_t *off_in, int fd_out, off_t *off_out,
189 size_t len, unsigned int flags)
190 {
191 size_t cnt = 0;
192
193 while (cnt < len) {
194 ssize_t r = splice(fd_in, off_in, fd_out, off_out, len - cnt, flags);
195 if (r <= 0) {
196 if (r == 0) {
197 // EOF
198 return cnt;
199 }
200 if (errno == EINTR)
201 continue;
202 if (errno == EAGAIN)
203 break;
204 return -errno;
205 }
206 cnt += r;
207 }
208 return cnt;
209 }
210
211 ssize_t safe_splice_exact(int fd_in, off_t *off_in, int fd_out,
212 off_t *off_out, size_t len, unsigned int flags)
213 {
214 ssize_t ret = safe_splice(fd_in, off_in, fd_out, off_out, len, flags);
215 if (ret < 0)
216 return ret;
217 if ((size_t)ret != len)
218 return -EDOM;
219 return 0;
220 }
221 #endif
222
223 int safe_write_file(const char *base, const char *file,
224 const char *val, size_t vallen,
225 unsigned mode)
226 {
227 int ret;
228 char fn[PATH_MAX];
229 char tmp[PATH_MAX];
230 int fd;
231
232 // does the file already have correct content?
233 char oldval[80];
234 ret = safe_read_file(base, file, oldval, sizeof(oldval));
235 if (ret == (int)vallen && memcmp(oldval, val, vallen) == 0)
236 return 0; // yes.
237
238 snprintf(fn, sizeof(fn), "%s/%s", base, file);
239 snprintf(tmp, sizeof(tmp), "%s/%s.tmp", base, file);
240 fd = open(tmp, O_WRONLY|O_CREAT|O_TRUNC|O_BINARY, mode);
241 if (fd < 0) {
242 ret = errno;
243 return -ret;
244 }
245 ret = safe_write(fd, val, vallen);
246 if (ret) {
247 VOID_TEMP_FAILURE_RETRY(close(fd));
248 return ret;
249 }
250
251 ret = fsync(fd);
252 if (ret < 0) ret = -errno;
253 VOID_TEMP_FAILURE_RETRY(close(fd));
254 if (ret < 0) {
255 unlink(tmp);
256 return ret;
257 }
258 ret = rename(tmp, fn);
259 if (ret < 0) {
260 ret = -errno;
261 unlink(tmp);
262 return ret;
263 }
264
265 fd = open(base, O_RDONLY|O_BINARY);
266 if (fd < 0) {
267 ret = -errno;
268 return ret;
269 }
270 ret = fsync(fd);
271 if (ret < 0) ret = -errno;
272 VOID_TEMP_FAILURE_RETRY(close(fd));
273
274 return ret;
275 }
276
277 int safe_read_file(const char *base, const char *file,
278 char *val, size_t vallen)
279 {
280 char fn[PATH_MAX];
281 int fd, len;
282
283 snprintf(fn, sizeof(fn), "%s/%s", base, file);
284 fd = open(fn, O_RDONLY|O_BINARY);
285 if (fd < 0) {
286 return -errno;
287 }
288 len = safe_read(fd, val, vallen);
289 if (len < 0) {
290 VOID_TEMP_FAILURE_RETRY(close(fd));
291 return len;
292 }
293 // close sometimes returns errors, but only after write()
294 VOID_TEMP_FAILURE_RETRY(close(fd));
295
296 return len;
297 }