This structure contains the data to be saved in the VirtualBox XML file
and can be manipulated with severals exposed functions.
The structure is created by vboxSnapshotLoadVboxFile taking the
machine XML file.
It also can rewrite the XML by using vboxSnapshotSaveVboxFile.
---
po/POTFILES.in | 1 +
src/Makefile.am | 1 +
src/vbox/vbox_snapshot_conf.c | 1383 +++++++++++++++++++++++++++++++++++++++++
src/vbox/vbox_snapshot_conf.h | 100 +++
4 files changed, 1485 insertions(+)
create mode 100644 src/vbox/vbox_snapshot_conf.c
create mode 100644 src/vbox/vbox_snapshot_conf.h
diff --git a/po/POTFILES.in b/po/POTFILES.in
index 122b853..ad56b88 100644
--- a/po/POTFILES.in
+++ b/po/POTFILES.in
@@ -208,6 +208,7 @@ src/util/virxml.c
src/vbox/vbox_MSCOMGlue.c
src/vbox/vbox_XPCOMCGlue.c
src/vbox/vbox_driver.c
+src/vbox/vbox_snapshot_conf.c
src/vbox/vbox_tmpl.c
src/vmware/vmware_conf.c
src/vmware/vmware_driver.c
diff --git a/src/Makefile.am b/src/Makefile.am
index 21d56fc..37f4df0 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -658,6 +658,7 @@ VMWARE_DRIVER_SOURCES = \
VBOX_DRIVER_SOURCES = \
vbox/vbox_glue.c vbox/vbox_glue.h \
vbox/vbox_driver.c vbox/vbox_driver.h \
+ vbox/vbox_snapshot_conf.c vbox/vbox_snapshot_conf.h \
vbox/vbox_V2_2.c vbox/vbox_CAPI_v2_2.h \
vbox/vbox_V3_0.c vbox/vbox_CAPI_v3_0.h \
vbox/vbox_V3_1.c vbox/vbox_CAPI_v3_1.h \
diff --git a/src/vbox/vbox_snapshot_conf.c b/src/vbox/vbox_snapshot_conf.c
new file mode 100644
index 0000000..81e780a
--- /dev/null
+++ b/src/vbox/vbox_snapshot_conf.c
@@ -0,0 +1,1383 @@
+/*
+ * Copyright 2014, diateam (
www.diateam.net)
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see
+ * <
http://www.gnu.org/licenses/>.
+ */
+
+#include <config.h>
+
+#include "vbox_snapshot_conf.h"
+#include "virerror.h"
+#include "viralloc.h"
+#include "virlog.h"
+#include "virstring.h"
+#include "virxml.h"
+
+#include <libxml/xpathInternals.h>
+#include <libxml2/libxml/xmlwriter.h>
+
+#define VIR_FROM_THIS VIR_FROM_VBOX
+VIR_LOG_INIT("vbox.vbox_snapshot_conf");
+
+static vboxSnapshotXmlHardDiskPtr createvboxSnapshotXmlHardDiskPtr(xmlNodePtr diskNode,
+ xmlXPathContextPtr
xPathContext,
+ char
*machineLocation)
+{
+ vboxSnapshotXmlHardDiskPtr hardDisk = NULL;
+ xmlNodePtr *nodes = NULL;
+ char *uuid = NULL;
+ char **searchTabResult = NULL;
+ int resultSize = 0;
+ size_t i = 0;
+ int result = -1;
+ char *location = NULL;
+ char *tmp = NULL;
+ if (VIR_ALLOC(hardDisk) < 0)
+ goto cleanup;
+
+ xPathContext->node = diskNode;
+
+ hardDisk->nchildren = virXPathNodeSet("./vbox:HardDisk", xPathContext,
&nodes);
+ if (hardDisk->nchildren && VIR_ALLOC_N(hardDisk->children,
hardDisk->nchildren) < 0)
+ goto cleanup;
+ for (i = 0; i < hardDisk->nchildren; i++) {
+ hardDisk->children[i] = createvboxSnapshotXmlHardDiskPtr(nodes[i],
xPathContext, machineLocation);
+ if (hardDisk->children[i] == NULL)
+ goto cleanup;
+ hardDisk->children[i]->parent = hardDisk;
+ }
+ uuid = virXMLPropString(diskNode, "uuid");
+ /*we use virStringSearch because the uuid is between brackets*/
+ resultSize = virStringSearch(uuid,
+ VBOX_UUID_REGEX,
+ 1,
+ &searchTabResult);
+ if (resultSize != 1) {
+ virReportError(VIR_ERR_XML_ERROR, "%s"
+ , _("Cannot parse <HardDisk> 'uuid'
attribute"));
+ goto cleanup;
+ }
+ if (VIR_STRDUP(hardDisk->uuid, searchTabResult[0]) < 0)
+ goto cleanup;
+
+ location = virXMLPropString(diskNode, "location");
+ if (location == NULL) {
+ virReportError(VIR_ERR_XML_ERROR, "%s"
+ , _("Cannot parse <HardDisk> 'location'
attribute"));
+ goto cleanup;
+ }
+ if (location[0] != '/') {
+ /*The location is a relative path, so we must change it into an absolute one. */
+ if (virAsprintf(&tmp, "%s%s", machineLocation, location) < 0)
+ goto cleanup;
+ if (VIR_STRDUP(hardDisk->location, tmp) < 0)
+ goto cleanup;
+ } else {
+ if (VIR_STRDUP(hardDisk->location, location) < 0)
+ goto cleanup;
+ }
+ hardDisk->format = virXMLPropString(diskNode, "format");
+ if (hardDisk->format == NULL) {
+ virReportError(VIR_ERR_XML_ERROR, "%s"
+ , _("Cannot parse <HardDisk> 'format'
attribute"));
+ goto cleanup;
+ }
+ hardDisk->type = virXMLPropString(diskNode, "type");
+ result = 0;
+
+ cleanup:
+ VIR_FREE(uuid);
+ VIR_FREE(nodes);
+ VIR_FREE(location);
+ VIR_FREE(tmp);
+ virStringFreeList(searchTabResult);
+ if (result < 0)
+ VIR_FREE(hardDisk);
+ return hardDisk;
+}
+
+static vboxSnapshotXmlMediaRegistryPtr retrieveMediaRegistry(xmlNodePtr
mediaRegistryNode,
+ xmlXPathContextPtr
xPathContext,
+ char *machineLocation)
+{
+ vboxSnapshotXmlMediaRegistryPtr mediaRegistry = NULL;
+ xmlNodePtr hardDisksNode = NULL;
+ xmlNodePtr *nodes = NULL;
+ size_t i = 0;
+ int result = -1;
+
+ if (VIR_ALLOC(mediaRegistry) < 0)
+ goto cleanup;
+
+ xPathContext->node = mediaRegistryNode;
+ hardDisksNode = virXPathNode("./vbox:HardDisks", xPathContext);
+
+ xPathContext->node = hardDisksNode;
+ mediaRegistry->ndisks = virXPathNodeSet("./vbox:HardDisk", xPathContext,
&nodes);
+ if (mediaRegistry->ndisks &&
+ VIR_ALLOC_N(mediaRegistry->disks, mediaRegistry->ndisks) < 0)
+ goto cleanup;
+ for (i = 0; i < mediaRegistry->ndisks; i++) {
+ mediaRegistry->disks[i] = createvboxSnapshotXmlHardDiskPtr(nodes[i],
+ xPathContext,
+ machineLocation);
+ if (mediaRegistry->disks[i] == NULL) {
+ virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+ _("Cannot create a vboxSnapshotXmlHardDisk"));
+ goto cleanup;
+ }
+ }
+ VIR_FREE(nodes);
+
+ xPathContext->node = mediaRegistryNode;
+ mediaRegistry->notherMedia =
virXPathNodeSet("./*[not(self::vbox:HardDisks)]",
+ xPathContext, &nodes);
+ if (mediaRegistry->notherMedia &&
+ VIR_ALLOC_N(mediaRegistry->otherMedia, mediaRegistry->notherMedia) <
0)
+ goto cleanup;
+ for (i = 0; i < mediaRegistry->notherMedia; i++) {
+ mediaRegistry->otherMedia[i] = virXMLNodeToString(mediaRegistryNode->doc,
+ nodes[i]);
+ }
+
+ result = 0;
+
+ cleanup:
+ if (result < 0)
+ VIR_FREE(mediaRegistry);
+ VIR_FREE(nodes);
+ return mediaRegistry;
+}
+
+static vboxSnapshotXmlSnapshotPtr retrieveSnapshot(xmlNodePtr snapshotNode,
+ xmlXPathContextPtr xPathContext)
+{
+ vboxSnapshotXmlSnapshotPtr snapshot = NULL;
+ xmlNodePtr hardwareNode = NULL;
+ xmlNodePtr descriptionNode = NULL;
+ xmlNodePtr storageControllerNode = NULL;
+ xmlNodePtr snapshotsNode = NULL;
+ xmlNodePtr *nodes = NULL;
+ char *uuid = NULL;
+ char **searchTabResult = NULL;
+ int resultSize = 0;
+ size_t i = 0;
+ int result = -1;
+
+ if (VIR_ALLOC(snapshot) < 0)
+ goto cleanup;
+
+ uuid = virXMLPropString(snapshotNode, "uuid");
+ /*we use virStringSearch because the uuid is between brackets*/
+ resultSize = virStringSearch(uuid,
+ VBOX_UUID_REGEX,
+ 1,
+ &searchTabResult);
+ if (resultSize != 1) {
+ virReportError(VIR_ERR_XML_ERROR, "%s"
+ , _("Cannot parse <Snapshot> 'uuid'
attribute"));
+ goto cleanup;
+ }
+ if (VIR_STRDUP(snapshot->uuid, searchTabResult[0]) < 0)
+ goto cleanup;
+
+ snapshot->name = virXMLPropString(snapshotNode, "name");
+ if (snapshot->name == NULL) {
+ virReportError(VIR_ERR_XML_ERROR, "%s"
+ , _("Cannot parse <Snapshot> 'name'
attribute"));
+ goto cleanup;
+ }
+ snapshot->timeStamp = virXMLPropString(snapshotNode, "timeStamp");
+ if (snapshot->timeStamp == NULL) {
+ virReportError(VIR_ERR_XML_ERROR, "%s"
+ , _("Cannot parse <Snapshot> 'timeStamp'
attribute"));
+ goto cleanup;
+ }
+
+ xPathContext->node = snapshotNode;
+ descriptionNode = virXPathNode("./vbox:Description", xPathContext);
+ if (descriptionNode != NULL) {
+ snapshot->description = virXMLNodeToString(descriptionNode->doc,
descriptionNode);
+ }
+
+ hardwareNode = virXPathNode("./vbox:Hardware", xPathContext);
+ if (hardwareNode == NULL) {
+ virReportError(VIR_ERR_XML_ERROR, "%s"
+ , _("Cannot parse <Snapshot> <Hardware>
node"));
+ goto cleanup;
+ }
+ snapshot->hardware = virXMLNodeToString(snapshotNode->doc, hardwareNode);
+
+ storageControllerNode = virXPathNode("./vbox:StorageControllers",
xPathContext);
+ if (storageControllerNode == NULL) {
+ virReportError(VIR_ERR_XML_ERROR, "%s"
+ , _("Cannot parse <Snapshot> <StorageControllers>
node"));
+ goto cleanup;
+ }
+ snapshot->storageController = virXMLNodeToString(snapshotNode->doc,
+ storageControllerNode);
+
+ snapshotsNode = virXPathNode("./vbox:Snapshots", xPathContext);
+
+ if (snapshotsNode != NULL) {
+ xPathContext->node = snapshotsNode;
+ snapshot->nchildren = virXPathNodeSet("./vbox:Snapshot",
xPathContext, &nodes);
+ if (snapshot->nchildren && VIR_ALLOC_N(snapshot->children,
snapshot->nchildren) < 0)
+ goto cleanup;
+ for (i = 0; i < snapshot->nchildren; i++) {
+ snapshot->children[i] = retrieveSnapshot(nodes[i], xPathContext);
+ if (snapshot->children[i] == NULL) {
+ virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+ _("Cannot create a
vboxSnapshotXmlSnapshotPtr"));
+ goto cleanup;
+ }
+ snapshot->children[i]->parent = snapshot;
+ }
+ }
+
+ result = 0;
+
+ cleanup:
+ if (result < 0)
+ VIR_FREE(snapshot);
+ VIR_FREE(nodes);
+ VIR_FREE(uuid);
+ virStringFreeList(searchTabResult);
+ return snapshot;
+}
+
+vboxSnapshotXmlSnapshotPtr snapshotByName(vboxSnapshotXmlSnapshotPtr snapshot,
+ char *snapshotName)
+{
+ size_t i = 0;
+ vboxSnapshotXmlSnapshotPtr ret = NULL;
+ if (STREQ(snapshot->name, snapshotName))
+ return snapshot;
+ for (i = 0; i < snapshot->nchildren; i++) {
+ ret = snapshotByName(snapshot->children[i], snapshotName);
+ if (ret != NULL)
+ return ret;
+ }
+ return ret;
+}
+
+static vboxSnapshotXmlHardDiskPtr hardDiskById(vboxSnapshotXmlHardDiskPtr disk,
+ char *parentHardDiskId)
+{
+ size_t i = 0;
+ vboxSnapshotXmlHardDiskPtr ret = NULL;
+ if (STREQ(disk->uuid, parentHardDiskId))
+ return disk;
+ for (i = 0; i < disk->nchildren; i++) {
+ ret = hardDiskById(disk->children[i], parentHardDiskId);
+ if (ret != NULL)
+ return ret;
+ }
+ return ret;
+}
+
+static vboxSnapshotXmlHardDiskPtr hardDiskByLocation(vboxSnapshotXmlHardDiskPtr disk,
+ char *parentLocation)
+{
+ size_t i = 0;
+ vboxSnapshotXmlHardDiskPtr ret = NULL;
+ if (STREQ(disk->location, parentLocation))
+ return disk;
+ for (i = 0; i < disk->nchildren; i++) {
+ ret = hardDiskByLocation(disk->children[i], parentLocation);
+ if (ret != NULL)
+ return ret;
+ }
+ return ret;
+}
+
+static xmlNodePtr createHardDiskNode(vboxSnapshotXmlHardDiskPtr hardDisk)
+{
+ int result = -1;
+ size_t i = 0;
+ char *uuid = NULL;
+ xmlNodePtr ret = xmlNewNode(NULL, BAD_CAST "HardDisk");
+ if (virAsprintf(&uuid, "{%s}", hardDisk->uuid) < 0)
+ goto cleanup;
+
+ if (xmlNewProp(ret, BAD_CAST "uuid", BAD_CAST uuid) == NULL)
+ goto cleanup;
+ if (xmlNewProp(ret, BAD_CAST "location", BAD_CAST hardDisk->location) ==
NULL)
+ goto cleanup;
+ if (xmlNewProp(ret, BAD_CAST "format", BAD_CAST hardDisk->format) ==
NULL)
+ goto cleanup;
+ if (hardDisk->type != NULL && xmlNewProp(ret, BAD_CAST "type",
BAD_CAST hardDisk->type) == NULL)
+ goto cleanup;
+
+ for (i = 0; i < hardDisk->nchildren; i++) {
+ xmlNodePtr child = createHardDiskNode(hardDisk->children[i]);
+ if (child != NULL)
+ xmlAddChild(ret, child);
+ }
+
+ result = 0;
+ cleanup:
+ if (result < 0) {
+ VIR_FREE(ret);
+ }
+ VIR_FREE(uuid);
+ return ret;
+}
+
+static int serializeSnapshot(xmlNodePtr node, vboxSnapshotXmlSnapshotPtr snapshot)
+{
+ int result = -1;
+ size_t i = 0;
+ xmlNodePtr descriptionNode = NULL;
+ xmlNodePtr snapshotsNode = NULL;
+ xmlNodePtr hardwareNode = NULL;
+ xmlNodePtr storageControllerNode = NULL;
+ xmlParserErrors parseError = XML_ERR_OK;
+ char *uuid = NULL;
+ char *timeStamp = NULL;
+
+ char **firstRegex = NULL;
+ int firstRegexResult = 0;
+ char **secondRegex = NULL;
+ int secondRegexResult = 0;
+
+ if (virAsprintf(&uuid, "{%s}", snapshot->uuid) < 0)
+ goto cleanup;
+
+ if (xmlNewProp(node, BAD_CAST "uuid", BAD_CAST uuid) == NULL)
+ goto cleanup;
+ if (xmlNewProp(node, BAD_CAST "name", BAD_CAST snapshot->name) == NULL)
+ goto cleanup;
+
+ /* We change the date format from "yyyy-MM-dd hh:mm:ss.msec+timeZone"
+ * to "yyyy-MM-ddThh:mm:ssZ"*/
+ firstRegexResult = virStringSearch(snapshot->timeStamp,
+ "([0-9]{4}-[0-9]{2}-[0-9]{2})",
+ 1,
+ &firstRegex);
+ secondRegexResult = virStringSearch(snapshot->timeStamp,
+ "([0-9]{2}:[0-9]{2}:[0-9]{2})",
+ 1,
+ &secondRegex);
+ if (firstRegexResult < 1)
+ goto cleanup;
+ if (secondRegexResult < 1)
+ goto cleanup;
+ if (virAsprintf(&timeStamp, "%sT%sZ", firstRegex[0], secondRegex[0])
< 0)
+ goto cleanup;
+
+ if (xmlNewProp(node, BAD_CAST "timeStamp", BAD_CAST timeStamp) == NULL)
+ goto cleanup;
+
+ /*node description*/
+ if (snapshot->description != NULL) {
+ descriptionNode = xmlNewNode(NULL, BAD_CAST "Description");
+ xmlNodeSetContent(descriptionNode, BAD_CAST snapshot->description);
+ xmlAddChild(node, descriptionNode);
+ }
+ /*hardware*/
+ parseError = xmlParseInNodeContext(node,
+ snapshot->hardware,
+ (int)strlen(snapshot->hardware),
+ 0,
+ &hardwareNode);
+ if (parseError != XML_ERR_OK) {
+ virReportError(VIR_ERR_XML_ERROR, "%s",
+ _("Unable to add the snapshot hardware"));
+ goto cleanup;
+ }
+ xmlAddChild(node, hardwareNode);
+
+ /*storageController*/
+ if (xmlParseInNodeContext(node, snapshot->storageController,
+ (int)strlen(snapshot->storageController),
+ 0,
+ &storageControllerNode) != XML_ERR_OK) {
+ virReportError(VIR_ERR_XML_ERROR, "%s",
+ _("Unable to add the snapshot storageController"));
+ goto cleanup;
+ }
+ xmlAddChild(node, storageControllerNode);
+
+ if (snapshot->nchildren > 0) {
+ snapshotsNode = xmlNewNode(NULL, BAD_CAST "Snapshots");
+ xmlAddChild(node, snapshotsNode);
+ for (i = 0; i < snapshot->nchildren; i++) {
+ xmlNodePtr child = xmlNewNode(NULL, BAD_CAST "Snapshot");
+ xmlAddChild(snapshotsNode, child);
+ if (serializeSnapshot(child, snapshot->children[i]) < 0) {
+ goto cleanup;
+ }
+ }
+ }
+ result = 0;
+
+ cleanup:
+ if (result < 0) {
+ xmlFreeNode(descriptionNode);
+ xmlFreeNode(snapshotsNode);
+ }
+ virStringFreeList(firstRegex);
+ virStringFreeList(secondRegex);
+ VIR_FREE(uuid);
+ VIR_FREE(timeStamp);
+ return result;
+}
+
+static size_t allChild(vboxSnapshotXmlHardDiskPtr disk, vboxSnapshotXmlHardDiskPtr
**list)
+{
+ size_t returnSize = 0;
+ size_t tempSize = 0;
+ vboxSnapshotXmlHardDiskPtr *ret = NULL;
+ vboxSnapshotXmlHardDiskPtr *tempList = NULL;
+ size_t i = 0;
+ size_t j = 0;
+ if (VIR_ALLOC_N(ret, 0) < 0)
+ return 0;
+
+ for (i = 0; i < disk->nchildren; i++) {
+ tempSize = allChild(disk->children[i], &tempList);
+ if (VIR_EXPAND_N(ret, returnSize, tempSize) < 0)
+ return 0;
+
+ for (j = 0; j < tempSize; j++) {
+ ret[returnSize - tempSize + j] = tempList[j];
+ }
+ }
+ if (VIR_EXPAND_N(ret, returnSize, 1) < 0)
+ return 0;
+
+ ret[returnSize - 1] = disk;
+ *list = ret;
+ return returnSize;
+}
+
+/*
+ *vboxSnapshotLoadVboxFile: Create a vboxSnapshotXmlMachinePtr from a VirtualBoxl xml
file.
+ *return an initialized vboxSnapshotXmlMachinePtr on success
+ *return NULL on failure
+ *filePath must not be NULL.
+ */
+vboxSnapshotXmlMachinePtr vboxSnapshotLoadVboxFile(const char *filePath, char
*machineLocation)
+{
+ int ret = -1;
+ vboxSnapshotXmlMachinePtr machineDescription = NULL;
+ xmlDocPtr xml = NULL;
+ xmlNodePtr machineNode = NULL;
+ xmlNodePtr cur = NULL;
+ xmlXPathContextPtr xPathContext = NULL;
+ char *currentStateModifiedString = NULL;
+
+ char **searchResultTab = NULL;
+ ssize_t searchResultSize = 0;
+ char *currentSnapshotAttribute = NULL;
+
+ if (filePath == NULL) {
+ virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+ _("Filepath is Null"));
+ goto cleanup;
+ }
+
+ if (VIR_ALLOC(machineDescription) < 0)
+ goto cleanup;
+
+ xml = virXMLParse(filePath, NULL, NULL);
+ if (xml == NULL) {
+ virReportError(VIR_ERR_XML_ERROR, "%s",
+ _("Unable to parse the xml"));
+ goto cleanup;
+ }
+ if (!(xPathContext = xmlXPathNewContext(xml))) {
+ virReportOOMError();
+ goto cleanup;
+ }
+ if (xmlXPathRegisterNs(xPathContext,
+ BAD_CAST "vbox",
+ BAD_CAST
"http://www.innotek.de/VirtualBox-settings") < 0) {
+ virReportError(VIR_ERR_XML_ERROR, "%s",
+ _("Failed to register xml namespace "
+
"'http://www.innotek.de/VirtualBox-settings'"));
+ goto cleanup;
+ }
+
+ /*Retrieve MachineNode*/
+ cur = xmlDocGetRootElement(xml);
+ xPathContext->node = cur;
+ machineNode = virXPathNode("./vbox:Machine", xPathContext);
+ if (machineNode == NULL) {
+ virReportError(VIR_ERR_XML_ERROR, "%s"
+ , _("Cannot parse <VirtualBox> <Machine>
node"));
+ goto cleanup;
+ }
+
+ machineDescription->uuid = virXMLPropString(machineNode, "uuid");
+ if (machineDescription->uuid == NULL) {
+ virReportError(VIR_ERR_XML_ERROR, "%s"
+ , _("Cannot parse <Machine> 'uuid'
attribute"));
+ goto cleanup;
+ }
+ machineDescription->name = virXMLPropString(machineNode, "name");
+ if (machineDescription->name == NULL) {
+ virReportError(VIR_ERR_XML_ERROR, "%s"
+ , _("Cannot parse <Machine> 'name'
attribute"));
+ goto cleanup;
+ }
+
+ currentSnapshotAttribute = virXMLPropString(machineNode,
"currentSnapshot");
+ if (currentSnapshotAttribute != NULL) {
+ /*we use virStringSearch because the uuid is between brackets*/
+ searchResultSize = virStringSearch(currentSnapshotAttribute,
+ VBOX_UUID_REGEX,
+ 1,
+ &searchResultTab);
+ if (searchResultSize != 1) {
+ virReportError(VIR_ERR_XML_ERROR, "%s"
+ , _("Cannot parse <Machine>
'currentSnapshot' attribute"));
+ goto cleanup;
+ }
+ if (VIR_STRDUP(machineDescription->currentSnapshot, searchResultTab[0]) <
0)
+ goto cleanup;
+ }
+
+
+ machineDescription->snapshotFolder = virXMLPropString(machineNode,
"snapshotFolder");
+ if (machineDescription->snapshotFolder == NULL) {
+ virReportError(VIR_ERR_XML_ERROR, "%s"
+ , _("Cannot parse <Machine> 'snapshotFolder'
attribute"));
+ goto cleanup;
+ }
+
+ currentStateModifiedString = virXMLPropString(machineNode,
"currentStateModified");
+ if (currentStateModifiedString != NULL && STREQ(currentStateModifiedString,
"true")) {
+ machineDescription->currentStateModified = 1;
+ } else {
+ machineDescription->currentStateModified = 0;
+ }
+ machineDescription->lastStateChange = virXMLPropString(machineNode,
"lastStateChange");
+ if (machineDescription->lastStateChange == NULL) {
+ virReportError(VIR_ERR_XML_ERROR, "%s"
+ , _("Cannot parse <Machine> 'lastStateChange'
attribute"));
+ goto cleanup;
+ }
+
+ xPathContext->node = machineNode;
+ cur = virXPathNode("./vbox:Hardware", xPathContext);
+ if (cur == NULL) {
+ virReportError(VIR_ERR_XML_ERROR, "%s"
+ , _("Cannot parse <Machine> <Hardware>
node"));
+ goto cleanup;
+ }
+ machineDescription->hardware = virXMLNodeToString(xml, cur);
+
+ cur = virXPathNode("./vbox:ExtraData", xPathContext);
+ if (cur)
+ machineDescription->extraData = virXMLNodeToString(xml, cur);
+
+ cur = virXPathNode("./vbox:StorageControllers", xPathContext);
+ if (cur == NULL) {
+ virReportError(VIR_ERR_XML_ERROR, "%s"
+ , _("Cannot parse <Machine> <StorageControllers>
node"));
+ goto cleanup;
+ }
+ machineDescription->storageController = virXMLNodeToString(xml, cur);
+
+ /*retrieve mediaRegistry*/
+ cur = virXPathNode("./vbox:MediaRegistry", xPathContext);
+ if (cur == NULL) {
+ virReportError(VIR_ERR_XML_ERROR, "%s"
+ , _("Cannot parse <Machine> <MediaRegistry>
node"));
+ goto cleanup;
+ }
+ machineDescription->mediaRegistry = retrieveMediaRegistry(cur, xPathContext,
machineLocation);
+ if (machineDescription->mediaRegistry == NULL) {
+ virReportError(VIR_ERR_XML_ERROR, "%s",
+ ("Unable to create media registry"));
+ goto cleanup;
+ }
+
+ /*retrieve snapshot*/
+ xPathContext->node = machineNode;
+ cur = virXPathNode("./vbox:Snapshot", xPathContext);
+ if (cur != NULL) {
+ machineDescription->snapshot = retrieveSnapshot(cur, xPathContext);
+ }
+
+ ret = 0;
+
+ cleanup:
+ VIR_FREE(xml);
+ VIR_FREE(xPathContext);
+ VIR_FREE(currentStateModifiedString);
+ virStringFreeList(searchResultTab);
+ if (ret < 0)
+ VIR_FREE(machineDescription);
+ return machineDescription;
+}
+
+/*
+ *addSnapshotToXmlMachine: Add a vboxSnapshotXmlSnapshotPtr to a
vboxSnapshotXmlMachinePtr.
+ *If 'snapshotParentName' is not NULL, the snapshot whose name is
'snapshotParentName'
+ *becomes the snapshot parent.
+ *return 0 on success
+ *return -1 on failure
+ */
+int addSnapshotToXmlMachine(vboxSnapshotXmlSnapshotPtr snapshot,
+ vboxSnapshotXmlMachinePtr machine,
+ char *snapshotParentName)
+{
+ int ret = -1;
+ vboxSnapshotXmlSnapshotPtr parentSnapshot = NULL;
+
+ if (snapshot == NULL) {
+ virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+ _("Snapshot is Null"));
+ goto cleanup;
+ }
+ if (machine == NULL) {
+ virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+ _("Machine is Null"));
+ goto cleanup;
+ }
+
+ /*If parent is NULL and the machine has no snapshot yet,
+ *it means that the added snapshot is the first snapshot*/
+ if (snapshotParentName == NULL) {
+ if (machine->snapshot != NULL) {
+ virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+ _("Unable to add this snapshot, there is already a
snapshot "
+ "linked to the machine"));
+ goto cleanup;
+ }
+ machine->snapshot = snapshot;
+ ret = 0;
+ goto cleanup;
+ } else {
+ if (machine->snapshot == NULL) {
+ virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+ _("The machine has no snapshot and it should have
it"));
+ goto cleanup;
+ }
+ parentSnapshot = snapshotByName(machine->snapshot, snapshotParentName);
+ if (parentSnapshot == NULL) {
+ virReportError(VIR_ERR_INTERNAL_ERROR,
+ _("Unable to find the snapshot %s"),
snapshotParentName);
+ goto cleanup;
+ }
+ if (VIR_EXPAND_N(parentSnapshot->children, parentSnapshot->nchildren, 1)
< 0)
+ goto cleanup;
+
+ parentSnapshot->children[parentSnapshot->nchildren - 1] = snapshot;
+ ret = 0;
+ }
+
+ cleanup:
+ return ret;
+}
+
+/*
+ *addHardDisksToMediaRegistry: Add a vboxSnapshotXmlHardDiskPtr to the registry as a
+ *child of the disk whose uuid is 'parentHardDiskId'.
+ *return 0 on success
+ *return -1 on failure
+ */
+int addHardDiskToMediaRegistry(vboxSnapshotXmlHardDiskPtr hardDisk,
+ vboxSnapshotXmlMediaRegistryPtr mediaRegistry,
+ char *parentHardDiskId)
+{
+ int ret = -1;
+ size_t i = 0;
+ vboxSnapshotXmlHardDiskPtr parentDisk = NULL;
+ if (hardDisk == NULL) {
+ virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+ _("Hard disk is null"));
+ goto cleanup;
+ }
+ if (mediaRegistry == NULL) {
+ virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+ _("Media Registry is null"));
+ goto cleanup;
+ }
+
+ for (i = 0; i < mediaRegistry->ndisks; i++) {
+ parentDisk = hardDiskById(mediaRegistry->disks[i], parentHardDiskId);
+ if (parentDisk != NULL)
+ break;
+ }
+ if (parentDisk == NULL) {
+ virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+ _("Unable to get the parent disk"));
+ goto cleanup;
+ }
+ /*Hard disk found*/
+ if (VIR_EXPAND_N(parentDisk->children, parentDisk->nchildren, 1) < 0)
+ goto cleanup;
+
+ parentDisk->children[parentDisk->nchildren - 1] = hardDisk;
+ if (hardDisk->parent == NULL) {
+ hardDisk->parent = parentDisk;
+ }
+ ret = 0;
+
+ cleanup:
+ return ret;
+}
+
+/*
+ *removeSnapshot: Remove the vboxSnapshotXmlSnapshotPtr whose name is
'snapshotName'
+ *from a vboxSnapshotXmlMachinePtr.
+ *return 0 on success
+ *return -1 on failure
+ */
+int removeSnapshot(vboxSnapshotXmlMachinePtr machine, char *snapshotName)
+{
+ int ret = -1;
+ size_t i = 0;
+ vboxSnapshotXmlSnapshotPtr snapshot = NULL;
+ vboxSnapshotXmlSnapshotPtr parentSnapshot = NULL;
+ if (machine == NULL) {
+ virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+ _("machine is null"));
+ goto cleanup;
+ }
+ if (snapshotName == NULL) {
+ virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+ _("snapshotName is null"));
+ goto cleanup;
+ }
+ if (machine->snapshot == NULL) {
+ virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+ _("the machine has no snapshot"));
+ goto cleanup;
+ }
+ snapshot = snapshotByName(machine->snapshot, snapshotName);
+ if (snapshot == NULL) {
+ virReportError(VIR_ERR_INTERNAL_ERROR,
+ _("Unable to find the snapshot with name %s"),
snapshotName);
+ goto cleanup;
+ }
+ if (snapshot->nchildren > 0) {
+ virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+ _("This snapshot has children, "
+ "please delete theses snapshots before"));
+ goto cleanup;
+ }
+
+ if (snapshot->parent == NULL) {
+ if (machine->snapshot != snapshot) {
+ virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+ _("You are trying to remove a snapshot which does not
exists"));
+ goto cleanup;
+ }
+ machine->snapshot = NULL;
+ VIR_FREE(snapshot);
+ ret = 0;
+ goto cleanup;
+ }
+ parentSnapshot = snapshot->parent;
+
+ snapshot->parent = NULL;
+ while (i < parentSnapshot->nchildren && parentSnapshot->children[i]
!= snapshot) {
+ ++i;
+ }
+ if (VIR_DELETE_ELEMENT(parentSnapshot->children, i, parentSnapshot->nchildren)
< 0)
+ goto cleanup;
+
+ ret = 0;
+ cleanup:
+ return ret;
+}
+
+/*
+ *removeHardDisk: Remove the vboxSnapshotXmlHardDiskPtr whose uuid is 'uuid' from
a
+ *vboxSnapshotXmlMediaRegistryPtr. The hard disk must not have any children.
+ *return 0 on success
+ *return -1 on failure
+ */
+int removeHardDisk(vboxSnapshotXmlMediaRegistryPtr mediaRegistry, char *uuid)
+{
+ int ret = -1;
+ size_t i = 0;
+ vboxSnapshotXmlHardDiskPtr hardDisk = NULL;
+ vboxSnapshotXmlHardDiskPtr parentHardDisk = NULL;
+ if (mediaRegistry == NULL) {
+ virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+ _("Media registry is null"));
+ goto cleanup;
+ }
+ if (uuid == NULL) {
+ virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+ _("Uuid is null"));
+ goto cleanup;
+ }
+
+ for (i = 0; i < mediaRegistry->ndisks; i++) {
+ hardDisk = hardDiskById(mediaRegistry->disks[i], uuid);
+ if (hardDisk != NULL)
+ break;
+ }
+ if (hardDisk == NULL) {
+ virReportError(VIR_ERR_INTERNAL_ERROR,
+ _("Unable to find the hard disk with uuid %s"), uuid);
+ goto cleanup;
+ }
+ if (hardDisk->parent == NULL) {
+ //it means that the hard disk is in 'root'
+ for (i = 0; i < mediaRegistry->ndisks; i++) {
+ if (hardDisk == mediaRegistry->disks[i])
+ break;
+ }
+ if (VIR_DELETE_ELEMENT(mediaRegistry->disks, i, mediaRegistry->ndisks) <
0)
+ goto cleanup;
+ ret = 0;
+ goto cleanup;
+ }
+
+ parentHardDisk = hardDisk->parent;
+ i = 0;
+ while (i < parentHardDisk->nchildren && parentHardDisk->children[i]
!= hardDisk) {
+ ++i;
+ }
+ hardDisk->parent = NULL;
+ if (VIR_DELETE_ELEMENT(parentHardDisk->children, i, parentHardDisk->nchildren)
< 0)
+ goto cleanup;
+ ret = 0;
+
+ cleanup:
+ return ret;
+}
+
+/*vboxSnapshotSaveVboxFile: Create a VirtualBox XML file from a
vboxSnapshotXmlMachinePtr.
+ *The file is saved at 'filePath'.
+ *return 0 on success
+ *return -1 on failure
+ */
+int vboxSnapshotSaveVboxFile(vboxSnapshotXmlMachinePtr machine, const char *filePath)
+{
+ int ret = -1;
+ size_t i = 0;
+ xmlDocPtr xml = NULL;
+ xmlTextWriterPtr writer = NULL;
+ xmlNodePtr mediaRegistryNode = NULL;
+ xmlNodePtr snapshotNode = NULL;
+ xmlNodePtr machineNode = NULL;
+ xmlNodePtr hardDisksNode = NULL;
+ xmlXPathContextPtr xPathContext = NULL;
+ char *currentSnapshot = NULL;
+ char *timeStamp = NULL;
+
+ char **firstRegex = NULL;
+ int firstRegexResult = 0;
+ char **secondRegex = NULL;
+ int secondRegexResult = 0;
+
+ if (machine == NULL) {
+ virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+ _("Machine is null"));
+ goto cleanup;
+ }
+ if (filePath == NULL) {
+ virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+ _("Filepath is null"));
+ goto cleanup;
+ }
+ xml = xmlNewDoc(BAD_CAST "1.0");
+ writer = xmlNewTextWriterDoc(&xml, 0);
+ //writting raw data first
+ if (xmlTextWriterStartDocument(writer, NULL, "ISO-8859-1", NULL) < 0) {
+ virReportError(VIR_ERR_XML_ERROR, "%s",
+ _("Error at xmlTextWriterStartDocument"));
+ 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 */
+ if (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") < 0) {
+ virReportError(VIR_ERR_XML_ERROR, "%s",
+ _("Error at xmlTextWriterWriteFormatComment"));
+ goto cleanup;
+ }
+ if (xmlTextWriterWriteRaw(writer, BAD_CAST "\n") < 0) {
+ virReportError(VIR_ERR_XML_ERROR, "%s",
+ _("Error at xmlTextWriterWriteRaw"));
+ goto cleanup;
+ }
+ /*Start an element named "VirtualBox". Since this is the first element,
+ *this will we be root element of the document*/
+ if (xmlTextWriterStartElement(writer, BAD_CAST "VirtualBox") < 0) {
+ virReportError(VIR_ERR_XML_ERROR, "%s",
+ _("Error at xmlTextWriterStartDocument"));
+ goto cleanup;
+ }
+ if (xmlTextWriterWriteAttribute(writer, BAD_CAST "version", BAD_CAST
"1.12-linux") < 0) {
+ virReportError(VIR_ERR_XML_ERROR, "%s",
+ _("Error at xmlTextWriterWriteAttribute"));
+ goto cleanup;
+ }
+ /*Start an element named "Machine" as child of VirtualBox.*/
+ if (xmlTextWriterStartElement(writer, BAD_CAST "Machine") < 0) {
+ virReportError(VIR_ERR_XML_ERROR, "%s",
+ _("Error at xmlTextWriterStartElement"));
+ goto cleanup;
+ }
+ //Settings machine Attributes
+ if (xmlTextWriterWriteAttribute(writer, BAD_CAST "uuid", BAD_CAST
machine->uuid) < 0) {
+ virReportError(VIR_ERR_XML_ERROR, "%s",
+ _("Error at xmlTextWriterWriteAttribute"));
+ goto cleanup;
+ }
+ if (xmlTextWriterWriteAttribute(writer, BAD_CAST "name", BAD_CAST
machine->name) < 0) {
+ virReportError(VIR_ERR_XML_ERROR, "%s",
+ _("Error at xmlTextWriterWriteAttribute"));
+ goto cleanup;
+ }
+ if (machine->currentSnapshot != NULL) {
+ if (virAsprintf(¤tSnapshot, "{%s}",
machine->currentSnapshot) < 0)
+ goto cleanup;
+ if (xmlTextWriterWriteAttribute(writer,
+ BAD_CAST "currentSnapshot",
+ BAD_CAST currentSnapshot) < 0) {
+ virReportError(VIR_ERR_XML_ERROR, "%s",
+ _("Error at xmlTextWriterWriteAttribute"));
+ goto cleanup;
+ }
+ }
+ if (xmlTextWriterWriteAttribute(writer,
+ BAD_CAST "snapshotFolder",
+ BAD_CAST machine->snapshotFolder) < 0) {
+ virReportError(VIR_ERR_XML_ERROR, "%s",
+ _("Error at xmlTextWriterWriteAttribute"));
+ goto cleanup;
+ }
+ if (xmlTextWriterWriteAttribute(writer,
+ BAD_CAST "currentStateModified",
+ BAD_CAST(machine->currentStateModified == 0 ?
"false" : "true")) < 0) {
+ virReportError(VIR_ERR_XML_ERROR, "%s",
+ _("Error at xmlTextWriterWriteAttribute"));
+ goto cleanup;
+ }
+ if (xmlTextWriterWriteAttribute(writer, BAD_CAST "OSType", BAD_CAST
"Other") < 0) {
+ virReportError(VIR_ERR_XML_ERROR, "%s",
+ _("Error at xmlTextWriterWriteAttribute"));
+ goto cleanup;
+ }
+
+ firstRegexResult = virStringSearch(machine->lastStateChange,
+ "([0-9]{4}-[0-9]{2}-[0-9]{2})",
+ 1,
+ &firstRegex);
+ secondRegexResult = virStringSearch(machine->lastStateChange,
+ "([0-9]{2}:[0-9]{2}:[0-9]{2})",
+ 1,
+ &secondRegex);
+ if (firstRegexResult < 1)
+ goto cleanup;
+ if (secondRegexResult < 1)
+ goto cleanup;
+
+ if (virAsprintf(&timeStamp, "%sT%sZ", firstRegex[0], secondRegex[0])
< 0)
+ goto cleanup;
+
+ if (xmlTextWriterWriteAttribute(writer,
+ BAD_CAST "lastStateChange",
+ BAD_CAST timeStamp) < 0) {
+ virReportError(VIR_ERR_XML_ERROR, "%s",
+ _("Error at xmlTextWriterWriteAttribute"));
+ goto cleanup;
+ }
+ if (xmlTextWriterStartElement(writer, BAD_CAST "MediaRegistry") < 0) {
+ virReportError(VIR_ERR_XML_ERROR, "%s",
+ _("Error at xmlTextWriterStartElement"));
+ goto cleanup;
+ }
+ for (i = 0; i < machine->mediaRegistry->notherMedia; i++) {
+ if (xmlTextWriterWriteRaw(writer,
+ BAD_CAST machine->mediaRegistry->otherMedia[i])
< 0) {
+ virReportError(VIR_ERR_XML_ERROR, "%s",
+ _("Error at xmlTextWriterWriteRaw"));
+ goto cleanup;
+ }
+ }
+ if (xmlTextWriterEndElement(writer) < 0) {
+ virReportError(VIR_ERR_XML_ERROR, "%s",
+ _("Error at xmlTextWriterEndElement"));
+ goto cleanup;
+ }
+ if (xmlTextWriterWriteRaw(writer, BAD_CAST machine->hardware) < 0) {
+ virReportError(VIR_ERR_XML_ERROR, "%s",
+ _("Error at xmlTextWriterWriteRaw"));
+ goto cleanup;
+ }
+ if (machine->extraData != NULL &&
+ xmlTextWriterWriteRaw(writer, BAD_CAST machine->extraData) < 0) {
+ virReportError(VIR_ERR_XML_ERROR, "%s",
+ _("Error at xmlTextWriterWriteRaw"));
+ goto cleanup;
+ }
+ if (xmlTextWriterWriteRaw(writer, BAD_CAST machine->storageController) < 0) {
+ virReportError(VIR_ERR_XML_ERROR, "%s",
+ _("Error at xmlTextWriterWriteRaw"));
+ goto cleanup;
+ }
+ if (xmlTextWriterEndDocument(writer) < 0) {
+ virReportError(VIR_ERR_XML_ERROR, "%s",
+ _("Error at xmlTextWriterEndDocument"));
+ goto cleanup;
+ }
+
+ if (!(xPathContext = xmlXPathNewContext(xml))) {
+ virReportOOMError();
+ goto cleanup;
+ }
+
+ /*Retrieve MediaRegistryNode*/
+ xPathContext->node = xmlDocGetRootElement(xml);
+ machineNode = virXPathNode("./Machine", xPathContext);
+ if (machineNode == NULL) {
+ virReportError(VIR_ERR_XML_ERROR, "%s",
+ _("Cannot parse <VirtualBox> <Machine>
node"));
+ goto cleanup;
+ }
+
+ xPathContext->node = machineNode;
+ mediaRegistryNode = virXPathNode("./MediaRegistry", xPathContext);
+
+ hardDisksNode = xmlNewNode(NULL, BAD_CAST "HardDisks");
+ for (i = 0; i < machine->mediaRegistry->ndisks; i++) {
+ xmlNodePtr child = createHardDiskNode(machine->mediaRegistry->disks[i]);
+ if (child != NULL)
+ xmlAddChild(hardDisksNode, child);
+ }
+ xmlAddChild(mediaRegistryNode, hardDisksNode);
+
+ if (machine->snapshot != NULL) {
+ snapshotNode = xmlNewNode(NULL, BAD_CAST "Snapshot");
+ xmlAddChild(machineNode, snapshotNode);
+ if (serializeSnapshot(snapshotNode, machine->snapshot) < 0) {
+ virReportError(VIR_ERR_XML_ERROR, "%s",
+ _("Failed to serialize snapshot"));
+ goto cleanup;
+ }
+ }
+ /*Adding namespace*/
+ if (xmlNewProp(xmlDocGetRootElement(xml),
+ BAD_CAST "xmlns",
+ BAD_CAST "http://www.innotek.de/VirtualBox-settings") ==
NULL) {
+ virReportError(VIR_ERR_XML_ERROR, "%s",
+ _("Error in xmlNewProp"));
+ goto cleanup;
+ }
+
+ if (xmlSaveFormatFileEnc(filePath, xml, "ISO-8859-1", -1) < 0) {
+ virReportError(VIR_ERR_XML_ERROR, "%s",
+ _("Unable to save the xml"));
+ goto cleanup;
+ }
+ ret = 0;
+
+ cleanup:
+ VIR_FREE(currentSnapshot);
+ VIR_FREE(timeStamp);
+ xmlFreeTextWriter(writer);
+ xmlFreeDoc(xml);
+ virStringFreeList(firstRegex);
+ virStringFreeList(secondRegex);
+ return ret;
+}
+
+/*
+ *isCurrentSnapshot: Return 1 if 'snapshotName' corresponds to the
+ *vboxSnapshotXmlMachinePtr's current snapshot, return 0 otherwise.
+ */
+int isCurrentSnapshot(vboxSnapshotXmlMachinePtr machine, char *snapshotName)
+{
+ vboxSnapshotXmlSnapshotPtr snapshot = NULL;
+ if (machine == NULL) {
+ virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+ _("Machine is null"));
+ goto cleanup;
+ }
+ if (snapshotName == NULL) {
+ virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+ _("snapshotName is null"));
+ goto cleanup;
+ }
+ snapshot = snapshotByName(machine->snapshot, snapshotName);
+ return STREQ(snapshot->uuid, machine->currentSnapshot);
+
+ cleanup:
+ return 0;
+}
+
+/*
+ *getRWDisksPathsFromLibvirtXML: Parse a libvirt XML snapshot file, allocates and
+ *fills a list of read-write disk paths.
+ *return array length on success, -1 on failure.
+ */
+int getRWDisksPathsFromLibvirtXML(char *filePath, char ***rwDisksPath)
+{
+ int result = -1;
+ size_t i = 0;
+ char **ret;
+ xmlDocPtr xml = NULL;
+ xmlXPathContextPtr xPathContext = NULL;
+ xmlNodePtr *nodes = NULL;
+ int nodeSize = 0;
+ if (filePath == NULL) {
+ virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+ _("filePath is null"));
+ goto cleanup;
+ }
+ xml = virXMLParse(filePath, NULL, NULL);
+ if (xml == NULL) {
+ virReportError(VIR_ERR_XML_ERROR, "%s",
+ _("Unable to parse the xml"));
+ goto cleanup;
+ }
+ if (!(xPathContext = xmlXPathNewContext(xml))) {
+ virReportOOMError();
+ goto cleanup;
+ }
+ xPathContext->node = xmlDocGetRootElement(xml);
+ nodeSize = virXPathNodeSet("/domainsnapshot/disks/disk", xPathContext,
&nodes);
+
+ if (VIR_ALLOC_N(ret, nodeSize) < 0)
+ goto cleanup;
+
+ for (i = 0; i < nodeSize; i++) {
+ xmlNodePtr node = nodes[i];
+ xPathContext->node = node;
+ xmlNodePtr sourceNode = virXPathNode("./source", xPathContext);
+ if (sourceNode) {
+ ret[i] = virXMLPropString(sourceNode, "file");
+ }
+ }
+ result = 0;
+
+ cleanup:
+ VIR_FREE(xml);
+ VIR_FREE(xPathContext);
+ if (result < 0) {
+ virStringFreeList(ret);
+ nodeSize = -1;
+ }
+ *rwDisksPath = ret;
+ return nodeSize;
+}
+
+/*
+ *getRODisksPathsFromLibvirtXML: *Parse a libvirt XML snapshot file, allocates and fills
+ *a list of read-only disk paths (the parents of the read-write disks).
+ *return array length on success, -1 on failure.
+ */
+int getRODisksPathsFromLibvirtXML(char *filePath, char ***roDisksPath)
+{
+ int result = -1;
+ size_t i = 0;
+ char **ret;
+ xmlDocPtr xml = NULL;
+ xmlXPathContextPtr xPathContext = NULL;
+ xmlNodePtr *nodes = NULL;
+ int nodeSize = 0;
+ if (filePath == NULL) {
+ virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+ _("filePath is null"));
+ goto cleanup;
+ }
+ xml = virXMLParse(filePath, NULL, NULL);
+ if (xml == NULL) {
+ virReportError(VIR_ERR_XML_ERROR, "%s",
+ _("Unable to parse the xml"));
+ goto cleanup;
+ }
+ if (!(xPathContext = xmlXPathNewContext(xml))) {
+ virReportOOMError();
+ goto cleanup;
+ }
+ xPathContext->node = xmlDocGetRootElement(xml);
+ nodeSize = virXPathNodeSet("/domainsnapshot/domain/devices/disk",
+ xPathContext,
+ &nodes);
+ if (VIR_ALLOC_N(ret, nodeSize) < 0)
+ goto cleanup;
+
+ for (i = 0; i < nodeSize; i++) {
+ xmlNodePtr node = nodes[i];
+ xPathContext->node = node;
+ xmlNodePtr sourceNode = virXPathNode("./source", xPathContext);
+ if (sourceNode) {
+ ret[i] = virXMLPropString(sourceNode, "file");
+ }
+ }
+ result = 0;
+
+ cleanup:
+ xmlFreeDoc(xml);
+ xmlXPathFreeContext(xPathContext);
+ if (result < 0) {
+ virStringFreeList(ret);
+ nodeSize = -1;
+ }
+ *roDisksPath = ret;
+ return nodeSize;
+}
+
+/*
+ *hardDiskUuidByLocation: Return the uuid of the hard disk whose location is
'location'
+ *return a valid uuid, or NULL on failure
+ */
+char *hardDiskUuidByLocation(vboxSnapshotXmlMachinePtr machine, char *location)
+{
+ size_t i = 0;
+ vboxSnapshotXmlHardDiskPtr hardDisk = NULL;
+ for (i = 0; i < machine->mediaRegistry->ndisks; i++) {
+ hardDisk = hardDiskByLocation(machine->mediaRegistry->disks[i], location);
+ if (hardDisk != NULL)
+ break;
+ }
+ if (hardDisk == NULL)
+ return NULL;
+ return hardDisk->uuid;
+}
+
+/*Retreive the whole ancestry of the vboxSnapshotXmlHardDiskPtr whose location is
+ *'location', and store them in a newly allocated list of
vboxSnapshotXmlHardDiskPtr.
+ *This list begins with the requested disk, and ends with the farthest ancestor.
+ *return array length on success, -1 on failure.*/
+
+size_t diskListToOpen(vboxSnapshotXmlMachinePtr machine,
+ vboxSnapshotXmlHardDiskPtr **hardDiskToOpen,
+ char *location)
+{
+ size_t i = 0;
+ size_t returnSize = 0;
+ vboxSnapshotXmlHardDiskPtr *ret = NULL;
+ vboxSnapshotXmlHardDiskPtr hardDisk = NULL;
+ for (i = 0; i < machine->mediaRegistry->ndisks; i++) {
+ hardDisk = hardDiskByLocation(machine->mediaRegistry->disks[i], location);
+ if (hardDisk != NULL)
+ break;
+ }
+ if (hardDisk == NULL)
+ return 0;
+ if (VIR_ALLOC_N(ret, 1) < 0)
+ return 0;
+
+ returnSize = 1;
+ ret[returnSize - 1] = hardDisk;
+
+ while (hardDisk->parent != NULL) {
+ if (VIR_EXPAND_N(ret, returnSize, 1) < 0)
+ return 0;
+ ret[returnSize - 1] = hardDisk->parent;
+ hardDisk = hardDisk->parent;
+ }
+ *hardDiskToOpen = ret;
+ return returnSize;
+}
+
+/*
+ *removeFakeDisks: Remove all fake disks from the machine's mediaRegistry
+ *return 0 on success
+ *return -1 on failure
+ */
+int removeFakeDisks(vboxSnapshotXmlMachinePtr machine)
+{
+ int ret = -1;
+ size_t i = 0;
+ size_t j = 0;
+ size_t tempSize = 0;
+ size_t diskSize = 0;
+ vboxSnapshotXmlHardDiskPtr *tempList = NULL;
+ vboxSnapshotXmlHardDiskPtr *diskList = NULL;
+ if (VIR_ALLOC_N(diskList, 0) < 0)
+ return ret;
+
+ for (i = 0; i < machine->mediaRegistry->ndisks; i++) {
+ tempSize = allChild(machine->mediaRegistry->disks[i], &tempList);
+ if (VIR_EXPAND_N(diskList, diskSize, tempSize) < 0)
+ return ret;
+ for (j = 0; j < tempSize; j++) {
+ diskList[diskSize - tempSize + j] = tempList[j];
+ }
+ }
+ for (i = 0; i < diskSize; i++) {
+ if (strstr(diskList[i]->location, "fake") != NULL) {
+ if (removeHardDisk(machine->mediaRegistry, diskList[i]->uuid) < 0)
{
+ virReportError(VIR_ERR_INTERNAL_ERROR,
+ _("Unable to remove hard disk %s from media
registry"),
+ diskList[i]->location);
+ return ret;
+ }
+ }
+ }
+ ret = 0;
+ return ret;
+}
+
+/*
+ *diskIsInMediaRegistry: Check if the media registry contains the disk whose location is
'location'.
+ *return 0 if the disk is not in the media registry
+ *return 1 if the disk is in the media registry
+ *return -1 on failure
+ */
+int diskIsInMediaRegistry(vboxSnapshotXmlMachinePtr machine, char *location)
+{
+ int ret = -1;
+ size_t i = 0;
+ size_t j = 0;
+ size_t tempSize = 0;
+ size_t diskSize = 0;
+ vboxSnapshotXmlHardDiskPtr *tempList = NULL;
+ vboxSnapshotXmlHardDiskPtr *diskList = NULL;
+ if (VIR_ALLOC_N(diskList, 0) < 0)
+ return ret;
+
+ for (i = 0; i < machine->mediaRegistry->ndisks; i++) {
+ tempSize = allChild(machine->mediaRegistry->disks[i], &tempList);
+ if (VIR_EXPAND_N(diskList, diskSize, tempSize) < 0)
+ return ret;
+ for (j = 0; j < tempSize; j++) {
+ diskList[diskSize - tempSize + j] = tempList[j];
+ }
+ }
+ for (i = 0; i < diskSize; i++) {
+ if (STREQ(diskList[i]->location, location)) {
+ ret = 1;
+ return ret;
+ }
+ }
+ ret = 0;
+ return ret;
+}
+
+/*
+ *hardDisksPtrByLocation: Return a vboxSnapshotXmlHardDiskPtr whose location is
'location'
+ */
+vboxSnapshotXmlHardDiskPtr hardDiskPtrByLocation(vboxSnapshotXmlMachinePtr machine, char
*location)
+{
+ int it = 0;
+ vboxSnapshotXmlHardDiskPtr disk = NULL;
+ for (it = 0; it < machine->mediaRegistry->ndisks; it++) {
+ disk = hardDiskByLocation(machine->mediaRegistry->disks[it], location);
+ if (disk != NULL)
+ break;
+ }
+ return disk;
+}
diff --git a/src/vbox/vbox_snapshot_conf.h b/src/vbox/vbox_snapshot_conf.h
new file mode 100644
index 0000000..d2352cb
--- /dev/null
+++ b/src/vbox/vbox_snapshot_conf.h
@@ -0,0 +1,100 @@
+/*
+ * Copyright 2014, diateam (
www.diateam.net)
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see
+ * <
http://www.gnu.org/licenses/>.
+ */
+
+#ifndef VBOX_SNAPSHOT_CONF_H
+# define VBOX_SNAPSHOT_CONF_H
+
+# include "internal.h"
+
+# define VBOX_UUID_REGEX
"([a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12})"
+
+/*Stores VirtualBox xml hard disk information
+A hard disk can have a parent and children*/
+typedef struct _vboxSnapshotXmlHardDisk vboxSnapshotXmlHardDisk;
+typedef vboxSnapshotXmlHardDisk *vboxSnapshotXmlHardDiskPtr;
+struct _vboxSnapshotXmlHardDisk {
+ vboxSnapshotXmlHardDiskPtr parent;
+ char *uuid;
+ char *location;
+ char *format;
+ char *type;
+ size_t nchildren;
+ vboxSnapshotXmlHardDiskPtr *children;
+};
+
+/*Stores Virtualbox xml media registry information
+We separate disks from other media to manipulate them*/
+typedef struct _vboxSnapshotXmlMediaRegistry vboxSnapshotXmlMediaRegistry;
+typedef vboxSnapshotXmlMediaRegistry *vboxSnapshotXmlMediaRegistryPtr;
+struct _vboxSnapshotXmlMediaRegistry {
+ size_t ndisks;
+ vboxSnapshotXmlHardDiskPtr *disks;
+ size_t notherMedia;
+ char **otherMedia;
+};
+
+/*Stores VirtualBox xml snapshot information
+A snapshot can have a parent and children*/
+typedef struct _vboxSnapshotXmlSnapshot vboxSnapshotXmlSnapshot;
+typedef vboxSnapshotXmlSnapshot *vboxSnapshotXmlSnapshotPtr;
+struct _vboxSnapshotXmlSnapshot {
+ vboxSnapshotXmlSnapshotPtr parent;
+ char *uuid;
+ char *name;
+ char *timeStamp;
+ char *description;
+ char *hardware;
+ char *storageController;
+ size_t nchildren;
+ vboxSnapshotXmlSnapshotPtr *children;
+};
+
+/*Stores VirtualBox xml Machine information*/
+typedef struct _vboxSnapshotXmlMachine vboxSnapshotXmlMachine;
+typedef vboxSnapshotXmlMachine *vboxSnapshotXmlMachinePtr;
+struct _vboxSnapshotXmlMachine {
+ char *uuid;
+ char *name;
+ char *currentSnapshot;
+ char *snapshotFolder;
+ int currentStateModified;
+ char *lastStateChange;
+ vboxSnapshotXmlMediaRegistryPtr mediaRegistry;
+ char *hardware;
+ char *extraData;
+ vboxSnapshotXmlSnapshotPtr snapshot;
+ char *storageController;
+};
+
+vboxSnapshotXmlMachinePtr vboxSnapshotLoadVboxFile(const char *filePath, char
*machineLocation);
+int addSnapshotToXmlMachine(vboxSnapshotXmlSnapshotPtr snapshot,
vboxSnapshotXmlMachinePtr machine, char *snapshotParentName);
+int addHardDiskToMediaRegistry(vboxSnapshotXmlHardDiskPtr hardDisk,
vboxSnapshotXmlMediaRegistryPtr mediaRegistry, char *parentHardDiskId);
+int removeSnapshot(vboxSnapshotXmlMachinePtr machine, char *snapshotName);
+int removeHardDisk(vboxSnapshotXmlMediaRegistryPtr mediaRegistry,char *uuid);
+int vboxSnapshotSaveVboxFile(vboxSnapshotXmlMachinePtr machine, const char *filePath);
+int isCurrentSnapshot(vboxSnapshotXmlMachinePtr machine, char *snapshotName);
+int getRWDisksPathsFromLibvirtXML(char *filePath, char ***realReadWriteDisksPath);
+int getRODisksPathsFromLibvirtXML(char *filePath, char ***realReadOnlyDisksPath);
+char *hardDiskUuidByLocation(vboxSnapshotXmlMachinePtr machine, char *location);
+size_t diskListToOpen(vboxSnapshotXmlMachinePtr machine, vboxSnapshotXmlHardDiskPtr
**hardDiskToOpen, char *location);
+int removeFakeDisks(vboxSnapshotXmlMachinePtr machine);
+int diskIsInMediaRegistry(vboxSnapshotXmlMachinePtr machine, char *location);
+vboxSnapshotXmlHardDiskPtr hardDiskPtrByLocation(vboxSnapshotXmlMachinePtr machine, char
*location);
+vboxSnapshotXmlSnapshotPtr snapshotByName(vboxSnapshotXmlSnapshotPtr snapshot, char
*snapshotName);
+
+#endif /*VBOX_SNAPSHOT_CONF_H*/
--
1.7.10.4