#include "kvm/read-write.h" #include #include #include #include #include /* Same as read(2) except that this function never returns EAGAIN or EINTR. */ ssize_t xread(int fd, void *buf, size_t count) { ssize_t nr; restart: nr = read(fd, buf, count); if ((nr < 0) && ((errno == EAGAIN) || (errno == EINTR))) goto restart; return nr; } /* Same as write(2) except that this function never returns EAGAIN or EINTR. */ ssize_t xwrite(int fd, const void *buf, size_t count) { ssize_t nr; restart: nr = write(fd, buf, count); if ((nr < 0) && ((errno == EAGAIN) || (errno == EINTR))) goto restart; return nr; } /* * Read in the whole file while not exceeding max_size bytes of the buffer. * Returns -1 (with errno set) in case of an error (ENOMEM if buffer was * too small) or the filesize if the whole file could be read. */ ssize_t read_file(int fd, char *buf, size_t max_size) { ssize_t ret; char dummy; errno = 0; ret = read_in_full(fd, buf, max_size); /* Probe whether we reached EOF. */ if (xread(fd, &dummy, 1) == 0) return ret; errno = ENOMEM; return -1; } ssize_t read_in_full(int fd, void *buf, size_t count) { ssize_t total = 0; char *p = buf; while (count > 0) { ssize_t nr; nr = xread(fd, p, count); if (nr <= 0) { if (total > 0) return total; return -1; } count -= nr; total += nr; p += nr; } return total; } ssize_t write_in_full(int fd, const void *buf, size_t count) { const char *p = buf; ssize_t total = 0; while (count > 0) { ssize_t nr; nr = xwrite(fd, p, count); if (nr < 0) return -1; if (nr == 0) { errno = ENOSPC; return -1; } count -= nr; total += nr; p += nr; } return total; } /* Same as pread(2) except that this function never returns EAGAIN or EINTR. */ ssize_t xpread(int fd, void *buf, size_t count, off_t offset) { ssize_t nr; restart: nr = pread(fd, buf, count, offset); if ((nr < 0) && ((errno == EAGAIN) || (errno == EINTR))) goto restart; return nr; } /* Same as pwrite(2) except that this function never returns EAGAIN or EINTR. */ ssize_t xpwrite(int fd, const void *buf, size_t count, off_t offset) { ssize_t nr; restart: nr = pwrite(fd, buf, count, offset); if ((nr < 0) && ((errno == EAGAIN) || (errno == EINTR))) goto restart; return nr; } ssize_t pread_in_full(int fd, void *buf, size_t count, off_t offset) { ssize_t total = 0; char *p = buf; while (count > 0) { ssize_t nr; nr = xpread(fd, p, count, offset); if (nr <= 0) { if (total > 0) return total; return -1; } count -= nr; total += nr; p += nr; offset += nr; } return total; } ssize_t pwrite_in_full(int fd, const void *buf, size_t count, off_t offset) { const char *p = buf; ssize_t total = 0; while (count > 0) { ssize_t nr; nr = xpwrite(fd, p, count, offset); if (nr < 0) return -1; if (nr == 0) { errno = ENOSPC; return -1; } count -= nr; total += nr; p += nr; offset += nr; } return total; } /* Same as readv(2) except that this function never returns EAGAIN or EINTR. */ ssize_t xreadv(int fd, const struct iovec *iov, int iovcnt) { ssize_t nr; restart: nr = readv(fd, iov, iovcnt); if ((nr < 0) && ((errno == EAGAIN) || (errno == EINTR))) goto restart; return nr; } /* Same as writev(2) except that this function never returns EAGAIN or EINTR. */ ssize_t xwritev(int fd, const struct iovec *iov, int iovcnt) { ssize_t nr; restart: nr = writev(fd, iov, iovcnt); if ((nr < 0) && ((errno == EAGAIN) || (errno == EINTR))) goto restart; return nr; } static inline ssize_t get_iov_size(const struct iovec *iov, int iovcnt) { size_t size = 0; while (iovcnt--) size += (iov++)->iov_len; return size; } static inline void shift_iovec(const struct iovec **iov, int *iovcnt, size_t nr, ssize_t *total, size_t *count, off_t *offset) { while (nr >= (*iov)->iov_len) { nr -= (*iov)->iov_len; *total += (*iov)->iov_len; *count -= (*iov)->iov_len; if (offset) *offset += (*iov)->iov_len; (*iovcnt)--; (*iov)++; } } ssize_t readv_in_full(int fd, const struct iovec *iov, int iovcnt) { ssize_t total = 0; size_t count = get_iov_size(iov, iovcnt); while (count > 0) { ssize_t nr; nr = xreadv(fd, iov, iovcnt); if (nr <= 0) { if (total > 0) return total; return -1; } shift_iovec(&iov, &iovcnt, nr, &total, &count, NULL); } return total; } ssize_t writev_in_full(int fd, const struct iovec *iov, int iovcnt) { ssize_t total = 0; size_t count = get_iov_size(iov, iovcnt); while (count > 0) { ssize_t nr; nr = xwritev(fd, iov, iovcnt); if (nr < 0) return -1; if (nr == 0) { errno = ENOSPC; return -1; } shift_iovec(&iov, &iovcnt, nr, &total, &count, NULL); } return total; } /* Same as preadv(2) except that this function never returns EAGAIN or EINTR. */ ssize_t xpreadv(int fd, const struct iovec *iov, int iovcnt, off_t offset) { ssize_t nr; restart: nr = preadv(fd, iov, iovcnt, offset); if ((nr < 0) && ((errno == EAGAIN) || (errno == EINTR))) goto restart; return nr; } /* Same as pwritev(2) except that this function never returns EAGAIN or EINTR. */ ssize_t xpwritev(int fd, const struct iovec *iov, int iovcnt, off_t offset) { ssize_t nr; restart: nr = pwritev(fd, iov, iovcnt, offset); if ((nr < 0) && ((errno == EAGAIN) || (errno == EINTR))) goto restart; return nr; } ssize_t preadv_in_full(int fd, const struct iovec *iov, int iovcnt, off_t offset) { ssize_t total = 0; size_t count = get_iov_size(iov, iovcnt); while (count > 0) { ssize_t nr; nr = xpreadv(fd, iov, iovcnt, offset); if (nr <= 0) { if (total > 0) return total; return -1; } shift_iovec(&iov, &iovcnt, nr, &total, &count, &offset); } return total; } ssize_t pwritev_in_full(int fd, const struct iovec *iov, int iovcnt, off_t offset) { ssize_t total = 0; size_t count = get_iov_size(iov, iovcnt); while (count > 0) { ssize_t nr; nr = xpwritev(fd, iov, iovcnt, offset); if (nr < 0) return -1; if (nr == 0) { errno = ENOSPC; return -1; } shift_iovec(&iov, &iovcnt, nr, &total, &count, &offset); } return total; }