]> git.proxmox.com Git - ceph.git/blame - ceph/src/common/safe_io.c
import ceph quincy 17.2.6
[ceph.git] / ceph / src / common / safe_io.c
CommitLineData
7c673cae
FG
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
31f18b77
FG
15#include "common/safe_io.h"
16#include "include/compat.h"
17
7c673cae
FG
18#include <stdio.h>
19#include <string.h>
20#include <unistd.h>
21#include <errno.h>
22#include <fcntl.h>
23#include <limits.h>
f67539c2 24#include <sys/socket.h>
7c673cae 25
7c673cae
FG
26ssize_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
f67539c2
TL
47#ifdef _WIN32
48// "read" doesn't work with Windows sockets.
49ssize_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
72ssize_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
7c673cae
FG
80ssize_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}
f67539c2
TL
89
90ssize_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
7c673cae
FG
100ssize_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
f67539c2
TL
115#ifdef _WIN32
116ssize_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
133ssize_t safe_send(int fd, const void *buf, size_t count)
134{
135 return safe_write(fd, buf, count);
136}
137#endif /* _WIN32 */
138
7c673cae
FG
139ssize_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
161ssize_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
171ssize_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
188ssize_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
211ssize_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
223int safe_write_file(const char *base, const char *file,
eafe8130
TL
224 const char *val, size_t vallen,
225 unsigned mode)
7c673cae
FG
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);
f67539c2 240 fd = open(tmp, O_WRONLY|O_CREAT|O_TRUNC|O_BINARY, mode);
7c673cae
FG
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
f67539c2 265 fd = open(base, O_RDONLY|O_BINARY);
7c673cae
FG
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
277int 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);
f67539c2 284 fd = open(fn, O_RDONLY|O_BINARY);
7c673cae
FG
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}