1271965Smarcel/*- 2271965Smarcel * Copyright (c) 2014 Marcel Moolenaar 3271965Smarcel * All rights reserved. 4271965Smarcel * 5271965Smarcel * Redistribution and use in source and binary forms, with or without 6271965Smarcel * modification, are permitted provided that the following conditions 7271965Smarcel * are met: 8271965Smarcel * 1. Redistributions of source code must retain the above copyright 9271965Smarcel * notice, this list of conditions and the following disclaimer. 10271965Smarcel * 2. Redistributions in binary form must reproduce the above copyright 11271965Smarcel * notice, this list of conditions and the following disclaimer in the 12271965Smarcel * documentation and/or other materials provided with the distribution. 13271965Smarcel * 14271965Smarcel * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15271965Smarcel * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16271965Smarcel * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17271965Smarcel * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18271965Smarcel * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19271965Smarcel * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20271965Smarcel * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21271965Smarcel * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22271965Smarcel * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23271965Smarcel * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24271965Smarcel * SUCH DAMAGE. 25271965Smarcel */ 26271965Smarcel 27271965Smarcel#include <sys/cdefs.h> 28271965Smarcel__FBSDID("$FreeBSD: stable/10/usr.bin/mkimg/qcow.c 315600 2017-03-20 00:55:24Z pfg $"); 29271965Smarcel 30271965Smarcel#include <sys/types.h> 31271965Smarcel#include <sys/endian.h> 32271965Smarcel#include <sys/errno.h> 33271965Smarcel#include <stdint.h> 34271965Smarcel#include <stdio.h> 35271965Smarcel#include <stdlib.h> 36271965Smarcel#include <string.h> 37271965Smarcel#include <unistd.h> 38271965Smarcel 39271965Smarcel#include "image.h" 40271965Smarcel#include "format.h" 41271965Smarcel#include "mkimg.h" 42271965Smarcel 43271965Smarcel/* Default cluster sizes. */ 44271965Smarcel#define QCOW1_CLSTR_LOG2SZ 12 /* 4KB */ 45271965Smarcel#define QCOW2_CLSTR_LOG2SZ 16 /* 64KB */ 46271965Smarcel 47272773Smarcel/* Flag bits in cluster offsets */ 48272773Smarcel#define QCOW_CLSTR_COMPRESSED (1ULL << 62) 49272773Smarcel#define QCOW_CLSTR_COPIED (1ULL << 63) 50272773Smarcel 51271965Smarcelstruct qcow_header { 52271965Smarcel uint32_t magic; 53271965Smarcel#define QCOW_MAGIC 0x514649fb 54271965Smarcel uint32_t version; 55271965Smarcel#define QCOW_VERSION_1 1 56271965Smarcel#define QCOW_VERSION_2 2 57271965Smarcel uint64_t path_offset; 58271965Smarcel uint32_t path_length; 59271965Smarcel uint32_t clstr_log2sz; /* v2 only */ 60271965Smarcel uint64_t disk_size; 61271965Smarcel union { 62271965Smarcel struct { 63271965Smarcel uint8_t clstr_log2sz; 64271965Smarcel uint8_t l2_log2sz; 65271965Smarcel uint16_t _pad; 66271965Smarcel uint32_t encryption; 67271965Smarcel uint64_t l1_offset; 68271965Smarcel } v1; 69271965Smarcel struct { 70271965Smarcel uint32_t encryption; 71271965Smarcel uint32_t l1_entries; 72271965Smarcel uint64_t l1_offset; 73271965Smarcel uint64_t refcnt_offset; 74276337Smarcel uint32_t refcnt_clstrs; 75271965Smarcel uint32_t snapshot_count; 76271965Smarcel uint64_t snapshot_offset; 77271965Smarcel } v2; 78271965Smarcel } u; 79271965Smarcel}; 80271965Smarcel 81271965Smarcelstatic u_int clstr_log2sz; 82271965Smarcel 83271965Smarcelstatic uint64_t 84271965Smarcelround_clstr(uint64_t ofs) 85271965Smarcel{ 86271965Smarcel uint64_t clstrsz; 87271965Smarcel 88271965Smarcel clstrsz = 1UL << clstr_log2sz; 89271965Smarcel return ((ofs + clstrsz - 1) & ~(clstrsz - 1)); 90271965Smarcel} 91271965Smarcel 92271965Smarcelstatic int 93271965Smarcelqcow_resize(lba_t imgsz, u_int version) 94271965Smarcel{ 95272773Smarcel uint64_t imagesz; 96271965Smarcel 97271965Smarcel switch (version) { 98271965Smarcel case QCOW_VERSION_1: 99271965Smarcel clstr_log2sz = QCOW1_CLSTR_LOG2SZ; 100271965Smarcel break; 101271965Smarcel case QCOW_VERSION_2: 102271965Smarcel clstr_log2sz = QCOW2_CLSTR_LOG2SZ; 103271965Smarcel break; 104271965Smarcel default: 105271965Smarcel return (EDOOFUS); 106271965Smarcel } 107271965Smarcel 108271965Smarcel imagesz = round_clstr(imgsz * secsz); 109271965Smarcel 110271965Smarcel if (verbose) 111272773Smarcel fprintf(stderr, "QCOW: image size = %ju, cluster size = %u\n", 112272773Smarcel (uintmax_t)imagesz, (u_int)(1U << clstr_log2sz)); 113271965Smarcel 114271965Smarcel return (image_set_size(imagesz / secsz)); 115271965Smarcel} 116271965Smarcel 117271965Smarcelstatic int 118271965Smarcelqcow1_resize(lba_t imgsz) 119271965Smarcel{ 120271965Smarcel 121271965Smarcel return (qcow_resize(imgsz, QCOW_VERSION_1)); 122271965Smarcel} 123271965Smarcel 124271965Smarcelstatic int 125271965Smarcelqcow2_resize(lba_t imgsz) 126271965Smarcel{ 127271965Smarcel 128271965Smarcel return (qcow_resize(imgsz, QCOW_VERSION_2)); 129271965Smarcel} 130271965Smarcel 131271965Smarcelstatic int 132271965Smarcelqcow_write(int fd, u_int version) 133271965Smarcel{ 134271965Smarcel struct qcow_header *hdr; 135272773Smarcel uint64_t *l1tbl, *l2tbl, *rctbl; 136272773Smarcel uint16_t *rcblk; 137272773Smarcel uint64_t clstr_imgsz, clstr_l2tbls, clstr_l1tblsz; 138272773Smarcel uint64_t clstr_rcblks, clstr_rctblsz; 139272773Smarcel uint64_t n, imagesz, nclstrs, ofs, ofsflags; 140272773Smarcel lba_t blk, blkofs, blk_imgsz; 141272773Smarcel u_int l1clno, l2clno, rcclno; 142276337Smarcel u_int blk_clstrsz, refcnt_clstrs; 143272773Smarcel u_int clstrsz, l1idx, l2idx; 144271965Smarcel int error; 145271965Smarcel 146271965Smarcel if (clstr_log2sz == 0) 147271965Smarcel return (EDOOFUS); 148271965Smarcel 149272773Smarcel clstrsz = 1U << clstr_log2sz; 150272773Smarcel blk_clstrsz = clstrsz / secsz; 151272773Smarcel blk_imgsz = image_get_size(); 152272773Smarcel imagesz = blk_imgsz * secsz; 153272773Smarcel clstr_imgsz = imagesz >> clstr_log2sz; 154272773Smarcel clstr_l2tbls = round_clstr(clstr_imgsz * 8) >> clstr_log2sz; 155272773Smarcel clstr_l1tblsz = round_clstr(clstr_l2tbls * 8) >> clstr_log2sz; 156272773Smarcel nclstrs = clstr_imgsz + clstr_l2tbls + clstr_l1tblsz + 1; 157272773Smarcel clstr_rcblks = clstr_rctblsz = 0; 158272773Smarcel do { 159272773Smarcel n = clstr_rcblks + clstr_rctblsz; 160272773Smarcel clstr_rcblks = round_clstr((nclstrs + n) * 2) >> clstr_log2sz; 161272773Smarcel clstr_rctblsz = round_clstr(clstr_rcblks * 8) >> clstr_log2sz; 162272773Smarcel } while (n < (clstr_rcblks + clstr_rctblsz)); 163271965Smarcel 164272773Smarcel /* 165272773Smarcel * We got all the sizes in clusters. Start the layout. 166272773Smarcel * 0 - header 167272773Smarcel * 1 - L1 table 168272773Smarcel * 2 - RC table (v2 only) 169272773Smarcel * 3 - L2 tables 170272773Smarcel * 4 - RC block (v2 only) 171272773Smarcel * 5 - data 172272773Smarcel */ 173271965Smarcel 174272773Smarcel l1clno = 1; 175272773Smarcel rcclno = 0; 176272773Smarcel rctbl = l2tbl = l1tbl = NULL; 177272773Smarcel rcblk = NULL; 178272773Smarcel 179271965Smarcel hdr = calloc(1, clstrsz); 180271965Smarcel if (hdr == NULL) 181271965Smarcel return (errno); 182271965Smarcel 183271965Smarcel be32enc(&hdr->magic, QCOW_MAGIC); 184271965Smarcel be32enc(&hdr->version, version); 185271965Smarcel be64enc(&hdr->disk_size, imagesz); 186271965Smarcel switch (version) { 187271965Smarcel case QCOW_VERSION_1: 188272773Smarcel ofsflags = 0; 189272773Smarcel l2clno = l1clno + clstr_l1tblsz; 190271965Smarcel hdr->u.v1.clstr_log2sz = clstr_log2sz; 191271965Smarcel hdr->u.v1.l2_log2sz = clstr_log2sz - 3; 192272773Smarcel be64enc(&hdr->u.v1.l1_offset, clstrsz * l1clno); 193271965Smarcel break; 194271965Smarcel case QCOW_VERSION_2: 195272773Smarcel ofsflags = QCOW_CLSTR_COPIED; 196272773Smarcel rcclno = l1clno + clstr_l1tblsz; 197272773Smarcel l2clno = rcclno + clstr_rctblsz; 198271965Smarcel be32enc(&hdr->clstr_log2sz, clstr_log2sz); 199272773Smarcel be32enc(&hdr->u.v2.l1_entries, clstr_l2tbls); 200272773Smarcel be64enc(&hdr->u.v2.l1_offset, clstrsz * l1clno); 201272773Smarcel be64enc(&hdr->u.v2.refcnt_offset, clstrsz * rcclno); 202276337Smarcel refcnt_clstrs = round_clstr(clstr_rcblks * 8) >> clstr_log2sz; 203276337Smarcel be32enc(&hdr->u.v2.refcnt_clstrs, refcnt_clstrs); 204271965Smarcel break; 205271965Smarcel default: 206271965Smarcel return (EDOOFUS); 207271965Smarcel } 208271965Smarcel 209272773Smarcel if (sparse_write(fd, hdr, clstrsz) < 0) { 210276337Smarcel error = errno; 211272773Smarcel goto out; 212272773Smarcel } 213271965Smarcel 214272773Smarcel free(hdr); 215272773Smarcel hdr = NULL; 216272773Smarcel 217272773Smarcel ofs = clstrsz * l2clno; 218272773Smarcel nclstrs = 1 + clstr_l1tblsz + clstr_rctblsz; 219272773Smarcel 220315600Spfg l1tbl = calloc(clstr_l1tblsz, clstrsz); 221271965Smarcel if (l1tbl == NULL) { 222271965Smarcel error = ENOMEM; 223271965Smarcel goto out; 224271965Smarcel } 225271965Smarcel 226272773Smarcel for (n = 0; n < clstr_imgsz; n++) { 227272773Smarcel blk = n * blk_clstrsz; 228272773Smarcel if (image_data(blk, blk_clstrsz)) { 229272773Smarcel nclstrs++; 230272773Smarcel l1idx = n >> (clstr_log2sz - 3); 231272773Smarcel if (l1tbl[l1idx] == 0) { 232272773Smarcel be64enc(l1tbl + l1idx, ofs + ofsflags); 233272773Smarcel ofs += clstrsz; 234272773Smarcel nclstrs++; 235272773Smarcel } 236271965Smarcel } 237271965Smarcel } 238271965Smarcel 239272773Smarcel if (sparse_write(fd, l1tbl, clstrsz * clstr_l1tblsz) < 0) { 240271965Smarcel error = errno; 241271965Smarcel goto out; 242272773Smarcel } 243271965Smarcel 244272773Smarcel clstr_rcblks = 0; 245272773Smarcel do { 246272773Smarcel n = clstr_rcblks; 247272773Smarcel clstr_rcblks = round_clstr((nclstrs + n) * 2) >> clstr_log2sz; 248272773Smarcel } while (n < clstr_rcblks); 249272773Smarcel 250272773Smarcel if (rcclno > 0) { 251315600Spfg rctbl = calloc(clstr_rctblsz, clstrsz); 252272773Smarcel if (rctbl == NULL) { 253272773Smarcel error = ENOMEM; 254272773Smarcel goto out; 255272773Smarcel } 256272773Smarcel for (n = 0; n < clstr_rcblks; n++) { 257272773Smarcel be64enc(rctbl + n, ofs); 258272773Smarcel ofs += clstrsz; 259272773Smarcel nclstrs++; 260272773Smarcel } 261272773Smarcel if (sparse_write(fd, rctbl, clstrsz * clstr_rctblsz) < 0) { 262272773Smarcel error = errno; 263272773Smarcel goto out; 264272773Smarcel } 265271965Smarcel free(rctbl); 266271965Smarcel rctbl = NULL; 267271965Smarcel } 268271965Smarcel 269271965Smarcel l2tbl = malloc(clstrsz); 270271965Smarcel if (l2tbl == NULL) { 271271965Smarcel error = ENOMEM; 272271965Smarcel goto out; 273271965Smarcel } 274271965Smarcel 275272773Smarcel for (l1idx = 0; l1idx < clstr_l2tbls; l1idx++) { 276271965Smarcel if (l1tbl[l1idx] == 0) 277271965Smarcel continue; 278271965Smarcel memset(l2tbl, 0, clstrsz); 279272773Smarcel blkofs = (lba_t)l1idx * blk_clstrsz * (clstrsz >> 3); 280271965Smarcel for (l2idx = 0; l2idx < (clstrsz >> 3); l2idx++) { 281272773Smarcel blk = blkofs + (lba_t)l2idx * blk_clstrsz; 282272773Smarcel if (blk >= blk_imgsz) 283271965Smarcel break; 284272773Smarcel if (image_data(blk, blk_clstrsz)) { 285272773Smarcel be64enc(l2tbl + l2idx, ofs + ofsflags); 286271965Smarcel ofs += clstrsz; 287271965Smarcel } 288271965Smarcel } 289271965Smarcel if (sparse_write(fd, l2tbl, clstrsz) < 0) { 290271965Smarcel error = errno; 291271965Smarcel goto out; 292271965Smarcel } 293271965Smarcel } 294271965Smarcel 295271965Smarcel free(l2tbl); 296271965Smarcel l2tbl = NULL; 297271965Smarcel free(l1tbl); 298271965Smarcel l1tbl = NULL; 299271965Smarcel 300272773Smarcel if (rcclno > 0) { 301315600Spfg rcblk = calloc(clstr_rcblks, clstrsz); 302272773Smarcel if (rcblk == NULL) { 303272773Smarcel error = ENOMEM; 304272773Smarcel goto out; 305272773Smarcel } 306272773Smarcel for (n = 0; n < nclstrs; n++) 307272773Smarcel be16enc(rcblk + n, 1); 308272773Smarcel if (sparse_write(fd, rcblk, clstrsz * clstr_rcblks) < 0) { 309272773Smarcel error = errno; 310272773Smarcel goto out; 311272773Smarcel } 312272773Smarcel free(rcblk); 313272773Smarcel rcblk = NULL; 314272773Smarcel } 315272773Smarcel 316271965Smarcel error = 0; 317272773Smarcel for (n = 0; n < clstr_imgsz; n++) { 318272773Smarcel blk = n * blk_clstrsz; 319272773Smarcel if (image_data(blk, blk_clstrsz)) { 320272773Smarcel error = image_copyout_region(fd, blk, blk_clstrsz); 321271965Smarcel if (error) 322271965Smarcel break; 323271965Smarcel } 324271965Smarcel } 325271965Smarcel if (!error) 326271965Smarcel error = image_copyout_done(fd); 327271965Smarcel 328271965Smarcel out: 329272773Smarcel if (rcblk != NULL) 330272773Smarcel free(rcblk); 331271965Smarcel if (l2tbl != NULL) 332271965Smarcel free(l2tbl); 333271965Smarcel if (rctbl != NULL) 334271965Smarcel free(rctbl); 335271965Smarcel if (l1tbl != NULL) 336271965Smarcel free(l1tbl); 337271965Smarcel if (hdr != NULL) 338271965Smarcel free(hdr); 339271965Smarcel return (error); 340271965Smarcel} 341271965Smarcel 342271965Smarcelstatic int 343271965Smarcelqcow1_write(int fd) 344271965Smarcel{ 345271965Smarcel 346271965Smarcel return (qcow_write(fd, QCOW_VERSION_1)); 347271965Smarcel} 348271965Smarcel 349271965Smarcelstatic int 350271965Smarcelqcow2_write(int fd) 351271965Smarcel{ 352271965Smarcel 353271965Smarcel return (qcow_write(fd, QCOW_VERSION_2)); 354271965Smarcel} 355271965Smarcel 356271965Smarcelstatic struct mkimg_format qcow1_format = { 357271965Smarcel .name = "qcow", 358271965Smarcel .description = "QEMU Copy-On-Write, version 1", 359271965Smarcel .resize = qcow1_resize, 360271965Smarcel .write = qcow1_write, 361271965Smarcel}; 362271965SmarcelFORMAT_DEFINE(qcow1_format); 363271965Smarcel 364271965Smarcelstatic struct mkimg_format qcow2_format = { 365271965Smarcel .name = "qcow2", 366271965Smarcel .description = "QEMU Copy-On-Write, version 2", 367271965Smarcel .resize = qcow2_resize, 368271965Smarcel .write = qcow2_write, 369271965Smarcel}; 370271965SmarcelFORMAT_DEFINE(qcow2_format); 371