From patchwork Fri Feb 6 16:40:37 2015 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Kevin Wolf X-Patchwork-Id: 437403 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from lists.gnu.org (lists.gnu.org [IPv6:2001:4830:134:3::11]) (using TLSv1 with cipher AES256-SHA (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 0C735140272 for ; Sat, 7 Feb 2015 04:02:16 +1100 (AEDT) Received: from localhost ([::1]:49422 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1YJmII-0007nz-TM for incoming@patchwork.ozlabs.org; Fri, 06 Feb 2015 12:02:14 -0500 Received: from eggs.gnu.org ([2001:4830:134:3::10]:44877) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1YJlyN-0004v0-Ga for qemu-devel@nongnu.org; Fri, 06 Feb 2015 11:41:44 -0500 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1YJlyG-0000q1-SW for qemu-devel@nongnu.org; Fri, 06 Feb 2015 11:41:39 -0500 Received: from mx1.redhat.com ([209.132.183.28]:56109) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1YJlyG-0000ph-Ep for qemu-devel@nongnu.org; Fri, 06 Feb 2015 11:41:32 -0500 Received: from int-mx13.intmail.prod.int.phx2.redhat.com (int-mx13.intmail.prod.int.phx2.redhat.com [10.5.11.26]) by mx1.redhat.com (8.14.4/8.14.4) with ESMTP id t16GfVDr026776 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-GCM-SHA384 bits=256 verify=FAIL) for ; Fri, 6 Feb 2015 11:41:31 -0500 Received: from noname.redhat.com (ovpn-116-120.ams2.redhat.com [10.36.116.120]) by int-mx13.intmail.prod.int.phx2.redhat.com (8.14.4/8.14.4) with ESMTP id t16GepF8006422; Fri, 6 Feb 2015 11:41:30 -0500 From: Kevin Wolf To: qemu-devel@nongnu.org Date: Fri, 6 Feb 2015 17:40:37 +0100 Message-Id: <1423240849-15499-31-git-send-email-kwolf@redhat.com> In-Reply-To: <1423240849-15499-1-git-send-email-kwolf@redhat.com> References: <1423240849-15499-1-git-send-email-kwolf@redhat.com> X-Scanned-By: MIMEDefang 2.68 on 10.5.11.26 X-detected-operating-system: by eggs.gnu.org: GNU/Linux 3.x X-Received-From: 209.132.183.28 Cc: kwolf@redhat.com Subject: [Qemu-devel] [PULL 30/42] block/dmg: support bzip2 block entry types X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.14 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org Sender: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org From: Peter Wu This patch adds support for bzip2-compressed block entries as introduced with OS X 10.4 (source: https://en.wikipedia.org/wiki/Apple_Disk_Image). It was tested against a 5.2G "OS X Yosemite" installation image which stores the BLXX block in the XML property list (instead of resource forks) and has over 5k chunks. New configure entries are added (--enable-bzip2 / --disable-bzip2) to control inclusion of bzip2 functionality (which requires linking against libbz2). The help message suggests that this option is needed for DMG files, but the tests are generic enough that other parts of QEMU can use bzip2 if needed. The identifiers are based on http://newosxbook.com/DMG.html. The decompression routines are based on the zlib case, but as there is no way to reset the decompression state (unlike zlib), memory is allocated and deallocated for every decompression. This should not be problematic as the decompression takes most of the time and as blocks are typically about/over 1 MiB in size, only one allocation is done every 2000 sectors. Signed-off-by: Peter Wu Reviewed-by: John Snow Acked-by: Paolo Bonzini Message-id: 1420566495-13284-12-git-send-email-peter@lekensteyn.nl Signed-off-by: Stefan Hajnoczi Signed-off-by: Kevin Wolf --- block/Makefile.objs | 1 + block/dmg.c | 43 ++++++++++++++++++++++++++++++++++++++++++- configure | 31 +++++++++++++++++++++++++++++++ 3 files changed, 74 insertions(+), 1 deletion(-) diff --git a/block/Makefile.objs b/block/Makefile.objs index 010afad..db2933e 100644 --- a/block/Makefile.objs +++ b/block/Makefile.objs @@ -37,5 +37,6 @@ gluster.o-libs := $(GLUSTERFS_LIBS) ssh.o-cflags := $(LIBSSH2_CFLAGS) ssh.o-libs := $(LIBSSH2_LIBS) archipelago.o-libs := $(ARCHIPELAGO_LIBS) +dmg.o-libs := $(BZIP2_LIBS) qcow.o-libs := -lz linux-aio.o-libs := -laio diff --git a/block/dmg.c b/block/dmg.c index cc584b5..797fda3 100644 --- a/block/dmg.c +++ b/block/dmg.c @@ -26,6 +26,9 @@ #include "qemu/bswap.h" #include "qemu/module.h" #include +#ifdef CONFIG_BZIP2 +#include +#endif #include enum { @@ -56,6 +59,9 @@ typedef struct BDRVDMGState { uint8_t *compressed_chunk; uint8_t *uncompressed_chunk; z_stream zstream; +#ifdef CONFIG_BZIP2 + bz_stream bzstream; +#endif } BDRVDMGState; static int dmg_probe(const uint8_t *buf, int buf_size, const char *filename) @@ -123,6 +129,7 @@ static void update_max_chunk_size(BDRVDMGState *s, uint32_t chunk, switch (s->types[chunk]) { case 0x80000005: /* zlib compressed */ + case 0x80000006: /* bzip2 compressed */ compressed_size = s->lengths[chunk]; uncompressed_sectors = s->sectorcounts[chunk]; break; @@ -198,6 +205,9 @@ static bool dmg_is_known_block_type(uint32_t entry_type) case 0x00000001: /* uncompressed */ case 0x00000002: /* zeroes */ case 0x80000005: /* zlib */ +#ifdef CONFIG_BZIP2 + case 0x80000006: /* bzip2 */ +#endif return true; default: return false; @@ -564,13 +574,16 @@ static inline int dmg_read_chunk(BlockDriverState *bs, uint64_t sector_num) if (!is_sector_in_chunk(s, s->current_chunk, sector_num)) { int ret; uint32_t chunk = search_chunk(s, sector_num); +#ifdef CONFIG_BZIP2 + uint64_t total_out; +#endif if (chunk >= s->n_chunks) { return -1; } s->current_chunk = s->n_chunks; - switch (s->types[chunk]) { + switch (s->types[chunk]) { /* block entry type */ case 0x80000005: { /* zlib compressed */ /* we need to buffer, because only the chunk as whole can be * inflated. */ @@ -594,6 +607,34 @@ static inline int dmg_read_chunk(BlockDriverState *bs, uint64_t sector_num) return -1; } break; } +#ifdef CONFIG_BZIP2 + case 0x80000006: /* bzip2 compressed */ + /* we need to buffer, because only the chunk as whole can be + * inflated. */ + ret = bdrv_pread(bs->file, s->offsets[chunk], + s->compressed_chunk, s->lengths[chunk]); + if (ret != s->lengths[chunk]) { + return -1; + } + + ret = BZ2_bzDecompressInit(&s->bzstream, 0, 0); + if (ret != BZ_OK) { + return -1; + } + s->bzstream.next_in = (char *)s->compressed_chunk; + s->bzstream.avail_in = (unsigned int) s->lengths[chunk]; + s->bzstream.next_out = (char *)s->uncompressed_chunk; + s->bzstream.avail_out = (unsigned int) 512 * s->sectorcounts[chunk]; + ret = BZ2_bzDecompress(&s->bzstream); + total_out = ((uint64_t)s->bzstream.total_out_hi32 << 32) + + s->bzstream.total_out_lo32; + BZ2_bzDecompressEnd(&s->bzstream); + if (ret != BZ_STREAM_END || + total_out != 512 * s->sectorcounts[chunk]) { + return -1; + } + break; +#endif /* CONFIG_BZIP2 */ case 1: /* copy */ ret = bdrv_pread(bs->file, s->offsets[chunk], s->uncompressed_chunk, s->lengths[chunk]); diff --git a/configure b/configure index e00e03a..7ba4bcb 100755 --- a/configure +++ b/configure @@ -313,6 +313,7 @@ glx="" zlib="yes" lzo="" snappy="" +bzip2="" guest_agent="" guest_agent_with_vss="no" vss_win32_sdk="" @@ -1060,6 +1061,10 @@ for opt do ;; --enable-snappy) snappy="yes" ;; + --disable-bzip2) bzip2="no" + ;; + --enable-bzip2) bzip2="yes" + ;; --enable-guest-agent) guest_agent="yes" ;; --disable-guest-agent) guest_agent="no" @@ -1374,6 +1379,8 @@ Advanced options (experts only): --enable-usb-redir enable usb network redirection support --enable-lzo enable the support of lzo compression library --enable-snappy enable the support of snappy compression library + --enable-bzip2 enable the support of bzip2 compression library (for + reading bzip2-compressed dmg images) --disable-guest-agent disable building of the QEMU Guest Agent --enable-guest-agent enable building of the QEMU Guest Agent --with-vss-sdk=SDK-path enable Windows VSS support in QEMU Guest Agent @@ -1820,6 +1827,24 @@ EOF fi ########################################## +# bzip2 check + +if test "$bzip2" != "no" ; then + cat > $TMPC << EOF +#include +int main(void) { BZ2_bzlibVersion(); return 0; } +EOF + if compile_prog "" "-lbz2" ; then + bzip2="yes" + else + if test "$bzip2" = "yes"; then + feature_not_found "libbzip2" "Install libbzip2 devel" + fi + bzip2="no" + fi +fi + +########################################## # libseccomp check if test "$seccomp" != "no" ; then @@ -4385,6 +4410,7 @@ echo "vhdx $vhdx" echo "Quorum $quorum" echo "lzo support $lzo" echo "snappy support $snappy" +echo "bzip2 support $bzip2" echo "NUMA host support $numa" if test "$sdl_too_old" = "yes"; then @@ -4743,6 +4769,11 @@ if test "$snappy" = "yes" ; then echo "CONFIG_SNAPPY=y" >> $config_host_mak fi +if test "$bzip2" = "yes" ; then + echo "CONFIG_BZIP2=y" >> $config_host_mak + echo "BZIP2_LIBS=-lbz2" >> $config_host_mak +fi + if test "$libiscsi" = "yes" ; then echo "CONFIG_LIBISCSI=m" >> $config_host_mak echo "LIBISCSI_CFLAGS=$libiscsi_cflags" >> $config_host_mak