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