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. */ 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. */ 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 */ 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 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 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. */ 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. */ 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 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 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. */ 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. */ 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 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 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 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 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. */ 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. */ 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 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 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 341 #ifdef CONFIG_HAS_AIO 342 int aio_pwritev(io_context_t ctx, struct iocb *iocb, int fd, const struct iovec *iov, int iovcnt, 343 off_t offset, int ev, void *param) 344 { 345 struct iocb *ios[1] = { iocb }; 346 int ret; 347 348 io_prep_pwritev(iocb, fd, iov, iovcnt, offset); 349 io_set_eventfd(iocb, ev); 350 iocb->data = param; 351 352 restart: 353 ret = io_submit(ctx, 1, ios); 354 if (ret == -EAGAIN) 355 goto restart; 356 return ret; 357 } 358 359 int aio_preadv(io_context_t ctx, struct iocb *iocb, int fd, const struct iovec *iov, int iovcnt, 360 off_t offset, int ev, void *param) 361 { 362 struct iocb *ios[1] = { iocb }; 363 int ret; 364 365 io_prep_preadv(iocb, fd, iov, iovcnt, offset); 366 io_set_eventfd(iocb, ev); 367 iocb->data = param; 368 369 restart: 370 ret = io_submit(ctx, 1, ios); 371 if (ret == -EAGAIN) 372 goto restart; 373 return ret; 374 } 375 #endif 376