1e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall/*
2e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall * qcow2.c --- Functions to generate qcow2 formatted disk images.  This
3e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall * format is used originally by QEMU for virtual machines, and stores the
4e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall * filesystem data on disk in a packed format to avoid creating sparse
5e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall * image files that need lots of seeking to read and write.
6e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall *
7e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall * The qcow2 format supports zlib compression, but that is not yet
8e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall * implemented.
9e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall *
10e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall * It is possible to directly mount a qcow2 image using qemu-nbd:
11e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall *
12e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall * [root]# modprobe nbd max_part=63
13e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall * [root]# qemu-nbd -c /dev/nbd0 image.img
14e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall * [root]# mount /dev/nbd0p1 /mnt/qemu
15e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall *
16e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall * Format details at http://people.gnome.org/~markmc/qcow-image-format.html
17e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall *
18e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall * Copyright (C) 2010 Red Hat, Inc., Lukas Czerner <lczerner@redhat.com>
19e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall *
20e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall * %Begin-Header%
21e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall * This file may be redistributed under the terms of the GNU Public
22e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall * License.
23e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall * %End-Header%
24e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall */
25e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall
26e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall#define _LARGEFILE_SOURCE
27e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall#define _LARGEFILE64_SOURCE
28e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall
29e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall#include <fcntl.h>
30e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall#include <grp.h>
31e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall#include <pwd.h>
32e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall#include <stdio.h>
33e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall#ifdef HAVE_STDLIB_H
34e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall#include <stdlib.h>
35e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall#endif
36e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall#include <string.h>
37e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall#include <time.h>
38e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall#include <unistd.h>
39e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall#include <fcntl.h>
40e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall#include <errno.h>
41e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall#include <sys/stat.h>
42e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall#include <sys/types.h>
43e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall#include <assert.h>
44e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall
45e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall#include "ext2fs/ext2fs.h"
46e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall#include "qcow2.h"
47e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall
48e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall/* Functions for converting qcow2 image into raw image */
49e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall
50e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrallstruct ext2_qcow2_hdr *qcow2_read_header(int fd)
51e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall{
52e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	void *buffer = NULL;
53e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	struct ext2_qcow2_hdr *hdr = NULL;
54e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	size_t size;
55e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	errcode_t ret;
56e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall
57e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	ret = ext2fs_get_mem(sizeof(struct ext2_qcow2_hdr), &buffer);
58e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	if (ret)
59e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall		return NULL;
60e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	memset(buffer, 0, sizeof(struct ext2_qcow2_hdr));
61e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall
62e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	if (ext2fs_llseek(fd, 0, SEEK_SET < 0)) {
63e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall		ext2fs_free_mem(&buffer);
64e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall		return NULL;
65e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	}
66e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall
67e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	size = read(fd, buffer, sizeof(struct ext2_qcow2_hdr));
68e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	if (size != sizeof(struct ext2_qcow2_hdr)) {
69e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall		ext2fs_free_mem(&buffer);
70e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall		return NULL;
71e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	}
72e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall
73e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	hdr = (struct ext2_qcow2_hdr *)(buffer);
74e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall
75e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	if ((ext2fs_be32_to_cpu(hdr->magic) != QCOW_MAGIC) ||
76e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	    (ext2fs_be32_to_cpu(hdr->version) != 2)) {
77e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall		ext2fs_free_mem(&hdr);
78e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall		return NULL;
79e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	}
80e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall
81e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	return hdr;
82e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall}
83e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall
84e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrallstatic int qcow2_read_l1_table(struct ext2_qcow2_image *img)
85e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall{
86e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	int fd = img->fd;
87e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	size_t size, l1_size = img->l1_size * sizeof(blk64_t);
88e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	blk64_t *table;
89e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	errcode_t ret;
90e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall
91e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	ret = ext2fs_get_memzero(l1_size, &table);
92e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	if (ret)
93e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall		return ret;
94e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall
95e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	if (ext2fs_llseek(fd, img->l1_offset, SEEK_SET) < 0) {
96e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall		ext2fs_free_mem(&table);
97e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall		return errno;
98e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	}
99e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall
100e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	size = read(fd, table, l1_size);
101e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	if (size != l1_size) {
102e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall		ext2fs_free_mem(&table);
103e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall		return errno;
104e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	}
105e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall
106e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	img->l1_table = table;
107e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall
108e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	return 0;
109e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall}
110e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall
111e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrallstatic int qcow2_read_l2_table(struct ext2_qcow2_image *img,
112e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall			       ext2_off64_t offset, blk64_t **l2_table)
113e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall{
114e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	int fd = img->fd;
115e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	size_t size;
116e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall
117e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	assert(*l2_table);
118e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall
119e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	if (ext2fs_llseek(fd, offset, SEEK_SET) < 0)
120e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall		return errno;
121e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall
122e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	size = read(fd, *l2_table, img->cluster_size);
123e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	if (size != img->cluster_size)
124e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall		return errno;
125e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall
126e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	return 0;
127e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall}
128e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall
129e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrallstatic int qcow2_copy_data(int fdin, int fdout, ext2_off64_t off_in,
130e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall			   ext2_off64_t off_out, void *buf, size_t count)
131e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall{
132e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	size_t size;
133e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall
134e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	assert(buf);
135e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall
136e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	if (ext2fs_llseek(fdout, off_out, SEEK_SET) < 0)
137e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall		return errno;
138e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall
139e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	if (ext2fs_llseek(fdin, off_in, SEEK_SET) < 0)
140e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall		return errno;
141e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall
142e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	size = read(fdin, buf, count);
143e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	if (size != count)
144e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall		return errno;
145e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall
146e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	size = write(fdout, buf, count);
147e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	if (size != count)
148e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall		return errno;
149e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall
150e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	return 0;
151e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall}
152e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall
153e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall
154e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrallint qcow2_write_raw_image(int qcow2_fd, int raw_fd,
155e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall			      struct ext2_qcow2_hdr *hdr)
156e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall{
157e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	struct ext2_qcow2_image img;
158e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	errcode_t ret = 0;
159e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	unsigned int l1_index, l2_index;
160e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	ext2_off64_t offset;
161e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	blk64_t *l1_table, *l2_table = NULL;
162e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	void *copy_buf = NULL;
163e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	size_t size;
164e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall
165e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	if (hdr->crypt_method)
166e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall		return -QCOW_ENCRYPTED;
167e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall
168e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	img.fd = qcow2_fd;
169e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	img.hdr = hdr;
170e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	img.l2_cache = NULL;
171e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	img.l1_table = NULL;
172e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	img.cluster_bits = ext2fs_be32_to_cpu(hdr->cluster_bits);
173e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	img.cluster_size = 1 << img.cluster_bits;
174e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	img.l1_size = ext2fs_be32_to_cpu(hdr->l1_size);
175e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	img.l1_offset = ext2fs_be64_to_cpu(hdr->l1_table_offset);
176e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	img.l2_size = 1 << (img.cluster_bits - 3);
177e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	img.image_size = ext2fs_be64_to_cpu(hdr->size);
178e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall
179e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall
180e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	ret = ext2fs_get_memzero(img.cluster_size, &l2_table);
181e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	if (ret)
182e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall		goto out;
183e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall
184e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	ret = ext2fs_get_memzero(1 << img.cluster_bits, &copy_buf);
185e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	if (ret)
186e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall		goto out;
187e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall
188e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	if (ext2fs_llseek(raw_fd, 0, SEEK_SET) < 0) {
189e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall		ret = errno;
190e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall		goto out;
191e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	}
192e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall
193e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	ret = qcow2_read_l1_table(&img);
194e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	if (ret)
195e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall		goto out;
196e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall
197e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	l1_table = img.l1_table;
198e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	/* Walk through l1 table */
199e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	for (l1_index = 0; l1_index < img.l1_size; l1_index++) {
200e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall		ext2_off64_t off_out;
201e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall
202e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall		offset = ext2fs_be64_to_cpu(l1_table[l1_index]) &
203e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall			 ~QCOW_OFLAG_COPIED;
204e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall
205e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall		if ((offset > img.image_size) ||
206e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall		    (offset <= 0))
207e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall			continue;
208e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall
209e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall		if (offset & QCOW_OFLAG_COMPRESSED) {
210e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall			ret = -QCOW_COMPRESSED;
211e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall			goto out;
212e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall		}
213e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall
214e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall		ret = qcow2_read_l2_table(&img, offset, &l2_table);
215e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall		if (ret)
216e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall			break;
217e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall
218e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall		/* Walk through l2 table and copy data blocks into raw image */
219e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall		for (l2_index = 0; l2_index < img.l2_size; l2_index++) {
220e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall			offset = ext2fs_be64_to_cpu(l2_table[l2_index]) &
221e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall				 ~QCOW_OFLAG_COPIED;
222e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall
223e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall			if (offset == 0)
224e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall				continue;
225e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall
226e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall			off_out = (l1_index * img.l2_size) +
227e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall				  l2_index;
228e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall			off_out <<= img.cluster_bits;
229e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall			ret = qcow2_copy_data(qcow2_fd, raw_fd, offset,
230e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall					off_out, copy_buf, img.cluster_size);
231e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall			if (ret)
232e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall				goto out;
233e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall		}
234e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	}
235e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall
236e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	/* Resize the output image to the filesystem size */
237e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	if (ext2fs_llseek(raw_fd, img.image_size - 1, SEEK_SET) < 0)
238e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall		return errno;
239e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall
240e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	((char *)copy_buf)[0] = 0;
241e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	size = write(raw_fd, copy_buf, 1);
242e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	if (size != 1) {
243e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall		ret = errno;
244e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall		goto out;
245e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	}
246e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall
247e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrallout:
248e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	if (copy_buf)
249e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall		ext2fs_free_mem(&copy_buf);
250e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	if (img.l1_table)
251e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall		ext2fs_free_mem(&img.l1_table);
252e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	if (l2_table)
253e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall		ext2fs_free_mem(&l2_table);
254e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	return ret;
255e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall}
256