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