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, ©_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(©_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