1 /*-
2 * SPDX-License-Identifier: BSD-2-Clause
3 *
4 * Copyright (c) 2014 Marcel Moolenaar
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26 * SUCH DAMAGE.
27 */
28
29 #include <sys/cdefs.h>
30 #include <sys/errno.h>
31 #include <assert.h>
32 #include <stdio.h>
33 #include <stdlib.h>
34 #include <string.h>
35
36 #include "endian.h"
37 #include "image.h"
38 #include "format.h"
39 #include "mkimg.h"
40
41 /* Default cluster sizes. */
42 #define QCOW1_CLSTR_LOG2SZ 12 /* 4KB */
43 #define QCOW2_CLSTR_LOG2SZ 16 /* 64KB */
44
45 /* Flag bits in cluster offsets */
46 #define QCOW_CLSTR_COMPRESSED (1ULL << 62)
47 #define QCOW_CLSTR_COPIED (1ULL << 63)
48
49 struct qcow_header {
50 uint32_t magic;
51 #define QCOW_MAGIC 0x514649fb
52 uint32_t version;
53 #define QCOW_VERSION_1 1
54 #define QCOW_VERSION_2 2
55 uint64_t path_offset;
56 uint32_t path_length;
57 uint32_t clstr_log2sz; /* v2 only */
58 uint64_t disk_size;
59 union {
60 struct {
61 uint8_t clstr_log2sz;
62 uint8_t l2_log2sz;
63 uint16_t _pad;
64 uint32_t encryption;
65 uint64_t l1_offset;
66 } v1;
67 struct {
68 uint32_t encryption;
69 uint32_t l1_entries;
70 uint64_t l1_offset;
71 uint64_t refcnt_offset;
72 uint32_t refcnt_clstrs;
73 uint32_t snapshot_count;
74 uint64_t snapshot_offset;
75 } v2;
76 } u;
77 };
78
79 static u_int clstr_log2sz;
80
81 static uint64_t
round_clstr(uint64_t ofs)82 round_clstr(uint64_t ofs)
83 {
84 uint64_t clstrsz;
85
86 clstrsz = 1UL << clstr_log2sz;
87 return ((ofs + clstrsz - 1) & ~(clstrsz - 1));
88 }
89
90 static int
qcow_resize(lba_t imgsz,u_int version)91 qcow_resize(lba_t imgsz, u_int version)
92 {
93 uint64_t imagesz;
94
95 switch (version) {
96 case QCOW_VERSION_1:
97 clstr_log2sz = QCOW1_CLSTR_LOG2SZ;
98 break;
99 case QCOW_VERSION_2:
100 clstr_log2sz = QCOW2_CLSTR_LOG2SZ;
101 break;
102 default:
103 assert(0);
104 }
105
106 imagesz = round_clstr(imgsz * secsz);
107
108 if (verbose)
109 fprintf(stderr, "QCOW: image size = %ju, cluster size = %u\n",
110 (uintmax_t)imagesz, (u_int)(1U << clstr_log2sz));
111
112 return (image_set_size(imagesz / secsz));
113 }
114
115 static int
qcow1_resize(lba_t imgsz)116 qcow1_resize(lba_t imgsz)
117 {
118
119 return (qcow_resize(imgsz, QCOW_VERSION_1));
120 }
121
122 static int
qcow2_resize(lba_t imgsz)123 qcow2_resize(lba_t imgsz)
124 {
125
126 return (qcow_resize(imgsz, QCOW_VERSION_2));
127 }
128
129 static int
qcow_write(int fd,u_int version)130 qcow_write(int fd, u_int version)
131 {
132 struct qcow_header *hdr;
133 uint64_t *l1tbl, *l2tbl, *rctbl;
134 uint16_t *rcblk;
135 uint64_t clstr_imgsz, clstr_l2tbls, clstr_l1tblsz;
136 uint64_t clstr_rcblks, clstr_rctblsz;
137 uint64_t n, imagesz, nclstrs, ofs, ofsflags;
138 lba_t blk, blkofs, blk_imgsz;
139 u_int l1clno, l2clno, rcclno;
140 u_int blk_clstrsz, refcnt_clstrs;
141 u_int clstrsz, l1idx, l2idx;
142 int error;
143
144 assert(clstr_log2sz != 0);
145
146 clstrsz = 1U << clstr_log2sz;
147 blk_clstrsz = clstrsz / secsz;
148 blk_imgsz = image_get_size();
149 imagesz = blk_imgsz * secsz;
150 clstr_imgsz = imagesz >> clstr_log2sz;
151 clstr_l2tbls = round_clstr(clstr_imgsz * 8) >> clstr_log2sz;
152 clstr_l1tblsz = round_clstr(clstr_l2tbls * 8) >> clstr_log2sz;
153 nclstrs = clstr_imgsz + clstr_l2tbls + clstr_l1tblsz + 1;
154 clstr_rcblks = clstr_rctblsz = 0;
155 do {
156 n = clstr_rcblks + clstr_rctblsz;
157 clstr_rcblks = round_clstr((nclstrs + n) * 2) >> clstr_log2sz;
158 clstr_rctblsz = round_clstr(clstr_rcblks * 8) >> clstr_log2sz;
159 } while (n < (clstr_rcblks + clstr_rctblsz));
160
161 /*
162 * We got all the sizes in clusters. Start the layout.
163 * 0 - header
164 * 1 - L1 table
165 * 2 - RC table (v2 only)
166 * 3 - L2 tables
167 * 4 - RC block (v2 only)
168 * 5 - data
169 */
170
171 l1clno = 1;
172 rcclno = 0;
173 rctbl = l2tbl = l1tbl = NULL;
174 rcblk = NULL;
175
176 hdr = calloc(1, clstrsz);
177 if (hdr == NULL)
178 return (errno);
179
180 be32enc(&hdr->magic, QCOW_MAGIC);
181 be32enc(&hdr->version, version);
182 be64enc(&hdr->disk_size, imagesz);
183 switch (version) {
184 case QCOW_VERSION_1:
185 ofsflags = 0;
186 l2clno = l1clno + clstr_l1tblsz;
187 hdr->u.v1.clstr_log2sz = clstr_log2sz;
188 hdr->u.v1.l2_log2sz = clstr_log2sz - 3;
189 be64enc(&hdr->u.v1.l1_offset, clstrsz * l1clno);
190 break;
191 case QCOW_VERSION_2:
192 ofsflags = QCOW_CLSTR_COPIED;
193 rcclno = l1clno + clstr_l1tblsz;
194 l2clno = rcclno + clstr_rctblsz;
195 be32enc(&hdr->clstr_log2sz, clstr_log2sz);
196 be32enc(&hdr->u.v2.l1_entries, clstr_l2tbls);
197 be64enc(&hdr->u.v2.l1_offset, clstrsz * l1clno);
198 be64enc(&hdr->u.v2.refcnt_offset, clstrsz * rcclno);
199 refcnt_clstrs = round_clstr(clstr_rcblks * 8) >> clstr_log2sz;
200 be32enc(&hdr->u.v2.refcnt_clstrs, refcnt_clstrs);
201 break;
202 default:
203 assert(0);
204 }
205
206 if (sparse_write(fd, hdr, clstrsz) < 0) {
207 error = errno;
208 goto out;
209 }
210
211 free(hdr);
212 hdr = NULL;
213
214 ofs = clstrsz * l2clno;
215 nclstrs = 1 + clstr_l1tblsz + clstr_rctblsz;
216
217 l1tbl = calloc(clstr_l1tblsz, clstrsz);
218 if (l1tbl == NULL) {
219 error = ENOMEM;
220 goto out;
221 }
222
223 for (n = 0; n < clstr_imgsz; n++) {
224 blk = n * blk_clstrsz;
225 if (image_data(blk, blk_clstrsz)) {
226 nclstrs++;
227 l1idx = n >> (clstr_log2sz - 3);
228 if (l1tbl[l1idx] == 0) {
229 be64enc(l1tbl + l1idx, ofs + ofsflags);
230 ofs += clstrsz;
231 nclstrs++;
232 }
233 }
234 }
235
236 if (sparse_write(fd, l1tbl, clstrsz * clstr_l1tblsz) < 0) {
237 error = errno;
238 goto out;
239 }
240
241 clstr_rcblks = 0;
242 do {
243 n = clstr_rcblks;
244 clstr_rcblks = round_clstr((nclstrs + n) * 2) >> clstr_log2sz;
245 } while (n < clstr_rcblks);
246
247 if (rcclno > 0) {
248 rctbl = calloc(clstr_rctblsz, clstrsz);
249 if (rctbl == NULL) {
250 error = ENOMEM;
251 goto out;
252 }
253 for (n = 0; n < clstr_rcblks; n++) {
254 be64enc(rctbl + n, ofs);
255 ofs += clstrsz;
256 nclstrs++;
257 }
258 if (sparse_write(fd, rctbl, clstrsz * clstr_rctblsz) < 0) {
259 error = errno;
260 goto out;
261 }
262 free(rctbl);
263 rctbl = NULL;
264 }
265
266 l2tbl = malloc(clstrsz);
267 if (l2tbl == NULL) {
268 error = ENOMEM;
269 goto out;
270 }
271
272 for (l1idx = 0; l1idx < clstr_l2tbls; l1idx++) {
273 if (l1tbl[l1idx] == 0)
274 continue;
275 memset(l2tbl, 0, clstrsz);
276 blkofs = (lba_t)l1idx * blk_clstrsz * (clstrsz >> 3);
277 for (l2idx = 0; l2idx < (clstrsz >> 3); l2idx++) {
278 blk = blkofs + (lba_t)l2idx * blk_clstrsz;
279 if (blk >= blk_imgsz)
280 break;
281 if (image_data(blk, blk_clstrsz)) {
282 be64enc(l2tbl + l2idx, ofs + ofsflags);
283 ofs += clstrsz;
284 }
285 }
286 if (sparse_write(fd, l2tbl, clstrsz) < 0) {
287 error = errno;
288 goto out;
289 }
290 }
291
292 free(l2tbl);
293 l2tbl = NULL;
294 free(l1tbl);
295 l1tbl = NULL;
296
297 if (rcclno > 0) {
298 rcblk = calloc(clstr_rcblks, clstrsz);
299 if (rcblk == NULL) {
300 error = ENOMEM;
301 goto out;
302 }
303 for (n = 0; n < nclstrs; n++)
304 be16enc(rcblk + n, 1);
305 if (sparse_write(fd, rcblk, clstrsz * clstr_rcblks) < 0) {
306 error = errno;
307 goto out;
308 }
309 free(rcblk);
310 rcblk = NULL;
311 }
312
313 error = 0;
314 for (n = 0; n < clstr_imgsz; n++) {
315 blk = n * blk_clstrsz;
316 if (image_data(blk, blk_clstrsz)) {
317 error = image_copyout_region(fd, blk, blk_clstrsz);
318 if (error)
319 break;
320 }
321 }
322 if (!error)
323 error = image_copyout_done(fd);
324
325 out:
326 if (rcblk != NULL)
327 free(rcblk);
328 if (l2tbl != NULL)
329 free(l2tbl);
330 if (rctbl != NULL)
331 free(rctbl);
332 if (l1tbl != NULL)
333 free(l1tbl);
334 if (hdr != NULL)
335 free(hdr);
336 return (error);
337 }
338
339 static int
qcow1_write(int fd)340 qcow1_write(int fd)
341 {
342
343 return (qcow_write(fd, QCOW_VERSION_1));
344 }
345
346 static int
qcow2_write(int fd)347 qcow2_write(int fd)
348 {
349
350 return (qcow_write(fd, QCOW_VERSION_2));
351 }
352
353 static struct mkimg_format qcow1_format = {
354 .name = "qcow",
355 .description = "QEMU Copy-On-Write, version 1",
356 .resize = qcow1_resize,
357 .write = qcow1_write,
358 };
359 FORMAT_DEFINE(qcow1_format);
360
361 static struct mkimg_format qcow2_format = {
362 .name = "qcow2",
363 .description = "QEMU Copy-On-Write, version 2",
364 .resize = qcow2_resize,
365 .write = qcow2_write,
366 };
367 FORMAT_DEFINE(qcow2_format);
368