[libvirt] [PATCH v8 3/4] vbox_tmpl.c: Patch for redefining snapshots
John Ferlan
jferlan at redhat.com
Wed Jun 11 12:52:34 UTC 2014
Another coverity error as listed in-line below in vboxSnapshotRedefine()
John
On 05/19/2014 08:47 AM, Yohan BELLEGUIC wrote:
> The machine is unregistered and its vbox XML file is changed in order to
> add snapshot information. The machine is then registered with the
> snapshot to redefine.
> ---
> src/vbox/vbox_tmpl.c | 976 +++++++++++++++++++++++++++++++++++++++++++++++++-
> 1 file changed, 970 insertions(+), 6 deletions(-)
>
> diff --git a/src/vbox/vbox_tmpl.c b/src/vbox/vbox_tmpl.c
> index 5d4a7ba..a7f15d4 100644
> --- a/src/vbox/vbox_tmpl.c
> +++ b/src/vbox/vbox_tmpl.c
> @@ -43,6 +43,7 @@
> #include "datatypes.h"
> #include "domain_conf.h"
> #include "snapshot_conf.h"
> +#include "vbox_snapshot_conf.h"
> #include "network_conf.h"
> #include "virerror.h"
> #include "domain_event.h"
> @@ -6015,6 +6016,958 @@ vboxDomainSnapshotGet(vboxGlobalData *data,
> return snapshot;
> }
>
> +#if VBOX_API_VERSION >= 4002000
> +static int vboxCloseDisksRecursively(virDomainPtr dom, char *location)
> +{
> + VBOX_OBJECT_CHECK(dom->conn, int, -1);
> + nsresult rc;
> + size_t i = 0;
> + PRUnichar *locationUtf = NULL;
> + IMedium *medium = NULL;
> + IMedium **children = NULL;
> + PRUint32 childrenSize = 0;
> + VBOX_UTF8_TO_UTF16(location, &locationUtf);
> + rc = data->vboxObj->vtbl->OpenMedium(data->vboxObj,
> + locationUtf,
> + 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->GetChildren(medium, &childrenSize, &children);
> + if (NS_FAILED(rc)) {
> + virReportError(VIR_ERR_INTERNAL_ERROR, "%s"
> + , _("Unable to get disk children"));
> + goto cleanup;
> + }
> + for (i = 0; i < childrenSize; i++) {
> + IMedium *childMedium = children[i];
> + if (childMedium) {
> + PRUnichar *childLocationUtf = NULL;
> + char *childLocation = NULL;
> + rc = childMedium->vtbl->GetLocation(childMedium, &childLocationUtf);
> + VBOX_UTF16_TO_UTF8(childLocationUtf, &childLocation);
> + VBOX_UTF16_FREE(childLocationUtf);
> + if (vboxCloseDisksRecursively(dom, childLocation) < 0) {
> + virReportError(VIR_ERR_INTERNAL_ERROR, "%s"
> + , _("Unable to close disk children"));
> + goto cleanup;
> + }
> + VIR_FREE(childLocation);
> + }
> + }
> + rc = medium->vtbl->Close(medium);
> + if (NS_FAILED(rc)) {
> + virReportError(VIR_ERR_INTERNAL_ERROR,
> + _("Unable to close HardDisk, rc=%08x"),
> + (unsigned)rc);
> + goto cleanup;
> + }
> +
> + ret = 0;
> + cleanup:
> + VBOX_UTF16_FREE(locationUtf);
> + return ret;
> +}
> +
> +static int
> +vboxSnapshotRedefine(virDomainPtr dom,
> + virDomainSnapshotDefPtr def,
> + bool isCurrent)
> +{
> + /*
> + * If your snapshot has a parent,
> + * it will only be redefined if you have already
> + * redefined the parent.
> + *
> + * The general algorithm of this function is below :
> + * First of all, we are going to create our vboxSnapshotXmlMachinePtr struct from
> + * the machine settings path.
> + * Then, if the machine current snapshot xml file is saved in the machine location,
> + * it means that this snapshot was previously modified by us and has fake disks.
> + * Fake disks are added when the flag VIR_DOMAIN_SNAPSHOT_CREATE_CURRENT was not set
> + * yet, in order to not corrupt read-only disks. The first thing to do is to remove those
> + * disks and restore the read-write disks, if any, in the vboxSnapshotXmlMachinePtr struct.
> + * We also delete the current snapshot xml file.
> + *
> + * After that, we are going to register the snapshot read-only disks that we want to redefine,
> + * if they are not in the media registry struct.
> + *
> + * The next step is to unregister the machine and close all disks.
> + *
> + * Then, we check if the flag VIR_DOMAIN_SNAPSHOT_CREATE_REDEFINE has already been set.
> + * If this flag was set, we just add read-write disks to the media registry
> + * struct. Otherwise, we save the snapshot xml file into the machine location in order
> + * to recover the read-write disks during the next redefine and we create differential disks
> + * from the snapshot read-only disks and add them to the media registry struct.
> + *
> + * Finally, we register the machine with the new virtualbox description file.
> + */
> + VBOX_OBJECT_CHECK(dom->conn, int, -1);
> + vboxIID domiid = VBOX_IID_INITIALIZER;
> + IMachine *machine = NULL;
> + nsresult rc;
> + PRUnichar *settingsFilePath = NULL;
> + char *settingsFilePath_Utf8 = NULL;
> + virVBoxSnapshotConfMachinePtr snapshotMachineDesc = NULL;
> + char *currentSnapshotXmlFilePath = NULL;
> + PRUnichar *machineNameUtf16 = NULL;
> + char *machineName = NULL;
> + char **realReadWriteDisksPath = NULL;
> + int realReadWriteDisksPathSize = 0;
> + char **realReadOnlyDisksPath = NULL;
> + int realReadOnlyDisksPathSize = 0;
> + virVBoxSnapshotConfSnapshotPtr newSnapshotPtr = NULL;
> + unsigned char snapshotUuid[VIR_UUID_BUFLEN];
> + int it = 0;
> + int jt = 0;
> + PRUint32 aMediaSize = 0;
> + IMedium **aMedia = NULL;
> + char *machineLocationPath = NULL;
> + char *nameTmpUse = NULL;
> + bool snapshotFileExists = false;
> + bool needToChangeStorageController = false;
> +
> + 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->SaveSettings(machine);
> + /*It may failed when the machine is not mutable.*/
> + rc = machine->vtbl->GetSettingsFilePath(machine, &settingsFilePath);
> + if (NS_FAILED(rc)) {
> + virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
> + _("cannot get settings file path"));
> + goto cleanup;
> + }
> + VBOX_UTF16_TO_UTF8(settingsFilePath, &settingsFilePath_Utf8);
> +
> + /*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_Utf8, nameTmpUse, "");
> + if (machineLocationPath == NULL) {
> + virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
> + _("Unable to get the machine location path"));
> + goto cleanup;
> + }
> +
> + /*We create the xml struct with the settings file path.*/
> + snapshotMachineDesc = virVBoxSnapshotConfLoadVboxFile(settingsFilePath_Utf8, machineLocationPath);
> + if (snapshotMachineDesc == NULL) {
> + virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
> + _("cannot create a vboxSnapshotXmlPtr"));
> + goto cleanup;
> + }
> + if (snapshotMachineDesc->currentSnapshot != NULL) {
> + if (virAsprintf(¤tSnapshotXmlFilePath, "%s%s.xml", machineLocationPath,
> + snapshotMachineDesc->currentSnapshot) < 0)
> + goto cleanup;
> + snapshotFileExists = virFileExists(currentSnapshotXmlFilePath);
> + }
> +
> + if (snapshotFileExists) {
> + /*
> + * We have created fake disks, so we have to remove them and replace them with
> + * the read-write disks if there are any. The fake disks will be closed during
> + * the machine unregistration.
> + */
> + if (virVBoxSnapshotConfRemoveFakeDisks(snapshotMachineDesc) < 0) {
> + virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
> + _("Unable to remove Fake Disks"));
> + goto cleanup;
> + }
> + realReadWriteDisksPathSize = virVBoxSnapshotConfGetRWDisksPathsFromLibvirtXML(currentSnapshotXmlFilePath,
> + &realReadWriteDisksPath);
> + realReadOnlyDisksPathSize = virVBoxSnapshotConfGetRODisksPathsFromLibvirtXML(currentSnapshotXmlFilePath,
> + &realReadOnlyDisksPath);
> + /*The read-only disk number is necessarily greater or equal to the
> + *read-write disk number*/
> + if (realReadOnlyDisksPathSize < realReadWriteDisksPathSize) {
> + virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
> + _("The read only disk number must be greater or equal to the "
> + " read write disk number"));
> + goto cleanup;
> + }
> + for (it = 0; it < realReadWriteDisksPathSize; it++) {
> + virVBoxSnapshotConfHardDiskPtr readWriteDisk = NULL;
> + PRUnichar *locationUtf = NULL;
> + IMedium *readWriteMedium = NULL;
> + PRUnichar *uuidUtf = NULL;
> + char *uuid = NULL;
> + PRUnichar *formatUtf = NULL;
> + char *format = NULL;
> + char *parentUuid = NULL;
> +
> + VBOX_UTF8_TO_UTF16(realReadWriteDisksPath[it], &locationUtf);
> + rc = data->vboxObj->vtbl->OpenMedium(data->vboxObj,
> + locationUtf,
> + DeviceType_HardDisk,
> + AccessMode_ReadWrite,
> + false,
> + &readWriteMedium);
> + if (NS_FAILED(rc)) {
> + virReportError(VIR_ERR_INTERNAL_ERROR,
> + _("Unable to open HardDisk, rc=%08x"),
> + (unsigned)rc);
> + VBOX_UTF16_FREE(locationUtf);
> + goto cleanup;
> + }
> + VBOX_UTF16_FREE(locationUtf);
> +
> + rc = readWriteMedium->vtbl->GetId(readWriteMedium, &uuidUtf);
> + if (NS_FAILED(rc)) {
> + virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
> + _("Unable to get the read write medium id"));
> + goto cleanup;
> + }
> + VBOX_UTF16_TO_UTF8(uuidUtf, &uuid);
> + VBOX_UTF16_FREE(uuidUtf);
> +
> + rc = readWriteMedium->vtbl->GetFormat(readWriteMedium, &formatUtf);
> + if (NS_FAILED(rc)) {
> + virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
> + _("Unable to get the read write medium format"));
> + VIR_FREE(uuid);
> + goto cleanup;
> + }
> + VBOX_UTF16_TO_UTF8(formatUtf, &format);
> + VBOX_UTF16_FREE(formatUtf);
> +
> + if (VIR_ALLOC(readWriteDisk) < 0) {
> + VIR_FREE(uuid);
> + VIR_FREE(formatUtf);
> + goto cleanup;
> + }
> +
> + readWriteDisk->format = format;
> + readWriteDisk->uuid = uuid;
> + readWriteDisk->location = realReadWriteDisksPath[it];
> + /*
> + * We get the current snapshot's read-only disk uuid in order to add the
> + * read-write disk to the media registry as it's child. The read-only disk
> + * is already in the media registry because it is the fake disk's parent.
> + */
> + parentUuid = virVBoxSnapshotConfHardDiskUuidByLocation(snapshotMachineDesc,
> + realReadOnlyDisksPath[it]);
(35) Event returned_null: "virVBoxSnapshotConfHardDiskUuidByLocation"
returns null (checked 4 out of 5 times). [details]
(44) Event var_assigned: Assigning: "parentUuid" = null return value
from "virVBoxSnapshotConfHardDiskUuidByLocation".
Looks like a
if (parentUuid == NULL) {
VIR_FREE(readWriteDisk);
goto cleanup;
}
Will resolve this.
> + if (virVBoxSnapshotConfAddHardDiskToMediaRegistry(readWriteDisk,
> + snapshotMachineDesc->mediaRegistry,
> + parentUuid) < 0) {
(45) Event dereference: Dereferencing a pointer that might be null
"parentUuid" when calling
"virVBoxSnapshotConfAddHardDiskToMediaRegistry". [details]
> + virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
> + _("Unable to add hard disk to media Registry"));
> + VIR_FREE(readWriteDisk);
> + goto cleanup;
> + }
> + rc = readWriteMedium->vtbl->Close(readWriteMedium);
> + if (NS_FAILED(rc)) {
> + virReportError(VIR_ERR_INTERNAL_ERROR,
> + _("Unable to close HardDisk, rc=%08x"),
> + (unsigned)rc);
> + goto cleanup;
> + }
> + }
> + /*
> + * Now we have done this swap, we remove the snapshot xml file from the
> + * current machine location.
> + */
> + if (unlink(currentSnapshotXmlFilePath) < 0) {
> + virReportSystemError(errno,
> + _("Unable to delete file %s"), currentSnapshotXmlFilePath);
> + goto cleanup;
> + }
> + }
> + /*
> + * Before unregistering the machine, while all disks are still open, ensure that all
> + * read-only disks are in the redefined snapshot's media registry (the disks need to
> + * be open to query their uuid).
> + */
> + for (it = 0; it < def->dom->ndisks; it++) {
> + int diskInMediaRegistry = 0;
> + IMedium *readOnlyMedium = NULL;
> + PRUnichar *locationUtf = NULL;
> + PRUnichar *uuidUtf = NULL;
> + char *uuid = NULL;
> + PRUnichar *formatUtf = NULL;
> + char *format = NULL;
> + PRUnichar *parentUuidUtf = NULL;
> + char *parentUuid = NULL;
> + virVBoxSnapshotConfHardDiskPtr readOnlyDisk = NULL;
> +
> + diskInMediaRegistry = virVBoxSnapshotConfDiskIsInMediaRegistry(snapshotMachineDesc,
> + def->dom->disks[it]->src.path);
> + if (diskInMediaRegistry == -1) {
> + virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
> + _("Unable to know if disk is in media registry"));
> + goto cleanup;
> + }
> + if (diskInMediaRegistry == 1) /*Nothing to do.*/
> + continue;
> + /*The read only disk is not in the media registry*/
> +
> + VBOX_UTF8_TO_UTF16(def->dom->disks[it]->src.path, &locationUtf);
> + rc = data->vboxObj->vtbl->OpenMedium(data->vboxObj,
> + locationUtf,
> + DeviceType_HardDisk,
> + AccessMode_ReadWrite,
> + false,
> + &readOnlyMedium);
> + if (NS_FAILED(rc)) {
> + virReportError(VIR_ERR_INTERNAL_ERROR,
> + _("Unable to open HardDisk, rc=%08x"),
> + (unsigned)rc);
> + VBOX_UTF16_FREE(locationUtf);
> + goto cleanup;
> + }
> + VBOX_UTF16_FREE(locationUtf);
> +
> + rc = readOnlyMedium->vtbl->GetId(readOnlyMedium, &uuidUtf);
> + if (NS_FAILED(rc)) {
> + virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
> + _("Unable to get hard disk id"));
> + goto cleanup;
> + }
> + VBOX_UTF16_TO_UTF8(uuidUtf, &uuid);
> + VBOX_UTF16_FREE(uuidUtf);
> +
> + rc = readOnlyMedium->vtbl->GetFormat(readOnlyMedium, &formatUtf);
> + if (NS_FAILED(rc)) {
> + virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
> + _("Unable to get hard disk format"));
> + VIR_FREE(uuid);
> + goto cleanup;
> + }
> + VBOX_UTF16_TO_UTF8(formatUtf, &format);
> + VBOX_UTF16_FREE(formatUtf);
> +
> + /*This disk is already in the media registry*/
> + IMedium *parentReadOnlyMedium = NULL;
> + rc = readOnlyMedium->vtbl->GetParent(readOnlyMedium, &parentReadOnlyMedium);
> + if (NS_FAILED(rc)) {
> + virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
> + _("Unable to get parent hard disk"));
> + VIR_FREE(uuid);
> + goto cleanup;
> + }
> +
> + rc = parentReadOnlyMedium->vtbl->GetId(parentReadOnlyMedium, &parentUuidUtf);
> + if (NS_FAILED(rc)) {
> + virReportError(VIR_ERR_INTERNAL_ERROR,
> + _("Unable to get hard disk id, rc=%08x"),
> + (unsigned)rc);
> + VIR_FREE(uuid);
> + goto cleanup;
> + }
> + VBOX_UTF16_TO_UTF8(parentUuidUtf, &parentUuid);
> + VBOX_UTF16_FREE(parentUuidUtf);
> +
> + rc = readOnlyMedium->vtbl->Close(readOnlyMedium);
> + if (NS_FAILED(rc)) {
> + virReportError(VIR_ERR_INTERNAL_ERROR,
> + _("Unable to close HardDisk, rc=%08x"),
> + (unsigned)rc);
> + VIR_FREE(uuid);
> + VIR_FREE(parentUuid);
> + goto cleanup;
> + }
> +
> + if (VIR_ALLOC(readOnlyDisk) < 0) {
> + VIR_FREE(uuid);
> + VIR_FREE(parentUuid);
> + goto cleanup;
> + }
> +
> + readOnlyDisk->format = format;
> + readOnlyDisk->uuid = uuid;
> + if (VIR_STRDUP(readOnlyDisk->location, def->dom->disks[it]->src.path) < 0) {
> + VIR_FREE(readOnlyDisk);
> + goto cleanup;
> + }
> +
> + if (virVBoxSnapshotConfAddHardDiskToMediaRegistry(readOnlyDisk, snapshotMachineDesc->mediaRegistry,
> + parentUuid) < 0) {
> + virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
> + _("Unable to add hard disk to media registry"));
> + VIR_FREE(readOnlyDisk);
> + goto cleanup;
> + }
> + }
> +
> + /*Now, we can unregister the machine*/
> + 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);
> +
> + /*
> + * Unregister the machine, and then close all disks returned by the unregister method.
> + * Some close operations will fail because some disks that need to be closed will not
> + * be returned by virtualbox. We will close them just after. We have to use this
> + * solution because it is the only way to delete fake disks.
> + */
> + for (it = 0; it < aMediaSize; it++) {
> + IMedium *medium = aMedia[it];
> + if (medium) {
> + PRUnichar *locationUtf16 = NULL;
> + char *locationUtf8 = NULL;
> + rc = medium->vtbl->GetLocation(medium, &locationUtf16);
> + if (NS_FAILED(rc)) {
> + virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
> + _("Unable to get medium location"));
> + goto cleanup;
> + }
> + VBOX_UTF16_TO_UTF8(locationUtf16, &locationUtf8);
> + VBOX_UTF16_FREE(locationUtf16);
> + if (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);
> + VIR_FREE(locationUtf8);
> + 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);
> + VIR_FREE(locationUtf8);
> + 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_UTF8_FREE(locationUtf8);
> + }
> + }
> + /*Close all disks that failed to close normally.*/
> + for (it = 0; it < snapshotMachineDesc->mediaRegistry->ndisks; it++) {
> + if (vboxCloseDisksRecursively(dom, snapshotMachineDesc->mediaRegistry->disks[it]->location) < 0) {
> + virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
> + _("Unable to close recursively all disks"));
> + goto cleanup;
> + }
> + }
> + /*Here, all disks are closed or deleted*/
> +
> + /*We are now going to create and fill the Snapshot xml struct*/
> + if (VIR_ALLOC(newSnapshotPtr) < 0)
> + goto cleanup;
> +
> + if (virUUIDGenerate(snapshotUuid) < 0)
> + goto cleanup;
> +
> + char uuidtmp[VIR_UUID_STRING_BUFLEN];
> + virUUIDFormat(snapshotUuid, uuidtmp);
> + if (VIR_STRDUP(newSnapshotPtr->uuid, uuidtmp) < 0)
> + goto cleanup;
> +
> + VIR_DEBUG("New snapshot UUID: %s", newSnapshotPtr->uuid);
> + if (VIR_STRDUP(newSnapshotPtr->name, def->name) < 0)
> + goto cleanup;
> +
> + newSnapshotPtr->timeStamp = virTimeStringThen(def->creationTime * 1000);
> +
> + if (VIR_STRDUP(newSnapshotPtr->description, def->description) < 0)
> + goto cleanup;
> +
> + if (VIR_STRDUP(newSnapshotPtr->hardware, snapshotMachineDesc->hardware) < 0)
> + goto cleanup;
> +
> + if (VIR_STRDUP(newSnapshotPtr->storageController, snapshotMachineDesc->storageController) < 0)
> + goto cleanup;
> +
> + /*We get the parent disk uuid from the parent disk location to correctly fill the storage controller.*/
> + for (it = 0; it < def->dom->ndisks; it++) {
> + char *location = NULL;
> + char *uuidReplacing = NULL;
> + char **searchResultTab = NULL;
> + ssize_t resultSize = 0;
> + char *tmp = NULL;
> +
> + location = def->dom->disks[it]->src.path;
> + if (!location)
> + goto cleanup;
> + /*Replacing the uuid*/
> + uuidReplacing = virVBoxSnapshotConfHardDiskUuidByLocation(snapshotMachineDesc, location);
> + if (uuidReplacing == NULL)
> + goto cleanup;
> +
> + resultSize = virStringSearch(newSnapshotPtr->storageController,
> + VBOX_UUID_REGEX,
> + it + 1,
> + &searchResultTab);
> + if (resultSize != it + 1)
> + goto cleanup;
> +
> + tmp = virStringReplace(newSnapshotPtr->storageController,
> + searchResultTab[it],
> + uuidReplacing);
> + virStringFreeList(searchResultTab);
> + VIR_FREE(newSnapshotPtr->storageController);
> + if (!tmp)
> + goto cleanup;
> + if (VIR_STRDUP(newSnapshotPtr->storageController, tmp) < 0)
> + goto cleanup;
> +
> + VIR_FREE(tmp);
> + }
> + if (virVBoxSnapshotConfAddSnapshotToXmlMachine(newSnapshotPtr, snapshotMachineDesc, def->parent) < 0) {
> + virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
> + _("Unable to add the snapshot to the machine description"));
> + goto cleanup;
> + }
> + /*
> + * We change the current snapshot only if there is no current snapshot or if the
> + * snapshotFile exists, otherwise, it means that the correct current snapshot is
> + * already set.
> + */
> +
> + if (snapshotMachineDesc->currentSnapshot == NULL || snapshotFileExists) {
> + snapshotMachineDesc->currentSnapshot = newSnapshotPtr->uuid;
> + needToChangeStorageController = true;
> + }
> +
> + /*
> + * Open the snapshot's read-write disk's full ancestry to allow opening the
> + * read-write disk itself.
> + */
> + for (it = 0; it < def->dom->ndisks; it++) {
> + char *location = NULL;
> + virVBoxSnapshotConfHardDiskPtr *hardDiskToOpen = NULL;
> + size_t hardDiskToOpenSize = 0;
> +
> + location = def->dom->disks[it]->src.path;
> + if (!location)
> + goto cleanup;
> +
> + hardDiskToOpenSize = virVBoxSnapshotConfDiskListToOpen(snapshotMachineDesc,
> + &hardDiskToOpen, location);
> + for (jt = hardDiskToOpenSize -1; jt >= 0; jt--) {
> + IMedium *medium = NULL;
> + PRUnichar *locationUtf16 = NULL;
> + VBOX_UTF8_TO_UTF16(hardDiskToOpen[jt]->location, &locationUtf16);
> +
> + rc = data->vboxObj->vtbl->OpenMedium(data->vboxObj,
> + locationUtf16,
> + DeviceType_HardDisk,
> + AccessMode_ReadWrite,
> + false,
> + &medium);
> + VBOX_UTF16_FREE(locationUtf16);
> + if (NS_FAILED(rc)) {
> + virReportError(VIR_ERR_INTERNAL_ERROR,
> + _("Unable to open HardDisk, rc=%08x"),
> + (unsigned)rc);
> + goto cleanup;
> + }
> + }
> + }
> + if (isCurrent || !needToChangeStorageController) {
> + /* We don't create a differential hard disk because either the current snapshot
> + * has already been defined or the snapshot to redefine is the current snapshot.
> + * If the snapshot to redefine is the current snapshot, we add read-write disks in
> + * the machine storage controllers.
> + */
> + for (it = 0; it < def->ndisks; it++) {
> + IMedium *medium = NULL;
> + PRUnichar *locationUtf16 = NULL;
> + virVBoxSnapshotConfHardDiskPtr disk = NULL;
> + PRUnichar *formatUtf16 = NULL;
> + char *format = NULL;
> + PRUnichar *uuidUtf16 = NULL;
> + char *uuid = NULL;
> + IMedium *parentDisk = NULL;
> + PRUnichar *parentUuidUtf16 = NULL;
> + char *parentUuid = NULL;
> +
> + VBOX_UTF8_TO_UTF16(def->disks[it].src.path, &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;
> + }
> + VBOX_UTF16_FREE(locationUtf16);
> +
> + if (VIR_ALLOC(disk) < 0)
> + goto cleanup;
> +
> + rc = medium->vtbl->GetFormat(medium, &formatUtf16);
> + if (NS_FAILED(rc)) {
> + virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
> + _("Unable to get disk format"));
> + VIR_FREE(disk);
> + goto cleanup;
> + }
> +
> + VBOX_UTF16_TO_UTF8(formatUtf16, &format);
> + disk->format = format;
> + VBOX_UTF16_FREE(formatUtf16);
> +
> + if (VIR_STRDUP(disk->location, def->disks[it].src.path) < 0) {
> + VIR_FREE(disk);
> + goto cleanup;
> + }
> +
> + rc = medium->vtbl->GetId(medium, &uuidUtf16);
> + if (NS_FAILED(rc)) {
> + virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
> + _("Unable to get disk uuid"));
> + VIR_FREE(disk);
> + goto cleanup;
> + }
> + VBOX_UTF16_TO_UTF8(uuidUtf16, &uuid);
> + disk->uuid = uuid;
> + VBOX_UTF16_FREE(uuidUtf16);
> +
> + rc = medium->vtbl->GetParent(medium, &parentDisk);
> + if (NS_FAILED(rc)) {
> + virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
> + _("Unable to get disk parent"));
> + VIR_FREE(disk);
> + goto cleanup;
> + }
> +
> + parentDisk->vtbl->GetId(parentDisk, &parentUuidUtf16);
> + VBOX_UTF16_TO_UTF8(parentUuidUtf16, &parentUuid);
> + VBOX_UTF16_FREE(parentUuidUtf16);
> + if (virVBoxSnapshotConfAddHardDiskToMediaRegistry(disk,
> + snapshotMachineDesc->mediaRegistry,
> + parentUuid) < 0) {
> + virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
> + _("Unable to add hard disk to the media registry"));
> + VIR_FREE(disk);
> + goto cleanup;
> + }
> +
> + if (needToChangeStorageController) {
> + /*We need to append this disk in the storage controller*/
> + char **searchResultTab = NULL;
> + ssize_t resultSize = 0;
> + char *tmp = NULL;
> + 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);
> + }
> + /*Close disk*/
> + rc = medium->vtbl->Close(medium);
> + if (NS_FAILED(rc)) {
> + virReportError(VIR_ERR_INTERNAL_ERROR,
> + _("Unable to close HardDisk, rc=%08x"),
> + (unsigned)rc);
> + goto cleanup;
> + }
> + }
> + } else {
> + /*Create a "fake" disk to avoid corrupting children snapshot disks.*/
> + for (it = 0; it < def->dom->ndisks; it++) {
> + IMedium *medium = NULL;
> + PRUnichar *locationUtf16 = NULL;
> + PRUnichar *parentUuidUtf16 = NULL;
> + char *parentUuid = NULL;
> + IMedium *newMedium = NULL;
> + PRUnichar *formatUtf16 = NULL;
> + PRUnichar *newLocation = NULL;
> + char *newLocationUtf8 = 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;
> +
> + VBOX_UTF8_TO_UTF16(def->dom->disks[it]->src.path, &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);
> + VBOX_UTF16_FREE(locationUtf16);
> + goto cleanup;
> + }
> + VBOX_UTF16_FREE(locationUtf16);
> +
> + 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_UTF8_TO_UTF16("VDI", &formatUtf16);
> +
> + if (virAsprintf(&newLocationUtf8, "%sfakedisk-%d.vdi", machineLocationPath, it) < 0)
> + goto cleanup;
> + VBOX_UTF8_TO_UTF16(newLocationUtf8, &newLocation);
> + rc = data->vboxObj->vtbl->CreateHardDisk(data->vboxObj,
> + formatUtf16,
> + newLocation,
> + &newMedium);
> + VBOX_UTF16_FREE(newLocation);
> + VBOX_UTF16_FREE(formatUtf16);
> + if (NS_FAILED(rc)) {
> + virReportError(VIR_ERR_INTERNAL_ERROR,
> + _("Unable to create HardDisk, rc=%08x"),
> + (unsigned)rc);
> + goto cleanup;
> + }
> +
> + IProgress *progress = NULL;
> +# 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 controllers.
> + */
> +
> + 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);
> + goto cleanup;
> + }
> + VBOX_UTF16_TO_UTF8(uuidUtf16, &uuid);
> + disk->uuid = uuid;
> + VBOX_UTF16_FREE(uuidUtf16);
> +
> + if (VIR_STRDUP(disk->location, newLocationUtf8) < 0)
> + 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 the fake disk 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;
> + }
> + }
> + /*
> + * We save the snapshot xml file to retrieve the real read-write disk during the
> + * next define. This file is saved as "'machineLocation'/snapshot-'uuid'.xml"
> + */
> + VIR_FREE(currentSnapshotXmlFilePath);
> + if (virAsprintf(¤tSnapshotXmlFilePath, "%s%s.xml", machineLocationPath, snapshotMachineDesc->currentSnapshot) < 0)
> + goto cleanup;
> + char *snapshotContent = virDomainSnapshotDefFormat(NULL, def, VIR_DOMAIN_XML_SECURE, 0);
> + if (snapshotContent == NULL) {
> + virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
> + _("Unable to get snapshot content"));
> + goto cleanup;
> + }
> + if (virFileWriteStr(currentSnapshotXmlFilePath, snapshotContent, 0644) < 0) {
> + virReportSystemError(errno, "%s",
> + _("Unable to save new snapshot xml file"));
> + goto cleanup;
> + }
> + VIR_FREE(snapshotContent);
> + }
> + /*
> + * All the snapshot structure manipulation is done, we close the disks we have
> + * previously opened.
> + */
> + for (it = 0; it < def->dom->ndisks; it++) {
> + char *location = def->dom->disks[it]->src.path;
> + if (!location)
> + goto cleanup;
> +
> + virVBoxSnapshotConfHardDiskPtr *hardDiskToOpen = NULL;
> + size_t hardDiskToOpenSize = virVBoxSnapshotConfDiskListToOpen(snapshotMachineDesc,
> + &hardDiskToOpen, location);
> + for (jt = 0; jt < hardDiskToOpenSize; jt++) {
> + IMedium *medium = NULL;
> + PRUnichar *locationUtf16 = NULL;
> + VBOX_UTF8_TO_UTF16(hardDiskToOpen[jt]->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->Close(medium);
> + if (NS_FAILED(rc)) {
> + virReportError(VIR_ERR_INTERNAL_ERROR,
> + _("Unable to close HardDisk, rc=%08x"),
> + (unsigned)rc);
> + goto cleanup;
> + }
> + VBOX_UTF16_FREE(locationUtf16);
> + }
> + }
> +
> + /*Now, we rewrite the 'machineName'.vbox file to redefine the machine.*/
> + if (virVBoxSnapshotConfSaveVboxFile(snapshotMachineDesc, settingsFilePath_Utf8) < 0) {
> + virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
> + _("Unable to serialize the machine description"));
> + goto cleanup;
> + }
> + rc = data->vboxObj->vtbl->OpenMachine(data->vboxObj,
> + settingsFilePath,
> + &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:
> + VBOX_RELEASE(machine);
> + VBOX_UTF16_FREE(settingsFilePath);
> + VBOX_UTF8_FREE(settingsFilePath_Utf8);
> + VIR_FREE(snapshotMachineDesc);
> + VIR_FREE(currentSnapshotXmlFilePath);
> + VBOX_UTF16_FREE(machineNameUtf16);
> + VBOX_UTF8_FREE(machineName);
> + virStringFreeList(realReadOnlyDisksPath);
> + virStringFreeList(realReadWriteDisksPath);
> + VIR_FREE(newSnapshotPtr);
> + VIR_FREE(machineLocationPath);
> + VIR_FREE(nameTmpUse);
> + return ret;
> +}
> +#endif
> +
> static virDomainSnapshotPtr
> vboxDomainSnapshotCreateXML(virDomainPtr dom,
> const char *xmlDesc,
> @@ -6036,9 +6989,15 @@ vboxDomainSnapshotCreateXML(virDomainPtr dom,
> #else
> PRInt32 result;
> #endif
> +#if VBOX_API_VERSION >= 4002000
> + bool isCurrent = false;
> +#endif
> +
>
> /* VBox has no snapshot metadata, so this flag is trivial. */
> - virCheckFlags(VIR_DOMAIN_SNAPSHOT_CREATE_NO_METADATA, NULL);
> + virCheckFlags(VIR_DOMAIN_SNAPSHOT_CREATE_NO_METADATA |
> + VIR_DOMAIN_SNAPSHOT_CREATE_REDEFINE |
> + VIR_DOMAIN_SNAPSHOT_CREATE_CURRENT, NULL);
>
> if (!(def = virDomainSnapshotDefParseString(xmlDesc, data->caps,
> data->xmlopt, -1,
> @@ -6046,11 +7005,6 @@ vboxDomainSnapshotCreateXML(virDomainPtr dom,
> VIR_DOMAIN_SNAPSHOT_PARSE_REDEFINE)))
> goto cleanup;
>
> - if (def->ndisks) {
> - virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
> - _("disk snapshots not supported yet"));
> - goto cleanup;
> - }
>
> vboxIIDFromUUID(&domiid, dom->uuid);
> rc = VBOX_OBJECT_GET_MACHINE(domiid.value, &machine);
> @@ -6060,6 +7014,16 @@ vboxDomainSnapshotCreateXML(virDomainPtr dom,
> goto cleanup;
> }
>
> +#if VBOX_API_VERSION >= 4002000
> + isCurrent = flags & VIR_DOMAIN_SNAPSHOT_CREATE_CURRENT;
> + if (flags & VIR_DOMAIN_SNAPSHOT_CREATE_REDEFINE) {
> + if (vboxSnapshotRedefine(dom, def, isCurrent) < 0)
> + goto cleanup;
> + ret = virGetDomainSnapshot(dom, def->name);
> + goto cleanup;
> + }
> +#endif
> +
> rc = machine->vtbl->GetState(machine, &state);
> if (NS_FAILED(rc)) {
> virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
>
More information about the libvir-list
mailing list