xref: /kvmtool/util/read-write.c (revision 30a9aa69300118907de7735f5695f8b142d74455)
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. */
xread(int fd,void * buf,size_t count)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. */
xwrite(int fd,const void * buf,size_t count)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 
35*649f9515SAndre Przywara /*
36*649f9515SAndre Przywara  * Read in the whole file while not exceeding max_size bytes of the buffer.
37*649f9515SAndre Przywara  * Returns -1 (with errno set) in case of an error (ENOMEM if buffer was
38*649f9515SAndre Przywara  * too small) or the filesize if the whole file could be read.
39*649f9515SAndre Przywara  */
read_file(int fd,char * buf,size_t max_size)40*649f9515SAndre Przywara ssize_t read_file(int fd, char *buf, size_t max_size)
41*649f9515SAndre Przywara {
42*649f9515SAndre Przywara 	ssize_t ret;
43*649f9515SAndre Przywara 	char dummy;
44*649f9515SAndre Przywara 
45*649f9515SAndre Przywara 	errno = 0;
46*649f9515SAndre Przywara 	ret = read_in_full(fd, buf, max_size);
47*649f9515SAndre Przywara 
48*649f9515SAndre Przywara 	/* Probe whether we reached EOF. */
49*649f9515SAndre Przywara 	if (xread(fd, &dummy, 1) == 0)
50*649f9515SAndre Przywara 		return ret;
51*649f9515SAndre Przywara 
52*649f9515SAndre Przywara 	errno = ENOMEM;
53*649f9515SAndre Przywara 	return -1;
54*649f9515SAndre Przywara }
55*649f9515SAndre Przywara 
read_in_full(int fd,void * buf,size_t count)56c4d7847bSPekka Enberg ssize_t read_in_full(int fd, void *buf, size_t count)
57c4d7847bSPekka Enberg {
58c4d7847bSPekka Enberg 	ssize_t total = 0;
59c4d7847bSPekka Enberg 	char *p = buf;
60c4d7847bSPekka Enberg 
61c4d7847bSPekka Enberg 	while (count > 0) {
62c4d7847bSPekka Enberg 		ssize_t nr;
63c4d7847bSPekka Enberg 
64c4d7847bSPekka Enberg 		nr = xread(fd, p, count);
65c4d7847bSPekka Enberg 		if (nr <= 0) {
66c4d7847bSPekka Enberg 			if (total > 0)
67c4d7847bSPekka Enberg 				return total;
68c4d7847bSPekka Enberg 
69c4d7847bSPekka Enberg 			return -1;
70c4d7847bSPekka Enberg 		}
71c4d7847bSPekka Enberg 
72c4d7847bSPekka Enberg 		count -= nr;
73c4d7847bSPekka Enberg 		total += nr;
74c4d7847bSPekka Enberg 		p += nr;
75c4d7847bSPekka Enberg 	}
76c4d7847bSPekka Enberg 
77c4d7847bSPekka Enberg 	return total;
78c4d7847bSPekka Enberg }
79c4d7847bSPekka Enberg 
write_in_full(int fd,const void * buf,size_t count)80c4d7847bSPekka Enberg ssize_t write_in_full(int fd, const void *buf, size_t count)
81c4d7847bSPekka Enberg {
82c4d7847bSPekka Enberg 	const char *p = buf;
83c4d7847bSPekka Enberg 	ssize_t total = 0;
84c4d7847bSPekka Enberg 
85c4d7847bSPekka Enberg 	while (count > 0) {
86c4d7847bSPekka Enberg 		ssize_t nr;
87c4d7847bSPekka Enberg 
88c4d7847bSPekka Enberg 		nr = xwrite(fd, p, count);
89c4d7847bSPekka Enberg 		if (nr < 0)
90c4d7847bSPekka Enberg 			return -1;
91c4d7847bSPekka Enberg 		if (nr == 0) {
92c4d7847bSPekka Enberg 			errno = ENOSPC;
93c4d7847bSPekka Enberg 			return -1;
94c4d7847bSPekka Enberg 		}
95c4d7847bSPekka Enberg 		count -= nr;
96c4d7847bSPekka Enberg 		total += nr;
97c4d7847bSPekka Enberg 		p += nr;
98c4d7847bSPekka Enberg 	}
99c4d7847bSPekka Enberg 
100c4d7847bSPekka Enberg 	return total;
101c4d7847bSPekka Enberg }
1026b7deb02SPekka Enberg 
1036b7deb02SPekka Enberg /* Same as pread(2) except that this function never returns EAGAIN or EINTR. */
xpread(int fd,void * buf,size_t count,off_t offset)1046b7deb02SPekka Enberg ssize_t xpread(int fd, void *buf, size_t count, off_t offset)
1056b7deb02SPekka Enberg {
1066b7deb02SPekka Enberg 	ssize_t nr;
1076b7deb02SPekka Enberg 
1086b7deb02SPekka Enberg restart:
1096b7deb02SPekka Enberg 	nr = pread(fd, buf, count, offset);
1106b7deb02SPekka Enberg 	if ((nr < 0) && ((errno == EAGAIN) || (errno == EINTR)))
1116b7deb02SPekka Enberg 		goto restart;
1126b7deb02SPekka Enberg 
1136b7deb02SPekka Enberg 	return nr;
1146b7deb02SPekka Enberg }
1156b7deb02SPekka Enberg 
1166b7deb02SPekka Enberg /* Same as pwrite(2) except that this function never returns EAGAIN or EINTR. */
xpwrite(int fd,const void * buf,size_t count,off_t offset)1176b7deb02SPekka Enberg ssize_t xpwrite(int fd, const void *buf, size_t count, off_t offset)
1186b7deb02SPekka Enberg {
1196b7deb02SPekka Enberg 	ssize_t nr;
1206b7deb02SPekka Enberg 
1216b7deb02SPekka Enberg restart:
1226b7deb02SPekka Enberg 	nr = pwrite(fd, buf, count, offset);
1236b7deb02SPekka Enberg 	if ((nr < 0) && ((errno == EAGAIN) || (errno == EINTR)))
1246b7deb02SPekka Enberg 		goto restart;
1256b7deb02SPekka Enberg 
1266b7deb02SPekka Enberg 	return nr;
1276b7deb02SPekka Enberg }
1286b7deb02SPekka Enberg 
pread_in_full(int fd,void * buf,size_t count,off_t offset)1296b7deb02SPekka Enberg ssize_t pread_in_full(int fd, void *buf, size_t count, off_t offset)
1306b7deb02SPekka Enberg {
1316b7deb02SPekka Enberg 	ssize_t total = 0;
1326b7deb02SPekka Enberg 	char *p = buf;
1336b7deb02SPekka Enberg 
1346b7deb02SPekka Enberg 	while (count > 0) {
1356b7deb02SPekka Enberg 		ssize_t nr;
1366b7deb02SPekka Enberg 
1376b7deb02SPekka Enberg 		nr = xpread(fd, p, count, offset);
1386b7deb02SPekka Enberg 		if (nr <= 0) {
1396b7deb02SPekka Enberg 			if (total > 0)
1406b7deb02SPekka Enberg 				return total;
1416b7deb02SPekka Enberg 
1426b7deb02SPekka Enberg 			return -1;
1436b7deb02SPekka Enberg 		}
1446b7deb02SPekka Enberg 
1456b7deb02SPekka Enberg 		count -= nr;
1466b7deb02SPekka Enberg 		total += nr;
1476b7deb02SPekka Enberg 		p += nr;
1486b7deb02SPekka Enberg 		offset += nr;
1496b7deb02SPekka Enberg 	}
1506b7deb02SPekka Enberg 
1516b7deb02SPekka Enberg 	return total;
1526b7deb02SPekka Enberg }
1536b7deb02SPekka Enberg 
pwrite_in_full(int fd,const void * buf,size_t count,off_t offset)1546b7deb02SPekka Enberg ssize_t pwrite_in_full(int fd, const void *buf, size_t count, off_t offset)
1556b7deb02SPekka Enberg {
1566b7deb02SPekka Enberg 	const char *p = buf;
1576b7deb02SPekka Enberg 	ssize_t total = 0;
1586b7deb02SPekka Enberg 
1596b7deb02SPekka Enberg 	while (count > 0) {
1606b7deb02SPekka Enberg 		ssize_t nr;
1616b7deb02SPekka Enberg 
1626b7deb02SPekka Enberg 		nr = xpwrite(fd, p, count, offset);
1636b7deb02SPekka Enberg 		if (nr < 0)
1646b7deb02SPekka Enberg 			return -1;
1656b7deb02SPekka Enberg 		if (nr == 0) {
1666b7deb02SPekka Enberg 			errno = ENOSPC;
1676b7deb02SPekka Enberg 			return -1;
1686b7deb02SPekka Enberg 		}
1696b7deb02SPekka Enberg 		count -= nr;
1706b7deb02SPekka Enberg 		total += nr;
1716b7deb02SPekka Enberg 		p += nr;
1726b7deb02SPekka Enberg 		offset += nr;
1736b7deb02SPekka Enberg 	}
1746b7deb02SPekka Enberg 
1756b7deb02SPekka Enberg 	return total;
1766b7deb02SPekka Enberg }
1771547507fSSasha Levin 
1781547507fSSasha Levin /* Same as readv(2) except that this function never returns EAGAIN or EINTR. */
xreadv(int fd,const struct iovec * iov,int iovcnt)1791547507fSSasha Levin ssize_t xreadv(int fd, const struct iovec *iov, int iovcnt)
1801547507fSSasha Levin {
1811547507fSSasha Levin 	ssize_t nr;
1821547507fSSasha Levin 
1831547507fSSasha Levin restart:
1841547507fSSasha Levin 	nr = readv(fd, iov, iovcnt);
1851547507fSSasha Levin 	if ((nr < 0) && ((errno == EAGAIN) || (errno == EINTR)))
1861547507fSSasha Levin 		goto restart;
1871547507fSSasha Levin 
1881547507fSSasha Levin 	return nr;
1891547507fSSasha Levin }
1901547507fSSasha Levin 
1911547507fSSasha Levin /* Same as writev(2) except that this function never returns EAGAIN or EINTR. */
xwritev(int fd,const struct iovec * iov,int iovcnt)1921547507fSSasha Levin ssize_t xwritev(int fd, const struct iovec *iov, int iovcnt)
1931547507fSSasha Levin {
1941547507fSSasha Levin 	ssize_t nr;
1951547507fSSasha Levin 
1961547507fSSasha Levin restart:
197f42cd9ccSPekka Enberg 	nr = writev(fd, iov, iovcnt);
1981547507fSSasha Levin 	if ((nr < 0) && ((errno == EAGAIN) || (errno == EINTR)))
1991547507fSSasha Levin 		goto restart;
2001547507fSSasha Levin 
2011547507fSSasha Levin 	return nr;
2021547507fSSasha Levin }
2031547507fSSasha Levin 
get_iov_size(const struct iovec * iov,int iovcnt)2041547507fSSasha Levin static inline ssize_t get_iov_size(const struct iovec *iov, int iovcnt)
2051547507fSSasha Levin {
2061547507fSSasha Levin 	size_t size = 0;
2071547507fSSasha Levin 	while (iovcnt--)
2081547507fSSasha Levin 		size += (iov++)->iov_len;
2091547507fSSasha Levin 
2101547507fSSasha Levin 	return size;
2111547507fSSasha Levin }
2121547507fSSasha Levin 
shift_iovec(const struct iovec ** iov,int * iovcnt,size_t nr,ssize_t * total,size_t * count,off_t * offset)2134c0205d0SSasha Levin static inline void shift_iovec(const struct iovec **iov, int *iovcnt,
2144c0205d0SSasha Levin 				size_t nr, ssize_t *total, size_t *count, off_t *offset)
2154c0205d0SSasha Levin {
2164c0205d0SSasha Levin 	while (nr >= (*iov)->iov_len) {
2174c0205d0SSasha Levin 		nr -= (*iov)->iov_len;
2184c0205d0SSasha Levin 		*total += (*iov)->iov_len;
2194c0205d0SSasha Levin 		*count -= (*iov)->iov_len;
2204c0205d0SSasha Levin 		if (offset)
2214c0205d0SSasha Levin 			*offset += (*iov)->iov_len;
2224c0205d0SSasha Levin 		(*iovcnt)--;
2234c0205d0SSasha Levin 		(*iov)++;
2244c0205d0SSasha Levin 	}
2254c0205d0SSasha Levin }
2264c0205d0SSasha Levin 
readv_in_full(int fd,const struct iovec * iov,int iovcnt)2271547507fSSasha Levin ssize_t readv_in_full(int fd, const struct iovec *iov, int iovcnt)
2281547507fSSasha Levin {
2291547507fSSasha Levin 	ssize_t total = 0;
2304c0205d0SSasha 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 = xreadv(fd, iov, iovcnt);
2361547507fSSasha Levin 		if (nr <= 0) {
2371547507fSSasha Levin 			if (total > 0)
2381547507fSSasha Levin 				return total;
2391547507fSSasha Levin 
2401547507fSSasha Levin 			return -1;
2411547507fSSasha Levin 		}
2421547507fSSasha Levin 
2434c0205d0SSasha Levin 		shift_iovec(&iov, &iovcnt, nr, &total, &count, NULL);
2441547507fSSasha Levin 	}
2451547507fSSasha Levin 
2461547507fSSasha Levin 	return total;
2471547507fSSasha Levin }
2481547507fSSasha Levin 
writev_in_full(int fd,const struct iovec * iov,int iovcnt)2491547507fSSasha Levin ssize_t writev_in_full(int fd, const struct iovec *iov, int iovcnt)
2501547507fSSasha Levin {
2511547507fSSasha Levin 	ssize_t total = 0;
2521547507fSSasha Levin 	size_t count = get_iov_size(iov, iovcnt);
2531547507fSSasha Levin 
2541547507fSSasha Levin 	while (count > 0) {
2551547507fSSasha Levin 		ssize_t nr;
2561547507fSSasha Levin 
2571547507fSSasha Levin 		nr = xwritev(fd, iov, iovcnt);
2581547507fSSasha Levin 		if (nr < 0)
2591547507fSSasha Levin 			return -1;
2601547507fSSasha Levin 		if (nr == 0) {
2611547507fSSasha Levin 			errno = ENOSPC;
2621547507fSSasha Levin 			return -1;
2631547507fSSasha Levin 		}
2641547507fSSasha Levin 
2654c0205d0SSasha Levin 		shift_iovec(&iov, &iovcnt, nr, &total, &count, NULL);
2661547507fSSasha Levin 	}
2671547507fSSasha Levin 
2681547507fSSasha Levin 	return total;
2691547507fSSasha Levin }
2701547507fSSasha Levin 
2711547507fSSasha Levin /* Same as preadv(2) except that this function never returns EAGAIN or EINTR. */
xpreadv(int fd,const struct iovec * iov,int iovcnt,off_t offset)2721547507fSSasha Levin ssize_t xpreadv(int fd, const struct iovec *iov, int iovcnt, off_t offset)
2731547507fSSasha Levin {
2741547507fSSasha Levin 	ssize_t nr;
2751547507fSSasha Levin 
2761547507fSSasha Levin restart:
2771547507fSSasha Levin 	nr = preadv(fd, iov, iovcnt, offset);
2781547507fSSasha Levin 	if ((nr < 0) && ((errno == EAGAIN) || (errno == EINTR)))
2791547507fSSasha Levin 		goto restart;
2801547507fSSasha Levin 
2811547507fSSasha Levin 	return nr;
2821547507fSSasha Levin }
2831547507fSSasha Levin 
2841547507fSSasha Levin /* Same as pwritev(2) except that this function never returns EAGAIN or EINTR. */
xpwritev(int fd,const struct iovec * iov,int iovcnt,off_t offset)2851547507fSSasha Levin ssize_t xpwritev(int fd, const struct iovec *iov, int iovcnt, off_t offset)
2861547507fSSasha Levin {
2871547507fSSasha Levin 	ssize_t nr;
2881547507fSSasha Levin 
2891547507fSSasha Levin restart:
2901547507fSSasha Levin 	nr = pwritev(fd, iov, iovcnt, offset);
2911547507fSSasha Levin 	if ((nr < 0) && ((errno == EAGAIN) || (errno == EINTR)))
2921547507fSSasha Levin 		goto restart;
2931547507fSSasha Levin 
2941547507fSSasha Levin 	return nr;
2951547507fSSasha Levin }
2961547507fSSasha Levin 
preadv_in_full(int fd,const struct iovec * iov,int iovcnt,off_t offset)2971547507fSSasha Levin ssize_t preadv_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 = xpreadv(fd, iov, iovcnt, offset);
3061547507fSSasha Levin 		if (nr <= 0) {
3071547507fSSasha Levin 			if (total > 0)
3081547507fSSasha Levin 				return total;
3091547507fSSasha Levin 
3101547507fSSasha Levin 			return -1;
3111547507fSSasha Levin 		}
3121547507fSSasha Levin 
3134c0205d0SSasha Levin 		shift_iovec(&iov, &iovcnt, nr, &total, &count, &offset);
3141547507fSSasha Levin 	}
3151547507fSSasha Levin 
3161547507fSSasha Levin 	return total;
3171547507fSSasha Levin }
3181547507fSSasha Levin 
pwritev_in_full(int fd,const struct iovec * iov,int iovcnt,off_t offset)3191547507fSSasha Levin ssize_t pwritev_in_full(int fd, const struct iovec *iov, int iovcnt, off_t offset)
3201547507fSSasha Levin {
3211547507fSSasha Levin 	ssize_t total = 0;
3221547507fSSasha Levin 	size_t count = get_iov_size(iov, iovcnt);
3231547507fSSasha Levin 
3241547507fSSasha Levin 	while (count > 0) {
3251547507fSSasha Levin 		ssize_t nr;
3261547507fSSasha Levin 
3271547507fSSasha Levin 		nr = xpwritev(fd, iov, iovcnt, offset);
3281547507fSSasha Levin 		if (nr < 0)
3291547507fSSasha Levin 			return -1;
3301547507fSSasha Levin 		if (nr == 0) {
3311547507fSSasha Levin 			errno = ENOSPC;
3321547507fSSasha Levin 			return -1;
3331547507fSSasha Levin 		}
3344c0205d0SSasha Levin 
3354c0205d0SSasha Levin 		shift_iovec(&iov, &iovcnt, nr, &total, &count, &offset);
3361547507fSSasha Levin 	}
3371547507fSSasha Levin 
3381547507fSSasha Levin 	return total;
3391547507fSSasha Levin }
340