xref: /kvmtool/util/read-write.c (revision 4c0205d09acf6f8702a002475f517d5e5a64ebd8)
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 static inline void shift_iovec(const struct iovec **iov, int *iovcnt,
192 				size_t nr, ssize_t *total, size_t *count, off_t *offset)
193 {
194 	while (nr >= (*iov)->iov_len) {
195 		nr -= (*iov)->iov_len;
196 		*total += (*iov)->iov_len;
197 		*count -= (*iov)->iov_len;
198 		if (offset)
199 			*offset += (*iov)->iov_len;
200 		(*iovcnt)--;
201 		(*iov)++;
202 	}
203 }
204 
205 ssize_t readv_in_full(int fd, const struct iovec *iov, int iovcnt)
206 {
207 	ssize_t total = 0;
208 	size_t count = get_iov_size(iov, iovcnt);
209 
210 	while (count > 0) {
211 		ssize_t nr;
212 
213 		nr = xreadv(fd, iov, iovcnt);
214 		if (nr <= 0) {
215 			if (total > 0)
216 				return total;
217 
218 			return -1;
219 		}
220 
221 		shift_iovec(&iov, &iovcnt, nr, &total, &count, NULL);
222 	}
223 
224 	return total;
225 }
226 
227 ssize_t writev_in_full(int fd, const struct iovec *iov, int iovcnt)
228 {
229 	ssize_t total = 0;
230 	size_t count = get_iov_size(iov, iovcnt);
231 
232 	while (count > 0) {
233 		ssize_t nr;
234 
235 		nr = xwritev(fd, iov, iovcnt);
236 		if (nr < 0)
237 			return -1;
238 		if (nr == 0) {
239 			errno = ENOSPC;
240 			return -1;
241 		}
242 
243 		shift_iovec(&iov, &iovcnt, nr, &total, &count, NULL);
244 	}
245 
246 	return total;
247 }
248 
249 /* Same as preadv(2) except that this function never returns EAGAIN or EINTR. */
250 ssize_t xpreadv(int fd, const struct iovec *iov, int iovcnt, off_t offset)
251 {
252 	ssize_t nr;
253 
254 restart:
255 	nr = preadv(fd, iov, iovcnt, offset);
256 	if ((nr < 0) && ((errno == EAGAIN) || (errno == EINTR)))
257 		goto restart;
258 
259 	return nr;
260 }
261 
262 /* Same as pwritev(2) except that this function never returns EAGAIN or EINTR. */
263 ssize_t xpwritev(int fd, const struct iovec *iov, int iovcnt, off_t offset)
264 {
265 	ssize_t nr;
266 
267 restart:
268 	nr = pwritev(fd, iov, iovcnt, offset);
269 	if ((nr < 0) && ((errno == EAGAIN) || (errno == EINTR)))
270 		goto restart;
271 
272 	return nr;
273 }
274 
275 ssize_t preadv_in_full(int fd, const struct iovec *iov, int iovcnt, off_t offset)
276 {
277 	ssize_t total = 0;
278 	size_t count = get_iov_size(iov, iovcnt);
279 
280 	while (count > 0) {
281 		ssize_t nr;
282 
283 		nr = xpreadv(fd, iov, iovcnt, offset);
284 		if (nr <= 0) {
285 			if (total > 0)
286 				return total;
287 
288 			return -1;
289 		}
290 
291 		shift_iovec(&iov, &iovcnt, nr, &total, &count, &offset);
292 	}
293 
294 	return total;
295 }
296 
297 ssize_t pwritev_in_full(int fd, const struct iovec *iov, int iovcnt, off_t offset)
298 {
299 	ssize_t total = 0;
300 	size_t count = get_iov_size(iov, iovcnt);
301 
302 	while (count > 0) {
303 		ssize_t nr;
304 
305 		nr = xpwritev(fd, iov, iovcnt, offset);
306 		if (nr < 0)
307 			return -1;
308 		if (nr == 0) {
309 			errno = ENOSPC;
310 			return -1;
311 		}
312 
313 		shift_iovec(&iov, &iovcnt, nr, &total, &count, &offset);
314 	}
315 
316 	return total;
317 }
318