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
@@ -5976,6 +5976,217 @@ 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);
+ VBOX_RELEASE(snap);
+ 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;
+
+ 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);
+ 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);
+ VBOX_RELEASE(snap);
+ vboxIIDUnalloc(&iid);
+ return ret;
+}
+
static virDomainSnapshotPtr
vboxDomainSnapshotLookupByName(virDomainPtr dom,
const char *name,
@@ -8945,6 +9156,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