xref: /kvmtool/util/read-write.c (revision 0ecc970fb2da8e357a1acb87d3f4edc82afb605a)
1 #include "kvm/read-write.h"
2 
3 #include <sys/types.h>
4 #include <sys/uio.h>
5 #include <unistd.h>
6 #include <string.h>
7 #include <errno.h>
8 
9 /* Same as read(2) except that this function never returns EAGAIN or EINTR. */
10 ssize_t xread(int fd, void *buf, size_t count)
11 {
12 	ssize_t nr;
13 
14 restart:
15 	nr = read(fd, buf, count);
16 	if ((nr < 0) && ((errno == EAGAIN) || (errno == EINTR)))
17 		goto restart;
18 
19 	return nr;
20 }
21 
22 /* Same as write(2) except that this function never returns EAGAIN or EINTR. */
23 ssize_t xwrite(int fd, const void *buf, size_t count)
24 {
25 	ssize_t nr;
26 
27 restart:
28 	nr = write(fd, buf, count);
29 	if ((nr < 0) && ((errno == EAGAIN) || (errno == EINTR)))
30 		goto restart;
31 
32 	return nr;
33 }
34 
35 ssize_t read_in_full(int fd, void *buf, size_t count)
36 {
37 	ssize_t total = 0;
38 	char *p = buf;
39 
40 	while (count > 0) {
41 		ssize_t nr;
42 
43 		nr = xread(fd, p, count);
44 		if (nr <= 0) {
45 			if (total > 0)
46 				return total;
47 
48 			return -1;
49 		}
50 
51 		count -= nr;
52 		total += nr;
53 		p += nr;
54 	}
55 
56 	return total;
57 }
58 
59 ssize_t write_in_full(int fd, const void *buf, size_t count)
60 {
61 	const char *p = buf;
62 	ssize_t total = 0;
63 
64 	while (count > 0) {
65 		ssize_t nr;
66 
67 		nr = xwrite(fd, p, count);
68 		if (nr < 0)
69 			return -1;
70 		if (nr == 0) {
71 			errno = ENOSPC;
72 			return -1;
73 		}
74 		count -= nr;
75 		total += nr;
76 		p += nr;
77 	}
78 
79 	return total;
80 }
81 
82 /* Same as pread(2) except that this function never returns EAGAIN or EINTR. */
83 ssize_t xpread(int fd, void *buf, size_t count, off_t offset)
84 {
85 	ssize_t nr;
86 
87 restart:
88 	nr = pread(fd, buf, count, offset);
89 	if ((nr < 0) && ((errno == EAGAIN) || (errno == EINTR)))
90 		goto restart;
91 
92 	return nr;
93 }
94 
95 /* Same as pwrite(2) except that this function never returns EAGAIN or EINTR. */
96 ssize_t xpwrite(int fd, const void *buf, size_t count, off_t offset)
97 {
98 	ssize_t nr;
99 
100 restart:
101 	nr = pwrite(fd, buf, count, offset);
102 	if ((nr < 0) && ((errno == EAGAIN) || (errno == EINTR)))
103 		goto restart;
104 
105 	return nr;
106 }
107 
108 ssize_t pread_in_full(int fd, void *buf, size_t count, off_t offset)
109 {
110 	ssize_t total = 0;
111 	char *p = buf;
112 
113 	while (count > 0) {
114 		ssize_t nr;
115 
116 		nr = xpread(fd, p, count, offset);
117 		if (nr <= 0) {
118 			if (total > 0)
119 				return total;
120 
121 			return -1;
122 		}
123 
124 		count -= nr;
125 		total += nr;
126 		p += nr;
127 		offset += nr;
128 	}
129 
130 	return total;
131 }
132 
133 ssize_t pwrite_in_full(int fd, const void *buf, size_t count, off_t offset)
134 {
135 	const char *p = buf;
136 	ssize_t total = 0;
137 
138 	while (count > 0) {
139 		ssize_t nr;
140 
141 		nr = xpwrite(fd, p, count, offset);
142 		if (nr < 0)
143 			return -1;
144 		if (nr == 0) {
145 			errno = ENOSPC;
146 			return -1;
147 		}
148 		count -= nr;
149 		total += nr;
150 		p += nr;
151 		offset += nr;
152 	}
153 
154 	return total;
155 }
156 
157 /* Same as readv(2) except that this function never returns EAGAIN or EINTR. */
158 ssize_t xreadv(int fd, const struct iovec *iov, int iovcnt)
159 {
160 	ssize_t nr;
161 
162 restart:
163 	nr = readv(fd, iov, iovcnt);
164 	if ((nr < 0) && ((errno == EAGAIN) || (errno == EINTR)))
165 		goto restart;
166 
167 	return nr;
168 }
169 
170 /* Same as writev(2) except that this function never returns EAGAIN or EINTR. */
171 ssize_t xwritev(int fd, const struct iovec *iov, int iovcnt)
172 {
173 	ssize_t nr;
174 
175 restart:
176 	nr = writev(fd, iov, iovcnt);
177 	if ((nr < 0) && ((errno == EAGAIN) || (errno == EINTR)))
178 		goto restart;
179 
180 	return nr;
181 }
182 
183 static inline ssize_t get_iov_size(const struct iovec *iov, int iovcnt)
184 {
185 	size_t size = 0;
186 	while (iovcnt--)
187 		size += (iov++)->iov_len;
188 
189 	return size;
190 }
191 
192 static inline void shift_iovec(const struct iovec **iov, int *iovcnt,
193 				size_t nr, ssize_t *total, size_t *count, off_t *offset)
194 {
195 	while (nr >= (*iov)->iov_len) {
196 		nr -= (*iov)->iov_len;
197 		*total += (*iov)->iov_len;
198 		*count -= (*iov)->iov_len;
199 		if (offset)
200 			*offset += (*iov)->iov_len;
201 		(*iovcnt)--;
202 		(*iov)++;
203 	}
204 }
205 
206 ssize_t readv_in_full(int fd, const struct iovec *iov, int iovcnt)
207 {
208 	ssize_t total = 0;
209 	size_t count = get_iov_size(iov, iovcnt);
210 
211 	while (count > 0) {
212 		ssize_t nr;
213 
214 		nr = xreadv(fd, iov, iovcnt);
215 		if (nr <= 0) {
216 			if (total > 0)
217 				return total;
218 
219 			return -1;
220 		}
221 
222 		shift_iovec(&iov, &iovcnt, nr, &total, &count, NULL);
223 	}
224 
225 	return total;
226 }
227 
228 ssize_t writev_in_full(int fd, const struct iovec *iov, int iovcnt)
229 {
230 	ssize_t total = 0;
231 	size_t count = get_iov_size(iov, iovcnt);
232 
233 	while (count > 0) {
234 		ssize_t nr;
235 
236 		nr = xwritev(fd, iov, iovcnt);
237 		if (nr < 0)
238 			return -1;
239 		if (nr == 0) {
240 			errno = ENOSPC;
241 			return -1;
242 		}
243 
244 		shift_iovec(&iov, &iovcnt, nr, &total, &count, NULL);
245 	}
246 
247 	return total;
248 }
249 
250 /* Same as preadv(2) except that this function never returns EAGAIN or EINTR. */
251 ssize_t xpreadv(int fd, const struct iovec *iov, int iovcnt, off_t offset)
252 {
253 	ssize_t nr;
254 
255 restart:
256 	nr = preadv(fd, iov, iovcnt, offset);
257 	if ((nr < 0) && ((errno == EAGAIN) || (errno == EINTR)))
258 		goto restart;
259 
260 	return nr;
261 }
262 
263 /* Same as pwritev(2) except that this function never returns EAGAIN or EINTR. */
264 ssize_t xpwritev(int fd, const struct iovec *iov, int iovcnt, off_t offset)
265 {
266 	ssize_t nr;
267 
268 restart:
269 	nr = pwritev(fd, iov, iovcnt, offset);
270 	if ((nr < 0) && ((errno == EAGAIN) || (errno == EINTR)))
271 		goto restart;
272 
273 	return nr;
274 }
275 
276 ssize_t preadv_in_full(int fd, const struct iovec *iov, int iovcnt, off_t offset)
277 {
278 	ssize_t total = 0;
279 	size_t count = get_iov_size(iov, iovcnt);
280 
281 	while (count > 0) {
282 		ssize_t nr;
283 
284 		nr = xpreadv(fd, iov, iovcnt, offset);
285 		if (nr <= 0) {
286 			if (total > 0)
287 				return total;
288 
289 			return -1;
290 		}
291 
292 		shift_iovec(&iov, &iovcnt, nr, &total, &count, &offset);
293 	}
294 
295 	return total;
296 }
297 
298 ssize_t pwritev_in_full(int fd, const struct iovec *iov, int iovcnt, off_t offset)
299 {
300 	ssize_t total = 0;
301 	size_t count = get_iov_size(iov, iovcnt);
302 
303 	while (count > 0) {
304 		ssize_t nr;
305 
306 		nr = xpwritev(fd, iov, iovcnt, offset);
307 		if (nr < 0)
308 			return -1;
309 		if (nr == 0) {
310 			errno = ENOSPC;
311 			return -1;
312 		}
313 
314 		shift_iovec(&iov, &iovcnt, nr, &total, &count, &offset);
315 	}
316 
317 	return total;
318 }
319 
320 #ifdef CONFIG_HAS_AIO
321 int aio_pwritev(io_context_t ctx, struct iocb *iocb, int fd, const struct iovec *iov, int iovcnt,
322 		off_t offset, int ev, void *param)
323 {
324 	struct iocb *ios[1] = { iocb };
325 	int ret;
326 
327 	io_prep_pwritev(iocb, fd, iov, iovcnt, offset);
328 	io_set_eventfd(iocb, ev);
329 	iocb->data = param;
330 
331 restart:
332 	ret = io_submit(ctx, 1, ios);
333 	if (ret == -EAGAIN)
334 		goto restart;
335 	return ret;
336 }
337 
338 int aio_preadv(io_context_t ctx, struct iocb *iocb, int fd, const struct iovec *iov, int iovcnt,
339 		off_t offset, int ev, void *param)
340 {
341 	struct iocb *ios[1] = { iocb };
342 	int ret;
343 
344 	io_prep_preadv(iocb, fd, iov, iovcnt, offset);
345 	io_set_eventfd(iocb, ev);
346 	iocb->data = param;
347 
348 restart:
349 	ret = io_submit(ctx, 1, ios);
350 	if (ret == -EAGAIN)
351 		goto restart;
352 	return ret;
353 }
354 #endif
355