xref: /kvmtool/util/read-write.c (revision 4c0205d09acf6f8702a002475f517d5e5a64ebd8)
1c4d7847bSPekka Enberg #include "kvm/read-write.h"
2c4d7847bSPekka Enberg 
3c4d7847bSPekka Enberg #include <sys/types.h>
4c4d7847bSPekka Enberg #include <unistd.h>
5c4d7847bSPekka Enberg #include <string.h>
6c4d7847bSPekka Enberg #include <errno.h>
7c4d7847bSPekka Enberg 
8c4d7847bSPekka Enberg /* Same as read(2) except that this function never returns EAGAIN or EINTR. */
9c4d7847bSPekka Enberg ssize_t xread(int fd, void *buf, size_t count)
10c4d7847bSPekka Enberg {
11c4d7847bSPekka Enberg 	ssize_t nr;
12c4d7847bSPekka Enberg 
13c4d7847bSPekka Enberg restart:
14c4d7847bSPekka Enberg 	nr = read(fd, buf, count);
15c4d7847bSPekka Enberg 	if ((nr < 0) && ((errno == EAGAIN) || (errno == EINTR)))
16c4d7847bSPekka Enberg 		goto restart;
17c4d7847bSPekka Enberg 
18c4d7847bSPekka Enberg 	return nr;
19c4d7847bSPekka Enberg }
20c4d7847bSPekka Enberg 
21c4d7847bSPekka Enberg /* Same as write(2) except that this function never returns EAGAIN or EINTR. */
22c4d7847bSPekka Enberg ssize_t xwrite(int fd, const void *buf, size_t count)
23c4d7847bSPekka Enberg {
24c4d7847bSPekka Enberg 	ssize_t nr;
25c4d7847bSPekka Enberg 
26c4d7847bSPekka Enberg restart:
27c4d7847bSPekka Enberg 	nr = write(fd, buf, count);
28c4d7847bSPekka Enberg 	if ((nr < 0) && ((errno == EAGAIN) || (errno == EINTR)))
29c4d7847bSPekka Enberg 		goto restart;
30c4d7847bSPekka Enberg 
31c4d7847bSPekka Enberg 	return nr;
32c4d7847bSPekka Enberg }
33c4d7847bSPekka Enberg 
34c4d7847bSPekka Enberg ssize_t read_in_full(int fd, void *buf, size_t count)
35c4d7847bSPekka Enberg {
36c4d7847bSPekka Enberg 	ssize_t total = 0;
37c4d7847bSPekka Enberg 	char *p = buf;
38c4d7847bSPekka Enberg 
39c4d7847bSPekka Enberg 	while (count > 0) {
40c4d7847bSPekka Enberg 		ssize_t nr;
41c4d7847bSPekka Enberg 
42c4d7847bSPekka Enberg 		nr = xread(fd, p, count);
43c4d7847bSPekka Enberg 		if (nr <= 0) {
44c4d7847bSPekka Enberg 			if (total > 0)
45c4d7847bSPekka Enberg 				return total;
46c4d7847bSPekka Enberg 
47c4d7847bSPekka Enberg 			return -1;
48c4d7847bSPekka Enberg 		}
49c4d7847bSPekka Enberg 
50c4d7847bSPekka Enberg 		count -= nr;
51c4d7847bSPekka Enberg 		total += nr;
52c4d7847bSPekka Enberg 		p += nr;
53c4d7847bSPekka Enberg 	}
54c4d7847bSPekka Enberg 
55c4d7847bSPekka Enberg 	return total;
56c4d7847bSPekka Enberg }
57c4d7847bSPekka Enberg 
58c4d7847bSPekka Enberg ssize_t write_in_full(int fd, const void *buf, size_t count)
59c4d7847bSPekka Enberg {
60c4d7847bSPekka Enberg 	const char *p = buf;
61c4d7847bSPekka Enberg 	ssize_t total = 0;
62c4d7847bSPekka Enberg 
63c4d7847bSPekka Enberg 	while (count > 0) {
64c4d7847bSPekka Enberg 		ssize_t nr;
65c4d7847bSPekka Enberg 
66c4d7847bSPekka Enberg 		nr = xwrite(fd, p, count);
67c4d7847bSPekka Enberg 		if (nr < 0)
68c4d7847bSPekka Enberg 			return -1;
69c4d7847bSPekka Enberg 		if (nr == 0) {
70c4d7847bSPekka Enberg 			errno = ENOSPC;
71c4d7847bSPekka Enberg 			return -1;
72c4d7847bSPekka Enberg 		}
73c4d7847bSPekka Enberg 		count -= nr;
74c4d7847bSPekka Enberg 		total += nr;
75c4d7847bSPekka Enberg 		p += nr;
76c4d7847bSPekka Enberg 	}
77c4d7847bSPekka Enberg 
78c4d7847bSPekka Enberg 	return total;
79c4d7847bSPekka Enberg }
806b7deb02SPekka Enberg 
816b7deb02SPekka Enberg /* Same as pread(2) except that this function never returns EAGAIN or EINTR. */
826b7deb02SPekka Enberg ssize_t xpread(int fd, void *buf, size_t count, off_t offset)
836b7deb02SPekka Enberg {
846b7deb02SPekka Enberg 	ssize_t nr;
856b7deb02SPekka Enberg 
866b7deb02SPekka Enberg restart:
876b7deb02SPekka Enberg 	nr = pread(fd, buf, count, offset);
886b7deb02SPekka Enberg 	if ((nr < 0) && ((errno == EAGAIN) || (errno == EINTR)))
896b7deb02SPekka Enberg 		goto restart;
906b7deb02SPekka Enberg 
916b7deb02SPekka Enberg 	return nr;
926b7deb02SPekka Enberg }
936b7deb02SPekka Enberg 
946b7deb02SPekka Enberg /* Same as pwrite(2) except that this function never returns EAGAIN or EINTR. */
956b7deb02SPekka Enberg ssize_t xpwrite(int fd, const void *buf, size_t count, off_t offset)
966b7deb02SPekka Enberg {
976b7deb02SPekka Enberg 	ssize_t nr;
986b7deb02SPekka Enberg 
996b7deb02SPekka Enberg restart:
1006b7deb02SPekka Enberg 	nr = pwrite(fd, buf, count, offset);
1016b7deb02SPekka Enberg 	if ((nr < 0) && ((errno == EAGAIN) || (errno == EINTR)))
1026b7deb02SPekka Enberg 		goto restart;
1036b7deb02SPekka Enberg 
1046b7deb02SPekka Enberg 	return nr;
1056b7deb02SPekka Enberg }
1066b7deb02SPekka Enberg 
1076b7deb02SPekka Enberg ssize_t pread_in_full(int fd, void *buf, size_t count, off_t offset)
1086b7deb02SPekka Enberg {
1096b7deb02SPekka Enberg 	ssize_t total = 0;
1106b7deb02SPekka Enberg 	char *p = buf;
1116b7deb02SPekka Enberg 
1126b7deb02SPekka Enberg 	while (count > 0) {
1136b7deb02SPekka Enberg 		ssize_t nr;
1146b7deb02SPekka Enberg 
1156b7deb02SPekka Enberg 		nr = xpread(fd, p, count, offset);
1166b7deb02SPekka Enberg 		if (nr <= 0) {
1176b7deb02SPekka Enberg 			if (total > 0)
1186b7deb02SPekka Enberg 				return total;
1196b7deb02SPekka Enberg 
1206b7deb02SPekka Enberg 			return -1;
1216b7deb02SPekka Enberg 		}
1226b7deb02SPekka Enberg 
1236b7deb02SPekka Enberg 		count -= nr;
1246b7deb02SPekka Enberg 		total += nr;
1256b7deb02SPekka Enberg 		p += nr;
1266b7deb02SPekka Enberg 		offset += nr;
1276b7deb02SPekka Enberg 	}
1286b7deb02SPekka Enberg 
1296b7deb02SPekka Enberg 	return total;
1306b7deb02SPekka Enberg }
1316b7deb02SPekka Enberg 
1326b7deb02SPekka Enberg ssize_t pwrite_in_full(int fd, const void *buf, size_t count, off_t offset)
1336b7deb02SPekka Enberg {
1346b7deb02SPekka Enberg 	const char *p = buf;
1356b7deb02SPekka Enberg 	ssize_t total = 0;
1366b7deb02SPekka Enberg 
1376b7deb02SPekka Enberg 	while (count > 0) {
1386b7deb02SPekka Enberg 		ssize_t nr;
1396b7deb02SPekka Enberg 
1406b7deb02SPekka Enberg 		nr = xpwrite(fd, p, count, offset);
1416b7deb02SPekka Enberg 		if (nr < 0)
1426b7deb02SPekka Enberg 			return -1;
1436b7deb02SPekka Enberg 		if (nr == 0) {
1446b7deb02SPekka Enberg 			errno = ENOSPC;
1456b7deb02SPekka Enberg 			return -1;
1466b7deb02SPekka Enberg 		}
1476b7deb02SPekka Enberg 		count -= nr;
1486b7deb02SPekka Enberg 		total += nr;
1496b7deb02SPekka Enberg 		p += nr;
1506b7deb02SPekka Enberg 		offset += nr;
1516b7deb02SPekka Enberg 	}
1526b7deb02SPekka Enberg 
1536b7deb02SPekka Enberg 	return total;
1546b7deb02SPekka Enberg }
1551547507fSSasha Levin 
1561547507fSSasha Levin /* Same as readv(2) except that this function never returns EAGAIN or EINTR. */
1571547507fSSasha Levin ssize_t xreadv(int fd, const struct iovec *iov, int iovcnt)
1581547507fSSasha Levin {
1591547507fSSasha Levin 	ssize_t nr;
1601547507fSSasha Levin 
1611547507fSSasha Levin restart:
1621547507fSSasha Levin 	nr = readv(fd, iov, iovcnt);
1631547507fSSasha Levin 	if ((nr < 0) && ((errno == EAGAIN) || (errno == EINTR)))
1641547507fSSasha Levin 		goto restart;
1651547507fSSasha Levin 
1661547507fSSasha Levin 	return nr;
1671547507fSSasha Levin }
1681547507fSSasha Levin 
1691547507fSSasha Levin /* Same as writev(2) except that this function never returns EAGAIN or EINTR. */
1701547507fSSasha Levin ssize_t xwritev(int fd, const struct iovec *iov, int iovcnt)
1711547507fSSasha Levin {
1721547507fSSasha Levin 	ssize_t nr;
1731547507fSSasha Levin 
1741547507fSSasha Levin restart:
1751547507fSSasha Levin 	nr = write(fd, iov, iovcnt);
1761547507fSSasha Levin 	if ((nr < 0) && ((errno == EAGAIN) || (errno == EINTR)))
1771547507fSSasha Levin 		goto restart;
1781547507fSSasha Levin 
1791547507fSSasha Levin 	return nr;
1801547507fSSasha Levin }
1811547507fSSasha Levin 
1821547507fSSasha Levin static inline ssize_t get_iov_size(const struct iovec *iov, int iovcnt)
1831547507fSSasha Levin {
1841547507fSSasha Levin 	size_t size = 0;
1851547507fSSasha Levin 	while (iovcnt--)
1861547507fSSasha Levin 		size += (iov++)->iov_len;
1871547507fSSasha Levin 
1881547507fSSasha Levin 	return size;
1891547507fSSasha Levin }
1901547507fSSasha Levin 
191*4c0205d0SSasha Levin static inline void shift_iovec(const struct iovec **iov, int *iovcnt,
192*4c0205d0SSasha Levin 				size_t nr, ssize_t *total, size_t *count, off_t *offset)
193*4c0205d0SSasha Levin {
194*4c0205d0SSasha Levin 	while (nr >= (*iov)->iov_len) {
195*4c0205d0SSasha Levin 		nr -= (*iov)->iov_len;
196*4c0205d0SSasha Levin 		*total += (*iov)->iov_len;
197*4c0205d0SSasha Levin 		*count -= (*iov)->iov_len;
198*4c0205d0SSasha Levin 		if (offset)
199*4c0205d0SSasha Levin 			*offset += (*iov)->iov_len;
200*4c0205d0SSasha Levin 		(*iovcnt)--;
201*4c0205d0SSasha Levin 		(*iov)++;
202*4c0205d0SSasha Levin 	}
203*4c0205d0SSasha Levin }
204*4c0205d0SSasha Levin 
2051547507fSSasha Levin ssize_t readv_in_full(int fd, const struct iovec *iov, int iovcnt)
2061547507fSSasha Levin {
2071547507fSSasha Levin 	ssize_t total = 0;
208*4c0205d0SSasha Levin 	size_t count = get_iov_size(iov, iovcnt);
2091547507fSSasha Levin 
2101547507fSSasha Levin 	while (count > 0) {
2111547507fSSasha Levin 		ssize_t nr;
2121547507fSSasha Levin 
2131547507fSSasha Levin 		nr = xreadv(fd, iov, iovcnt);
2141547507fSSasha Levin 		if (nr <= 0) {
2151547507fSSasha Levin 			if (total > 0)
2161547507fSSasha Levin 				return total;
2171547507fSSasha Levin 
2181547507fSSasha Levin 			return -1;
2191547507fSSasha Levin 		}
2201547507fSSasha Levin 
221*4c0205d0SSasha Levin 		shift_iovec(&iov, &iovcnt, nr, &total, &count, NULL);
2221547507fSSasha Levin 	}
2231547507fSSasha Levin 
2241547507fSSasha Levin 	return total;
2251547507fSSasha Levin }
2261547507fSSasha Levin 
2271547507fSSasha Levin ssize_t writev_in_full(int fd, const struct iovec *iov, int iovcnt)
2281547507fSSasha Levin {
2291547507fSSasha Levin 	ssize_t total = 0;
2301547507fSSasha Levin 	size_t count = get_iov_size(iov, iovcnt);
2311547507fSSasha Levin 
2321547507fSSasha Levin 	while (count > 0) {
2331547507fSSasha Levin 		ssize_t nr;
2341547507fSSasha Levin 
2351547507fSSasha Levin 		nr = xwritev(fd, iov, iovcnt);
2361547507fSSasha Levin 		if (nr < 0)
2371547507fSSasha Levin 			return -1;
2381547507fSSasha Levin 		if (nr == 0) {
2391547507fSSasha Levin 			errno = ENOSPC;
2401547507fSSasha Levin 			return -1;
2411547507fSSasha Levin 		}
2421547507fSSasha Levin 
243*4c0205d0SSasha Levin 		shift_iovec(&iov, &iovcnt, nr, &total, &count, NULL);
2441547507fSSasha Levin 	}
2451547507fSSasha Levin 
2461547507fSSasha Levin 	return total;
2471547507fSSasha Levin }
2481547507fSSasha Levin 
2491547507fSSasha Levin /* Same as preadv(2) except that this function never returns EAGAIN or EINTR. */
2501547507fSSasha Levin ssize_t xpreadv(int fd, const struct iovec *iov, int iovcnt, off_t offset)
2511547507fSSasha Levin {
2521547507fSSasha Levin 	ssize_t nr;
2531547507fSSasha Levin 
2541547507fSSasha Levin restart:
2551547507fSSasha Levin 	nr = preadv(fd, iov, iovcnt, offset);
2561547507fSSasha Levin 	if ((nr < 0) && ((errno == EAGAIN) || (errno == EINTR)))
2571547507fSSasha Levin 		goto restart;
2581547507fSSasha Levin 
2591547507fSSasha Levin 	return nr;
2601547507fSSasha Levin }
2611547507fSSasha Levin 
2621547507fSSasha Levin /* Same as pwritev(2) except that this function never returns EAGAIN or EINTR. */
2631547507fSSasha Levin ssize_t xpwritev(int fd, const struct iovec *iov, int iovcnt, off_t offset)
2641547507fSSasha Levin {
2651547507fSSasha Levin 	ssize_t nr;
2661547507fSSasha Levin 
2671547507fSSasha Levin restart:
2681547507fSSasha Levin 	nr = pwritev(fd, iov, iovcnt, offset);
2691547507fSSasha Levin 	if ((nr < 0) && ((errno == EAGAIN) || (errno == EINTR)))
2701547507fSSasha Levin 		goto restart;
2711547507fSSasha Levin 
2721547507fSSasha Levin 	return nr;
2731547507fSSasha Levin }
2741547507fSSasha Levin 
2751547507fSSasha Levin ssize_t preadv_in_full(int fd, const struct iovec *iov, int iovcnt, off_t offset)
2761547507fSSasha Levin {
2771547507fSSasha Levin 	ssize_t total = 0;
2781547507fSSasha Levin 	size_t count = get_iov_size(iov, iovcnt);
2791547507fSSasha Levin 
2801547507fSSasha Levin 	while (count > 0) {
2811547507fSSasha Levin 		ssize_t nr;
2821547507fSSasha Levin 
2831547507fSSasha Levin 		nr = xpreadv(fd, iov, iovcnt, offset);
2841547507fSSasha Levin 		if (nr <= 0) {
2851547507fSSasha Levin 			if (total > 0)
2861547507fSSasha Levin 				return total;
2871547507fSSasha Levin 
2881547507fSSasha Levin 			return -1;
2891547507fSSasha Levin 		}
2901547507fSSasha Levin 
291*4c0205d0SSasha Levin 		shift_iovec(&iov, &iovcnt, nr, &total, &count, &offset);
2921547507fSSasha Levin 	}
2931547507fSSasha Levin 
2941547507fSSasha Levin 	return total;
2951547507fSSasha Levin }
2961547507fSSasha Levin 
2971547507fSSasha Levin ssize_t pwritev_in_full(int fd, const struct iovec *iov, int iovcnt, off_t offset)
2981547507fSSasha Levin {
2991547507fSSasha Levin 	ssize_t total = 0;
3001547507fSSasha Levin 	size_t count = get_iov_size(iov, iovcnt);
3011547507fSSasha Levin 
3021547507fSSasha Levin 	while (count > 0) {
3031547507fSSasha Levin 		ssize_t nr;
3041547507fSSasha Levin 
3051547507fSSasha Levin 		nr = xpwritev(fd, iov, iovcnt, offset);
3061547507fSSasha Levin 		if (nr < 0)
3071547507fSSasha Levin 			return -1;
3081547507fSSasha Levin 		if (nr == 0) {
3091547507fSSasha Levin 			errno = ENOSPC;
3101547507fSSasha Levin 			return -1;
3111547507fSSasha Levin 		}
312*4c0205d0SSasha Levin 
313*4c0205d0SSasha Levin 		shift_iovec(&iov, &iovcnt, nr, &total, &count, &offset);
3141547507fSSasha Levin 	}
3151547507fSSasha Levin 
3161547507fSSasha Levin 	return total;
3171547507fSSasha Levin }
318