diff --git a/disk-image.c b/disk-image.c index 9a83027..80999c1 100644 --- a/disk-image.c +++ b/disk-image.c @@ -35,10 +35,7 @@ static int raw_image__read_sector(struct disk_image *self, uint64_t sector, void if (offset + dst_len > self->size) return -1; - if (lseek(self->fd, offset, SEEK_SET) < 0) - return -1; - - if (read_in_full(self->fd, dst, dst_len) < 0) + if (pread_in_full(self->fd, dst, dst_len, offset) < 0) return -1; return 0; @@ -51,10 +48,7 @@ static int raw_image__write_sector(struct disk_image *self, uint64_t sector, voi if (offset + src_len > self->size) return -1; - if (lseek(self->fd, offset, SEEK_SET) < 0) - return -1; - - if (write_in_full(self->fd, src, src_len) < 0) + if (pwrite_in_full(self->fd, src, src_len, offset) < 0) return -1; return 0; diff --git a/include/kvm/read-write.h b/include/kvm/read-write.h index a49394b..069326b 100644 --- a/include/kvm/read-write.h +++ b/include/kvm/read-write.h @@ -10,4 +10,10 @@ ssize_t xwrite(int fd, const void *buf, size_t count); ssize_t read_in_full(int fd, void *buf, size_t count); ssize_t write_in_full(int fd, const void *buf, size_t count); +ssize_t xpread(int fd, void *buf, size_t count, off_t offset); +ssize_t xpwrite(int fd, const void *buf, size_t count, off_t offset); + +ssize_t pread_in_full(int fd, void *buf, size_t count, off_t offset); +ssize_t pwrite_in_full(int fd, const void *buf, size_t count, off_t offset); + #endif /* KVM_READ_WRITE_H */ diff --git a/read-write.c b/read-write.c index 46b147d..398918b 100644 --- a/read-write.c +++ b/read-write.c @@ -77,3 +77,78 @@ ssize_t write_in_full(int fd, const void *buf, size_t count) 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; +}