qcow2-util.c revision b5efdb8af40ea759a1ea584c1bc44ecc81dd00ce
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering This file is part of systemd.
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering Copyright 2015 Lennart Poettering
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering systemd is free software; you can redistribute it and/or modify it
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering under the terms of the GNU Lesser General Public License as published by
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering the Free Software Foundation; either version 2.1 of the License, or
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering (at your option) any later version.
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering systemd is distributed in the hope that it will be useful, but
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering WITHOUT ANY WARRANTY; without even the implied warranty of
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering Lesser General Public License for more details.
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering You should have received a copy of the GNU Lesser General Public License
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering along with systemd; If not, see <http://www.gnu.org/licenses/>.
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering /* The remainder is only present on QCOW3 */
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering#define HEADER_MAGIC(header) be32toh((header)->magic)
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering#define HEADER_VERSION(header) be32toh((header)->version)
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering#define HEADER_CLUSTER_BITS(header) be32toh((header)->cluster_bits)
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering#define HEADER_CLUSTER_SIZE(header) (1ULL << HEADER_CLUSTER_BITS(header))
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering#define HEADER_L2_BITS(header) (HEADER_CLUSTER_BITS(header) - 3)
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering#define HEADER_SIZE(header) be64toh((header)->size)
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering#define HEADER_CRYPT_METHOD(header) be32toh((header)->crypt_method)
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering#define HEADER_L1_SIZE(header) be32toh((header)->l1_size)
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering#define HEADER_L2_SIZE(header) (HEADER_CLUSTER_SIZE(header)/sizeof(uint64_t))
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering#define HEADER_L1_TABLE_OFFSET(header) be64toh((header)->l1_table_offset)
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poetteringstatic uint32_t HEADER_HEADER_LENGTH(const Header *h) {
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering return offsetof(Header, incompatible_features);
1c7dd82563ff2e71a067aea20d2acb2d0553644bLennart Poettering r = btrfs_clone_range(sfd, soffset, dfd, doffset, cluster_size);
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering l = pread(sfd, buffer, cluster_size, soffset);
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering l = pwrite(dfd, buffer, cluster_size, doffset);
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering _cleanup_free_ void *large_buffer = NULL;
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering /* The usual cluster buffer doesn't suffice, let's
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering * allocate a larger one, temporarily */
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering l = pread(sfd, buffer1, compressed_size, soffset);
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering sz = (uint8_t*) s.next_out - (uint8_t*) buffer2;
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering if (r != Z_STREAM_END || sz != cluster_size)
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering l = pwrite(dfd, buffer2, cluster_size, doffset);
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering csize_shift = 64 - 2 - (HEADER_CLUSTER_BITS(header) - 8);
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering csize_mask = (1ULL << (HEADER_CLUSTER_BITS(header) - 8)) - 1;
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering sz = (((q >> csize_shift) & csize_mask) + 1) * 512 - (q & 511);
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering /* We make no distinction between zero blocks and holes */
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering return q > 0; /* returns positive if not a hole */
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poetteringstatic int verify_header(const Header *header) {
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering if (HEADER_CLUSTER_BITS(header) < 9) /* 512K */
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering if (HEADER_CLUSTER_BITS(header) > 21) /* 2MB */
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering if (HEADER_SIZE(header) % HEADER_CLUSTER_SIZE(header) != 0)
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering if (HEADER_L1_SIZE(header) > 32*1024*1024) /* 32MB */
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering if (HEADER_HEADER_LENGTH(header) < sizeof(Header))
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poetteringint qcow2_convert(int qcow2_fd, int raw_fd) {
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering _cleanup_free_ void *buffer1 = NULL, *buffer2 = NULL;
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering _cleanup_free_ be64_t *l1_table = NULL, *l2_table = NULL;
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering l = pread(qcow2_fd, &header, sizeof(header), 0);
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering if (l != sizeof(header))
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering l1_table = new(be64_t, HEADER_L1_SIZE(&header));
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering l2_table = malloc(HEADER_CLUSTER_SIZE(&header));
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering buffer1 = malloc(HEADER_CLUSTER_SIZE(&header));
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering buffer2 = malloc(HEADER_CLUSTER_SIZE(&header));
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering /* Empty the file if it exists, we rely on zero bits */
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering if (ftruncate(raw_fd, HEADER_SIZE(&header)) < 0)
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering sz = sizeof(uint64_t) * HEADER_L1_SIZE(&header);
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering l = pread(qcow2_fd, l1_table, sz, HEADER_L1_TABLE_OFFSET(&header));
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering for (i = 0; i < HEADER_L1_SIZE(&header); i ++) {
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering r = normalize_offset(&header, l1_table[i], &l2_begin, NULL, NULL);
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering l = pread(qcow2_fd, l2_table, HEADER_CLUSTER_SIZE(&header), l2_begin);
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering if ((uint64_t) l != HEADER_CLUSTER_SIZE(&header))
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering for (j = 0; j < HEADER_L2_SIZE(&header); j++) {
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering p = ((i << HEADER_L2_BITS(&header)) + j) << HEADER_CLUSTER_BITS(&header);
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering r = normalize_offset(&header, l2_table[j], &data_begin, &compressed, &compressed_size);
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering compressed_size, HEADER_CLUSTER_SIZE(&header),
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering if (l != sizeof(id))