From 72c23d65c15669c6e4e71c53d2b77c453ee65bea Mon Sep 17 00:00:00 2001 From: Taowei Date: Mon, 11 Aug 2014 18:06:54 +0800 Subject: [PATCH] vbox: Rewrite vboxDomainSnapshotGetXMLDesc --- src/vbox/vbox_common.c | 712 ++++++++++++++++++++++++++++++++ src/vbox/vbox_tmpl.c | 756 +++++----------------------------- src/vbox/vbox_uniformed_api.h | 22 +- 3 files changed, 843 insertions(+), 647 deletions(-) diff --git a/src/vbox/vbox_common.c b/src/vbox/vbox_common.c index 4123ebc7e5..0b1e981231 100644 --- a/src/vbox/vbox_common.c +++ b/src/vbox/vbox_common.c @@ -77,6 +77,8 @@ VIR_LOG_INIT("vbox.vbox_common"); #define VBOX_UTF16_TO_UTF8(arg1, arg2) gVBoxAPI.UPFN.Utf16ToUtf8(data->pFuncs, arg1, arg2) #define VBOX_UTF8_TO_UTF16(arg1, arg2) gVBoxAPI.UPFN.Utf8ToUtf16(data->pFuncs, arg1, arg2) +#define VBOX_ADDREF(arg) gVBoxAPI.nsUISupports.AddRef((void *)(arg)) + #define VBOX_RELEASE(arg) \ do { \ if (arg) { \ @@ -5357,3 +5359,713 @@ vboxDomainSnapshotCreateXML(virDomainPtr dom, virDomainSnapshotDefFree(def); return ret; } + +static int +vboxDomainSnapshotGetAll(virDomainPtr dom, + IMachine *machine, + ISnapshot ***snapshots) +{ + vboxIIDUnion empty; + ISnapshot **list = NULL; + PRUint32 count; + nsresult rc; + unsigned int next; + unsigned int top; + + VBOX_IID_INITIALIZE(&empty); + rc = gVBoxAPI.UIMachine.GetSnapshotCount(machine, &count); + if (NS_FAILED(rc)) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("could not get snapshot count for domain %s"), + dom->name); + goto error; + } + + if (count == 0) + goto out; + + if (VIR_ALLOC_N(list, count) < 0) + goto error; + + rc = gVBoxAPI.UIMachine.FindSnapshot(machine, &empty, list); + if (NS_FAILED(rc) || !list[0]) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("could not get root snapshot for domain %s"), + dom->name); + goto error; + } + + /* BFS walk through snapshot tree */ + top = 1; + for (next = 0; next < count; next++) { + vboxArray children = VBOX_ARRAY_INITIALIZER; + size_t i; + + if (!list[next]) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("unexpected number of snapshots < %u"), count); + goto error; + } + + rc = gVBoxAPI.UArray.vboxArrayGet(&children, list[next], + gVBoxAPI.UArray.handleSnapshotGetChildren(list[next])); + if (NS_FAILED(rc)) { + virReportError(VIR_ERR_INTERNAL_ERROR, + "%s", _("could not get children snapshots")); + goto error; + } + for (i = 0; i < children.count; i++) { + ISnapshot *child = children.items[i]; + if (!child) + continue; + if (top == count) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("unexpected number of snapshots > %u"), count); + gVBoxAPI.UArray.vboxArrayRelease(&children); + goto error; + } + VBOX_ADDREF(child); + list[top++] = child; + } + gVBoxAPI.UArray.vboxArrayRelease(&children); + } + + out: + *snapshots = list; + return count; + + error: + if (list) { + for (next = 0; next < count; next++) + VBOX_RELEASE(list[next]); + } + VIR_FREE(list); + + return -1; +} + +static ISnapshot * +vboxDomainSnapshotGet(vboxGlobalData *data, + virDomainPtr dom, + IMachine *machine, + const char *name) +{ + ISnapshot **snapshots = NULL; + ISnapshot *snapshot = NULL; + nsresult rc; + int count = 0; + size_t i; + + if ((count = vboxDomainSnapshotGetAll(dom, machine, &snapshots)) < 0) + goto cleanup; + + for (i = 0; i < count; i++) { + PRUnichar *nameUtf16; + char *nameUtf8; + + rc = gVBoxAPI.UISnapshot.GetName(snapshots[i], &nameUtf16); + if (NS_FAILED(rc) || !nameUtf16) { + virReportError(VIR_ERR_INTERNAL_ERROR, + "%s", _("could not get snapshot name")); + goto cleanup; + } + VBOX_UTF16_TO_UTF8(nameUtf16, &nameUtf8); + VBOX_UTF16_FREE(nameUtf16); + if (STREQ(name, nameUtf8)) + snapshot = snapshots[i]; + VBOX_UTF8_FREE(nameUtf8); + + if (snapshot) + break; + } + + if (!snapshot) { + virReportError(VIR_ERR_OPERATION_INVALID, + _("domain %s has no snapshots with name %s"), + dom->name, name); + goto cleanup; + } + + cleanup: + if (count > 0) { + for (i = 0; i < count; i++) { + if (snapshots[i] != snapshot) + VBOX_RELEASE(snapshots[i]); + } + } + VIR_FREE(snapshots); + return snapshot; +} + +static +int vboxSnapshotGetReadWriteDisks(virDomainSnapshotDefPtr def, + virDomainSnapshotPtr snapshot) +{ + virDomainPtr dom = snapshot->domain; + VBOX_OBJECT_CHECK(dom->conn, int, -1); + vboxIIDUnion domiid; + IMachine *machine = NULL; + ISnapshot *snap = NULL; + IMachine *snapMachine = NULL; + vboxArray mediumAttachments = VBOX_ARRAY_INITIALIZER; + PRUint32 maxPortPerInst[StorageBus_Floppy + 1] = {}; + PRUint32 maxSlotPerPort[StorageBus_Floppy + 1] = {}; + int diskCount = 0; + nsresult rc; + vboxIIDUnion snapIid; + char *snapshotUuidStr = NULL; + size_t i = 0; + + if (!gVBoxAPI.vboxSnapshotRedefine) + VIR_WARN("This function may not work in current version"); + + VBOX_IID_INITIALIZE(&snapIid); + if (openSessionForMachine(data, dom->uuid, &domiid, &machine, false) < 0) + goto cleanup; + + if (!(snap = vboxDomainSnapshotGet(data, dom, machine, snapshot->name))) + goto cleanup; + + rc = gVBoxAPI.UISnapshot.GetId(snap, &snapIid); + if (NS_FAILED(rc)) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("Could not get snapshot id")); + goto cleanup; + } + + gVBoxAPI.UIID.vboxIIDToUtf8(data, &snapIid, &snapshotUuidStr); + vboxIIDUnalloc(&snapIid); + rc = gVBoxAPI.UISnapshot.GetMachine(snap, &snapMachine); + if (NS_FAILED(rc)) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("could not get machine")); + goto cleanup; + } + def->ndisks = 0; + rc = gVBoxAPI.UArray.vboxArrayGet(&mediumAttachments, snapMachine, + gVBoxAPI.UArray.handleMachineGetMediumAttachments(snapMachine)); + if (NS_FAILED(rc)) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("no medium attachments")); + goto cleanup; + } + /* get the number of attachments */ + for (i = 0; i < mediumAttachments.count; i++) { + IMediumAttachment *imediumattach = mediumAttachments.items[i]; + if (imediumattach) { + IMedium *medium = NULL; + + rc = gVBoxAPI.UIMediumAttachment.GetMedium(imediumattach, &medium); + if (NS_FAILED(rc)) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("cannot get medium")); + goto cleanup; + } + if (medium) { + def->ndisks++; + VBOX_RELEASE(medium); + } + } + } + /* Allocate mem, if fails return error */ + if (VIR_ALLOC_N(def->disks, def->ndisks) < 0) + goto cleanup; + for (i = 0; i < def->ndisks; i++) { + if (VIR_ALLOC(def->disks[i].src) < 0) + goto cleanup; + } + + if (!vboxGetMaxPortSlotValues(data->vboxObj, maxPortPerInst, maxSlotPerPort)) + goto cleanup; + + /* get the attachment details here */ + for (i = 0; i < mediumAttachments.count && diskCount < def->ndisks; i++) { + IStorageController *storageController = NULL; + PRUnichar *storageControllerName = NULL; + PRUint32 deviceType = DeviceType_Null; + PRUint32 storageBus = StorageBus_Null; + IMedium *disk = NULL; + PRUnichar *childLocUtf16 = NULL; + char *childLocUtf8 = NULL; + PRUint32 deviceInst = 0; + PRInt32 devicePort = 0; + PRInt32 deviceSlot = 0; + vboxArray children = VBOX_ARRAY_INITIALIZER; + vboxArray snapshotIids = VBOX_ARRAY_INITIALIZER; + IMediumAttachment *imediumattach = mediumAttachments.items[i]; + void *handle; + size_t j = 0; + size_t k = 0; + if (!imediumattach) + continue; + rc = gVBoxAPI.UIMediumAttachment.GetMedium(imediumattach, &disk); + if (NS_FAILED(rc)) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("cannot get medium")); + goto cleanup; + } + if (!disk) + continue; + rc = gVBoxAPI.UIMediumAttachment.GetController(imediumattach, &storageControllerName); + if (NS_FAILED(rc)) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("cannot get controller")); + goto cleanup; + } + if (!storageControllerName) { + VBOX_RELEASE(disk); + continue; + } + handle = gVBoxAPI.UArray.handleMediumGetChildren(disk); + rc = gVBoxAPI.UArray.vboxArrayGet(&children, disk, handle); + if (NS_FAILED(rc)) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("cannot get children disk")); + goto cleanup; + } + handle = gVBoxAPI.UArray.handleMediumGetSnapshotIds(disk); + rc = gVBoxAPI.UArray.vboxArrayGetWithIIDArg(&snapshotIids, disk, + handle, &domiid); + if (NS_FAILED(rc)) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("cannot get snapshot ids")); + goto cleanup; + } + for (j = 0; j < children.count; ++j) { + IMedium *child = children.items[j]; + for (k = 0; k < snapshotIids.count; ++k) { + PRUnichar *diskSnapId = snapshotIids.items[k]; + char *diskSnapIdStr = NULL; + VBOX_UTF16_TO_UTF8(diskSnapId, &diskSnapIdStr); + if (STREQ(diskSnapIdStr, snapshotUuidStr)) { + rc = gVBoxAPI.UIMachine.GetStorageControllerByName(machine, + storageControllerName, + &storageController); + VBOX_UTF16_FREE(storageControllerName); + if (!storageController) { + VBOX_RELEASE(child); + break; + } + rc = gVBoxAPI.UIMedium.GetLocation(child, &childLocUtf16); + if (NS_FAILED(rc)) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("cannot get disk location")); + goto cleanup; + } + VBOX_UTF16_TO_UTF8(childLocUtf16, &childLocUtf8); + VBOX_UTF16_FREE(childLocUtf16); + if (VIR_STRDUP(def->disks[diskCount].src->path, childLocUtf8) < 0) { + VBOX_RELEASE(child); + VBOX_RELEASE(storageController); + goto cleanup; + } + VBOX_UTF8_FREE(childLocUtf8); + + rc = gVBoxAPI.UIStorageController.GetBus(storageController, &storageBus); + if (NS_FAILED(rc)) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("cannot get storage controller bus")); + goto cleanup; + } + rc = gVBoxAPI.UIMediumAttachment.GetType(imediumattach, &deviceType); + if (NS_FAILED(rc)) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("cannot get medium attachment type")); + goto cleanup; + } + rc = gVBoxAPI.UIMediumAttachment.GetPort(imediumattach, &devicePort); + if (NS_FAILED(rc)) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("cannot get medium attachment type")); + goto cleanup; + } + rc = gVBoxAPI.UIMediumAttachment.GetDevice(imediumattach, &deviceSlot); + if (NS_FAILED(rc)) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("cannot get medium attachment device")); + goto cleanup; + } + def->disks[diskCount].src->type = VIR_STORAGE_TYPE_FILE; + def->disks[diskCount].name = vboxGenerateMediumName(storageBus, + deviceInst, + devicePort, + deviceSlot, + maxPortPerInst, + maxSlotPerPort); + } + VBOX_UTF8_FREE(diskSnapIdStr); + } + } + VBOX_RELEASE(storageController); + VBOX_RELEASE(disk); + diskCount++; + } + gVBoxAPI.UArray.vboxArrayRelease(&mediumAttachments); + + ret = 0; + cleanup: + if (ret < 0) { + for (i = 0; i < def->ndisks; i++) { + VIR_FREE(def->disks[i].src); + } + VIR_FREE(def->disks); + def->ndisks = 0; + } + VBOX_RELEASE(snap); + return ret; +} + +static +int vboxSnapshotGetReadOnlyDisks(virDomainSnapshotPtr snapshot, + virDomainSnapshotDefPtr def) +{ + virDomainPtr dom = snapshot->domain; + VBOX_OBJECT_CHECK(dom->conn, int, -1); + vboxIIDUnion domiid; + ISnapshot *snap = NULL; + IMachine *machine = NULL; + IMachine *snapMachine = NULL; + IStorageController *storageController = NULL; + IMedium *disk = NULL; + nsresult rc; + vboxArray mediumAttachments = VBOX_ARRAY_INITIALIZER; + size_t i = 0; + PRUint32 maxPortPerInst[StorageBus_Floppy + 1] = {}; + PRUint32 maxSlotPerPort[StorageBus_Floppy + 1] = {}; + int diskCount = 0; + + if (!gVBoxAPI.vboxSnapshotRedefine) + VIR_WARN("This function may not work in current version"); + + if (openSessionForMachine(data, dom->uuid, &domiid, &machine, false) < 0) + goto cleanup; + + if (!(snap = vboxDomainSnapshotGet(data, dom, machine, snapshot->name))) + goto cleanup; + + rc = gVBoxAPI.UISnapshot.GetMachine(snap, &snapMachine); + if (NS_FAILED(rc)) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("cannot get machine")); + goto cleanup; + } + /* + * Get READ ONLY disks + * In the snapshot metadata, these are the disks written inside the node + */ + rc = gVBoxAPI.UArray.vboxArrayGet(&mediumAttachments, snapMachine, + gVBoxAPI.UArray.handleMachineGetMediumAttachments(snapMachine)); + if (NS_FAILED(rc)) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("cannot get medium attachments")); + goto cleanup; + } + /* get the number of attachments */ + for (i = 0; i < mediumAttachments.count; i++) { + IMediumAttachment *imediumattach = mediumAttachments.items[i]; + if (imediumattach) { + IMedium *medium = NULL; + + rc = gVBoxAPI.UIMediumAttachment.GetMedium(imediumattach, &medium); + if (NS_FAILED(rc)) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("cannot get medium")); + goto cleanup; + } + if (medium) { + def->dom->ndisks++; + VBOX_RELEASE(medium); + } + } + } + + /* Allocate mem, if fails return error */ + if (VIR_ALLOC_N(def->dom->disks, def->dom->ndisks) >= 0) { + for (i = 0; i < def->dom->ndisks; i++) { + virDomainDiskDefPtr diskDef = virDomainDiskDefNew(); + if (!diskDef) + goto cleanup; + def->dom->disks[i] = diskDef; + } + } else { + goto cleanup; + } + + if (!vboxGetMaxPortSlotValues(data->vboxObj, maxPortPerInst, maxSlotPerPort)) + goto cleanup; + + /* get the attachment details here */ + for (i = 0; i < mediumAttachments.count && diskCount < def->dom->ndisks; i++) { + PRUnichar *storageControllerName = NULL; + PRUint32 deviceType = DeviceType_Null; + PRUint32 storageBus = StorageBus_Null; + PRBool readOnly = PR_FALSE; + PRUnichar *mediumLocUtf16 = NULL; + char *mediumLocUtf8 = NULL; + PRUint32 deviceInst = 0; + PRInt32 devicePort = 0; + PRInt32 deviceSlot = 0; + IMediumAttachment *imediumattach = mediumAttachments.items[i]; + if (!imediumattach) + continue; + rc = gVBoxAPI.UIMediumAttachment.GetMedium(imediumattach, &disk); + if (NS_FAILED(rc)) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("cannot get medium")); + goto cleanup; + } + if (!disk) + continue; + rc = gVBoxAPI.UIMediumAttachment.GetController(imediumattach, &storageControllerName); + if (NS_FAILED(rc)) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("cannot get storage controller name")); + goto cleanup; + } + if (!storageControllerName) + continue; + rc = gVBoxAPI.UIMachine.GetStorageControllerByName(machine, + storageControllerName, + &storageController); + if (NS_FAILED(rc)) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("cannot get storage controller")); + goto cleanup; + } + VBOX_UTF16_FREE(storageControllerName); + if (!storageController) + continue; + rc = gVBoxAPI.UIMedium.GetLocation(disk, &mediumLocUtf16); + if (NS_FAILED(rc)) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("cannot get disk location")); + goto cleanup; + } + VBOX_UTF16_TO_UTF8(mediumLocUtf16, &mediumLocUtf8); + VBOX_UTF16_FREE(mediumLocUtf16); + if (VIR_STRDUP(def->dom->disks[diskCount]->src->path, mediumLocUtf8) < 0) + goto cleanup; + + VBOX_UTF8_FREE(mediumLocUtf8); + + rc = gVBoxAPI.UIStorageController.GetBus(storageController, &storageBus); + if (NS_FAILED(rc)) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("cannot get storage controller bus")); + goto cleanup; + } + if (storageBus == StorageBus_IDE) { + def->dom->disks[diskCount]->bus = VIR_DOMAIN_DISK_BUS_IDE; + } else if (storageBus == StorageBus_SATA) { + def->dom->disks[diskCount]->bus = VIR_DOMAIN_DISK_BUS_SATA; + } else if (storageBus == StorageBus_SCSI) { + def->dom->disks[diskCount]->bus = VIR_DOMAIN_DISK_BUS_SCSI; + } else if (storageBus == StorageBus_Floppy) { + def->dom->disks[diskCount]->bus = VIR_DOMAIN_DISK_BUS_FDC; + } + + rc = gVBoxAPI.UIMediumAttachment.GetType(imediumattach, &deviceType); + if (NS_FAILED(rc)) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("cannot get medium attachment type")); + goto cleanup; + } + if (deviceType == DeviceType_HardDisk) + def->dom->disks[diskCount]->device = VIR_DOMAIN_DISK_DEVICE_DISK; + else if (deviceType == DeviceType_Floppy) + def->dom->disks[diskCount]->device = VIR_DOMAIN_DISK_DEVICE_FLOPPY; + else if (deviceType == DeviceType_DVD) + def->dom->disks[diskCount]->device = VIR_DOMAIN_DISK_DEVICE_CDROM; + + rc = gVBoxAPI.UIMediumAttachment.GetPort(imediumattach, &devicePort); + if (NS_FAILED(rc)) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("cannot get medium attachment port")); + goto cleanup; + } + rc = gVBoxAPI.UIMediumAttachment.GetDevice(imediumattach, &deviceSlot); + if (NS_FAILED(rc)) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("cannot get device")); + goto cleanup; + } + rc = gVBoxAPI.UIMedium.GetReadOnly(disk, &readOnly); + if (NS_FAILED(rc)) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("cannot get read only attribute")); + goto cleanup; + } + if (readOnly == PR_TRUE) + def->dom->disks[diskCount]->src->readonly = true; + def->dom->disks[diskCount]->src->type = VIR_STORAGE_TYPE_FILE; + def->dom->disks[diskCount]->dst = vboxGenerateMediumName(storageBus, + deviceInst, + devicePort, + deviceSlot, + maxPortPerInst, + maxSlotPerPort); + if (!def->dom->disks[diskCount]->dst) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("Could not generate medium name for the disk " + "at: controller instance:%u, port:%d, slot:%d"), + deviceInst, devicePort, deviceSlot); + ret = -1; + goto cleanup; + } + diskCount ++; + } + /* cleanup on error */ + + ret = 0; + cleanup: + if (ret < 0) { + for (i = 0; i < def->dom->ndisks; i++) + virDomainDiskDefFree(def->dom->disks[i]); + VIR_FREE(def->dom->disks); + def->dom->ndisks = 0; + } + VBOX_RELEASE(disk); + VBOX_RELEASE(storageController); + gVBoxAPI.UArray.vboxArrayRelease(&mediumAttachments); + VBOX_RELEASE(snap); + return ret; +} + +char *vboxDomainSnapshotGetXMLDesc(virDomainSnapshotPtr snapshot, + unsigned int flags) +{ + virDomainPtr dom = snapshot->domain; + VBOX_OBJECT_CHECK(dom->conn, char *, NULL); + vboxIIDUnion domiid; + IMachine *machine = NULL; + ISnapshot *snap = NULL; + ISnapshot *parent = NULL; + nsresult rc; + virDomainSnapshotDefPtr def = NULL; + PRUnichar *str16; + char *str8; + PRInt64 timestamp; + PRBool online = PR_FALSE; + char uuidstr[VIR_UUID_STRING_BUFLEN]; + + virCheckFlags(0, NULL); + + if (openSessionForMachine(data, dom->uuid, &domiid, &machine, false) < 0) + goto cleanup; + + if (!(snap = vboxDomainSnapshotGet(data, dom, machine, snapshot->name))) + goto cleanup; + + if (VIR_ALLOC(def) < 0 || VIR_ALLOC(def->dom) < 0) + goto cleanup; + if (VIR_STRDUP(def->name, snapshot->name) < 0) + goto cleanup; + + if (gVBoxAPI.vboxSnapshotRedefine) { + /* Register def->dom properties for them to be saved inside the snapshot XMl + * Otherwise, there is a problem while parsing the xml + */ + PRUint32 memorySize = 0; + PRUint32 CPUCount = 0; + + def->dom->virtType = VIR_DOMAIN_VIRT_VBOX; + def->dom->id = dom->id; + memcpy(def->dom->uuid, dom->uuid, VIR_UUID_BUFLEN); + if (VIR_STRDUP(def->dom->name, dom->name) < 0) + goto cleanup; + gVBoxAPI.UIMachine.GetMemorySize(machine, &memorySize); + def->dom->mem.cur_balloon = memorySize * 1024; + /* Currently setting memory and maxMemory as same, cause + * the notation here seems to be inconsistent while + * reading and while dumping xml + */ + def->dom->mem.max_balloon = memorySize * 1024; + if (VIR_STRDUP(def->dom->os.type, "hvm") < 0) + goto cleanup; + def->dom->os.arch = virArchFromHost(); + gVBoxAPI.UIMachine.GetCPUCount(machine, &CPUCount); + def->dom->maxvcpus = def->dom->vcpus = CPUCount; + if (vboxSnapshotGetReadWriteDisks(def, snapshot) < 0) { + VIR_DEBUG("Could not get read write disks for snapshot"); + } + + if (vboxSnapshotGetReadOnlyDisks(snapshot, def) < 0) { + VIR_DEBUG("Could not get Readonly disks for snapshot"); + } + } + + rc = gVBoxAPI.UISnapshot.GetDescription(snap, &str16); + if (NS_FAILED(rc)) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("could not get description of snapshot %s"), + snapshot->name); + goto cleanup; + } + if (str16) { + VBOX_UTF16_TO_UTF8(str16, &str8); + VBOX_UTF16_FREE(str16); + if (VIR_STRDUP(def->description, str8) < 0) { + VBOX_UTF8_FREE(str8); + goto cleanup; + } + VBOX_UTF8_FREE(str8); + } + + rc = gVBoxAPI.UISnapshot.GetTimeStamp(snap, ×tamp); + if (NS_FAILED(rc)) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("could not get creation time of snapshot %s"), + snapshot->name); + goto cleanup; + } + /* timestamp is in milliseconds while creationTime in seconds */ + def->creationTime = timestamp / 1000; + + rc = gVBoxAPI.UISnapshot.GetParent(snap, &parent); + if (NS_FAILED(rc)) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("could not get parent of snapshot %s"), + snapshot->name); + goto cleanup; + } + if (parent) { + rc = gVBoxAPI.UISnapshot.GetName(parent, &str16); + if (NS_FAILED(rc) || !str16) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("could not get name of parent of snapshot %s"), + snapshot->name); + goto cleanup; + } + VBOX_UTF16_TO_UTF8(str16, &str8); + VBOX_UTF16_FREE(str16); + if (VIR_STRDUP(def->parent, str8) < 0) { + VBOX_UTF8_FREE(str8); + goto cleanup; + } + VBOX_UTF8_FREE(str8); + } + + rc = gVBoxAPI.UISnapshot.GetOnline(snap, &online); + if (NS_FAILED(rc)) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("could not get online state of snapshot %s"), + snapshot->name); + goto cleanup; + } + if (online) + def->state = VIR_DOMAIN_RUNNING; + else + def->state = VIR_DOMAIN_SHUTOFF; + + virUUIDFormat(dom->uuid, uuidstr); + memcpy(def->dom->uuid, dom->uuid, VIR_UUID_BUFLEN); + ret = virDomainSnapshotDefFormat(uuidstr, def, flags, 0); + + cleanup: + virDomainSnapshotDefFree(def); + VBOX_RELEASE(parent); + VBOX_RELEASE(snap); + VBOX_RELEASE(machine); + vboxIIDUnalloc(&domiid); + return ret; +} diff --git a/src/vbox/vbox_tmpl.c b/src/vbox/vbox_tmpl.c index 1f4336b76e..c5493bc465 100644 --- a/src/vbox/vbox_tmpl.c +++ b/src/vbox/vbox_tmpl.c @@ -676,70 +676,6 @@ _vboxIIDFromArrayItem(vboxGlobalData *data, vboxIIDUnion *iidu, #endif /* !(VBOX_API_VERSION == 2002000) */ -/** - * function to generate the name for medium, - * for e.g: hda, sda, etc - * - * @returns null terminated string with device name or NULL - * for failures - * @param conn Input Connection Pointer - * @param storageBus Input storage bus type - * @param deviceInst Input device instance number - * @param devicePort Input port number - * @param deviceSlot Input slot number - * @param aMaxPortPerInst Input array of max port per device instance - * @param aMaxSlotPerPort Input array of max slot per device port - * - */ -/* This functions is used for 4.2 and later only since vboxDomainGetXMLDesc - * is rewritten. */ -#if VBOX_API_VERSION >= 4002000 -static char *vboxGenerateMediumName(PRUint32 storageBus, - PRInt32 deviceInst, - PRInt32 devicePort, - PRInt32 deviceSlot, - PRUint32 *aMaxPortPerInst, - PRUint32 *aMaxSlotPerPort) -{ - const char *prefix = NULL; - char *name = NULL; - int total = 0; - PRUint32 maxPortPerInst = 0; - PRUint32 maxSlotPerPort = 0; - - if (!aMaxPortPerInst || - !aMaxSlotPerPort) - return NULL; - - if ((storageBus < StorageBus_IDE) || - (storageBus > StorageBus_Floppy)) - return NULL; - - maxPortPerInst = aMaxPortPerInst[storageBus]; - maxSlotPerPort = aMaxSlotPerPort[storageBus]; - total = (deviceInst * maxPortPerInst * maxSlotPerPort) - + (devicePort * maxSlotPerPort) - + deviceSlot; - - if (storageBus == StorageBus_IDE) { - prefix = "hd"; - } else if ((storageBus == StorageBus_SATA) || - (storageBus == StorageBus_SCSI)) { - prefix = "sd"; - } else if (storageBus == StorageBus_Floppy) { - prefix = "fd"; - } - - name = virIndexToDiskName(total, prefix); - - VIR_DEBUG("name=%s, total=%d, storageBus=%u, deviceInst=%d, " - "devicePort=%d deviceSlot=%d, maxPortPerInst=%u maxSlotPerPort=%u", - NULLSTR(name), total, storageBus, deviceInst, devicePort, - deviceSlot, maxPortPerInst, maxSlotPerPort); - return name; -} -#endif /* VBOX_API_VERSION >= 4002000 */ - /** * function to get the StorageBus, Port number * and Device number for the given devicename @@ -803,7 +739,6 @@ static bool vboxGetDeviceDetails(const char *deviceName, return true; } -# endif /* VBOX_API_VERSION < 4000000 */ /** * function to get the values for max port per @@ -816,9 +751,8 @@ static bool vboxGetDeviceDetails(const char *deviceName, * */ -/* This function would not be used in 4.0 and 4.1 since - * vboxDomainGetXMLDesc is written*/ -# if VBOX_API_VERSION >= 4002000 || VBOX_API_VERSION < 4000000 +/* This function would not be used in 4.1 and later since + * vboxDomainSnapshotGetXMLDesc is written*/ static bool vboxGetMaxPortSlotValues(IVirtualBox *vbox, PRUint32 *maxPortPerInst, PRUint32 *maxSlotPerPort) @@ -863,7 +797,7 @@ static bool vboxGetMaxPortSlotValues(IVirtualBox *vbox, return true; } -# endif /* VBOX_API_VERSION >= 4002000 || VBOX_API_VERSION < 4000000 */ +# endif /* VBOX_API_VERSION < 4000000 */ /** * Converts Utf-16 string to int @@ -1589,583 +1523,6 @@ vboxDomainSnapshotGet(vboxGlobalData *data, return snapshot; } -#if VBOX_API_VERSION >=4002000 -static -int vboxSnapshotGetReadWriteDisks(virDomainSnapshotDefPtr def, - virDomainSnapshotPtr snapshot) -{ - virDomainPtr dom = snapshot->domain; - VBOX_OBJECT_CHECK(dom->conn, int, -1); - vboxIID domiid = VBOX_IID_INITIALIZER; - IMachine *machine = NULL; - ISnapshot *snap = NULL; - IMachine *snapMachine = NULL; - vboxArray mediumAttachments = VBOX_ARRAY_INITIALIZER; - PRUint32 maxPortPerInst[StorageBus_Floppy + 1] = {}; - PRUint32 maxSlotPerPort[StorageBus_Floppy + 1] = {}; - int diskCount = 0; - nsresult rc; - vboxIID snapIid = VBOX_IID_INITIALIZER; - char *snapshotUuidStr = NULL; - size_t i = 0; - - vboxIIDFromUUID(&domiid, dom->uuid); - rc = VBOX_OBJECT_GET_MACHINE(domiid.value, &machine); - if (NS_FAILED(rc)) { - virReportError(VIR_ERR_INTERNAL_ERROR, "%s", - _("no domain with matching UUID")); - goto cleanup; - } - if (!(snap = vboxDomainSnapshotGet(data, dom, machine, snapshot->name))) - goto cleanup; - - rc = snap->vtbl->GetId(snap, &snapIid.value); - if (NS_FAILED(rc)) { - virReportError(VIR_ERR_INTERNAL_ERROR, "%s", - _("Could not get snapshot id")); - goto cleanup; - } - - VBOX_UTF16_TO_UTF8(snapIid.value, &snapshotUuidStr); - rc = snap->vtbl->GetMachine(snap, &snapMachine); - if (NS_FAILED(rc)) { - virReportError(VIR_ERR_INTERNAL_ERROR, "%s", - _("could not get machine")); - goto cleanup; - } - def->ndisks = 0; - rc = vboxArrayGet(&mediumAttachments, snapMachine, snapMachine->vtbl->GetMediumAttachments); - if (NS_FAILED(rc)) { - virReportError(VIR_ERR_INTERNAL_ERROR, "%s", - _("no medium attachments")); - goto cleanup; - } - /* get the number of attachments */ - for (i = 0; i < mediumAttachments.count; i++) { - IMediumAttachment *imediumattach = mediumAttachments.items[i]; - if (imediumattach) { - IMedium *medium = NULL; - - rc = imediumattach->vtbl->GetMedium(imediumattach, &medium); - if (NS_FAILED(rc)) { - virReportError(VIR_ERR_INTERNAL_ERROR, "%s", - _("cannot get medium")); - goto cleanup; - } - if (medium) { - def->ndisks++; - VBOX_RELEASE(medium); - } - } - } - /* Allocate mem, if fails return error */ - if (VIR_ALLOC_N(def->disks, def->ndisks) < 0) - goto cleanup; - for (i = 0; i < def->ndisks; i++) { - if (VIR_ALLOC(def->disks[i].src) < 0) - goto cleanup; - } - - if (!vboxGetMaxPortSlotValues(data->vboxObj, maxPortPerInst, maxSlotPerPort)) - goto cleanup; - - /* get the attachment details here */ - for (i = 0; i < mediumAttachments.count && diskCount < def->ndisks; i++) { - IStorageController *storageController = NULL; - PRUnichar *storageControllerName = NULL; - PRUint32 deviceType = DeviceType_Null; - PRUint32 storageBus = StorageBus_Null; - IMedium *disk = NULL; - PRUnichar *childLocUtf16 = NULL; - char *childLocUtf8 = NULL; - PRUint32 deviceInst = 0; - PRInt32 devicePort = 0; - PRInt32 deviceSlot = 0; - vboxArray children = VBOX_ARRAY_INITIALIZER; - vboxArray snapshotIids = VBOX_ARRAY_INITIALIZER; - IMediumAttachment *imediumattach = mediumAttachments.items[i]; - size_t j = 0; - size_t k = 0; - if (!imediumattach) - continue; - rc = imediumattach->vtbl->GetMedium(imediumattach, &disk); - if (NS_FAILED(rc)) { - virReportError(VIR_ERR_INTERNAL_ERROR, "%s", - _("cannot get medium")); - goto cleanup; - } - if (!disk) - continue; - rc = imediumattach->vtbl->GetController(imediumattach, &storageControllerName); - if (NS_FAILED(rc)) { - virReportError(VIR_ERR_INTERNAL_ERROR, "%s", - _("cannot get controller")); - goto cleanup; - } - if (!storageControllerName) { - VBOX_RELEASE(disk); - continue; - } - rc = vboxArrayGet(&children, disk, disk->vtbl->GetChildren); - if (NS_FAILED(rc)) { - virReportError(VIR_ERR_INTERNAL_ERROR, "%s", - _("cannot get children disk")); - goto cleanup; - } - rc = vboxArrayGetWithPtrArg(&snapshotIids, disk, disk->vtbl->GetSnapshotIds, domiid.value); - if (NS_FAILED(rc)) { - virReportError(VIR_ERR_INTERNAL_ERROR, "%s", - _("cannot get snapshot ids")); - goto cleanup; - } - for (j = 0; j < children.count; ++j) { - IMedium *child = children.items[j]; - for (k = 0; k < snapshotIids.count; ++k) { - PRUnichar *diskSnapId = snapshotIids.items[k]; - char *diskSnapIdStr = NULL; - VBOX_UTF16_TO_UTF8(diskSnapId, &diskSnapIdStr); - if (STREQ(diskSnapIdStr, snapshotUuidStr)) { - rc = machine->vtbl->GetStorageControllerByName(machine, - storageControllerName, - &storageController); - VBOX_UTF16_FREE(storageControllerName); - if (!storageController) { - VBOX_RELEASE(child); - break; - } - rc = child->vtbl->GetLocation(child, &childLocUtf16); - if (NS_FAILED(rc)) { - virReportError(VIR_ERR_INTERNAL_ERROR, "%s", - _("cannot get disk location")); - goto cleanup; - } - VBOX_UTF16_TO_UTF8(childLocUtf16, &childLocUtf8); - VBOX_UTF16_FREE(childLocUtf16); - if (VIR_STRDUP(def->disks[diskCount].src->path, childLocUtf8) < 0) { - VBOX_RELEASE(child); - VBOX_RELEASE(storageController); - goto cleanup; - } - VBOX_UTF8_FREE(childLocUtf8); - - rc = storageController->vtbl->GetBus(storageController, &storageBus); - if (NS_FAILED(rc)) { - virReportError(VIR_ERR_INTERNAL_ERROR, "%s", - _("cannot get storage controller bus")); - goto cleanup; - } - rc = imediumattach->vtbl->GetType(imediumattach, &deviceType); - if (NS_FAILED(rc)) { - virReportError(VIR_ERR_INTERNAL_ERROR, "%s", - _("cannot get medium attachment type")); - goto cleanup; - } - rc = imediumattach->vtbl->GetPort(imediumattach, &devicePort); - if (NS_FAILED(rc)) { - virReportError(VIR_ERR_INTERNAL_ERROR, "%s", - _("cannot get medium attachment type")); - goto cleanup; - } - rc = imediumattach->vtbl->GetDevice(imediumattach, &deviceSlot); - if (NS_FAILED(rc)) { - virReportError(VIR_ERR_INTERNAL_ERROR, "%s", - _("cannot get medium attachment device")); - goto cleanup; - } - def->disks[diskCount].src->type = VIR_STORAGE_TYPE_FILE; - def->disks[diskCount].name = vboxGenerateMediumName(storageBus, - deviceInst, - devicePort, - deviceSlot, - maxPortPerInst, - maxSlotPerPort); - } - VBOX_UTF8_FREE(diskSnapIdStr); - } - } - VBOX_RELEASE(storageController); - VBOX_RELEASE(disk); - diskCount++; - } - vboxArrayRelease(&mediumAttachments); - - ret = 0; - cleanup: - if (ret < 0) { - for (i = 0; i < def->ndisks; i++) { - VIR_FREE(def->disks[i].src); - } - VIR_FREE(def->disks); - def->ndisks = 0; - } - VBOX_RELEASE(snap); - return ret; -} - -static -int vboxSnapshotGetReadOnlyDisks(virDomainSnapshotPtr snapshot, - virDomainSnapshotDefPtr def) -{ - virDomainPtr dom = snapshot->domain; - VBOX_OBJECT_CHECK(dom->conn, int, -1); - vboxIID domiid = VBOX_IID_INITIALIZER; - ISnapshot *snap = NULL; - IMachine *machine = NULL; - IMachine *snapMachine = NULL; - IStorageController *storageController = NULL; - IMedium *disk = NULL; - nsresult rc; - vboxIIDFromUUID(&domiid, dom->uuid); - vboxArray mediumAttachments = VBOX_ARRAY_INITIALIZER; - size_t i = 0; - PRUint32 maxPortPerInst[StorageBus_Floppy + 1] = {}; - PRUint32 maxSlotPerPort[StorageBus_Floppy + 1] = {}; - int diskCount = 0; - - rc = VBOX_OBJECT_GET_MACHINE(domiid.value, &machine); - if (NS_FAILED(rc)) { - virReportError(VIR_ERR_NO_DOMAIN, "%s", - _("no domain with matching UUID")); - goto cleanup; - } - - if (!(snap = vboxDomainSnapshotGet(data, dom, machine, snapshot->name))) - goto cleanup; - - rc = snap->vtbl->GetMachine(snap, &snapMachine); - if (NS_FAILED(rc)) { - virReportError(VIR_ERR_INTERNAL_ERROR, "%s", - _("cannot get machine")); - goto cleanup; - } - /* - * Get READ ONLY disks - * In the snapshot metadata, these are the disks written inside the node - */ - rc = vboxArrayGet(&mediumAttachments, snapMachine, snapMachine->vtbl->GetMediumAttachments); - if (NS_FAILED(rc)) { - virReportError(VIR_ERR_INTERNAL_ERROR, "%s", - _("cannot get medium attachments")); - goto cleanup; - } - /* get the number of attachments */ - for (i = 0; i < mediumAttachments.count; i++) { - IMediumAttachment *imediumattach = mediumAttachments.items[i]; - if (imediumattach) { - IMedium *medium = NULL; - - rc = imediumattach->vtbl->GetMedium(imediumattach, &medium); - if (NS_FAILED(rc)) { - virReportError(VIR_ERR_INTERNAL_ERROR, "%s", - _("cannot get medium")); - goto cleanup; - } - if (medium) { - def->dom->ndisks++; - VBOX_RELEASE(medium); - } - } - } - - /* Allocate mem, if fails return error */ - if (VIR_ALLOC_N(def->dom->disks, def->dom->ndisks) >= 0) { - for (i = 0; i < def->dom->ndisks; i++) { - virDomainDiskDefPtr diskDef = virDomainDiskDefNew(); - if (!diskDef) - goto cleanup; - def->dom->disks[i] = diskDef; - } - } else { - goto cleanup; - } - - if (!vboxGetMaxPortSlotValues(data->vboxObj, maxPortPerInst, maxSlotPerPort)) - goto cleanup; - - /* get the attachment details here */ - for (i = 0; i < mediumAttachments.count && diskCount < def->dom->ndisks; i++) { - PRUnichar *storageControllerName = NULL; - PRUint32 deviceType = DeviceType_Null; - PRUint32 storageBus = StorageBus_Null; - PRBool readOnly = PR_FALSE; - PRUnichar *mediumLocUtf16 = NULL; - char *mediumLocUtf8 = NULL; - PRUint32 deviceInst = 0; - PRInt32 devicePort = 0; - PRInt32 deviceSlot = 0; - IMediumAttachment *imediumattach = mediumAttachments.items[i]; - if (!imediumattach) - continue; - rc = imediumattach->vtbl->GetMedium(imediumattach, &disk); - if (NS_FAILED(rc)) { - virReportError(VIR_ERR_INTERNAL_ERROR, "%s", - _("cannot get medium")); - goto cleanup; - } - if (!disk) - continue; - rc = imediumattach->vtbl->GetController(imediumattach, &storageControllerName); - if (NS_FAILED(rc)) { - virReportError(VIR_ERR_INTERNAL_ERROR, "%s", - _("cannot get storage controller name")); - goto cleanup; - } - if (!storageControllerName) - continue; - rc = machine->vtbl->GetStorageControllerByName(machine, - storageControllerName, - &storageController); - if (NS_FAILED(rc)) { - virReportError(VIR_ERR_INTERNAL_ERROR, "%s", - _("cannot get storage controller")); - goto cleanup; - } - VBOX_UTF16_FREE(storageControllerName); - if (!storageController) - continue; - rc = disk->vtbl->GetLocation(disk, &mediumLocUtf16); - if (NS_FAILED(rc)) { - virReportError(VIR_ERR_INTERNAL_ERROR, "%s", - _("cannot get disk location")); - goto cleanup; - } - VBOX_UTF16_TO_UTF8(mediumLocUtf16, &mediumLocUtf8); - VBOX_UTF16_FREE(mediumLocUtf16); - if (VIR_STRDUP(def->dom->disks[diskCount]->src->path, mediumLocUtf8) < 0) - goto cleanup; - - VBOX_UTF8_FREE(mediumLocUtf8); - - rc = storageController->vtbl->GetBus(storageController, &storageBus); - if (NS_FAILED(rc)) { - virReportError(VIR_ERR_INTERNAL_ERROR, "%s", - _("cannot get storage controller bus")); - goto cleanup; - } - if (storageBus == StorageBus_IDE) { - def->dom->disks[diskCount]->bus = VIR_DOMAIN_DISK_BUS_IDE; - } else if (storageBus == StorageBus_SATA) { - def->dom->disks[diskCount]->bus = VIR_DOMAIN_DISK_BUS_SATA; - } else if (storageBus == StorageBus_SCSI) { - def->dom->disks[diskCount]->bus = VIR_DOMAIN_DISK_BUS_SCSI; - } else if (storageBus == StorageBus_Floppy) { - def->dom->disks[diskCount]->bus = VIR_DOMAIN_DISK_BUS_FDC; - } - - rc = imediumattach->vtbl->GetType(imediumattach, &deviceType); - if (NS_FAILED(rc)) { - virReportError(VIR_ERR_INTERNAL_ERROR, "%s", - _("cannot get medium attachment type")); - goto cleanup; - } - if (deviceType == DeviceType_HardDisk) - def->dom->disks[diskCount]->device = VIR_DOMAIN_DISK_DEVICE_DISK; - else if (deviceType == DeviceType_Floppy) - def->dom->disks[diskCount]->device = VIR_DOMAIN_DISK_DEVICE_FLOPPY; - else if (deviceType == DeviceType_DVD) - def->dom->disks[diskCount]->device = VIR_DOMAIN_DISK_DEVICE_CDROM; - - rc = imediumattach->vtbl->GetPort(imediumattach, &devicePort); - if (NS_FAILED(rc)) { - virReportError(VIR_ERR_INTERNAL_ERROR, "%s", - _("cannot get medium attachment port")); - goto cleanup; - } - rc = imediumattach->vtbl->GetDevice(imediumattach, &deviceSlot); - if (NS_FAILED(rc)) { - virReportError(VIR_ERR_INTERNAL_ERROR, "%s", - _("cannot get device")); - goto cleanup; - } - rc = disk->vtbl->GetReadOnly(disk, &readOnly); - if (NS_FAILED(rc)) { - virReportError(VIR_ERR_INTERNAL_ERROR, "%s", - _("cannot get read only attribute")); - goto cleanup; - } - if (readOnly == PR_TRUE) - def->dom->disks[diskCount]->src->readonly = true; - def->dom->disks[diskCount]->src->type = VIR_STORAGE_TYPE_FILE; - def->dom->disks[diskCount]->dst = vboxGenerateMediumName(storageBus, - deviceInst, - devicePort, - deviceSlot, - maxPortPerInst, - maxSlotPerPort); - if (!def->dom->disks[diskCount]->dst) { - virReportError(VIR_ERR_INTERNAL_ERROR, - _("Could not generate medium name for the disk " - "at: controller instance:%u, port:%d, slot:%d"), - deviceInst, devicePort, deviceSlot); - ret = -1; - goto cleanup; - } - diskCount ++; - } - /* cleanup on error */ - - ret = 0; - cleanup: - if (ret < 0) { - for (i = 0; i < def->dom->ndisks; i++) - virDomainDiskDefFree(def->dom->disks[i]); - VIR_FREE(def->dom->disks); - def->dom->ndisks = 0; - } - VBOX_RELEASE(disk); - VBOX_RELEASE(storageController); - vboxArrayRelease(&mediumAttachments); - VBOX_RELEASE(snap); - return ret; -} -#endif - -static char * -vboxDomainSnapshotGetXMLDesc(virDomainSnapshotPtr snapshot, - unsigned int flags) -{ - virDomainPtr dom = snapshot->domain; - VBOX_OBJECT_CHECK(dom->conn, char *, NULL); - vboxIID domiid = VBOX_IID_INITIALIZER; - IMachine *machine = NULL; - ISnapshot *snap = NULL; - ISnapshot *parent = NULL; - nsresult rc; - virDomainSnapshotDefPtr def = NULL; - PRUnichar *str16; - char *str8; - PRInt64 timestamp; - PRBool online = PR_FALSE; - char uuidstr[VIR_UUID_STRING_BUFLEN]; -#if VBOX_API_VERSION >=4002000 - PRUint32 memorySize = 0; - PRUint32 CPUCount = 0; -#endif - - virCheckFlags(0, NULL); - - vboxIIDFromUUID(&domiid, dom->uuid); - rc = VBOX_OBJECT_GET_MACHINE(domiid.value, &machine); - if (NS_FAILED(rc)) { - virReportError(VIR_ERR_NO_DOMAIN, "%s", - _("no domain with matching UUID")); - goto cleanup; - } - - if (!(snap = vboxDomainSnapshotGet(data, dom, machine, snapshot->name))) - goto cleanup; - - if (VIR_ALLOC(def) < 0 || VIR_ALLOC(def->dom) < 0) - goto cleanup; - if (VIR_STRDUP(def->name, snapshot->name) < 0) - goto cleanup; - -#if VBOX_API_VERSION >=4002000 - /* Register def->dom properties for them to be saved inside the snapshot XMl - * Otherwise, there is a problem while parsing the xml - */ - def->dom->virtType = VIR_DOMAIN_VIRT_VBOX; - def->dom->id = dom->id; - memcpy(def->dom->uuid, dom->uuid, VIR_UUID_BUFLEN); - if (VIR_STRDUP(def->dom->name, dom->name) < 0) - goto cleanup; - machine->vtbl->GetMemorySize(machine, &memorySize); - def->dom->mem.cur_balloon = memorySize * 1024; - /* Currently setting memory and maxMemory as same, cause - * the notation here seems to be inconsistent while - * reading and while dumping xml - */ - def->dom->mem.max_balloon = memorySize * 1024; - if (VIR_STRDUP(def->dom->os.type, "hvm") < 0) - goto cleanup; - def->dom->os.arch = virArchFromHost(); - machine->vtbl->GetCPUCount(machine, &CPUCount); - def->dom->maxvcpus = def->dom->vcpus = CPUCount; - if (vboxSnapshotGetReadWriteDisks(def, snapshot) < 0) { - VIR_DEBUG("Could not get read write disks for snapshot"); - } - - if (vboxSnapshotGetReadOnlyDisks(snapshot, def) < 0) { - VIR_DEBUG("Could not get Readonly disks for snapshot"); - } -#endif /* VBOX_API_VERSION >= 4002000 */ - - rc = snap->vtbl->GetDescription(snap, &str16); - if (NS_FAILED(rc)) { - virReportError(VIR_ERR_INTERNAL_ERROR, - _("could not get description of snapshot %s"), - snapshot->name); - goto cleanup; - } - if (str16) { - VBOX_UTF16_TO_UTF8(str16, &str8); - VBOX_UTF16_FREE(str16); - if (VIR_STRDUP(def->description, str8) < 0) { - VBOX_UTF8_FREE(str8); - goto cleanup; - } - VBOX_UTF8_FREE(str8); - } - - rc = snap->vtbl->GetTimeStamp(snap, ×tamp); - if (NS_FAILED(rc)) { - virReportError(VIR_ERR_INTERNAL_ERROR, - _("could not get creation time of snapshot %s"), - snapshot->name); - goto cleanup; - } - /* timestamp is in milliseconds while creationTime in seconds */ - def->creationTime = timestamp / 1000; - - rc = snap->vtbl->GetParent(snap, &parent); - if (NS_FAILED(rc)) { - virReportError(VIR_ERR_INTERNAL_ERROR, - _("could not get parent of snapshot %s"), - snapshot->name); - goto cleanup; - } - if (parent) { - rc = parent->vtbl->GetName(parent, &str16); - if (NS_FAILED(rc) || !str16) { - virReportError(VIR_ERR_INTERNAL_ERROR, - _("could not get name of parent of snapshot %s"), - snapshot->name); - goto cleanup; - } - VBOX_UTF16_TO_UTF8(str16, &str8); - VBOX_UTF16_FREE(str16); - if (VIR_STRDUP(def->parent, str8) < 0) { - VBOX_UTF8_FREE(str8); - goto cleanup; - } - VBOX_UTF8_FREE(str8); - } - - rc = snap->vtbl->GetOnline(snap, &online); - if (NS_FAILED(rc)) { - virReportError(VIR_ERR_INTERNAL_ERROR, - _("could not get online state of snapshot %s"), - snapshot->name); - goto cleanup; - } - if (online) - def->state = VIR_DOMAIN_RUNNING; - else - def->state = VIR_DOMAIN_SHUTOFF; - - virUUIDFormat(dom->uuid, uuidstr); - memcpy(def->dom->uuid, dom->uuid, VIR_UUID_BUFLEN); - ret = virDomainSnapshotDefFormat(uuidstr, def, flags, 0); - - cleanup: - virDomainSnapshotDefFree(def); - VBOX_RELEASE(parent); - VBOX_RELEASE(snap); - VBOX_RELEASE(machine); - vboxIIDUnalloc(&domiid); - return ret; -} - static int vboxDomainSnapshotNum(virDomainPtr dom, unsigned int flags) @@ -6709,6 +6066,12 @@ _vboxIIDToUtf8(vboxGlobalData *data ATTRIBUTE_UNUSED, #endif /* !(VBOX_API_VERSION == 2002000) */ } +static nsresult +_vboxArrayGetWithIIDArg(vboxArray *array, void *self, void *getter, vboxIIDUnion *iidu) +{ + return vboxArrayGetWithPtrArg(array, self, getter, IID_MEMBER(value)); +} + static void* _handleGetMachines(IVirtualBox *vboxObj) { return vboxObj->vtbl->GetMachines; @@ -6733,11 +6096,36 @@ static void* _handleMachineGetSharedFolders(IMachine *machine) return machine->vtbl->GetSharedFolders; } +static void* _handleSnapshotGetChildren(ISnapshot *snapshot) +{ + return snapshot->vtbl->GetChildren; +} + +static void* _handleMediumGetChildren(IMedium *medium ATTRIBUTE_UNUSED) +{ +#if VBOX_API_VERSION < 3001000 + vboxUnsupported(); + return 0; +#else /* VBOX_API_VERSION >= 3001000 */ + return medium->vtbl->GetChildren; +#endif /* VBOX_API_VERSION >= 3001000 */ +} + +static void* _handleMediumGetSnapshotIds(IMedium *medium) +{ + return medium->vtbl->GetSnapshotIds; +} + static nsresult _nsisupportsRelease(nsISupports *nsi) { return nsi->vtbl->Release(nsi); } +static nsresult _nsisupportsAddRef(nsISupports *nsi) +{ + return nsi->vtbl->AddRef(nsi); +} + static nsresult _virtualboxGetVersion(IVirtualBox *vboxObj, PRUnichar **versionUtf16) { @@ -6989,6 +6377,16 @@ _machineUnregister(IMachine *machine ATTRIBUTE_UNUSED, #endif /* VBOX_API_VERSION >= 4000000 */ } +static nsresult +_machineFindSnapshot(IMachine *machine, vboxIIDUnion *iidu, ISnapshot **snapshot) +{ +#if VBOX_API_VERSION < 4000000 + return machine->vtbl->GetSnapshot(machine, IID_MEMBER(value), snapshot); +#else /* VBOX_API_VERSION >= 4000000 */ + return machine->vtbl->FindSnapshot(machine, IID_MEMBER(value), snapshot); +#endif /* VBOX_API_VERSION >= 4000000 */ +} + static nsresult _machineGetAccessible(IMachine *machine, PRBool *isAccessible) { @@ -7218,6 +6616,12 @@ _machineSetExtraData(IMachine *machine, PRUnichar *key, PRUnichar *value) return machine->vtbl->SetExtraData(machine, key, value); } +static nsresult +_machineGetSnapshotCount(IMachine *machine, PRUint32 *snapshotCount) +{ + return machine->vtbl->GetSnapshotCount(machine, snapshotCount); +} + static nsresult _machineSaveSettings(IMachine *machine) { @@ -8156,6 +7560,48 @@ _sharedFolderGetWritable(ISharedFolder *sharedFolder, PRBool *writable) return sharedFolder->vtbl->GetWritable(sharedFolder, writable); } +static nsresult +_snapshotGetName(ISnapshot *snapshot, PRUnichar **name) +{ + return snapshot->vtbl->GetName(snapshot, name); +} + +static nsresult +_snapshotGetId(ISnapshot *snapshot, vboxIIDUnion *iidu) +{ + return snapshot->vtbl->GetId(snapshot, &IID_MEMBER(value)); +} + +static nsresult +_snapshotGetMachine(ISnapshot *snapshot, IMachine **machine) +{ + return snapshot->vtbl->GetMachine(snapshot, machine); +} + +static nsresult +_snapshotGetDescription(ISnapshot *snapshot, PRUnichar **description) +{ + return snapshot->vtbl->GetDescription(snapshot, description); +} + +static nsresult +_snapshotGetTimeStamp(ISnapshot *snapshot, PRInt64 *timeStamp) +{ + return snapshot->vtbl->GetTimeStamp(snapshot, timeStamp); +} + +static nsresult +_snapshotGetParent(ISnapshot *snapshot, ISnapshot **parent) +{ + return snapshot->vtbl->GetParent(snapshot, parent); +} + +static nsresult +_snapshotGetOnline(ISnapshot *snapshot, PRBool *online) +{ + return snapshot->vtbl->GetOnline(snapshot, online); +} + static bool _machineStateOnline(PRUint32 state) { return ((state >= MachineState_FirstOnline) && @@ -8213,15 +7659,20 @@ static vboxUniformedIID _UIID = { static vboxUniformedArray _UArray = { .vboxArrayGet = vboxArrayGet, + .vboxArrayGetWithIIDArg = _vboxArrayGetWithIIDArg, .vboxArrayRelease = vboxArrayRelease, .handleGetMachines = _handleGetMachines, .handleUSBGetDeviceFilters = _handleUSBGetDeviceFilters, .handleMachineGetMediumAttachments = _handleMachineGetMediumAttachments, .handleMachineGetSharedFolders = _handleMachineGetSharedFolders, + .handleSnapshotGetChildren = _handleSnapshotGetChildren, + .handleMediumGetChildren = _handleMediumGetChildren, + .handleMediumGetSnapshotIds = _handleMediumGetSnapshotIds, }; static vboxUniformednsISupports _nsUISupports = { .Release = _nsisupportsRelease, + .AddRef = _nsisupportsAddRef, }; static vboxUniformedIVirtualBox _UIVirtualBox = { @@ -8244,6 +7695,7 @@ static vboxUniformedIMachine _UIMachine = { .RemoveSharedFolder = _machineRemoveSharedFolder, .LaunchVMProcess = _machineLaunchVMProcess, .Unregister = _machineUnregister, + .FindSnapshot = _machineFindSnapshot, .GetAccessible = _machineGetAccessible, .GetState = _machineGetState, .GetName = _machineGetName, @@ -8276,6 +7728,7 @@ static vboxUniformedIMachine _UIMachine = { .SetAccelerate2DVideoEnabled = _machineSetAccelerate2DVideoEnabled, .GetExtraData = _machineGetExtraData, .SetExtraData = _machineSetExtraData, + .GetSnapshotCount = _machineGetSnapshotCount, .SaveSettings = _machineSaveSettings, }; @@ -8433,6 +7886,16 @@ static vboxUniformedISharedFolder _UISharedFolder = { .GetWritable = _sharedFolderGetWritable, }; +static vboxUniformedISnapshot _UISnapshot = { + .GetName = _snapshotGetName, + .GetId = _snapshotGetId, + .GetMachine = _snapshotGetMachine, + .GetDescription = _snapshotGetDescription, + .GetTimeStamp = _snapshotGetTimeStamp, + .GetParent = _snapshotGetParent, + .GetOnline = _snapshotGetOnline, +}; + static uniformedMachineStateChecker _machineStateChecker = { .Online = _machineStateOnline, .Inactive = _machineStateInactive, @@ -8482,6 +7945,7 @@ void NAME(InstallUniformedAPI)(vboxUniformedAPI *pVBoxAPI) pVBoxAPI->UIMediumAttachment = _UIMediumAttachment; pVBoxAPI->UIStorageController = _UIStorageController; pVBoxAPI->UISharedFolder = _UISharedFolder; + pVBoxAPI->UISnapshot = _UISnapshot; pVBoxAPI->machineStateChecker = _machineStateChecker; #if VBOX_API_VERSION <= 2002000 || VBOX_API_VERSION >= 4000000 diff --git a/src/vbox/vbox_uniformed_api.h b/src/vbox/vbox_uniformed_api.h index 8357df5d6a..6b04b57216 100644 --- a/src/vbox/vbox_uniformed_api.h +++ b/src/vbox/vbox_uniformed_api.h @@ -166,17 +166,22 @@ typedef struct { /* Functions for vboxArray */ typedef struct { nsresult (*vboxArrayGet)(vboxArray *array, void *self, void *getter); + nsresult (*vboxArrayGetWithIIDArg)(vboxArray *array, void *self, void *getter, vboxIIDUnion *iidu); void (*vboxArrayRelease)(vboxArray *array); /* Generate function pointers for vboxArrayGet */ void* (*handleGetMachines)(IVirtualBox *vboxObj); void* (*handleUSBGetDeviceFilters)(IUSBCommon *USBCommon); void* (*handleMachineGetMediumAttachments)(IMachine *machine); void* (*handleMachineGetSharedFolders)(IMachine *machine); + void* (*handleSnapshotGetChildren)(ISnapshot *snapshot); + void* (*handleMediumGetChildren)(IMedium *medium); + void* (*handleMediumGetSnapshotIds)(IMedium *medium); } vboxUniformedArray; /* Functions for nsISupports */ typedef struct { nsresult (*Release)(nsISupports *nsi); + nsresult (*AddRef)(nsISupports *nsi); } vboxUniformednsISupports; /* Functions for IVirtualBox */ @@ -211,6 +216,7 @@ typedef struct { IProgress **progress); nsresult (*Unregister)(IMachine *machine, PRUint32 cleanupMode, PRUint32 *aMediaSize, IMedium ***aMedia); + nsresult (*FindSnapshot)(IMachine *machine, vboxIIDUnion *iidu, ISnapshot **snapshot); nsresult (*GetAccessible)(IMachine *machine, PRBool *isAccessible); nsresult (*GetState)(IMachine *machine, PRUint32 *state); nsresult (*GetName)(IMachine *machine, PRUnichar **name); @@ -243,6 +249,7 @@ typedef struct { nsresult (*SetAccelerate2DVideoEnabled)(IMachine *machine, PRBool accelerate2DVideoEnabled); nsresult (*GetExtraData)(IMachine *machine, PRUnichar *key, PRUnichar **value); nsresult (*SetExtraData)(IMachine *machine, PRUnichar *key, PRUnichar *value); + nsresult (*GetSnapshotCount)(IMachine *machine, PRUint32 *snapshotCount); nsresult (*SaveSettings)(IMachine *machine); } vboxUniformedIMachine; @@ -427,6 +434,17 @@ typedef struct { nsresult (*GetWritable)(ISharedFolder *sharedFolder, PRBool *writable); } vboxUniformedISharedFolder; +/* Functions for ISnapshot */ +typedef struct { + nsresult (*GetName)(ISnapshot *snapshot, PRUnichar **name); + nsresult (*GetId)(ISnapshot *snapshot, vboxIIDUnion *iidu); + nsresult (*GetMachine)(ISnapshot *snapshot, IMachine **machine); + nsresult (*GetDescription)(ISnapshot *snapshot, PRUnichar **description); + nsresult (*GetTimeStamp)(ISnapshot *snapshot, PRInt64 *timeStamp); + nsresult (*GetParent)(ISnapshot *snapshot, ISnapshot **parent); + nsresult (*GetOnline)(ISnapshot *snapshot, PRBool *online); +} vboxUniformedISnapshot; + typedef struct { bool (*Online)(PRUint32 state); bool (*Inactive)(PRUint32 state); @@ -477,6 +495,7 @@ typedef struct { vboxUniformedIMediumAttachment UIMediumAttachment; vboxUniformedIStorageController UIStorageController; vboxUniformedISharedFolder UISharedFolder; + vboxUniformedISnapshot UISnapshot; uniformedMachineStateChecker machineStateChecker; /* vbox API features */ bool domainEventCallbacks; @@ -556,7 +575,8 @@ virDomainSnapshotPtr vboxDomainSnapshotCreateXML(virDomainPtr dom, const char *xmlDesc, unsigned int flags); - +char *vboxDomainSnapshotGetXMLDesc(virDomainSnapshotPtr snapshot, + unsigned int flags); /* Version specified functions for installing uniformed API */ void vbox22InstallUniformedAPI(vboxUniformedAPI *pVBoxAPI); -- GitLab