diff mbox

[RFC,v2,03/16] QEMUFilePart: A shim to read part of a file

Message ID 1398271069-22057-4-git-send-email-dgilbert@redhat.com
State New
Headers show

Commit Message

Dr. David Alan Gilbert April 23, 2014, 4:37 p.m. UTC
From: "Dr. David Alan Gilbert" <dgilbert@redhat.com>

QEMUFilePart takes a backing QEMUFile and a length, and exposes only
'length' bytes from the backing QEMUFile.

Signed-off-by: Dr. David Alan Gilbert <dgilbert@redhat.com>
---
 include/migration/qemu-file.h |  2 ++
 qemu-file.c                   | 73 +++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 75 insertions(+)
diff mbox

Patch

diff --git a/include/migration/qemu-file.h b/include/migration/qemu-file.h
index f066801..88728c9 100644
--- a/include/migration/qemu-file.h
+++ b/include/migration/qemu-file.h
@@ -121,6 +121,8 @@  QEMUFile *qemu_fdopen(int fd, const char *mode);
 QEMUFile *qemu_fopen_socket(int fd, const char *mode);
 QEMUFile *qemu_popen_cmd(const char *command, const char *mode);
 QEMUFile *qemu_bufopen(const char *mode, QEMUSizedBuffer *input);
+QEMUFile *qemu_partopen(const char *mode, QEMUFile *backing, size_t len);
+
 int qemu_get_fd(QEMUFile *f);
 int qemu_fclose(QEMUFile *f);
 int64_t qemu_ftell(QEMUFile *f);
diff --git a/qemu-file.c b/qemu-file.c
index a5bf643..eec4dbc 100644
--- a/qemu-file.c
+++ b/qemu-file.c
@@ -1244,3 +1244,76 @@  QEMUFile *qemu_bufopen(const char *mode, QEMUSizedBuffer *input)
     }
     return s->file;
 }
+
+/*
+ * 'part' QEMUFile is a QEMUFile that will return 'n' bytes from another
+ * QEMUFile (at it's current pointer) and then stop
+ * It never reads past 'n' on the backing QEMUFile, thus allowing the caller
+ * to carry on reading * from the original file.
+ */
+typedef struct QEMUFilePart {
+    QEMUFile *backing;
+    size_t remaining_to_read; /* Bytes left that we can read from backing */
+    QEMUFile *file;
+} QEMUFilePart;
+
+static int part_get_buffer(void *opaque, uint8_t *buf, int64_t pos, int size)
+{
+    QEMUFilePart *p = opaque;
+    int toread, res;
+
+    if (pos != 0) {
+        /* Not bothering with offsets */
+        return -EINVAL;
+    }
+
+    toread = MIN(size, p->remaining_to_read);
+
+    if (toread == 0) {
+        /* All done */
+        return 0;
+    }
+
+    res = qemu_get_buffer(p->backing, buf, toread);
+
+    if (res > 0) {
+        p->remaining_to_read -= res;
+    }
+
+    return res;
+}
+
+static int part_close(void *opaque)
+{
+    QEMUFilePart *p = opaque;
+
+    g_free(p);
+
+    /* Note we don't close the backing file, that's still usable */
+
+    return 0;
+}
+
+static const QEMUFileOps part_read_ops = {
+    .get_buffer = part_get_buffer,
+    .close      = part_close
+};
+
+QEMUFile *qemu_partopen(const char *mode, QEMUFile *backing, size_t len)
+{
+    QEMUFilePart *p;
+
+    if (mode == NULL || strcmp(mode, "r")) {
+        error_report("qemu_partopen: Only supports 'r' mode");
+        return NULL;
+    }
+
+    p = g_malloc0(sizeof(QEMUFilePart));
+
+    p->backing = backing;
+    p->remaining_to_read = len;
+    p->file = qemu_fopen_ops(p, &part_read_ops);
+
+    return p->file;
+}
+