qcow2-util.c revision edce2aed3aa93b84f7b4c70412bdb665da2977b0
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering/***
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering This file is part of systemd.
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering Copyright 2015 Lennart Poettering
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart 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
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
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***/
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering#include <zlib.h>
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering#include "util.h"
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering#include "sparse-endian.h"
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering#include "qcow2-util.h"
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering#define QCOW2_MAGIC 0x514649fb
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering#define QCOW2_COPIED (1ULL << 63)
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering#define QCOW2_COMPRESSED (1ULL << 62)
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering#define QCOW2_ZERO (1ULL << 0)
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poetteringtypedef struct _packed_ Header {
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering be32_t magic;
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering be32_t version;
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering be64_t backing_file_offset;
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering be32_t backing_file_size;
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering be32_t cluster_bits;
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering be64_t size;
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering be32_t crypt_method;
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering be32_t l1_size;
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering be64_t l1_table_offset;
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering be64_t refcount_table_offset;
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering be32_t refcount_table_clusters;
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering be32_t nb_snapshots;
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering be64_t snapshots_offset;
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering /* The remainder is only present on QCOW3 */
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering be64_t incompatible_features;
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering be64_t compatible_features;
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering be64_t autoclear_features;
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering be32_t refcount_order;
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering be32_t header_length;
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering} Header;
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering
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 Poettering
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poetteringstatic uint32_t HEADER_HEADER_LENGTH(const Header *h) {
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering if (HEADER_VERSION(h) < 3)
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering return offsetof(Header, incompatible_features);
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering return be32toh(h->header_length);
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering}
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poetteringstatic int copy_cluster(
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering int sfd, uint64_t soffset,
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering int dfd, uint64_t doffset,
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering uint64_t cluster_size,
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering void *buffer) {
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering ssize_t l;
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering l = pread(sfd, buffer, cluster_size, soffset);
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering if (l < 0)
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering return -errno;
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering if ((uint64_t) l != cluster_size)
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering return -EIO;
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering l = pwrite(dfd, buffer, cluster_size, doffset);
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering if (l < 0)
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering return -errno;
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering if ((uint64_t) l != cluster_size)
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering return -EIO;
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering return 0;
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering}
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poetteringstatic int decompress_cluster(
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering int sfd, uint64_t soffset,
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering int dfd, uint64_t doffset,
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering uint64_t compressed_size,
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering uint64_t cluster_size,
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering void *buffer1,
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering void *buffer2) {
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering _cleanup_free_ void *large_buffer = NULL;
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering z_stream s = {};
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering uint64_t sz;
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering ssize_t l;
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering int r;
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering if (compressed_size > cluster_size) {
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering /* The usual cluster buffer doesn't suffice, let's
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering * allocate a larger one, temporarily */
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering large_buffer = malloc(compressed_size);
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering if (!large_buffer)
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering return -ENOMEM;
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering buffer1 = large_buffer;
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering }
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering l = pread(sfd, buffer1, compressed_size, soffset);
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering if (l < 0)
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering return -errno;
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering if ((uint64_t) l != compressed_size)
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering return -EIO;
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering s.next_in = buffer1;
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering s.avail_in = compressed_size;
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering s.next_out = buffer2;
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering s.avail_out = cluster_size;
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering r = inflateInit2(&s, -12);
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering if (r != Z_OK)
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering return -EIO;
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering r = inflate(&s, Z_FINISH);
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering sz = (uint8_t*) s.next_out - (uint8_t*) buffer2;
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering inflateEnd(&s);
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering if (r != Z_STREAM_END || sz != cluster_size)
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering return -EIO;
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering l = pwrite(dfd, buffer2, cluster_size, doffset);
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering if (l < 0)
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering return -errno;
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering if ((uint64_t) l != cluster_size)
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering return -EIO;
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering return 0;
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering}
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poetteringstatic int normalize_offset(
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering const Header *header,
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering uint64_t p,
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering uint64_t *ret,
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering bool *compressed,
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering uint64_t *compressed_size) {
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering uint64_t q;
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering q = be64toh(p);
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering if (q & QCOW2_COMPRESSED) {
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering uint64_t sz, csize_shift, csize_mask;
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering if (!compressed)
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering return -ENOTSUP;
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering
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 q &= ((1ULL << csize_shift) - 1);
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering if (compressed_size)
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering *compressed_size = sz;
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering *compressed = true;
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering } else {
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering if (compressed) {
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering *compressed = false;
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering *compressed_size = 0;
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering }
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering if (q & QCOW2_ZERO) {
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering /* We make no distinction between zero blocks and holes */
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering *ret = 0;
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering return 0;
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering }
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering q &= ~QCOW2_COPIED;
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering }
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering *ret = q;
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering return q > 0; /* returns positive if not a hole */
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering}
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poetteringstatic int verify_header(const Header *header) {
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering assert(header);
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering if (HEADER_MAGIC(header) != QCOW2_MAGIC)
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering return -EBADMSG;
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering if (HEADER_VERSION(header) != 2 &&
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering HEADER_VERSION(header) != 3)
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering return -ENOTSUP;
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering if (HEADER_CRYPT_METHOD(header) != 0)
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering return -ENOTSUP;
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering if (HEADER_CLUSTER_BITS(header) < 9) /* 512K */
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering return -EBADMSG;
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering if (HEADER_CLUSTER_BITS(header) > 21) /* 2MB */
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering return -EBADMSG;
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering if (HEADER_SIZE(header) % HEADER_CLUSTER_SIZE(header) != 0)
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering return -EBADMSG;
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering if (HEADER_L1_SIZE(header) > 32*1024*1024) /* 32MB */
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering return -EBADMSG;
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering if (HEADER_VERSION(header) == 3) {
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering if (header->incompatible_features != 0)
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering return -ENOTSUP;
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering if (HEADER_HEADER_LENGTH(header) < sizeof(Header))
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering return -EBADMSG;
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering }
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering return 0;
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering}
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering
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 uint64_t sz, i;
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering Header header;
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering ssize_t l;
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering int r;
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering l = pread(qcow2_fd, &header, sizeof(header), 0);
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering if (l < 0)
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering return -errno;
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering if (l != sizeof(header))
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering return -EIO;
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering r = verify_header(&header);
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering if (r < 0)
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering return r;
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering l1_table = new(be64_t, HEADER_L1_SIZE(&header));
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering if (!l1_table)
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering return -ENOMEM;
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering l2_table = malloc(HEADER_CLUSTER_SIZE(&header));
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering if (!l2_table)
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering return -ENOMEM;
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering buffer1 = malloc(HEADER_CLUSTER_SIZE(&header));
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering if (!buffer1)
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering return -ENOMEM;
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering buffer2 = malloc(HEADER_CLUSTER_SIZE(&header));
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering if (!buffer2)
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering return -ENOMEM;
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering /* Empty the file if it exists, we rely on zero bits */
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering if (ftruncate(raw_fd, 0) < 0)
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering return -errno;
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering if (ftruncate(raw_fd, HEADER_SIZE(&header)) < 0)
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering return -errno;
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering
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 if (l < 0)
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering return -errno;
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering if ((uint64_t) l != sz)
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering return -EIO;
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering for (i = 0; i < HEADER_L1_SIZE(&header); i ++) {
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering uint64_t l2_begin, j;
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering r = normalize_offset(&header, l1_table[i], &l2_begin, NULL, NULL);
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering if (r < 0)
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering return r;
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering if (r == 0)
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering continue;
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering l = pread(qcow2_fd, l2_table, HEADER_CLUSTER_SIZE(&header), l2_begin);
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering if (l < 0)
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering return -errno;
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering if ((uint64_t) l != HEADER_CLUSTER_SIZE(&header))
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering return -EIO;
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering for (j = 0; j < HEADER_L2_SIZE(&header); j++) {
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering uint64_t data_begin, p, compressed_size;
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering bool compressed;
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering p = ((i << HEADER_L2_BITS(&header)) + j) << HEADER_CLUSTER_BITS(&header);
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering r = normalize_offset(&header, l2_table[j], &data_begin, &compressed, &compressed_size);
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering if (r < 0)
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering return r;
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering if (r == 0)
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering continue;
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering if (compressed)
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering r = decompress_cluster(
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering qcow2_fd, data_begin,
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering raw_fd, p,
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering compressed_size, HEADER_CLUSTER_SIZE(&header),
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering buffer1, buffer2);
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering else
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering r = copy_cluster(
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering qcow2_fd, data_begin,
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering raw_fd, p,
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering HEADER_CLUSTER_SIZE(&header), buffer1);
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering if (r < 0)
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering return r;
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering }
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering }
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering return 0;
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering}
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poetteringint qcow2_detect(int fd) {
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering be32_t id;
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering ssize_t l;
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering l = pread(fd, &id, sizeof(id), 0);
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering if (l < 0)
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering return -errno;
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering if (l != sizeof(id))
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering return -EIO;
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering return htobe32(QCOW2_MAGIC) == id;
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering}