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 : }
|