[libvirt] [PATCHv5 4/5] vbox_tmpl.c: Patch for redefining snapshots

Manuel VIVES manuel.vives at diateam.net
Fri Jan 3 14:25:33 UTC 2014


The snapshots are saved in xml files, and then can be redefined
---
 src/vbox/vbox_tmpl.c | 1083 +++++++++++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 1075 insertions(+), 8 deletions(-)

diff --git a/src/vbox/vbox_tmpl.c b/src/vbox/vbox_tmpl.c
index 98724c1..a43a875 100644
--- a/src/vbox/vbox_tmpl.c
+++ b/src/vbox/vbox_tmpl.c
@@ -61,6 +61,7 @@
 #include "virstring.h"
 #include "virtime.h"
 #include "virutil.h"
+#include "dirname.h"
 
 /* This one changes from version to version. */
 #if VBOX_API_VERSION == 2002
@@ -276,9 +277,19 @@ static vboxGlobalData *g_pVBoxGlobalData = NULL;
 
 #endif /* VBOX_API_VERSION >= 4000 */
 
+/*This error is a bit specific
+ *In the VBOX API it is named E_ACCESSDENIED
+ *It is returned when the called object is not ready. In
+ *particular when we do any call on a disk which has been closed
+*/
+#define VBOX_E_ACCESSDENIED 0x80070005
 static virDomainPtr vboxDomainDefineXML(virConnectPtr conn, const char *xml);
 static int vboxDomainCreate(virDomainPtr dom);
 static int vboxDomainUndefineFlags(virDomainPtr dom, unsigned int flags);
+static virStorageVolPtr vboxStorageVolLookupByPath(virConnectPtr conn, const char *path);
+static int vboxStorageDeleteOrClose(virStorageVolPtr vol,
+                                    unsigned int flags,
+                                    unsigned int flagDeleteOrClose);
 
 static void vboxDriverLock(vboxGlobalData *data) {
     virMutexLock(&data->lock);
@@ -5951,6 +5962,1055 @@ cleanup:
     return snapshot;
 }
 
+#if VBOX_API_VERSION >=4002
+static void
+vboxSnapshotXmlRetrieveSnapshotNodeByName(xmlNodePtr a_node,
+                               const char *name,
+                               xmlNodePtr *snap_node)
+{
+    xmlNodePtr cur_node = NULL;
+    char *xmlName;
+    for (cur_node = a_node; cur_node; cur_node = cur_node->next) {
+        if (cur_node->type == XML_ELEMENT_NODE) {
+            if (!xmlStrcmp(cur_node->name, (const xmlChar *) "Snapshot")) {
+                if ((xmlName = virXMLPropString(cur_node, "name"))) {
+                    if (STREQ(xmlName, name)) {
+                        VIR_FREE(xmlName);
+                        *snap_node = cur_node;
+                        return;
+                    }
+                    VIR_FREE(xmlName);
+                }
+            }
+        }
+        if (cur_node->children)
+            vboxSnapshotXmlRetrieveSnapshotNodeByName(cur_node->children, name,
+                                                      snap_node);
+    }
+}
+
+static int
+vboxDetachAndCloseDisks(virDomainPtr dom,
+                        IMedium *disk)
+{
+    VBOX_OBJECT_CHECK(dom->conn, int, -1);
+    nsresult rc;
+    PRUnichar *location = NULL;
+    vboxArray childrenDiskArray = VBOX_ARRAY_INITIALIZER;
+    virStorageVolPtr volPtr = NULL;
+    char *location_utf8 = NULL;
+    PRUint32 dummyState = 0;
+    size_t i = 0;
+    if (disk == NULL) {
+        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+                       _("null pointer to disk"));
+        goto cleanup;
+    }
+    rc = disk->vtbl->GetLocation(disk, &location);
+    if (rc == VBOX_E_ACCESSDENIED) {
+        ret = 0;
+        VIR_DEBUG("Disk already closed");
+        goto cleanup;
+    }
+    if (NS_FAILED(rc)) {
+        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+                       _("cannot get disk location"));
+        goto cleanup;
+    }
+    rc = vboxArrayGet(&childrenDiskArray, disk, disk->vtbl->GetChildren);
+    if (NS_FAILED(rc)) {
+        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+                       _("cannot get children disks"));
+        goto cleanup;
+    }
+    for (i = 0; i < childrenDiskArray.count; ++i) {
+        IMedium *childDisk = childrenDiskArray.items[i];
+        if (childDisk) {
+            vboxDetachAndCloseDisks(dom, childDisk);
+        }
+    }
+    rc = disk->vtbl->RefreshState(disk, &dummyState);
+    if (NS_FAILED(rc)) {
+        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+                       _("cannot refresh state"));
+        goto cleanup;
+    }
+    VBOX_UTF16_TO_UTF8(location, &location_utf8);
+    volPtr = vboxStorageVolLookupByPath(dom->conn, location_utf8);
+
+    if (volPtr) {
+        VIR_DEBUG("Closing %s", location_utf8);
+        if (vboxStorageDeleteOrClose(volPtr, 0, VBOX_STORAGE_CLOSE_FLAG) < 0) {
+            virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+                           _("error while closing disk"));
+            goto cleanup;
+        }
+        ret = 0;
+    }
+cleanup:
+    VBOX_UTF8_FREE(location_utf8);
+    VBOX_UTF16_FREE(location);
+    vboxArrayRelease(&childrenDiskArray);
+    return ret;
+}
+
+static void
+vboxSnapshotXmlAddChild(xmlNodePtr parent,
+                xmlNodePtr child)
+{
+    /*Used in order to add child without writing the stuff concerning xml namespaces*/
+    xmlBufferPtr tmpBuf = xmlBufferCreate();
+    char *tmpString = NULL;
+    xmlNodePtr tmpNode = NULL;
+    xmlNodeDump(tmpBuf, parent->doc, child, 0, 0);
+    if (VIR_STRDUP(tmpString, (char *)xmlBufferContent(tmpBuf)) >= 0) {
+        xmlParseInNodeContext(parent, tmpString, (int)strlen(tmpString), 0, &tmpNode);
+        if (tmpNode) {
+            if (xmlAddChild(parent, xmlCopyNode(tmpNode, 1)) == NULL) {
+                VIR_DEBUG("Error while adding %s to %s",
+                          (char *)tmpNode->name,
+                          (char *)parent->name);
+            }
+        }
+    }
+    xmlFree(tmpNode);
+    xmlBufferFree(tmpBuf);
+}
+
+static void
+vboxSnapshotXmlRetrieveMachineNode(xmlNodePtr root,
+                        xmlNodePtr *machineNode)
+{
+    xmlNodePtr cur = root->xmlChildrenNode;
+    while (cur && xmlIsBlankNode(cur)) {
+        cur = cur -> next;
+    }
+    if (xmlStrcmp(cur->name, (const xmlChar *) "Machine")) {
+        VIR_DEBUG("Problem, found %s, Machine expected", (char *)cur->name);
+        return;
+    }
+    *machineNode = cur;
+}
+
+static void
+vboxSnapshotXmlRetrieveSnapshotsNode(xmlNodePtr snapshotNode,
+                            xmlNodePtr *snapshotsNode)
+{
+    xmlNodePtr cur_node = NULL;
+
+    for (cur_node = snapshotNode; cur_node; cur_node = cur_node->next) {
+        if (cur_node->type == XML_ELEMENT_NODE) {
+            if (!xmlStrcmp(cur_node->name, (const xmlChar *) "Snapshots")) {
+                *snapshotsNode = cur_node;
+                return;
+            }
+        }
+        if (cur_node->children)
+            vboxSnapshotXmlRetrieveSnapshotsNode(cur_node->children, snapshotsNode);
+    }
+}
+
+static void
+vboxSnapshotXmlRetrieveRootNodeByName(xmlNodePtr root,
+                           const char *name,
+                            xmlNodePtr *returnNode)
+{
+    xmlNodePtr cur = root->xmlChildrenNode;
+    while (cur && xmlIsBlankNode(cur)) {
+        cur = cur -> next;
+    }
+    if (xmlStrcmp(cur->name, (const xmlChar *) "Machine")) {
+        VIR_DEBUG("Problem, found %s, Machine expected", (char *)cur->name);
+    }
+    cur=cur->xmlChildrenNode;
+    while (cur != NULL) {
+        if (!xmlStrcmp(cur->name, (const xmlChar*) name)) {
+            *returnNode = cur;
+            return;
+        }
+        cur = cur -> next;
+    }
+}
+
+static void
+vboxSnapshotXmlAppendDiskToMediaRegistry(xmlNodePtr *inMediaRegistry,
+                              char *parentId,
+                              char *childId,
+                              char *childLocation,
+                              char *childFormat)
+{
+    /*This function will modify the inMediaregistry node to append
+     * all the informations about the child disk
+     */
+    xmlNodePtr cur_node = NULL;
+    for (cur_node = *inMediaRegistry; cur_node; cur_node = cur_node->next) {
+        if (cur_node) {
+            if (cur_node->type == XML_ELEMENT_NODE
+                && !xmlStrcmp(cur_node->name, (const xmlChar *) "HardDisk")
+                && xmlHasProp(cur_node, BAD_CAST "uuid") != NULL
+                && STREQ((char *)xmlHasProp(cur_node, BAD_CAST "uuid")->children->content,
+                         parentId)) {
+
+                xmlNodePtr childDiskNode = xmlNewTextChild(cur_node,
+                                                           NULL,
+                                                           BAD_CAST "HardDisk",
+                                                           NULL);
+                xmlNewProp(childDiskNode, BAD_CAST "uuid", BAD_CAST childId);
+                xmlNewProp(childDiskNode, BAD_CAST "location", BAD_CAST childLocation);
+                xmlNewProp(childDiskNode, BAD_CAST "format", BAD_CAST childFormat);
+                return;
+            }
+        }
+        if (&(cur_node->children))
+            vboxSnapshotXmlAppendDiskToMediaRegistry(&(cur_node->children),
+                                                     parentId,
+                                                     childId,
+                                                     childLocation,
+                                                     childFormat);
+
+    }
+}
+
+static int
+vboxSnapshotGenerateVboxXML(xmlNodePtr rootElementVboxXML,
+                            char *storageControllerString,
+                            char *parent,
+                            char *defName,
+                            char *timeStamp,
+                            char *uuid,
+                            xmlNodePtr *snapshotNodeReturned)
+{
+    xmlDocPtr doc;
+    xmlNodePtr snapshotNode;
+    xmlNodePtr snapshotsNode;
+    xmlNodePtr machineHardwareNode = NULL;
+    char *uuidstrWithBrackets = NULL;
+    char *timeVboxFormat = NULL;
+    int ret = -1;
+    /* We change the date format from "yyyy-MM-dd hh:mm:ss.msec+timeZone"
+     * to "yyyy-MM-ddThh:mm:ssZ"
+    */
+    char **splittedOnPlus = virStringSplit(timeStamp, "+", 0);
+    const char **splittedOnSpace = (const char**)virStringSplit(splittedOnPlus[0],
+                                                                " ",
+                                                                0);
+    char *joinWithT = virStringJoin(splittedOnSpace, "T");
+    char *date = virStringSplit(joinWithT, ".", 0)[0];
+    VIR_FREE(splittedOnPlus);
+    VIR_FREE(splittedOnSpace);
+    VIR_FREE(joinWithT);
+
+    /*Retrieve hardware*/
+    vboxSnapshotXmlRetrieveRootNodeByName(rootElementVboxXML, "Hardware",
+                                          &machineHardwareNode);
+    /* Create a new XML DOM tree, to which the XML document will be
+         * written */
+    doc = xmlNewDoc(BAD_CAST XML_DEFAULT_VERSION);
+    if (doc == NULL) {
+        VIR_DEBUG("Error creating the xml document tree\n");
+        ret = -1;
+        goto cleanup;
+    }
+    /* Create a new XML node, to which the XML document will be
+         * appended */
+    snapshotNode = xmlNewDocNode(doc, NULL, BAD_CAST "Snapshot", NULL);
+    if (snapshotNode == NULL) {
+        VIR_DEBUG("Error creating the xml node Snapshot\n");
+        ret = -1;
+        goto cleanup;
+    }
+    if (virAsprintf(&uuidstrWithBrackets, "{%s}", uuid) != -1) {
+        xmlNewProp(snapshotNode, BAD_CAST "uuid", BAD_CAST uuidstrWithBrackets);
+        VIR_FREE(uuidstrWithBrackets);
+    }
+    xmlNewProp(snapshotNode, BAD_CAST "name", BAD_CAST defName);
+    if (virAsprintf(&timeVboxFormat, "%sZ", date) != -1) {
+        xmlNewProp(snapshotNode, BAD_CAST "timeStamp", BAD_CAST timeVboxFormat);
+        VIR_FREE(timeVboxFormat);
+    }
+    xmlDocSetRootElement(doc, snapshotNode);
+    if (machineHardwareNode) {
+        vboxSnapshotXmlAddChild(snapshotNode, machineHardwareNode);
+    }
+    xmlNodePtr listStorageControllerNodes;
+    xmlParseInNodeContext(snapshotNode, storageControllerString,
+                          (int)strlen(storageControllerString),
+                          0,
+                          &listStorageControllerNodes);
+    if (listStorageControllerNodes) {
+        if (xmlAddChild(snapshotNode, xmlCopyNode(listStorageControllerNodes, 1)) == NULL) {
+            VIR_DEBUG("Could not add listStorageControllerNodes node to snapshot node");
+            ret = -1;
+            goto cleanup;
+        }
+    }
+    snapshotsNode = xmlNewDocNode(doc, NULL, BAD_CAST "Snapshots", NULL);
+    if (snapshotsNode == NULL) {
+        VIR_DEBUG("Error creating the xml node Snapshots\n");
+        ret = -1;
+        goto cleanup;
+    }
+    if (snapshotsNode) {
+        if (xmlAddChild(snapshotNode, xmlCopyNode(snapshotsNode, 1)) == NULL) {
+            VIR_DEBUG("Could not add snapshotsNode node to snapshot node");
+            ret = -1;
+            goto cleanup;
+        }
+    }
+    if (parent) {
+        xmlNodePtr rootSnapshotNode = NULL;
+        xmlNodePtr parentNode = NULL;
+        xmlNodePtr parentSnapshotsNode = NULL;
+        vboxSnapshotXmlRetrieveRootNodeByName(rootElementVboxXML,
+                                              "Snapshot",
+                                              &rootSnapshotNode);
+        if (!rootSnapshotNode) {
+            VIR_DEBUG("Could not retrieve Snapshot node");
+            ret = -1;
+            goto cleanup;
+        }
+        vboxSnapshotXmlRetrieveSnapshotNodeByName(rootSnapshotNode,
+                                                  parent,
+                                                  &parentNode);
+        if (!parentNode) {
+            VIR_DEBUG("Could not retrieve Snapshot node of %s", parent);
+            ret = -1;
+            goto cleanup;
+        }
+        vboxSnapshotXmlRetrieveSnapshotsNode(parentNode->children,
+                                             &parentSnapshotsNode);
+        if (!parentSnapshotsNode) {
+            VIR_DEBUG("Could not retrieve Snapshots node");
+            ret = -1;
+            goto cleanup;
+        }
+        if (xmlAddChild(parentSnapshotsNode, xmlCopyNode(snapshotNode, 1)) == NULL) {
+            VIR_DEBUG("Could not add snapshotsNode node to its parent");
+            ret = -1;
+            goto cleanup;
+        } else {
+            *snapshotNodeReturned = xmlCopyNode(rootSnapshotNode, 1);
+        }
+    } else {
+        *snapshotNodeReturned = xmlCopyNode(snapshotNode, 1);
+    }
+    ret = 0;
+cleanup:
+    return ret;
+}
+
+static xmlBufferPtr
+vboxSnapshotGenerateXmlSkeleton(char *domainUuid,
+                        char *machineName,
+                        char *snapshotUuid,
+                        char *snapshotFolder,
+                        PRInt64 lastStateChange,
+                        bool isCurrent,
+                        char *savedCurrentSnapshotUuid)
+{
+    char *snapshotUuidWithBrackets = NULL;
+    char *lastStateChangeStr = NULL;
+    /*Let's write a new xml
+        */
+    xmlTextWriterPtr writer;
+    xmlBufferPtr buf = xmlBufferCreate();
+    xmlBufferPtr ret = NULL;
+    int resultXml;
+    char *uuidWithBracket = NULL;
+
+    /* Create a new XmlWriter with no compression. */
+    writer = xmlNewTextWriterMemory(buf, 0);
+    if (writer == NULL) {
+        VIR_DEBUG("Error creating the xml writer\n");
+        goto cleanup;
+    }
+
+    /* Start the document with the xml default for the version,
+     * encoding ISO 8859-1 and the default for the standalone
+     * declaration. */
+    resultXml = xmlTextWriterStartDocument(writer, NULL, "ISO-8859-1", NULL);
+    if (resultXml < 0) {
+        VIR_DEBUG("Error at xmlTextWriterStartDocument\n");
+        goto cleanup;
+    }
+    /* Write a comment as child of root.
+     * Please observe, that the input to the xmlTextWriter functions
+     * HAS to be in UTF-8, even if the output XML is encoded
+     * in iso-8859-1 */
+    resultXml = xmlTextWriterWriteFormatComment(writer,
+        "WARNING: THIS IS AN AUTO-GENERATED FILE. CHANGES TO IT ARE LIKELY TO BE \n"
+        "OVERWRITTEN AND LOST.\n"
+        "Changes to this xml configuration should be made using Virtualbox \n"
+        "or other application using the libvirt API");
+
+    if (resultXml < 0) {
+        VIR_DEBUG("Error at xmlTextWriterWriteComment\n");
+        goto cleanup;
+    }
+    xmlTextWriterWriteRaw(writer, BAD_CAST "\n"); /*Break line after comment*/
+
+    /* Start an element named "VirtualBox". Since thist is the first
+     * element, this will be the root element of the document. */
+    resultXml = xmlTextWriterStartElement(writer, BAD_CAST "VirtualBox");
+    if (resultXml < 0) {
+        VIR_DEBUG("Error creating the xml node\n");
+        goto cleanup;
+    }
+    resultXml = xmlTextWriterWriteAttribute(writer,
+                                            BAD_CAST "version",
+                                            BAD_CAST "1.12-linux");
+    if (resultXml < 0) {
+        VIR_DEBUG("Error at xmlTextWriterWriteAttribute\n");
+        goto cleanup;
+    }
+    /* Start an element named "Machine" as child of VirtualBox. */
+    resultXml = xmlTextWriterStartElement(writer, BAD_CAST "Machine");
+    if (resultXml < 0) {
+        VIR_DEBUG("Error at xmlTextWriterStartElement\n");
+        goto cleanup;
+    }
+    /* Add an attribute with name "uuid" and value "{uuid}" to Machine. */
+    if (virAsprintf(&uuidWithBracket, "{%s}", domainUuid) != -1) {
+        resultXml = xmlTextWriterWriteAttribute(writer,
+                                                BAD_CAST "uuid",
+                                                BAD_CAST uuidWithBracket);
+        if (resultXml < 0) {
+            VIR_DEBUG("Error at xmlTextWriterWriteAttribute\n");
+            goto cleanup;
+        }
+        VIR_FREE(uuidWithBracket);
+    }
+
+    if (!machineName) {
+        VIR_DEBUG("No machine name");
+        goto cleanup;
+    }
+    resultXml = xmlTextWriterWriteAttribute(writer,
+                                            BAD_CAST "name",
+                                            BAD_CAST machineName);
+    if (resultXml < 0) {
+        VIR_DEBUG("Error at xmlTextWriterWriteAttribute\n");
+        goto cleanup;
+    }
+    resultXml = xmlTextWriterWriteAttribute(writer,
+                                            BAD_CAST "OSType",
+                                            BAD_CAST "Other");
+    if (resultXml < 0) {
+        VIR_DEBUG("Error at xmlTextWriterWriteAttribute\n");
+        goto cleanup;
+    }
+
+    if (!snapshotFolder) {
+        VIR_DEBUG("No machine snapshotFolder");
+        goto cleanup;
+    }
+    resultXml = xmlTextWriterWriteAttribute(writer,
+                                            BAD_CAST "snapshotFolder",
+                                            BAD_CAST snapshotFolder);
+    if (resultXml < 0) {
+        VIR_DEBUG("Error at xmlTextWriterWriteAttribute\n");
+        goto cleanup;
+    }
+    if (virAsprintf(&lastStateChangeStr, "%ld", lastStateChange) < 0) {
+        VIR_DEBUG("Could not convert lastStateChange from long to string");
+        goto cleanup;
+    }
+    resultXml = xmlTextWriterWriteAttribute(writer,
+                                            BAD_CAST "lastStateChange",
+                                            BAD_CAST lastStateChangeStr);
+    if (resultXml < 0) {
+        VIR_DEBUG("Error at xmlTextWriterWriteAttribute\n");
+        goto cleanup;
+    }
+    /* Current Snapshot
+     * https://www.virtualbox.org/sdkref/interface_i_machine.html#ac785dbe04eccc0793d949d6940202767
+     * There is always a current snapshot, except when there is no snapshot (obvious)
+     * or when they have all been deleted (obvious) or when the current snapshot
+     * is deleted and it does not have a parent (not so obvious).
+     *
+     * This can happen only when the last snapshot is deleted because there can
+     * only be one snapshot with no parent, the first one.
+     *
+     * For the moment we always put the snapshot we are defining as current snapshot.
+     * When all the snapshots are redefined, you can always set the current snapshot
+     * to one you have previously saved.
+     */
+    if (isCurrent) {
+        if (virAsprintf(&snapshotUuidWithBrackets, "{%s}", snapshotUuid) != -1) {
+            resultXml = xmlTextWriterWriteAttribute(writer,
+                                                    BAD_CAST "currentSnapshot",
+                                                    BAD_CAST snapshotUuidWithBrackets);
+            if (resultXml < 0) {
+                VIR_DEBUG("Error at xmlTextWriterWriteAttribute\n");
+                goto cleanup;
+            }
+            VIR_FREE(snapshotUuidWithBrackets);
+        }
+    }
+    if (savedCurrentSnapshotUuid != NULL) {
+        if (virAsprintf(&snapshotUuidWithBrackets, "{%s}", savedCurrentSnapshotUuid) != -1) {
+            resultXml = xmlTextWriterWriteAttribute(writer,
+                                                    BAD_CAST "currentSnapshot",
+                                                    BAD_CAST snapshotUuidWithBrackets);
+            if (resultXml < 0) {
+                VIR_DEBUG("Error at xmlTextWriterWriteAttribute\n");
+                goto cleanup;
+            }
+            VIR_FREE(snapshotUuidWithBrackets);
+        }
+    }
+
+    /* Here we could close the elements Machine and VirtualBox using the
+     * function xmlTextWriterEndElement, but since we do not want to
+     * write any other elements, we simply call xmlTextWriterEndDocument,
+     * which will do all the work. */
+    resultXml = xmlTextWriterEndDocument(writer);
+    if (resultXml < 0) {
+        VIR_DEBUG("Error at xmlTextWriterEndDocument\n");
+        goto cleanup;
+    }
+    xmlFreeTextWriter(writer);
+    /* Now we have a file containing the skeleton for the xml we want to build
+     * It should look like this:
+     * <?xml version="1.0" encoding="ISO-8859-1"?>
+     * <!--comment
+     * -->
+     * <VirtualBox>
+     *  <Machine uuid="{anUuid}" name="the name" OSType="Other"
+     *      snapshotFolder="/path/to/SnapshotFolder"
+     *      lastStateChange="a date"/>
+     * </VirtualBox>
+     */
+     ret = buf;
+cleanup:
+    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.
+     *
+     */
+
+    VBOX_OBJECT_CHECK(dom->conn, int, 0);
+    vboxIID domiid = VBOX_IID_INITIALIZER;
+    IMachine *machine = NULL;
+    nsresult rc;
+    PRUnichar *settingsFilePath = NULL;
+    char *settingsFilePath_Utf8 = NULL;
+    size_t it = 0;
+
+    IMachine *newMachine = NULL;
+    xmlDocPtr xml = NULL;
+    bool snapshotHasParents = !(def->parent == NULL);
+
+    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"));
+        ret = -1;
+        goto cleanup;
+    }
+
+
+    rc = machine->vtbl->SaveSettings(machine);
+    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);
+    xml = virXMLParse(settingsFilePath_Utf8, NULL, NULL);
+    if (xml) {
+        xmlNodePtr cur = NULL;
+        xmlNodePtr machineHardwareNode = NULL;
+        xmlNodePtr extraDataNode = NULL;
+        xmlNodePtr mediaRegistryNodeOriginal = NULL;
+        xmlNodePtr snapshotStorageControllersNode = NULL;
+        xmlNodePtr modifiedMachineStorageControllersNode = NULL;
+        char *newMachineStorageControllersString = NULL;
+        char *newSnapshotStorageControllersString = NULL;
+        char snapshotuuidstr[VIR_UUID_STRING_BUFLEN];
+        unsigned char snapshotUuid[VIR_UUID_BUFLEN];
+
+        char *domainUuid = NULL;
+        PRUnichar *machineNameUtf16 = NULL;
+        char *machineName = NULL;
+        PRUnichar *snapshotFolderUtf16 = NULL;
+        PRInt64 lastStateChange = 0;
+        ISnapshot *savedCurrentSnapshot = NULL;
+        vboxIID savedCurrentSnapshotIid = VBOX_IID_INITIALIZER;
+        char *savedCurrentSnapshotUuid = NULL;
+        cur = xmlDocGetRootElement(xml);
+        xmlBufferPtr buf = xmlBufferCreate();
+        if (cur == NULL) {
+            VIR_DEBUG("empty document\n");
+            ret = -1;
+            goto cleanup;
+        }
+        /*Retrieve hardware*/
+        vboxSnapshotXmlRetrieveRootNodeByName(cur, "Hardware", &machineHardwareNode);
+        if (!machineHardwareNode) {
+            VIR_DEBUG("Could not retrieve Hardware node");
+            ret = -1;
+            goto cleanup;
+        }
+        /*Retrieve storageController*/
+        buf = xmlBufferCreate();
+        vboxSnapshotXmlRetrieveRootNodeByName(cur,
+                                              "StorageControllers",
+                                              &snapshotStorageControllersNode);
+        if (!snapshotStorageControllersNode) {
+            VIR_DEBUG("Could not retrieve StorageControllers node");
+            ret = -1;
+            goto cleanup;
+        }
+        xmlNodeDump(buf, xml, snapshotStorageControllersNode, 0, 0);
+        ignore_value(VIR_STRDUP(newMachineStorageControllersString,
+                                (char *)xmlBufferContent(buf)));
+        ignore_value(VIR_STRDUP(newSnapshotStorageControllersString,
+                                newMachineStorageControllersString));
+        xmlBufferFree(buf);
+        /*Retrieve ExtraData*/
+        vboxSnapshotXmlRetrieveRootNodeByName(cur, "ExtraData", &extraDataNode);
+        if (!extraDataNode) {
+            VIR_DEBUG("Could not retrieve ExtraData node");
+            ret = -1;
+            goto cleanup;
+        }
+        /*Retrieve MediaRegistry*/
+        vboxSnapshotXmlRetrieveRootNodeByName(cur,
+                                              "MediaRegistry",
+                                              &mediaRegistryNodeOriginal);
+        if (!mediaRegistryNodeOriginal) {
+            VIR_DEBUG("Could not retrieve MediaRegistry node");
+            ret = -1;
+            goto cleanup;
+        }
+        vboxArray mediumAttachments         = VBOX_ARRAY_INITIALIZER;
+        rc = vboxArrayGet(&mediumAttachments,
+                          machine,
+                          machine->vtbl->GetMediumAttachments);
+        if (NS_FAILED(rc)) {
+            virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+                           _("cannot get medium attachments"));
+            goto cleanup;
+        }
+
+        /*Read only disks*/
+        for (it = 0; it<def->dom->ndisks; ++it) {
+            IMedium *mediumReadOnly = NULL;
+            PRUnichar *locationReadOnlyDiskUtf16 = NULL;
+            PRUnichar *mediumReadOnlyFormatUtf16 = NULL;
+            PRUnichar *mediumReadOnlyIdUtf16 = NULL;
+            char *mediumReadOnlyFormat = NULL;
+            char *mediumReadOnlyId = NULL;
+            char *mediaRegistryNodeOriginalString = NULL;
+            VBOX_UTF8_TO_UTF16(def->dom->disks[it]->src, &locationReadOnlyDiskUtf16);
+            data->vboxObj->vtbl->OpenMedium(data->vboxObj,
+                                            locationReadOnlyDiskUtf16,
+                                            DeviceType_HardDisk,
+                                            AccessMode_ReadWrite,
+                                            false,
+                                            &mediumReadOnly);
+            if (mediumReadOnly) {
+                rc = mediumReadOnly->vtbl->GetId(mediumReadOnly,
+                                                 &mediumReadOnlyIdUtf16);
+                if (NS_FAILED(rc)) {
+                    virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+                                   _("cannot get medium id"));
+                    goto cleanup;
+                }
+                rc = mediumReadOnly->vtbl->GetFormat(mediumReadOnly,
+                                                     &mediumReadOnlyFormatUtf16);
+                if (NS_FAILED(rc)) {
+                    virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+                                   _("cannot get medium format"));
+                    goto cleanup;
+                }
+                VBOX_UTF16_TO_UTF8(mediumReadOnlyIdUtf16, &mediumReadOnlyId);
+                VBOX_UTF16_TO_UTF8(mediumReadOnlyFormatUtf16, &mediumReadOnlyFormat);
+                char *uuidToReplace = NULL;
+                virSearchRegex(newSnapshotStorageControllersString,
+                               it,
+                               "([a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12})",
+                               &uuidToReplace);
+                if (STRNEQ(uuidToReplace, mediumReadOnlyId)) {
+                    char *tmp = NULL;
+                    tmp = virStrReplace(newSnapshotStorageControllersString,
+                                        uuidToReplace,
+                                        mediumReadOnlyId);
+                    VIR_FREE(newSnapshotStorageControllersString);
+                    if (!tmp)
+                        goto cleanup;
+                    if (VIR_STRDUP(newSnapshotStorageControllersString, tmp) < 0) {
+                        VIR_DEBUG("Error while using strdup");
+                    }
+                    VIR_FREE(tmp);
+                }
+                IMedium *mediumReadOnlyParent = NULL;
+                rc = mediumReadOnly->vtbl->GetParent(mediumReadOnly,
+                                                     &mediumReadOnlyParent);
+                if (NS_FAILED(rc)) {
+                    virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+                                   _("cannot get medium parent"));
+                    goto cleanup;
+                }
+                if (mediumReadOnlyParent) {
+                    PRUnichar *parentIdUtf16 = NULL;
+                    char *parentId = NULL;
+                    char *parentIdWithBrackets = NULL;
+                    char *childIdWithBrackets = NULL;
+                    rc = mediumReadOnlyParent->vtbl->GetId(mediumReadOnlyParent, &parentIdUtf16);
+                    if (NS_FAILED(rc)) {
+                        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+                                       _("cannot get medium id"));
+                        goto cleanup;
+                    }
+                    if (parentIdUtf16) {
+                        VBOX_UTF16_TO_UTF8(parentIdUtf16, &parentId);
+                        if ((virAsprintf(&parentIdWithBrackets, "{%s}", parentId) != -1)
+                            && (virAsprintf(&childIdWithBrackets, "{%s}", mediumReadOnlyId) != -1)) {
+                            buf = xmlBufferCreate();
+                            xmlNodeDump(buf, mediaRegistryNodeOriginal->doc, mediaRegistryNodeOriginal, 0, 0);
+                            ignore_value(VIR_STRDUP(mediaRegistryNodeOriginalString,
+                                                    (char *)xmlBufferContent(buf)));
+                            if (strstr(mediaRegistryNodeOriginalString, childIdWithBrackets) == NULL) {
+                                vboxSnapshotXmlAppendDiskToMediaRegistry(&mediaRegistryNodeOriginal->children,
+                                                                         parentIdWithBrackets,
+                                                                         childIdWithBrackets,
+                                                                         def->dom->disks[it]->src,
+                                                                         mediumReadOnlyFormat);
+                            } else {
+                                VIR_DEBUG("Already added");
+                            }
+                            VIR_FREE(parentIdWithBrackets);
+                            VIR_FREE(childIdWithBrackets);
+                        }
+                        VBOX_UTF8_FREE(parentId);
+                    }
+                    VBOX_RELEASE(mediumReadOnlyParent);
+                    VBOX_UTF16_FREE(parentIdUtf16);
+                }
+                VBOX_UTF8_FREE(mediumReadOnlyFormat);
+                VBOX_UTF8_FREE(mediumReadOnlyId);
+                VBOX_RELEASE(mediumReadOnly);
+            }
+            VBOX_UTF16_FREE(mediumReadOnlyIdUtf16);
+            VBOX_UTF16_FREE(mediumReadOnlyFormatUtf16);
+            VBOX_UTF16_FREE(locationReadOnlyDiskUtf16);
+        }
+
+        /*Read Write disks*/
+        for (it = 0; it< def->ndisks; ++it) {
+            IMedium *mediumReadWrite = NULL;
+            PRUnichar *mediumReadWriteFormatUtf16 = NULL;
+            PRUnichar *mediumReadWriteIdUtf16 = NULL;
+            PRUnichar *locationReadWriteDiskUtf16 = NULL;
+            char *mediumReadWriteFormat = NULL;
+            char *mediumReadWriteId = NULL;
+            char *mediaRegistryNodeOriginalString = NULL;
+            VBOX_UTF8_TO_UTF16(def->disks[it].file, &locationReadWriteDiskUtf16);
+            rc = data->vboxObj->vtbl->OpenMedium(data->vboxObj,
+                                                 locationReadWriteDiskUtf16,
+                                                 DeviceType_HardDisk,
+                                                 AccessMode_ReadWrite,
+                                                 false,
+                                                 &mediumReadWrite);
+            if (NS_FAILED(rc)) {
+                virReportError(VIR_ERR_INTERNAL_ERROR, "%s"
+                               "%s",
+                               _("Could not open medium"), def->disks[it].file);
+                ret = -1;
+                goto cleanup;
+            }
+            if (mediumReadWrite) {
+                rc = mediumReadWrite->vtbl->GetId(mediumReadWrite,
+                                                  &mediumReadWriteIdUtf16);
+                if (NS_FAILED(rc)) {
+                    virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+                                   _("cannot get medium id"));
+                    goto cleanup;
+                }
+                rc = mediumReadWrite->vtbl->GetFormat(mediumReadWrite,
+                                                      &mediumReadWriteFormatUtf16);
+                if (NS_FAILED(rc)) {
+                    virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+                                   _("cannot get medium format"));
+                    goto cleanup;
+                }
+                VBOX_UTF16_TO_UTF8(mediumReadWriteIdUtf16, &mediumReadWriteId);
+                VBOX_UTF16_TO_UTF8(mediumReadWriteFormatUtf16, &mediumReadWriteFormat);
+                char *uuidToReplace = NULL;
+                virSearchRegex(newMachineStorageControllersString,
+                               it,
+                               "([a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12})",
+                               &uuidToReplace);
+                if (STRNEQ(uuidToReplace, mediumReadWriteId)) {
+                    char *tmp = NULL;
+                    tmp = virStrReplace(newMachineStorageControllersString,
+                                        uuidToReplace,
+                                        mediumReadWriteId);
+                    VIR_FREE(newMachineStorageControllersString);
+                    if (!tmp)
+                        goto cleanup;
+                    if (VIR_STRDUP(newMachineStorageControllersString, tmp) < 0) {
+                        VIR_DEBUG("Error while using strdup");
+                    }
+                    VIR_FREE(tmp);
+                }
+                buf = xmlBufferCreate();
+                xmlNodeDump(buf, mediaRegistryNodeOriginal->doc, mediaRegistryNodeOriginal, 0, 0);
+                ignore_value(VIR_STRDUP(mediaRegistryNodeOriginalString,
+                                        (char *)xmlBufferContent(buf)));
+                xmlBufferFree(buf);
+                if (mediaRegistryNodeOriginalString && (strstr(mediaRegistryNodeOriginalString,
+                                                               mediumReadWriteId) == NULL)) {
+                    IMedium *mediumReadWriteParent = NULL;
+                    rc = mediumReadWrite->vtbl->GetParent(mediumReadWrite,
+                                                          &mediumReadWriteParent);
+                    if (NS_FAILED(rc)) {
+                        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+                                       _("cannot get disk parent"));
+                        goto cleanup;
+                    }
+                    if (mediumReadWriteParent) {
+                        PRUnichar *parentIdUtf16 = NULL;
+                        char *parentId = NULL;
+                        char *parentIdWithBrackets = NULL;
+                        char *childIdWithBrackets = NULL;
+                        rc = mediumReadWriteParent->vtbl->GetId(mediumReadWriteParent,
+                                                                &parentIdUtf16);
+                        if (NS_FAILED(rc)) {
+                            virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+                                           _("cannot get disk id"));
+                            goto cleanup;
+                        }
+                        if (parentIdUtf16) {
+                            VBOX_UTF16_TO_UTF8(parentIdUtf16, &parentId);
+                            if ((virAsprintf(&parentIdWithBrackets, "{%s}", parentId) != -1)
+                                && (virAsprintf(&childIdWithBrackets, "{%s}", mediumReadWriteId) != -1)) {
+                                vboxSnapshotXmlAppendDiskToMediaRegistry(&(mediaRegistryNodeOriginal->children),
+                                                                         parentIdWithBrackets,
+                                                                         childIdWithBrackets,
+                                                                         def->disks[it].file,
+                                                                         mediumReadWriteFormat);
+                                VIR_FREE(parentIdWithBrackets);
+                                VIR_FREE(childIdWithBrackets);
+                            }
+                            VBOX_UTF8_FREE(parentId);
+                        }
+                        VBOX_RELEASE(mediumReadWriteParent);
+                        VBOX_UTF16_FREE(parentIdUtf16);
+                    }
+                }
+                VBOX_UTF8_FREE(mediumReadWriteFormat);
+                VBOX_UTF8_FREE(mediumReadWriteId);
+                VBOX_RELEASE(mediumReadWrite);
+            }
+            VBOX_UTF16_FREE(mediumReadWriteIdUtf16);
+            VBOX_UTF16_FREE(mediumReadWriteFormatUtf16);
+            VBOX_UTF16_FREE(locationReadWriteDiskUtf16);
+        }
+        vboxArrayRelease(&mediumAttachments);
+
+        /*Generation of the skeleton*/
+
+        VBOX_UTF16_TO_UTF8((PRUnichar *)domiid.value, &domainUuid);
+        rc = machine->vtbl->GetName(machine, &machineNameUtf16);
+        if (NS_FAILED(rc)) {
+            virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+                           _("cannot get machine name"));
+            goto cleanup;
+        }
+        rc = machine->vtbl->GetSnapshotFolder(machine, &snapshotFolderUtf16);
+        if (NS_FAILED(rc)) {
+            virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+                           _("cannot get snapshot folder"));
+            goto cleanup;
+        }
+        char *snapshotFolder = NULL;
+        VBOX_UTF16_TO_UTF8(snapshotFolderUtf16, &snapshotFolder);
+        VBOX_UTF16_FREE(snapshotFolderUtf16);
+        VBOX_UTF16_TO_UTF8(machineNameUtf16, &machineName);
+        VBOX_UTF16_FREE(machineNameUtf16);
+        if (snapshotUuid == NULL) {
+            VIR_DEBUG("Bad initialization");
+        }
+        if (virUUIDGenerate(snapshotUuid) == -1) {
+            VIR_DEBUG("Could not generate a snapshot uuid");
+        } else {
+            virUUIDFormat(snapshotUuid, snapshotuuidstr);
+            VIR_DEBUG("UUID: %s", snapshotuuidstr);
+        }
+        rc = machine->vtbl->GetCurrentSnapshot(machine, &savedCurrentSnapshot);
+        if (NS_FAILED(rc)) {
+            virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+                           _("cannot get current snapshot"));
+            goto cleanup;
+        }
+        if (savedCurrentSnapshot) {
+            savedCurrentSnapshot->vtbl->GetId(savedCurrentSnapshot,
+                                              &savedCurrentSnapshotIid.value);
+            VBOX_UTF16_TO_UTF8(savedCurrentSnapshotIid.value,
+                               &savedCurrentSnapshotUuid);
+            vboxIIDUnalloc(&savedCurrentSnapshotIid);
+            VBOX_RELEASE(savedCurrentSnapshot);
+        }
+        rc = machine ->vtbl->GetLastStateChange(machine, &lastStateChange);
+        if (NS_FAILED(rc)) {
+            virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+                           _("cannot get last state change"));
+            goto cleanup;
+        }
+        xmlBufferPtr skeletonBuf = vboxSnapshotGenerateXmlSkeleton(domainUuid,
+                                                                   machineName,
+                                                                   snapshotuuidstr,
+                                                                   snapshotFolder,
+                                                                   lastStateChange,
+                                                                   isCurrent,
+                                                                   savedCurrentSnapshotUuid);
+        /* Now we can reopen our file in tree mode and append node we want. */
+        xmlDocPtr newXml = virXMLParse(NULL, (char *)skeletonBuf->content, NULL);
+        if (newXml) {
+            xmlNodePtr newXmlRootElement = xmlDocGetRootElement(newXml);
+            xmlNodePtr newXmlMachineNode = NULL;
+            xmlNodePtr snapshotNodeToAppend = NULL;
+            IMedium *array[] = { NULL };
+            IProgress *progress = NULL;
+            vboxArray media = VBOX_ARRAY_INITIALIZER;
+
+            vboxSnapshotXmlRetrieveMachineNode(newXmlRootElement, &newXmlMachineNode);
+            if (newXmlMachineNode) {
+                if (mediaRegistryNodeOriginal) {
+                    vboxSnapshotXmlAddChild(newXmlMachineNode, mediaRegistryNodeOriginal);
+                }
+                if (extraDataNode) {
+                    vboxSnapshotXmlAddChild(newXmlMachineNode, extraDataNode);
+                }
+            }
+            if (!snapshotHasParents) {
+                vboxSnapshotGenerateVboxXML(xmlDocGetRootElement(xml),
+                                            newSnapshotStorageControllersString,
+                                            NULL,
+                                            def->name,
+                                            virTimeStringThen(def->creationTime*1000),
+                                            snapshotuuidstr,
+                                            &snapshotNodeToAppend);
+            } else {
+                vboxSnapshotGenerateVboxXML(xmlDocGetRootElement(xml),
+                                            newSnapshotStorageControllersString,
+                                            def->parent,
+                                            def->name,
+                                            virTimeStringThen(def->creationTime*1000),
+                                            snapshotuuidstr,
+                                            &snapshotNodeToAppend);
+            }
+            if (snapshotNodeToAppend) {
+                if (xmlAddChild(newXmlMachineNode, xmlCopyNode(snapshotNodeToAppend, 1)) == NULL) {
+                    VIR_DEBUG("Error while building the xml");
+                }
+            }
+            if (newXmlMachineNode) {
+                if (machineHardwareNode) {
+                    vboxSnapshotXmlAddChild(newXmlMachineNode, machineHardwareNode);
+                }
+                xmlParseInNodeContext(newXmlMachineNode,
+                                      newMachineStorageControllersString,
+                                      (int)strlen(newMachineStorageControllersString),
+                                      0,
+                                      &modifiedMachineStorageControllersNode);
+                if (modifiedMachineStorageControllersNode) {
+                    if (xmlAddChild(newXmlMachineNode, xmlCopyNode(modifiedMachineStorageControllersNode, 1)) == NULL) {
+                        VIR_DEBUG("Could not add modifiedSnapshotStorageControllersNode node to snapshot node");
+                    }
+                }
+            }
+            xmlNewProp(newXmlRootElement, BAD_CAST "xmlns", BAD_CAST "http://www.innotek.de/VirtualBox-settings");
+            rc = vboxArrayGetWithUintArg(&media,
+                                         machine,
+                                         machine->vtbl->Unregister,
+                                         CleanupMode_DetachAllReturnHardDisksOnly);
+            for (it = 0; it < media.count; ++it) {
+                IMedium *disk = media.items[it];
+                if (disk)
+                    vboxDetachAndCloseDisks(dom, disk);
+            }
+# if VBOX_API_VERSION == 4002
+            rc = machine->vtbl->Delete(machine, 0, array, &progress);
+# elif VBOX_API_VERSION >= 4003
+            rc = machine->vtbl->DeleteConfig(machine, 0, array, &progress);
+# endif
+            if (NS_FAILED(rc)) {
+                virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+                               _("cannot delete machine"));
+                goto cleanup;
+            }
+            if (progress != NULL) {
+                progress->vtbl->WaitForCompletion(progress, -1);
+                VBOX_RELEASE(progress);
+            }
+            vboxArrayRelease(&media);
+            if (virFileMakePath(mdir_name(settingsFilePath_Utf8)) < 0)
+                virReportError(VIR_ERR_INTERNAL_ERROR, "%s"
+                               " %s",
+                               _("Cannot create path :"),
+                               settingsFilePath_Utf8);
+            if (xmlSaveFormatFileEnc(settingsFilePath_Utf8, newXml, "ISO-8859-1", 1) <= 0) {
+                virReportError(VIR_ERR_INTERNAL_ERROR, "%s"
+                               " %s",
+                               _("Cannot save xml file to:"),
+                               settingsFilePath_Utf8);
+            }
+            rc = data->vboxObj->vtbl->OpenMachine(data->vboxObj,
+                                                  settingsFilePath,
+                                                  &newMachine);
+            unsigned int failedCounter = 10;
+            while (NS_FAILED(rc) && (rc == 0x80004005 /*NSCOM standard error*/) && failedCounter != 0) {
+                /* There is some random fails happening and they are not the error
+                 * supposed to happen.
+                 * I didn't have some solution on #vbox-dev
+                 * but it appears that with another try it works
+                 * so that's why we are trying 10 times maximum
+                */
+                rc = data->vboxObj->vtbl->OpenMachine(data->vboxObj,
+                                                      settingsFilePath,
+                                                      &newMachine);
+                failedCounter--;
+            }
+            if (NS_FAILED(rc)) {
+                virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+                               _("cannot open machine"));
+                goto cleanup;
+            }
+            if (newMachine) {
+                rc = data->vboxObj->vtbl->RegisterMachine(data->vboxObj, newMachine);
+                if (NS_FAILED(rc)) {
+                    virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+                                   _("cannot register machine"));
+                    goto cleanup;
+                }
+            }
+            else {
+                ret = -1;
+                goto cleanup;
+            }
+        }
+    }
+    ret = 0;
+cleanup:
+    xmlFreeDoc(xml);
+    return ret;
+}
+#endif
 static virDomainSnapshotPtr
 vboxDomainSnapshotCreateXML(virDomainPtr dom,
                             const char *xmlDesc,
@@ -5972,9 +7032,14 @@ vboxDomainSnapshotCreateXML(virDomainPtr dom,
 #else
     PRInt32 result;
 #endif
+#if VBOX_API_VERSION >= 4002
+    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,
@@ -5982,11 +7047,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);
@@ -5996,6 +7056,15 @@ vboxDomainSnapshotCreateXML(virDomainPtr dom,
         goto cleanup;
     }
 
+#if VBOX_API_VERSION >= 4002
+    isCurrent = flags & VIR_DOMAIN_SNAPSHOT_CREATE_CURRENT;
+    if (flags & VIR_DOMAIN_SNAPSHOT_CREATE_REDEFINE) {
+        vboxSnapshotRedefine(dom, def, isCurrent);
+        ret = virGetDomainSnapshot(dom, def->name);
+        goto cleanup;
+    }
+#endif
+
     rc = machine->vtbl->GetState(machine, &state);
     if (NS_FAILED(rc)) {
         virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
@@ -7339,8 +8408,6 @@ cleanup:
     return ret;
 }
 
-
-
 static int
 vboxDomainSnapshotDelete(virDomainSnapshotPtr snapshot,
                          unsigned int flags)
-- 
1.7.10.4




More information about the libvir-list mailing list