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