19f532d00SPekka Enberg #include "kvm/disk-image.h" 29f532d00SPekka Enberg 3c4d7847bSPekka Enberg #include "kvm/read-write.h" 49f532d00SPekka Enberg #include "kvm/util.h" 59f532d00SPekka Enberg 69f532d00SPekka Enberg #include <sys/types.h> 733d33901SPekka Enberg #include <inttypes.h> 89f532d00SPekka Enberg #include <sys/mman.h> 99f532d00SPekka Enberg #include <sys/stat.h> 105646450dSPekka Enberg #include <stdbool.h> 119f532d00SPekka Enberg #include <stddef.h> 129f532d00SPekka Enberg #include <stdlib.h> 139f532d00SPekka Enberg #include <unistd.h> 149f532d00SPekka Enberg #include <fcntl.h> 159f532d00SPekka Enberg 16499f3bedSPekka Enberg struct disk_image *disk_image__new(int fd, uint64_t size, struct disk_image_operations *ops) 179f532d00SPekka Enberg { 189f532d00SPekka Enberg struct disk_image *self; 199f532d00SPekka Enberg 209f532d00SPekka Enberg self = malloc(sizeof *self); 219f532d00SPekka Enberg if (!self) 229f532d00SPekka Enberg return NULL; 239f532d00SPekka Enberg 24499f3bedSPekka Enberg self->fd = fd; 25499f3bedSPekka Enberg self->size = size; 26499f3bedSPekka Enberg self->ops = ops; 279f532d00SPekka Enberg 289f532d00SPekka Enberg return self; 299f532d00SPekka Enberg } 309f532d00SPekka Enberg 31499f3bedSPekka Enberg static int raw_image__read_sector(struct disk_image *self, uint64_t sector, void *dst, uint32_t dst_len) 329f532d00SPekka Enberg { 339f532d00SPekka Enberg uint64_t offset = sector << SECTOR_SHIFT; 349f532d00SPekka Enberg 355a24a9f2SPekka Enberg if (offset + dst_len > self->size) 369f532d00SPekka Enberg return -1; 379f532d00SPekka Enberg 386b7deb02SPekka Enberg if (pread_in_full(self->fd, dst, dst_len, offset) < 0) 39c4d7847bSPekka Enberg return -1; 409f532d00SPekka Enberg 419f532d00SPekka Enberg return 0; 429f532d00SPekka Enberg } 43258dd093SPekka Enberg 44499f3bedSPekka Enberg static int raw_image__write_sector(struct disk_image *self, uint64_t sector, void *src, uint32_t src_len) 45258dd093SPekka Enberg { 46258dd093SPekka Enberg uint64_t offset = sector << SECTOR_SHIFT; 47258dd093SPekka Enberg 48258dd093SPekka Enberg if (offset + src_len > self->size) 49258dd093SPekka Enberg return -1; 50258dd093SPekka Enberg 516b7deb02SPekka Enberg if (pwrite_in_full(self->fd, src, src_len, offset) < 0) 52c4d7847bSPekka Enberg return -1; 53258dd093SPekka Enberg 54258dd093SPekka Enberg return 0; 55258dd093SPekka Enberg } 56499f3bedSPekka Enberg 57499f3bedSPekka Enberg static struct disk_image_operations raw_image_ops = { 58499f3bedSPekka Enberg .read_sector = raw_image__read_sector, 59499f3bedSPekka Enberg .write_sector = raw_image__write_sector, 60499f3bedSPekka Enberg }; 61499f3bedSPekka Enberg 62499f3bedSPekka Enberg static struct disk_image *raw_image__probe(int fd) 63499f3bedSPekka Enberg { 64499f3bedSPekka Enberg struct stat st; 65499f3bedSPekka Enberg 66499f3bedSPekka Enberg if (fstat(fd, &st) < 0) 67499f3bedSPekka Enberg return NULL; 68499f3bedSPekka Enberg 69499f3bedSPekka Enberg return disk_image__new(fd, st.st_size, &raw_image_ops); 70499f3bedSPekka Enberg } 71499f3bedSPekka Enberg 72499f3bedSPekka Enberg struct disk_image *disk_image__open(const char *filename) 73499f3bedSPekka Enberg { 74499f3bedSPekka Enberg struct disk_image *self; 75499f3bedSPekka Enberg int fd; 76499f3bedSPekka Enberg 77499f3bedSPekka Enberg fd = open(filename, O_RDWR); 78499f3bedSPekka Enberg if (fd < 0) 79499f3bedSPekka Enberg return NULL; 80499f3bedSPekka Enberg 81499f3bedSPekka Enberg self = raw_image__probe(fd); 82499f3bedSPekka Enberg if (self) 83499f3bedSPekka Enberg return self; 84499f3bedSPekka Enberg 85*d6c58e5bSPrasad Joshi if (close(fd) < 0) 86499f3bedSPekka Enberg warning("close() failed"); 87499f3bedSPekka Enberg 88499f3bedSPekka Enberg return NULL; 89499f3bedSPekka Enberg } 90499f3bedSPekka Enberg 91499f3bedSPekka Enberg void disk_image__close(struct disk_image *self) 92499f3bedSPekka Enberg { 9382d94c50SIngo Molnar /* If there was no disk image then there's nothing to do: */ 9482d94c50SIngo Molnar if (!self) 9582d94c50SIngo Molnar return; 9682d94c50SIngo Molnar 97499f3bedSPekka Enberg if (self->ops->close) 98499f3bedSPekka Enberg self->ops->close(self); 99499f3bedSPekka Enberg 100499f3bedSPekka Enberg if (close(self->fd) < 0) 101499f3bedSPekka Enberg warning("close() failed"); 102499f3bedSPekka Enberg 103499f3bedSPekka Enberg free(self); 104499f3bedSPekka Enberg } 105