]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/import/qcow2-util.c
Merge pull request #7388 from keszybz/doc-tweak
[thirdparty/systemd.git] / src / import / qcow2-util.c
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
22 #include "alloc-util.h"
23 #include "btrfs-util.h"
24 #include "qcow2-util.h"
25 #include "sparse-endian.h"
26 #include "util.h"
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
34 typedef 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
74 static 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
81 static 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;
88 int r;
89
90 r = btrfs_clone_range(sfd, soffset, dfd, doffset, cluster_size);
91 if (r >= 0)
92 return r;
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
109 static 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
164 static 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)
179 return -EOPNOTSUPP;
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
210 static int verify_header(const Header *header) {
211 assert(header);
212
213 if (HEADER_MAGIC(header) != QCOW2_MAGIC)
214 return -EBADMSG;
215
216 if (!IN_SET(HEADER_VERSION(header), 2, 3))
217 return -EOPNOTSUPP;
218
219 if (HEADER_CRYPT_METHOD(header) != 0)
220 return -EOPNOTSUPP;
221
222 if (HEADER_CLUSTER_BITS(header) < 9) /* 512K */
223 return -EBADMSG;
224
225 if (HEADER_CLUSTER_BITS(header) > 21) /* 2MB */
226 return -EBADMSG;
227
228 if (HEADER_SIZE(header) % HEADER_CLUSTER_SIZE(header) != 0)
229 return -EBADMSG;
230
231 if (HEADER_L1_SIZE(header) > 32*1024*1024) /* 32MB */
232 return -EBADMSG;
233
234 if (HEADER_VERSION(header) == 3) {
235
236 if (header->incompatible_features != 0)
237 return -EOPNOTSUPP;
238
239 if (HEADER_HEADER_LENGTH(header) < sizeof(Header))
240 return -EBADMSG;
241 }
242
243 return 0;
244 }
245
246 int qcow2_convert(int qcow2_fd, int raw_fd) {
247 _cleanup_free_ void *buffer1 = NULL, *buffer2 = NULL;
248 _cleanup_free_ be64_t *l1_table = NULL, *l2_table = NULL;
249 uint64_t sz, i;
250 Header header;
251 ssize_t l;
252 int r;
253
254 l = pread(qcow2_fd, &header, sizeof(header), 0);
255 if (l < 0)
256 return -errno;
257 if (l != sizeof(header))
258 return -EIO;
259
260 r = verify_header(&header);
261 if (r < 0)
262 return r;
263
264 l1_table = new(be64_t, HEADER_L1_SIZE(&header));
265 if (!l1_table)
266 return -ENOMEM;
267
268 l2_table = malloc(HEADER_CLUSTER_SIZE(&header));
269 if (!l2_table)
270 return -ENOMEM;
271
272 buffer1 = malloc(HEADER_CLUSTER_SIZE(&header));
273 if (!buffer1)
274 return -ENOMEM;
275
276 buffer2 = malloc(HEADER_CLUSTER_SIZE(&header));
277 if (!buffer2)
278 return -ENOMEM;
279
280 /* Empty the file if it exists, we rely on zero bits */
281 if (ftruncate(raw_fd, 0) < 0)
282 return -errno;
283
284 if (ftruncate(raw_fd, HEADER_SIZE(&header)) < 0)
285 return -errno;
286
287 sz = sizeof(uint64_t) * HEADER_L1_SIZE(&header);
288 l = pread(qcow2_fd, l1_table, sz, HEADER_L1_TABLE_OFFSET(&header));
289 if (l < 0)
290 return -errno;
291 if ((uint64_t) l != sz)
292 return -EIO;
293
294 for (i = 0; i < HEADER_L1_SIZE(&header); i ++) {
295 uint64_t l2_begin, j;
296
297 r = normalize_offset(&header, l1_table[i], &l2_begin, NULL, NULL);
298 if (r < 0)
299 return r;
300 if (r == 0)
301 continue;
302
303 l = pread(qcow2_fd, l2_table, HEADER_CLUSTER_SIZE(&header), l2_begin);
304 if (l < 0)
305 return -errno;
306 if ((uint64_t) l != HEADER_CLUSTER_SIZE(&header))
307 return -EIO;
308
309 for (j = 0; j < HEADER_L2_SIZE(&header); j++) {
310 uint64_t data_begin, p, compressed_size;
311 bool compressed;
312
313 p = ((i << HEADER_L2_BITS(&header)) + j) << HEADER_CLUSTER_BITS(&header);
314
315 r = normalize_offset(&header, l2_table[j], &data_begin, &compressed, &compressed_size);
316 if (r < 0)
317 return r;
318 if (r == 0)
319 continue;
320
321 if (compressed)
322 r = decompress_cluster(
323 qcow2_fd, data_begin,
324 raw_fd, p,
325 compressed_size, HEADER_CLUSTER_SIZE(&header),
326 buffer1, buffer2);
327 else
328 r = copy_cluster(
329 qcow2_fd, data_begin,
330 raw_fd, p,
331 HEADER_CLUSTER_SIZE(&header), buffer1);
332 if (r < 0)
333 return r;
334 }
335 }
336
337 return 0;
338 }
339
340 int qcow2_detect(int fd) {
341 be32_t id;
342 ssize_t l;
343
344 l = pread(fd, &id, sizeof(id), 0);
345 if (l < 0)
346 return -errno;
347 if (l != sizeof(id))
348 return -EIO;
349
350 return htobe32(QCOW2_MAGIC) == id;
351 }