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