[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Qemu-devel] [RFC PATCH 07/16] Visitor: Binary compatible input visitor
From: |
Dr. David Alan Gilbert (git) |
Subject: |
[Qemu-devel] [RFC PATCH 07/16] Visitor: Binary compatible input visitor |
Date: |
Tue, 25 Mar 2014 20:17:18 +0000 |
From: "Dr. David Alan Gilbert" <address@hidden>
based on Michael Roth's
https://lists.gnu.org/archive/html/qemu-devel/2011-09/msg02470.html
Signed-off-by: Dr. David Alan Gilbert <address@hidden>
---
include/qapi/qemu-file-binary-input-visitor.h | 27 +
qapi/Makefile.objs | 2 +-
qapi/qemu-file-binary-input-visitor.c | 688 ++++++++++++++++++++++++++
3 files changed, 716 insertions(+), 1 deletion(-)
create mode 100644 include/qapi/qemu-file-binary-input-visitor.h
create mode 100644 qapi/qemu-file-binary-input-visitor.c
diff --git a/include/qapi/qemu-file-binary-input-visitor.h
b/include/qapi/qemu-file-binary-input-visitor.h
new file mode 100644
index 0000000..dd7e40e
--- /dev/null
+++ b/include/qapi/qemu-file-binary-input-visitor.h
@@ -0,0 +1,27 @@
+/*
+ * QEMUFile Visitor
+ *
+ * Copyright IBM, Corp. 2011
+ *
+ * Authors:
+ * Michael Roth <address@hidden>
+ *
+ * This work is licensed under the terms of the GNU LGPL, version 2.1 or later.
+ * See the COPYING.LIB file in the top-level directory.
+ *
+ */
+
+#ifndef QEMU_FILE_BINARY_INPUT_VISITOR_H
+#define QEMU_FILE_BINARY_INPUT_VISITOR_H
+
+#include "visitor.h"
+
+typedef struct QemuFileBinInputVisitor QemuFileBinInputVisitor;
+
+QemuFileBinInputVisitor *qemu_file_bin_input_visitor_new(QEMUFile *f);
+void qemu_file_bin_input_visitor_cleanup(QemuFileBinInputVisitor *d);
+
+Visitor *qemu_file_bin_input_get_visitor(QemuFileBinInputVisitor *v);
+
+#endif
+
diff --git a/qapi/Makefile.objs b/qapi/Makefile.objs
index 06c69e6..3d9d47a 100644
--- a/qapi/Makefile.objs
+++ b/qapi/Makefile.objs
@@ -1,6 +1,6 @@
util-obj-y = qapi-visit-core.o qapi-dealloc-visitor.o qmp-input-visitor.o
util-obj-y += qmp-output-visitor.o qmp-registry.o qmp-dispatch.o
util-obj-y += string-input-visitor.o string-output-visitor.o
-util-obj-y += qemu-file-binary-output-visitor.o
+util-obj-y += qemu-file-binary-output-visitor.o
qemu-file-binary-input-visitor.o
util-obj-y += qemu-file-debug-output-visitor.o
util-obj-y += opts-visitor.o
diff --git a/qapi/qemu-file-binary-input-visitor.c
b/qapi/qemu-file-binary-input-visitor.c
new file mode 100644
index 0000000..162765e
--- /dev/null
+++ b/qapi/qemu-file-binary-input-visitor.c
@@ -0,0 +1,688 @@
+/*
+ * QEMUFile Output Visitor
+ *
+ * Copyright IBM, Corp. 2011
+ * Copyright Red Hat, Corp. 2014
+ *
+ * Authors:
+ * Michael Roth <address@hidden>
+ * David Gilbert <address@hidden>
+ *
+ * This work is licensed under the terms of the GNU LGPL, version 2.1 or later.
+ * See the COPYING.LIB file in the top-level directory.
+ *
+ */
+
+#include "qapi/qemu-file-binary-input-visitor.h"
+#include "qapi/visitor-impl.h"
+#include "qapi/qmp/qerror.h"
+#include "qemu/queue.h"
+#include "qemu-common.h"
+#include "hw/hw.h"
+#include "migration/migration.h"
+
+/* Note that this can generate so much debug virt-test times out */
+#if 0
+#define DPRINTF(v, fmt, ...) \
+ do { \
+ fprintf(stderr, "%*s qfbiv/%s/%d: " fmt "\n", v->depth, "", __func__, \
+ __LINE__, ## __VA_ARGS__); \
+ } while (0)
+#else
+#define DPRINTF(v, fmt, ...) \
+ do { } while (0)
+#endif
+
+typedef struct {
+ size_t elem_count;
+ size_t elem_size;
+ size_t pos;
+} ArrayInfo;
+
+typedef struct {
+ Visit_seq_compat_mode mode;
+ const void *data;
+ bool hit_end;
+} SeqCompatInfo;
+
+typedef struct StackEntry {
+ enum {
+ QFIV_ARRAY,
+ QFIV_LIST,
+ QFIV_STRUCT,
+ QFIV_SEQCOMPAT,
+ } type;
+ ArrayInfo array_info;
+ SeqCompatInfo seqcompat_info;
+ QTAILQ_ENTRY(StackEntry) node;
+} StackEntry;
+
+struct QemuFileBinInputVisitor {
+ Visitor visitor;
+ QTAILQ_HEAD(, StackEntry) stack;
+ QEMUFile *file;
+ unsigned int depth;
+};
+
+static QemuFileBinInputVisitor *to_iv(Visitor *v)
+{
+ return container_of(v, QemuFileBinInputVisitor, visitor);
+}
+
+static void qfbi_push(QemuFileBinInputVisitor *iv, StackEntry *e)
+{
+ QTAILQ_INSERT_HEAD(&iv->stack, e, node);
+ iv->depth++;
+}
+
+static void qfbi_push_array(QemuFileBinInputVisitor *iv,
+ ArrayInfo ai)
+{
+ StackEntry *e = g_malloc0(sizeof(*e));
+ e->type = QFIV_ARRAY;
+ e->array_info = ai;
+ qfbi_push(iv, e);
+}
+
+static void qfbi_push_list(QemuFileBinInputVisitor *iv)
+{
+ StackEntry *e = g_malloc0(sizeof(*e));
+ e->type = QFIV_LIST;
+ qfbi_push(iv, e);
+}
+
+static void qfbi_push_seqcompat(QemuFileBinInputVisitor *iv,
+ SeqCompatInfo sci)
+{
+ StackEntry *e = g_malloc0(sizeof(*e));
+ e->type = QFIV_SEQCOMPAT;
+ e->seqcompat_info = sci;
+ qfbi_push(iv, e);
+}
+
+static void qfbi_push_struct(QemuFileBinInputVisitor *iv)
+{
+ StackEntry *e = g_malloc0(sizeof(*e));
+ e->type = QFIV_STRUCT;
+ qfbi_push(iv, e);
+}
+
+static void *qfbi_pop(QemuFileBinInputVisitor *iv)
+{
+ StackEntry *e = QTAILQ_FIRST(&iv->stack);
+ QTAILQ_REMOVE(&iv->stack, e, node);
+ iv->depth--;
+ return e;
+}
+
+static bool qfbi_is_array(QemuFileBinInputVisitor *iv)
+{
+ StackEntry *e = QTAILQ_FIRST(&iv->stack);
+ return e->type == QFIV_ARRAY;
+}
+
+static bool qfbi_is_list(QemuFileBinInputVisitor *iv)
+{
+ StackEntry *e = QTAILQ_FIRST(&iv->stack);
+ return e && e->type == QFIV_LIST;
+}
+
+/* If we are in a seqcompat list return true and fill in
+ * sci with the compat mode
+ */
+static bool qfbi_is_seqcompat(QemuFileBinInputVisitor *iv,
+ SeqCompatInfo **sci)
+{
+ StackEntry *e = QTAILQ_FIRST(&iv->stack);
+ if (e && e->type == QFIV_SEQCOMPAT) {
+ *sci = &e->seqcompat_info;
+ return true;
+ }
+ return false;
+}
+
+static void qfbi_start_struct(Visitor *v, void **obj,
+ const char *kind,
+ const char *name, size_t size,
+ Error **errp)
+{
+ QemuFileBinInputVisitor *iv = to_iv(v);
+ DPRINTF(iv, "for '%s' of '%s'", name, kind);
+
+ qfbi_push_struct(iv);
+}
+
+static void qfbi_end_struct(Visitor *v, Error **errp)
+{
+ QemuFileBinInputVisitor *iv = to_iv(v);
+ StackEntry *e = qfbi_pop(iv);
+
+ DPRINTF(iv, "<");
+ if (!e || e->type != QFIV_STRUCT) {
+ error_set(errp, QERR_UNDEFINED_ERROR);
+ return;
+ }
+ g_free(e);
+}
+
+static void qfbi_start_list(Visitor *v, const char *name, Error **errp)
+{
+ QemuFileBinInputVisitor *iv = to_iv(v);
+ qfbi_push_list(iv);
+}
+
+static GenericList *qfbi_next_list(Visitor *v, GenericList **list, Error
**errp)
+{
+ QemuFileBinInputVisitor *iv = to_iv(v);
+ GenericList *entry;
+
+ if (!qfbi_is_list(iv)) {
+ error_set(errp, QERR_UNDEFINED_ERROR);
+ }
+
+ /* Some users maintain their own list structure */
+ if (!list) {
+ return NULL;
+ }
+
+ entry = g_malloc0(sizeof(*entry));
+ if (*list) {
+ (*list)->next = entry;
+ }
+
+ *list = entry;
+ return entry;
+}
+
+static void qfbi_end_list(Visitor *v, Error **errp)
+{
+ QemuFileBinInputVisitor *iv = to_iv(v);
+ StackEntry *e = qfbi_pop(iv);
+ if (!e || e->type != QFIV_LIST) {
+ error_set(errp, QERR_UNDEFINED_ERROR);
+ return;
+ }
+ g_free(e);
+}
+
+static void qfbi_start_array(Visitor *v, void **obj, const char *name,
+ size_t elem_count, size_t elem_size, Error **errp)
+{
+ QemuFileBinInputVisitor *iv = to_iv(v);
+ ArrayInfo ai = {
+ .elem_count = elem_count,
+ .elem_size = elem_size,
+ .pos = 0
+ };
+ if (obj && (*obj == NULL) && elem_size) {
+ *obj = g_malloc0(elem_count * elem_size);
+ }
+ qfbi_push_array(iv, ai);
+}
+
+static void qfbi_next_array(Visitor *v, Error **errp)
+{
+ QemuFileBinInputVisitor *iv = to_iv(v);
+ StackEntry *e = QTAILQ_FIRST(&iv->stack);
+
+ if (!qfbi_is_array(iv) ||
+ e->array_info.pos >= e->array_info.elem_count) {
+ error_set(errp, QERR_UNDEFINED_ERROR);
+ }
+
+ e->array_info.pos++;
+}
+
+static void qfbi_end_array(Visitor *v, Error **errp)
+{
+ QemuFileBinInputVisitor *iv = to_iv(v);
+ StackEntry *e = qfbi_pop(iv);
+ if (!e || e->type != QFIV_ARRAY) {
+ error_set(errp, QERR_UNDEFINED_ERROR);
+ return;
+ }
+ g_free(e);
+}
+
+static void qfbi_type_str(Visitor *v, char **obj, const char *name,
+ Error **errp)
+{
+ if (obj) {
+ g_free(*obj);
+ }
+}
+
+/* Read in a byte+buffer -> giving a string. obj must be a buffer of
+ * at least 256 chars in length
+ */
+static void qfbi_type_str256(Visitor *v, char *obj, const char *name,
+ Error **errp)
+{
+ QemuFileBinInputVisitor *iv = to_iv(v);
+ unsigned int len = qemu_get_byte(iv->file);
+
+ qemu_get_buffer(iv->file, (uint8_t *)obj, len);
+ obj[len] = 0;
+ DPRINTF(iv, "for '%s' len=%d str=%s", name, len, obj);
+}
+
+static void qfbi_type_buffer(Visitor *v, void *data, size_t len, bool async,
+ const char *name, Error **errp)
+{
+ QemuFileBinInputVisitor *iv = to_iv(v);
+ qemu_get_buffer(iv->file, data, len);
+}
+
+static void qfbi_type_uint8(Visitor *v, uint8_t *obj, const char *name,
+ Error **errp)
+{
+ QemuFileBinInputVisitor *iv = to_iv(v);
+ *obj = qemu_get_byte(iv->file);
+ DPRINTF(iv, "for '%s' / %u", name, *obj);
+}
+
+static void qfbi_type_uint16(Visitor *v, uint16_t *obj, const char *name,
+ Error **errp)
+{
+ QemuFileBinInputVisitor *iv = to_iv(v);
+ qemu_get_be16s(iv->file, obj);
+ DPRINTF(iv, "for '%s' / %u", name, *obj);
+}
+
+static void qfbi_type_uint32(Visitor *v, uint32_t *obj, const char *name,
+ Error **errp)
+{
+ QemuFileBinInputVisitor *iv = to_iv(v);
+ qemu_get_be32s(iv->file, obj);
+ DPRINTF(iv, "for '%s' / %u", name, *obj);
+}
+
+static void qfbi_type_uint64(Visitor *v, uint64_t *obj, const char *name,
+ Error **errp)
+{
+ QemuFileBinInputVisitor *iv = to_iv(v);
+ qemu_get_be64s(iv->file, obj);
+ DPRINTF(iv, "for '%s' / %lu", name, *obj);
+}
+
+static void qfbi_type_int8(Visitor *v, int8_t *obj, const char *name,
+ Error **errp)
+{
+ QemuFileBinInputVisitor *iv = to_iv(v);
+ *obj = qemu_get_sbyte(iv->file);
+ DPRINTF(iv, "for '%s' / %d", name, *obj);
+}
+
+static void qfbi_type_int16(Visitor *v, int16_t *obj, const char *name,
+ Error **errp)
+{
+ QemuFileBinInputVisitor *iv = to_iv(v);
+ qemu_get_sbe16s(iv->file, obj);
+ DPRINTF(iv, "for '%s' / %d", name, *obj);
+}
+
+static void qfbi_type_int32(Visitor *v, int32_t *obj, const char *name,
+ Error **errp)
+{
+ QemuFileBinInputVisitor *iv = to_iv(v);
+ qemu_get_sbe32s(iv->file, obj);
+ DPRINTF(iv, "for '%s' / %d", name, *obj);
+}
+
+static void qfbi_type_int64(Visitor *v, int64_t *obj, const char *name,
+ Error **errp)
+{
+ QemuFileBinInputVisitor *iv = to_iv(v);
+ qemu_get_sbe64s(iv->file, obj);
+ DPRINTF(iv, "for '%s' / %ld", name, *obj);
+}
+
+static void qfbi_type_bool(Visitor *v, bool *obj, const char *name,
+ Error **errp)
+{
+ uint8_t val;
+ qfbi_type_uint8(v, &val, name, errp);
+ *obj = val;
+}
+
+static QEMUFile *qfbi_get_qemufile(Visitor *v)
+{
+ QemuFileBinInputVisitor *iv = to_iv(v);
+
+ return iv->file;
+}
+
+static void qfbi_get_next_type(Visitor *v, int *kind, const int *qobjects,
+ const char *name, Error **errp)
+{
+ QemuFileBinInputVisitor *iv = to_iv(v);
+ SeqCompatInfo *sci;
+ uint64_t tmp64;
+ uint8_t tmpbyte;
+
+ DPRINTF(iv, "for '%s'", name);
+ if (qfbi_is_seqcompat(iv, &sci)) {
+ DPRINTF(iv, "/seqcompat for '%s'", name);
+ if (sci->hit_end) {
+ error_setg(errp, "Attempted to read beyond the end of list '%s'",
+ name);
+ *kind = -1;
+ return;
+ }
+
+ DPRINTF(iv, "/seqcompat for '%s' mode=%d tmpbyte=%d", name, sci->mode,
+ tmpbyte);
+ switch (sci->mode) {
+ case VISIT_SEQ_COMPAT_BYTE0TERM:
+ /*
+ * End of the list is marked by a 0 byte,
+ * we'll consume the byte read
+ */
+ tmpbyte = qemu_get_byte(iv->file);
+ if (tmpbyte == 0) {
+ sci->hit_end = true;
+ }
+ *kind = tmpbyte;
+ break;
+
+ case VISIT_SEQ_COMPAT_RAMSECLIST:
+ /*
+ * the RAM sections are lists of entries each that start with a
+ * 64 bit word that has an address or length, OR'd with a set of
+ * the RAM_SAVE_FLAG_ bits; RAM_SAVE_FLAG_EOS indicates the end
+ * of the list.
+ * We don't consume the word since it'll be consumed by
+ * the SEQ_COMPAT_RAMSECENTRY; except for the EOS
+ */
+
+ if (qemu_peek_buffer(iv->file, (uint8_t *)&tmp64, 8, 0) != 8) {
+ error_setg(errp, "Failed to read flag word for '%s'", name);
+ *kind = -1;
+ return;
+ }
+
+ tmp64 = be64_to_cpu(tmp64);
+
+ *kind = tmp64 & RAM_SAVE_FLAG_MASK;
+ DPRINTF(iv, "tmp64=0x%lx *kind=%x\n", tmp64, *kind);
+ if (tmp64 & RAM_SAVE_FLAG_EOS) {
+ tmp64 = qemu_get_be64(iv->file); /* Consume terminator */
+ sci->hit_end = true;
+ }
+ break;
+
+ case VISIT_SEQ_COMPAT_SUBSECLIST:
+ /* In theory subsections are terminated by a
+ * byte != QEMU_VM_SUBSECTION
+ * and that byte is part of whatever comes next, so we mustn't
+ * consume the terminator if it's not valid.
+ * However, it's worse than that, historical layouts weren't
+ * really that careful about what came next, so you can get
+ * false sections, so we check everything in the header and if
+ * it's not valid we declare it end-of-section.
+ * For this case the 'opaque' passed in is the parent string
+ * name.
+ */
+ if (qemu_peek_buffer(iv->file, &tmpbyte, 1, 0) != 1) {
+ error_setg(errp, "Failed to read type byte for '%s'", name);
+ *kind = -1;
+ return;
+ }
+
+ if (tmpbyte == QEMU_VM_SUBSECTION) {
+ uint8_t len, size;
+ char idstr[256];
+ char *parent_name = (char *)sci->data;
+ size_t pn_len = strlen(parent_name);
+ DPRINTF(iv, "/subsection for '%s'/%s", name, parent_name);
+
+ len = qemu_peek_byte(iv->file, 1);
+ if (len < (pn_len + 1)) {
+ DPRINTF(iv, "/subsection for '%s'/%s - len too short",
+ name, parent_name);
+ sci->hit_end = true;
+ *kind = 0xff;
+ break;
+ }
+ size = qemu_peek_buffer(iv->file, (uint8_t *)idstr,
+ len, 2);
+ if (size != len) {
+ DPRINTF(iv, "/subsection for '%s'/%s - size!=len",
+ name, parent_name);
+ sci->hit_end = true;
+ *kind = 0xff;
+ break;
+ }
+ idstr[size] = 0;
+
+ if (strncmp(parent_name, idstr, pn_len) != 0) {
+ DPRINTF(iv, "/subsection for n='%s' / pn='%s' "
+ "idstr='%s' - invalid subsection name",
+ name, parent_name, idstr);
+ /* it don't have a valid subsection name */
+ sci->hit_end = true;
+ *kind = 0xff;
+ break;
+ }
+ qemu_file_skip(iv->file, 1); /* subsection byte */
+
+ /* We're not going to consume the name or idstr here
+ * since they're logically part of the item not the
+ * list, so they're going to get re-read.
+ */
+ DPRINTF(iv, "/subsection for '%s' got %s from %s "
+ "tmpbyte=%d", name, idstr, parent_name,
+ tmpbyte);
+ } else {
+ sci->hit_end = true;
+ }
+ *kind = tmpbyte;
+ break;
+
+ default:
+ *kind = -1;
+ error_set(errp, QERR_UNDEFINED_ERROR);
+ return;
+ }
+ return;
+ }
+
+ /* Only dealing with SeqCompat's for the moment */
+ error_set(errp, QERR_UNDEFINED_ERROR);
+}
+
+static void qfbi_start_sequence_compat(Visitor *v, const char *name,
+ Visit_seq_compat_mode compat_mode,
+ void *opaque, Error **errp)
+{
+ QemuFileBinInputVisitor *iv = to_iv(v);
+ SeqCompatInfo sci = {
+ .mode = compat_mode,
+ .data = opaque
+ };
+ SectionHeader *sh;
+ ramsecentry_header *rse_hdr;
+ unsigned int len;
+ uint32_t tmp;
+ uint64_t tmp64;
+
+ switch (compat_mode) {
+ case VISIT_SEQ_COMPAT_FILE:
+ tmp = qemu_get_be32(iv->file);
+ if (tmp != QEMU_VM_FILE_MAGIC) {
+ error_setg(errp, "Incorrect SaveVM file header (read)");
+ return;
+ }
+
+ tmp = qemu_get_be32(iv->file);
+ if (tmp == QEMU_VM_FILE_VERSION_COMPAT) {
+ error_setg(errp, "SaveVM v2 format is obsolete and will not load");
+ return;
+ }
+ if (tmp != QEMU_VM_FILE_VERSION) {
+ error_setg(errp, "Unsupported SaveVM format (%d)", tmp);
+ return;
+ }
+ sci.hit_end = true; /* It doesn't iterate over this as a list */
+ break;
+
+ case VISIT_SEQ_COMPAT_SECTION_HEADER:
+ /*
+ * for VM_SECTION_FULL and VM_SECTION_START
+ * 'opaque' points to a struct Sectionheader
+ */
+ sh = opaque;
+ sh->section_id = qemu_get_be32(iv->file);
+ len = qemu_get_byte(iv->file);
+ qemu_get_buffer(iv->file, (uint8_t *)sh->idstr, len);
+ sh->idstr[len] = 0;
+ sh->instance_id = qemu_get_be32(iv->file);
+ sh->version_id = qemu_get_be32(iv->file);
+ DPRINTF(iv, "for '%s'/%s v %d", name, sh->idstr, sh->version_id);
+ sci.hit_end = true; /* It doesn't iterate over this as a list */
+ break;
+
+ case VISIT_SEQ_COMPAT_SECTION_MIN:
+ /* for VM_SECTION_PART?END where the section ID is already known */
+ sh = opaque;
+ sh->section_id = qemu_get_be32(iv->file);
+ sci.hit_end = true; /* It doesn't iterate over this as a list */
+ break;
+
+
+ case VISIT_SEQ_COMPAT_VMSTATE:
+ /* These don't need anything in the header on the compatibility side */
+ sci.hit_end = true; /* It doesn't iterate over this as a list */
+ break;
+
+ case VISIT_SEQ_COMPAT_BYTE0TERM:
+ case VISIT_SEQ_COMPAT_SUBSECLIST:
+ case VISIT_SEQ_COMPAT_RAMSECLIST:
+ /* These don't need anything in the header on the compatibility side */
+ break;
+
+ case VISIT_SEQ_COMPAT_RAMSECENTRY:
+ rse_hdr = opaque;
+ tmp64 = qemu_get_be64(iv->file);
+ rse_hdr->flags = tmp64 & RAM_SAVE_FLAG_MASK;
+ rse_hdr->addr = tmp64 - rse_hdr->flags;
+ if ((rse_hdr->flags &
+ (RAM_SAVE_FLAG_CONTINUE | RAM_SAVE_FLAG_MEM_SIZE |
+ RAM_SAVE_FLAG_HOOK)) == 0) {
+ len = qemu_get_byte(iv->file);
+ qemu_get_buffer(iv->file, (uint8_t *)rse_hdr->idstr, len);
+ rse_hdr->idstr[len] = 0;
+ }
+ sci.hit_end = true; /* It doesn't iterate over this as a list */
+ break;
+
+ case VISIT_SEQ_COMPAT_SUBSECTION: /* An element in a subsection list */
+ sh = opaque;
+ len = qemu_get_byte(iv->file);
+ qemu_get_buffer(iv->file, (uint8_t *)sh->idstr, len);
+ sh->idstr[len] = 0;
+ sh->version_id = qemu_get_be32(iv->file);
+ DPRINTF(iv, "for '%s'/%s v %d", name, sh->idstr, sh->version_id);
+ sci.hit_end = true; /* It doesn't iterate over this as a list */
+ break;
+
+ case VISIT_SEQ_COMPAT_BLOB:
+ /* Nothing in the header, but opaque gets a copy of our QEMUFile -
+ * other implementations might give a different QEMUFile
+ */
+ *(QEMUFile **)opaque = iv->file;
+ sci.hit_end = true; /* It doesn't iterate over this as a list */
+ break;
+
+ }
+
+ DPRINTF(iv, "for '%s'", name);
+ qfbi_push_seqcompat(iv, sci);
+
+
+ /* We don't need to read anything at this point */
+}
+
+static void qfbi_end_sequence_compat(Visitor *v, const char* name,
+ Visit_seq_compat_mode compat_mode,
+ Error **errp)
+{
+ QemuFileBinInputVisitor *iv = to_iv(v);
+ StackEntry *e = qfbi_pop(iv);
+ DPRINTF(iv, "> for '%s'", name);
+ if (!e || e->type != QFIV_SEQCOMPAT) {
+ error_setg(errp, "bad struct stack %d", e ? e->type : -1);
+ if (e) {
+ g_free(e);
+ }
+ return;
+ }
+ if (e->seqcompat_info.mode != compat_mode) {
+ error_setg(errp, "mismatched seqcompat mode %d/%d", compat_mode,
+ e->seqcompat_info.mode);
+ }
+ if (!*errp && !e->seqcompat_info.hit_end) {
+ error_setg(errp, "Didn't read the whole of list for '%s'", name);
+ }
+ g_free(e);
+}
+
+static void qfbi_destroy(Visitor *v, Error **errp)
+{
+ QemuFileBinInputVisitor *iv = to_iv(v);
+
+ qemu_file_bin_input_visitor_cleanup(iv);
+}
+
+Visitor *qemu_file_bin_input_get_visitor(QemuFileBinInputVisitor *iv)
+{
+ return &iv->visitor;
+}
+
+void qemu_file_bin_input_visitor_cleanup(QemuFileBinInputVisitor *iv)
+{
+ g_free(iv);
+}
+
+QemuFileBinInputVisitor *qemu_file_bin_input_visitor_new(QEMUFile *f)
+{
+ QemuFileBinInputVisitor *v;
+
+ v = g_malloc0(sizeof(*v));
+
+ v->file = f;
+
+ v->visitor.start_struct = qfbi_start_struct;
+ v->visitor.end_struct = qfbi_end_struct;
+ v->visitor.start_list = qfbi_start_list;
+ v->visitor.next_list = qfbi_next_list;
+ v->visitor.end_list = qfbi_end_list;
+ v->visitor.start_array = qfbi_start_array;
+ v->visitor.next_array = qfbi_next_array;
+ v->visitor.end_array = qfbi_end_array;
+ v->visitor.type_int = qfbi_type_int64;
+ v->visitor.type_buffer = qfbi_type_buffer;
+ v->visitor.type_uint8 = qfbi_type_uint8;
+ v->visitor.type_uint16 = qfbi_type_uint16;
+ v->visitor.type_uint32 = qfbi_type_uint32;
+ v->visitor.type_uint64 = qfbi_type_uint64;
+ v->visitor.type_int8 = qfbi_type_int8;
+ v->visitor.type_int16 = qfbi_type_int16;
+ v->visitor.type_int32 = qfbi_type_int32;
+ v->visitor.type_int64 = qfbi_type_int64;
+ v->visitor.type_bool = qfbi_type_bool;
+ v->visitor.type_str = qfbi_type_str;
+ v->visitor.type_str256 = qfbi_type_str256;
+ v->visitor.destroy = qfbi_destroy;
+ v->visitor.start_sequence_compat = qfbi_start_sequence_compat;
+ v->visitor.get_next_type = qfbi_get_next_type;
+ v->visitor.end_sequence_compat = qfbi_end_sequence_compat;
+ v->visitor.get_qemufile = qfbi_get_qemufile;
+
+ v->visitor.flags = VISITOR_LOADING;
+
+ QTAILQ_INIT(&v->stack);
+ v->depth = 0;
+
+ return v;
+}
--
1.8.5.3
- [Qemu-devel] [RFC PATCH 04/16] Header/constant/types fixes for visitors, (continued)
- [Qemu-devel] [RFC PATCH 04/16] Header/constant/types fixes for visitors, Dr. David Alan Gilbert (git), 2014/03/25
- [Qemu-devel] [RFC PATCH 06/16] Visitor: Debug output visitor, Dr. David Alan Gilbert (git), 2014/03/25
- [Qemu-devel] [RFC PATCH 08/16] Visitor: Output path, Dr. David Alan Gilbert (git), 2014/03/25
- [Qemu-devel] [RFC PATCH 09/16] Visitor: Load path, Dr. David Alan Gilbert (git), 2014/03/25
- [Qemu-devel] [RFC PATCH 12/16] BER Visitor: Create output visitor, Dr. David Alan Gilbert (git), 2014/03/25
- [Qemu-devel] [RFC PATCH 13/16] BER Visitor: Create input visitor, Dr. David Alan Gilbert (git), 2014/03/25
- [Qemu-devel] [RFC PATCH 14/16] Start some BER format docs, Dr. David Alan Gilbert (git), 2014/03/25
- [Qemu-devel] [RFC PATCH 15/16] ASN.1 schema for new migration format, Dr. David Alan Gilbert (git), 2014/03/25
- [Qemu-devel] [RFC PATCH 01/16] Visitor: Add methods for migration format use, Dr. David Alan Gilbert (git), 2014/03/25
- [Qemu-devel] [RFC PATCH 03/16] qemu-file: Add set/get tmp_visitor, Dr. David Alan Gilbert (git), 2014/03/25
- [Qemu-devel] [RFC PATCH 07/16] Visitor: Binary compatible input visitor,
Dr. David Alan Gilbert (git) <=
- [Qemu-devel] [RFC PATCH 10/16] Visitor: Common types to use visitors, Dr. David Alan Gilbert (git), 2014/03/25
- [Qemu-devel] [RFC PATCH 11/16] Choose output visitor based on env variable, Dr. David Alan Gilbert (git), 2014/03/25
- [Qemu-devel] [RFC PATCH 16/16] Wire in BER visitors, Dr. David Alan Gilbert (git), 2014/03/25
- Re: [Qemu-devel] [RFC PATCH 00/16] visitor+BER migration format, Michael S. Tsirkin, 2014/03/25