xref: /kvmtool/util/read-write.c (revision 1547507fa38e1c0468b0278ba25097f289ea7f3a)
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 }
155*1547507fSSasha Levin 
156*1547507fSSasha Levin /* Same as readv(2) except that this function never returns EAGAIN or EINTR. */
157*1547507fSSasha Levin ssize_t xreadv(int fd, const struct iovec *iov, int iovcnt)
158*1547507fSSasha Levin {
159*1547507fSSasha Levin 	ssize_t nr;
160*1547507fSSasha Levin 
161*1547507fSSasha Levin restart:
162*1547507fSSasha Levin 	nr = readv(fd, iov, iovcnt);
163*1547507fSSasha Levin 	if ((nr < 0) && ((errno == EAGAIN) || (errno == EINTR)))
164*1547507fSSasha Levin 		goto restart;
165*1547507fSSasha Levin 
166*1547507fSSasha Levin 	return nr;
167*1547507fSSasha Levin }
168*1547507fSSasha Levin 
169*1547507fSSasha Levin /* Same as writev(2) except that this function never returns EAGAIN or EINTR. */
170*1547507fSSasha Levin ssize_t xwritev(int fd, const struct iovec *iov, int iovcnt)
171*1547507fSSasha Levin {
172*1547507fSSasha Levin 	ssize_t nr;
173*1547507fSSasha Levin 
174*1547507fSSasha Levin restart:
175*1547507fSSasha Levin 	nr = write(fd, iov, iovcnt);
176*1547507fSSasha Levin 	if ((nr < 0) && ((errno == EAGAIN) || (errno == EINTR)))
177*1547507fSSasha Levin 		goto restart;
178*1547507fSSasha Levin 
179*1547507fSSasha Levin 	return nr;
180*1547507fSSasha Levin }
181*1547507fSSasha Levin 
182*1547507fSSasha Levin static inline ssize_t get_iov_size(const struct iovec *iov, int iovcnt)
183*1547507fSSasha Levin {
184*1547507fSSasha Levin 	size_t size = 0;
185*1547507fSSasha Levin 	while (iovcnt--)
186*1547507fSSasha Levin 		size += (iov++)->iov_len;
187*1547507fSSasha Levin 
188*1547507fSSasha Levin 	return size;
189*1547507fSSasha Levin }
190*1547507fSSasha Levin 
191*1547507fSSasha Levin ssize_t readv_in_full(int fd, const struct iovec *iov, int iovcnt)
192*1547507fSSasha Levin {
193*1547507fSSasha Levin 	ssize_t total = 0;
194*1547507fSSasha Levin 	ssize_t count = get_iov_size(iov, iovcnt);
195*1547507fSSasha Levin 
196*1547507fSSasha Levin 	while (count > 0) {
197*1547507fSSasha Levin 		ssize_t nr;
198*1547507fSSasha Levin 
199*1547507fSSasha Levin 		nr = xreadv(fd, iov, iovcnt);
200*1547507fSSasha Levin 		if (nr <= 0) {
201*1547507fSSasha Levin 			if (total > 0)
202*1547507fSSasha Levin 				return total;
203*1547507fSSasha Levin 
204*1547507fSSasha Levin 			return -1;
205*1547507fSSasha Levin 		}
206*1547507fSSasha Levin 
207*1547507fSSasha Levin 		while ((size_t)nr >= iov->iov_len) {
208*1547507fSSasha Levin 			nr -= iov->iov_len;
209*1547507fSSasha Levin 			total += iov->iov_len;
210*1547507fSSasha Levin 			count -= iov->iov_len;
211*1547507fSSasha Levin 			iovcnt--;
212*1547507fSSasha Levin 			iov++;
213*1547507fSSasha Levin 		}
214*1547507fSSasha Levin 	}
215*1547507fSSasha Levin 
216*1547507fSSasha Levin 	return total;
217*1547507fSSasha Levin }
218*1547507fSSasha Levin 
219*1547507fSSasha Levin ssize_t writev_in_full(int fd, const struct iovec *iov, int iovcnt)
220*1547507fSSasha Levin {
221*1547507fSSasha Levin 	ssize_t total = 0;
222*1547507fSSasha Levin 	size_t count = get_iov_size(iov, iovcnt);
223*1547507fSSasha Levin 
224*1547507fSSasha Levin 	while (count > 0) {
225*1547507fSSasha Levin 		ssize_t nr;
226*1547507fSSasha Levin 
227*1547507fSSasha Levin 		nr = xwritev(fd, iov, iovcnt);
228*1547507fSSasha Levin 		if (nr < 0)
229*1547507fSSasha Levin 			return -1;
230*1547507fSSasha Levin 		if (nr == 0) {
231*1547507fSSasha Levin 			errno = ENOSPC;
232*1547507fSSasha Levin 			return -1;
233*1547507fSSasha Levin 		}
234*1547507fSSasha Levin 
235*1547507fSSasha Levin 		while ((size_t)nr >= iov->iov_len) {
236*1547507fSSasha Levin 			nr -= iov->iov_len;
237*1547507fSSasha Levin 			total += iov->iov_len;
238*1547507fSSasha Levin 			count -= iov->iov_len;
239*1547507fSSasha Levin 			iovcnt--;
240*1547507fSSasha Levin 			iov++;
241*1547507fSSasha Levin 		}
242*1547507fSSasha Levin 	}
243*1547507fSSasha Levin 
244*1547507fSSasha Levin 	return total;
245*1547507fSSasha Levin }
246*1547507fSSasha Levin 
247*1547507fSSasha Levin /* Same as preadv(2) except that this function never returns EAGAIN or EINTR. */
248*1547507fSSasha Levin ssize_t xpreadv(int fd, const struct iovec *iov, int iovcnt, off_t offset)
249*1547507fSSasha Levin {
250*1547507fSSasha Levin 	ssize_t nr;
251*1547507fSSasha Levin 
252*1547507fSSasha Levin restart:
253*1547507fSSasha Levin 	nr = preadv(fd, iov, iovcnt, offset);
254*1547507fSSasha Levin 	if ((nr < 0) && ((errno == EAGAIN) || (errno == EINTR)))
255*1547507fSSasha Levin 		goto restart;
256*1547507fSSasha Levin 
257*1547507fSSasha Levin 	return nr;
258*1547507fSSasha Levin }
259*1547507fSSasha Levin 
260*1547507fSSasha Levin /* Same as pwritev(2) except that this function never returns EAGAIN or EINTR. */
261*1547507fSSasha Levin ssize_t xpwritev(int fd, const struct iovec *iov, int iovcnt, off_t offset)
262*1547507fSSasha Levin {
263*1547507fSSasha Levin 	ssize_t nr;
264*1547507fSSasha Levin 
265*1547507fSSasha Levin restart:
266*1547507fSSasha Levin 	nr = pwritev(fd, iov, iovcnt, offset);
267*1547507fSSasha Levin 	if ((nr < 0) && ((errno == EAGAIN) || (errno == EINTR)))
268*1547507fSSasha Levin 		goto restart;
269*1547507fSSasha Levin 
270*1547507fSSasha Levin 	return nr;
271*1547507fSSasha Levin }
272*1547507fSSasha Levin 
273*1547507fSSasha Levin ssize_t preadv_in_full(int fd, const struct iovec *iov, int iovcnt, off_t offset)
274*1547507fSSasha Levin {
275*1547507fSSasha Levin 	ssize_t total = 0;
276*1547507fSSasha Levin 	size_t count = get_iov_size(iov, iovcnt);
277*1547507fSSasha Levin 
278*1547507fSSasha Levin 	while (count > 0) {
279*1547507fSSasha Levin 		ssize_t nr;
280*1547507fSSasha Levin 
281*1547507fSSasha Levin 		nr = xpreadv(fd, iov, iovcnt, offset);
282*1547507fSSasha Levin 		if (nr <= 0) {
283*1547507fSSasha Levin 			if (total > 0)
284*1547507fSSasha Levin 				return total;
285*1547507fSSasha Levin 
286*1547507fSSasha Levin 			return -1;
287*1547507fSSasha Levin 		}
288*1547507fSSasha Levin 
289*1547507fSSasha Levin 		while ((size_t)nr >= iov->iov_len) {
290*1547507fSSasha Levin 			nr -= iov->iov_len;
291*1547507fSSasha Levin 			total += iov->iov_len;
292*1547507fSSasha Levin 			count -= iov->iov_len;
293*1547507fSSasha Levin 			iovcnt--;
294*1547507fSSasha Levin 			iov++;
295*1547507fSSasha Levin 		}
296*1547507fSSasha Levin 	}
297*1547507fSSasha Levin 
298*1547507fSSasha Levin 	return total;
299*1547507fSSasha Levin }
300*1547507fSSasha Levin 
301*1547507fSSasha Levin ssize_t pwritev_in_full(int fd, const struct iovec *iov, int iovcnt, off_t offset)
302*1547507fSSasha Levin {
303*1547507fSSasha Levin 	ssize_t total = 0;
304*1547507fSSasha Levin 	size_t count = get_iov_size(iov, iovcnt);
305*1547507fSSasha Levin 
306*1547507fSSasha Levin 	while (count > 0) {
307*1547507fSSasha Levin 		ssize_t nr;
308*1547507fSSasha Levin 
309*1547507fSSasha Levin 		nr = xpwritev(fd, iov, iovcnt, offset);
310*1547507fSSasha Levin 		if (nr < 0)
311*1547507fSSasha Levin 			return -1;
312*1547507fSSasha Levin 		if (nr == 0) {
313*1547507fSSasha Levin 			errno = ENOSPC;
314*1547507fSSasha Levin 			return -1;
315*1547507fSSasha Levin 		}
316*1547507fSSasha Levin 		while ((size_t)nr >= iov->iov_len) {
317*1547507fSSasha Levin 			nr -= iov->iov_len;
318*1547507fSSasha Levin 			total += iov->iov_len;
319*1547507fSSasha Levin 			count -= iov->iov_len;
320*1547507fSSasha Levin 			iovcnt--;
321*1547507fSSasha Levin 			iov++;
322*1547507fSSasha Levin 		}
323*1547507fSSasha Levin 	}
324*1547507fSSasha Levin 
325*1547507fSSasha Levin 	return total;
326*1547507fSSasha Levin }
327