]>
Commit | Line | Data |
---|---|---|
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 |
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 | ||
f67539c2 TL |
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 | ||
7c673cae FG |
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 | } | |
f67539c2 TL |
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 | ||
7c673cae FG |
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 | ||
f67539c2 TL |
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 | ||
7c673cae FG |
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, | |
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 | ||
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); | |
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 | } |