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