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