diff --git a/src/vbox/vbox_common.c b/src/vbox/vbox_common.c index 0638807234a047f0c70a015bd2b600c3ba9a00d3..d7f298b7f605d4da55caecfda61b62c2ef093569 100644 --- a/src/vbox/vbox_common.c +++ b/src/vbox/vbox_common.c @@ -6512,3 +6512,612 @@ int vboxDomainRevertToSnapshot(virDomainSnapshotPtr snapshot, vboxIIDUnalloc(&domiid); return ret; } + +static int +vboxDomainSnapshotDeleteSingle(vboxGlobalData *data, + IConsole *console, + ISnapshot *snapshot) +{ + IProgress *progress = NULL; + vboxIIDUnion iid; + int ret = -1; + nsresult rc; + resultCodeUnion result; + + VBOX_IID_INITIALIZE(&iid); + rc = gVBoxAPI.UISnapshot.GetId(snapshot, &iid); + if (NS_FAILED(rc)) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("could not get snapshot UUID")); + goto cleanup; + } + + rc = gVBoxAPI.UIConsole.DeleteSnapshot(console, &iid, &progress); + if (NS_FAILED(rc) || !progress) { + if (rc == VBOX_E_INVALID_VM_STATE) { + virReportError(VIR_ERR_OPERATION_INVALID, "%s", + _("cannot delete domain snapshot for running domain")); + } else { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("could not delete snapshot")); + } + goto cleanup; + } + + gVBoxAPI.UIProgress.WaitForCompletion(progress, -1); + gVBoxAPI.UIProgress.GetResultCode(progress, &result); + if (RC_FAILED(result)) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("could not delete snapshot")); + goto cleanup; + } + + ret = 0; + + cleanup: + VBOX_RELEASE(progress); + vboxIIDUnalloc(&iid); + return ret; +} + +static int +vboxDomainSnapshotDeleteTree(vboxGlobalData *data, + IConsole *console, + ISnapshot *snapshot) +{ + vboxArray children = VBOX_ARRAY_INITIALIZER; + int ret = -1; + nsresult rc; + size_t i; + + rc = gVBoxAPI.UArray.vboxArrayGet(&children, snapshot, + gVBoxAPI.UArray.handleSnapshotGetChildren(snapshot)); + if (NS_FAILED(rc)) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("could not get children snapshots")); + goto cleanup; + } + + for (i = 0; i < children.count; i++) { + if (vboxDomainSnapshotDeleteTree(data, console, children.items[i])) + goto cleanup; + } + + ret = vboxDomainSnapshotDeleteSingle(data, console, snapshot); + + cleanup: + gVBoxAPI.UArray.vboxArrayRelease(&children); + return ret; +} + +static int +vboxDomainSnapshotDeleteMetadataOnly(virDomainSnapshotPtr snapshot) +{ + /* + * This function will remove the node in the vbox xml corresponding to the snapshot. + * It is usually called by vboxDomainSnapshotDelete() with the flag + * VIR_DOMAIN_SNAPSHOT_DELETE_METADATA_ONLY. + * If you want to use it anywhere else, be careful, if the snapshot you want to delete + * has children, the result is not granted, they will probably will be deleted in the + * xml, but you may have a problem with hard drives. + * + * If the snapshot which is being deleted is the current one, we will set the current + * snapshot of the machine to the parent of this snapshot. Before writing the modified + * xml file, we undefine the machine from vbox. After writing the file, we redefine + * the machine with the new file. + */ + + virDomainPtr dom = snapshot->domain; + VBOX_OBJECT_CHECK(dom->conn, int, -1); + virDomainSnapshotDefPtr def = NULL; + char *defXml = NULL; + vboxIIDUnion domiid; + nsresult rc; + IMachine *machine = NULL; + PRUnichar *settingsFilePathUtf16 = NULL; + char *settingsFilepath = NULL; + virVBoxSnapshotConfMachinePtr snapshotMachineDesc = NULL; + int isCurrent = -1; + int it = 0; + PRUnichar *machineNameUtf16 = NULL; + char *machineName = NULL; + char *nameTmpUse = NULL; + char *machineLocationPath = NULL; + PRUint32 aMediaSize = 0; + IMedium **aMedia = NULL; + + VBOX_IID_INITIALIZE(&domiid); + if (!gVBoxAPI.vboxSnapshotRedefine) + VIR_WARN("This function may not work in current version"); + + defXml = vboxDomainSnapshotGetXMLDesc(snapshot, 0); + if (!defXml) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("Unable to get XML Desc of snapshot")); + goto cleanup; + } + def = virDomainSnapshotDefParseString(defXml, + data->caps, + data->xmlopt, + -1, + VIR_DOMAIN_SNAPSHOT_PARSE_DISKS | + VIR_DOMAIN_SNAPSHOT_PARSE_REDEFINE); + if (!def) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("Unable to get a virDomainSnapshotDefPtr")); + goto cleanup; + } + + if (openSessionForMachine(data, dom->uuid, &domiid, &machine, false) < 0) + goto cleanup; + rc = gVBoxAPI.UIMachine.GetSettingsFilePath(machine, &settingsFilePathUtf16); + if (NS_FAILED(rc)) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("cannot get settings file path")); + goto cleanup; + } + VBOX_UTF16_TO_UTF8(settingsFilePathUtf16, &settingsFilepath); + + /*Getting the machine name to retrieve the machine location path.*/ + rc = gVBoxAPI.UIMachine.GetName(machine, &machineNameUtf16); + if (NS_FAILED(rc)) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("cannot get machine name")); + goto cleanup; + } + VBOX_UTF16_TO_UTF8(machineNameUtf16, &machineName); + if (virAsprintf(&nameTmpUse, "%s.vbox", machineName) < 0) + goto cleanup; + machineLocationPath = virStringReplace(settingsFilepath, nameTmpUse, ""); + if (machineLocationPath == NULL) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("Unable to get the machine location path")); + goto cleanup; + } + snapshotMachineDesc = virVBoxSnapshotConfLoadVboxFile(settingsFilepath, machineLocationPath); + if (!snapshotMachineDesc) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("cannot create a vboxSnapshotXmlPtr")); + goto cleanup; + } + + isCurrent = virVBoxSnapshotConfIsCurrentSnapshot(snapshotMachineDesc, def->name); + if (isCurrent < 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("Unable to know if the snapshot is the current snapshot")); + goto cleanup; + } + if (isCurrent) { + /* + * If the snapshot is the current snapshot, it means that the machine has read-write + * disks. The first thing to do is to manipulate VirtualBox API to create + * differential read-write disks if the parent snapshot is not null. + */ + if (def->parent != NULL) { + for (it = 0; it < def->dom->ndisks; it++) { + virVBoxSnapshotConfHardDiskPtr readOnly = NULL; + IMedium *medium = NULL; + PRUnichar *locationUtf16 = NULL; + char *parentUuid = NULL; + IMedium *newMedium = NULL; + PRUnichar *formatUtf16 = NULL; + PRUnichar *newLocation = NULL; + char *newLocationUtf8 = NULL; + IProgress *progress = NULL; + virVBoxSnapshotConfHardDiskPtr disk = NULL; + char *uuid = NULL; + char *format = NULL; + char **searchResultTab = NULL; + ssize_t resultSize = 0; + char *tmp = NULL; + vboxIIDUnion iid, parentiid; + resultCodeUnion resultCode; + + VBOX_IID_INITIALIZE(&iid); + VBOX_IID_INITIALIZE(&parentiid); + readOnly = virVBoxSnapshotConfHardDiskPtrByLocation(snapshotMachineDesc, + def->dom->disks[it]->src->path); + if (!readOnly) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("Cannot get hard disk by location")); + goto cleanup; + } + if (readOnly->parent == NULL) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("The read only disk has no parent")); + goto cleanup; + } + + VBOX_UTF8_TO_UTF16(readOnly->parent->location, &locationUtf16); + rc = gVBoxAPI.UIVirtualBox.OpenMedium(data->vboxObj, + locationUtf16, + DeviceType_HardDisk, + AccessMode_ReadWrite, + &medium); + if (NS_FAILED(rc)) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("Unable to open HardDisk, rc=%08x"), + (unsigned)rc); + goto cleanup; + } + + rc = gVBoxAPI.UIMedium.GetId(medium, &parentiid); + if (NS_FAILED(rc)) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("Unable to get hardDisk Id, rc=%08x"), + (unsigned)rc); + goto cleanup; + } + gVBoxAPI.UIID.vboxIIDToUtf8(data, &parentiid, &parentUuid); + vboxIIDUnalloc(&parentiid); + VBOX_UTF16_FREE(locationUtf16); + VBOX_UTF8_TO_UTF16("VDI", &formatUtf16); + + if (virAsprintf(&newLocationUtf8, "%sfakedisk-%s-%d.vdi", + machineLocationPath, def->parent, it) < 0) + goto cleanup; + VBOX_UTF8_TO_UTF16(newLocationUtf8, &newLocation); + rc = gVBoxAPI.UIVirtualBox.CreateHardDiskMedium(data->vboxObj, + formatUtf16, + newLocation, + &newMedium); + if (NS_FAILED(rc)) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("Unable to create HardDisk, rc=%08x"), + (unsigned)rc); + goto cleanup; + } + VBOX_UTF16_FREE(formatUtf16); + VBOX_UTF16_FREE(newLocation); + + PRUint32 tab[1]; + tab[0] = MediumVariant_Diff; + gVBoxAPI.UIMedium.CreateDiffStorage(medium, newMedium, 1, tab, &progress); + + gVBoxAPI.UIProgress.WaitForCompletion(progress, -1); + gVBoxAPI.UIProgress.GetResultCode(progress, &resultCode); + if (RC_FAILED(resultCode)) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("Error while creating diff storage, rc=%08x"), + resultCode.uResultCode); + goto cleanup; + } + VBOX_RELEASE(progress); + /* + * The differential disk is created, we add it to the media registry and + * the machine storage controller. + */ + + if (VIR_ALLOC(disk) < 0) + goto cleanup; + + rc = gVBoxAPI.UIMedium.GetId(newMedium, &iid); + if (NS_FAILED(rc)) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("Unable to get medium uuid, rc=%08x"), + (unsigned)rc); + VIR_FREE(disk); + goto cleanup; + } + gVBoxAPI.UIID.vboxIIDToUtf8(data, &iid, &uuid); + disk->uuid = uuid; + vboxIIDUnalloc(&iid); + + if (VIR_STRDUP(disk->location, newLocationUtf8) < 0) { + VIR_FREE(disk); + goto cleanup; + } + + rc = gVBoxAPI.UIMedium.GetFormat(newMedium, &formatUtf16); + VBOX_UTF16_TO_UTF8(formatUtf16, &format); + disk->format = format; + VBOX_UTF16_FREE(formatUtf16); + + if (virVBoxSnapshotConfAddHardDiskToMediaRegistry(disk, + snapshotMachineDesc->mediaRegistry, + parentUuid) < 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("Unable to add hard disk to the media registry")); + goto cleanup; + } + /*Adding fake disks to the machine storage controllers*/ + + resultSize = virStringSearch(snapshotMachineDesc->storageController, + VBOX_UUID_REGEX, + it + 1, + &searchResultTab); + if (resultSize != it + 1) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("Unable to find UUID %s"), searchResultTab[it]); + goto cleanup; + } + + tmp = virStringReplace(snapshotMachineDesc->storageController, + searchResultTab[it], + disk->uuid); + virStringFreeList(searchResultTab); + VIR_FREE(snapshotMachineDesc->storageController); + if (!tmp) + goto cleanup; + if (VIR_STRDUP(snapshotMachineDesc->storageController, tmp) < 0) + goto cleanup; + + VIR_FREE(tmp); + /*Closing the "fake" disk*/ + rc = gVBoxAPI.UIMedium.Close(newMedium); + if (NS_FAILED(rc)) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("Unable to close the new medium, rc=%08x"), + (unsigned)rc); + goto cleanup; + } + } + } else { + for (it = 0; it < def->dom->ndisks; it++) { + const char *uuidRO = NULL; + char **searchResultTab = NULL; + ssize_t resultSize = 0; + char *tmp = NULL; + uuidRO = virVBoxSnapshotConfHardDiskUuidByLocation(snapshotMachineDesc, + def->dom->disks[it]->src->path); + if (!uuidRO) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("No such disk in media registry %s"), + def->dom->disks[it]->src->path); + goto cleanup; + } + + resultSize = virStringSearch(snapshotMachineDesc->storageController, + VBOX_UUID_REGEX, + it + 1, + &searchResultTab); + if (resultSize != it + 1) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("Unable to find UUID %s"), + searchResultTab[it]); + goto cleanup; + } + + tmp = virStringReplace(snapshotMachineDesc->storageController, + searchResultTab[it], + uuidRO); + virStringFreeList(searchResultTab); + VIR_FREE(snapshotMachineDesc->storageController); + if (!tmp) + goto cleanup; + if (VIR_STRDUP(snapshotMachineDesc->storageController, tmp) < 0) + goto cleanup; + + VIR_FREE(tmp); + } + } + } + /*We remove the read write disks from the media registry*/ + for (it = 0; it < def->ndisks; it++) { + const char *uuidRW = + virVBoxSnapshotConfHardDiskUuidByLocation(snapshotMachineDesc, + def->disks[it].src->path); + if (!uuidRW) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("Unable to find UUID for location %s"), def->disks[it].src->path); + goto cleanup; + } + if (virVBoxSnapshotConfRemoveHardDisk(snapshotMachineDesc->mediaRegistry, uuidRW) < 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("Unable to remove disk from media registry. uuid = %s"), uuidRW); + goto cleanup; + } + } + /*If the parent snapshot is not NULL, we remove the-read only disks from the media registry*/ + if (def->parent != NULL) { + for (it = 0; it < def->dom->ndisks; it++) { + const char *uuidRO = + virVBoxSnapshotConfHardDiskUuidByLocation(snapshotMachineDesc, + def->dom->disks[it]->src->path); + if (!uuidRO) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("Unable to find UUID for location %s"), def->dom->disks[it]->src->path); + goto cleanup; + } + if (virVBoxSnapshotConfRemoveHardDisk(snapshotMachineDesc->mediaRegistry, uuidRO) < 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("Unable to remove disk from media registry. uuid = %s"), uuidRO); + goto cleanup; + } + } + } + rc = gVBoxAPI.UIMachine.Unregister(machine, + CleanupMode_DetachAllReturnHardDisksOnly, + &aMediaSize, + &aMedia); + if (NS_FAILED(rc)) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("Unable to unregister machine, rc=%08x"), + (unsigned)rc); + goto cleanup; + } + VBOX_RELEASE(machine); + for (it = 0; it < aMediaSize; it++) { + IMedium *medium = aMedia[it]; + PRUnichar *locationUtf16 = NULL; + char *locationUtf8 = NULL; + + if (!medium) + continue; + + rc = gVBoxAPI.UIMedium.GetLocation(medium, &locationUtf16); + VBOX_UTF16_TO_UTF8(locationUtf16, &locationUtf8); + if (isCurrent && strstr(locationUtf8, "fake") != NULL) { + /*we delete the fake disk because we don't need it anymore*/ + IProgress *progress = NULL; + resultCodeUnion resultCode; + rc = gVBoxAPI.UIMedium.DeleteStorage(medium, &progress); + if (NS_FAILED(rc)) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("Unable to delete medium, rc=%08x"), + (unsigned)rc); + goto cleanup; + } + gVBoxAPI.UIProgress.WaitForCompletion(progress, -1); + gVBoxAPI.UIProgress.GetResultCode(progress, &resultCode); + if (RC_FAILED(resultCode)) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("Error while closing medium, rc=%08x"), + resultCode.uResultCode); + goto cleanup; + } + VBOX_RELEASE(progress); + } else { + /* This a comment from vboxmanage code in the handleUnregisterVM + * function in VBoxManageMisc.cpp : + * Note that the IMachine::Unregister method will return the medium + * reference in a sane order, which means that closing will normally + * succeed, unless there is still another machine which uses the + * medium. No harm done if we ignore the error. */ + rc = gVBoxAPI.UIMedium.Close(medium); + } + VBOX_UTF16_FREE(locationUtf16); + VBOX_UTF8_FREE(locationUtf8); + } + + /*removing the snapshot*/ + if (virVBoxSnapshotConfRemoveSnapshot(snapshotMachineDesc, def->name) < 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("Unable to remove snapshot %s"), def->name); + goto cleanup; + } + + if (isCurrent) { + VIR_FREE(snapshotMachineDesc->currentSnapshot); + if (def->parent != NULL) { + virVBoxSnapshotConfSnapshotPtr snap = virVBoxSnapshotConfSnapshotByName(snapshotMachineDesc->snapshot, def->parent); + if (!snap) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("Unable to get the snapshot to remove")); + goto cleanup; + } + if (VIR_STRDUP(snapshotMachineDesc->currentSnapshot, snap->uuid) < 0) + goto cleanup; + } + } + + /*Registering the machine*/ + if (virVBoxSnapshotConfSaveVboxFile(snapshotMachineDesc, settingsFilepath) < 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("Unable to serialize the machine description")); + goto cleanup; + } + rc = gVBoxAPI.UIVirtualBox.OpenMachine(data->vboxObj, + settingsFilePathUtf16, + &machine); + if (NS_FAILED(rc)) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("Unable to open Machine, rc=%08x"), + (unsigned)rc); + goto cleanup; + } + + rc = gVBoxAPI.UIVirtualBox.RegisterMachine(data->vboxObj, machine); + if (NS_FAILED(rc)) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("Unable to register Machine, rc=%08x"), + (unsigned)rc); + goto cleanup; + } + + ret = 0; + cleanup: + VIR_FREE(def); + VIR_FREE(defXml); + VBOX_RELEASE(machine); + VBOX_UTF16_FREE(settingsFilePathUtf16); + VBOX_UTF8_FREE(settingsFilepath); + VIR_FREE(snapshotMachineDesc); + VBOX_UTF16_FREE(machineNameUtf16); + VBOX_UTF8_FREE(machineName); + VIR_FREE(machineLocationPath); + VIR_FREE(nameTmpUse); + + return ret; +} + +int vboxDomainSnapshotDelete(virDomainSnapshotPtr snapshot, + unsigned int flags) +{ + virDomainPtr dom = snapshot->domain; + VBOX_OBJECT_CHECK(dom->conn, int, -1); + vboxIIDUnion domiid; + IMachine *machine = NULL; + ISnapshot *snap = NULL; + IConsole *console = NULL; + PRUint32 state; + nsresult rc; + vboxArray snapChildren = VBOX_ARRAY_INITIALIZER; + + virCheckFlags(VIR_DOMAIN_SNAPSHOT_DELETE_CHILDREN | + VIR_DOMAIN_SNAPSHOT_DELETE_METADATA_ONLY, -1); + + if (openSessionForMachine(data, dom->uuid, &domiid, &machine, false) < 0) + goto cleanup; + + snap = vboxDomainSnapshotGet(data, dom, machine, snapshot->name); + if (!snap) + goto cleanup; + + rc = gVBoxAPI.UIMachine.GetState(machine, &state); + if (NS_FAILED(rc)) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("could not get domain state")); + goto cleanup; + } + + /* In case we just want to delete the metadata, we will edit the vbox file in order + *to remove the node concerning the snapshot + */ + if (flags & VIR_DOMAIN_SNAPSHOT_DELETE_METADATA_ONLY) { + rc = gVBoxAPI.UArray.vboxArrayGet(&snapChildren, snap, + gVBoxAPI.UArray.handleSnapshotGetChildren(snap)); + if (NS_FAILED(rc)) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("could not get snapshot children")); + goto cleanup; + } + if (snapChildren.count != 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("cannot delete metadata of a snapshot with children")); + goto cleanup; + } else + if (gVBoxAPI.vboxSnapshotRedefine) { + ret = vboxDomainSnapshotDeleteMetadataOnly(snapshot); + } + goto cleanup; + } + + if (gVBoxAPI.machineStateChecker.Online(state)) { + virReportError(VIR_ERR_OPERATION_INVALID, "%s", + _("cannot delete snapshots of running domain")); + goto cleanup; + } + + rc = gVBoxAPI.UISession.Open(data, &domiid, machine); + if (NS_SUCCEEDED(rc)) + rc = gVBoxAPI.UISession.GetConsole(data->vboxSession, &console); + if (NS_FAILED(rc)) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("could not open VirtualBox session with domain %s"), + dom->name); + goto cleanup; + } + + if (flags & VIR_DOMAIN_SNAPSHOT_DELETE_CHILDREN) + ret = vboxDomainSnapshotDeleteTree(data, console, snap); + else + ret = vboxDomainSnapshotDeleteSingle(data, console, snap); + + cleanup: + VBOX_RELEASE(console); + VBOX_RELEASE(snap); + vboxIIDUnalloc(&domiid); + gVBoxAPI.UISession.Close(data->vboxSession); + return ret; +} diff --git a/src/vbox/vbox_common.h b/src/vbox/vbox_common.h index 1c01fe8366f47e4d7b0faae3da5b552e088f7c5c..15bf8e2c18ba079874ae2da96e3e1b953614f91e 100644 --- a/src/vbox/vbox_common.h +++ b/src/vbox/vbox_common.h @@ -265,6 +265,19 @@ enum MediumVariant MediumVariant_Diff = 0x20000 }; +# define VBOX_E_OBJECT_NOT_FOUND 0x80BB0001 +# define VBOX_E_INVALID_VM_STATE 0x80BB0002 +# define VBOX_E_VM_ERROR 0x80BB0003 +# define VBOX_E_FILE_ERROR 0x80BB0004 +# define VBOX_E_IPRT_ERROR 0x80BB0005 +# define VBOX_E_PDM_ERROR 0x80BB0006 +# define VBOX_E_INVALID_OBJECT_STATE 0x80BB0007 +# define VBOX_E_HOST_ERROR 0x80BB0008 +# define VBOX_E_NOT_SUPPORTED 0x80BB0009 +# define VBOX_E_XML_ERROR 0x80BB000A +# define VBOX_E_INVALID_SESSION_STATE 0x80BB000B +# define VBOX_E_OBJECT_IN_USE 0x80BB000C + /* Simplied definitions in vbox_CAPI_*.h */ typedef void const *PCVBOXXPCOM; diff --git a/src/vbox/vbox_tmpl.c b/src/vbox/vbox_tmpl.c index 4e24fb23094c9fff68503259766866169d8ebe9c..23ff2834bdacb7f01559e10eaef763c34ad35741 100644 --- a/src/vbox/vbox_tmpl.c +++ b/src/vbox/vbox_tmpl.c @@ -1383,146 +1383,6 @@ _vboxAttachDrivesOld(virDomainDefPtr def ATTRIBUTE_UNUSED, #endif /* VBOX_API_VERSION >= 4000000 */ -static int -vboxDomainSnapshotGetAll(virDomainPtr dom, - IMachine *machine, - ISnapshot ***snapshots) -{ - vboxIID empty = VBOX_IID_INITIALIZER; - ISnapshot **list = NULL; - PRUint32 count; - nsresult rc; - unsigned int next; - unsigned int top; - - rc = machine->vtbl->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; - -#if VBOX_API_VERSION < 4000000 - rc = machine->vtbl->GetSnapshot(machine, empty.value, list); -#else /* VBOX_API_VERSION >= 4000000 */ - rc = machine->vtbl->FindSnapshot(machine, empty.value, list); -#endif /* VBOX_API_VERSION >= 4000000 */ - 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 = vboxArrayGet(&children, list[next], - list[next]->vtbl->GetChildren); - 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); - vboxArrayRelease(&children); - goto error; - } - VBOX_ADDREF(child); - list[top++] = child; - } - 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 = snapshots[i]->vtbl->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; -} - #if VBOX_API_VERSION < 3001000 static int _vboxDomainSnapshotRestore(virDomainPtr dom, @@ -1630,633 +1490,6 @@ _vboxDomainSnapshotRestore(virDomainPtr dom, } #endif -static int -vboxDomainSnapshotDeleteSingle(vboxGlobalData *data, - IConsole *console, - ISnapshot *snapshot) -{ - IProgress *progress = NULL; - vboxIID iid = VBOX_IID_INITIALIZER; - int ret = -1; - nsresult rc; -#if VBOX_API_VERSION == 2002000 - nsresult result; -#else - PRInt32 result; -#endif - - rc = snapshot->vtbl->GetId(snapshot, &iid.value); - if (NS_FAILED(rc)) { - virReportError(VIR_ERR_INTERNAL_ERROR, "%s", - _("could not get snapshot UUID")); - goto cleanup; - } - -#if VBOX_API_VERSION < 3001000 - rc = console->vtbl->DiscardSnapshot(console, iid.value, &progress); -#else - rc = console->vtbl->DeleteSnapshot(console, iid.value, &progress); -#endif - if (NS_FAILED(rc) || !progress) { - if (rc == VBOX_E_INVALID_VM_STATE) { - virReportError(VIR_ERR_OPERATION_INVALID, "%s", - _("cannot delete domain snapshot for running domain")); - } else { - virReportError(VIR_ERR_INTERNAL_ERROR, "%s", - _("could not delete snapshot")); - } - goto cleanup; - } - - progress->vtbl->WaitForCompletion(progress, -1); - progress->vtbl->GetResultCode(progress, &result); - if (NS_FAILED(result)) { - virReportError(VIR_ERR_INTERNAL_ERROR, "%s", - _("could not delete snapshot")); - goto cleanup; - } - - ret = 0; - - cleanup: - VBOX_RELEASE(progress); - vboxIIDUnalloc(&iid); - return ret; -} - -static int -vboxDomainSnapshotDeleteTree(vboxGlobalData *data, - IConsole *console, - ISnapshot *snapshot) -{ - vboxArray children = VBOX_ARRAY_INITIALIZER; - int ret = -1; - nsresult rc; - size_t i; - - rc = vboxArrayGet(&children, snapshot, snapshot->vtbl->GetChildren); - if (NS_FAILED(rc)) { - virReportError(VIR_ERR_INTERNAL_ERROR, "%s", - _("could not get children snapshots")); - goto cleanup; - } - - for (i = 0; i < children.count; i++) { - if (vboxDomainSnapshotDeleteTree(data, console, children.items[i])) - goto cleanup; - } - - ret = vboxDomainSnapshotDeleteSingle(data, console, snapshot); - - cleanup: - vboxArrayRelease(&children); - return ret; -} - -#if VBOX_API_VERSION >= 4002000 -static int -vboxDomainSnapshotDeleteMetadataOnly(virDomainSnapshotPtr snapshot) -{ - /* - * This function will remove the node in the vbox xml corresponding to the snapshot. - * It is usually called by vboxDomainSnapshotDelete() with the flag - * VIR_DOMAIN_SNAPSHOT_DELETE_METADATA_ONLY. - * If you want to use it anywhere else, be careful, if the snapshot you want to delete - * has children, the result is not granted, they will probably will be deleted in the - * xml, but you may have a problem with hard drives. - * - * If the snapshot which is being deleted is the current one, we will set the current - * snapshot of the machine to the parent of this snapshot. Before writing the modified - * xml file, we undefine the machine from vbox. After writing the file, we redefine - * the machine with the new file. - */ - - virDomainPtr dom = snapshot->domain; - VBOX_OBJECT_CHECK(dom->conn, int, -1); - virDomainSnapshotDefPtr def = NULL; - char *defXml = NULL; - vboxIID domiid = VBOX_IID_INITIALIZER; - nsresult rc; - IMachine *machine = NULL; - PRUnichar *settingsFilePathUtf16 = NULL; - char *settingsFilepath = NULL; - virVBoxSnapshotConfMachinePtr snapshotMachineDesc = NULL; - int isCurrent = -1; - int it = 0; - PRUnichar *machineNameUtf16 = NULL; - char *machineName = NULL; - char *nameTmpUse = NULL; - char *machineLocationPath = NULL; - PRUint32 aMediaSize = 0; - IMedium **aMedia = NULL; - - defXml = vboxDomainSnapshotGetXMLDesc(snapshot, 0); - if (!defXml) { - virReportError(VIR_ERR_INTERNAL_ERROR, "%s", - _("Unable to get XML Desc of snapshot")); - goto cleanup; - } - def = virDomainSnapshotDefParseString(defXml, - data->caps, - data->xmlopt, - -1, - VIR_DOMAIN_SNAPSHOT_PARSE_DISKS | - VIR_DOMAIN_SNAPSHOT_PARSE_REDEFINE); - if (!def) { - virReportError(VIR_ERR_INTERNAL_ERROR, "%s", - _("Unable to get a virDomainSnapshotDefPtr")); - goto cleanup; - } - - 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; - } - rc = machine->vtbl->GetSettingsFilePath(machine, &settingsFilePathUtf16); - if (NS_FAILED(rc)) { - virReportError(VIR_ERR_INTERNAL_ERROR, "%s", - _("cannot get settings file path")); - goto cleanup; - } - VBOX_UTF16_TO_UTF8(settingsFilePathUtf16, &settingsFilepath); - - /*Getting the machine name to retrieve the machine location path.*/ - rc = machine->vtbl->GetName(machine, &machineNameUtf16); - if (NS_FAILED(rc)) { - virReportError(VIR_ERR_INTERNAL_ERROR, "%s", - _("cannot get machine name")); - goto cleanup; - } - VBOX_UTF16_TO_UTF8(machineNameUtf16, &machineName); - if (virAsprintf(&nameTmpUse, "%s.vbox", machineName) < 0) - goto cleanup; - machineLocationPath = virStringReplace(settingsFilepath, nameTmpUse, ""); - if (machineLocationPath == NULL) { - virReportError(VIR_ERR_INTERNAL_ERROR, "%s", - _("Unable to get the machine location path")); - goto cleanup; - } - snapshotMachineDesc = virVBoxSnapshotConfLoadVboxFile(settingsFilepath, machineLocationPath); - if (!snapshotMachineDesc) { - virReportError(VIR_ERR_INTERNAL_ERROR, "%s", - _("cannot create a vboxSnapshotXmlPtr")); - goto cleanup; - } - - isCurrent = virVBoxSnapshotConfIsCurrentSnapshot(snapshotMachineDesc, def->name); - if (isCurrent < 0) { - virReportError(VIR_ERR_INTERNAL_ERROR, "%s", - _("Unable to know if the snapshot is the current snapshot")); - goto cleanup; - } - if (isCurrent) { - /* - * If the snapshot is the current snapshot, it means that the machine has read-write - * disks. The first thing to do is to manipulate VirtualBox API to create - * differential read-write disks if the parent snapshot is not null. - */ - if (def->parent != NULL) { - for (it = 0; it < def->dom->ndisks; it++) { - virVBoxSnapshotConfHardDiskPtr readOnly = NULL; - IMedium *medium = NULL; - PRUnichar *locationUtf16 = NULL; - PRUnichar *parentUuidUtf16 = NULL; - char *parentUuid = NULL; - IMedium *newMedium = NULL; - PRUnichar *formatUtf16 = NULL; - PRUnichar *newLocation = NULL; - char *newLocationUtf8 = NULL; - IProgress *progress = NULL; - PRInt32 resultCode = -1; - virVBoxSnapshotConfHardDiskPtr disk = NULL; - PRUnichar *uuidUtf16 = NULL; - char *uuid = NULL; - char *format = NULL; - char **searchResultTab = NULL; - ssize_t resultSize = 0; - char *tmp = NULL; - - readOnly = virVBoxSnapshotConfHardDiskPtrByLocation(snapshotMachineDesc, - def->dom->disks[it]->src->path); - if (!readOnly) { - virReportError(VIR_ERR_INTERNAL_ERROR, "%s", - _("Cannot get hard disk by location")); - goto cleanup; - } - if (readOnly->parent == NULL) { - virReportError(VIR_ERR_INTERNAL_ERROR, "%s", - _("The read only disk has no parent")); - goto cleanup; - } - - VBOX_UTF8_TO_UTF16(readOnly->parent->location, &locationUtf16); - rc = data->vboxObj->vtbl->OpenMedium(data->vboxObj, - locationUtf16, - DeviceType_HardDisk, - AccessMode_ReadWrite, - false, - &medium); - if (NS_FAILED(rc)) { - virReportError(VIR_ERR_INTERNAL_ERROR, - _("Unable to open HardDisk, rc=%08x"), - (unsigned)rc); - goto cleanup; - } - - rc = medium->vtbl->GetId(medium, &parentUuidUtf16); - if (NS_FAILED(rc)) { - virReportError(VIR_ERR_INTERNAL_ERROR, - _("Unable to get hardDisk Id, rc=%08x"), - (unsigned)rc); - goto cleanup; - } - VBOX_UTF16_TO_UTF8(parentUuidUtf16, &parentUuid); - VBOX_UTF16_FREE(parentUuidUtf16); - VBOX_UTF16_FREE(locationUtf16); - VBOX_UTF8_TO_UTF16("VDI", &formatUtf16); - - if (virAsprintf(&newLocationUtf8, "%sfakedisk-%s-%d.vdi", - machineLocationPath, def->parent, it) < 0) - goto cleanup; - VBOX_UTF8_TO_UTF16(newLocationUtf8, &newLocation); - rc = data->vboxObj->vtbl->CreateHardDisk(data->vboxObj, - formatUtf16, - newLocation, - &newMedium); - if (NS_FAILED(rc)) { - virReportError(VIR_ERR_INTERNAL_ERROR, - _("Unable to create HardDisk, rc=%08x"), - (unsigned)rc); - goto cleanup; - } - VBOX_UTF16_FREE(formatUtf16); - VBOX_UTF16_FREE(newLocation); - -# if VBOX_API_VERSION < 4003000 - medium->vtbl->CreateDiffStorage(medium, newMedium, MediumVariant_Diff, &progress); -# else - PRUint32 tab[1]; - tab[0] = MediumVariant_Diff; - medium->vtbl->CreateDiffStorage(medium, newMedium, 1, tab, &progress); -# endif - - progress->vtbl->WaitForCompletion(progress, -1); - progress->vtbl->GetResultCode(progress, &resultCode); - if (NS_FAILED(resultCode)) { - virReportError(VIR_ERR_INTERNAL_ERROR, - _("Error while creating diff storage, rc=%08x"), - (unsigned)resultCode); - goto cleanup; - } - VBOX_RELEASE(progress); - /* - * The differential disk is created, we add it to the media registry and - * the machine storage controller. - */ - - if (VIR_ALLOC(disk) < 0) - goto cleanup; - - rc = newMedium->vtbl->GetId(newMedium, &uuidUtf16); - if (NS_FAILED(rc)) { - virReportError(VIR_ERR_INTERNAL_ERROR, - _("Unable to get medium uuid, rc=%08x"), - (unsigned)rc); - VIR_FREE(disk); - goto cleanup; - } - VBOX_UTF16_TO_UTF8(uuidUtf16, &uuid); - disk->uuid = uuid; - VBOX_UTF16_FREE(uuidUtf16); - - if (VIR_STRDUP(disk->location, newLocationUtf8) < 0) { - VIR_FREE(disk); - goto cleanup; - } - - rc = newMedium->vtbl->GetFormat(newMedium, &formatUtf16); - VBOX_UTF16_TO_UTF8(formatUtf16, &format); - disk->format = format; - VBOX_UTF16_FREE(formatUtf16); - - if (virVBoxSnapshotConfAddHardDiskToMediaRegistry(disk, - snapshotMachineDesc->mediaRegistry, - parentUuid) < 0) { - virReportError(VIR_ERR_INTERNAL_ERROR, "%s", - _("Unable to add hard disk to the media registry")); - goto cleanup; - } - /*Adding fake disks to the machine storage controllers*/ - - resultSize = virStringSearch(snapshotMachineDesc->storageController, - VBOX_UUID_REGEX, - it + 1, - &searchResultTab); - if (resultSize != it + 1) { - virReportError(VIR_ERR_INTERNAL_ERROR, - _("Unable to find UUID %s"), searchResultTab[it]); - goto cleanup; - } - - tmp = virStringReplace(snapshotMachineDesc->storageController, - searchResultTab[it], - disk->uuid); - virStringFreeList(searchResultTab); - VIR_FREE(snapshotMachineDesc->storageController); - if (!tmp) - goto cleanup; - if (VIR_STRDUP(snapshotMachineDesc->storageController, tmp) < 0) - goto cleanup; - - VIR_FREE(tmp); - /*Closing the "fake" disk*/ - rc = newMedium->vtbl->Close(newMedium); - if (NS_FAILED(rc)) { - virReportError(VIR_ERR_INTERNAL_ERROR, - _("Unable to close the new medium, rc=%08x"), - (unsigned)rc); - goto cleanup; - } - } - } else { - for (it = 0; it < def->dom->ndisks; it++) { - const char *uuidRO = NULL; - char **searchResultTab = NULL; - ssize_t resultSize = 0; - char *tmp = NULL; - uuidRO = virVBoxSnapshotConfHardDiskUuidByLocation(snapshotMachineDesc, - def->dom->disks[it]->src->path); - if (!uuidRO) { - virReportError(VIR_ERR_INTERNAL_ERROR, - _("No such disk in media registry %s"), - def->dom->disks[it]->src->path); - goto cleanup; - } - - resultSize = virStringSearch(snapshotMachineDesc->storageController, - VBOX_UUID_REGEX, - it + 1, - &searchResultTab); - if (resultSize != it + 1) { - virReportError(VIR_ERR_INTERNAL_ERROR, - _("Unable to find UUID %s"), - searchResultTab[it]); - goto cleanup; - } - - tmp = virStringReplace(snapshotMachineDesc->storageController, - searchResultTab[it], - uuidRO); - virStringFreeList(searchResultTab); - VIR_FREE(snapshotMachineDesc->storageController); - if (!tmp) - goto cleanup; - if (VIR_STRDUP(snapshotMachineDesc->storageController, tmp) < 0) - goto cleanup; - - VIR_FREE(tmp); - } - } - } - /*We remove the read write disks from the media registry*/ - for (it = 0; it < def->ndisks; it++) { - const char *uuidRW = - virVBoxSnapshotConfHardDiskUuidByLocation(snapshotMachineDesc, - def->disks[it].src->path); - if (!uuidRW) { - virReportError(VIR_ERR_INTERNAL_ERROR, - _("Unable to find UUID for location %s"), def->disks[it].src->path); - goto cleanup; - } - if (virVBoxSnapshotConfRemoveHardDisk(snapshotMachineDesc->mediaRegistry, uuidRW) < 0) { - virReportError(VIR_ERR_INTERNAL_ERROR, - _("Unable to remove disk from media registry. uuid = %s"), uuidRW); - goto cleanup; - } - } - /*If the parent snapshot is not NULL, we remove the-read only disks from the media registry*/ - if (def->parent != NULL) { - for (it = 0; it < def->dom->ndisks; it++) { - const char *uuidRO = - virVBoxSnapshotConfHardDiskUuidByLocation(snapshotMachineDesc, - def->dom->disks[it]->src->path); - if (!uuidRO) { - virReportError(VIR_ERR_INTERNAL_ERROR, - _("Unable to find UUID for location %s"), def->dom->disks[it]->src->path); - goto cleanup; - } - if (virVBoxSnapshotConfRemoveHardDisk(snapshotMachineDesc->mediaRegistry, uuidRO) < 0) { - virReportError(VIR_ERR_INTERNAL_ERROR, - _("Unable to remove disk from media registry. uuid = %s"), uuidRO); - goto cleanup; - } - } - } - rc = machine->vtbl->Unregister(machine, - CleanupMode_DetachAllReturnHardDisksOnly, - &aMediaSize, - &aMedia); - if (NS_FAILED(rc)) { - virReportError(VIR_ERR_INTERNAL_ERROR, - _("Unable to unregister machine, rc=%08x"), - (unsigned)rc); - goto cleanup; - } - VBOX_RELEASE(machine); - for (it = 0; it < aMediaSize; it++) { - IMedium *medium = aMedia[it]; - if (medium) { - PRUnichar *locationUtf16 = NULL; - char *locationUtf8 = NULL; - rc = medium->vtbl->GetLocation(medium, &locationUtf16); - VBOX_UTF16_TO_UTF8(locationUtf16, &locationUtf8); - if (isCurrent && strstr(locationUtf8, "fake") != NULL) { - /*we delete the fake disk because we don't need it anymore*/ - IProgress *progress = NULL; - PRInt32 resultCode = -1; - rc = medium->vtbl->DeleteStorage(medium, &progress); - if (NS_FAILED(rc)) { - virReportError(VIR_ERR_INTERNAL_ERROR, - _("Unable to delete medium, rc=%08x"), - (unsigned)rc); - goto cleanup; - } - progress->vtbl->WaitForCompletion(progress, -1); - progress->vtbl->GetResultCode(progress, &resultCode); - if (NS_FAILED(resultCode)) { - virReportError(VIR_ERR_INTERNAL_ERROR, - _("Error while closing medium, rc=%08x"), - (unsigned)resultCode); - goto cleanup; - } - VBOX_RELEASE(progress); - } else { - /* This a comment from vboxmanage code in the handleUnregisterVM - * function in VBoxManageMisc.cpp : - * Note that the IMachine::Unregister method will return the medium - * reference in a sane order, which means that closing will normally - * succeed, unless there is still another machine which uses the - * medium. No harm done if we ignore the error. */ - rc = medium->vtbl->Close(medium); - } - VBOX_UTF16_FREE(locationUtf16); - VBOX_UTF8_FREE(locationUtf8); - } - } - - /*removing the snapshot*/ - if (virVBoxSnapshotConfRemoveSnapshot(snapshotMachineDesc, def->name) < 0) { - virReportError(VIR_ERR_INTERNAL_ERROR, - _("Unable to remove snapshot %s"), def->name); - goto cleanup; - } - - if (isCurrent) { - VIR_FREE(snapshotMachineDesc->currentSnapshot); - if (def->parent != NULL) { - virVBoxSnapshotConfSnapshotPtr snap = virVBoxSnapshotConfSnapshotByName(snapshotMachineDesc->snapshot, def->parent); - if (!snap) { - virReportError(VIR_ERR_INTERNAL_ERROR, "%s", - _("Unable to get the snapshot to remove")); - goto cleanup; - } - if (VIR_STRDUP(snapshotMachineDesc->currentSnapshot, snap->uuid) < 0) - goto cleanup; - } - } - - /*Registering the machine*/ - if (virVBoxSnapshotConfSaveVboxFile(snapshotMachineDesc, settingsFilepath) < 0) { - virReportError(VIR_ERR_INTERNAL_ERROR, "%s", - _("Unable to serialize the machine description")); - goto cleanup; - } - rc = data->vboxObj->vtbl->OpenMachine(data->vboxObj, - settingsFilePathUtf16, - &machine); - if (NS_FAILED(rc)) { - virReportError(VIR_ERR_INTERNAL_ERROR, - _("Unable to open Machine, rc=%08x"), - (unsigned)rc); - goto cleanup; - } - - rc = data->vboxObj->vtbl->RegisterMachine(data->vboxObj, machine); - if (NS_FAILED(rc)) { - virReportError(VIR_ERR_INTERNAL_ERROR, - _("Unable to register Machine, rc=%08x"), - (unsigned)rc); - goto cleanup; - } - - ret = 0; - cleanup: - VIR_FREE(def); - VIR_FREE(defXml); - VBOX_RELEASE(machine); - VBOX_UTF16_FREE(settingsFilePathUtf16); - VBOX_UTF8_FREE(settingsFilepath); - VIR_FREE(snapshotMachineDesc); - VBOX_UTF16_FREE(machineNameUtf16); - VBOX_UTF8_FREE(machineName); - VIR_FREE(machineLocationPath); - VIR_FREE(nameTmpUse); - - return ret; -} -#endif - -static int -vboxDomainSnapshotDelete(virDomainSnapshotPtr snapshot, - unsigned int flags) -{ - virDomainPtr dom = snapshot->domain; - VBOX_OBJECT_CHECK(dom->conn, int, -1); - vboxIID domiid = VBOX_IID_INITIALIZER; - IMachine *machine = NULL; - ISnapshot *snap = NULL; - IConsole *console = NULL; - PRUint32 state; - nsresult rc; - vboxArray snapChildren = VBOX_ARRAY_INITIALIZER; - - virCheckFlags(VIR_DOMAIN_SNAPSHOT_DELETE_CHILDREN | - VIR_DOMAIN_SNAPSHOT_DELETE_METADATA_ONLY, -1); - - 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; - } - - snap = vboxDomainSnapshotGet(data, dom, machine, snapshot->name); - if (!snap) - goto cleanup; - - rc = machine->vtbl->GetState(machine, &state); - if (NS_FAILED(rc)) { - virReportError(VIR_ERR_INTERNAL_ERROR, "%s", - _("could not get domain state")); - goto cleanup; - } - - /* In case we just want to delete the metadata, we will edit the vbox file in order - *to remove the node concerning the snapshot - */ - if (flags & VIR_DOMAIN_SNAPSHOT_DELETE_METADATA_ONLY) { - rc = vboxArrayGet(&snapChildren, snap, snap->vtbl->GetChildren); - if (NS_FAILED(rc)) { - virReportError(VIR_ERR_INTERNAL_ERROR, "%s", - _("could not get snapshot children")); - goto cleanup; - } - if (snapChildren.count != 0) { - virReportError(VIR_ERR_INTERNAL_ERROR, "%s", - _("cannot delete metadata of a snapshot with children")); - goto cleanup; - } else { -#if VBOX_API_VERSION >= 4002000 - ret = vboxDomainSnapshotDeleteMetadataOnly(snapshot); -#endif - } - goto cleanup; - } - - if (state >= MachineState_FirstOnline - && state <= MachineState_LastOnline) { - virReportError(VIR_ERR_OPERATION_INVALID, "%s", - _("cannot delete snapshots of running domain")); - goto cleanup; - } - - rc = VBOX_SESSION_OPEN(domiid.value, machine); - if (NS_SUCCEEDED(rc)) - rc = data->vboxSession->vtbl->GetConsole(data->vboxSession, &console); - if (NS_FAILED(rc)) { - virReportError(VIR_ERR_INTERNAL_ERROR, - _("could not open VirtualBox session with domain %s"), - dom->name); - goto cleanup; - } - - if (flags & VIR_DOMAIN_SNAPSHOT_DELETE_CHILDREN) - ret = vboxDomainSnapshotDeleteTree(data, console, snap); - else - ret = vboxDomainSnapshotDeleteSingle(data, console, snap); - - cleanup: - VBOX_RELEASE(console); - VBOX_RELEASE(snap); - vboxIIDUnalloc(&domiid); - VBOX_SESSION_CLOSE(); - return ret; -} - #if VBOX_API_VERSION <= 2002000 || VBOX_API_VERSION >= 4000000 /* No Callback support for VirtualBox 2.2.* series */ /* No Callback support for VirtualBox 4.* series */ @@ -6231,6 +5464,16 @@ _consoleTakeSnapshot(IConsole *console, PRUnichar *name, return console->vtbl->TakeSnapshot(console, name, description, progress); } +static nsresult +_consoleDeleteSnapshot(IConsole *console, vboxIIDUnion *iidu, IProgress **progress) +{ +#if VBOX_API_VERSION < 3001000 + return console->vtbl->DiscardSnapshot(console, IID_MEMBER(value), progress); +#else /* VBOX_API_VERSION >= 3001000 */ + return console->vtbl->DeleteSnapshot(console, IID_MEMBER(value), progress); +#endif /* VBOX_API_VERSION >= 3001000 */ +} + static nsresult _progressWaitForCompletion(IProgress *progress, PRInt32 timeout) { @@ -7243,6 +6486,7 @@ static vboxUniformedIConsole _UIConsole = { .PowerDown = _consolePowerDown, .Reset = _consoleReset, .TakeSnapshot = _consoleTakeSnapshot, + .DeleteSnapshot = _consoleDeleteSnapshot, }; static vboxUniformedIProgress _UIProgress = { diff --git a/src/vbox/vbox_uniformed_api.h b/src/vbox/vbox_uniformed_api.h index 005b21b95d4d4181f6c151cc68384e7ffec10709..2800b6039e099f7a0abe51ab82c750d1cef28fae 100644 --- a/src/vbox/vbox_uniformed_api.h +++ b/src/vbox/vbox_uniformed_api.h @@ -272,6 +272,7 @@ typedef struct { nsresult (*Reset)(IConsole *console); nsresult (*TakeSnapshot)(IConsole *console, PRUnichar *name, PRUnichar *description, IProgress **progress); + nsresult (*DeleteSnapshot)(IConsole *console, vboxIIDUnion *iidu, IProgress **progress); } vboxUniformedIConsole; /* Functions for IProgress */ @@ -596,6 +597,9 @@ int vboxDomainSnapshotHasMetadata(virDomainSnapshotPtr snapshot, unsigned int flags); int vboxDomainRevertToSnapshot(virDomainSnapshotPtr snapshot, unsigned int flags); +int vboxDomainSnapshotDelete(virDomainSnapshotPtr snapshot, + unsigned int flags); + /* Version specified functions for installing uniformed API */ void vbox22InstallUniformedAPI(vboxUniformedAPI *pVBoxAPI);