qcow2-util.c revision 15411c0cb1192799b37ec8f25d6f30e8d7292fc6
/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
/***
This file is part of systemd.
Copyright 2015 Lennart Poettering
under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation; either version 2.1 of the License, or
(at your option) any later version.
systemd is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
#include <zlib.h>
#include "util.h"
#include "sparse-endian.h"
#include "qcow2-util.h"
#include "btrfs-util.h"
#define QCOW2_MAGIC 0x514649fb
#define QCOW2_ZERO (1ULL << 0)
/* The remainder is only present on QCOW3 */
} Header;
if (HEADER_VERSION(h) < 3)
return be32toh(h->header_length);
}
static int copy_cluster(
void *buffer) {
ssize_t l;
int r;
if (r >= 0)
return r;
if (l < 0)
return -errno;
if ((uint64_t) l != cluster_size)
return -EIO;
if (l < 0)
return -errno;
if ((uint64_t) l != cluster_size)
return -EIO;
return 0;
}
static int decompress_cluster(
void *buffer1,
void *buffer2) {
z_stream s = {};
ssize_t l;
int r;
if (compressed_size > cluster_size) {
/* The usual cluster buffer doesn't suffice, let's
* allocate a larger one, temporarily */
if (!large_buffer)
return -ENOMEM;
}
if (l < 0)
return -errno;
if ((uint64_t) l != compressed_size)
return -EIO;
s.avail_in = compressed_size;
s.avail_out = cluster_size;
r = inflateInit2(&s, -12);
if (r != Z_OK)
return -EIO;
inflateEnd(&s);
return -EIO;
if (l < 0)
return -errno;
if ((uint64_t) l != cluster_size)
return -EIO;
return 0;
}
static int normalize_offset(
uint64_t p,
bool *compressed,
uint64_t q;
q = be64toh(p);
if (q & QCOW2_COMPRESSED) {
if (!compressed)
return -EOPNOTSUPP;
if (compressed_size)
*compressed_size = sz;
*compressed = true;
} else {
if (compressed) {
*compressed = false;
*compressed_size = 0;
}
if (q & QCOW2_ZERO) {
/* We make no distinction between zero blocks and holes */
*ret = 0;
return 0;
}
q &= ~QCOW2_COPIED;
}
*ret = q;
return q > 0; /* returns positive if not a hole */
}
return -EBADMSG;
return -EOPNOTSUPP;
if (HEADER_CRYPT_METHOD(header) != 0)
return -EOPNOTSUPP;
return -EBADMSG;
return -EBADMSG;
return -EBADMSG;
return -EBADMSG;
if (header->incompatible_features != 0)
return -EOPNOTSUPP;
return -EBADMSG;
}
return 0;
}
ssize_t l;
int r;
if (l < 0)
return -errno;
if (l != sizeof(header))
return -EIO;
r = verify_header(&header);
if (r < 0)
return r;
if (!l1_table)
return -ENOMEM;
if (!l2_table)
return -ENOMEM;
if (!buffer1)
return -ENOMEM;
if (!buffer2)
return -ENOMEM;
/* Empty the file if it exists, we rely on zero bits */
return -errno;
return -errno;
if (l < 0)
return -errno;
return -EIO;
for (i = 0; i < HEADER_L1_SIZE(&header); i ++) {
if (r < 0)
return r;
if (r == 0)
continue;
if (l < 0)
return -errno;
return -EIO;
for (j = 0; j < HEADER_L2_SIZE(&header); j++) {
bool compressed;
if (r < 0)
return r;
if (r == 0)
continue;
if (compressed)
r = decompress_cluster(
raw_fd, p,
else
r = copy_cluster(
raw_fd, p,
if (r < 0)
return r;
}
}
return 0;
}
int qcow2_detect(int fd) {
ssize_t l;
if (l < 0)
return -errno;
if (l != sizeof(id))
return -EIO;
}