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