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