qemu-devel.nongnu.org archive mirror
 help / color / mirror / Atom feed
* [Qemu-devel] [PATCH v2 0/6] parallels format support improvements
@ 2014-10-29 13:38 Denis V. Lunev
  2014-10-29 13:38 ` [Qemu-devel] [PATCH 1/6] configure: add dependency from libxml2 Denis V. Lunev
                   ` (5 more replies)
  0 siblings, 6 replies; 15+ messages in thread
From: Denis V. Lunev @ 2014-10-29 13:38 UTC (permalink / raw)
  Cc: Kevin Wolf, Jeff Cody, qemu-devel, Stefan Hajnoczi, Roman Kagan

The patchset implements additional compatibility bits for Parallels
format:
- initial support of parsing of Parallels DiskDeskriptor.xml
  Typically Parallels disk bundle consists of several images which are
  glued by XML disk descriptor. Also XML hides inside several important
  parameters which are not available in the image header.
- support for padded Parallels images.
  For the time being Parallels was created an optimization for such OSes
  in its desktop product. Desktop users are not qualified enough to create
  properly aligned installations. Thus Parallels makes a blind guess
  on a customer behalf and creates so-called "padded" images if guest
  OS type is specified as WinXP, Win2k and Win2k3.

The code uses approach from VMDK support, either image or XML descriptor
could be used. Though there is temporary hack in the opening code:
BlockDriverState->file is being reopened inside parallels_open. I prefer
to keep this code in this state till proper Parallels snapshots support
in order to minimize current changes.

Changes from v1:
- dropped already merged part (original patches 1-3)

CC: Jeff Cody <jcody@redhat.com>
CC: Kevin Wolf <kwolf@redhat.com>
CC: Stefan Hajnoczi <stefanha@redhat.com>
CC: Roman Kagan <rkagan@parallels.com>

^ permalink raw reply	[flat|nested] 15+ messages in thread

* [Qemu-devel] [PATCH 1/6] configure: add dependency from libxml2
  2014-10-29 13:38 [Qemu-devel] [PATCH v2 0/6] parallels format support improvements Denis V. Lunev
@ 2014-10-29 13:38 ` Denis V. Lunev
  2014-11-05  7:32   ` Michael Tokarev
  2014-10-29 13:38 ` [Qemu-devel] [PATCH 2/6] block/parallels: allow to specify DiskDescriptor.xml instead of image file Denis V. Lunev
                   ` (4 subsequent siblings)
  5 siblings, 1 reply; 15+ messages in thread
From: Denis V. Lunev @ 2014-10-29 13:38 UTC (permalink / raw)
  Cc: Kevin Wolf, Jeff Cody, qemu-devel, Stefan Hajnoczi, Paolo Bonzini,
	Denis V. Lunev

This dependency is required for adequate Parallels images support.
Typically the disk consists of several images which are glued by
XML disk descriptor. Also XML hides inside several important parameters
which are not available in the image header.

The patch also adds clause to checkpatch.pl to understand libxml2 types.
In the other case there is the following false positive:
    ERROR: need consistent spacing around '*' (ctx:WxB)
    #210: FILE: block/parallels.c:232:
    +   !xmlStrcmp(root->name, (const xmlChar *)"Parallels_disk_image"))

Signed-off-by: Denis V. Lunev <den@openvz.org>
Acked-by: Roman Kagan <rkagan@parallels.com>
CC: Jeff Cody <jcody@redhat.com>
CC: Kevin Wolf <kwolf@redhat.com>
CC: Stefan Hajnoczi <stefanha@redhat.com>
CC: Paolo Bonzini <pbonzini@redhat.com>
---
 configure             | 29 +++++++++++++++++++++++++++++
 scripts/checkpatch.pl |  1 +
 2 files changed, 30 insertions(+)

diff --git a/configure b/configure
index a9e4d49..5426752 100755
--- a/configure
+++ b/configure
@@ -335,6 +335,7 @@ libssh2=""
 vhdx=""
 quorum=""
 numa=""
+libxml2=""
 
 # parse CC options first
 for opt do
@@ -1129,6 +1130,10 @@ for opt do
   ;;
   --enable-numa) numa="yes"
   ;;
+  --disable-libxml2) libxml2="no"
+  ;;
+  --enable-libxml2) libxml2="yes"
+  ;;
   *)
       echo "ERROR: unknown option $opt"
       echo "Try '$0 --help' for more information"
@@ -1400,6 +1405,8 @@ Advanced options (experts only):
   --enable-quorum          enable quorum block filter support
   --disable-numa           disable libnuma support
   --enable-numa            enable libnuma support
+  --disable-libxml2        disable libxml2 (for Parallels image format)
+  --enable-libxml2         enable libxml2 (for Parallels image format)
 
 NOTE: The object files are built at the place where configure is launched
 EOF
@@ -4097,6 +4104,23 @@ if test -z "$zero_malloc" ; then
     fi
 fi
 
+# check for libxml2
+if test "$libxml2" != "no" ; then
+    if $pkg_config --exists libxml-2.0; then
+        libxml2="yes"
+        libxml2_cflags=$($pkg_config --cflags libxml-2.0)
+        libxml2_libs=$($pkg_config --libs libxml-2.0)
+        QEMU_CFLAGS="$QEMU_CFLAGS $libxml2_cflags"
+        libs_softmmu="$libs_softmmu $libxml2_libs"
+        libs_tools="$libs_tools $libxml2_libs"
+    else
+        if test "$libxml2" = "yes"; then
+            feature_not_found "libxml2" "Install libxml2 devel"
+        fi
+        libxml2="no"
+    fi
+fi
+
 # Now we've finished running tests it's OK to add -Werror to the compiler flags
 if test "$werror" = "yes"; then
     QEMU_CFLAGS="-Werror $QEMU_CFLAGS"
@@ -4340,6 +4364,7 @@ echo "Quorum            $quorum"
 echo "lzo support       $lzo"
 echo "snappy support    $snappy"
 echo "NUMA host support $numa"
+echo "libxml2           $libxml2"
 
 if test "$sdl_too_old" = "yes"; then
 echo "-> Your SDL version is too old - please upgrade to have SDL support"
@@ -4846,6 +4871,10 @@ if test "$rdma" = "yes" ; then
   echo "CONFIG_RDMA=y" >> $config_host_mak
 fi
 
+if test "$libxml2" = "yes" ; then
+  echo "CONFIG_LIBXML2=y" >> $config_host_mak
+fi
+
 # Hold two types of flag:
 #   CONFIG_THREAD_SETNAME_BYTHREAD  - we've got a way of setting the name on
 #                                     a thread we have a handle to
diff --git a/scripts/checkpatch.pl b/scripts/checkpatch.pl
index 053e432..3ddb097 100755
--- a/scripts/checkpatch.pl
+++ b/scripts/checkpatch.pl
@@ -242,6 +242,7 @@ our @typeList = (
 	qr{${Ident}_t},
 	qr{${Ident}_handler},
 	qr{${Ident}_handler_fn},
+	qr{xml${Ident}},
 );
 our @modifierList = (
 	qr{fastcall},
-- 
1.9.1

^ permalink raw reply related	[flat|nested] 15+ messages in thread

* [Qemu-devel] [PATCH 2/6] block/parallels: allow to specify DiskDescriptor.xml instead of image file
  2014-10-29 13:38 [Qemu-devel] [PATCH v2 0/6] parallels format support improvements Denis V. Lunev
  2014-10-29 13:38 ` [Qemu-devel] [PATCH 1/6] configure: add dependency from libxml2 Denis V. Lunev
@ 2014-10-29 13:38 ` Denis V. Lunev
  2014-11-05  2:12   ` Jeff Cody
  2014-10-29 13:38 ` [Qemu-devel] [PATCH 3/6] iotests: simple parallels XML disk descriptor file test added Denis V. Lunev
                   ` (3 subsequent siblings)
  5 siblings, 1 reply; 15+ messages in thread
From: Denis V. Lunev @ 2014-10-29 13:38 UTC (permalink / raw)
  Cc: Kevin Wolf, Denis V. Lunev, Jeff Cody, qemu-devel,
	Stefan Hajnoczi

Typically Parallels disk bundle consists of several images which are
glued by XML disk descriptor. Also XML hides inside several important
parameters which are not available in the image header.

This patch allows to specify this XML file as a filename for an image
to open. It is allowed only to open Compressed images with the only
snapshot inside. No additional options are parsed at the moment.

The code itself is dumb enough for a while. If XML file is specified,
the file is parsed and the image is reopened as bs->file to keep the
rest of the driver untouched. This would be changed later with more
features added.

Signed-off-by: Denis V. Lunev <den@openvz.org>
Acked-by: Roman Kagan <rkagan@parallels.com>
CC: Jeff Cody <jcody@redhat.com>
CC: Kevin Wolf <kwolf@redhat.com>
CC: Stefan Hajnoczi <stefanha@redhat.com>
---
 block/parallels.c | 231 ++++++++++++++++++++++++++++++++++++++++++++++++++++--
 1 file changed, 226 insertions(+), 5 deletions(-)

diff --git a/block/parallels.c b/block/parallels.c
index 4f9cd8d..201c0f1 100644
--- a/block/parallels.c
+++ b/block/parallels.c
@@ -27,6 +27,11 @@
 #include "block/block_int.h"
 #include "qemu/module.h"
 
+#if CONFIG_LIBXML2
+#include <libxml/parser.h>
+#include <libxml/tree.h>
+#endif
+
 /**************************************************************/
 
 #define HEADER_MAGIC "WithoutFreeSpace"
@@ -34,6 +39,10 @@
 #define HEADER_VERSION 2
 #define HEADER_SIZE 64
 
+#define PARALLELS_XML       100
+#define PARALLELS_IMAGE     101
+
+
 // always little-endian
 struct parallels_header {
     char magic[16]; // "WithoutFreeSpace"
@@ -59,6 +68,194 @@ typedef struct BDRVParallelsState {
     unsigned int off_multiplier;
 } BDRVParallelsState;
 
+static int parallels_open_image(BlockDriverState *bs, Error **errp);
+
+#if CONFIG_LIBXML2
+static xmlNodePtr xml_find(xmlNode *node, const char *elem)
+{
+    xmlNode *child;
+
+    for (child = node->xmlChildrenNode; child != NULL; child = child->next) {
+        if (!xmlStrcmp(child->name, (const xmlChar *)elem) &&
+                child->type == XML_ELEMENT_NODE) {
+            return child;
+        }
+    }
+    return NULL;
+}
+
+static xmlNodePtr xml_seek(xmlNode *root, const char *elem)
+{
+    xmlNode *child = root;
+    const char *path;
+    char nodename[128];
+    int last = 0;
+
+    path = elem;
+    if (path[0] == '/') {
+        path++;
+    }
+    if (path[0] == 0) {
+        return NULL;
+    }
+    while (!last) {
+        const char *p = strchr(path, '/');
+        int length;
+        if (p == NULL) {
+            length = strlen(path);
+            last = 1;
+        } else {
+            length = p - path;
+        }
+        memcpy(nodename, path, length);
+        nodename[length] = 0;
+        child = xml_find(child, nodename);
+        if (child == NULL) {
+            return NULL;
+        }
+        path = ++p;
+    }
+    return child;
+}
+
+static const char *xml_get_text(xmlNode *node, const char *name)
+{
+    xmlNode *child;
+
+    node = xml_seek(node, name);
+    if (node == NULL) {
+        return NULL;
+    }
+
+    for (child = node->xmlChildrenNode; child; child = child->next) {
+        if (child->type == XML_TEXT_NODE) {
+            return (const char *)child->content;
+        }
+    }
+    return NULL;
+}
+
+static int parallels_open_xml(BlockDriverState *bs, int flags, Error **errp)
+{
+    int size, ret;
+    xmlDoc *doc = NULL;
+    xmlNode *root, *image;
+    char *xml = NULL;
+    const char *data;
+    char image_path[PATH_MAX];
+    Error *local_err = NULL;
+
+    ret = size = bdrv_getlength(bs->file);
+    if (ret < 0) {
+        goto fail;
+    }
+    /* XML file size should be resonable */
+    ret = -EFBIG;
+    if (size > 65536) {
+        goto fail;
+    }
+
+    xml = g_malloc(size + 1);
+
+    ret = bdrv_pread(bs->file, 0, xml, size);
+    if (ret != size) {
+        goto fail;
+    }
+    xml[size] = 0;
+
+    ret = -EINVAL;
+    doc = xmlReadMemory(xml, size, NULL, NULL,
+                        XML_PARSE_NOERROR | XML_PARSE_NOWARNING);
+    if (doc == NULL) {
+        goto fail;
+    }
+    root = xmlDocGetRootElement(doc);
+    if (root == NULL) {
+        goto fail;
+    }
+    image = xml_seek(root, "/StorageData/Storage/Image");
+    data = ""; /* make gcc happy */
+    for (size = 0; image != NULL; image = image->next) {
+        if (image->type != XML_ELEMENT_NODE) {
+            continue;
+        }
+
+        size++;
+        data = xml_get_text(image, "Type");
+        if (data != NULL && strcmp(data, "Compressed")) {
+            error_setg(errp, "Only compressed Parallels images are supported");
+            goto done;
+        }
+
+        data = xml_get_text(image, "File");
+        if (data == NULL) {
+            goto fail;
+        }
+    }
+    /* Images with more than 1 snapshots are not supported at the moment */
+    if (size != 1) {
+        error_setg(errp, "Parallels images with snapshots are not supported");
+        goto done;
+    }
+
+    path_combine(image_path, sizeof(image_path), bs->file->filename, data);
+    /* the caller (top layer bdrv_open) will close file for us if bs->file
+       is changed. */
+    bs->file = NULL;
+
+    ret = bdrv_open(&bs->file, image_path, NULL, NULL, flags | BDRV_O_PROTOCOL,
+                    NULL, &local_err);
+    if (ret < 0) {
+        error_setg_errno(errp, -ret, "Could not open '%s': %s",
+                         image_path, error_get_pretty(local_err));
+        error_free(local_err);
+    } else {
+        ret = parallels_open_image(bs, errp);
+    }
+
+done:
+    if (doc != NULL) {
+        xmlFreeDoc(doc);
+    }
+    if (xml != NULL) {
+        g_free(xml);
+    }
+    return ret;
+
+fail:
+    error_setg(errp, "Failed to parse Parallels disk descriptor XML");
+    goto done;
+}
+#endif
+
+static int parallels_probe_xml(const uint8_t *buf, int buf_size)
+{
+    int score = 0;
+#if CONFIG_LIBXML2
+    xmlDoc *doc;
+    xmlNode *root;
+
+    doc = xmlReadMemory((const char *)buf, buf_size, NULL, NULL,
+                        XML_PARSE_NOERROR | XML_PARSE_NOWARNING);
+    if (doc == NULL) {
+        return 0;   /* This is not an XML, we don't care */
+    }
+
+    root = xmlDocGetRootElement(doc);
+    if (root == NULL) {
+        goto done;
+    }
+    if (!xmlStrcmp(root->name, (const xmlChar *)"Parallels_disk_image")) {
+        score = PARALLELS_XML;
+    }
+
+done:
+    xmlFreeDoc(doc);
+#endif
+    return score;
+}
+
+
 static int parallels_probe(const uint8_t *buf, int buf_size, const char *filename)
 {
     const struct parallels_header *ph = (const void *)buf;
@@ -69,13 +266,12 @@ static int parallels_probe(const uint8_t *buf, int buf_size, const char *filenam
     if ((!memcmp(ph->magic, HEADER_MAGIC, 16) ||
         !memcmp(ph->magic, HEADER_MAGIC2, 16)) &&
         (le32_to_cpu(ph->version) == HEADER_VERSION))
-        return 100;
+        return PARALLELS_IMAGE;
 
-    return 0;
+    return parallels_probe_xml(buf, buf_size);
 }
 
-static int parallels_open(BlockDriverState *bs, QDict *options, int flags,
-                          Error **errp)
+static int parallels_open_image(BlockDriverState *bs, Error **errp)
 {
     BDRVParallelsState *s = bs->opaque;
     int i;
@@ -139,13 +335,38 @@ static int parallels_open(BlockDriverState *bs, QDict *options, int flags,
     return 0;
 
 fail_format:
-    error_setg(errp, "Image not in Parallels format");
+    error_setg(errp, "Image is not in Parallels format");
     ret = -EINVAL;
 fail:
     g_free(s->catalog_bitmap);
     return ret;
 }
 
+static int parallels_open(BlockDriverState *bs, QDict *options, int flags,
+                          Error **errp)
+{
+    uint8_t buf[1024];
+    int score;
+
+    score = bdrv_pread(bs->file, 0, buf, sizeof(buf));
+    if (score < 0) {
+        return score;
+    }
+
+    score = parallels_probe(buf, (unsigned)score, NULL);
+    if (score == PARALLELS_XML) {
+#if CONFIG_LIBXML2
+        return parallels_open_xml(bs, flags, errp);
+#endif
+    } else if (score == PARALLELS_IMAGE) {
+        return parallels_open_image(bs, errp);
+    }
+
+    error_setg(errp, "Image is not in Parallels format");
+    return -EINVAL;
+}
+
+
 static int64_t seek_to_sector(BlockDriverState *bs, int64_t sector_num)
 {
     BDRVParallelsState *s = bs->opaque;
-- 
1.9.1

^ permalink raw reply related	[flat|nested] 15+ messages in thread

* [Qemu-devel] [PATCH 3/6] iotests: simple parallels XML disk descriptor file test added
  2014-10-29 13:38 [Qemu-devel] [PATCH v2 0/6] parallels format support improvements Denis V. Lunev
  2014-10-29 13:38 ` [Qemu-devel] [PATCH 1/6] configure: add dependency from libxml2 Denis V. Lunev
  2014-10-29 13:38 ` [Qemu-devel] [PATCH 2/6] block/parallels: allow to specify DiskDescriptor.xml instead of image file Denis V. Lunev
@ 2014-10-29 13:38 ` Denis V. Lunev
  2014-11-05  2:24   ` Jeff Cody
  2014-10-29 13:38 ` [Qemu-devel] [PATCH 4/6] block/parallels: support padded Parallels images Denis V. Lunev
                   ` (2 subsequent siblings)
  5 siblings, 1 reply; 15+ messages in thread
From: Denis V. Lunev @ 2014-10-29 13:38 UTC (permalink / raw)
  Cc: Kevin Wolf, Denis V. Lunev, Jeff Cody, qemu-devel,
	Stefan Hajnoczi

Signed-off-by: Denis V. Lunev <den@openvz.org>
Acked-by: Roman Kagan <rkagan@parallels.com>
CC: Jeff Cody <jcody@redhat.com>
CC: Kevin Wolf <kwolf@redhat.com>
CC: Stefan Hajnoczi <stefanha@redhat.com>
---
 tests/qemu-iotests/076                                    |   6 ++++++
 tests/qemu-iotests/076.out                                |   4 ++++
 tests/qemu-iotests/sample_images/parallels-simple.xml.bz2 | Bin 0 -> 374 bytes
 3 files changed, 10 insertions(+)
 create mode 100644 tests/qemu-iotests/sample_images/parallels-simple.xml.bz2

diff --git a/tests/qemu-iotests/076 b/tests/qemu-iotests/076
index ed2be35..242d0c3 100755
--- a/tests/qemu-iotests/076
+++ b/tests/qemu-iotests/076
@@ -75,6 +75,12 @@ echo "== Read from a valid v2 image =="
 _use_sample_img parallels-v2.bz2
 { $QEMU_IO -c "read -P 0x11 0 64k" $TEST_IMG; } 2>&1 | _filter_qemu_io | _filter_testdir
 
+echo
+echo "== Read from a valid v2 image opened through xml =="
+_use_sample_img parallels-v2.bz2
+_use_sample_img parallels-simple.xml.bz2
+{ $QEMU_IO -c "read -P 0x11 0 64k" $TEST_IMG; } 2>&1 | _filter_qemu_io | _filter_testdir
+
 # success, all done
 echo "*** done"
 rm -f $seq.full
diff --git a/tests/qemu-iotests/076.out b/tests/qemu-iotests/076.out
index 32ade08..628d9bf 100644
--- a/tests/qemu-iotests/076.out
+++ b/tests/qemu-iotests/076.out
@@ -19,4 +19,8 @@ no file open, try 'help open'
 == Read from a valid v2 image ==
 read 65536/65536 bytes at offset 0
 64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+
+== Read from a valid v2 image opened through xml ==
+read 65536/65536 bytes at offset 0
+64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
 *** done
diff --git a/tests/qemu-iotests/sample_images/parallels-simple.xml.bz2 b/tests/qemu-iotests/sample_images/parallels-simple.xml.bz2
new file mode 100644
index 0000000000000000000000000000000000000000..13760bc9f30246ba01f43cdca3d3d90780430f61
GIT binary patch
literal 374
zcmV-+0g3)XT4*^jL0KkKSx`RPoB#ls-+)w5Py_$xpWsdazwh08Faddp1^@s613&-(
z00UFVg-_KD8fY4NVup`X5ukcZBTOVwCXAT_OhRY?0}wJ9sXCPa+IAr*0!sLV#k$+r
zFRIp6TJ>A%(u7Qkn2MJtX_(TWtce9REA{g&qLoa&l#2??q)aKM7Qx|d6glC9JSZw~
z-{Dy+9yLxWKg_2Xm02klNIFQqySl|-EJ?WkLWzOBm`Xui7_);kgut`D<Jy*x1cG2m
zCYzWh49n~Qks#g*ByEgsjlH07DHv)~9ZRui7r}`9{%wsd23x|ItiZh!U&QMH5t<C-
zN>^IdcIOOiAVM)WoC{=C8L4k%Ybsug63k@+f`frkh@_Ij10W;xr->@K!oLkGw3Lv$
zS&-sh3*_e*@-+(JnDfSD#7GS;nh3VYlxtRDgM<i`;3IE%@(Ot{k5NIKyfDy8eeT(5
UX+T&T%b)nWk}1N3f`Rtj;5{a#bN~PV

literal 0
HcmV?d00001

-- 
1.9.1

^ permalink raw reply related	[flat|nested] 15+ messages in thread

* [Qemu-devel] [PATCH 4/6] block/parallels: support padded Parallels images
  2014-10-29 13:38 [Qemu-devel] [PATCH v2 0/6] parallels format support improvements Denis V. Lunev
                   ` (2 preceding siblings ...)
  2014-10-29 13:38 ` [Qemu-devel] [PATCH 3/6] iotests: simple parallels XML disk descriptor file test added Denis V. Lunev
@ 2014-10-29 13:38 ` Denis V. Lunev
  2014-11-05  2:49   ` Jeff Cody
  2014-10-29 13:38 ` [Qemu-devel] [PATCH 5/6] iotests: padded parallels image test Denis V. Lunev
  2014-10-29 13:38 ` [Qemu-devel] [PATCH 6/6] parallels: change copyright information in the image header Denis V. Lunev
  5 siblings, 1 reply; 15+ messages in thread
From: Denis V. Lunev @ 2014-10-29 13:38 UTC (permalink / raw)
  Cc: Kevin Wolf, Denis V. Lunev, Jeff Cody, qemu-devel,
	Stefan Hajnoczi

Unfortunately, old guest OSes do not align partitions to page size by
default. This is true for Windows 2003 and Windows XP.

For the time being Parallels was created an optimization for such OSes
in its desktop product. Desktop users are not qualified enough to create
properly aligned installations. Thus Parallels makes a blind guess
on a customer behalf and creates so-called "padded" images if guest
OS type is specified as WinXP, Win2k and Win2k3.

"Padding" is a value which should be added to guest LBA to obtain
sector number inside the image. This results in a shifted images.
   0123        offset inside image (in 512 byte sectors)
  +-------
  +.012        guest data (512 byte sectors)
  +-------
The information about this is available in DiskDescriptor.xml ONLY. There
is no such data in the image header.

There share of such images could be evaluated as 6-8% according to the
statistics in my hands.

This patch obtains proper value from XML and applies it on reading.

Signed-off-by: Denis V. Lunev <den@openvz.org>
Acked-by: Roman Kagan <rkagan@parallels.com>
CC: Jeff Cody <jcody@redhat.com>
CC: Kevin Wolf <kwolf@redhat.com>
CC: Stefan Hajnoczi <stefanha@redhat.com>
---
 block/parallels.c | 19 +++++++++++++++++++
 1 file changed, 19 insertions(+)

diff --git a/block/parallels.c b/block/parallels.c
index 201c0f1..d07e4f7 100644
--- a/block/parallels.c
+++ b/block/parallels.c
@@ -66,6 +66,7 @@ typedef struct BDRVParallelsState {
     unsigned int tracks;
 
     unsigned int off_multiplier;
+    unsigned int padding;
 } BDRVParallelsState;
 
 static int parallels_open_image(BlockDriverState *bs, Error **errp);
@@ -144,6 +145,7 @@ static int parallels_open_xml(BlockDriverState *bs, int flags, Error **errp)
     const char *data;
     char image_path[PATH_MAX];
     Error *local_err = NULL;
+    BDRVParallelsState *s = bs->opaque;
 
     ret = size = bdrv_getlength(bs->file);
     if (ret < 0) {
@@ -173,6 +175,19 @@ static int parallels_open_xml(BlockDriverState *bs, int flags, Error **errp)
     if (root == NULL) {
         goto fail;
     }
+
+    data = xml_get_text(root, "/Disk_Parameters/Padding");
+    if (data != NULL) {
+        char *endptr;
+        unsigned long pad;
+
+        pad = strtoul(data, &endptr, 0);
+        if ((endptr != NULL && *endptr != '\0') || pad > UINT_MAX) {
+            goto fail;
+        }
+        s->padding = (uint32_t)pad;
+    }
+
     image = xml_seek(root, "/StorageData/Storage/Image");
     data = ""; /* make gcc happy */
     for (size = 0; image != NULL; image = image->next) {
@@ -385,6 +400,10 @@ static int64_t seek_to_sector(BlockDriverState *bs, int64_t sector_num)
 static int parallels_read(BlockDriverState *bs, int64_t sector_num,
                     uint8_t *buf, int nb_sectors)
 {
+    BDRVParallelsState *s = bs->opaque;
+
+    sector_num += s->padding;
+
     while (nb_sectors > 0) {
         int64_t position = seek_to_sector(bs, sector_num);
         if (position >= 0) {
-- 
1.9.1

^ permalink raw reply related	[flat|nested] 15+ messages in thread

* [Qemu-devel] [PATCH 5/6] iotests: padded parallels image test
  2014-10-29 13:38 [Qemu-devel] [PATCH v2 0/6] parallels format support improvements Denis V. Lunev
                   ` (3 preceding siblings ...)
  2014-10-29 13:38 ` [Qemu-devel] [PATCH 4/6] block/parallels: support padded Parallels images Denis V. Lunev
@ 2014-10-29 13:38 ` Denis V. Lunev
  2014-11-05  2:55   ` Jeff Cody
  2014-10-29 13:38 ` [Qemu-devel] [PATCH 6/6] parallels: change copyright information in the image header Denis V. Lunev
  5 siblings, 1 reply; 15+ messages in thread
From: Denis V. Lunev @ 2014-10-29 13:38 UTC (permalink / raw)
  Cc: Kevin Wolf, Denis V. Lunev, Jeff Cody, qemu-devel,
	Stefan Hajnoczi

Unfortunately, old guest OSes do not align partitions to page size by
default. This is true for Windows 2003 and Windows XP.

"Padding" is a value which should be added to guest LBA to obtain
sector number inside the image. This results in a shifted images.
   0123        offset inside image (in 512 byte sectors)
  +-------
  +.012        guest data (512 byte sectors)
  +-------
The information about this is available in DiskDescriptor.xml ONLY. There
is no such data in the image header.

This patch contains very simple image with padding and corresponding
XML disk descriptor created in authentic way.

Signed-off-by: Denis V. Lunev <den@openvz.org>
Acked-by: Roman Kagan <rkagan@parallels.com>
CC: Jeff Cody <jcody@redhat.com>
CC: Kevin Wolf <kwolf@redhat.com>
CC: Stefan Hajnoczi <stefanha@redhat.com>
---
 tests/qemu-iotests/076                                    |   6 ++++++
 tests/qemu-iotests/076.out                                |   4 ++++
 tests/qemu-iotests/sample_images/parallels-padded.xml.bz2 | Bin 0 -> 377 bytes
 tests/qemu-iotests/sample_images/parallels-v2-padded.bz2  | Bin 0 -> 139 bytes
 4 files changed, 10 insertions(+)
 create mode 100644 tests/qemu-iotests/sample_images/parallels-padded.xml.bz2
 create mode 100644 tests/qemu-iotests/sample_images/parallels-v2-padded.bz2

diff --git a/tests/qemu-iotests/076 b/tests/qemu-iotests/076
index 242d0c3..c83b953 100755
--- a/tests/qemu-iotests/076
+++ b/tests/qemu-iotests/076
@@ -81,6 +81,12 @@ _use_sample_img parallels-v2.bz2
 _use_sample_img parallels-simple.xml.bz2
 { $QEMU_IO -c "read -P 0x11 0 64k" $TEST_IMG; } 2>&1 | _filter_qemu_io | _filter_testdir
 
+echo
+echo "== Read from a valid v2 image opened through xml with padding =="
+_use_sample_img parallels-v2-padded.bz2
+_use_sample_img parallels-padded.xml.bz2
+{ $QEMU_IO -c "read -P 0x11 0 64k" $TEST_IMG; } 2>&1 | _filter_qemu_io | _filter_testdir
+
 # success, all done
 echo "*** done"
 rm -f $seq.full
diff --git a/tests/qemu-iotests/076.out b/tests/qemu-iotests/076.out
index 628d9bf..46680d8 100644
--- a/tests/qemu-iotests/076.out
+++ b/tests/qemu-iotests/076.out
@@ -23,4 +23,8 @@ read 65536/65536 bytes at offset 0
 == Read from a valid v2 image opened through xml ==
 read 65536/65536 bytes at offset 0
 64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+
+== Read from a valid v2 image opened through xml with padding ==
+read 65536/65536 bytes at offset 0
+64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
 *** done
diff --git a/tests/qemu-iotests/sample_images/parallels-padded.xml.bz2 b/tests/qemu-iotests/sample_images/parallels-padded.xml.bz2
new file mode 100644
index 0000000000000000000000000000000000000000..90e481b88e1f4d65256d0511a8509114c6358052
GIT binary patch
literal 377
zcmV-<0fzoUT4*^jL0KkKS+JP`&Hw<KUw~9lPy_$xpWsdazwh08FaddH8X6Fz^phqa
z0kr@C000`P{z){A0000Upa9SS5-9{U$c>4nhyVtdfq>MRN`P%Vs7e5mydg1cvP<`s
zYo%7Ss&>_C5i%-bDqP)#HmEBiP+TU)8WyoiurHMw!l_ZF1>8_3m3N^^QwEd8=8hkN
zLO3;VtVoT0C3B518KN#oIV4@)7DfOSbkchYBQVO$9`K;#(G?m(FfikRxR&q(!eB`z
zPfQaAWzYbTAj%3PZH#S=y<l!A7-v`x<>0Cm|7Ih97TD6vNg%Klm)F8;i7;OxS)eka
zB8A?w-Lb<P2oQ=RX}Frn6(&gA)fHtcO2o1qAWlwhDKQig<sdQwI23XvR~T0E)#6G<
zUDR|Oi30I4$}VPcTnCQ(CKJjW0g+;mFwDaQlohzp(E|mg47s2j;G&NR^b?hm3@s%x
XY}H|5IAssg=l(9_ig2MJVKN1r8+(|=

literal 0
HcmV?d00001

diff --git a/tests/qemu-iotests/sample_images/parallels-v2-padded.bz2 b/tests/qemu-iotests/sample_images/parallels-v2-padded.bz2
new file mode 100644
index 0000000000000000000000000000000000000000..80948ce689e2c5c2335d6e6b36965fe0b2305613
GIT binary patch
literal 139
zcmV;60CfLCT4*^jL0KkKSt&WeumB1p|H%DFU;t162mk{B2!JYJ)<8f2AOHXuAOMPl
zQl^8-X^;SIHmDUv6HN?Ehp1#2<6B`Us=32n6t4O~g)zWI0C`4`x5NN3Kna)uT+{)Q
t08GFDLI4D2paA;U<m>wRX=_?<Gd@%RJirP-3P26T+>uTcBnnP&Yyj78F)siB

literal 0
HcmV?d00001

-- 
1.9.1

^ permalink raw reply related	[flat|nested] 15+ messages in thread

* [Qemu-devel] [PATCH 6/6] parallels: change copyright information in the image header
  2014-10-29 13:38 [Qemu-devel] [PATCH v2 0/6] parallels format support improvements Denis V. Lunev
                   ` (4 preceding siblings ...)
  2014-10-29 13:38 ` [Qemu-devel] [PATCH 5/6] iotests: padded parallels image test Denis V. Lunev
@ 2014-10-29 13:38 ` Denis V. Lunev
  2014-11-05  2:56   ` Jeff Cody
  5 siblings, 1 reply; 15+ messages in thread
From: Denis V. Lunev @ 2014-10-29 13:38 UTC (permalink / raw)
  Cc: Kevin Wolf, Denis V. Lunev, Jeff Cody, qemu-devel,
	Stefan Hajnoczi

Signed-off-by: Denis V. Lunev <den@openvz.org>
Acked-by: Roman Kagan <rkagan@parallels.com>
CC: Jeff Cody <jcody@redhat.com>
CC: Kevin Wolf <kwolf@redhat.com>
CC: Stefan Hajnoczi <stefanha@redhat.com>
---
 block/parallels.c | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/block/parallels.c b/block/parallels.c
index d07e4f7..1491211 100644
--- a/block/parallels.c
+++ b/block/parallels.c
@@ -2,8 +2,10 @@
  * Block driver for Parallels disk image format
  *
  * Copyright (c) 2007 Alex Beregszaszi
+ * Copyright (c) 2014 Denis V. Lunev <den@openvz.org>
  *
- * This code is based on comparing different disk images created by Parallels.
+ * This code was originally based on comparing different disk images created
+ * by Parallels.
  *
  * Permission is hereby granted, free of charge, to any person obtaining a copy
  * of this software and associated documentation files (the "Software"), to deal
-- 
1.9.1

^ permalink raw reply related	[flat|nested] 15+ messages in thread

* Re: [Qemu-devel] [PATCH 2/6] block/parallels: allow to specify DiskDescriptor.xml instead of image file
  2014-10-29 13:38 ` [Qemu-devel] [PATCH 2/6] block/parallels: allow to specify DiskDescriptor.xml instead of image file Denis V. Lunev
@ 2014-11-05  2:12   ` Jeff Cody
  2014-11-05 10:51     ` Denis V. Lunev
  0 siblings, 1 reply; 15+ messages in thread
From: Jeff Cody @ 2014-11-05  2:12 UTC (permalink / raw)
  To: Denis V. Lunev; +Cc: Kevin Wolf, qemu-devel, Stefan Hajnoczi

On Wed, Oct 29, 2014 at 04:38:07PM +0300, Denis V. Lunev wrote:
> Typically Parallels disk bundle consists of several images which are
> glued by XML disk descriptor. Also XML hides inside several important
> parameters which are not available in the image header.
> 
> This patch allows to specify this XML file as a filename for an image
> to open. It is allowed only to open Compressed images with the only
> snapshot inside. No additional options are parsed at the moment.
> 
> The code itself is dumb enough for a while. If XML file is specified,
> the file is parsed and the image is reopened as bs->file to keep the
> rest of the driver untouched. This would be changed later with more
> features added.
> 
> Signed-off-by: Denis V. Lunev <den@openvz.org>
> Acked-by: Roman Kagan <rkagan@parallels.com>
> CC: Jeff Cody <jcody@redhat.com>
> CC: Kevin Wolf <kwolf@redhat.com>
> CC: Stefan Hajnoczi <stefanha@redhat.com>
> ---
>  block/parallels.c | 231 ++++++++++++++++++++++++++++++++++++++++++++++++++++--
>  1 file changed, 226 insertions(+), 5 deletions(-)
> 
> diff --git a/block/parallels.c b/block/parallels.c
> index 4f9cd8d..201c0f1 100644
> --- a/block/parallels.c
> +++ b/block/parallels.c
> @@ -27,6 +27,11 @@
>  #include "block/block_int.h"
>  #include "qemu/module.h"
>  
> +#if CONFIG_LIBXML2
> +#include <libxml/parser.h>
> +#include <libxml/tree.h>
> +#endif
> +
>  /**************************************************************/
>  
>  #define HEADER_MAGIC "WithoutFreeSpace"
> @@ -34,6 +39,10 @@
>  #define HEADER_VERSION 2
>  #define HEADER_SIZE 64
>  
> +#define PARALLELS_XML       100
> +#define PARALLELS_IMAGE     101
> +
> +
>  // always little-endian
>  struct parallels_header {
>      char magic[16]; // "WithoutFreeSpace"
> @@ -59,6 +68,194 @@ typedef struct BDRVParallelsState {
>      unsigned int off_multiplier;
>  } BDRVParallelsState;
>  
> +static int parallels_open_image(BlockDriverState *bs, Error **errp);

You shouldn't need this forward declaration, if you put your new
function parallels_open_xml() after parallels_open_image().

> +
> +#if CONFIG_LIBXML2
> +static xmlNodePtr xml_find(xmlNode *node, const char *elem)
> +{
> +    xmlNode *child;
> +
> +    for (child = node->xmlChildrenNode; child != NULL; child = child->next) {
> +        if (!xmlStrcmp(child->name, (const xmlChar *)elem) &&
> +                child->type == XML_ELEMENT_NODE) {
> +            return child;
> +        }
> +    }
> +    return NULL;
> +}
> +
> +static xmlNodePtr xml_seek(xmlNode *root, const char *elem)
> +{
> +    xmlNode *child = root;
> +    const char *path;
> +    char nodename[128];
> +    int last = 0;
> +
> +    path = elem;
> +    if (path[0] == '/') {
> +        path++;
> +    }
> +    if (path[0] == 0) {
> +        return NULL;
> +    }
> +    while (!last) {
> +        const char *p = strchr(path, '/');
> +        int length;
> +        if (p == NULL) {
> +            length = strlen(path);
> +            last = 1;
> +        } else {
> +            length = p - path;
> +        }
> +        memcpy(nodename, path, length);
> +        nodename[length] = 0;

It looks like "elem" is always controlled by us, and not passed by the
user - will this always be the case?

If not, this doesn't seem safe, with nodename being a local array of
128 bytes.  How about using g_strdup() or g_strndup() here?

> +        child = xml_find(child, nodename);
> +        if (child == NULL) {
> +            return NULL;
> +        }
> +        path = ++p;
> +    }
> +    return child;
> +}
> +
> +static const char *xml_get_text(xmlNode *node, const char *name)
> +{
> +    xmlNode *child;
> +
> +    node = xml_seek(node, name);
> +    if (node == NULL) {
> +        return NULL;
> +    }
> +
> +    for (child = node->xmlChildrenNode; child; child = child->next) {
> +        if (child->type == XML_TEXT_NODE) {
> +            return (const char *)child->content;
> +        }
> +    }
> +    return NULL;
> +}
> +
> +static int parallels_open_xml(BlockDriverState *bs, int flags, Error **errp)
> +{
> +    int size, ret;
> +    xmlDoc *doc = NULL;
> +    xmlNode *root, *image;
> +    char *xml = NULL;
> +    const char *data;
> +    char image_path[PATH_MAX];
> +    Error *local_err = NULL;
> +
> +    ret = size = bdrv_getlength(bs->file);
> +    if (ret < 0) {
> +        goto fail;
> +    }
> +    /* XML file size should be resonable */

s/resonable/reasonable

> +    ret = -EFBIG;
> +    if (size > 65536) {
> +        goto fail;
> +    }
> +
> +    xml = g_malloc(size + 1);
> +
> +    ret = bdrv_pread(bs->file, 0, xml, size);
> +    if (ret != size) {
> +        goto fail;
> +    }
> +    xml[size] = 0;
> +
> +    ret = -EINVAL;
> +    doc = xmlReadMemory(xml, size, NULL, NULL,
> +                        XML_PARSE_NOERROR | XML_PARSE_NOWARNING);
> +    if (doc == NULL) {
> +        goto fail;
> +    }
> +    root = xmlDocGetRootElement(doc);
> +    if (root == NULL) {
> +        goto fail;
> +    }
> +    image = xml_seek(root, "/StorageData/Storage/Image");
> +    data = ""; /* make gcc happy */

What gcc warning are you trying to suppress here?

> +    for (size = 0; image != NULL; image = image->next) {
> +        if (image->type != XML_ELEMENT_NODE) {
> +            continue;
> +        }
> +
> +        size++;
> +        data = xml_get_text(image, "Type");
> +        if (data != NULL && strcmp(data, "Compressed")) {
> +            error_setg(errp, "Only compressed Parallels images are supported");
> +            goto done;
> +        }
> +
> +        data = xml_get_text(image, "File");
> +        if (data == NULL) {
> +            goto fail;
> +        }
> +    }
> +    /* Images with more than 1 snapshots are not supported at the moment */
> +    if (size != 1) {
> +        error_setg(errp, "Parallels images with snapshots are not supported");
> +        goto done;
> +    }
> +
> +    path_combine(image_path, sizeof(image_path), bs->file->filename, data);
> +    /* the caller (top layer bdrv_open) will close file for us if bs->file
> +       is changed. */
> +    bs->file = NULL;
> +
> +    ret = bdrv_open(&bs->file, image_path, NULL, NULL, flags | BDRV_O_PROTOCOL,
> +                    NULL, &local_err);
> +    if (ret < 0) {
> +        error_setg_errno(errp, -ret, "Could not open '%s': %s",
> +                         image_path, error_get_pretty(local_err));
> +        error_free(local_err);

error_get_pretty() is not NULL friendly - but I don't think it is an
issue, because if (ret < 0) is true, then (local_err) should be set as
well. Just an observation, I don't think you need to do anything here.

> +    } else {
> +        ret = parallels_open_image(bs, errp);
> +    }
> +
> +done:
> +    if (doc != NULL) {
> +        xmlFreeDoc(doc);
> +    }
> +    if (xml != NULL) {
> +        g_free(xml);
> +    }
> +    return ret;
> +
> +fail:
> +    error_setg(errp, "Failed to parse Parallels disk descriptor XML");
> +    goto done;
> +}
> +#endif
> +
> +static int parallels_probe_xml(const uint8_t *buf, int buf_size)
> +{
> +    int score = 0;
> +#if CONFIG_LIBXML2
> +    xmlDoc *doc;
> +    xmlNode *root;
> +
> +    doc = xmlReadMemory((const char *)buf, buf_size, NULL, NULL,
> +                        XML_PARSE_NOERROR | XML_PARSE_NOWARNING);
> +    if (doc == NULL) {
> +        return 0;   /* This is not an XML, we don't care */
> +    }
> +
> +    root = xmlDocGetRootElement(doc);
> +    if (root == NULL) {
> +        goto done;
> +    }
> +    if (!xmlStrcmp(root->name, (const xmlChar *)"Parallels_disk_image")) {
> +        score = PARALLELS_XML;
> +    }
> +
> +done:
> +    xmlFreeDoc(doc);
> +#endif
> +    return score;
> +}
> +
> +
>  static int parallels_probe(const uint8_t *buf, int buf_size, const char *filename)
>  {
>      const struct parallels_header *ph = (const void *)buf;
> @@ -69,13 +266,12 @@ static int parallels_probe(const uint8_t *buf, int buf_size, const char *filenam
>      if ((!memcmp(ph->magic, HEADER_MAGIC, 16) ||
>          !memcmp(ph->magic, HEADER_MAGIC2, 16)) &&
>          (le32_to_cpu(ph->version) == HEADER_VERSION))
> -        return 100;
> +        return PARALLELS_IMAGE;
>  
> -    return 0;
> +    return parallels_probe_xml(buf, buf_size);
>  }
>

Hmm.  So PARALLELS_XML is 100, and PARALLELS_IMAGE is 101 - and, this
is used later in this patch, to differentiate between XML and non-XML
images.  This is somewhat abusing the .bdrv_probe(), I think - the
intention of .bdrv_probe() is to return a confidence score between
0-100.

I think you'd be better off just checking the magic in
parallels_open() rather than overloading the .bdrv_probe() function.


> -static int parallels_open(BlockDriverState *bs, QDict *options, int flags,
> -                          Error **errp)
> +static int parallels_open_image(BlockDriverState *bs, Error **errp)
>  {
>      BDRVParallelsState *s = bs->opaque;
>      int i;
> @@ -139,13 +335,38 @@ static int parallels_open(BlockDriverState *bs, QDict *options, int flags,
>      return 0;
>  
>  fail_format:
> -    error_setg(errp, "Image not in Parallels format");
> +    error_setg(errp, "Image is not in Parallels format");
>      ret = -EINVAL;
>  fail:
>      g_free(s->catalog_bitmap);
>      return ret;
>  }
>  
> +static int parallels_open(BlockDriverState *bs, QDict *options, int flags,
> +                          Error **errp)
> +{
> +    uint8_t buf[1024];
> +    int score;
> +
> +    score = bdrv_pread(bs->file, 0, buf, sizeof(buf));
> +    if (score < 0) {
> +        return score;
> +    }
> +
> +    score = parallels_probe(buf, (unsigned)score, NULL);
> +    if (score == PARALLELS_XML) {
> +#if CONFIG_LIBXML2
> +        return parallels_open_xml(bs, flags, errp);
> +#endif
> +    } else if (score == PARALLELS_IMAGE) {
> +        return parallels_open_image(bs, errp);
> +    }
> +
> +    error_setg(errp, "Image is not in Parallels format");
> +    return -EINVAL;
> +}
> +
> +
>  static int64_t seek_to_sector(BlockDriverState *bs, int64_t sector_num)
>  {
>      BDRVParallelsState *s = bs->opaque;
> -- 
> 1.9.1
> 

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [Qemu-devel] [PATCH 3/6] iotests: simple parallels XML disk descriptor file test added
  2014-10-29 13:38 ` [Qemu-devel] [PATCH 3/6] iotests: simple parallels XML disk descriptor file test added Denis V. Lunev
@ 2014-11-05  2:24   ` Jeff Cody
  0 siblings, 0 replies; 15+ messages in thread
From: Jeff Cody @ 2014-11-05  2:24 UTC (permalink / raw)
  To: Denis V. Lunev; +Cc: Kevin Wolf, qemu-devel, Stefan Hajnoczi

On Wed, Oct 29, 2014 at 04:38:08PM +0300, Denis V. Lunev wrote:
> Signed-off-by: Denis V. Lunev <den@openvz.org>
> Acked-by: Roman Kagan <rkagan@parallels.com>
> CC: Jeff Cody <jcody@redhat.com>
> CC: Kevin Wolf <kwolf@redhat.com>
> CC: Stefan Hajnoczi <stefanha@redhat.com>
> ---
>  tests/qemu-iotests/076                                    |   6 ++++++
>  tests/qemu-iotests/076.out                                |   4 ++++
>  tests/qemu-iotests/sample_images/parallels-simple.xml.bz2 | Bin 0 -> 374 bytes
>  3 files changed, 10 insertions(+)
>  create mode 100644 tests/qemu-iotests/sample_images/parallels-simple.xml.bz2
> 
> diff --git a/tests/qemu-iotests/076 b/tests/qemu-iotests/076
> index ed2be35..242d0c3 100755
> --- a/tests/qemu-iotests/076
> +++ b/tests/qemu-iotests/076
> @@ -75,6 +75,12 @@ echo "== Read from a valid v2 image =="
>  _use_sample_img parallels-v2.bz2
>  { $QEMU_IO -c "read -P 0x11 0 64k" $TEST_IMG; } 2>&1 | _filter_qemu_io | _filter_testdir
>  
> +echo
> +echo "== Read from a valid v2 image opened through xml =="
> +_use_sample_img parallels-v2.bz2
> +_use_sample_img parallels-simple.xml.bz2
> +{ $QEMU_IO -c "read -P 0x11 0 64k" $TEST_IMG; } 2>&1 | _filter_qemu_io | _filter_testdir
> +

$TEST_IMG should be quoted, to be path-safe ("$TEST_IMG") - although,
looks like 076 has some other instances of unquoted $TEST_IMG, as
well (not your fault).  I don't care if you fix it here or not, we can
fix them all up in a later patch.

>  # success, all done
>  echo "*** done"
>  rm -f $seq.full
> diff --git a/tests/qemu-iotests/076.out b/tests/qemu-iotests/076.out
> index 32ade08..628d9bf 100644
> --- a/tests/qemu-iotests/076.out
> +++ b/tests/qemu-iotests/076.out
> @@ -19,4 +19,8 @@ no file open, try 'help open'
>  == Read from a valid v2 image ==
>  read 65536/65536 bytes at offset 0
>  64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
> +
> +== Read from a valid v2 image opened through xml ==
> +read 65536/65536 bytes at offset 0
> +64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
>  *** done
> diff --git a/tests/qemu-iotests/sample_images/parallels-simple.xml.bz2 b/tests/qemu-iotests/sample_images/parallels-simple.xml.bz2
> new file mode 100644
> index 0000000000000000000000000000000000000000..13760bc9f30246ba01f43cdca3d3d90780430f61
> GIT binary patch
> literal 374
> zcmV-+0g3)XT4*^jL0KkKSx`RPoB#ls-+)w5Py_$xpWsdazwh08Faddp1^@s613&-(
> z00UFVg-_KD8fY4NVup`X5ukcZBTOVwCXAT_OhRY?0}wJ9sXCPa+IAr*0!sLV#k$+r
> zFRIp6TJ>A%(u7Qkn2MJtX_(TWtce9REA{g&qLoa&l#2??q)aKM7Qx|d6glC9JSZw~
> z-{Dy+9yLxWKg_2Xm02klNIFQqySl|-EJ?WkLWzOBm`Xui7_);kgut`D<Jy*x1cG2m
> zCYzWh49n~Qks#g*ByEgsjlH07DHv)~9ZRui7r}`9{%wsd23x|ItiZh!U&QMH5t<C-
> zN>^IdcIOOiAVM)WoC{=C8L4k%Ybsug63k@+f`frkh@_Ij10W;xr->@K!oLkGw3Lv$
> zS&-sh3*_e*@-+(JnDfSD#7GS;nh3VYlxtRDgM<i`;3IE%@(Ot{k5NIKyfDy8eeT(5
> UX+T&T%b)nWk}1N3f`Rtj;5{a#bN~PV
> 
> literal 0
> HcmV?d00001
> 
> -- 
> 1.9.1
>

Reviewed-by: Jeff Cody <jcody@redhat.com>

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [Qemu-devel] [PATCH 4/6] block/parallels: support padded Parallels images
  2014-10-29 13:38 ` [Qemu-devel] [PATCH 4/6] block/parallels: support padded Parallels images Denis V. Lunev
@ 2014-11-05  2:49   ` Jeff Cody
  0 siblings, 0 replies; 15+ messages in thread
From: Jeff Cody @ 2014-11-05  2:49 UTC (permalink / raw)
  To: Denis V. Lunev; +Cc: Kevin Wolf, qemu-devel, Stefan Hajnoczi

On Wed, Oct 29, 2014 at 04:38:09PM +0300, Denis V. Lunev wrote:
> Unfortunately, old guest OSes do not align partitions to page size by
> default. This is true for Windows 2003 and Windows XP.
> 
> For the time being Parallels was created an optimization for such OSes
> in its desktop product. Desktop users are not qualified enough to create
> properly aligned installations. Thus Parallels makes a blind guess
> on a customer behalf and creates so-called "padded" images if guest
> OS type is specified as WinXP, Win2k and Win2k3.
> 
> "Padding" is a value which should be added to guest LBA to obtain
> sector number inside the image. This results in a shifted images.
>    0123        offset inside image (in 512 byte sectors)
>   +-------
>   +.012        guest data (512 byte sectors)
>   +-------
> The information about this is available in DiskDescriptor.xml ONLY. There
> is no such data in the image header.
> 
> There share of such images could be evaluated as 6-8% according to the
> statistics in my hands.
> 
> This patch obtains proper value from XML and applies it on reading.
> 
> Signed-off-by: Denis V. Lunev <den@openvz.org>
> Acked-by: Roman Kagan <rkagan@parallels.com>
> CC: Jeff Cody <jcody@redhat.com>
> CC: Kevin Wolf <kwolf@redhat.com>
> CC: Stefan Hajnoczi <stefanha@redhat.com>
> ---
>  block/parallels.c | 19 +++++++++++++++++++
>  1 file changed, 19 insertions(+)
> 
> diff --git a/block/parallels.c b/block/parallels.c
> index 201c0f1..d07e4f7 100644
> --- a/block/parallels.c
> +++ b/block/parallels.c
> @@ -66,6 +66,7 @@ typedef struct BDRVParallelsState {
>      unsigned int tracks;
>  
>      unsigned int off_multiplier;
> +    unsigned int padding;
>  } BDRVParallelsState;
>  
>  static int parallels_open_image(BlockDriverState *bs, Error **errp);
> @@ -144,6 +145,7 @@ static int parallels_open_xml(BlockDriverState *bs, int flags, Error **errp)
>      const char *data;
>      char image_path[PATH_MAX];
>      Error *local_err = NULL;
> +    BDRVParallelsState *s = bs->opaque;
>  
>      ret = size = bdrv_getlength(bs->file);
>      if (ret < 0) {
> @@ -173,6 +175,19 @@ static int parallels_open_xml(BlockDriverState *bs, int flags, Error **errp)
>      if (root == NULL) {
>          goto fail;
>      }
> +
> +    data = xml_get_text(root, "/Disk_Parameters/Padding");
> +    if (data != NULL) {
> +        char *endptr;
> +        unsigned long pad;
> +
> +        pad = strtoul(data, &endptr, 0);
> +        if ((endptr != NULL && *endptr != '\0') || pad > UINT_MAX) {
> +            goto fail;
> +        }
> +        s->padding = (uint32_t)pad;
> +    }
> +
>      image = xml_seek(root, "/StorageData/Storage/Image");
>      data = ""; /* make gcc happy */
>      for (size = 0; image != NULL; image = image->next) {
> @@ -385,6 +400,10 @@ static int64_t seek_to_sector(BlockDriverState *bs, int64_t sector_num)
>  static int parallels_read(BlockDriverState *bs, int64_t sector_num,
>                      uint8_t *buf, int nb_sectors)
>  {
> +    BDRVParallelsState *s = bs->opaque;
> +
> +    sector_num += s->padding;
> +
>      while (nb_sectors > 0) {
>          int64_t position = seek_to_sector(bs, sector_num);
>          if (position >= 0) {
> -- 
> 1.9.1
> 

Reviewed-by: Jeff Cody <jcody@redhat.com>

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [Qemu-devel] [PATCH 5/6] iotests: padded parallels image test
  2014-10-29 13:38 ` [Qemu-devel] [PATCH 5/6] iotests: padded parallels image test Denis V. Lunev
@ 2014-11-05  2:55   ` Jeff Cody
  0 siblings, 0 replies; 15+ messages in thread
From: Jeff Cody @ 2014-11-05  2:55 UTC (permalink / raw)
  To: Denis V. Lunev; +Cc: Kevin Wolf, qemu-devel, Stefan Hajnoczi

On Wed, Oct 29, 2014 at 04:38:10PM +0300, Denis V. Lunev wrote:
> Unfortunately, old guest OSes do not align partitions to page size by
> default. This is true for Windows 2003 and Windows XP.
> 
> "Padding" is a value which should be added to guest LBA to obtain
> sector number inside the image. This results in a shifted images.
>    0123        offset inside image (in 512 byte sectors)
>   +-------
>   +.012        guest data (512 byte sectors)
>   +-------
> The information about this is available in DiskDescriptor.xml ONLY. There
> is no such data in the image header.
> 
> This patch contains very simple image with padding and corresponding
> XML disk descriptor created in authentic way.
> 
> Signed-off-by: Denis V. Lunev <den@openvz.org>
> Acked-by: Roman Kagan <rkagan@parallels.com>
> CC: Jeff Cody <jcody@redhat.com>
> CC: Kevin Wolf <kwolf@redhat.com>
> CC: Stefan Hajnoczi <stefanha@redhat.com>
> ---
>  tests/qemu-iotests/076                                    |   6 ++++++
>  tests/qemu-iotests/076.out                                |   4 ++++
>  tests/qemu-iotests/sample_images/parallels-padded.xml.bz2 | Bin 0 -> 377 bytes
>  tests/qemu-iotests/sample_images/parallels-v2-padded.bz2  | Bin 0 -> 139 bytes
>  4 files changed, 10 insertions(+)
>  create mode 100644 tests/qemu-iotests/sample_images/parallels-padded.xml.bz2
>  create mode 100644 tests/qemu-iotests/sample_images/parallels-v2-padded.bz2
> 
> diff --git a/tests/qemu-iotests/076 b/tests/qemu-iotests/076
> index 242d0c3..c83b953 100755
> --- a/tests/qemu-iotests/076
> +++ b/tests/qemu-iotests/076
> @@ -81,6 +81,12 @@ _use_sample_img parallels-v2.bz2
>  _use_sample_img parallels-simple.xml.bz2
>  { $QEMU_IO -c "read -P 0x11 0 64k" $TEST_IMG; } 2>&1 | _filter_qemu_io | _filter_testdir
>  
> +echo
> +echo "== Read from a valid v2 image opened through xml with padding =="
> +_use_sample_img parallels-v2-padded.bz2
> +_use_sample_img parallels-padded.xml.bz2
> +{ $QEMU_IO -c "read -P 0x11 0 64k" $TEST_IMG; } 2>&1 | _filter_qemu_io | _filter_testdir
> +

Same comment as before on $TEST_IMG needing quoting, and as before,
can wait until we clean up the other instances in this same file.


Reviewed-by: Jeff Cody <jcody@redhat.com>


>  # success, all done
>  echo "*** done"
>  rm -f $seq.full
> diff --git a/tests/qemu-iotests/076.out b/tests/qemu-iotests/076.out
> index 628d9bf..46680d8 100644
> --- a/tests/qemu-iotests/076.out
> +++ b/tests/qemu-iotests/076.out
> @@ -23,4 +23,8 @@ read 65536/65536 bytes at offset 0
>  == Read from a valid v2 image opened through xml ==
>  read 65536/65536 bytes at offset 0
>  64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
> +
> +== Read from a valid v2 image opened through xml with padding ==
> +read 65536/65536 bytes at offset 0
> +64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
>  *** done
> diff --git a/tests/qemu-iotests/sample_images/parallels-padded.xml.bz2 b/tests/qemu-iotests/sample_images/parallels-padded.xml.bz2
> new file mode 100644
> index 0000000000000000000000000000000000000000..90e481b88e1f4d65256d0511a8509114c6358052
> GIT binary patch
> literal 377
> zcmV-<0fzoUT4*^jL0KkKS+JP`&Hw<KUw~9lPy_$xpWsdazwh08FaddH8X6Fz^phqa
> z0kr@C000`P{z){A0000Upa9SS5-9{U$c>4nhyVtdfq>MRN`P%Vs7e5mydg1cvP<`s
> zYo%7Ss&>_C5i%-bDqP)#HmEBiP+TU)8WyoiurHMw!l_ZF1>8_3m3N^^QwEd8=8hkN
> zLO3;VtVoT0C3B518KN#oIV4@)7DfOSbkchYBQVO$9`K;#(G?m(FfikRxR&q(!eB`z
> zPfQaAWzYbTAj%3PZH#S=y<l!A7-v`x<>0Cm|7Ih97TD6vNg%Klm)F8;i7;OxS)eka
> zB8A?w-Lb<P2oQ=RX}Frn6(&gA)fHtcO2o1qAWlwhDKQig<sdQwI23XvR~T0E)#6G<
> zUDR|Oi30I4$}VPcTnCQ(CKJjW0g+;mFwDaQlohzp(E|mg47s2j;G&NR^b?hm3@s%x
> XY}H|5IAssg=l(9_ig2MJVKN1r8+(|=
> 
> literal 0
> HcmV?d00001
> 
> diff --git a/tests/qemu-iotests/sample_images/parallels-v2-padded.bz2 b/tests/qemu-iotests/sample_images/parallels-v2-padded.bz2
> new file mode 100644
> index 0000000000000000000000000000000000000000..80948ce689e2c5c2335d6e6b36965fe0b2305613
> GIT binary patch
> literal 139
> zcmV;60CfLCT4*^jL0KkKSt&WeumB1p|H%DFU;t162mk{B2!JYJ)<8f2AOHXuAOMPl
> zQl^8-X^;SIHmDUv6HN?Ehp1#2<6B`Us=32n6t4O~g)zWI0C`4`x5NN3Kna)uT+{)Q
> t08GFDLI4D2paA;U<m>wRX=_?<Gd@%RJirP-3P26T+>uTcBnnP&Yyj78F)siB
> 
> literal 0
> HcmV?d00001
> 
> -- 
> 1.9.1
> 

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [Qemu-devel] [PATCH 6/6] parallels: change copyright information in the image header
  2014-10-29 13:38 ` [Qemu-devel] [PATCH 6/6] parallels: change copyright information in the image header Denis V. Lunev
@ 2014-11-05  2:56   ` Jeff Cody
  0 siblings, 0 replies; 15+ messages in thread
From: Jeff Cody @ 2014-11-05  2:56 UTC (permalink / raw)
  To: Denis V. Lunev; +Cc: Kevin Wolf, qemu-devel, Stefan Hajnoczi

On Wed, Oct 29, 2014 at 04:38:11PM +0300, Denis V. Lunev wrote:
> Signed-off-by: Denis V. Lunev <den@openvz.org>
> Acked-by: Roman Kagan <rkagan@parallels.com>
> CC: Jeff Cody <jcody@redhat.com>
> CC: Kevin Wolf <kwolf@redhat.com>
> CC: Stefan Hajnoczi <stefanha@redhat.com>
> ---
>  block/parallels.c | 4 +++-
>  1 file changed, 3 insertions(+), 1 deletion(-)
> 
> diff --git a/block/parallels.c b/block/parallels.c
> index d07e4f7..1491211 100644
> --- a/block/parallels.c
> +++ b/block/parallels.c
> @@ -2,8 +2,10 @@
>   * Block driver for Parallels disk image format
>   *
>   * Copyright (c) 2007 Alex Beregszaszi
> + * Copyright (c) 2014 Denis V. Lunev <den@openvz.org>
>   *
> - * This code is based on comparing different disk images created by Parallels.
> + * This code was originally based on comparing different disk images created
> + * by Parallels.
>   *
>   * Permission is hereby granted, free of charge, to any person obtaining a copy
>   * of this software and associated documentation files (the "Software"), to deal
> -- 
> 1.9.1
>

Reviewed-by: Jeff Cody <jcody@redhat.com>

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [Qemu-devel] [PATCH 1/6] configure: add dependency from libxml2
  2014-10-29 13:38 ` [Qemu-devel] [PATCH 1/6] configure: add dependency from libxml2 Denis V. Lunev
@ 2014-11-05  7:32   ` Michael Tokarev
  2014-11-05  8:19     ` Denis V. Lunev
  0 siblings, 1 reply; 15+ messages in thread
From: Michael Tokarev @ 2014-11-05  7:32 UTC (permalink / raw)
  To: Denis V. Lunev
  Cc: Kevin Wolf, Fam Zheng, Jeff Cody, qemu-devel, Stefan Hajnoczi,
	Paolo Bonzini

29.10.2014 16:38, Denis V. Lunev wrote:
> This dependency is required for adequate Parallels images support.
> Typically the disk consists of several images which are glued by
> XML disk descriptor. Also XML hides inside several important parameters
> which are not available in the image header.
[]
> +# check for libxml2
> +if test "$libxml2" != "no" ; then
> +    if $pkg_config --exists libxml-2.0; then
> +        libxml2="yes"
> +        libxml2_cflags=$($pkg_config --cflags libxml-2.0)
> +        libxml2_libs=$($pkg_config --libs libxml-2.0)
> +        QEMU_CFLAGS="$QEMU_CFLAGS $libxml2_cflags"
> +        libs_softmmu="$libs_softmmu $libxml2_libs"
> +        libs_tools="$libs_tools $libxml2_libs"

Please NO.  NO NO NO NO :)

Create a separate make variable, $LIBXML or something,
and add it as a parallels.o dependency, not libs_softmmu
etc.  Ditto for the cflags.  See examples -- libiscsi,
libcurl, librbd - in block/Makefile.objs.

After that, I think we'll move parallels.o to be a module ;)

(Cc'ing Fam)

Thanks,

/mjt

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [Qemu-devel] [PATCH 1/6] configure: add dependency from libxml2
  2014-11-05  7:32   ` Michael Tokarev
@ 2014-11-05  8:19     ` Denis V. Lunev
  0 siblings, 0 replies; 15+ messages in thread
From: Denis V. Lunev @ 2014-11-05  8:19 UTC (permalink / raw)
  To: Michael Tokarev
  Cc: Kevin Wolf, Fam Zheng, Jeff Cody, qemu-devel, Stefan Hajnoczi,
	Paolo Bonzini

On 05/11/14 10:32, Michael Tokarev wrote:
> 29.10.2014 16:38, Denis V. Lunev wrote:
>> This dependency is required for adequate Parallels images support.
>> Typically the disk consists of several images which are glued by
>> XML disk descriptor. Also XML hides inside several important parameters
>> which are not available in the image header.
> []
>> +# check for libxml2
>> +if test "$libxml2" != "no" ; then
>> +    if $pkg_config --exists libxml-2.0; then
>> +        libxml2="yes"
>> +        libxml2_cflags=$($pkg_config --cflags libxml-2.0)
>> +        libxml2_libs=$($pkg_config --libs libxml-2.0)
>> +        QEMU_CFLAGS="$QEMU_CFLAGS $libxml2_cflags"
>> +        libs_softmmu="$libs_softmmu $libxml2_libs"
>> +        libs_tools="$libs_tools $libxml2_libs"
> Please NO.  NO NO NO NO :)
>
> Create a separate make variable, $LIBXML or something,
> and add it as a parallels.o dependency, not libs_softmmu
> etc.  Ditto for the cflags.  See examples -- libiscsi,
> libcurl, librbd - in block/Makefile.objs.
no prob
> After that, I think we'll move parallels.o to be a module ;)
>
> (Cc'ing Fam)
what does it mean for me? Could you point out the place
to read/understand the difference.

Thank you in advance,
     Den

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [Qemu-devel] [PATCH 2/6] block/parallels: allow to specify DiskDescriptor.xml instead of image file
  2014-11-05  2:12   ` Jeff Cody
@ 2014-11-05 10:51     ` Denis V. Lunev
  0 siblings, 0 replies; 15+ messages in thread
From: Denis V. Lunev @ 2014-11-05 10:51 UTC (permalink / raw)
  To: Jeff Cody; +Cc: Kevin Wolf, qemu-devel, Stefan Hajnoczi

On 05/11/14 05:12, Jeff Cody wrote:
> On Wed, Oct 29, 2014 at 04:38:07PM +0300, Denis V. Lunev wrote:
>> Typically Parallels disk bundle consists of several images which are
>> glued by XML disk descriptor. Also XML hides inside several important
>> parameters which are not available in the image header.
>>
>> This patch allows to specify this XML file as a filename for an image
>> to open. It is allowed only to open Compressed images with the only
>> snapshot inside. No additional options are parsed at the moment.
>>
>> The code itself is dumb enough for a while. If XML file is specified,
>> the file is parsed and the image is reopened as bs->file to keep the
>> rest of the driver untouched. This would be changed later with more
>> features added.
>>
>> Signed-off-by: Denis V. Lunev <den@openvz.org>
>> Acked-by: Roman Kagan <rkagan@parallels.com>
>> CC: Jeff Cody <jcody@redhat.com>
>> CC: Kevin Wolf <kwolf@redhat.com>
>> CC: Stefan Hajnoczi <stefanha@redhat.com>
>> ---
>>   block/parallels.c | 231 ++++++++++++++++++++++++++++++++++++++++++++++++++++--
>>   1 file changed, 226 insertions(+), 5 deletions(-)
>>
>> diff --git a/block/parallels.c b/block/parallels.c
>> index 4f9cd8d..201c0f1 100644
>> --- a/block/parallels.c
>> +++ b/block/parallels.c
>> @@ -27,6 +27,11 @@
>>   #include "block/block_int.h"
>>   #include "qemu/module.h"
>>   
>> +#if CONFIG_LIBXML2
>> +#include <libxml/parser.h>
>> +#include <libxml/tree.h>
>> +#endif
>> +
>>   /**************************************************************/
>>   
>>   #define HEADER_MAGIC "WithoutFreeSpace"
>> @@ -34,6 +39,10 @@
>>   #define HEADER_VERSION 2
>>   #define HEADER_SIZE 64
>>   
>> +#define PARALLELS_XML       100
>> +#define PARALLELS_IMAGE     101
>> +
>> +
>>   // always little-endian
>>   struct parallels_header {
>>       char magic[16]; // "WithoutFreeSpace"
>> @@ -59,6 +68,194 @@ typedef struct BDRVParallelsState {
>>       unsigned int off_multiplier;
>>   } BDRVParallelsState;
>>   
>> +static int parallels_open_image(BlockDriverState *bs, Error **errp);
> You shouldn't need this forward declaration, if you put your new
> function parallels_open_xml() after parallels_open_image().
ok, fair enough. This is a rudiment from my previous internal version
which has been implemented in the other way.

>> +
>> +#if CONFIG_LIBXML2
>> +static xmlNodePtr xml_find(xmlNode *node, const char *elem)
>> +{
>> +    xmlNode *child;
>> +
>> +    for (child = node->xmlChildrenNode; child != NULL; child = child->next) {
>> +        if (!xmlStrcmp(child->name, (const xmlChar *)elem) &&
>> +                child->type == XML_ELEMENT_NODE) {
>> +            return child;
>> +        }
>> +    }
>> +    return NULL;
>> +}
>> +
>> +static xmlNodePtr xml_seek(xmlNode *root, const char *elem)
>> +{
>> +    xmlNode *child = root;
>> +    const char *path;
>> +    char nodename[128];
>> +    int last = 0;
>> +
>> +    path = elem;
>> +    if (path[0] == '/') {
>> +        path++;
>> +    }
>> +    if (path[0] == 0) {
>> +        return NULL;
>> +    }
>> +    while (!last) {
>> +        const char *p = strchr(path, '/');
>> +        int length;
>> +        if (p == NULL) {
>> +            length = strlen(path);
>> +            last = 1;
>> +        } else {
>> +            length = p - path;
>> +        }
>> +        memcpy(nodename, path, length);
>> +        nodename[length] = 0;
> It looks like "elem" is always controlled by us, and not passed by the
> user - will this always be the case?
>
> If not, this doesn't seem safe, with nodename being a local array of
> 128 bytes.  How about using g_strdup() or g_strndup() here?
yes, this constraint is used now and will be used in the future.
XML structure is known and it is fixed. Here we just shortcut
the navigation in the tree in a convenient way to pass entire
path is one call.

I think that we can switch to interface like
    static xmlNodePtr xml_seek(xmlNode *root, ...)
and call it like
     xml_seek(root, "StorageData", "Storage", "Image", NULL);
in this case we will be able to drop a lot of processing and
parsing inside including strchr, memcpy, strlen etc


>> +        child = xml_find(child, nodename);
>> +        if (child == NULL) {
>> +            return NULL;
>> +        }
>> +        path = ++p;
>> +    }
>> +    return child;
>> +}
>> +
>> +static const char *xml_get_text(xmlNode *node, const char *name)
>> +{
>> +    xmlNode *child;
>> +
>> +    node = xml_seek(node, name);
>> +    if (node == NULL) {
>> +        return NULL;
>> +    }
>> +
>> +    for (child = node->xmlChildrenNode; child; child = child->next) {
>> +        if (child->type == XML_TEXT_NODE) {
>> +            return (const char *)child->content;
>> +        }
>> +    }
>> +    return NULL;
>> +}
>> +
>> +static int parallels_open_xml(BlockDriverState *bs, int flags, Error **errp)
>> +{
>> +    int size, ret;
>> +    xmlDoc *doc = NULL;
>> +    xmlNode *root, *image;
>> +    char *xml = NULL;
>> +    const char *data;
>> +    char image_path[PATH_MAX];
>> +    Error *local_err = NULL;
>> +
>> +    ret = size = bdrv_getlength(bs->file);
>> +    if (ret < 0) {
>> +        goto fail;
>> +    }
>> +    /* XML file size should be resonable */
> s/resonable/reasonable
ok
>> +    ret = -EFBIG;
>> +    if (size > 65536) {
>> +        goto fail;
>> +    }
>> +
>> +    xml = g_malloc(size + 1);
>> +
>> +    ret = bdrv_pread(bs->file, 0, xml, size);
>> +    if (ret != size) {
>> +        goto fail;
>> +    }
>> +    xml[size] = 0;
>> +
>> +    ret = -EINVAL;
>> +    doc = xmlReadMemory(xml, size, NULL, NULL,
>> +                        XML_PARSE_NOERROR | XML_PARSE_NOWARNING);
>> +    if (doc == NULL) {
>> +        goto fail;
>> +    }
>> +    root = xmlDocGetRootElement(doc);
>> +    if (root == NULL) {
>> +        goto fail;
>> +    }
>> +    image = xml_seek(root, "/StorageData/Storage/Image");
>> +    data = ""; /* make gcc happy */
> What gcc warning are you trying to suppress here?

use of uninitialized variable in the line below.
     path_combine(image_path, sizeof(image_path), bs->file->filename, data);
which can not happen due to check size == 1 a line above.

>
>> +    for (size = 0; image != NULL; image = image->next) {
>> +        if (image->type != XML_ELEMENT_NODE) {
>> +            continue;
>> +        }
>> +
>> +        size++;
>> +        data = xml_get_text(image, "Type");
>> +        if (data != NULL && strcmp(data, "Compressed")) {
>> +            error_setg(errp, "Only compressed Parallels images are supported");
>> +            goto done;
>> +        }
>> +
>> +        data = xml_get_text(image, "File");
>> +        if (data == NULL) {
>> +            goto fail;
>> +        }
>> +    }
>> +    /* Images with more than 1 snapshots are not supported at the moment */
>> +    if (size != 1) {
>> +        error_setg(errp, "Parallels images with snapshots are not supported");
>> +        goto done;
>> +    }
>> +
>> +    path_combine(image_path, sizeof(image_path), bs->file->filename, data);
>> +    /* the caller (top layer bdrv_open) will close file for us if bs->file
>> +       is changed. */
>> +    bs->file = NULL;
>> +
>> +    ret = bdrv_open(&bs->file, image_path, NULL, NULL, flags | BDRV_O_PROTOCOL,
>> +                    NULL, &local_err);
>> +    if (ret < 0) {
>> +        error_setg_errno(errp, -ret, "Could not open '%s': %s",
>> +                         image_path, error_get_pretty(local_err));
>> +        error_free(local_err);
> error_get_pretty() is not NULL friendly - but I don't think it is an
> issue, because if (ret < 0) is true, then (local_err) should be set as
> well. Just an observation, I don't think you need to do anything here.
thank you for pointing this out

>> +    } else {
>> +        ret = parallels_open_image(bs, errp);
>> +    }
>> +
>> +done:
>> +    if (doc != NULL) {
>> +        xmlFreeDoc(doc);
>> +    }
>> +    if (xml != NULL) {
>> +        g_free(xml);
>> +    }
>> +    return ret;
>> +
>> +fail:
>> +    error_setg(errp, "Failed to parse Parallels disk descriptor XML");
>> +    goto done;
>> +}
>> +#endif
>> +
>> +static int parallels_probe_xml(const uint8_t *buf, int buf_size)
>> +{
>> +    int score = 0;
>> +#if CONFIG_LIBXML2
>> +    xmlDoc *doc;
>> +    xmlNode *root;
>> +
>> +    doc = xmlReadMemory((const char *)buf, buf_size, NULL, NULL,
>> +                        XML_PARSE_NOERROR | XML_PARSE_NOWARNING);
>> +    if (doc == NULL) {
>> +        return 0;   /* This is not an XML, we don't care */
>> +    }
>> +
>> +    root = xmlDocGetRootElement(doc);
>> +    if (root == NULL) {
>> +        goto done;
>> +    }
>> +    if (!xmlStrcmp(root->name, (const xmlChar *)"Parallels_disk_image")) {
>> +        score = PARALLELS_XML;
>> +    }
>> +
>> +done:
>> +    xmlFreeDoc(doc);
>> +#endif
>> +    return score;
>> +}
>> +
>> +
>>   static int parallels_probe(const uint8_t *buf, int buf_size, const char *filename)
>>   {
>>       const struct parallels_header *ph = (const void *)buf;
>> @@ -69,13 +266,12 @@ static int parallels_probe(const uint8_t *buf, int buf_size, const char *filenam
>>       if ((!memcmp(ph->magic, HEADER_MAGIC, 16) ||
>>           !memcmp(ph->magic, HEADER_MAGIC2, 16)) &&
>>           (le32_to_cpu(ph->version) == HEADER_VERSION))
>> -        return 100;
>> +        return PARALLELS_IMAGE;
>>   
>> -    return 0;
>> +    return parallels_probe_xml(buf, buf_size);
>>   }
>>
> Hmm.  So PARALLELS_XML is 100, and PARALLELS_IMAGE is 101 - and, this
> is used later in this patch, to differentiate between XML and non-XML
> images.  This is somewhat abusing the .bdrv_probe(), I think - the
> intention of .bdrv_probe() is to return a confidence score between
> 0-100.
>
> I think you'd be better off just checking the magic in
> parallels_open() rather than overloading the .bdrv_probe() function.
>
you are right. I have missed this thing. Need some thinking on this,
but, anyway, this should be fixed.

>> -static int parallels_open(BlockDriverState *bs, QDict *options, int flags,
>> -                          Error **errp)
>> +static int parallels_open_image(BlockDriverState *bs, Error **errp)
>>   {
>>       BDRVParallelsState *s = bs->opaque;
>>       int i;
>> @@ -139,13 +335,38 @@ static int parallels_open(BlockDriverState *bs, QDict *options, int flags,
>>       return 0;
>>   
>>   fail_format:
>> -    error_setg(errp, "Image not in Parallels format");
>> +    error_setg(errp, "Image is not in Parallels format");
>>       ret = -EINVAL;
>>   fail:
>>       g_free(s->catalog_bitmap);
>>       return ret;
>>   }
>>   
>> +static int parallels_open(BlockDriverState *bs, QDict *options, int flags,
>> +                          Error **errp)
>> +{
>> +    uint8_t buf[1024];
>> +    int score;
>> +
>> +    score = bdrv_pread(bs->file, 0, buf, sizeof(buf));
>> +    if (score < 0) {
>> +        return score;
>> +    }
>> +
>> +    score = parallels_probe(buf, (unsigned)score, NULL);
>> +    if (score == PARALLELS_XML) {
>> +#if CONFIG_LIBXML2
>> +        return parallels_open_xml(bs, flags, errp);
>> +#endif
>> +    } else if (score == PARALLELS_IMAGE) {
>> +        return parallels_open_image(bs, errp);
>> +    }
>> +
>> +    error_setg(errp, "Image is not in Parallels format");
>> +    return -EINVAL;
>> +}
>> +
>> +
>>   static int64_t seek_to_sector(BlockDriverState *bs, int64_t sector_num)
>>   {
>>       BDRVParallelsState *s = bs->opaque;
>> -- 
>> 1.9.1
>>

^ permalink raw reply	[flat|nested] 15+ messages in thread

end of thread, other threads:[~2014-11-05 10:51 UTC | newest]

Thread overview: 15+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2014-10-29 13:38 [Qemu-devel] [PATCH v2 0/6] parallels format support improvements Denis V. Lunev
2014-10-29 13:38 ` [Qemu-devel] [PATCH 1/6] configure: add dependency from libxml2 Denis V. Lunev
2014-11-05  7:32   ` Michael Tokarev
2014-11-05  8:19     ` Denis V. Lunev
2014-10-29 13:38 ` [Qemu-devel] [PATCH 2/6] block/parallels: allow to specify DiskDescriptor.xml instead of image file Denis V. Lunev
2014-11-05  2:12   ` Jeff Cody
2014-11-05 10:51     ` Denis V. Lunev
2014-10-29 13:38 ` [Qemu-devel] [PATCH 3/6] iotests: simple parallels XML disk descriptor file test added Denis V. Lunev
2014-11-05  2:24   ` Jeff Cody
2014-10-29 13:38 ` [Qemu-devel] [PATCH 4/6] block/parallels: support padded Parallels images Denis V. Lunev
2014-11-05  2:49   ` Jeff Cody
2014-10-29 13:38 ` [Qemu-devel] [PATCH 5/6] iotests: padded parallels image test Denis V. Lunev
2014-11-05  2:55   ` Jeff Cody
2014-10-29 13:38 ` [Qemu-devel] [PATCH 6/6] parallels: change copyright information in the image header Denis V. Lunev
2014-11-05  2:56   ` Jeff Cody

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).