summary refs log tree commit diff stats
diff options
context:
space:
mode:
-rw-r--r--block/Makefile.objs3
-rw-r--r--block/dmg-bz2.c61
-rw-r--r--block/dmg.c69
-rw-r--r--block/dmg.h59
-rw-r--r--scripts/modules/module_block.py7
-rw-r--r--util/module.c18
6 files changed, 155 insertions, 62 deletions
diff --git a/block/Makefile.objs b/block/Makefile.objs
index 7d4031dae5..67a036a1df 100644
--- a/block/Makefile.objs
+++ b/block/Makefile.objs
@@ -41,6 +41,7 @@ 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)
+block-obj-$(if $(CONFIG_BZIP2),m,n) += dmg-bz2.o
+dmg-bz2.o-libs     := $(BZIP2_LIBS)
 qcow.o-libs        := -lz
 linux-aio.o-libs   := -laio
diff --git a/block/dmg-bz2.c b/block/dmg-bz2.c
new file mode 100644
index 0000000000..9059492a9f
--- /dev/null
+++ b/block/dmg-bz2.c
@@ -0,0 +1,61 @@
+/*
+ * DMG bzip2 uncompression
+ *
+ * Copyright (c) 2004 Johannes E. Schindelin
+ * Copyright (c) 2016 Red Hat, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+#include "qemu/osdep.h"
+#include "qemu-common.h"
+#include "dmg.h"
+#include <bzlib.h>
+
+static int dmg_uncompress_bz2_do(char *next_in, unsigned int avail_in,
+                                 char *next_out, unsigned int avail_out)
+{
+    int ret;
+    uint64_t total_out;
+    bz_stream bzstream = {};
+
+    ret = BZ2_bzDecompressInit(&bzstream, 0, 0);
+    if (ret != BZ_OK) {
+        return -1;
+    }
+    bzstream.next_in = next_in;
+    bzstream.avail_in = avail_in;
+    bzstream.next_out = next_out;
+    bzstream.avail_out = avail_out;
+    ret = BZ2_bzDecompress(&bzstream);
+    total_out = ((uint64_t)bzstream.total_out_hi32 << 32) +
+                bzstream.total_out_lo32;
+    BZ2_bzDecompressEnd(&bzstream);
+    if (ret != BZ_STREAM_END ||
+        total_out != avail_out) {
+        return -1;
+    }
+    return 0;
+}
+
+__attribute__((constructor))
+static void dmg_bz2_init(void)
+{
+    assert(!dmg_uncompress_bz2);
+    dmg_uncompress_bz2 = dmg_uncompress_bz2_do;
+}
diff --git a/block/dmg.c b/block/dmg.c
index b0ed89baa7..58a3ae86c1 100644
--- a/block/dmg.c
+++ b/block/dmg.c
@@ -28,10 +28,10 @@
 #include "qemu/bswap.h"
 #include "qemu/error-report.h"
 #include "qemu/module.h"
-#include <zlib.h>
-#ifdef CONFIG_BZIP2
-#include <bzlib.h>
-#endif
+#include "dmg.h"
+
+int (*dmg_uncompress_bz2)(char *next_in, unsigned int avail_in,
+                          char *next_out, unsigned int avail_out);
 
 enum {
     /* Limit chunk sizes to prevent unreasonable amounts of memory being used
@@ -41,31 +41,6 @@ enum {
     DMG_SECTORCOUNTS_MAX = DMG_LENGTHS_MAX / 512,
 };
 
-typedef struct BDRVDMGState {
-    CoMutex lock;
-    /* each chunk contains a certain number of sectors,
-     * offsets[i] is the offset in the .dmg file,
-     * lengths[i] is the length of the compressed chunk,
-     * sectors[i] is the sector beginning at offsets[i],
-     * sectorcounts[i] is the number of sectors in that chunk,
-     * the sectors array is ordered
-     * 0<=i<n_chunks */
-
-    uint32_t n_chunks;
-    uint32_t* types;
-    uint64_t* offsets;
-    uint64_t* lengths;
-    uint64_t* sectors;
-    uint64_t* sectorcounts;
-    uint32_t current_chunk;
-    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)
 {
     int len;
@@ -210,10 +185,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;
+    case 0x80000006:    /* bzip2 */
+        return !!dmg_uncompress_bz2;
     default:
         return false;
     }
@@ -439,6 +413,7 @@ static int dmg_open(BlockDriverState *bs, QDict *options, int flags,
     int64_t offset;
     int ret;
 
+    block_module_load_one("dmg-bz2");
     bs->read_only = true;
 
     s->n_chunks = 0;
@@ -587,9 +562,6 @@ 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;
@@ -620,8 +592,10 @@ static inline int dmg_read_chunk(BlockDriverState *bs, uint64_t sector_num)
                 return -1;
             }
             break; }
-#ifdef CONFIG_BZIP2
         case 0x80000006: /* bzip2 compressed */
+            if (!dmg_uncompress_bz2) {
+                break;
+            }
             /* we need to buffer, because only the chunk as whole can be
              * inflated. */
             ret = bdrv_pread(bs->file, s->offsets[chunk],
@@ -630,24 +604,15 @@ static inline int dmg_read_chunk(BlockDriverState *bs, uint64_t sector_num)
                 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;
+            ret = dmg_uncompress_bz2((char *)s->compressed_chunk,
+                                     (unsigned int) s->lengths[chunk],
+                                     (char *)s->uncompressed_chunk,
+                                     (unsigned int)
+                                         (512 * s->sectorcounts[chunk]));
+            if (ret < 0) {
+                return ret;
             }
             break;
-#endif /* CONFIG_BZIP2 */
         case 1: /* copy */
             ret = bdrv_pread(bs->file, s->offsets[chunk],
                              s->uncompressed_chunk, s->lengths[chunk]);
diff --git a/block/dmg.h b/block/dmg.h
new file mode 100644
index 0000000000..b592d6fa8b
--- /dev/null
+++ b/block/dmg.h
@@ -0,0 +1,59 @@
+/*
+ * Header for DMG driver
+ *
+ * Copyright (c) 2004-2006 Fabrice Bellard
+ * Copyright (c) 2016 Red hat, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#ifndef BLOCK_DMG_H
+#define BLOCK_DMG_H
+
+#include "qemu/osdep.h"
+#include "qemu-common.h"
+#include "block/block_int.h"
+#include <zlib.h>
+
+typedef struct BDRVDMGState {
+    CoMutex lock;
+    /* each chunk contains a certain number of sectors,
+     * offsets[i] is the offset in the .dmg file,
+     * lengths[i] is the length of the compressed chunk,
+     * sectors[i] is the sector beginning at offsets[i],
+     * sectorcounts[i] is the number of sectors in that chunk,
+     * the sectors array is ordered
+     * 0<=i<n_chunks */
+
+    uint32_t n_chunks;
+    uint32_t *types;
+    uint64_t *offsets;
+    uint64_t *lengths;
+    uint64_t *sectors;
+    uint64_t *sectorcounts;
+    uint32_t current_chunk;
+    uint8_t *compressed_chunk;
+    uint8_t *uncompressed_chunk;
+    z_stream zstream;
+} BDRVDMGState;
+
+extern int (*dmg_uncompress_bz2)(char *next_in, unsigned int avail_in,
+                                 char *next_out, unsigned int avail_out);
+
+#endif
diff --git a/scripts/modules/module_block.py b/scripts/modules/module_block.py
index db4fb540cd..3f73007640 100644
--- a/scripts/modules/module_block.py
+++ b/scripts/modules/module_block.py
@@ -37,7 +37,6 @@ def add_module(fheader, library, format_name, protocol_name):
 def process_file(fheader, filename):
     # This parser assumes the coding style rules are being followed
     with open(filename, "r") as cfile:
-        found_something = False
         found_start = False
         library, _ = os.path.splitext(os.path.basename(filename))
         for line in cfile:
@@ -51,16 +50,10 @@ def process_file(fheader, filename):
                     add_module(fheader, library, format_name, protocol_name)
                     found_start = False
             elif line.find("static BlockDriver") != -1:
-                found_something = True
                 found_start = True
                 format_name = ""
                 protocol_name = ""
 
-        if not found_something:
-            print("No BlockDriver struct found in " + filename + ". \
-                    Is this really a module?", file=sys.stderr)
-            sys.exit(1)
-
 def print_top(fheader):
     fheader.write('''/* AUTOMATICALLY GENERATED, DO NOT MODIFY */
 /*
diff --git a/util/module.c b/util/module.c
index a5f7fbd941..c90973721f 100644
--- a/util/module.c
+++ b/util/module.c
@@ -163,14 +163,28 @@ void module_load_one(const char *prefix, const char *lib_name)
     char *fname = NULL;
     char *exec_dir;
     char *dirs[3];
+    char *module_name;
     int i = 0;
     int ret;
+    static GHashTable *loaded_modules;
 
     if (!g_module_supported()) {
         fprintf(stderr, "Module is not supported by system.\n");
         return;
     }
 
+    if (!loaded_modules) {
+        loaded_modules = g_hash_table_new(g_str_hash, g_str_equal);
+    }
+
+    module_name = g_strdup_printf("%s%s", prefix, lib_name);
+
+    if (g_hash_table_lookup(loaded_modules, module_name)) {
+        g_free(module_name);
+        return;
+    }
+    g_hash_table_insert(loaded_modules, module_name, module_name);
+
     exec_dir = qemu_get_exec_dir();
     dirs[i++] = g_strdup_printf("%s", CONFIG_QEMU_MODDIR);
     dirs[i++] = g_strdup_printf("%s/..", exec_dir ? : "");
@@ -180,8 +194,8 @@ void module_load_one(const char *prefix, const char *lib_name)
     exec_dir = NULL;
 
     for (i = 0; i < ARRAY_SIZE(dirs); i++) {
-        fname = g_strdup_printf("%s/%s%s%s",
-                dirs[i], prefix, lib_name, HOST_DSOSUF);
+        fname = g_strdup_printf("%s/%s%s",
+                dirs[i], module_name, HOST_DSOSUF);
         ret = module_load_file(fname);
         g_free(fname);
         fname = NULL;