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