xref: /kvmtool/util/read-write.c (revision 1664498d4a7d0c795ca5f590c61f9494ecd5e5f8)
1c4d7847bSPekka Enberg #include "kvm/read-write.h"
2c4d7847bSPekka Enberg 
3c4d7847bSPekka Enberg #include <sys/types.h>
4150aa4c0SPekka Enberg #include <sys/uio.h>
5c4d7847bSPekka Enberg #include <unistd.h>
6c4d7847bSPekka Enberg #include <string.h>
7c4d7847bSPekka Enberg #include <errno.h>
8c4d7847bSPekka Enberg 
9c4d7847bSPekka Enberg /* Same as read(2) except that this function never returns EAGAIN or EINTR. */
10c4d7847bSPekka Enberg ssize_t xread(int fd, void *buf, size_t count)
11c4d7847bSPekka Enberg {
12c4d7847bSPekka Enberg 	ssize_t nr;
13c4d7847bSPekka Enberg 
14c4d7847bSPekka Enberg restart:
15c4d7847bSPekka Enberg 	nr = read(fd, buf, count);
16c4d7847bSPekka Enberg 	if ((nr < 0) && ((errno == EAGAIN) || (errno == EINTR)))
17c4d7847bSPekka Enberg 		goto restart;
18c4d7847bSPekka Enberg 
19c4d7847bSPekka Enberg 	return nr;
20c4d7847bSPekka Enberg }
21c4d7847bSPekka Enberg 
22c4d7847bSPekka Enberg /* Same as write(2) except that this function never returns EAGAIN or EINTR. */
23c4d7847bSPekka Enberg ssize_t xwrite(int fd, const void *buf, size_t count)
24c4d7847bSPekka Enberg {
25c4d7847bSPekka Enberg 	ssize_t nr;
26c4d7847bSPekka Enberg 
27c4d7847bSPekka Enberg restart:
28c4d7847bSPekka Enberg 	nr = write(fd, buf, count);
29c4d7847bSPekka Enberg 	if ((nr < 0) && ((errno == EAGAIN) || (errno == EINTR)))
30c4d7847bSPekka Enberg 		goto restart;
31c4d7847bSPekka Enberg 
32c4d7847bSPekka Enberg 	return nr;
33c4d7847bSPekka Enberg }
34c4d7847bSPekka Enberg 
35c4d7847bSPekka Enberg ssize_t read_in_full(int fd, void *buf, size_t count)
36c4d7847bSPekka Enberg {
37c4d7847bSPekka Enberg 	ssize_t total = 0;
38c4d7847bSPekka Enberg 	char *p = buf;
39c4d7847bSPekka Enberg 
40c4d7847bSPekka Enberg 	while (count > 0) {
41c4d7847bSPekka Enberg 		ssize_t nr;
42c4d7847bSPekka Enberg 
43c4d7847bSPekka Enberg 		nr = xread(fd, p, count);
44c4d7847bSPekka Enberg 		if (nr <= 0) {
45c4d7847bSPekka Enberg 			if (total > 0)
46c4d7847bSPekka Enberg 				return total;
47c4d7847bSPekka Enberg 
48c4d7847bSPekka Enberg 			return -1;
49c4d7847bSPekka Enberg 		}
50c4d7847bSPekka Enberg 
51c4d7847bSPekka Enberg 		count -= nr;
52c4d7847bSPekka Enberg 		total += nr;
53c4d7847bSPekka Enberg 		p += nr;
54c4d7847bSPekka Enberg 	}
55c4d7847bSPekka Enberg 
56c4d7847bSPekka Enberg 	return total;
57c4d7847bSPekka Enberg }
58c4d7847bSPekka Enberg 
59c4d7847bSPekka Enberg ssize_t write_in_full(int fd, const void *buf, size_t count)
60c4d7847bSPekka Enberg {
61c4d7847bSPekka Enberg 	const char *p = buf;
62c4d7847bSPekka Enberg 	ssize_t total = 0;
63c4d7847bSPekka Enberg 
64c4d7847bSPekka Enberg 	while (count > 0) {
65c4d7847bSPekka Enberg 		ssize_t nr;
66c4d7847bSPekka Enberg 
67c4d7847bSPekka Enberg 		nr = xwrite(fd, p, count);
68c4d7847bSPekka Enberg 		if (nr < 0)
69c4d7847bSPekka Enberg 			return -1;
70c4d7847bSPekka Enberg 		if (nr == 0) {
71c4d7847bSPekka Enberg 			errno = ENOSPC;
72c4d7847bSPekka Enberg 			return -1;
73c4d7847bSPekka Enberg 		}
74c4d7847bSPekka Enberg 		count -= nr;
75c4d7847bSPekka Enberg 		total += nr;
76c4d7847bSPekka Enberg 		p += nr;
77c4d7847bSPekka Enberg 	}
78c4d7847bSPekka Enberg 
79c4d7847bSPekka Enberg 	return total;
80c4d7847bSPekka Enberg }
816b7deb02SPekka Enberg 
826b7deb02SPekka Enberg /* Same as pread(2) except that this function never returns EAGAIN or EINTR. */
836b7deb02SPekka Enberg ssize_t xpread(int fd, void *buf, size_t count, off_t offset)
846b7deb02SPekka Enberg {
856b7deb02SPekka Enberg 	ssize_t nr;
866b7deb02SPekka Enberg 
876b7deb02SPekka Enberg restart:
886b7deb02SPekka Enberg 	nr = pread(fd, buf, count, offset);
896b7deb02SPekka Enberg 	if ((nr < 0) && ((errno == EAGAIN) || (errno == EINTR)))
906b7deb02SPekka Enberg 		goto restart;
916b7deb02SPekka Enberg 
926b7deb02SPekka Enberg 	return nr;
936b7deb02SPekka Enberg }
946b7deb02SPekka Enberg 
956b7deb02SPekka Enberg /* Same as pwrite(2) except that this function never returns EAGAIN or EINTR. */
966b7deb02SPekka Enberg ssize_t xpwrite(int fd, const void *buf, size_t count, off_t offset)
976b7deb02SPekka Enberg {
986b7deb02SPekka Enberg 	ssize_t nr;
996b7deb02SPekka Enberg 
1006b7deb02SPekka Enberg restart:
1016b7deb02SPekka Enberg 	nr = pwrite(fd, buf, count, offset);
1026b7deb02SPekka Enberg 	if ((nr < 0) && ((errno == EAGAIN) || (errno == EINTR)))
1036b7deb02SPekka Enberg 		goto restart;
1046b7deb02SPekka Enberg 
1056b7deb02SPekka Enberg 	return nr;
1066b7deb02SPekka Enberg }
1076b7deb02SPekka Enberg 
1086b7deb02SPekka Enberg ssize_t pread_in_full(int fd, void *buf, size_t count, off_t offset)
1096b7deb02SPekka Enberg {
1106b7deb02SPekka Enberg 	ssize_t total = 0;
1116b7deb02SPekka Enberg 	char *p = buf;
1126b7deb02SPekka Enberg 
1136b7deb02SPekka Enberg 	while (count > 0) {
1146b7deb02SPekka Enberg 		ssize_t nr;
1156b7deb02SPekka Enberg 
1166b7deb02SPekka Enberg 		nr = xpread(fd, p, count, offset);
1176b7deb02SPekka Enberg 		if (nr <= 0) {
1186b7deb02SPekka Enberg 			if (total > 0)
1196b7deb02SPekka Enberg 				return total;
1206b7deb02SPekka Enberg 
1216b7deb02SPekka Enberg 			return -1;
1226b7deb02SPekka Enberg 		}
1236b7deb02SPekka Enberg 
1246b7deb02SPekka Enberg 		count -= nr;
1256b7deb02SPekka Enberg 		total += nr;
1266b7deb02SPekka Enberg 		p += nr;
1276b7deb02SPekka Enberg 		offset += nr;
1286b7deb02SPekka Enberg 	}
1296b7deb02SPekka Enberg 
1306b7deb02SPekka Enberg 	return total;
1316b7deb02SPekka Enberg }
1326b7deb02SPekka Enberg 
1336b7deb02SPekka Enberg ssize_t pwrite_in_full(int fd, const void *buf, size_t count, off_t offset)
1346b7deb02SPekka Enberg {
1356b7deb02SPekka Enberg 	const char *p = buf;
1366b7deb02SPekka Enberg 	ssize_t total = 0;
1376b7deb02SPekka Enberg 
1386b7deb02SPekka Enberg 	while (count > 0) {
1396b7deb02SPekka Enberg 		ssize_t nr;
1406b7deb02SPekka Enberg 
1416b7deb02SPekka Enberg 		nr = xpwrite(fd, p, count, offset);
1426b7deb02SPekka Enberg 		if (nr < 0)
1436b7deb02SPekka Enberg 			return -1;
1446b7deb02SPekka Enberg 		if (nr == 0) {
1456b7deb02SPekka Enberg 			errno = ENOSPC;
1466b7deb02SPekka Enberg 			return -1;
1476b7deb02SPekka Enberg 		}
1486b7deb02SPekka Enberg 		count -= nr;
1496b7deb02SPekka Enberg 		total += nr;
1506b7deb02SPekka Enberg 		p += nr;
1516b7deb02SPekka Enberg 		offset += nr;
1526b7deb02SPekka Enberg 	}
1536b7deb02SPekka Enberg 
1546b7deb02SPekka Enberg 	return total;
1556b7deb02SPekka Enberg }
1561547507fSSasha Levin 
1571547507fSSasha Levin /* Same as readv(2) except that this function never returns EAGAIN or EINTR. */
1581547507fSSasha Levin ssize_t xreadv(int fd, const struct iovec *iov, int iovcnt)
1591547507fSSasha Levin {
1601547507fSSasha Levin 	ssize_t nr;
1611547507fSSasha Levin 
1621547507fSSasha Levin restart:
1631547507fSSasha Levin 	nr = readv(fd, iov, iovcnt);
1641547507fSSasha Levin 	if ((nr < 0) && ((errno == EAGAIN) || (errno == EINTR)))
1651547507fSSasha Levin 		goto restart;
1661547507fSSasha Levin 
1671547507fSSasha Levin 	return nr;
1681547507fSSasha Levin }
1691547507fSSasha Levin 
1701547507fSSasha Levin /* Same as writev(2) except that this function never returns EAGAIN or EINTR. */
1711547507fSSasha Levin ssize_t xwritev(int fd, const struct iovec *iov, int iovcnt)
1721547507fSSasha Levin {
1731547507fSSasha Levin 	ssize_t nr;
1741547507fSSasha Levin 
1751547507fSSasha Levin restart:
176f42cd9ccSPekka Enberg 	nr = writev(fd, iov, iovcnt);
1771547507fSSasha Levin 	if ((nr < 0) && ((errno == EAGAIN) || (errno == EINTR)))
1781547507fSSasha Levin 		goto restart;
1791547507fSSasha Levin 
1801547507fSSasha Levin 	return nr;
1811547507fSSasha Levin }
1821547507fSSasha Levin 
1831547507fSSasha Levin static inline ssize_t get_iov_size(const struct iovec *iov, int iovcnt)
1841547507fSSasha Levin {
1851547507fSSasha Levin 	size_t size = 0;
1861547507fSSasha Levin 	while (iovcnt--)
1871547507fSSasha Levin 		size += (iov++)->iov_len;
1881547507fSSasha Levin 
1891547507fSSasha Levin 	return size;
1901547507fSSasha Levin }
1911547507fSSasha Levin 
1924c0205d0SSasha Levin static inline void shift_iovec(const struct iovec **iov, int *iovcnt,
1934c0205d0SSasha Levin 				size_t nr, ssize_t *total, size_t *count, off_t *offset)
1944c0205d0SSasha Levin {
1954c0205d0SSasha Levin 	while (nr >= (*iov)->iov_len) {
1964c0205d0SSasha Levin 		nr -= (*iov)->iov_len;
1974c0205d0SSasha Levin 		*total += (*iov)->iov_len;
1984c0205d0SSasha Levin 		*count -= (*iov)->iov_len;
1994c0205d0SSasha Levin 		if (offset)
2004c0205d0SSasha Levin 			*offset += (*iov)->iov_len;
2014c0205d0SSasha Levin 		(*iovcnt)--;
2024c0205d0SSasha Levin 		(*iov)++;
2034c0205d0SSasha Levin 	}
2044c0205d0SSasha Levin }
2054c0205d0SSasha Levin 
2061547507fSSasha Levin ssize_t readv_in_full(int fd, const struct iovec *iov, int iovcnt)
2071547507fSSasha Levin {
2081547507fSSasha Levin 	ssize_t total = 0;
2094c0205d0SSasha Levin 	size_t count = get_iov_size(iov, iovcnt);
2101547507fSSasha Levin 
2111547507fSSasha Levin 	while (count > 0) {
2121547507fSSasha Levin 		ssize_t nr;
2131547507fSSasha Levin 
2141547507fSSasha Levin 		nr = xreadv(fd, iov, iovcnt);
2151547507fSSasha Levin 		if (nr <= 0) {
2161547507fSSasha Levin 			if (total > 0)
2171547507fSSasha Levin 				return total;
2181547507fSSasha Levin 
2191547507fSSasha Levin 			return -1;
2201547507fSSasha Levin 		}
2211547507fSSasha Levin 
2224c0205d0SSasha Levin 		shift_iovec(&iov, &iovcnt, nr, &total, &count, NULL);
2231547507fSSasha Levin 	}
2241547507fSSasha Levin 
2251547507fSSasha Levin 	return total;
2261547507fSSasha Levin }
2271547507fSSasha Levin 
2281547507fSSasha Levin ssize_t writev_in_full(int fd, const struct iovec *iov, int iovcnt)
2291547507fSSasha Levin {
2301547507fSSasha Levin 	ssize_t total = 0;
2311547507fSSasha Levin 	size_t count = get_iov_size(iov, iovcnt);
2321547507fSSasha Levin 
2331547507fSSasha Levin 	while (count > 0) {
2341547507fSSasha Levin 		ssize_t nr;
2351547507fSSasha Levin 
2361547507fSSasha Levin 		nr = xwritev(fd, iov, iovcnt);
2371547507fSSasha Levin 		if (nr < 0)
2381547507fSSasha Levin 			return -1;
2391547507fSSasha Levin 		if (nr == 0) {
2401547507fSSasha Levin 			errno = ENOSPC;
2411547507fSSasha Levin 			return -1;
2421547507fSSasha Levin 		}
2431547507fSSasha Levin 
2444c0205d0SSasha Levin 		shift_iovec(&iov, &iovcnt, nr, &total, &count, NULL);
2451547507fSSasha Levin 	}
2461547507fSSasha Levin 
2471547507fSSasha Levin 	return total;
2481547507fSSasha Levin }
2491547507fSSasha Levin 
2501547507fSSasha Levin /* Same as preadv(2) except that this function never returns EAGAIN or EINTR. */
2511547507fSSasha Levin ssize_t xpreadv(int fd, const struct iovec *iov, int iovcnt, off_t offset)
2521547507fSSasha Levin {
2531547507fSSasha Levin 	ssize_t nr;
2541547507fSSasha Levin 
2551547507fSSasha Levin restart:
2561547507fSSasha Levin 	nr = preadv(fd, iov, iovcnt, offset);
2571547507fSSasha Levin 	if ((nr < 0) && ((errno == EAGAIN) || (errno == EINTR)))
2581547507fSSasha Levin 		goto restart;
2591547507fSSasha Levin 
2601547507fSSasha Levin 	return nr;
2611547507fSSasha Levin }
2621547507fSSasha Levin 
2631547507fSSasha Levin /* Same as pwritev(2) except that this function never returns EAGAIN or EINTR. */
2641547507fSSasha Levin ssize_t xpwritev(int fd, const struct iovec *iov, int iovcnt, off_t offset)
2651547507fSSasha Levin {
2661547507fSSasha Levin 	ssize_t nr;
2671547507fSSasha Levin 
2681547507fSSasha Levin restart:
2691547507fSSasha Levin 	nr = pwritev(fd, iov, iovcnt, offset);
2701547507fSSasha Levin 	if ((nr < 0) && ((errno == EAGAIN) || (errno == EINTR)))
2711547507fSSasha Levin 		goto restart;
2721547507fSSasha Levin 
2731547507fSSasha Levin 	return nr;
2741547507fSSasha Levin }
2751547507fSSasha Levin 
2761547507fSSasha Levin ssize_t preadv_in_full(int fd, const struct iovec *iov, int iovcnt, off_t offset)
2771547507fSSasha Levin {
2781547507fSSasha Levin 	ssize_t total = 0;
2791547507fSSasha Levin 	size_t count = get_iov_size(iov, iovcnt);
2801547507fSSasha Levin 
2811547507fSSasha Levin 	while (count > 0) {
2821547507fSSasha Levin 		ssize_t nr;
2831547507fSSasha Levin 
2841547507fSSasha Levin 		nr = xpreadv(fd, iov, iovcnt, offset);
2851547507fSSasha Levin 		if (nr <= 0) {
2861547507fSSasha Levin 			if (total > 0)
2871547507fSSasha Levin 				return total;
2881547507fSSasha Levin 
2891547507fSSasha Levin 			return -1;
2901547507fSSasha Levin 		}
2911547507fSSasha Levin 
2924c0205d0SSasha Levin 		shift_iovec(&iov, &iovcnt, nr, &total, &count, &offset);
2931547507fSSasha Levin 	}
2941547507fSSasha Levin 
2951547507fSSasha Levin 	return total;
2961547507fSSasha Levin }
2971547507fSSasha Levin 
2981547507fSSasha Levin ssize_t pwritev_in_full(int fd, const struct iovec *iov, int iovcnt, off_t offset)
2991547507fSSasha Levin {
3001547507fSSasha Levin 	ssize_t total = 0;
3011547507fSSasha Levin 	size_t count = get_iov_size(iov, iovcnt);
3021547507fSSasha Levin 
3031547507fSSasha Levin 	while (count > 0) {
3041547507fSSasha Levin 		ssize_t nr;
3051547507fSSasha Levin 
3061547507fSSasha Levin 		nr = xpwritev(fd, iov, iovcnt, offset);
3071547507fSSasha Levin 		if (nr < 0)
3081547507fSSasha Levin 			return -1;
3091547507fSSasha Levin 		if (nr == 0) {
3101547507fSSasha Levin 			errno = ENOSPC;
3111547507fSSasha Levin 			return -1;
3121547507fSSasha Levin 		}
3134c0205d0SSasha Levin 
3144c0205d0SSasha Levin 		shift_iovec(&iov, &iovcnt, nr, &total, &count, &offset);
3151547507fSSasha Levin 	}
3161547507fSSasha Levin 
3171547507fSSasha Levin 	return total;
3181547507fSSasha Levin }
319*1664498dSSasha Levin 
320*1664498dSSasha Levin #ifdef CONFIG_HAS_AIO
321*1664498dSSasha Levin int aio_pwritev(io_context_t ctx, struct iocb *iocb, int fd, const struct iovec *iov, int iovcnt,
322*1664498dSSasha Levin 		off_t offset, int ev, void *param)
323*1664498dSSasha Levin {
324*1664498dSSasha Levin 	struct iocb *ios[1] = { iocb };
325*1664498dSSasha Levin 
326*1664498dSSasha Levin 	io_prep_pwritev(iocb, fd, iov, iovcnt, offset);
327*1664498dSSasha Levin 	io_set_eventfd(iocb, ev);
328*1664498dSSasha Levin 	iocb->data = param;
329*1664498dSSasha Levin 
330*1664498dSSasha Levin 	return io_submit(ctx, 1, ios);
331*1664498dSSasha Levin }
332*1664498dSSasha Levin 
333*1664498dSSasha Levin int aio_preadv(io_context_t ctx, struct iocb *iocb, int fd, const struct iovec *iov, int iovcnt,
334*1664498dSSasha Levin 		off_t offset, int ev, void *param)
335*1664498dSSasha Levin {
336*1664498dSSasha Levin 	struct iocb *ios[1] = { iocb };
337*1664498dSSasha Levin 
338*1664498dSSasha Levin 	io_prep_preadv(iocb, fd, iov, iovcnt, offset);
339*1664498dSSasha Levin 	io_set_eventfd(iocb, ev);
340*1664498dSSasha Levin 	iocb->data = param;
341*1664498dSSasha Levin 
342*1664498dSSasha Levin 	return io_submit(ctx, 1, ios);
343*1664498dSSasha Levin }
344*1664498dSSasha Levin #endif