Branch data Line data Source code
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 : 0 : static uint32_t HEADER_HEADER_LENGTH(const Header *h) {
58 [ # # ]: 0 : if (HEADER_VERSION(h) < 3)
59 : 0 : return offsetof(Header, incompatible_features);
60 : :
61 : 0 : return be32toh(h->header_length);
62 : : }
63 : :
64 : 0 : 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 : 0 : r = btrfs_clone_range(sfd, soffset, dfd, doffset, cluster_size);
74 [ # # ]: 0 : if (r >= 0)
75 : 0 : return r;
76 : :
77 : 0 : l = pread(sfd, buffer, cluster_size, soffset);
78 [ # # ]: 0 : if (l < 0)
79 : 0 : return -errno;
80 [ # # ]: 0 : if ((uint64_t) l != cluster_size)
81 : 0 : return -EIO;
82 : :
83 : 0 : l = pwrite(dfd, buffer, cluster_size, doffset);
84 [ # # ]: 0 : if (l < 0)
85 : 0 : return -errno;
86 [ # # ]: 0 : if ((uint64_t) l != cluster_size)
87 : 0 : return -EIO;
88 : :
89 : 0 : return 0;
90 : : }
91 : :
92 : 0 : 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 : 0 : _cleanup_free_ void *large_buffer = NULL;
101 : 0 : z_stream s = {};
102 : : uint64_t sz;
103 : : ssize_t l;
104 : : int r;
105 : :
106 [ # # ]: 0 : if (compressed_size > cluster_size) {
107 : : /* The usual cluster buffer doesn't suffice, let's
108 : : * allocate a larger one, temporarily */
109 : :
110 : 0 : large_buffer = malloc(compressed_size);
111 [ # # ]: 0 : if (!large_buffer)
112 : 0 : return -ENOMEM;
113 : :
114 : 0 : buffer1 = large_buffer;
115 : : }
116 : :
117 : 0 : l = pread(sfd, buffer1, compressed_size, soffset);
118 [ # # ]: 0 : if (l < 0)
119 : 0 : return -errno;
120 [ # # ]: 0 : if ((uint64_t) l != compressed_size)
121 : 0 : return -EIO;
122 : :
123 : 0 : s.next_in = buffer1;
124 : 0 : s.avail_in = compressed_size;
125 : 0 : s.next_out = buffer2;
126 : 0 : s.avail_out = cluster_size;
127 : :
128 : 0 : r = inflateInit2(&s, -12);
129 [ # # ]: 0 : if (r != Z_OK)
130 : 0 : return -EIO;
131 : :
132 : 0 : r = inflate(&s, Z_FINISH);
133 : 0 : sz = (uint8_t*) s.next_out - (uint8_t*) buffer2;
134 : 0 : inflateEnd(&s);
135 [ # # # # ]: 0 : if (r != Z_STREAM_END || sz != cluster_size)
136 : 0 : return -EIO;
137 : :
138 : 0 : l = pwrite(dfd, buffer2, cluster_size, doffset);
139 [ # # ]: 0 : if (l < 0)
140 : 0 : return -errno;
141 [ # # ]: 0 : if ((uint64_t) l != cluster_size)
142 : 0 : return -EIO;
143 : :
144 : 0 : return 0;
145 : : }
146 : :
147 : 0 : 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 : 0 : q = be64toh(p);
157 : :
158 [ # # ]: 0 : if (q & QCOW2_COMPRESSED) {
159 : : uint64_t sz, csize_shift, csize_mask;
160 : :
161 [ # # ]: 0 : if (!compressed)
162 : 0 : return -EOPNOTSUPP;
163 : :
164 : 0 : csize_shift = 64 - 2 - (HEADER_CLUSTER_BITS(header) - 8);
165 : 0 : csize_mask = (1ULL << (HEADER_CLUSTER_BITS(header) - 8)) - 1;
166 : 0 : sz = (((q >> csize_shift) & csize_mask) + 1) * 512 - (q & 511);
167 : 0 : q &= ((1ULL << csize_shift) - 1);
168 : :
169 [ # # ]: 0 : if (compressed_size)
170 : 0 : *compressed_size = sz;
171 : :
172 : 0 : *compressed = true;
173 : :
174 : : } else {
175 [ # # ]: 0 : if (compressed) {
176 : 0 : *compressed = false;
177 : 0 : *compressed_size = 0;
178 : : }
179 : :
180 [ # # ]: 0 : if (q & QCOW2_ZERO) {
181 : : /* We make no distinction between zero blocks and holes */
182 : 0 : *ret = 0;
183 : 0 : return 0;
184 : : }
185 : :
186 : 0 : q &= ~QCOW2_COPIED;
187 : : }
188 : :
189 : 0 : *ret = q;
190 : 0 : return q > 0; /* returns positive if not a hole */
191 : : }
192 : :
193 : 0 : static int verify_header(const Header *header) {
194 [ # # ]: 0 : assert(header);
195 : :
196 [ # # ]: 0 : if (HEADER_MAGIC(header) != QCOW2_MAGIC)
197 : 0 : return -EBADMSG;
198 : :
199 [ # # # # ]: 0 : if (!IN_SET(HEADER_VERSION(header), 2, 3))
200 : 0 : return -EOPNOTSUPP;
201 : :
202 [ # # ]: 0 : if (HEADER_CRYPT_METHOD(header) != 0)
203 : 0 : return -EOPNOTSUPP;
204 : :
205 [ # # ]: 0 : if (HEADER_CLUSTER_BITS(header) < 9) /* 512K */
206 : 0 : return -EBADMSG;
207 : :
208 [ # # ]: 0 : if (HEADER_CLUSTER_BITS(header) > 21) /* 2MB */
209 : 0 : return -EBADMSG;
210 : :
211 [ # # ]: 0 : if (HEADER_SIZE(header) % HEADER_CLUSTER_SIZE(header) != 0)
212 : 0 : return -EBADMSG;
213 : :
214 [ # # ]: 0 : if (HEADER_L1_SIZE(header) > 32*1024*1024) /* 32MB */
215 : 0 : return -EBADMSG;
216 : :
217 [ # # ]: 0 : if (HEADER_VERSION(header) == 3) {
218 : :
219 [ # # ]: 0 : if (header->incompatible_features != 0)
220 : 0 : return -EOPNOTSUPP;
221 : :
222 [ # # ]: 0 : if (HEADER_HEADER_LENGTH(header) < sizeof(Header))
223 : 0 : return -EBADMSG;
224 : : }
225 : :
226 : 0 : return 0;
227 : : }
228 : :
229 : 0 : int qcow2_convert(int qcow2_fd, int raw_fd) {
230 : 0 : _cleanup_free_ void *buffer1 = NULL, *buffer2 = NULL;
231 : 0 : _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 : 0 : l = pread(qcow2_fd, &header, sizeof(header), 0);
238 [ # # ]: 0 : if (l < 0)
239 : 0 : return -errno;
240 [ # # ]: 0 : if (l != sizeof(header))
241 : 0 : return -EIO;
242 : :
243 : 0 : r = verify_header(&header);
244 [ # # ]: 0 : if (r < 0)
245 : 0 : return r;
246 : :
247 : 0 : l1_table = new(be64_t, HEADER_L1_SIZE(&header));
248 [ # # ]: 0 : if (!l1_table)
249 : 0 : return -ENOMEM;
250 : :
251 : 0 : l2_table = malloc(HEADER_CLUSTER_SIZE(&header));
252 [ # # ]: 0 : if (!l2_table)
253 : 0 : return -ENOMEM;
254 : :
255 : 0 : buffer1 = malloc(HEADER_CLUSTER_SIZE(&header));
256 [ # # ]: 0 : if (!buffer1)
257 : 0 : return -ENOMEM;
258 : :
259 : 0 : buffer2 = malloc(HEADER_CLUSTER_SIZE(&header));
260 [ # # ]: 0 : if (!buffer2)
261 : 0 : return -ENOMEM;
262 : :
263 : : /* Empty the file if it exists, we rely on zero bits */
264 [ # # ]: 0 : if (ftruncate(raw_fd, 0) < 0)
265 : 0 : return -errno;
266 : :
267 [ # # ]: 0 : if (ftruncate(raw_fd, HEADER_SIZE(&header)) < 0)
268 : 0 : return -errno;
269 : :
270 : 0 : sz = sizeof(uint64_t) * HEADER_L1_SIZE(&header);
271 : 0 : l = pread(qcow2_fd, l1_table, sz, HEADER_L1_TABLE_OFFSET(&header));
272 [ # # ]: 0 : if (l < 0)
273 : 0 : return -errno;
274 [ # # ]: 0 : if ((uint64_t) l != sz)
275 : 0 : return -EIO;
276 : :
277 [ # # ]: 0 : for (i = 0; i < HEADER_L1_SIZE(&header); i ++) {
278 : : uint64_t l2_begin, j;
279 : :
280 : 0 : r = normalize_offset(&header, l1_table[i], &l2_begin, NULL, NULL);
281 [ # # ]: 0 : if (r < 0)
282 : 0 : return r;
283 [ # # ]: 0 : if (r == 0)
284 : 0 : continue;
285 : :
286 : 0 : l = pread(qcow2_fd, l2_table, HEADER_CLUSTER_SIZE(&header), l2_begin);
287 [ # # ]: 0 : if (l < 0)
288 : 0 : return -errno;
289 [ # # ]: 0 : if ((uint64_t) l != HEADER_CLUSTER_SIZE(&header))
290 : 0 : return -EIO;
291 : :
292 [ # # ]: 0 : for (j = 0; j < HEADER_L2_SIZE(&header); j++) {
293 : : uint64_t data_begin, p, compressed_size;
294 : : bool compressed;
295 : :
296 : 0 : p = ((i << HEADER_L2_BITS(&header)) + j) << HEADER_CLUSTER_BITS(&header);
297 : :
298 : 0 : r = normalize_offset(&header, l2_table[j], &data_begin, &compressed, &compressed_size);
299 [ # # ]: 0 : if (r < 0)
300 : 0 : return r;
301 [ # # ]: 0 : if (r == 0)
302 : 0 : continue;
303 : :
304 [ # # ]: 0 : if (compressed)
305 : 0 : r = decompress_cluster(
306 : : qcow2_fd, data_begin,
307 : : raw_fd, p,
308 : 0 : compressed_size, HEADER_CLUSTER_SIZE(&header),
309 : : buffer1, buffer2);
310 : : else
311 : 0 : r = copy_cluster(
312 : : qcow2_fd, data_begin,
313 : : raw_fd, p,
314 : 0 : HEADER_CLUSTER_SIZE(&header), buffer1);
315 [ # # ]: 0 : if (r < 0)
316 : 0 : return r;
317 : : }
318 : : }
319 : :
320 : 0 : return 0;
321 : : }
322 : :
323 : 0 : int qcow2_detect(int fd) {
324 : : be32_t id;
325 : : ssize_t l;
326 : :
327 : 0 : l = pread(fd, &id, sizeof(id), 0);
328 [ # # ]: 0 : if (l < 0)
329 : 0 : return -errno;
330 [ # # ]: 0 : if (l != sizeof(id))
331 : 0 : return -EIO;
332 : :
333 : 0 : return htobe32(QCOW2_MAGIC) == id;
334 : : }
|