From: "Dr. David Alan Gilbert" <dgilb...@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 <dgilb...@redhat.com> --- include/migration/qemu-file.h | 2 ++ qemu-file.c | 73 +++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 75 insertions(+) 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; +} + -- 1.9.0