2011/10/7 Eric Blake <eblake(a)redhat.com>:
Adding this for VBox was a bit harder than for ESX, but the same
principles apply for starting the traversal at a known point
rather than covering the entire hierarchy.
* src/vbox/vbox_tmpl.c (vboxCountDescendants)
(vboxDomainSnapshotNumChildren)
(vboxDomainSnapshotListChildrenNames): New functions.
---
Changes in v2: avoid leaking snapshot, and fix recursive children
names to get through loop properly by transferring initial snapshot
into loop then skipping that element while grabbing names.
Still untested from my end, but hopefully does better.
src/vbox/vbox_tmpl.c | 213 ++++++++++++++++++++++++++++++++++++++++++++++++++
1 files changed, 213 insertions(+), 0 deletions(-)
diff --git a/src/vbox/vbox_tmpl.c b/src/vbox/vbox_tmpl.c
index c74d2cf..84a4fca 100644
--- a/src/vbox/vbox_tmpl.c
+++ b/src/vbox/vbox_tmpl.c
+static int
+vboxDomainSnapshotListChildrenNames(virDomainSnapshotPtr snapshot,
+ char **names,
+ int nameslen,
+ unsigned int flags)
+{
+ virDomainPtr dom = snapshot->domain;
+ VBOX_OBJECT_CHECK(dom->conn, int, -1);
+ vboxIID iid = VBOX_IID_INITIALIZER;
+ IMachine *machine = NULL;
+ ISnapshot *snap = NULL;
+ nsresult rc;
+ ISnapshot **snapshots = NULL;
+ PRUint32 count = 0;
+ int i;
+ vboxArray children = VBOX_ARRAY_INITIALIZER;
+
+ virCheckFlags(VIR_DOMAIN_SNAPSHOT_LIST_DESCENDANTS |
+ VIR_DOMAIN_SNAPSHOT_LIST_METADATA, -1);
+
+ vboxIIDFromUUID(&iid, dom->uuid);
+ rc = VBOX_OBJECT_GET_MACHINE(iid.value, &machine);
+ if (NS_FAILED(rc)) {
+ vboxError(VIR_ERR_NO_DOMAIN, "%s",
+ _("no domain with matching UUID"));
+ goto cleanup;
+ }
+
+ if (!(snap = vboxDomainSnapshotGet(data, dom, machine, snapshot->name)))
+ goto cleanup;
+
+ if (!nameslen || (flags & VIR_DOMAIN_SNAPSHOT_LIST_METADATA)) {
+ ret = 0;
+ goto cleanup;
+ }
+
+ /* Over-allocates, but this is the easiest way to do things */
+ rc = machine->vtbl->GetSnapshotCount(machine, &count);
+ if (NS_FAILED(rc)) {
+ vboxError(VIR_ERR_INTERNAL_ERROR,
+ _("could not get snapshot count for domain %s"),
+ dom->name);
+ goto cleanup;
+ }
+
+ if (VIR_ALLOC_N(snapshots, count) < 0) {
+ virReportOOMError();
+ goto cleanup;
+ }
+
+ rc = vboxArrayGet(&children, snap, snap->vtbl->GetChildren);
+ if (NS_FAILED(rc)) {
+ vboxError(VIR_ERR_INTERNAL_ERROR,
+ "%s", _("could not get children snapshots"));
+ goto cleanup;
+ }
+
+ if (flags & VIR_DOMAIN_SNAPSHOT_LIST_DESCENDANTS) {
+ int top = children.count;
+ int next;
+
+ snapshots[0] = snap;
+ snap = NULL;
+ for (next = 0; next < count; next++) {
+ if (!snapshots[next])
+ break;
+ rc = vboxArrayGet(&children, snapshots[next],
+ snapshots[next]->vtbl->GetChildren);
+ if (NS_FAILED(rc)) {
+ vboxError(VIR_ERR_INTERNAL_ERROR,
+ "%s", _("could not get children
snapshots"));
+ goto cleanup;
+ }
+ for (i = 0; i < children.count; i++) {
+ ISnapshot *child = children.items[i];
+ if (!child)
+ continue;
+ if (top == count) {
+ vboxError(VIR_ERR_INTERNAL_ERROR,
+ _("unexpected number of snapshots > %u"),
count);
+ vboxArrayRelease(&children);
+ goto cleanup;
+ }
+ VBOX_ADDREF(child);
+ snapshots[top++] = child;
+ }
+ vboxArrayRelease(&children);
+ }
+ count = top - 1;
+ } else {
+ count = children.count;
+ }
+
+ for (i = 0; i < nameslen; i++) {
+ PRUnichar *nameUtf16;
+ char *name;
+ int j = i + !!(flags & VIR_DOMAIN_SNAPSHOT_LIST_DESCENDANTS);
+
+ if (i >= count)
+ break;
+
+ rc = snapshots[j]->vtbl->GetName(snapshots[j], &nameUtf16);
Still a segfault here because snapshots[0] is NULL. Also I think this
logic is too complicated here. Are we really afraid of a stack
overflow because of a domain with many snapshots that we need to avoid
a recursive solution?
You already implemented vboxCountDescendants recursively, I'd suggest
to do the same here too.
I attached a patch to be applied on top of this one that does this and
works for me.
ACK with the attached patch applied.
--
Matthias Bolte
http://photron.blogspot.com