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", > -- libvir-list mailing list libvir-list@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/libvir-list