7 #include "tools-util.h"
9 #define QCOW_MAGIC (('Q' << 24) | ('F' << 16) | ('I' << 8) | 0xfb)
10 #define QCOW_VERSION 2
11 #define QCOW_OFLAG_COPIED (1LL << 63)
17 u64 backing_file_offset;
18 u32 backing_file_size;
27 u64 refcount_table_offset;
28 u32 refcount_table_blocks;
44 static void flush_l2(struct qcow2_image *img)
46 if (img->l1_index != -1) {
47 img->l1_table[img->l1_index] =
48 cpu_to_be64(img->offset|QCOW_OFLAG_COPIED);
49 xpwrite(img->fd, img->l2_table, img->block_size, img->offset);
50 img->offset += img->block_size;
52 memset(img->l2_table, 0, img->block_size);
57 static void add_l2(struct qcow2_image *img, u64 src_blk, u64 dst_offset)
59 unsigned l2_size = img->block_size / sizeof(u64);
60 u64 l1_index = src_blk / l2_size;
61 u64 l2_index = src_blk & (l2_size - 1);
63 if (img->l1_index != l1_index) {
65 img->l1_index = l1_index;
68 img->l2_table[l2_index] = cpu_to_be64(dst_offset|QCOW_OFLAG_COPIED);
71 void qcow2_write_image(int infd, int outfd, ranges *data,
74 u64 image_size = get_size(NULL, infd);
75 unsigned l2_size = block_size / sizeof(u64);
76 unsigned l1_size = DIV_ROUND_UP(image_size, (u64) block_size * l2_size);
77 struct qcow2_hdr hdr = { 0 };
78 struct qcow2_image img = {
80 .block_size = block_size,
81 .l2_table = xcalloc(l2_size, sizeof(u64)),
82 .l1_table = xcalloc(l1_size, sizeof(u64)),
84 .offset = round_up(sizeof(hdr), block_size),
87 char *buf = xmalloc(block_size);
88 u64 src_offset, dst_offset;
90 assert(is_power_of_2(block_size));
92 ranges_roundup(data, block_size);
93 ranges_sort_merge(data);
96 darray_foreach(r, *data)
97 for (src_offset = r->start;
99 src_offset += block_size) {
100 dst_offset = img.offset;
101 img.offset += img.block_size;
103 xpread(infd, buf, block_size, src_offset);
104 xpwrite(outfd, buf, block_size, dst_offset);
106 add_l2(&img, src_offset / block_size, dst_offset);
111 /* Write L1 table: */
112 dst_offset = img.offset;
113 img.offset += round_up(l1_size * sizeof(u64), block_size);
114 xpwrite(img.fd, img.l1_table, l1_size * sizeof(u64), dst_offset);
117 hdr.magic = cpu_to_be32(QCOW_MAGIC);
118 hdr.version = cpu_to_be32(QCOW_VERSION);
119 hdr.block_bits = cpu_to_be32(ilog2(block_size));
120 hdr.size = cpu_to_be64(image_size);
121 hdr.l1_size = cpu_to_be32(l1_size);
122 hdr.l1_table_offset = cpu_to_be64(dst_offset);
124 memset(buf, 0, block_size);
125 memcpy(buf, &hdr, sizeof(hdr));
126 xpwrite(img.fd, buf, block_size, 0);