xref: /kvmtool/disk/core.c (revision ca7c891bfee4076bdc4d973120af7e6b5ea5a000)
19f532d00SPekka Enberg #include "kvm/disk-image.h"
29f532d00SPekka Enberg 
39f532d00SPekka Enberg #include "kvm/util.h"
49f532d00SPekka Enberg 
59f532d00SPekka Enberg #include <sys/types.h>
69f532d00SPekka Enberg #include <sys/mman.h>
79f532d00SPekka Enberg #include <sys/stat.h>
89f532d00SPekka Enberg #include <stddef.h>
99f532d00SPekka Enberg #include <stdlib.h>
109f532d00SPekka Enberg #include <unistd.h>
119f532d00SPekka Enberg #include <fcntl.h>
129f532d00SPekka Enberg 
139f532d00SPekka Enberg #define SECTOR_SHIFT		9
149f532d00SPekka Enberg #define SECTOR_SIZE		(1UL << SECTOR_SHIFT)
159f532d00SPekka Enberg 
169f532d00SPekka Enberg struct disk_image *disk_image__open(const char *filename)
179f532d00SPekka Enberg {
189f532d00SPekka Enberg 	struct disk_image *self;
199f532d00SPekka Enberg 	struct stat st;
20*ca7c891bSCyrill Gorcunov 	int cylinders, heads, sectors;
219f532d00SPekka Enberg 
229f532d00SPekka Enberg 	self		= malloc(sizeof *self);
239f532d00SPekka Enberg 	if (!self)
249f532d00SPekka Enberg 		return NULL;
259f532d00SPekka Enberg 
269f532d00SPekka Enberg 	self->fd	= open(filename, O_RDONLY);
279f532d00SPekka Enberg 	if (self->fd < 0)
289f532d00SPekka Enberg 		goto failed_free;
299f532d00SPekka Enberg 
309f532d00SPekka Enberg 	if (fstat(self->fd, &st) < 0)
319f532d00SPekka Enberg 		goto failed_close_fd;
329f532d00SPekka Enberg 
339f532d00SPekka Enberg 	self->size	= st.st_size;
349f532d00SPekka Enberg 
359f532d00SPekka Enberg 	self->mmap	= mmap(NULL, self->size, PROT_READ, MAP_PRIVATE, self->fd, 0);
369f532d00SPekka Enberg 	if (self->mmap == MAP_FAILED)
379f532d00SPekka Enberg 		goto failed_close_fd;
389f532d00SPekka Enberg 
39*ca7c891bSCyrill Gorcunov 	/*
40*ca7c891bSCyrill Gorcunov 	 * set the standart disk geometry of the image
41*ca7c891bSCyrill Gorcunov 	 *
42*ca7c891bSCyrill Gorcunov 	 * real disk example
43*ca7c891bSCyrill Gorcunov 	 * Disk /dev/sda: 500.1 GB, 500107862016 bytes
44*ca7c891bSCyrill Gorcunov 	 * 255 heads, 63 sectors/track, 60801 cylinders, total 976773168 sectors
45*ca7c891bSCyrill Gorcunov 	 */
46*ca7c891bSCyrill Gorcunov 	cylinders = (self->size >> SECTOR_SHIFT) / 16383;
47*ca7c891bSCyrill Gorcunov 	if (cylinders > 16383)
48*ca7c891bSCyrill Gorcunov 		cylinders = 16383;
49*ca7c891bSCyrill Gorcunov 	else if (cylinders < 2)
50*ca7c891bSCyrill Gorcunov 		cylinders = 2;
51*ca7c891bSCyrill Gorcunov 	heads = (self->size >> SECTOR_SHIFT) / cylinders;
52*ca7c891bSCyrill Gorcunov 	if (heads > 255)
53*ca7c891bSCyrill Gorcunov 		heads = 255;
54*ca7c891bSCyrill Gorcunov 	else if (heads < 1)
55*ca7c891bSCyrill Gorcunov 		heads = 1;
56*ca7c891bSCyrill Gorcunov 	sectors = (self->size >> SECTOR_SHIFT) / cylinders / heads;
57*ca7c891bSCyrill Gorcunov 	if (sectors > 255)
58*ca7c891bSCyrill Gorcunov 		sectors = 255;
59*ca7c891bSCyrill Gorcunov 	else if (sectors < 1)
60*ca7c891bSCyrill Gorcunov 		sectors = 1;
61*ca7c891bSCyrill Gorcunov 
62*ca7c891bSCyrill Gorcunov 	self->sectors	= sectors;
63*ca7c891bSCyrill Gorcunov 	self->heads	= heads;
64*ca7c891bSCyrill Gorcunov 	self->cylinders	= cylinders;
65*ca7c891bSCyrill Gorcunov 
66*ca7c891bSCyrill Gorcunov 	info("block image geometry: sectors: %d heads: %d cylinders: %d",
67*ca7c891bSCyrill Gorcunov 		sectors, heads, cylinders);
68*ca7c891bSCyrill Gorcunov 
699f532d00SPekka Enberg 	return self;
709f532d00SPekka Enberg 
719f532d00SPekka Enberg failed_close_fd:
729f532d00SPekka Enberg 	close(self->fd);
739f532d00SPekka Enberg failed_free:
749f532d00SPekka Enberg 	free(self);
759f532d00SPekka Enberg 
769f532d00SPekka Enberg 	return NULL;
779f532d00SPekka Enberg }
789f532d00SPekka Enberg 
799f532d00SPekka Enberg void disk_image__close(struct disk_image *self)
809f532d00SPekka Enberg {
819f532d00SPekka Enberg 	if (munmap(self->mmap, self->size) < 0)
829f532d00SPekka Enberg 		warning("munmap() failed");
839f532d00SPekka Enberg 
849f532d00SPekka Enberg 	if (close(self->fd) < 0)
859f532d00SPekka Enberg 		warning("close() failed");
869f532d00SPekka Enberg 
879f532d00SPekka Enberg 	free(self);
889f532d00SPekka Enberg }
899f532d00SPekka Enberg 
905a24a9f2SPekka Enberg int disk_image__read_sector(struct disk_image *self, uint64_t sector, void *dst, uint32_t dst_len)
919f532d00SPekka Enberg {
929f532d00SPekka Enberg 	uint64_t offset = sector << SECTOR_SHIFT;
939f532d00SPekka Enberg 
945a24a9f2SPekka Enberg 	if (offset + dst_len > self->size)
959f532d00SPekka Enberg 		return -1;
969f532d00SPekka Enberg 
975a24a9f2SPekka Enberg 	memcpy(dst, self->mmap + offset, dst_len);
989f532d00SPekka Enberg 
999f532d00SPekka Enberg 	return 0;
1009f532d00SPekka Enberg }
101