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