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 16*499f3bedSPekka 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 24*499f3bedSPekka Enberg self->fd = fd; 25*499f3bedSPekka Enberg self->size = size; 26*499f3bedSPekka Enberg self->ops = ops; 279f532d00SPekka Enberg 289f532d00SPekka Enberg return self; 299f532d00SPekka Enberg } 309f532d00SPekka Enberg 31*499f3bedSPekka 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 38c4d7847bSPekka Enberg if (lseek(self->fd, offset, SEEK_SET) < 0) 39c4d7847bSPekka Enberg return -1; 40c4d7847bSPekka Enberg 41c4d7847bSPekka Enberg if (read_in_full(self->fd, dst, dst_len) < 0) 42c4d7847bSPekka Enberg return -1; 439f532d00SPekka Enberg 449f532d00SPekka Enberg return 0; 459f532d00SPekka Enberg } 46258dd093SPekka Enberg 47*499f3bedSPekka Enberg static int raw_image__write_sector(struct disk_image *self, uint64_t sector, void *src, uint32_t src_len) 48258dd093SPekka Enberg { 49258dd093SPekka Enberg uint64_t offset = sector << SECTOR_SHIFT; 50258dd093SPekka Enberg 51258dd093SPekka Enberg if (offset + src_len > self->size) 52258dd093SPekka Enberg return -1; 53258dd093SPekka Enberg 54c4d7847bSPekka Enberg if (lseek(self->fd, offset, SEEK_SET) < 0) 55c4d7847bSPekka Enberg return -1; 56c4d7847bSPekka Enberg 57c4d7847bSPekka Enberg if (write_in_full(self->fd, src, src_len) < 0) 58c4d7847bSPekka Enberg return -1; 59258dd093SPekka Enberg 60258dd093SPekka Enberg return 0; 61258dd093SPekka Enberg } 62*499f3bedSPekka Enberg 63*499f3bedSPekka Enberg static struct disk_image_operations raw_image_ops = { 64*499f3bedSPekka Enberg .read_sector = raw_image__read_sector, 65*499f3bedSPekka Enberg .write_sector = raw_image__write_sector, 66*499f3bedSPekka Enberg }; 67*499f3bedSPekka Enberg 68*499f3bedSPekka Enberg static struct disk_image *raw_image__probe(int fd) 69*499f3bedSPekka Enberg { 70*499f3bedSPekka Enberg struct stat st; 71*499f3bedSPekka Enberg 72*499f3bedSPekka Enberg if (fstat(fd, &st) < 0) 73*499f3bedSPekka Enberg return NULL; 74*499f3bedSPekka Enberg 75*499f3bedSPekka Enberg return disk_image__new(fd, st.st_size, &raw_image_ops); 76*499f3bedSPekka Enberg } 77*499f3bedSPekka Enberg 78*499f3bedSPekka Enberg struct disk_image *disk_image__open(const char *filename) 79*499f3bedSPekka Enberg { 80*499f3bedSPekka Enberg struct disk_image *self; 81*499f3bedSPekka Enberg int fd; 82*499f3bedSPekka Enberg 83*499f3bedSPekka Enberg fd = open(filename, O_RDWR); 84*499f3bedSPekka Enberg if (fd < 0) 85*499f3bedSPekka Enberg return NULL; 86*499f3bedSPekka Enberg 87*499f3bedSPekka Enberg self = raw_image__probe(fd); 88*499f3bedSPekka Enberg if (self) 89*499f3bedSPekka Enberg return self; 90*499f3bedSPekka Enberg 91*499f3bedSPekka Enberg if (close(self->fd) < 0) 92*499f3bedSPekka Enberg warning("close() failed"); 93*499f3bedSPekka Enberg 94*499f3bedSPekka Enberg return NULL; 95*499f3bedSPekka Enberg } 96*499f3bedSPekka Enberg 97*499f3bedSPekka Enberg void disk_image__close(struct disk_image *self) 98*499f3bedSPekka Enberg { 99*499f3bedSPekka Enberg if (self->ops->close) 100*499f3bedSPekka Enberg self->ops->close(self); 101*499f3bedSPekka Enberg 102*499f3bedSPekka Enberg if (close(self->fd) < 0) 103*499f3bedSPekka Enberg warning("close() failed"); 104*499f3bedSPekka Enberg 105*499f3bedSPekka Enberg free(self); 106*499f3bedSPekka Enberg } 107