2 * qcow2.c --- Functions to generate qcow2 formatted disk images. This
3 * format is used originally by QEMU for virtual machines, and stores the
4 * filesystem data on disk in a packed format to avoid creating sparse
5 * image files that need lots of seeking to read and write.
7 * The qcow2 format supports zlib compression, but that is not yet
10 * It is possible to directly mount a qcow2 image using qemu-nbd:
12 * [root]# modprobe nbd max_part=63
13 * [root]# qemu-nbd -c /dev/nbd0 image.img
14 * [root]# mount /dev/nbd0p1 /mnt/qemu
16 * Format details at http://people.gnome.org/~markmc/qcow-image-format.html
18 * Copyright (C) 2010 Red Hat, Inc., Lukas Czerner <lczerner@redhat.com>
21 * This file may be redistributed under the terms of the GNU Public
26 #ifndef _LARGEFILE_SOURCE
27 #define _LARGEFILE_SOURCE
29 #ifndef _LARGEFILE64_SOURCE
30 #define _LARGEFILE64_SOURCE
47 #include <sys/types.h>
50 #include "ext2fs/ext2fs.h"
53 /* Functions for converting qcow2 image into raw image */
55 struct ext2_qcow2_hdr *qcow2_read_header(int fd)
58 struct ext2_qcow2_hdr *hdr = NULL;
62 ret = ext2fs_get_mem(sizeof(struct ext2_qcow2_hdr), &buffer);
65 memset(buffer, 0, sizeof(struct ext2_qcow2_hdr));
67 if (ext2fs_llseek(fd, 0, SEEK_SET < 0)) {
68 ext2fs_free_mem(&buffer);
72 size = read(fd, buffer, sizeof(struct ext2_qcow2_hdr));
73 if (size != sizeof(struct ext2_qcow2_hdr)) {
74 ext2fs_free_mem(&buffer);
78 hdr = (struct ext2_qcow2_hdr *)(buffer);
80 if ((ext2fs_be32_to_cpu(hdr->magic) != QCOW_MAGIC) ||
81 (ext2fs_be32_to_cpu(hdr->version) != 2)) {
82 ext2fs_free_mem(&hdr);
89 static int qcow2_read_l1_table(struct ext2_qcow2_image *img)
92 size_t size, l1_size = img->l1_size * sizeof(blk64_t);
96 ret = ext2fs_get_memzero(l1_size, &table);
100 if (ext2fs_llseek(fd, img->l1_offset, SEEK_SET) < 0) {
101 ext2fs_free_mem(&table);
105 size = read(fd, table, l1_size);
106 if (size != l1_size) {
107 ext2fs_free_mem(&table);
111 img->l1_table = table;
116 static int qcow2_read_l2_table(struct ext2_qcow2_image *img,
117 __u64 offset, blk64_t **l2_table)
124 if (ext2fs_llseek(fd, offset, SEEK_SET) < 0)
127 size = read(fd, *l2_table, img->cluster_size);
128 if (size != img->cluster_size)
134 static int qcow2_copy_data(int fdin, int fdout, __u64 off_in,
135 __u64 off_out, void *buf, size_t count)
143 if (ext2fs_llseek(fdout, off_out, SEEK_SET) < 0)
146 if (ext2fs_llseek(fdin, off_in, SEEK_SET) < 0)
151 c1 = read(fdin, buf, count);
152 if (c1 < 0 || ((c1 == 0) && errno))
157 for (ptr = buf, c = c1; c > 0; ptr += c2, c -= c2) {
159 c2 = write(fdout, ptr, c1);
160 if (c2 < 0 || ((c2 == 0) && errno))
162 if (c2 == 0 && --retries <= 0)
163 break; /* This should never happen... */
171 int qcow2_write_raw_image(int qcow2_fd, int raw_fd,
172 struct ext2_qcow2_hdr *hdr)
174 struct ext2_qcow2_image img;
176 unsigned int l1_index, l2_index;
178 blk64_t *l1_table, *l2_table = NULL;
179 void *copy_buf = NULL;
181 unsigned int max_l1_size;
183 if (hdr->crypt_method)
184 return -QCOW_ENCRYPTED;
190 img.cluster_bits = ext2fs_be32_to_cpu(hdr->cluster_bits);
191 if (img.cluster_bits < 9 || img.cluster_bits > 31)
192 return -QCOW_CORRUPTED;
193 img.cluster_size = 1 << img.cluster_bits;
194 img.l1_size = ext2fs_be32_to_cpu(hdr->l1_size);
195 img.l1_offset = ext2fs_be64_to_cpu(hdr->l1_table_offset);
196 img.l2_size = 1 << (img.cluster_bits - 3);
197 img.image_size = ext2fs_be64_to_cpu(hdr->size);
199 if (img.l1_offset & (img.cluster_size - 1))
200 return -QCOW_CORRUPTED;
202 max_l1_size = (img.image_size >> ((2 * img.cluster_bits) - 3)) +
204 if (img.l1_size > max_l1_size)
205 return -QCOW_CORRUPTED;
207 ret = ext2fs_get_memzero(img.cluster_size, &l2_table);
211 ret = ext2fs_get_memzero(1 << img.cluster_bits, ©_buf);
215 if (ext2fs_llseek(raw_fd, 0, SEEK_SET) < 0) {
220 ret = qcow2_read_l1_table(&img);
224 l1_table = img.l1_table;
225 /* Walk through l1 table */
226 for (l1_index = 0; l1_index < img.l1_size; l1_index++) {
229 offset = ext2fs_be64_to_cpu(l1_table[l1_index]) &
232 if ((offset > img.image_size) ||
236 if (offset & QCOW_OFLAG_COMPRESSED) {
237 ret = -QCOW_COMPRESSED;
241 ret = qcow2_read_l2_table(&img, offset, &l2_table);
245 /* Walk through l2 table and copy data blocks into raw image */
246 for (l2_index = 0; l2_index < img.l2_size; l2_index++) {
247 offset = ext2fs_be64_to_cpu(l2_table[l2_index]) &
253 off_out = ((__u64)l1_index * img.l2_size) +
255 off_out <<= img.cluster_bits;
256 ret = qcow2_copy_data(qcow2_fd, raw_fd, offset,
257 off_out, copy_buf, img.cluster_size);
263 /* Resize the output image to the filesystem size */
264 if (ext2fs_llseek(raw_fd, img.image_size - 1, SEEK_SET) < 0) {
269 ((char *)copy_buf)[0] = 0;
270 size = write(raw_fd, copy_buf, 1);
278 ext2fs_free_mem(©_buf);
280 ext2fs_free_mem(&img.l1_table);
282 ext2fs_free_mem(&l2_table);