提交 4fab8d3f 编写于 作者: T Taowei 提交者: Michal Privoznik

vbox: Rewrite vboxDomainSnapshotDelete

上级 a9725126
......@@ -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;
}
......@@ -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;
......
......@@ -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 = {
......
......@@ -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);
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册