---
src/vbox/vbox_common.c | 609 ++++++++++++++++++++++++++++++++
src/vbox/vbox_common.h | 13 +
src/vbox/vbox_tmpl.c | 778 +----------------------------------------
src/vbox/vbox_uniformed_api.h | 4 +
4 files changed, 637 insertions(+), 767 deletions(-)
diff --git a/src/vbox/vbox_common.c b/src/vbox/vbox_common.c
index f5b07cf..505f1cd 100644
--- a/src/vbox/vbox_common.c
+++ b/src/vbox/vbox_common.c
@@ -6524,3 +6524,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 1c01fe8..15bf8e2 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 adba028..044e6d6 100644
--- a/src/vbox/vbox_tmpl.c
+++ b/src/vbox/vbox_tmpl.c
@@ -1382,146 +1382,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,
@@ -1629,633 +1489,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,
}
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)
{
return progress->vtbl->WaitForCompletion(progress, timeout);
@@ -7242,6 +6485,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 005b21b..2800b60 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);
--
1.7.9.5