return vzDomainSetMemoryFlagsImpl(domain, memory, 0, false);
}
+static virDomainSnapshotObjPtr
+vzSnapObjFromName(virDomainSnapshotObjListPtr snapshots, const char *name)
+{
+ virDomainSnapshotObjPtr snap = NULL;
+ snap = virDomainSnapshotFindByName(snapshots, name);
+ if (!snap)
+ virReportError(VIR_ERR_NO_DOMAIN_SNAPSHOT,
+ _("no domain snapshot with matching name '%s'"), name);
+
+ return snap;
+}
+
+static virDomainSnapshotObjPtr
+vzSnapObjFromSnapshot(virDomainSnapshotObjListPtr snapshots,
+ virDomainSnapshotPtr snapshot)
+{
+ return vzSnapObjFromName(snapshots, snapshot->name);
+}
+
+static int
+vzCurrentSnapshotIterator(void *payload,
+ const void *name ATTRIBUTE_UNUSED,
+ void *data)
+{
+ virDomainSnapshotObjPtr snapshot = payload;
+ virDomainSnapshotObjPtr *current = data;
+
+ if (snapshot->def->current)
+ *current = snapshot;
+
+ return 0;
+}
+
+static virDomainSnapshotObjPtr
+vzFindCurrentSnapshot(virDomainSnapshotObjListPtr snapshots)
+{
+ virDomainSnapshotObjPtr current = NULL;
+
+ virDomainSnapshotForEach(snapshots, vzCurrentSnapshotIterator, ¤t);
+ return current;
+}
+
+static int
+vzDomainSnapshotNum(virDomainPtr domain, unsigned int flags)
+{
+ virDomainObjPtr dom;
+ virDomainSnapshotObjListPtr snapshots = NULL;
+ int n = -1;
+
+ virCheckFlags(VIR_DOMAIN_SNAPSHOT_LIST_ROOTS |
+ VIR_DOMAIN_SNAPSHOT_FILTERS_ALL, -1);
+
+ if (!(dom = vzDomObjFromDomain(domain)))
+ return -1;
+
+ if (!(snapshots = prlsdkLoadSnapshots(dom)))
+ goto cleanup;
+
+ n = virDomainSnapshotObjListNum(snapshots, NULL, flags);
+
+ cleanup:
+ virDomainSnapshotObjListFree(snapshots);
+ virObjectUnlock(dom);
+
+ return n;
+}
+
+static int
+vzDomainSnapshotListNames(virDomainPtr domain,
+ char **names,
+ int nameslen,
+ unsigned int flags)
+{
+ virDomainObjPtr dom;
+ virDomainSnapshotObjListPtr snapshots = NULL;
+ int n = -1;
+
+ virCheckFlags(VIR_DOMAIN_SNAPSHOT_LIST_ROOTS |
+ VIR_DOMAIN_SNAPSHOT_FILTERS_ALL, -1);
+
+ if (!(dom = vzDomObjFromDomain(domain)))
+ return -1;
+
+ if (!(snapshots = prlsdkLoadSnapshots(dom)))
+ goto cleanup;
+
+ n = virDomainSnapshotObjListGetNames(snapshots, NULL, names, nameslen, flags);
+
+ cleanup:
+ virDomainSnapshotObjListFree(snapshots);
+ virObjectUnlock(dom);
+
+ return n;
+}
+
+static int
+vzDomainListAllSnapshots(virDomainPtr domain,
+ virDomainSnapshotPtr **snaps,
+ unsigned int flags)
+{
+ virDomainObjPtr dom;
+ virDomainSnapshotObjListPtr snapshots = NULL;
+ int n = -1;
+
+ virCheckFlags(VIR_DOMAIN_SNAPSHOT_LIST_ROOTS |
+ VIR_DOMAIN_SNAPSHOT_FILTERS_ALL, -1);
+
+ if (!(dom = vzDomObjFromDomain(domain)))
+ return -1;
+
+ if (!(snapshots = prlsdkLoadSnapshots(dom)))
+ goto cleanup;
+
+ n = virDomainListSnapshots(snapshots, NULL, domain, snaps, flags);
+
+ cleanup:
+ virDomainSnapshotObjListFree(snapshots);
+ virObjectUnlock(dom);
+
+ return n;
+}
+
+static char *
+vzDomainSnapshotGetXMLDesc(virDomainSnapshotPtr snapshot, unsigned int flags)
+{
+ virDomainObjPtr dom;
+ char *xml = NULL;
+ virDomainSnapshotObjPtr snap;
+ char uuidstr[VIR_UUID_STRING_BUFLEN];
+ virDomainSnapshotObjListPtr snapshots = NULL;
+ vzConnPtr privconn = snapshot->domain->conn->privateData;
+
+ virCheckFlags(VIR_DOMAIN_XML_SECURE, NULL);
+
+ if (!(dom = vzDomObjFromDomain(snapshot->domain)))
+ return NULL;
+
+ if (!(snapshots = prlsdkLoadSnapshots(dom)))
+ goto cleanup;
+
+ if (!(snap = vzSnapObjFromSnapshot(snapshots, snapshot)))
+ goto cleanup;
+
+ virUUIDFormat(snapshot->domain->uuid, uuidstr);
+
+ xml = virDomainSnapshotDefFormat(uuidstr, snap->def, privconn->driver->caps,
+ virDomainDefFormatConvertXMLFlags(flags),
+ 0);
+
+ cleanup:
+ virDomainSnapshotObjListFree(snapshots);
+ virObjectUnlock(dom);
+
+ return xml;
+}
+
+static int
+vzDomainSnapshotNumChildren(virDomainSnapshotPtr snapshot, unsigned int flags)
+{
+ virDomainObjPtr dom;
+ virDomainSnapshotObjPtr snap;
+ virDomainSnapshotObjListPtr snapshots = NULL;
+ int n = -1;
+
+ virCheckFlags(VIR_DOMAIN_SNAPSHOT_LIST_DESCENDANTS |
+ VIR_DOMAIN_SNAPSHOT_FILTERS_ALL, -1);
+
+ if (!(dom = vzDomObjFromDomain(snapshot->domain)))
+ return -1;
+
+ if (!(snapshots = prlsdkLoadSnapshots(dom)))
+ goto cleanup;
+
+ if (!(snap = vzSnapObjFromSnapshot(snapshots, snapshot)))
+ goto cleanup;
+
+ n = virDomainSnapshotObjListNum(snapshots, snap, flags);
+
+ cleanup:
+ virDomainSnapshotObjListFree(snapshots);
+ virObjectUnlock(dom);
+
+ return n;
+}
+
+static int
+vzDomainSnapshotListChildrenNames(virDomainSnapshotPtr snapshot,
+ char **names,
+ int nameslen,
+ unsigned int flags)
+{
+ virDomainObjPtr dom;
+ virDomainSnapshotObjPtr snap;
+ virDomainSnapshotObjListPtr snapshots = NULL;
+ int n = -1;
+
+ virCheckFlags(VIR_DOMAIN_SNAPSHOT_LIST_DESCENDANTS |
+ VIR_DOMAIN_SNAPSHOT_FILTERS_ALL, -1);
+
+ if (!(dom = vzDomObjFromDomain(snapshot->domain)))
+ return -1;
+
+ if (!(snapshots = prlsdkLoadSnapshots(dom)))
+ goto cleanup;
+
+ if (!(snap = vzSnapObjFromSnapshot(snapshots, snapshot)))
+ goto cleanup;
+
+ n = virDomainSnapshotObjListGetNames(snapshots, snap, names, nameslen, flags);
+
+ cleanup:
+ virDomainSnapshotObjListFree(snapshots);
+ virObjectUnlock(dom);
+
+ return n;
+}
+
+static int
+vzDomainSnapshotListAllChildren(virDomainSnapshotPtr snapshot,
+ virDomainSnapshotPtr **snaps,
+ unsigned int flags)
+{
+ virDomainObjPtr dom;
+ virDomainSnapshotObjPtr snap;
+ virDomainSnapshotObjListPtr snapshots = NULL;
+ int n = -1;
+
+ virCheckFlags(VIR_DOMAIN_SNAPSHOT_LIST_DESCENDANTS |
+ VIR_DOMAIN_SNAPSHOT_FILTERS_ALL, -1);
+
+ if (!(dom = vzDomObjFromDomain(snapshot->domain)))
+ return -1;
+
+ if (!(snapshots = prlsdkLoadSnapshots(dom)))
+ goto cleanup;
+
+ if (!(snap = vzSnapObjFromSnapshot(snapshots, snapshot)))
+ goto cleanup;
+
+ n = virDomainListSnapshots(snapshots, snap, snapshot->domain, snaps, flags);
+
+ cleanup:
+ virDomainSnapshotObjListFree(snapshots);
+ virObjectUnlock(dom);
+
+ return n;
+}
+
+static virDomainSnapshotPtr
+vzDomainSnapshotLookupByName(virDomainPtr domain,
+ const char *name,
+ unsigned int flags)
+{
+ virDomainObjPtr dom;
+ virDomainSnapshotObjPtr snap;
+ virDomainSnapshotPtr snapshot = NULL;
+ virDomainSnapshotObjListPtr snapshots = NULL;
+
+ virCheckFlags(0, NULL);
+
+ if (!(dom = vzDomObjFromDomain(domain)))
+ return NULL;
+
+ if (!(snapshots = prlsdkLoadSnapshots(dom)))
+ goto cleanup;
+
+ if (!(snap = vzSnapObjFromName(snapshots, name)))
+ goto cleanup;
+
+ snapshot = virGetDomainSnapshot(domain, snap->def->name);
+
+ cleanup:
+ virObjectUnlock(dom);
+ virDomainSnapshotObjListFree(snapshots);
+
+ return snapshot;
+}
+
+static int
+vzDomainHasCurrentSnapshot(virDomainPtr domain, unsigned int flags)
+{
+ virDomainObjPtr dom;
+ virDomainSnapshotObjListPtr snapshots = NULL;
+ int ret = -1;
+
+ virCheckFlags(0, -1);
+
+ if (!(dom = vzDomObjFromDomain(domain)))
+ return -1;
+
+ if (!(snapshots = prlsdkLoadSnapshots(dom)))
+ goto cleanup;
+
+ ret = vzFindCurrentSnapshot(snapshots) != NULL;
+
+ cleanup:
+ virDomainSnapshotObjListFree(snapshots);
+ virObjectUnlock(dom);
+
+ return ret;
+}
+
+static virDomainSnapshotPtr
+vzDomainSnapshotGetParent(virDomainSnapshotPtr snapshot, unsigned int flags)
+{
+ virDomainObjPtr dom;
+ virDomainSnapshotObjPtr snap;
+ virDomainSnapshotPtr parent = NULL;
+ virDomainSnapshotObjListPtr snapshots = NULL;
+
+ virCheckFlags(0, NULL);
+
+ if (!(dom = vzDomObjFromDomain(snapshot->domain)))
+ return NULL;
+
+ if (!(snapshots = prlsdkLoadSnapshots(dom)))
+ goto cleanup;
+
+ if (!(snap = vzSnapObjFromSnapshot(snapshots, snapshot)))
+ goto cleanup;
+
+ if (!snap->def->parent) {
+ virReportError(VIR_ERR_NO_DOMAIN_SNAPSHOT,
+ _("snapshot '%s' does not have a parent"),
+ snap->def->name);
+ goto cleanup;
+ }
+
+ parent = virGetDomainSnapshot(snapshot->domain, snap->def->parent);
+
+ cleanup:
+ virDomainSnapshotObjListFree(snapshots);
+ virObjectUnlock(dom);
+
+ return parent;
+}
+
+static virDomainSnapshotPtr
+vzDomainSnapshotCurrent(virDomainPtr domain, unsigned int flags)
+{
+ virDomainObjPtr dom;
+ virDomainSnapshotPtr snapshot = NULL;
+ virDomainSnapshotObjListPtr snapshots = NULL;
+ virDomainSnapshotObjPtr current;
+
+ virCheckFlags(0, NULL);
+
+ if (!(dom = vzDomObjFromDomain(domain)))
+ return NULL;
+
+ if (!(snapshots = prlsdkLoadSnapshots(dom)))
+ goto cleanup;
+
+ if (!(current = vzFindCurrentSnapshot(snapshots))) {
+ virReportError(VIR_ERR_NO_DOMAIN_SNAPSHOT, "%s",
+ _("the domain does not have a current snapshot"));
+ goto cleanup;
+ }
+
+ snapshot = virGetDomainSnapshot(domain, current->def->name);
+
+ cleanup:
+ virDomainSnapshotObjListFree(snapshots);
+ virObjectUnlock(dom);
+
+ return snapshot;
+}
+
+static int
+vzDomainSnapshotIsCurrent(virDomainSnapshotPtr snapshot, unsigned int flags)
+{
+ virDomainObjPtr dom;
+ int ret = -1;
+ virDomainSnapshotObjListPtr snapshots = NULL;
+ virDomainSnapshotObjPtr current;
+
+ virCheckFlags(0, -1);
+
+ if (!(dom = vzDomObjFromDomain(snapshot->domain)))
+ return -1;
+
+ if (!(snapshots = prlsdkLoadSnapshots(dom)))
+ goto cleanup;
+
+ current = vzFindCurrentSnapshot(snapshots);
+ ret = current && STREQ(snapshot->name, current->def->name);
+
+ cleanup:
+ virDomainSnapshotObjListFree(snapshots);
+ virObjectUnlock(dom);
+
+ return ret;
+}
+
+static int
+vzDomainSnapshotHasMetadata(virDomainSnapshotPtr snapshot,
+ unsigned int flags)
+{
+ virDomainObjPtr dom;
+ int ret = -1;
+ virDomainSnapshotObjPtr snap;
+ virDomainSnapshotObjListPtr snapshots = NULL;
+
+ virCheckFlags(0, -1);
+
+ if (!(dom = vzDomObjFromDomain(snapshot->domain)))
+ return -1;
+
+ if (!(snapshots = prlsdkLoadSnapshots(dom)))
+ goto cleanup;
+
+ if (!(snap = vzSnapObjFromSnapshot(snapshots, snapshot)))
+ goto cleanup;
+
+ ret = 1;
+
+ cleanup:
+ virDomainSnapshotObjListFree(snapshots);
+ virObjectUnlock(dom);
+ return ret;
+}
+
+static virDomainSnapshotPtr
+vzDomainSnapshotCreateXML(virDomainPtr domain,
+ const char *xmlDesc,
+ unsigned int flags)
+{
+ virDomainSnapshotDefPtr def = NULL;
+ virDomainSnapshotPtr snapshot = NULL;
+ virDomainObjPtr dom;
+ vzConnPtr privconn = domain->conn->privateData;
+ vzDriverPtr driver = privconn->driver;
+ unsigned int parse_flags = VIR_DOMAIN_SNAPSHOT_PARSE_DISKS;
+ virDomainSnapshotObjListPtr snapshots = NULL;
+ virDomainSnapshotObjPtr current;
+
+ virCheckFlags(0, NULL);
+
+ if (!(dom = vzDomObjFromDomain(domain)))
+ return NULL;
+
+ if (!(def = virDomainSnapshotDefParseString(xmlDesc, driver->caps,
+ driver->xmlopt, parse_flags)))
+ goto cleanup;
+
+ if (def->ndisks > 0) {
+ virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
+ _("configuring disks is not supported for vz snapshots"));
+ goto cleanup;
+ }
+
+ if (def->memory) {
+ virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
+ _("configuring memory location is not supported"));
+ goto cleanup;
+ }
+
+ /* snaphot name is ignored, it will be set to auto generated by sdk uuid */
+ if (prlsdkCreateSnapshot(dom, def->description) < 0)
+ goto cleanup;
+
+ if (!(snapshots = prlsdkLoadSnapshots(dom)))
+ goto cleanup;
+
+ if (!(current = vzFindCurrentSnapshot(snapshots))) {
+ virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+ _("can't find created snapshot"));
+ goto cleanup;
+ }
+
+ /* hopefully new current snapshot is newly created one */
+ snapshot = virGetDomainSnapshot(domain, current->def->name);
+
+ cleanup:
+ virDomainSnapshotObjListFree(snapshots);
+ virObjectUnlock(dom);
+ virDomainSnapshotDefFree(def);
+
+ return snapshot;
+}
+
+static int
+vzDomainSnapshotDelete(virDomainSnapshotPtr snapshot, unsigned int flags)
+{
+ virDomainObjPtr dom;
+ int ret = -1;
+
+ virCheckFlags(VIR_DOMAIN_SNAPSHOT_DELETE_CHILDREN, -1);
+
+ if (!(dom = vzDomObjFromDomain(snapshot->domain)))
+ return -1;
+
+ ret = prlsdkDeleteSnapshot(dom, snapshot->name,
+ flags & VIR_DOMAIN_SNAPSHOT_DELETE_CHILDREN);
+
+ virObjectUnlock(dom);
+
+ return ret;
+}
+
+static int
+vzDomainRevertToSnapshot(virDomainSnapshotPtr snapshot, unsigned int flags)
+{
+ virDomainObjPtr dom;
+ int ret = -1;
+
+ virCheckFlags(VIR_DOMAIN_SNAPSHOT_REVERT_PAUSED, -1);
+
+ if (!(dom = vzDomObjFromDomain(snapshot->domain)))
+ return -1;
+
+ ret = prlsdkSwitchToSnapshot(dom, snapshot->name,
+ flags & VIR_DOMAIN_SNAPSHOT_REVERT_PAUSED);
+
+ virObjectUnlock(dom);
+
+ return ret;
+}
+
static virHypervisorDriver vzHypervisorDriver = {
.name = "vz",
.connectOpen = vzConnectOpen, /* 0.10.0 */
.connectUnregisterCloseCallback = vzConnectUnregisterCloseCallback, /* 1.3.2 */
.domainSetMemoryFlags = vzDomainSetMemoryFlags, /* 1.3.4 */
.domainSetMemory = vzDomainSetMemory, /* 1.3.4 */
+ .domainSnapshotNum = vzDomainSnapshotNum, /* 1.3.5 */
+ .domainSnapshotListNames = vzDomainSnapshotListNames, /* 1.3.5 */
+ .domainListAllSnapshots = vzDomainListAllSnapshots, /* 1.3.5 */
+ .domainSnapshotGetXMLDesc = vzDomainSnapshotGetXMLDesc, /* 1.3.5 */
+ .domainSnapshotNumChildren = vzDomainSnapshotNumChildren, /* 1.3.5 */
+ .domainSnapshotListChildrenNames = vzDomainSnapshotListChildrenNames, /* 1.3.5 */
+ .domainSnapshotListAllChildren = vzDomainSnapshotListAllChildren, /* 1.3.5 */
+ .domainSnapshotLookupByName = vzDomainSnapshotLookupByName, /* 1.3.5 */
+ .domainHasCurrentSnapshot = vzDomainHasCurrentSnapshot, /* 1.3.5 */
+ .domainSnapshotGetParent = vzDomainSnapshotGetParent, /* 1.3.5 */
+ .domainSnapshotCurrent = vzDomainSnapshotCurrent, /* 1.3.5 */
+ .domainSnapshotIsCurrent = vzDomainSnapshotIsCurrent, /* 1.3.5 */
+ .domainSnapshotHasMetadata = vzDomainSnapshotHasMetadata, /* 1.3.5 */
+ .domainSnapshotCreateXML = vzDomainSnapshotCreateXML, /* 1.3.5 */
+ .domainSnapshotDelete = vzDomainSnapshotDelete, /* 1.3.5 */
+ .domainRevertToSnapshot = vzDomainRevertToSnapshot, /* 1.3.5 */
};
static virConnectDriver vzConnectDriver = {
error:
return -1;
}
+
+static long long
+prlsdkParseDateTime(const char *str)
+{
+ struct tm tm;
+ const char *tmp;
+
+ tmp = strptime(str, "%Y-%m-%d %H:%M:%S", &tm);
+ if (!tmp || *tmp != '\0') {
+ virReportError(VIR_ERR_INTERNAL_ERROR,
+ _("unexpected DateTime format: '%s'"), str);
+ return -1;
+ }
+
+ return mktime(&tm);
+}
+
+static virDomainSnapshotObjListPtr
+prlsdkParseSnapshotTree(const char *treexml)
+{
+ virDomainSnapshotObjListPtr ret = NULL;
+ xmlDocPtr xml = NULL;
+ xmlXPathContextPtr ctxt = NULL;
+ xmlNodePtr root;
+ xmlNodePtr *nodes = NULL;
+ virDomainSnapshotDefPtr def = NULL;
+ virDomainSnapshotObjPtr snapshot;
+ virDomainSnapshotObjPtr current = NULL;
+ virDomainSnapshotObjListPtr snapshots = NULL;
+ char *xmlstr = NULL;
+ int n;
+ size_t i;
+
+ if (!(snapshots = virDomainSnapshotObjListNew()))
+ return NULL;
+
+ if (*treexml == '\0')
+ return snapshots;
+
+ if (!(xml = virXMLParse(NULL, treexml, _("(snapshot_tree)"))))
+ goto cleanup;
+
+ root = xmlDocGetRootElement(xml);
+ if (!xmlStrEqual(root->name, BAD_CAST "ParallelsSavedStates")) {
+ virReportError(VIR_ERR_INTERNAL_ERROR,
+ _("unexpected root element: '%s'"), root->name);
+ goto cleanup;
+ }
+
+ ctxt = xmlXPathNewContext(xml);
+ if (ctxt == NULL) {
+ virReportOOMError();
+ goto cleanup;
+ }
+ ctxt->node = root;
+
+ if ((n = virXPathNodeSet("//SavedStateItem", ctxt, &nodes)) < 0) {
+ virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+ _("cannot extract snapshot nodes"));
+ goto cleanup;
+ }
+
+ for (i = 0; i < n; i++) {
+ if (nodes[i]->parent == root)
+ continue;
+
+ if (VIR_ALLOC(def) < 0)
+ goto cleanup;
+
+ ctxt->node = nodes[i];
+
+ def->name = virXPathString("string(./@guid)", ctxt);
+ if (!def->name) {
+ virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+ _("missing 'guid' attribute"));
+ goto cleanup;
+ }
+
+ def->parent = virXPathString("string(../@guid)", ctxt);
+
+ xmlstr = virXPathString("string(./DateTime)", ctxt);
+ if (!xmlstr) {
+ virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+ _("missing 'DateTime' element"));
+ goto cleanup;
+ }
+ if ((def->creationTime = prlsdkParseDateTime(xmlstr)) < 0)
+ goto cleanup;
+ VIR_FREE(xmlstr);
+
+ def->description = virXPathString("string(./Description)", ctxt);
+
+ def->memory = VIR_DOMAIN_SNAPSHOT_LOCATION_NONE;
+ xmlstr = virXPathString("string(./@state)", ctxt);
+ if (!xmlstr) {
+ virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+ _("missing 'state' attribute"));
+ goto cleanup;
+ } else if (STREQ(xmlstr, "poweron")) {
+ def->state = VIR_DOMAIN_RUNNING;
+ def->memory = VIR_DOMAIN_SNAPSHOT_LOCATION_INTERNAL;
+ } else if (STREQ(xmlstr, "pause")) {
+ def->state = VIR_DOMAIN_PAUSED;
+ def->memory = VIR_DOMAIN_SNAPSHOT_LOCATION_INTERNAL;
+ } else if (STREQ(xmlstr, "suspend")) {
+ def->state = VIR_DOMAIN_SHUTOFF;
+ } else if (STREQ(xmlstr, "poweroff")) {
+ def->state = VIR_DOMAIN_SHUTOFF;
+ } else {
+ virReportError(VIR_ERR_INTERNAL_ERROR,
+ _("unexpected snapshot state: %s"), xmlstr);
+ }
+ VIR_FREE(xmlstr);
+
+ xmlstr = virXPathString("string(./@current)", ctxt);
+ def->current = xmlstr && STREQ("yes", xmlstr);
+ VIR_FREE(xmlstr);
+
+ if (!(snapshot = virDomainSnapshotAssignDef(snapshots, def)))
+ goto cleanup;
+ def = NULL;
+
+ if (snapshot->def->current) {
+ if (current) {
+ virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+ _("too many current snapshots"));
+ goto cleanup;
+ }
+ current = snapshot;
+ }
+ }
+
+ if (virDomainSnapshotUpdateRelations(snapshots) < 0) {
+ virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+ _("snapshots have inconsistent relations"));
+ goto cleanup;
+ }
+
+ ret = snapshots;
+ snapshots = NULL;
+
+ cleanup:
+ virDomainSnapshotObjListFree(snapshots);
+ VIR_FREE(nodes);
+ VIR_FREE(xmlstr);
+ xmlXPathFreeContext(ctxt);
+ xmlFreeDoc(xml);
+ VIR_FREE(def);
+
+ return ret;
+}
+
+virDomainSnapshotObjListPtr
+prlsdkLoadSnapshots(virDomainObjPtr dom)
+{
+ virDomainSnapshotObjListPtr ret = NULL;
+ PRL_HANDLE job;
+ PRL_HANDLE result = PRL_INVALID_HANDLE;
+ vzDomObjPtr privdom = dom->privateData;
+ char *treexml = NULL;
+
+ job = PrlVm_GetSnapshotsTreeEx(privdom->sdkdom, PGST_WITHOUT_SCREENSHOTS);
+ if (PRL_FAILED(getJobResult(job, &result)))
+ goto cleanup;
+
+ if (!(treexml = prlsdkGetStringParamVar(PrlResult_GetParamAsString, result)))
+ goto cleanup;
+
+ ret = prlsdkParseSnapshotTree(treexml);
+ cleanup:
+
+ PrlHandle_Free(result);
+ VIR_FREE(treexml);
+ return ret;
+}
+
+int prlsdkCreateSnapshot(virDomainObjPtr dom, const char *description)
+{
+ vzDomObjPtr privdom = dom->privateData;
+ PRL_HANDLE job;
+
+ job = PrlVm_CreateSnapshot(privdom->sdkdom, "",
+ description ? : "");
+ if (PRL_FAILED(waitJob(job)))
+ return -1;
+
+ return 0;
+}
+
+int prlsdkDeleteSnapshot(virDomainObjPtr dom, const char *uuid, bool children)
+{
+ vzDomObjPtr privdom = dom->privateData;
+ PRL_HANDLE job;
+
+ job = PrlVm_DeleteSnapshot(privdom->sdkdom, uuid, children);
+ if (PRL_FAILED(waitJob(job)))
+ return -1;
+
+ return 0;
+}
+
+int prlsdkSwitchToSnapshot(virDomainObjPtr dom, const char *uuid, bool paused)
+{
+ vzDomObjPtr privdom = dom->privateData;
+ PRL_HANDLE job;
+ PRL_UINT32 flags = 0;
+
+ if (paused)
+ flags |= PSSF_SKIP_RESUME;
+
+ job = PrlVm_SwitchToSnapshotEx(privdom->sdkdom, uuid, flags);
+ if (PRL_FAILED(waitJob(job)))
+ return -1;
+
+ return 0;
+}