1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
4 This file is part of systemd.
6 Copyright 2015 Lennart Poettering
8 systemd is free software; you can redistribute it and/or modify it
9 under the terms of the GNU Lesser General Public License as published by
10 the Free Software Foundation; either version 2.1 of the License, or
11 (at your option) any later version.
13 systemd is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 Lesser General Public License for more details.
18 You should have received a copy of the GNU Lesser General Public License
19 along with systemd; If not, see <http://www.gnu.org/licenses/>.
25 #include "sparse-endian.h"
26 #include "qcow2-util.h"
28 #define QCOW2_MAGIC 0x514649fb
30 #define QCOW2_COPIED (1ULL << 63)
31 #define QCOW2_COMPRESSED (1ULL << 62)
32 #define QCOW2_ZERO (1ULL << 0)
34 typedef struct _packed_ Header {
38 be64_t backing_file_offset;
39 be32_t backing_file_size;
46 be64_t l1_table_offset;
48 be64_t refcount_table_offset;
49 be32_t refcount_table_clusters;
52 be64_t snapshots_offset;
54 /* The remainder is only present on QCOW3 */
55 be64_t incompatible_features;
56 be64_t compatible_features;
57 be64_t autoclear_features;
59 be32_t refcount_order;
63 #define HEADER_MAGIC(header) be32toh((header)->magic)
64 #define HEADER_VERSION(header) be32toh((header)->version)
65 #define HEADER_CLUSTER_BITS(header) be32toh((header)->cluster_bits)
66 #define HEADER_CLUSTER_SIZE(header) (1ULL << HEADER_CLUSTER_BITS(header))
67 #define HEADER_L2_BITS(header) (HEADER_CLUSTER_BITS(header) - 3)
68 #define HEADER_SIZE(header) be64toh((header)->size)
69 #define HEADER_CRYPT_METHOD(header) be32toh((header)->crypt_method)
70 #define HEADER_L1_SIZE(header) be32toh((header)->l1_size)
71 #define HEADER_L2_SIZE(header) (HEADER_CLUSTER_SIZE(header)/sizeof(uint64_t))
72 #define HEADER_L1_TABLE_OFFSET(header) be64toh((header)->l1_table_offset)
74 static uint32_t HEADER_HEADER_LENGTH(const Header *h) {
75 if (HEADER_VERSION(h) < 3)
76 return offsetof(Header, incompatible_features);
78 return be32toh(h->header_length);
81 static int copy_cluster(
82 int sfd, uint64_t soffset,
83 int dfd, uint64_t doffset,
84 uint64_t cluster_size,
89 l = pread(sfd, buffer, cluster_size, soffset);
92 if ((uint64_t) l != cluster_size)
95 l = pwrite(dfd, buffer, cluster_size, doffset);
98 if ((uint64_t) l != cluster_size)
104 static int decompress_cluster(
105 int sfd, uint64_t soffset,
106 int dfd, uint64_t doffset,
107 uint64_t compressed_size,
108 uint64_t cluster_size,
112 _cleanup_free_ void *large_buffer = NULL;
118 if (compressed_size > cluster_size) {
119 /* The usual cluster buffer doesn't suffice, let's
120 * allocate a larger one, temporarily */
122 large_buffer = malloc(compressed_size);
126 buffer1 = large_buffer;
129 l = pread(sfd, buffer1, compressed_size, soffset);
132 if ((uint64_t) l != compressed_size)
136 s.avail_in = compressed_size;
137 s.next_out = buffer2;
138 s.avail_out = cluster_size;
140 r = inflateInit2(&s, -12);
144 r = inflate(&s, Z_FINISH);
145 sz = (uint8_t*) s.next_out - (uint8_t*) buffer2;
147 if (r != Z_STREAM_END || sz != cluster_size)
150 l = pwrite(dfd, buffer2, cluster_size, doffset);
153 if ((uint64_t) l != cluster_size)
159 static int normalize_offset(
160 const Header *header,
164 uint64_t *compressed_size) {
170 if (q & QCOW2_COMPRESSED) {
171 uint64_t sz, csize_shift, csize_mask;
176 csize_shift = 64 - 2 - (HEADER_CLUSTER_BITS(header) - 8);
177 csize_mask = (1ULL << (HEADER_CLUSTER_BITS(header) - 8)) - 1;
178 sz = (((q >> csize_shift) & csize_mask) + 1) * 512 - (q & 511);
179 q &= ((1ULL << csize_shift) - 1);
182 *compressed_size = sz;
189 *compressed_size = 0;
192 if (q & QCOW2_ZERO) {
193 /* We make no distinction between zero blocks and holes */
202 return q > 0; /* returns positive if not a hole */
205 static int verify_header(const Header *header) {
208 if (HEADER_MAGIC(header) != QCOW2_MAGIC)
211 if (HEADER_VERSION(header) != 2 &&
212 HEADER_VERSION(header) != 3)
215 if (HEADER_CRYPT_METHOD(header) != 0)
218 if (HEADER_CLUSTER_BITS(header) < 9) /* 512K */
221 if (HEADER_CLUSTER_BITS(header) > 21) /* 2MB */
224 if (HEADER_SIZE(header) % HEADER_CLUSTER_SIZE(header) != 0)
227 if (HEADER_L1_SIZE(header) > 32*1024*1024) /* 32MB */
230 if (HEADER_VERSION(header) == 3) {
232 if (header->incompatible_features != 0)
235 if (HEADER_HEADER_LENGTH(header) < sizeof(Header))
242 int qcow2_convert(int qcow2_fd, int raw_fd) {
243 _cleanup_free_ void *buffer1 = NULL, *buffer2 = NULL;
244 _cleanup_free_ be64_t *l1_table = NULL, *l2_table = NULL;
250 l = pread(qcow2_fd, &header, sizeof(header), 0);
253 if (l != sizeof(header))
256 r = verify_header(&header);
260 l1_table = new(be64_t, HEADER_L1_SIZE(&header));
264 l2_table = malloc(HEADER_CLUSTER_SIZE(&header));
268 buffer1 = malloc(HEADER_CLUSTER_SIZE(&header));
272 buffer2 = malloc(HEADER_CLUSTER_SIZE(&header));
276 /* Empty the file if it exists, we rely on zero bits */
277 if (ftruncate(raw_fd, 0) < 0)
280 if (ftruncate(raw_fd, HEADER_SIZE(&header)) < 0)
283 sz = sizeof(uint64_t) * HEADER_L1_SIZE(&header);
284 l = pread(qcow2_fd, l1_table, sz, HEADER_L1_TABLE_OFFSET(&header));
287 if ((uint64_t) l != sz)
290 for (i = 0; i < HEADER_L1_SIZE(&header); i ++) {
291 uint64_t l2_begin, j;
293 r = normalize_offset(&header, l1_table[i], &l2_begin, NULL, NULL);
299 l = pread(qcow2_fd, l2_table, HEADER_CLUSTER_SIZE(&header), l2_begin);
302 if ((uint64_t) l != HEADER_CLUSTER_SIZE(&header))
305 for (j = 0; j < HEADER_L2_SIZE(&header); j++) {
306 uint64_t data_begin, p, compressed_size;
309 p = ((i << HEADER_L2_BITS(&header)) + j) << HEADER_CLUSTER_BITS(&header);
311 r = normalize_offset(&header, l2_table[j], &data_begin, &compressed, &compressed_size);
318 r = decompress_cluster(
319 qcow2_fd, data_begin,
321 compressed_size, HEADER_CLUSTER_SIZE(&header),
325 qcow2_fd, data_begin,
327 HEADER_CLUSTER_SIZE(&header), buffer1);
336 int qcow2_detect(int fd) {
340 l = pread(fd, &id, sizeof(id), 0);
346 return htobe32(QCOW2_MAGIC) == id;