[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Xen-devel] [RFC] libxc: Move compression support into own file



Move the existing decompression methods into its own file.

Signed-off-by: Bastian Blank <waldi@xxxxxxxxxx>

diff -r 66f563be41d9 tools/libxc/Makefile
--- a/tools/libxc/Makefile      Tue Feb 19 10:49:53 2013 +0100
+++ b/tools/libxc/Makefile      Tue Feb 26 19:23:05 2013 +0100
@@ -58,6 +58,7 @@
 GUEST_SRCS-y                 += xc_dom_core.c xc_dom_boot.c
 GUEST_SRCS-y                 += xc_dom_elfloader.c
 GUEST_SRCS-$(CONFIG_X86)     += xc_dom_bzimageloader.c
+GUEST_SRCS-$(CONFIG_X86)     += xc_dom_decompress.c
 GUEST_SRCS-$(CONFIG_ARM)     += xc_dom_armzimageloader.c
 GUEST_SRCS-y                 += xc_dom_binloader.c
 GUEST_SRCS-y                 += xc_dom_compat_linux.c
@@ -182,8 +183,8 @@
 zlib-options = $(ZLIB)
 endif
 
-xc_dom_bzimageloader.o: CFLAGS += $(call zlib-options,D)
-xc_dom_bzimageloader.opic: CFLAGS += $(call zlib-options,D)
+xc_dom_decompress.o: CFLAGS += $(call zlib-options,D)
+xc_dom_decompress.opic: CFLAGS += $(call zlib-options,D)
 
 libxenguest.so.$(MAJOR).$(MINOR): COMPRESSION_LIBS = $(call zlib-options,l)
 libxenguest.so.$(MAJOR).$(MINOR): $(GUEST_PIC_OBJS) libxenctrl.so
diff -r 66f563be41d9 tools/libxc/xc_dom.h
--- a/tools/libxc/xc_dom.h      Tue Feb 19 10:49:53 2013 +0100
+++ b/tools/libxc/xc_dom.h      Tue Feb 26 19:23:05 2013 +0100
@@ -293,6 +293,17 @@
 void xc_dom_unmap_one(struct xc_dom_image *dom, xen_pfn_t pfn);
 void xc_dom_unmap_all(struct xc_dom_image *dom);
 
+int xc_try_bzip2_decode(struct xc_dom_image *dom, void **blob, size_t *size)
+    __attribute__((visibility("hidden")));
+int xc_try_gzip_decode(struct xc_dom_image *dom, void **blob, size_t *size)
+    __attribute__((visibility("hidden")));
+int xc_try_lzma_decode(struct xc_dom_image *dom, void **blob, size_t *size)
+    __attribute__((visibility("hidden")));
+int xc_try_lzo1x_decode(struct xc_dom_image *dom, void **blob, size_t *size)
+    __attribute__((visibility("hidden")));
+int xc_try_xz_decode(struct xc_dom_image *dom, void **blob, size_t *size)
+    __attribute__((visibility("hidden")));
+
 static inline void *xc_dom_seg_to_ptr(struct xc_dom_image *dom,
                                       struct xc_dom_seg *seg)
 {
diff -r 66f563be41d9 tools/libxc/xc_dom_bzimageloader.c
--- a/tools/libxc/xc_dom_bzimageloader.c        Tue Feb 19 10:49:53 2013 +0100
+++ b/tools/libxc/xc_dom_bzimageloader.c        Tue Feb 26 19:23:05 2013 +0100
@@ -35,533 +35,6 @@
 #include "xg_private.h"
 #include "xc_dom.h"
 
-#if defined(HAVE_BZLIB)
-
-#include <bzlib.h>
-
-static int xc_try_bzip2_decode(
-    struct xc_dom_image *dom, void **blob, size_t *size)
-{
-    bz_stream stream;
-    int ret;
-    char *out_buf;
-    char *tmp_buf;
-    int retval = -1;
-    unsigned int outsize;
-    uint64_t total;
-
-    stream.bzalloc = NULL;
-    stream.bzfree = NULL;
-    stream.opaque = NULL;
-
-    if ( dom->kernel_size == 0)
-    {
-        DOMPRINTF("BZIP2: Input is 0 size");
-        return -1;
-    }
-
-    ret = BZ2_bzDecompressInit(&stream, 0, 0);
-    if ( ret != BZ_OK )
-    {
-        DOMPRINTF("BZIP2: Error initting stream");
-        return -1;
-    }
-
-    /* sigh.  We don't know up-front how much memory we are going to need
-     * for the output buffer.  Allocate the output buffer to be equal
-     * the input buffer to start, and we'll realloc as needed.
-     */
-    outsize = dom->kernel_size;
-
-    /*
-     * stream.avail_in and outsize are unsigned int, while kernel_size
-     * is a size_t. Check we aren't overflowing.
-     */
-    if ( outsize != dom->kernel_size )
-    {
-        DOMPRINTF("BZIP2: Input too large");
-        goto bzip2_cleanup;
-    }
-
-    out_buf = malloc(outsize);
-    if ( out_buf == NULL )
-    {
-        DOMPRINTF("BZIP2: Failed to alloc memory");
-        goto bzip2_cleanup;
-    }
-
-    stream.next_in = dom->kernel_blob;
-    stream.avail_in = dom->kernel_size;
-
-    stream.next_out = out_buf;
-    stream.avail_out = dom->kernel_size;
-
-    for ( ; ; )
-    {
-        ret = BZ2_bzDecompress(&stream);
-        if ( ret == BZ_STREAM_END )
-        {
-            DOMPRINTF("BZIP2: Saw data stream end");
-            retval = 0;
-            break;
-        }
-        if ( ret != BZ_OK )
-        {
-            DOMPRINTF("BZIP2: error %d", ret);
-            free(out_buf);
-            goto bzip2_cleanup;
-        }
-
-        if ( stream.avail_out == 0 )
-        {
-            /* Protect against output buffer overflow */
-            if ( outsize > UINT_MAX / 2 )
-            {
-                DOMPRINTF("BZIP2: output buffer overflow");
-                free(out_buf);
-                goto bzip2_cleanup;
-            }
-
-            if ( xc_dom_kernel_check_size(dom, outsize * 2) )
-            {
-                DOMPRINTF("BZIP2: output too large");
-                free(out_buf);
-                goto bzip2_cleanup;
-            }
-
-            tmp_buf = realloc(out_buf, outsize * 2);
-            if ( tmp_buf == NULL )
-            {
-                DOMPRINTF("BZIP2: Failed to realloc memory");
-                free(out_buf);
-                goto bzip2_cleanup;
-            }
-            out_buf = tmp_buf;
-
-            stream.next_out = out_buf + outsize;
-            stream.avail_out = (outsize * 2) - outsize;
-            outsize *= 2;
-        }
-        else if ( stream.avail_in == 0 )
-        {
-            /*
-             * If there is output buffer available then this indicates
-             * that BZ2_bzDecompress would like more input data to be
-             * provided.  However our complete input buffer is in
-             * memory and provided upfront so if avail_in is zero this
-             * actually indicates a truncated input.
-             */
-            DOMPRINTF("BZIP2: not enough input");
-            free(out_buf);
-            goto bzip2_cleanup;
-        }
-    }
-
-    total = (((uint64_t)stream.total_out_hi32) << 32) | stream.total_out_lo32;
-
-    DOMPRINTF("%s: BZIP2 decompress OK, 0x%zx -> 0x%lx",
-              __FUNCTION__, *size, (long unsigned int) total);
-
-    *blob = out_buf;
-    *size = total;
-
- bzip2_cleanup:
-    BZ2_bzDecompressEnd(&stream);
-
-    return retval;
-}
-
-#else /* !defined(HAVE_BZLIB) */
-
-static int xc_try_bzip2_decode(
-    struct xc_dom_image *dom, void **blob, size_t *size)
-{
-    DOMPRINTF("%s: BZIP2 decompress support unavailable",
-              __FUNCTION__);
-    return -1;
-}
-
-#endif
-
-#if defined(HAVE_LZMA)
-
-#include <lzma.h>
-
-static int _xc_try_lzma_decode(
-    struct xc_dom_image *dom, void **blob, size_t *size,
-    lzma_stream *stream, const char *what)
-{
-    lzma_ret ret;
-    lzma_action action = LZMA_RUN;
-    unsigned char *out_buf;
-    unsigned char *tmp_buf;
-    int retval = -1;
-    size_t outsize;
-    const char *msg;
-
-    if ( dom->kernel_size == 0)
-    {
-        DOMPRINTF("%s: Input is 0 size", what);
-        return -1;
-    }
-
-    /* sigh.  We don't know up-front how much memory we are going to need
-     * for the output buffer.  Allocate the output buffer to be equal
-     * the input buffer to start, and we'll realloc as needed.
-     */
-    outsize = dom->kernel_size;
-    out_buf = malloc(outsize);
-    if ( out_buf == NULL )
-    {
-        DOMPRINTF("%s: Failed to alloc memory", what);
-        goto lzma_cleanup;
-    }
-
-    stream->next_in = dom->kernel_blob;
-    stream->avail_in = dom->kernel_size;
-
-    stream->next_out = out_buf;
-    stream->avail_out = dom->kernel_size;
-
-    for ( ; ; )
-    {
-        ret = lzma_code(stream, action);
-        if ( ret == LZMA_STREAM_END )
-        {
-            DOMPRINTF("%s: Saw data stream end", what);
-            retval = 0;
-            break;
-        }
-        if ( ret != LZMA_OK )
-        {
-            switch ( ret )
-            {
-            case LZMA_MEM_ERROR:
-                msg = strerror(ENOMEM);
-                break;
-
-            case LZMA_MEMLIMIT_ERROR:
-                msg = "Memory usage limit reached";
-                break;
-
-            case LZMA_FORMAT_ERROR:
-                msg = "File format not recognized";
-                break;
-
-            case LZMA_OPTIONS_ERROR:
-                // FIXME: Better message?
-                msg = "Unsupported compression options";
-                break;
-
-            case LZMA_DATA_ERROR:
-                msg = "File is corrupt";
-                break;
-
-            case LZMA_BUF_ERROR:
-                msg = "Unexpected end of input";
-                break;
-
-            default:
-                msg = "Internal program error (bug)";
-                break;
-            }
-            DOMPRINTF("%s: %s decompression error: %s",
-                      __FUNCTION__, what, msg);
-            free(out_buf);
-            goto lzma_cleanup;
-        }
-
-        if ( stream->avail_out == 0 )
-        {
-            /* Protect against output buffer overflow */
-            if ( outsize > SIZE_MAX / 2 )
-            {
-                DOMPRINTF("%s: output buffer overflow", what);
-                free(out_buf);
-                goto lzma_cleanup;
-            }
-
-            if ( xc_dom_kernel_check_size(dom, outsize * 2) )
-            {
-                DOMPRINTF("%s: output too large", what);
-                free(out_buf);
-                goto lzma_cleanup;
-            }
-
-            tmp_buf = realloc(out_buf, outsize * 2);
-            if ( tmp_buf == NULL )
-            {
-                DOMPRINTF("%s: Failed to realloc memory", what);
-                free(out_buf);
-                goto lzma_cleanup;
-            }
-            out_buf = tmp_buf;
-
-            stream->next_out = out_buf + outsize;
-            stream->avail_out = (outsize * 2) - outsize;
-            outsize *= 2;
-        }
-    }
-
-    DOMPRINTF("%s: %s decompress OK, 0x%zx -> 0x%zx",
-              __FUNCTION__, what, *size, (size_t)stream->total_out);
-
-    *blob = out_buf;
-    *size = stream->total_out;
-
- lzma_cleanup:
-    lzma_end(stream);
-
-    return retval;
-}
-
-/* 128 Mb is the minimum size (half-way) documented to work for all inputs. */
-#define LZMA_BLOCK_SIZE (128*1024*1024)
-
-static int xc_try_xz_decode(
-    struct xc_dom_image *dom, void **blob, size_t *size)
-{
-    lzma_stream stream = LZMA_STREAM_INIT;
-
-    if ( lzma_stream_decoder(&stream, LZMA_BLOCK_SIZE, 0) != LZMA_OK )
-    {
-        DOMPRINTF("XZ: Failed to init decoder");
-        return -1;
-    }
-
-    return _xc_try_lzma_decode(dom, blob, size, &stream, "XZ");
-}
-
-static int xc_try_lzma_decode(
-    struct xc_dom_image *dom, void **blob, size_t *size)
-{
-    lzma_stream stream = LZMA_STREAM_INIT;
-
-    if ( lzma_alone_decoder(&stream, LZMA_BLOCK_SIZE) != LZMA_OK )
-    {
-        DOMPRINTF("LZMA: Failed to init decoder");
-        return -1;
-    }
-
-    return _xc_try_lzma_decode(dom, blob, size, &stream, "LZMA");
-}
-
-#else /* !defined(HAVE_LZMA) */
-
-static int xc_try_xz_decode(
-    struct xc_dom_image *dom, void **blob, size_t *size)
-{
-    DOMPRINTF("%s: XZ decompress support unavailable",
-              __FUNCTION__);
-    return -1;
-}
-
-static int xc_try_lzma_decode(
-    struct xc_dom_image *dom, void **blob, size_t *size)
-{
-    DOMPRINTF("%s: LZMA decompress support unavailable",
-              __FUNCTION__);
-    return -1;
-}
-
-#endif
-
-#if defined(HAVE_LZO1X)
-
-#include <lzo/lzo1x.h>
-
-#define LZOP_HEADER_HAS_FILTER 0x00000800
-#define LZOP_MAX_BLOCK_SIZE (64*1024*1024)
-
-static inline uint_fast16_t lzo_read_16(const unsigned char *buf)
-{
-    return buf[1] | (buf[0] << 8);
-}
-
-static inline uint_fast32_t lzo_read_32(const unsigned char *buf)
-{
-    return lzo_read_16(buf + 2) | ((uint32_t)lzo_read_16(buf) << 16);
-}
-
-static int xc_try_lzo1x_decode(
-    struct xc_dom_image *dom, void **blob, size_t *size)
-{
-    int ret;
-    const unsigned char *cur = dom->kernel_blob;
-    unsigned char *out_buf = NULL;
-    size_t left = dom->kernel_size;
-    const char *msg;
-    unsigned version;
-    static const unsigned char magic[] = {
-        0x89, 0x4c, 0x5a, 0x4f, 0x00, 0x0d, 0x0a, 0x1a, 0x0a
-    };
-
-    /*
-     * lzo_uint should match size_t. Check that this is the case to be
-     * sure we won't overflow various lzo_uint fields.
-     */
-    XC_BUILD_BUG_ON(sizeof(lzo_uint) != sizeof(size_t));
-
-    ret = lzo_init();
-    if ( ret != LZO_E_OK )
-    {
-        DOMPRINTF("LZO1x: Failed to init library (%d)\n", ret);
-        return -1;
-    }
-
-    if ( left < 16 || memcmp(cur, magic, 9) )
-    {
-        DOMPRINTF("LZO1x: Unrecognized magic\n");
-        return -1;
-    }
-
-    /* get version (2bytes), skip library version (2),
-     * 'need to be extracted' version (2) and method (1) */
-    version = lzo_read_16(cur + 9);
-    cur += 16;
-    left -= 16;
-
-    if ( version >= 0x0940 )
-    {
-        /* skip level */
-        ++cur;
-        if ( left )
-            --left;
-    }
-
-    if ( left >= 4 && (lzo_read_32(cur) & LZOP_HEADER_HAS_FILTER) )
-        ret = 8; /* flags + filter info */
-    else
-        ret = 4; /* flags */
-
-    /* skip mode and mtime_low */
-    ret += 8;
-    if ( version >= 0x0940 )
-        ret += 4; /* skip mtime_high */
-
-    /* don't care about the file name, and skip checksum */
-    if ( left > ret )
-        ret += 1 + cur[ret] + 4;
-
-    if ( left < ret )
-    {
-        DOMPRINTF("LZO1x: Incomplete header\n");
-        return -1;
-    }
-    cur += ret;
-    left -= ret;
-
-    for ( *size = 0; ; )
-    {
-        lzo_uint src_len, dst_len, out_len;
-        unsigned char *tmp_buf;
-
-        msg = "Short input";
-        if ( left < 4 )
-            break;
-
-        dst_len = lzo_read_32(cur);
-        if ( !dst_len )
-            return 0;
-
-        if ( dst_len > LZOP_MAX_BLOCK_SIZE )
-        {
-            msg = "Block size too large";
-            break;
-        }
-
-        if ( left < 12 )
-            break;
-
-        src_len = lzo_read_32(cur + 4);
-        cur += 12; /* also skip block checksum info */
-        left -= 12;
-
-        msg = "Bad source length";
-        if ( src_len <= 0 || src_len > dst_len || src_len > left )
-            break;
-
-        msg = "Output buffer overflow";
-        if ( *size > SIZE_MAX - dst_len )
-            break;
-
-        msg = "Decompressed image too large";
-        if ( xc_dom_kernel_check_size(dom, *size + dst_len) )
-            break;
-
-        msg = "Failed to (re)alloc memory";
-        tmp_buf = realloc(out_buf, *size + dst_len);
-        if ( tmp_buf == NULL )
-            break;
-
-        out_buf = tmp_buf;
-        out_len = dst_len;
-
-        ret = lzo1x_decompress_safe(cur, src_len,
-                                    out_buf + *size, &out_len, NULL);
-        switch ( ret )
-        {
-        case LZO_E_OK:
-            msg = "Input underrun";
-            if ( out_len != dst_len )
-                break;
-
-            *blob = out_buf;
-            *size += out_len;
-            cur += src_len;
-            left -= src_len;
-            continue;
-
-        case LZO_E_INPUT_NOT_CONSUMED:
-            msg = "Unconsumed input";
-            break;
-
-        case LZO_E_OUTPUT_OVERRUN:
-            msg = "Output overrun";
-            break;
-
-        case LZO_E_INPUT_OVERRUN:
-            msg = "Input overrun";
-            break;
-
-        case LZO_E_LOOKBEHIND_OVERRUN:
-            msg = "Look-behind overrun";
-            break;
-
-        case LZO_E_EOF_NOT_FOUND:
-            msg = "No EOF marker";
-            break;
-
-        case LZO_E_ERROR:
-            msg = "General error";
-            break;
-
-        default:
-            msg = "Internal program error (bug)";
-            break;
-        }
-
-        break;
-    }
-
-    free(out_buf);
-    DOMPRINTF("LZO1x decompression error: %s\n", msg);
-
-    return -1;
-}
-
-#else /* !defined(HAVE_LZO1X) */
-
-static int xc_try_lzo1x_decode(
-    struct xc_dom_image *dom, void **blob, size_t *size)
-{
-    DOMPRINTF("%s: LZO1x decompress support unavailable\n",
-                  __FUNCTION__);
-    return -1;
-}
-
-#endif
-
 struct setup_header {
     uint8_t  _pad0[0x1f1];  /* skip uninteresting stuff */
     uint8_t  setup_sects;
diff -r 66f563be41d9 tools/libxc/xc_dom_decompress.c
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/libxc/xc_dom_decompress.c   Tue Feb 26 19:23:05 2013 +0100
@@ -0,0 +1,567 @@
+/*
+ * Xen decompression wrapper
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation;
+ * version 2.1 of the License.
+ *
+ * This library 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 this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  
USA
+ *
+ * written 2006 by Gerd Hoffmann <kraxel@xxxxxxx>.
+ * written 2007 by Jeremy Fitzhardinge <jeremy@xxxxxxxxxxxxx>
+ * written 2008 by Ian Campbell <ijc@xxxxxxxxxxxxxx>
+ * written 2009 by Chris Lalancette <clalance@xxxxxxxxxx>
+ *
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <inttypes.h>
+
+#include "xg_private.h"
+#include "xc_dom.h"
+
+#if defined(HAVE_BZLIB)
+
+#include <bzlib.h>
+
+int xc_try_bzip2_decode(
+    struct xc_dom_image *dom, void **blob, size_t *size)
+{
+    bz_stream stream;
+    int ret;
+    char *out_buf;
+    char *tmp_buf;
+    int retval = -1;
+    unsigned int outsize;
+    uint64_t total;
+
+    stream.bzalloc = NULL;
+    stream.bzfree = NULL;
+    stream.opaque = NULL;
+
+    if ( dom->kernel_size == 0)
+    {
+        DOMPRINTF("BZIP2: Input is 0 size");
+        return -1;
+    }
+
+    ret = BZ2_bzDecompressInit(&stream, 0, 0);
+    if ( ret != BZ_OK )
+    {
+        DOMPRINTF("BZIP2: Error initting stream");
+        return -1;
+    }
+
+    /* sigh.  We don't know up-front how much memory we are going to need
+     * for the output buffer.  Allocate the output buffer to be equal
+     * the input buffer to start, and we'll realloc as needed.
+     */
+    outsize = dom->kernel_size;
+
+    /*
+     * stream.avail_in and outsize are unsigned int, while kernel_size
+     * is a size_t. Check we aren't overflowing.
+     */
+    if ( outsize != dom->kernel_size )
+    {
+        DOMPRINTF("BZIP2: Input too large");
+        goto bzip2_cleanup;
+    }
+
+    out_buf = malloc(outsize);
+    if ( out_buf == NULL )
+    {
+        DOMPRINTF("BZIP2: Failed to alloc memory");
+        goto bzip2_cleanup;
+    }
+
+    stream.next_in = dom->kernel_blob;
+    stream.avail_in = dom->kernel_size;
+
+    stream.next_out = out_buf;
+    stream.avail_out = dom->kernel_size;
+
+    for ( ; ; )
+    {
+        ret = BZ2_bzDecompress(&stream);
+        if ( ret == BZ_STREAM_END )
+        {
+            DOMPRINTF("BZIP2: Saw data stream end");
+            retval = 0;
+            break;
+        }
+        if ( ret != BZ_OK )
+        {
+            DOMPRINTF("BZIP2: error %d", ret);
+            free(out_buf);
+            goto bzip2_cleanup;
+        }
+
+        if ( stream.avail_out == 0 )
+        {
+            /* Protect against output buffer overflow */
+            if ( outsize > UINT_MAX / 2 )
+            {
+                DOMPRINTF("BZIP2: output buffer overflow");
+                free(out_buf);
+                goto bzip2_cleanup;
+            }
+
+            if ( xc_dom_kernel_check_size(dom, outsize * 2) )
+            {
+                DOMPRINTF("BZIP2: output too large");
+                free(out_buf);
+                goto bzip2_cleanup;
+            }
+
+            tmp_buf = realloc(out_buf, outsize * 2);
+            if ( tmp_buf == NULL )
+            {
+                DOMPRINTF("BZIP2: Failed to realloc memory");
+                free(out_buf);
+                goto bzip2_cleanup;
+            }
+            out_buf = tmp_buf;
+
+            stream.next_out = out_buf + outsize;
+            stream.avail_out = (outsize * 2) - outsize;
+            outsize *= 2;
+        }
+        else if ( stream.avail_in == 0 )
+        {
+            /*
+             * If there is output buffer available then this indicates
+             * that BZ2_bzDecompress would like more input data to be
+             * provided.  However our complete input buffer is in
+             * memory and provided upfront so if avail_in is zero this
+             * actually indicates a truncated input.
+             */
+            DOMPRINTF("BZIP2: not enough input");
+            free(out_buf);
+            goto bzip2_cleanup;
+        }
+    }
+
+    total = (((uint64_t)stream.total_out_hi32) << 32) | stream.total_out_lo32;
+
+    DOMPRINTF("%s: BZIP2 decompress OK, 0x%zx -> 0x%lx",
+              __FUNCTION__, *size, (long unsigned int) total);
+
+    *blob = out_buf;
+    *size = total;
+
+ bzip2_cleanup:
+    BZ2_bzDecompressEnd(&stream);
+
+    return retval;
+}
+
+#else /* !defined(HAVE_BZLIB) */
+
+int xc_try_bzip2_decode(
+    struct xc_dom_image *dom, void **blob, size_t *size)
+{
+    DOMPRINTF("%s: BZIP2 decompress support unavailable",
+              __FUNCTION__);
+    return -1;
+}
+
+#endif
+
+#if defined(HAVE_LZMA)
+
+#include <lzma.h>
+
+static int _xc_try_lzma_decode(
+    struct xc_dom_image *dom, void **blob, size_t *size,
+    lzma_stream *stream, const char *what)
+{
+    lzma_ret ret;
+    lzma_action action = LZMA_RUN;
+    unsigned char *out_buf;
+    unsigned char *tmp_buf;
+    int retval = -1;
+    size_t outsize;
+    const char *msg;
+
+    if ( dom->kernel_size == 0)
+    {
+        DOMPRINTF("%s: Input is 0 size", what);
+        return -1;
+    }
+
+    /* sigh.  We don't know up-front how much memory we are going to need
+     * for the output buffer.  Allocate the output buffer to be equal
+     * the input buffer to start, and we'll realloc as needed.
+     */
+    outsize = dom->kernel_size;
+    out_buf = malloc(outsize);
+    if ( out_buf == NULL )
+    {
+        DOMPRINTF("%s: Failed to alloc memory", what);
+        goto lzma_cleanup;
+    }
+
+    stream->next_in = dom->kernel_blob;
+    stream->avail_in = dom->kernel_size;
+
+    stream->next_out = out_buf;
+    stream->avail_out = dom->kernel_size;
+
+    for ( ; ; )
+    {
+        ret = lzma_code(stream, action);
+        if ( ret == LZMA_STREAM_END )
+        {
+            DOMPRINTF("%s: Saw data stream end", what);
+            retval = 0;
+            break;
+        }
+        if ( ret != LZMA_OK )
+        {
+            switch ( ret )
+            {
+            case LZMA_MEM_ERROR:
+                msg = strerror(ENOMEM);
+                break;
+
+            case LZMA_MEMLIMIT_ERROR:
+                msg = "Memory usage limit reached";
+                break;
+
+            case LZMA_FORMAT_ERROR:
+                msg = "File format not recognized";
+                break;
+
+            case LZMA_OPTIONS_ERROR:
+                // FIXME: Better message?
+                msg = "Unsupported compression options";
+                break;
+
+            case LZMA_DATA_ERROR:
+                msg = "File is corrupt";
+                break;
+
+            case LZMA_BUF_ERROR:
+                msg = "Unexpected end of input";
+                break;
+
+            default:
+                msg = "Internal program error (bug)";
+                break;
+            }
+            DOMPRINTF("%s: %s decompression error: %s",
+                      __FUNCTION__, what, msg);
+            free(out_buf);
+            goto lzma_cleanup;
+        }
+
+        if ( stream->avail_out == 0 )
+        {
+            /* Protect against output buffer overflow */
+            if ( outsize > SIZE_MAX / 2 )
+            {
+                DOMPRINTF("%s: output buffer overflow", what);
+                free(out_buf);
+                goto lzma_cleanup;
+            }
+
+            if ( xc_dom_kernel_check_size(dom, outsize * 2) )
+            {
+                DOMPRINTF("%s: output too large", what);
+                free(out_buf);
+                goto lzma_cleanup;
+            }
+
+            tmp_buf = realloc(out_buf, outsize * 2);
+            if ( tmp_buf == NULL )
+            {
+                DOMPRINTF("%s: Failed to realloc memory", what);
+                free(out_buf);
+                goto lzma_cleanup;
+            }
+            out_buf = tmp_buf;
+
+            stream->next_out = out_buf + outsize;
+            stream->avail_out = (outsize * 2) - outsize;
+            outsize *= 2;
+        }
+    }
+
+    DOMPRINTF("%s: %s decompress OK, 0x%zx -> 0x%zx",
+              __FUNCTION__, what, *size, (size_t)stream->total_out);
+
+    *blob = out_buf;
+    *size = stream->total_out;
+
+ lzma_cleanup:
+    lzma_end(stream);
+
+    return retval;
+}
+
+/* 128 Mb is the minimum size (half-way) documented to work for all inputs. */
+#define LZMA_BLOCK_SIZE (128*1024*1024)
+
+int xc_try_xz_decode(
+    struct xc_dom_image *dom, void **blob, size_t *size)
+{
+    lzma_stream stream = LZMA_STREAM_INIT;
+
+    if ( lzma_stream_decoder(&stream, LZMA_BLOCK_SIZE, 0) != LZMA_OK )
+    {
+        DOMPRINTF("XZ: Failed to init decoder");
+        return -1;
+    }
+
+    return _xc_try_lzma_decode(dom, blob, size, &stream, "XZ");
+}
+
+int xc_try_lzma_decode(
+    struct xc_dom_image *dom, void **blob, size_t *size)
+{
+    lzma_stream stream = LZMA_STREAM_INIT;
+
+    if ( lzma_alone_decoder(&stream, LZMA_BLOCK_SIZE) != LZMA_OK )
+    {
+        DOMPRINTF("LZMA: Failed to init decoder");
+        return -1;
+    }
+
+    return _xc_try_lzma_decode(dom, blob, size, &stream, "LZMA");
+}
+
+#else /* !defined(HAVE_LZMA) */
+
+int xc_try_xz_decode(
+    struct xc_dom_image *dom, void **blob, size_t *size)
+{
+    DOMPRINTF("%s: XZ decompress support unavailable",
+              __FUNCTION__);
+    return -1;
+}
+
+int xc_try_lzma_decode(
+    struct xc_dom_image *dom, void **blob, size_t *size)
+{
+    DOMPRINTF("%s: LZMA decompress support unavailable",
+              __FUNCTION__);
+    return -1;
+}
+
+#endif
+
+#if defined(HAVE_LZO1X)
+
+#include <lzo/lzo1x.h>
+
+#define LZOP_HEADER_HAS_FILTER 0x00000800
+#define LZOP_MAX_BLOCK_SIZE (64*1024*1024)
+
+static inline uint_fast16_t lzo_read_16(const unsigned char *buf)
+{
+    return buf[1] | (buf[0] << 8);
+}
+
+static inline uint_fast32_t lzo_read_32(const unsigned char *buf)
+{
+    return lzo_read_16(buf + 2) | ((uint32_t)lzo_read_16(buf) << 16);
+}
+
+int xc_try_lzo1x_decode(
+    struct xc_dom_image *dom, void **blob, size_t *size)
+{
+    int ret;
+    const unsigned char *cur = dom->kernel_blob;
+    unsigned char *out_buf = NULL;
+    size_t left = dom->kernel_size;
+    const char *msg;
+    unsigned version;
+    static const unsigned char magic[] = {
+        0x89, 0x4c, 0x5a, 0x4f, 0x00, 0x0d, 0x0a, 0x1a, 0x0a
+    };
+
+    /*
+     * lzo_uint should match size_t. Check that this is the case to be
+     * sure we won't overflow various lzo_uint fields.
+     */
+    XC_BUILD_BUG_ON(sizeof(lzo_uint) != sizeof(size_t));
+
+    ret = lzo_init();
+    if ( ret != LZO_E_OK )
+    {
+        DOMPRINTF("LZO1x: Failed to init library (%d)\n", ret);
+        return -1;
+    }
+
+    if ( left < 16 || memcmp(cur, magic, 9) )
+    {
+        DOMPRINTF("LZO1x: Unrecognized magic\n");
+        return -1;
+    }
+
+    /* get version (2bytes), skip library version (2),
+     * 'need to be extracted' version (2) and method (1) */
+    version = lzo_read_16(cur + 9);
+    cur += 16;
+    left -= 16;
+
+    if ( version >= 0x0940 )
+    {
+        /* skip level */
+        ++cur;
+        if ( left )
+            --left;
+    }
+
+    if ( left >= 4 && (lzo_read_32(cur) & LZOP_HEADER_HAS_FILTER) )
+        ret = 8; /* flags + filter info */
+    else
+        ret = 4; /* flags */
+
+    /* skip mode and mtime_low */
+    ret += 8;
+    if ( version >= 0x0940 )
+        ret += 4; /* skip mtime_high */
+
+    /* don't care about the file name, and skip checksum */
+    if ( left > ret )
+        ret += 1 + cur[ret] + 4;
+
+    if ( left < ret )
+    {
+        DOMPRINTF("LZO1x: Incomplete header\n");
+        return -1;
+    }
+    cur += ret;
+    left -= ret;
+
+    for ( *size = 0; ; )
+    {
+        lzo_uint src_len, dst_len, out_len;
+        unsigned char *tmp_buf;
+
+        msg = "Short input";
+        if ( left < 4 )
+            break;
+
+        dst_len = lzo_read_32(cur);
+        if ( !dst_len )
+            return 0;
+
+        if ( dst_len > LZOP_MAX_BLOCK_SIZE )
+        {
+            msg = "Block size too large";
+            break;
+        }
+
+        if ( left < 12 )
+            break;
+
+        src_len = lzo_read_32(cur + 4);
+        cur += 12; /* also skip block checksum info */
+        left -= 12;
+
+        msg = "Bad source length";
+        if ( src_len <= 0 || src_len > dst_len || src_len > left )
+            break;
+
+        msg = "Output buffer overflow";
+        if ( *size > SIZE_MAX - dst_len )
+            break;
+
+        msg = "Decompressed image too large";
+        if ( xc_dom_kernel_check_size(dom, *size + dst_len) )
+            break;
+
+        msg = "Failed to (re)alloc memory";
+        tmp_buf = realloc(out_buf, *size + dst_len);
+        if ( tmp_buf == NULL )
+            break;
+
+        out_buf = tmp_buf;
+        out_len = dst_len;
+
+        ret = lzo1x_decompress_safe(cur, src_len,
+                                    out_buf + *size, &out_len, NULL);
+        switch ( ret )
+        {
+        case LZO_E_OK:
+            msg = "Input underrun";
+            if ( out_len != dst_len )
+                break;
+
+            *blob = out_buf;
+            *size += out_len;
+            cur += src_len;
+            left -= src_len;
+            continue;
+
+        case LZO_E_INPUT_NOT_CONSUMED:
+            msg = "Unconsumed input";
+            break;
+
+        case LZO_E_OUTPUT_OVERRUN:
+            msg = "Output overrun";
+            break;
+
+        case LZO_E_INPUT_OVERRUN:
+            msg = "Input overrun";
+            break;
+
+        case LZO_E_LOOKBEHIND_OVERRUN:
+            msg = "Look-behind overrun";
+            break;
+
+        case LZO_E_EOF_NOT_FOUND:
+            msg = "No EOF marker";
+            break;
+
+        case LZO_E_ERROR:
+            msg = "General error";
+            break;
+
+        default:
+            msg = "Internal program error (bug)";
+            break;
+        }
+
+        break;
+    }
+
+    free(out_buf);
+    DOMPRINTF("LZO1x decompression error: %s\n", msg);
+
+    return -1;
+}
+
+#else /* !defined(HAVE_LZO1X) */
+
+int xc_try_lzo1x_decode(
+    struct xc_dom_image *dom, void **blob, size_t *size)
+{
+    DOMPRINTF("%s: LZO1x decompress support unavailable\n",
+                  __FUNCTION__);
+    return -1;
+}
+
+#endif
+
+/*
+ * Local variables:
+ * mode: C
+ * c-set-style: "BSD"
+ * c-basic-offset: 4
+ * tab-width: 4
+ * indent-tabs-mode: nil
+ * End:
+ */

_______________________________________________
Xen-devel mailing list
Xen-devel@xxxxxxxxxxxxx
http://lists.xen.org/xen-devel


 


Rackspace

Lists.xenproject.org is hosted with RackSpace, monitoring our
servers 24x7x365 and backed by RackSpace's Fanatical Support®.