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. --- Caveat: Again, only compile-tested. No idea if it really works. It copies a good chunk of code from vboxDomainSnapshotGetAll, but I didn't really see a clean way to factor that repeated chunk into its own function. src/vbox/vbox_tmpl.c | 208 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 files changed, 208 insertions(+), 0 deletions(-) diff --git a/src/vbox/vbox_tmpl.c b/src/vbox/vbox_tmpl.c index d1da6fd..a5372e8 100644 --- a/src/vbox/vbox_tmpl.c +++ b/src/vbox/vbox_tmpl.c @@ -6030,6 +6030,212 @@ cleanup: return ret; } +static int +vboxCountDescendants(ISnapshot *snapshot, bool recurse) +{ + vboxArray children = VBOX_ARRAY_INITIALIZER; + nsresult rc; + int count = 0; + int i; + + rc = vboxArrayGet(&children, snapshot, snapshot->vtbl->GetChildren); + if (NS_FAILED(rc)) { + vboxError(VIR_ERR_INTERNAL_ERROR, + "%s", _("could not get children snapshots")); + count = -1; + goto cleanup; + } + + if (recurse) { + for (i = 0; i < children.count; i++) { + int descendants = vboxCountDescendants(children.items[i], true); + if (descendants < 0) { + count = -1; + goto cleanup; + } + count += 1 + descendants; + } + } else { + count = children.count; + } + +cleanup: + vboxArrayRelease(&children); + return count; +} + +static int +vboxDomainSnapshotNumChildren(virDomainSnapshotPtr snapshot, + 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; + bool recurse; + + virCheckFlags(VIR_DOMAIN_SNAPSHOT_LIST_DESCENDANTS | + VIR_DOMAIN_SNAPSHOT_LIST_METADATA, -1); + + recurse = (flags & VIR_DOMAIN_SNAPSHOT_LIST_DESCENDANTS) != 0; + + 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; + + /* VBox snapshots do not require libvirt to maintain any metadata. */ + if (flags & VIR_DOMAIN_SNAPSHOT_LIST_METADATA) { + ret = 0; + goto cleanup; + } + + ret = vboxCountDescendants(snap, recurse); + +cleanup: + VBOX_RELEASE(machine); + vboxIIDUnalloc(&iid); + return ret; +} + +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; + + 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; + } else { + count = children.count; + } + + for (i = 0; i < nameslen; i++) { + PRUnichar *nameUtf16; + char *name; + + if (i >= count) + break; + + rc = snapshots[i]->vtbl->GetName(snapshots[i], &nameUtf16); + if (NS_FAILED(rc) || !nameUtf16) { + vboxError(VIR_ERR_INTERNAL_ERROR, + "%s", _("could not get snapshot name")); + goto cleanup; + } + VBOX_UTF16_TO_UTF8(nameUtf16, &name); + VBOX_UTF16_FREE(nameUtf16); + names[i] = strdup(name); + VBOX_UTF8_FREE(name); + if (!names[i]) { + virReportOOMError(); + goto cleanup; + } + } + + if (count <= nameslen) + ret = count; + else + ret = nameslen; + +cleanup: + if (count > 0) { + for (i = 0; i < count; i++) + VBOX_RELEASE(snapshots[i]); + } + VIR_FREE(snapshots); + VBOX_RELEASE(machine); + vboxIIDUnalloc(&iid); + return ret; +} + static virDomainSnapshotPtr vboxDomainSnapshotLookupByName(virDomainPtr dom, const char *name, @@ -8999,6 +9205,8 @@ virDriver NAME(Driver) = { .domainSnapshotGetXMLDesc = vboxDomainSnapshotGetXMLDesc, /* 0.8.0 */ .domainSnapshotNum = vboxDomainSnapshotNum, /* 0.8.0 */ .domainSnapshotListNames = vboxDomainSnapshotListNames, /* 0.8.0 */ + .domainSnapshotNumChildren = vboxDomainSnapshotNumChildren, /* 0.9.7 */ + .domainSnapshotListChildrenNames = vboxDomainSnapshotListChildrenNames, /* 0.9.7 */ .domainSnapshotLookupByName = vboxDomainSnapshotLookupByName, /* 0.8.0 */ .domainHasCurrentSnapshot = vboxDomainHasCurrentSnapshot, /* 0.8.0 */ .domainSnapshotGetParent = vboxDomainSnapshotGetParent, /* 0.9.7 */ -- 1.7.4.4 -- libvir-list mailing list libvir-list@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/libvir-list