19f532d00SPekka Enberg #include "kvm/disk-image.h" 29f532d00SPekka Enberg 39f532d00SPekka Enberg #include "kvm/util.h" 49f532d00SPekka Enberg 59f532d00SPekka Enberg #include <sys/types.h> 633d33901SPekka Enberg #include <inttypes.h> 79f532d00SPekka Enberg #include <sys/mman.h> 89f532d00SPekka Enberg #include <sys/stat.h> 9*5646450dSPekka Enberg #include <stdbool.h> 109f532d00SPekka Enberg #include <stddef.h> 119f532d00SPekka Enberg #include <stdlib.h> 129f532d00SPekka Enberg #include <unistd.h> 139f532d00SPekka Enberg #include <fcntl.h> 149f532d00SPekka Enberg 159f532d00SPekka Enberg #define SECTOR_SHIFT 9 169f532d00SPekka Enberg #define SECTOR_SIZE (1UL << SECTOR_SHIFT) 179f532d00SPekka Enberg 18*5646450dSPekka Enberg static const char QCOW_MAGIC[] = { 'Q', 'F', 'I', 0xfb }; 19*5646450dSPekka Enberg 20*5646450dSPekka Enberg struct qcow_header { 21*5646450dSPekka Enberg uint8_t magic[5]; 22*5646450dSPekka Enberg }; 23*5646450dSPekka Enberg 24*5646450dSPekka Enberg static bool disk_image__is_qcow(struct disk_image *self) 25*5646450dSPekka Enberg { 26*5646450dSPekka Enberg struct qcow_header *header = self->mmap; 27*5646450dSPekka Enberg 28*5646450dSPekka Enberg return !memcmp(header->magic, QCOW_MAGIC, ARRAY_SIZE(QCOW_MAGIC)); 29*5646450dSPekka Enberg } 30*5646450dSPekka Enberg 319f532d00SPekka Enberg struct disk_image *disk_image__open(const char *filename) 329f532d00SPekka Enberg { 339f532d00SPekka Enberg struct disk_image *self; 349f532d00SPekka Enberg struct stat st; 359f532d00SPekka Enberg 369f532d00SPekka Enberg self = malloc(sizeof *self); 379f532d00SPekka Enberg if (!self) 389f532d00SPekka Enberg return NULL; 399f532d00SPekka Enberg 409f532d00SPekka Enberg self->fd = open(filename, O_RDONLY); 419f532d00SPekka Enberg if (self->fd < 0) 429f532d00SPekka Enberg goto failed_free; 439f532d00SPekka Enberg 449f532d00SPekka Enberg if (fstat(self->fd, &st) < 0) 459f532d00SPekka Enberg goto failed_close_fd; 469f532d00SPekka Enberg 479f532d00SPekka Enberg self->size = st.st_size; 489f532d00SPekka Enberg 499f532d00SPekka Enberg self->mmap = mmap(NULL, self->size, PROT_READ, MAP_PRIVATE, self->fd, 0); 509f532d00SPekka Enberg if (self->mmap == MAP_FAILED) 519f532d00SPekka Enberg goto failed_close_fd; 529f532d00SPekka Enberg 53*5646450dSPekka Enberg if (disk_image__is_qcow(self)) 54*5646450dSPekka Enberg die("QCOW disk image format is not supported."); 55*5646450dSPekka Enberg 569f532d00SPekka Enberg return self; 579f532d00SPekka Enberg 589f532d00SPekka Enberg failed_close_fd: 599f532d00SPekka Enberg close(self->fd); 609f532d00SPekka Enberg failed_free: 619f532d00SPekka Enberg free(self); 629f532d00SPekka Enberg 639f532d00SPekka Enberg return NULL; 649f532d00SPekka Enberg } 659f532d00SPekka Enberg 669f532d00SPekka Enberg void disk_image__close(struct disk_image *self) 679f532d00SPekka Enberg { 689f532d00SPekka Enberg if (munmap(self->mmap, self->size) < 0) 699f532d00SPekka Enberg warning("munmap() failed"); 709f532d00SPekka Enberg 719f532d00SPekka Enberg if (close(self->fd) < 0) 729f532d00SPekka Enberg warning("close() failed"); 739f532d00SPekka Enberg 749f532d00SPekka Enberg free(self); 759f532d00SPekka Enberg } 769f532d00SPekka Enberg 775a24a9f2SPekka Enberg int disk_image__read_sector(struct disk_image *self, uint64_t sector, void *dst, uint32_t dst_len) 789f532d00SPekka Enberg { 799f532d00SPekka Enberg uint64_t offset = sector << SECTOR_SHIFT; 809f532d00SPekka Enberg 815a24a9f2SPekka Enberg if (offset + dst_len > self->size) 829f532d00SPekka Enberg return -1; 839f532d00SPekka Enberg 845a24a9f2SPekka Enberg memcpy(dst, self->mmap + offset, dst_len); 859f532d00SPekka Enberg 869f532d00SPekka Enberg return 0; 879f532d00SPekka Enberg } 88