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