xref: /freebsd-src/usr.bin/mkimg/qcow.c (revision 1d386b48a555f61cb7325543adbbb5c3f3407a66)
138501a46SMarcel Moolenaar /*-
238501a46SMarcel Moolenaar  * Copyright (c) 2014 Marcel Moolenaar
338501a46SMarcel Moolenaar  * All rights reserved.
438501a46SMarcel Moolenaar  *
538501a46SMarcel Moolenaar  * Redistribution and use in source and binary forms, with or without
638501a46SMarcel Moolenaar  * modification, are permitted provided that the following conditions
738501a46SMarcel Moolenaar  * are met:
838501a46SMarcel Moolenaar  * 1. Redistributions of source code must retain the above copyright
938501a46SMarcel Moolenaar  *    notice, this list of conditions and the following disclaimer.
1038501a46SMarcel Moolenaar  * 2. Redistributions in binary form must reproduce the above copyright
1138501a46SMarcel Moolenaar  *    notice, this list of conditions and the following disclaimer in the
1238501a46SMarcel Moolenaar  *    documentation and/or other materials provided with the distribution.
1338501a46SMarcel Moolenaar  *
1438501a46SMarcel Moolenaar  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
1538501a46SMarcel Moolenaar  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1638501a46SMarcel Moolenaar  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
1738501a46SMarcel Moolenaar  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
1838501a46SMarcel Moolenaar  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
1938501a46SMarcel Moolenaar  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2038501a46SMarcel Moolenaar  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2138501a46SMarcel Moolenaar  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2238501a46SMarcel Moolenaar  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2338501a46SMarcel Moolenaar  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2438501a46SMarcel Moolenaar  * SUCH DAMAGE.
2538501a46SMarcel Moolenaar  */
2638501a46SMarcel Moolenaar 
2738501a46SMarcel Moolenaar #include <sys/cdefs.h>
2838501a46SMarcel Moolenaar #include <sys/errno.h>
294039ea7cSMarcel Moolenaar #include <assert.h>
3038501a46SMarcel Moolenaar #include <stdio.h>
3138501a46SMarcel Moolenaar #include <stdlib.h>
3238501a46SMarcel Moolenaar #include <string.h>
3338501a46SMarcel Moolenaar 
345aad7d9aSMarcel Moolenaar #include "endian.h"
3538501a46SMarcel Moolenaar #include "image.h"
3638501a46SMarcel Moolenaar #include "format.h"
3738501a46SMarcel Moolenaar #include "mkimg.h"
3838501a46SMarcel Moolenaar 
3938501a46SMarcel Moolenaar /* Default cluster sizes. */
4038501a46SMarcel Moolenaar #define	QCOW1_CLSTR_LOG2SZ	12	/* 4KB */
4138501a46SMarcel Moolenaar #define	QCOW2_CLSTR_LOG2SZ	16	/* 64KB */
4238501a46SMarcel Moolenaar 
430e651cfeSMarcel Moolenaar /* Flag bits in cluster offsets */
440e651cfeSMarcel Moolenaar #define	QCOW_CLSTR_COMPRESSED	(1ULL << 62)
450e651cfeSMarcel Moolenaar #define	QCOW_CLSTR_COPIED	(1ULL << 63)
460e651cfeSMarcel Moolenaar 
4738501a46SMarcel Moolenaar struct qcow_header {
4838501a46SMarcel Moolenaar 	uint32_t	magic;
4938501a46SMarcel Moolenaar #define	QCOW_MAGIC		0x514649fb
5038501a46SMarcel Moolenaar 	uint32_t	version;
5138501a46SMarcel Moolenaar #define	QCOW_VERSION_1		1
5238501a46SMarcel Moolenaar #define	QCOW_VERSION_2		2
5338501a46SMarcel Moolenaar 	uint64_t	path_offset;
5438501a46SMarcel Moolenaar 	uint32_t	path_length;
5538501a46SMarcel Moolenaar 	uint32_t	clstr_log2sz;	/* v2 only */
5638501a46SMarcel Moolenaar 	uint64_t	disk_size;
5738501a46SMarcel Moolenaar 	union {
5838501a46SMarcel Moolenaar 		struct {
5938501a46SMarcel Moolenaar 			uint8_t		clstr_log2sz;
6038501a46SMarcel Moolenaar 			uint8_t		l2_log2sz;
6138501a46SMarcel Moolenaar 			uint16_t	_pad;
6238501a46SMarcel Moolenaar 			uint32_t	encryption;
6338501a46SMarcel Moolenaar 			uint64_t	l1_offset;
6438501a46SMarcel Moolenaar 		} v1;
6538501a46SMarcel Moolenaar 		struct {
6638501a46SMarcel Moolenaar 			uint32_t	encryption;
6738501a46SMarcel Moolenaar 			uint32_t	l1_entries;
6838501a46SMarcel Moolenaar 			uint64_t	l1_offset;
6938501a46SMarcel Moolenaar 			uint64_t	refcnt_offset;
700f49f146SMarcel Moolenaar 			uint32_t	refcnt_clstrs;
7138501a46SMarcel Moolenaar 			uint32_t	snapshot_count;
7238501a46SMarcel Moolenaar 			uint64_t	snapshot_offset;
7338501a46SMarcel Moolenaar 		} v2;
7438501a46SMarcel Moolenaar 	} u;
7538501a46SMarcel Moolenaar };
7638501a46SMarcel Moolenaar 
7738501a46SMarcel Moolenaar static u_int clstr_log2sz;
7838501a46SMarcel Moolenaar 
7938501a46SMarcel Moolenaar static uint64_t
round_clstr(uint64_t ofs)8038501a46SMarcel Moolenaar round_clstr(uint64_t ofs)
8138501a46SMarcel Moolenaar {
8238501a46SMarcel Moolenaar 	uint64_t clstrsz;
8338501a46SMarcel Moolenaar 
8438501a46SMarcel Moolenaar 	clstrsz = 1UL << clstr_log2sz;
8538501a46SMarcel Moolenaar 	return ((ofs + clstrsz - 1) & ~(clstrsz - 1));
8638501a46SMarcel Moolenaar }
8738501a46SMarcel Moolenaar 
8838501a46SMarcel Moolenaar static int
qcow_resize(lba_t imgsz,u_int version)8938501a46SMarcel Moolenaar qcow_resize(lba_t imgsz, u_int version)
9038501a46SMarcel Moolenaar {
910e651cfeSMarcel Moolenaar 	uint64_t imagesz;
9238501a46SMarcel Moolenaar 
9338501a46SMarcel Moolenaar 	switch (version) {
9438501a46SMarcel Moolenaar 	case QCOW_VERSION_1:
9538501a46SMarcel Moolenaar 		clstr_log2sz = QCOW1_CLSTR_LOG2SZ;
9638501a46SMarcel Moolenaar 		break;
9738501a46SMarcel Moolenaar 	case QCOW_VERSION_2:
9838501a46SMarcel Moolenaar 		clstr_log2sz = QCOW2_CLSTR_LOG2SZ;
9938501a46SMarcel Moolenaar 		break;
10038501a46SMarcel Moolenaar 	default:
1014039ea7cSMarcel Moolenaar 		assert(0);
10238501a46SMarcel Moolenaar 	}
10338501a46SMarcel Moolenaar 
10438501a46SMarcel Moolenaar 	imagesz = round_clstr(imgsz * secsz);
10538501a46SMarcel Moolenaar 
10638501a46SMarcel Moolenaar 	if (verbose)
1070e651cfeSMarcel Moolenaar 		fprintf(stderr, "QCOW: image size = %ju, cluster size = %u\n",
1080e651cfeSMarcel Moolenaar 		    (uintmax_t)imagesz, (u_int)(1U << clstr_log2sz));
10938501a46SMarcel Moolenaar 
11038501a46SMarcel Moolenaar 	return (image_set_size(imagesz / secsz));
11138501a46SMarcel Moolenaar }
11238501a46SMarcel Moolenaar 
11338501a46SMarcel Moolenaar static int
qcow1_resize(lba_t imgsz)11438501a46SMarcel Moolenaar qcow1_resize(lba_t imgsz)
11538501a46SMarcel Moolenaar {
11638501a46SMarcel Moolenaar 
11738501a46SMarcel Moolenaar 	return (qcow_resize(imgsz, QCOW_VERSION_1));
11838501a46SMarcel Moolenaar }
11938501a46SMarcel Moolenaar 
12038501a46SMarcel Moolenaar static int
qcow2_resize(lba_t imgsz)12138501a46SMarcel Moolenaar qcow2_resize(lba_t imgsz)
12238501a46SMarcel Moolenaar {
12338501a46SMarcel Moolenaar 
12438501a46SMarcel Moolenaar 	return (qcow_resize(imgsz, QCOW_VERSION_2));
12538501a46SMarcel Moolenaar }
12638501a46SMarcel Moolenaar 
12738501a46SMarcel Moolenaar static int
qcow_write(int fd,u_int version)12838501a46SMarcel Moolenaar qcow_write(int fd, u_int version)
12938501a46SMarcel Moolenaar {
13038501a46SMarcel Moolenaar 	struct qcow_header *hdr;
131e1870642SMarcel Moolenaar 	uint64_t *l1tbl, *l2tbl, *rctbl;
132e1870642SMarcel Moolenaar 	uint16_t *rcblk;
1330e651cfeSMarcel Moolenaar 	uint64_t clstr_imgsz, clstr_l2tbls, clstr_l1tblsz;
1340e651cfeSMarcel Moolenaar 	uint64_t clstr_rcblks, clstr_rctblsz;
1350e651cfeSMarcel Moolenaar 	uint64_t n, imagesz, nclstrs, ofs, ofsflags;
1360e651cfeSMarcel Moolenaar 	lba_t blk, blkofs, blk_imgsz;
1370e651cfeSMarcel Moolenaar 	u_int l1clno, l2clno, rcclno;
1380f49f146SMarcel Moolenaar 	u_int blk_clstrsz, refcnt_clstrs;
1390e651cfeSMarcel Moolenaar 	u_int clstrsz, l1idx, l2idx;
14038501a46SMarcel Moolenaar 	int error;
14138501a46SMarcel Moolenaar 
1424039ea7cSMarcel Moolenaar 	assert(clstr_log2sz != 0);
14338501a46SMarcel Moolenaar 
1440e651cfeSMarcel Moolenaar 	clstrsz = 1U << clstr_log2sz;
1450e651cfeSMarcel Moolenaar 	blk_clstrsz = clstrsz / secsz;
1460e651cfeSMarcel Moolenaar 	blk_imgsz = image_get_size();
1470e651cfeSMarcel Moolenaar 	imagesz = blk_imgsz * secsz;
1480e651cfeSMarcel Moolenaar 	clstr_imgsz = imagesz >> clstr_log2sz;
1490e651cfeSMarcel Moolenaar 	clstr_l2tbls = round_clstr(clstr_imgsz * 8) >> clstr_log2sz;
1500e651cfeSMarcel Moolenaar 	clstr_l1tblsz = round_clstr(clstr_l2tbls * 8) >> clstr_log2sz;
1510e651cfeSMarcel Moolenaar 	nclstrs = clstr_imgsz + clstr_l2tbls + clstr_l1tblsz + 1;
1520e651cfeSMarcel Moolenaar 	clstr_rcblks = clstr_rctblsz = 0;
1530e651cfeSMarcel Moolenaar 	do {
1540e651cfeSMarcel Moolenaar 		n = clstr_rcblks + clstr_rctblsz;
1550e651cfeSMarcel Moolenaar 		clstr_rcblks = round_clstr((nclstrs + n) * 2) >> clstr_log2sz;
1560e651cfeSMarcel Moolenaar 		clstr_rctblsz = round_clstr(clstr_rcblks * 8) >> clstr_log2sz;
1570e651cfeSMarcel Moolenaar 	} while (n < (clstr_rcblks + clstr_rctblsz));
15838501a46SMarcel Moolenaar 
1590e651cfeSMarcel Moolenaar 	/*
1600e651cfeSMarcel Moolenaar 	 * We got all the sizes in clusters. Start the layout.
1610e651cfeSMarcel Moolenaar 	 * 0 - header
1620e651cfeSMarcel Moolenaar 	 * 1 - L1 table
1630e651cfeSMarcel Moolenaar 	 * 2 - RC table (v2 only)
164e1870642SMarcel Moolenaar 	 * 3 - L2 tables
165e1870642SMarcel Moolenaar 	 * 4 - RC block (v2 only)
166e1870642SMarcel Moolenaar 	 * 5 - data
1670e651cfeSMarcel Moolenaar 	 */
1680e651cfeSMarcel Moolenaar 
1690e651cfeSMarcel Moolenaar 	l1clno = 1;
1700e651cfeSMarcel Moolenaar 	rcclno = 0;
171e1870642SMarcel Moolenaar 	rctbl = l2tbl = l1tbl = NULL;
172e1870642SMarcel Moolenaar 	rcblk = NULL;
17338501a46SMarcel Moolenaar 
17438501a46SMarcel Moolenaar 	hdr = calloc(1, clstrsz);
17538501a46SMarcel Moolenaar 	if (hdr == NULL)
17638501a46SMarcel Moolenaar 		return (errno);
17738501a46SMarcel Moolenaar 
17838501a46SMarcel Moolenaar 	be32enc(&hdr->magic, QCOW_MAGIC);
17938501a46SMarcel Moolenaar 	be32enc(&hdr->version, version);
18038501a46SMarcel Moolenaar 	be64enc(&hdr->disk_size, imagesz);
18138501a46SMarcel Moolenaar 	switch (version) {
18238501a46SMarcel Moolenaar 	case QCOW_VERSION_1:
1830e651cfeSMarcel Moolenaar 		ofsflags = 0;
1840e651cfeSMarcel Moolenaar 		l2clno = l1clno + clstr_l1tblsz;
18538501a46SMarcel Moolenaar 		hdr->u.v1.clstr_log2sz = clstr_log2sz;
18638501a46SMarcel Moolenaar 		hdr->u.v1.l2_log2sz = clstr_log2sz - 3;
1870e651cfeSMarcel Moolenaar 		be64enc(&hdr->u.v1.l1_offset, clstrsz * l1clno);
18838501a46SMarcel Moolenaar 		break;
18938501a46SMarcel Moolenaar 	case QCOW_VERSION_2:
1900e651cfeSMarcel Moolenaar 		ofsflags = QCOW_CLSTR_COPIED;
1910e651cfeSMarcel Moolenaar 		rcclno = l1clno + clstr_l1tblsz;
192e1870642SMarcel Moolenaar 		l2clno = rcclno + clstr_rctblsz;
19338501a46SMarcel Moolenaar 		be32enc(&hdr->clstr_log2sz, clstr_log2sz);
1940e651cfeSMarcel Moolenaar 		be32enc(&hdr->u.v2.l1_entries, clstr_l2tbls);
1950e651cfeSMarcel Moolenaar 		be64enc(&hdr->u.v2.l1_offset, clstrsz * l1clno);
1960e651cfeSMarcel Moolenaar 		be64enc(&hdr->u.v2.refcnt_offset, clstrsz * rcclno);
1970f49f146SMarcel Moolenaar 		refcnt_clstrs = round_clstr(clstr_rcblks * 8) >> clstr_log2sz;
1980f49f146SMarcel Moolenaar 		be32enc(&hdr->u.v2.refcnt_clstrs, refcnt_clstrs);
19938501a46SMarcel Moolenaar 		break;
20038501a46SMarcel Moolenaar 	default:
2014039ea7cSMarcel Moolenaar 		assert(0);
20238501a46SMarcel Moolenaar 	}
20338501a46SMarcel Moolenaar 
204e1870642SMarcel Moolenaar 	if (sparse_write(fd, hdr, clstrsz) < 0) {
205e1870642SMarcel Moolenaar 		error = errno;
206e1870642SMarcel Moolenaar 		goto out;
207e1870642SMarcel Moolenaar 	}
208e1870642SMarcel Moolenaar 
209e1870642SMarcel Moolenaar 	free(hdr);
210e1870642SMarcel Moolenaar 	hdr = NULL;
211e1870642SMarcel Moolenaar 
212e1870642SMarcel Moolenaar 	ofs = clstrsz * l2clno;
213e1870642SMarcel Moolenaar 	nclstrs = 1 + clstr_l1tblsz + clstr_rctblsz;
21438501a46SMarcel Moolenaar 
215*6613eaa4SPedro F. Giffuni 	l1tbl = calloc(clstr_l1tblsz, clstrsz);
21638501a46SMarcel Moolenaar 	if (l1tbl == NULL) {
21738501a46SMarcel Moolenaar 		error = ENOMEM;
21838501a46SMarcel Moolenaar 		goto out;
21938501a46SMarcel Moolenaar 	}
220e1870642SMarcel Moolenaar 
221e1870642SMarcel Moolenaar 	for (n = 0; n < clstr_imgsz; n++) {
222e1870642SMarcel Moolenaar 		blk = n * blk_clstrsz;
223e1870642SMarcel Moolenaar 		if (image_data(blk, blk_clstrsz)) {
224e1870642SMarcel Moolenaar 			nclstrs++;
225e1870642SMarcel Moolenaar 			l1idx = n >> (clstr_log2sz - 3);
226e1870642SMarcel Moolenaar 			if (l1tbl[l1idx] == 0) {
227e1870642SMarcel Moolenaar 				be64enc(l1tbl + l1idx, ofs + ofsflags);
228e1870642SMarcel Moolenaar 				ofs += clstrsz;
229e1870642SMarcel Moolenaar 				nclstrs++;
230e1870642SMarcel Moolenaar 			}
231e1870642SMarcel Moolenaar 		}
232e1870642SMarcel Moolenaar 	}
233e1870642SMarcel Moolenaar 
234e1870642SMarcel Moolenaar 	if (sparse_write(fd, l1tbl, clstrsz * clstr_l1tblsz) < 0) {
235e1870642SMarcel Moolenaar 		error = errno;
236e1870642SMarcel Moolenaar 		goto out;
237e1870642SMarcel Moolenaar 	}
238e1870642SMarcel Moolenaar 
239e1870642SMarcel Moolenaar 	clstr_rcblks = 0;
240e1870642SMarcel Moolenaar 	do {
241e1870642SMarcel Moolenaar 		n = clstr_rcblks;
242e1870642SMarcel Moolenaar 		clstr_rcblks = round_clstr((nclstrs + n) * 2) >> clstr_log2sz;
243e1870642SMarcel Moolenaar 	} while (n < clstr_rcblks);
244e1870642SMarcel Moolenaar 
2450e651cfeSMarcel Moolenaar 	if (rcclno > 0) {
246*6613eaa4SPedro F. Giffuni 		rctbl = calloc(clstr_rctblsz, clstrsz);
24738501a46SMarcel Moolenaar 		if (rctbl == NULL) {
24838501a46SMarcel Moolenaar 			error = ENOMEM;
24938501a46SMarcel Moolenaar 			goto out;
25038501a46SMarcel Moolenaar 		}
251e1870642SMarcel Moolenaar 		for (n = 0; n < clstr_rcblks; n++) {
252e1870642SMarcel Moolenaar 			be64enc(rctbl + n, ofs);
25338501a46SMarcel Moolenaar 			ofs += clstrsz;
254e1870642SMarcel Moolenaar 			nclstrs++;
25538501a46SMarcel Moolenaar 		}
256e1870642SMarcel Moolenaar 		if (sparse_write(fd, rctbl, clstrsz * clstr_rctblsz) < 0) {
25738501a46SMarcel Moolenaar 			error = errno;
25838501a46SMarcel Moolenaar 			goto out;
259e1870642SMarcel Moolenaar 		}
26038501a46SMarcel Moolenaar 		free(rctbl);
26138501a46SMarcel Moolenaar 		rctbl = NULL;
26238501a46SMarcel Moolenaar 	}
26338501a46SMarcel Moolenaar 
26438501a46SMarcel Moolenaar 	l2tbl = malloc(clstrsz);
26538501a46SMarcel Moolenaar 	if (l2tbl == NULL) {
26638501a46SMarcel Moolenaar 		error = ENOMEM;
26738501a46SMarcel Moolenaar 		goto out;
26838501a46SMarcel Moolenaar 	}
26938501a46SMarcel Moolenaar 
2700e651cfeSMarcel Moolenaar 	for (l1idx = 0; l1idx < clstr_l2tbls; l1idx++) {
27138501a46SMarcel Moolenaar 		if (l1tbl[l1idx] == 0)
27238501a46SMarcel Moolenaar 			continue;
27338501a46SMarcel Moolenaar 		memset(l2tbl, 0, clstrsz);
2740e651cfeSMarcel Moolenaar 		blkofs = (lba_t)l1idx * blk_clstrsz * (clstrsz >> 3);
27538501a46SMarcel Moolenaar 		for (l2idx = 0; l2idx < (clstrsz >> 3); l2idx++) {
2760e651cfeSMarcel Moolenaar 			blk = blkofs + (lba_t)l2idx * blk_clstrsz;
2770e651cfeSMarcel Moolenaar 			if (blk >= blk_imgsz)
27838501a46SMarcel Moolenaar 				break;
2790e651cfeSMarcel Moolenaar 			if (image_data(blk, blk_clstrsz)) {
2800e651cfeSMarcel Moolenaar 				be64enc(l2tbl + l2idx, ofs + ofsflags);
28138501a46SMarcel Moolenaar 				ofs += clstrsz;
28238501a46SMarcel Moolenaar 			}
28338501a46SMarcel Moolenaar 		}
28438501a46SMarcel Moolenaar 		if (sparse_write(fd, l2tbl, clstrsz) < 0) {
28538501a46SMarcel Moolenaar 			error = errno;
28638501a46SMarcel Moolenaar 			goto out;
28738501a46SMarcel Moolenaar 		}
28838501a46SMarcel Moolenaar 	}
28938501a46SMarcel Moolenaar 
29038501a46SMarcel Moolenaar 	free(l2tbl);
29138501a46SMarcel Moolenaar 	l2tbl = NULL;
29238501a46SMarcel Moolenaar 	free(l1tbl);
29338501a46SMarcel Moolenaar 	l1tbl = NULL;
29438501a46SMarcel Moolenaar 
295e1870642SMarcel Moolenaar 	if (rcclno > 0) {
296*6613eaa4SPedro F. Giffuni 		rcblk = calloc(clstr_rcblks, clstrsz);
297e1870642SMarcel Moolenaar 		if (rcblk == NULL) {
298e1870642SMarcel Moolenaar 			error = ENOMEM;
299e1870642SMarcel Moolenaar 			goto out;
300e1870642SMarcel Moolenaar 		}
301e1870642SMarcel Moolenaar 		for (n = 0; n < nclstrs; n++)
302e1870642SMarcel Moolenaar 			be16enc(rcblk + n, 1);
303e1870642SMarcel Moolenaar 		if (sparse_write(fd, rcblk, clstrsz * clstr_rcblks) < 0) {
304e1870642SMarcel Moolenaar 			error = errno;
305e1870642SMarcel Moolenaar 			goto out;
306e1870642SMarcel Moolenaar 		}
307e1870642SMarcel Moolenaar 		free(rcblk);
308e1870642SMarcel Moolenaar 		rcblk = NULL;
309e1870642SMarcel Moolenaar 	}
310e1870642SMarcel Moolenaar 
31138501a46SMarcel Moolenaar 	error = 0;
3120e651cfeSMarcel Moolenaar 	for (n = 0; n < clstr_imgsz; n++) {
3130e651cfeSMarcel Moolenaar 		blk = n * blk_clstrsz;
3140e651cfeSMarcel Moolenaar 		if (image_data(blk, blk_clstrsz)) {
3150e651cfeSMarcel Moolenaar 			error = image_copyout_region(fd, blk, blk_clstrsz);
31638501a46SMarcel Moolenaar 			if (error)
31738501a46SMarcel Moolenaar 				break;
31838501a46SMarcel Moolenaar 		}
31938501a46SMarcel Moolenaar 	}
32038501a46SMarcel Moolenaar 	if (!error)
32138501a46SMarcel Moolenaar 		error = image_copyout_done(fd);
32238501a46SMarcel Moolenaar 
32338501a46SMarcel Moolenaar  out:
324e1870642SMarcel Moolenaar 	if (rcblk != NULL)
325e1870642SMarcel Moolenaar 		free(rcblk);
32638501a46SMarcel Moolenaar 	if (l2tbl != NULL)
32738501a46SMarcel Moolenaar 		free(l2tbl);
32838501a46SMarcel Moolenaar 	if (rctbl != NULL)
32938501a46SMarcel Moolenaar 		free(rctbl);
33038501a46SMarcel Moolenaar 	if (l1tbl != NULL)
33138501a46SMarcel Moolenaar 		free(l1tbl);
33238501a46SMarcel Moolenaar 	if (hdr != NULL)
33338501a46SMarcel Moolenaar 		free(hdr);
33438501a46SMarcel Moolenaar 	return (error);
33538501a46SMarcel Moolenaar }
33638501a46SMarcel Moolenaar 
33738501a46SMarcel Moolenaar static int
qcow1_write(int fd)33838501a46SMarcel Moolenaar qcow1_write(int fd)
33938501a46SMarcel Moolenaar {
34038501a46SMarcel Moolenaar 
34138501a46SMarcel Moolenaar 	return (qcow_write(fd, QCOW_VERSION_1));
34238501a46SMarcel Moolenaar }
34338501a46SMarcel Moolenaar 
34438501a46SMarcel Moolenaar static int
qcow2_write(int fd)34538501a46SMarcel Moolenaar qcow2_write(int fd)
34638501a46SMarcel Moolenaar {
34738501a46SMarcel Moolenaar 
34838501a46SMarcel Moolenaar 	return (qcow_write(fd, QCOW_VERSION_2));
34938501a46SMarcel Moolenaar }
35038501a46SMarcel Moolenaar 
35138501a46SMarcel Moolenaar static struct mkimg_format qcow1_format = {
35238501a46SMarcel Moolenaar 	.name = "qcow",
35338501a46SMarcel Moolenaar 	.description = "QEMU Copy-On-Write, version 1",
35438501a46SMarcel Moolenaar 	.resize = qcow1_resize,
35538501a46SMarcel Moolenaar 	.write = qcow1_write,
35638501a46SMarcel Moolenaar };
35738501a46SMarcel Moolenaar FORMAT_DEFINE(qcow1_format);
35838501a46SMarcel Moolenaar 
35938501a46SMarcel Moolenaar static struct mkimg_format qcow2_format = {
36038501a46SMarcel Moolenaar 	.name = "qcow2",
36138501a46SMarcel Moolenaar 	.description = "QEMU Copy-On-Write, version 2",
36238501a46SMarcel Moolenaar 	.resize = qcow2_resize,
36338501a46SMarcel Moolenaar 	.write = qcow2_write,
36438501a46SMarcel Moolenaar };
36538501a46SMarcel Moolenaar FORMAT_DEFINE(qcow2_format);
366