aboutsummaryrefslogtreecommitdiff
path: root/savevm.c
diff options
context:
space:
mode:
authorJuan Quintela <quintela@redhat.com>2011-10-04 15:28:31 +0200
committerJuan Quintela <quintela@redhat.com>2011-10-20 13:23:11 +0200
commitc63807244fb55071675907460a0ecf228c1766c8 (patch)
tree40e84a912c1cd8904478dcc3d692b5a0f9ff80e5 /savevm.c
parent65f3bb3da3d5b46daebbfc54bd41ee493fdaba86 (diff)
savevm: improve subsections detection on load
We add qemu_peek_buffer, that is identical to qemu_get_buffer, just that it don't update f->buf_index. We add a paramenter to qemu_peek_byte() to be able to peek more than one byte. Once this is done, to see if we have a subsection we look: - 1st byte is QEMU_VM_SUBSECTION - 2nd byte is a length, and is bigger than section name - 3rd element is a string that starts with section_name So, we shouldn't have false positives (yes, content could still get us wrong but probabilities are really low). v2: - Alex Williamsom found that we could get negative values on index. - Rework code to fix that part. - Rewrite qemu_get_buffer() using qemu_peek_buffer() v3: - return "done" on error case v4: - fix qemu_file_skip() off by one. Signed-off-by: Juan Quintela <quintela@redhat.com>
Diffstat (limited to 'savevm.c')
-rw-r--r--savevm.c110
1 files changed, 75 insertions, 35 deletions
diff --git a/savevm.c b/savevm.c
index 038099979e..a4cb3157bb 100644
--- a/savevm.c
+++ b/savevm.c
@@ -532,59 +532,85 @@ void qemu_put_byte(QEMUFile *f, int v)
qemu_fflush(f);
}
-int qemu_get_buffer(QEMUFile *f, uint8_t *buf, int size1)
+static void qemu_file_skip(QEMUFile *f, int size)
{
- int size, l;
+ if (f->buf_index + size <= f->buf_size) {
+ f->buf_index += size;
+ }
+}
+
+static int qemu_peek_buffer(QEMUFile *f, uint8_t *buf, int size, size_t offset)
+{
+ int pending;
+ int index;
if (f->is_write) {
abort();
}
- size = size1;
- while (size > 0) {
- l = f->buf_size - f->buf_index;
- if (l == 0) {
- qemu_fill_buffer(f);
- l = f->buf_size - f->buf_index;
- if (l == 0) {
- break;
- }
- }
- if (l > size) {
- l = size;
+ index = f->buf_index + offset;
+ pending = f->buf_size - index;
+ if (pending < size) {
+ qemu_fill_buffer(f);
+ index = f->buf_index + offset;
+ pending = f->buf_size - index;
+ }
+
+ if (pending <= 0) {
+ return 0;
+ }
+ if (size > pending) {
+ size = pending;
+ }
+
+ memcpy(buf, f->buf + index, size);
+ return size;
+}
+
+int qemu_get_buffer(QEMUFile *f, uint8_t *buf, int size)
+{
+ int pending = size;
+ int done = 0;
+
+ while (pending > 0) {
+ int res;
+
+ res = qemu_peek_buffer(f, buf, pending, 0);
+ if (res == 0) {
+ return done;
}
- memcpy(buf, f->buf + f->buf_index, l);
- f->buf_index += l;
- buf += l;
- size -= l;
+ qemu_file_skip(f, res);
+ buf += res;
+ pending -= res;
+ done += res;
}
- return size1 - size;
+ return done;
}
-static int qemu_peek_byte(QEMUFile *f)
+static int qemu_peek_byte(QEMUFile *f, int offset)
{
+ int index = f->buf_index + offset;
+
if (f->is_write) {
abort();
}
- if (f->buf_index >= f->buf_size) {
+ if (index >= f->buf_size) {
qemu_fill_buffer(f);
- if (f->buf_index >= f->buf_size) {
+ index = f->buf_index + offset;
+ if (index >= f->buf_size) {
return 0;
}
}
- return f->buf[f->buf_index];
+ return f->buf[index];
}
int qemu_get_byte(QEMUFile *f)
{
int result;
- result = qemu_peek_byte(f);
-
- if (f->buf_index < f->buf_size) {
- f->buf_index++;
- }
+ result = qemu_peek_byte(f, 0);
+ qemu_file_skip(f, 1);
return result;
}
@@ -1684,22 +1710,36 @@ static int vmstate_subsection_load(QEMUFile *f, const VMStateDescription *vmsd,
return 0;
}
- while (qemu_peek_byte(f) == QEMU_VM_SUBSECTION) {
+ while (qemu_peek_byte(f, 0) == QEMU_VM_SUBSECTION) {
char idstr[256];
int ret;
- uint8_t version_id, len;
+ uint8_t version_id, len, size;
const VMStateDescription *sub_vmsd;
- qemu_get_byte(f); /* subsection */
- len = qemu_get_byte(f);
- qemu_get_buffer(f, (uint8_t *)idstr, len);
- idstr[len] = 0;
- version_id = qemu_get_be32(f);
+ len = qemu_peek_byte(f, 1);
+ if (len < strlen(vmsd->name) + 1) {
+ /* subsection name has be be "section_name/a" */
+ return 0;
+ }
+ size = qemu_peek_buffer(f, (uint8_t *)idstr, len, 2);
+ if (size != len) {
+ return 0;
+ }
+ idstr[size] = 0;
+ if (strncmp(vmsd->name, idstr, strlen(vmsd->name)) != 0) {
+ /* it don't have a valid subsection name */
+ return 0;
+ }
sub_vmsd = vmstate_get_subsection(sub, idstr);
if (sub_vmsd == NULL) {
return -ENOENT;
}
+ qemu_file_skip(f, 1); /* subsection */
+ qemu_file_skip(f, 1); /* len */
+ qemu_file_skip(f, len); /* idstr */
+ version_id = qemu_get_be32(f);
+
assert(!sub_vmsd->subsections);
ret = vmstate_load_state(f, sub_vmsd, opaque, version_id);
if (ret) {