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