xref: /kvmtool/disk/core.c (revision 5646450daad830bdcae12377cd75baa48f64b62d)
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