@@ -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);
@@ -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;
+}
+