This patch adds support functions for operating on in memory sized file buffers.

Signed-off-by: Stefan Berger <stef...@linux.vnet.ibm.com>
Signed-off-by: Joel Schopp <jsch...@linux.vnet.ibm.com>
---
 include/migration/qemu-file.h |   12 +++
 include/qemu-common.h         |   15 ++++
 util/qemu-file.c              |  184 +++++++++++++++++++++++++++++++++++++++++
 3 files changed, 211 insertions(+)

diff --git a/include/migration/qemu-file.h b/include/migration/qemu-file.h
index 07d8362..2bc77b1 100644
--- a/include/migration/qemu-file.h
+++ b/include/migration/qemu-file.h
@@ -24,6 +24,8 @@
 #ifndef QEMU_FILE_H
 #define QEMU_FILE_H 1
 
+#include <stdint.h>
+
 /* This function writes a chunk of data to a file at the given position.
  * The pos argument can be ignored if the file is only being used for
  * streaming.  The handler should try to write all of the data it can.
@@ -58,6 +60,14 @@ typedef struct QEMUFileOps {
     QEMUFileGetFD *get_fd;
 } QEMUFileOps;
 
+struct QEMUSizedBuffer {
+    unsigned char *buffer;
+    uint64_t size;
+    uint64_t used;
+};
+
+typedef struct QEMUSizedBuffer QEMUSizedBuffer;
+
 QEMUFile *qemu_fopen_ops(void *opaque, const QEMUFileOps *ops);
 QEMUFile *qemu_fopen(const char *filename, const char *mode);
 QEMUFile *qemu_fdopen(int fd, const char *mode);
@@ -71,6 +81,8 @@ void qemu_put_byte(QEMUFile *f, int v);
 int qemu_read_bytes(QEMUFile *f, uint8_t *buf, int size);
 int qemu_peek_bytes(QEMUFile *f, uint8_t *buf, int size, size_t offset);
 int qemu_write_bytes(QEMUFile *f, const uint8_t *buf, int size);
+QEMUFile *qemu_bufopen(const char *mode, QEMUSizedBuffer *input);
+const QEMUSizedBuffer *qemu_buf_get(QEMUFile *f);
 
 static inline void qemu_put_ubyte(QEMUFile *f, unsigned int v)
 {
diff --git a/include/qemu-common.h b/include/qemu-common.h
index 5e13708..de1cdc0 100644
--- a/include/qemu-common.h
+++ b/include/qemu-common.h
@@ -442,4 +442,19 @@ int64_t pow2floor(int64_t value);
 int uleb128_encode_small(uint8_t *out, uint32_t n);
 int uleb128_decode_small(const uint8_t *in, uint32_t *n);
 
+/* QEMU Sized Buffer */
+#include "include/migration/qemu-file.h"
+QEMUSizedBuffer *qsb_create(const uint8_t *buffer, uint64_t len);
+QEMUSizedBuffer *qsb_clone(const QEMUSizedBuffer *);
+void qsb_free(QEMUSizedBuffer *);
+uint64_t qsb_set_length(QEMUSizedBuffer *qsb, uint64_t length);
+uint64_t qsb_get_length(const QEMUSizedBuffer *qsb);
+const unsigned char *qsb_get_buffer(const QEMUSizedBuffer *, int64_t pos);
+int qsb_write_at(QEMUSizedBuffer *qsb, const uint8_t *buf,
+                 int64_t pos, int size);
+int qsb_append_qsb(QEMUSizedBuffer *dest, const QEMUSizedBuffer *src);
+int qsb_append(QEMUSizedBuffer *dest, const uint8_t *buffer, uint64_t len);
+
+
+
 #endif
diff --git a/util/qemu-file.c b/util/qemu-file.c
index e698713..4442dcc 100644
--- a/util/qemu-file.c
+++ b/util/qemu-file.c
@@ -710,3 +710,187 @@ int qemu_write_bytes(QEMUFile *f, const uint8_t *buf, int 
size)
 
     return size;
 }
+
+
+QEMUSizedBuffer *qsb_create(const uint8_t *buffer, uint64_t len)
+{
+    QEMUSizedBuffer *qsb;
+    uint64_t alloc_len;
+
+    alloc_len = (len > 1024) ? len : 1024;
+
+    qsb = g_new0(QEMUSizedBuffer, 1);
+    if (!qsb) {
+        return NULL;
+    }
+
+    qsb->buffer = g_malloc(alloc_len);
+    if (!qsb->buffer) {
+        g_free(qsb);
+        return NULL;
+    }
+    qsb->size = alloc_len;
+
+    if (buffer) {
+        memcpy(qsb->buffer, buffer, len);
+        qsb->used = len;
+    }
+
+    return qsb;
+}
+
+void qsb_free(QEMUSizedBuffer *qsb)
+{
+    if (!qsb) {
+        return;
+    }
+    g_free(qsb->buffer);
+    g_free(qsb);
+}
+
+uint64_t qsb_get_length(const QEMUSizedBuffer *qsb)
+{
+    return qsb->used;
+}
+
+uint64_t qsb_set_length(QEMUSizedBuffer *qsb, uint64_t new_len)
+{
+    if (new_len <= qsb->size) {
+        qsb->used = new_len;
+    } else {
+        qsb->used = qsb->size;
+    }
+    return qsb->used;
+}
+
+const unsigned char *qsb_get_buffer(const QEMUSizedBuffer *qsb, int64_t pos)
+{
+    if (pos < qsb->used) {
+        return &qsb->buffer[pos];
+    }
+    return NULL;
+}
+
+int qsb_write_at(QEMUSizedBuffer *qsb, const uint8_t *buf,
+                 int64_t pos, int size)
+{
+    if (pos + size > qsb->size) {
+        qsb->buffer = g_realloc(qsb->buffer, pos + size + 1024);
+        if (qsb->buffer == NULL) {
+            return -ENOMEM;
+        }
+        qsb->size = pos + size;
+    }
+    memcpy(&qsb->buffer[pos], buf, size);
+    if (pos + size > qsb->used) {
+        qsb->used = pos + size;
+    }
+
+    return size;
+}
+
+int qsb_append_qsb(QEMUSizedBuffer *dest, const QEMUSizedBuffer *src)
+{
+    return qsb_write_at(dest, qsb_get_buffer(src, 0),
+                        qsb_get_length(dest), qsb_get_length(src));
+}
+
+int qsb_append(QEMUSizedBuffer *dest, const uint8_t *buf, uint64_t len)
+{
+    return qsb_write_at(dest, buf,
+                        qsb_get_length(dest), len);
+}
+
+QEMUSizedBuffer *qsb_clone(const QEMUSizedBuffer *in)
+{
+    return qsb_create(qsb_get_buffer(in, 0),
+                      qsb_get_length(in));
+}
+
+typedef struct QEMUBuffer {
+    QEMUSizedBuffer *qsb;
+    QEMUFile *file;
+} QEMUBuffer;
+
+static int buf_get_buffer(void *opaque, uint8_t *buf, int64_t pos, int size)
+{
+    QEMUBuffer *s = opaque;
+    ssize_t len = qsb_get_length(s->qsb) - pos;
+
+    if (len <= 0) {
+        return 0;
+    }
+
+    if (len > size) {
+        len = size;
+    }
+    memcpy(buf, qsb_get_buffer(s->qsb, pos), len);
+
+    return len;
+}
+
+static int buf_put_buffer(void *opaque, const uint8_t *buf,
+                          int64_t pos, int size)
+{
+    QEMUBuffer *s = opaque;
+
+    return qsb_write_at(s->qsb, buf, pos, size);
+}
+
+static int buf_close(void *opaque)
+{
+    QEMUBuffer *s = opaque;
+
+    qsb_free(s->qsb);
+
+    g_free(s);
+
+    return 0;
+}
+
+const QEMUSizedBuffer *qemu_buf_get(QEMUFile *f)
+{
+    QEMUBuffer *p;
+
+    qemu_fflush(f);
+
+    p = (QEMUBuffer *)f->opaque;
+
+    return p->qsb;
+}
+
+static const QEMUFileOps buf_read_ops = {
+    .get_buffer = buf_get_buffer,
+    .close =      buf_close
+};
+
+static const QEMUFileOps buf_write_ops = {
+    .put_buffer = buf_put_buffer,
+    .close =      buf_close
+};
+
+QEMUFile *qemu_bufopen(const char *mode, QEMUSizedBuffer *input)
+{
+    QEMUBuffer *s;
+
+    if (mode == NULL || (mode[0] != 'r' && mode[0] != 'w') || mode[1] != 0) {
+        fprintf(stderr, "qemu_bufopen: Argument validity check failed\n");
+        return NULL;
+    }
+
+    s = g_malloc0(sizeof(QEMUBuffer));
+    if (mode[0] == 'r') {
+        s->qsb = input;
+    }
+
+    if (s->qsb == NULL) {
+        s->qsb = qsb_create(NULL, 0);
+    }
+
+    if (mode[0] == 'r') {
+        s->file = qemu_fopen_ops(s, &buf_read_ops);
+    } else {
+        s->file = qemu_fopen_ops(s, &buf_write_ops);
+    }
+    return s->file;
+}
-- 
1.7.10.4


Reply via email to