]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/import/qcow2-util.c
util-lib: split out allocation calls into alloc-util.[ch]
[thirdparty/systemd.git] / src / import / qcow2-util.c
CommitLineData
edce2aed
LP
1/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
2
3/***
4 This file is part of systemd.
5
6 Copyright 2015 Lennart Poettering
7
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.
12
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.
17
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/>.
20***/
21
22#include <zlib.h>
23
b5efdb8a 24#include "alloc-util.h"
1c7dd825 25#include "btrfs-util.h"
b5efdb8a
LP
26#include "qcow2-util.h"
27#include "sparse-endian.h"
28#include "util.h"
edce2aed
LP
29
30#define QCOW2_MAGIC 0x514649fb
31
32#define QCOW2_COPIED (1ULL << 63)
33#define QCOW2_COMPRESSED (1ULL << 62)
34#define QCOW2_ZERO (1ULL << 0)
35
36typedef struct _packed_ Header {
37 be32_t magic;
38 be32_t version;
39
40 be64_t backing_file_offset;
41 be32_t backing_file_size;
42
43 be32_t cluster_bits;
44 be64_t size;
45 be32_t crypt_method;
46
47 be32_t l1_size;
48 be64_t l1_table_offset;
49
50 be64_t refcount_table_offset;
51 be32_t refcount_table_clusters;
52
53 be32_t nb_snapshots;
54 be64_t snapshots_offset;
55
56 /* The remainder is only present on QCOW3 */
57 be64_t incompatible_features;
58 be64_t compatible_features;
59 be64_t autoclear_features;
60
61 be32_t refcount_order;
62 be32_t header_length;
63} Header;
64
65#define HEADER_MAGIC(header) be32toh((header)->magic)
66#define HEADER_VERSION(header) be32toh((header)->version)
67#define HEADER_CLUSTER_BITS(header) be32toh((header)->cluster_bits)
68#define HEADER_CLUSTER_SIZE(header) (1ULL << HEADER_CLUSTER_BITS(header))
69#define HEADER_L2_BITS(header) (HEADER_CLUSTER_BITS(header) - 3)
70#define HEADER_SIZE(header) be64toh((header)->size)
71#define HEADER_CRYPT_METHOD(header) be32toh((header)->crypt_method)
72#define HEADER_L1_SIZE(header) be32toh((header)->l1_size)
73#define HEADER_L2_SIZE(header) (HEADER_CLUSTER_SIZE(header)/sizeof(uint64_t))
74#define HEADER_L1_TABLE_OFFSET(header) be64toh((header)->l1_table_offset)
75
76static uint32_t HEADER_HEADER_LENGTH(const Header *h) {
77 if (HEADER_VERSION(h) < 3)
78 return offsetof(Header, incompatible_features);
79
80 return be32toh(h->header_length);
81}
82
83static int copy_cluster(
84 int sfd, uint64_t soffset,
85 int dfd, uint64_t doffset,
86 uint64_t cluster_size,
87 void *buffer) {
88
89 ssize_t l;
1c7dd825
LP
90 int r;
91
92 r = btrfs_clone_range(sfd, soffset, dfd, doffset, cluster_size);
93 if (r >= 0)
94 return r;
edce2aed
LP
95
96 l = pread(sfd, buffer, cluster_size, soffset);
97 if (l < 0)
98 return -errno;
99 if ((uint64_t) l != cluster_size)
100 return -EIO;
101
102 l = pwrite(dfd, buffer, cluster_size, doffset);
103 if (l < 0)
104 return -errno;
105 if ((uint64_t) l != cluster_size)
106 return -EIO;
107
108 return 0;
109}
110
111static int decompress_cluster(
112 int sfd, uint64_t soffset,
113 int dfd, uint64_t doffset,
114 uint64_t compressed_size,
115 uint64_t cluster_size,
116 void *buffer1,
117 void *buffer2) {
118
119 _cleanup_free_ void *large_buffer = NULL;
120 z_stream s = {};
121 uint64_t sz;
122 ssize_t l;
123 int r;
124
125 if (compressed_size > cluster_size) {
126 /* The usual cluster buffer doesn't suffice, let's
127 * allocate a larger one, temporarily */
128
129 large_buffer = malloc(compressed_size);
130 if (!large_buffer)
131 return -ENOMEM;
132
133 buffer1 = large_buffer;
134 }
135
136 l = pread(sfd, buffer1, compressed_size, soffset);
137 if (l < 0)
138 return -errno;
139 if ((uint64_t) l != compressed_size)
140 return -EIO;
141
142 s.next_in = buffer1;
143 s.avail_in = compressed_size;
144 s.next_out = buffer2;
145 s.avail_out = cluster_size;
146
147 r = inflateInit2(&s, -12);
148 if (r != Z_OK)
149 return -EIO;
150
151 r = inflate(&s, Z_FINISH);
152 sz = (uint8_t*) s.next_out - (uint8_t*) buffer2;
153 inflateEnd(&s);
154 if (r != Z_STREAM_END || sz != cluster_size)
155 return -EIO;
156
157 l = pwrite(dfd, buffer2, cluster_size, doffset);
158 if (l < 0)
159 return -errno;
160 if ((uint64_t) l != cluster_size)
161 return -EIO;
162
163 return 0;
164}
165
166static int normalize_offset(
167 const Header *header,
168 uint64_t p,
169 uint64_t *ret,
170 bool *compressed,
171 uint64_t *compressed_size) {
172
173 uint64_t q;
174
175 q = be64toh(p);
176
177 if (q & QCOW2_COMPRESSED) {
178 uint64_t sz, csize_shift, csize_mask;
179
180 if (!compressed)
15411c0c 181 return -EOPNOTSUPP;
edce2aed
LP
182
183 csize_shift = 64 - 2 - (HEADER_CLUSTER_BITS(header) - 8);
184 csize_mask = (1ULL << (HEADER_CLUSTER_BITS(header) - 8)) - 1;
185 sz = (((q >> csize_shift) & csize_mask) + 1) * 512 - (q & 511);
186 q &= ((1ULL << csize_shift) - 1);
187
188 if (compressed_size)
189 *compressed_size = sz;
190
191 *compressed = true;
192
193 } else {
194 if (compressed) {
195 *compressed = false;
196 *compressed_size = 0;
197 }
198
199 if (q & QCOW2_ZERO) {
200 /* We make no distinction between zero blocks and holes */
201 *ret = 0;
202 return 0;
203 }
204
205 q &= ~QCOW2_COPIED;
206 }
207
208 *ret = q;
209 return q > 0; /* returns positive if not a hole */
210}
211
212static int verify_header(const Header *header) {
213 assert(header);
214
215 if (HEADER_MAGIC(header) != QCOW2_MAGIC)
216 return -EBADMSG;
217
218 if (HEADER_VERSION(header) != 2 &&
219 HEADER_VERSION(header) != 3)
15411c0c 220 return -EOPNOTSUPP;
edce2aed
LP
221
222 if (HEADER_CRYPT_METHOD(header) != 0)
15411c0c 223 return -EOPNOTSUPP;
edce2aed
LP
224
225 if (HEADER_CLUSTER_BITS(header) < 9) /* 512K */
226 return -EBADMSG;
227
228 if (HEADER_CLUSTER_BITS(header) > 21) /* 2MB */
229 return -EBADMSG;
230
231 if (HEADER_SIZE(header) % HEADER_CLUSTER_SIZE(header) != 0)
232 return -EBADMSG;
233
234 if (HEADER_L1_SIZE(header) > 32*1024*1024) /* 32MB */
235 return -EBADMSG;
236
237 if (HEADER_VERSION(header) == 3) {
238
239 if (header->incompatible_features != 0)
15411c0c 240 return -EOPNOTSUPP;
edce2aed
LP
241
242 if (HEADER_HEADER_LENGTH(header) < sizeof(Header))
243 return -EBADMSG;
244 }
245
246 return 0;
247}
248
249int qcow2_convert(int qcow2_fd, int raw_fd) {
250 _cleanup_free_ void *buffer1 = NULL, *buffer2 = NULL;
251 _cleanup_free_ be64_t *l1_table = NULL, *l2_table = NULL;
252 uint64_t sz, i;
253 Header header;
254 ssize_t l;
255 int r;
256
257 l = pread(qcow2_fd, &header, sizeof(header), 0);
258 if (l < 0)
259 return -errno;
260 if (l != sizeof(header))
261 return -EIO;
262
263 r = verify_header(&header);
264 if (r < 0)
265 return r;
266
267 l1_table = new(be64_t, HEADER_L1_SIZE(&header));
268 if (!l1_table)
269 return -ENOMEM;
270
271 l2_table = malloc(HEADER_CLUSTER_SIZE(&header));
272 if (!l2_table)
273 return -ENOMEM;
274
275 buffer1 = malloc(HEADER_CLUSTER_SIZE(&header));
276 if (!buffer1)
277 return -ENOMEM;
278
279 buffer2 = malloc(HEADER_CLUSTER_SIZE(&header));
280 if (!buffer2)
281 return -ENOMEM;
282
283 /* Empty the file if it exists, we rely on zero bits */
284 if (ftruncate(raw_fd, 0) < 0)
285 return -errno;
286
287 if (ftruncate(raw_fd, HEADER_SIZE(&header)) < 0)
288 return -errno;
289
290 sz = sizeof(uint64_t) * HEADER_L1_SIZE(&header);
291 l = pread(qcow2_fd, l1_table, sz, HEADER_L1_TABLE_OFFSET(&header));
292 if (l < 0)
293 return -errno;
294 if ((uint64_t) l != sz)
295 return -EIO;
296
297 for (i = 0; i < HEADER_L1_SIZE(&header); i ++) {
298 uint64_t l2_begin, j;
299
300 r = normalize_offset(&header, l1_table[i], &l2_begin, NULL, NULL);
301 if (r < 0)
302 return r;
303 if (r == 0)
304 continue;
305
306 l = pread(qcow2_fd, l2_table, HEADER_CLUSTER_SIZE(&header), l2_begin);
307 if (l < 0)
308 return -errno;
309 if ((uint64_t) l != HEADER_CLUSTER_SIZE(&header))
310 return -EIO;
311
312 for (j = 0; j < HEADER_L2_SIZE(&header); j++) {
313 uint64_t data_begin, p, compressed_size;
314 bool compressed;
315
316 p = ((i << HEADER_L2_BITS(&header)) + j) << HEADER_CLUSTER_BITS(&header);
317
318 r = normalize_offset(&header, l2_table[j], &data_begin, &compressed, &compressed_size);
319 if (r < 0)
320 return r;
321 if (r == 0)
322 continue;
323
324 if (compressed)
325 r = decompress_cluster(
326 qcow2_fd, data_begin,
327 raw_fd, p,
328 compressed_size, HEADER_CLUSTER_SIZE(&header),
329 buffer1, buffer2);
330 else
331 r = copy_cluster(
332 qcow2_fd, data_begin,
333 raw_fd, p,
334 HEADER_CLUSTER_SIZE(&header), buffer1);
335 if (r < 0)
336 return r;
337 }
338 }
339
340 return 0;
341}
342
343int qcow2_detect(int fd) {
344 be32_t id;
345 ssize_t l;
346
347 l = pread(fd, &id, sizeof(id), 0);
348 if (l < 0)
349 return -errno;
350 if (l != sizeof(id))
351 return -EIO;
352
353 return htobe32(QCOW2_MAGIC) == id;
354}