1 /*
2 * virdomainsnapshotobjlist.c: handle a tree of snapshot objects
3 * (derived from snapshot_conf.c)
4 *
5 * Copyright (C) 2006-2019 Red Hat, Inc.
6 * Copyright (C) 2006-2008 Daniel P. Berrange
7 *
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License as published by the Free Software Foundation; either
11 * version 2.1 of the License, or (at your option) any later version.
12 *
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Lesser General Public License for more details.
17 *
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with this library. If not, see
20 * <http://www.gnu.org/licenses/>.
21 */
22
23 #include <config.h>
24
25 #include "internal.h"
26 #include "virdomainsnapshotobjlist.h"
27 #include "snapshot_conf.h"
28 #include "virlog.h"
29 #include "virerror.h"
30 #include "datatypes.h"
31 #include "virstring.h"
32 #include "viralloc.h"
33
34 #define VIR_FROM_THIS VIR_FROM_DOMAIN_SNAPSHOT
35
36 VIR_LOG_INIT("conf.virdomainsnapshotobjlist");
37
38 struct _virDomainSnapshotObjList {
39 virDomainMomentObjList *base;
40 };
41
42
43 virDomainMomentObj *
virDomainSnapshotAssignDef(virDomainSnapshotObjList * snapshots,virDomainSnapshotDef * def)44 virDomainSnapshotAssignDef(virDomainSnapshotObjList *snapshots,
45 virDomainSnapshotDef *def)
46 {
47 return virDomainMomentAssignDef(snapshots->base, &def->parent);
48 }
49
50
51 static bool
virDomainSnapshotFilter(virDomainMomentObj * obj,unsigned int flags)52 virDomainSnapshotFilter(virDomainMomentObj *obj,
53 unsigned int flags)
54 {
55 virDomainSnapshotDef *def = virDomainSnapshotObjGetDef(obj);
56
57 /* Caller has already sanitized flags and performed filtering on
58 * DESCENDANTS and LEAVES. */
59 if (flags & VIR_DOMAIN_SNAPSHOT_FILTERS_STATUS) {
60 if (!(flags & VIR_DOMAIN_SNAPSHOT_LIST_INACTIVE) &&
61 def->state == VIR_DOMAIN_SNAPSHOT_SHUTOFF)
62 return false;
63 if (!(flags & VIR_DOMAIN_SNAPSHOT_LIST_DISK_ONLY) &&
64 def->state == VIR_DOMAIN_SNAPSHOT_DISK_SNAPSHOT)
65 return false;
66 if (!(flags & VIR_DOMAIN_SNAPSHOT_LIST_ACTIVE) &&
67 def->state != VIR_DOMAIN_SNAPSHOT_SHUTOFF &&
68 def->state != VIR_DOMAIN_SNAPSHOT_DISK_SNAPSHOT)
69 return false;
70 }
71
72 if ((flags & VIR_DOMAIN_SNAPSHOT_LIST_INTERNAL) &&
73 virDomainSnapshotIsExternal(obj))
74 return false;
75 if ((flags & VIR_DOMAIN_SNAPSHOT_LIST_EXTERNAL) &&
76 !virDomainSnapshotIsExternal(obj))
77 return false;
78
79 return true;
80 }
81
82
83 virDomainSnapshotObjList *
virDomainSnapshotObjListNew(void)84 virDomainSnapshotObjListNew(void)
85 {
86 virDomainSnapshotObjList *snapshots;
87
88 snapshots = g_new0(virDomainSnapshotObjList, 1);
89 snapshots->base = virDomainMomentObjListNew();
90 if (!snapshots->base) {
91 VIR_FREE(snapshots);
92 return NULL;
93 }
94 return snapshots;
95 }
96
97
98 void
virDomainSnapshotObjListFree(virDomainSnapshotObjList * snapshots)99 virDomainSnapshotObjListFree(virDomainSnapshotObjList *snapshots)
100 {
101 if (!snapshots)
102 return;
103 virDomainMomentObjListFree(snapshots->base);
104 g_free(snapshots);
105 }
106
107
108 int
virDomainSnapshotObjListGetNames(virDomainSnapshotObjList * snapshots,virDomainMomentObj * from,char ** const names,int maxnames,unsigned int flags)109 virDomainSnapshotObjListGetNames(virDomainSnapshotObjList *snapshots,
110 virDomainMomentObj *from,
111 char **const names,
112 int maxnames,
113 unsigned int flags)
114 {
115 /* Convert public flags into common flags */
116 unsigned int moment_flags = 0;
117 struct { int snap_flag; int moment_flag; } map[] = {
118 { VIR_DOMAIN_SNAPSHOT_LIST_ROOTS,
119 VIR_DOMAIN_MOMENT_LIST_ROOTS, },
120 { VIR_DOMAIN_SNAPSHOT_LIST_TOPOLOGICAL,
121 VIR_DOMAIN_MOMENT_LIST_TOPOLOGICAL, },
122 { VIR_DOMAIN_SNAPSHOT_LIST_LEAVES,
123 VIR_DOMAIN_MOMENT_LIST_LEAVES, },
124 { VIR_DOMAIN_SNAPSHOT_LIST_NO_LEAVES,
125 VIR_DOMAIN_MOMENT_LIST_NO_LEAVES, },
126 { VIR_DOMAIN_SNAPSHOT_LIST_METADATA,
127 VIR_DOMAIN_MOMENT_LIST_METADATA, },
128 { VIR_DOMAIN_SNAPSHOT_LIST_NO_METADATA,
129 VIR_DOMAIN_MOMENT_LIST_NO_METADATA, },
130 };
131 size_t i;
132
133 for (i = 0; i < G_N_ELEMENTS(map); i++) {
134 if (flags & map[i].snap_flag) {
135 flags &= ~map[i].snap_flag;
136 moment_flags |= map[i].moment_flag;
137 }
138 }
139
140 /* For ease of coding the visitor, it is easier to zero each group
141 * where all of the bits are set. */
142 if ((flags & VIR_DOMAIN_SNAPSHOT_FILTERS_LEAVES) ==
143 VIR_DOMAIN_SNAPSHOT_FILTERS_LEAVES)
144 flags &= ~VIR_DOMAIN_SNAPSHOT_FILTERS_LEAVES;
145 if ((flags & VIR_DOMAIN_SNAPSHOT_FILTERS_STATUS) ==
146 VIR_DOMAIN_SNAPSHOT_FILTERS_STATUS)
147 flags &= ~VIR_DOMAIN_SNAPSHOT_FILTERS_STATUS;
148 if ((flags & VIR_DOMAIN_SNAPSHOT_FILTERS_LOCATION) ==
149 VIR_DOMAIN_SNAPSHOT_FILTERS_LOCATION)
150 flags &= ~VIR_DOMAIN_SNAPSHOT_FILTERS_LOCATION;
151 return virDomainMomentObjListGetNames(snapshots->base, from, names,
152 maxnames, moment_flags,
153 virDomainSnapshotFilter, flags);
154 }
155
156
157 int
virDomainSnapshotObjListNum(virDomainSnapshotObjList * snapshots,virDomainMomentObj * from,unsigned int flags)158 virDomainSnapshotObjListNum(virDomainSnapshotObjList *snapshots,
159 virDomainMomentObj *from,
160 unsigned int flags)
161 {
162 return virDomainSnapshotObjListGetNames(snapshots, from, NULL, 0, flags);
163 }
164
165
166 virDomainMomentObj *
virDomainSnapshotFindByName(virDomainSnapshotObjList * snapshots,const char * name)167 virDomainSnapshotFindByName(virDomainSnapshotObjList *snapshots,
168 const char *name)
169 {
170 return virDomainMomentFindByName(snapshots->base, name);
171 }
172
173
174 /* Return the current snapshot, or NULL */
175 virDomainMomentObj *
virDomainSnapshotGetCurrent(virDomainSnapshotObjList * snapshots)176 virDomainSnapshotGetCurrent(virDomainSnapshotObjList *snapshots)
177 {
178 return virDomainMomentGetCurrent(snapshots->base);
179 }
180
181
182 /* Return the current snapshot's name, or NULL */
183 const char *
virDomainSnapshotGetCurrentName(virDomainSnapshotObjList * snapshots)184 virDomainSnapshotGetCurrentName(virDomainSnapshotObjList *snapshots)
185 {
186 return virDomainMomentGetCurrentName(snapshots->base);
187 }
188
189
190 /* Update the current snapshot, using NULL if no current remains */
191 void
virDomainSnapshotSetCurrent(virDomainSnapshotObjList * snapshots,virDomainMomentObj * snapshot)192 virDomainSnapshotSetCurrent(virDomainSnapshotObjList *snapshots,
193 virDomainMomentObj *snapshot)
194 {
195 virDomainMomentSetCurrent(snapshots->base, snapshot);
196 }
197
198
199 /* Remove snapshot from the list; return true if it was current */
200 bool
virDomainSnapshotObjListRemove(virDomainSnapshotObjList * snapshots,virDomainMomentObj * snapshot)201 virDomainSnapshotObjListRemove(virDomainSnapshotObjList *snapshots,
202 virDomainMomentObj *snapshot)
203 {
204 return virDomainMomentObjListRemove(snapshots->base, snapshot);
205 }
206
207
208 /* Remove all snapshots tracked in the list */
209 void
virDomainSnapshotObjListRemoveAll(virDomainSnapshotObjList * snapshots)210 virDomainSnapshotObjListRemoveAll(virDomainSnapshotObjList *snapshots)
211 {
212 return virDomainMomentObjListRemoveAll(snapshots->base);
213 }
214
215
216 int
virDomainSnapshotForEach(virDomainSnapshotObjList * snapshots,virHashIterator iter,void * data)217 virDomainSnapshotForEach(virDomainSnapshotObjList *snapshots,
218 virHashIterator iter,
219 void *data)
220 {
221 return virDomainMomentForEach(snapshots->base, iter, data);
222 }
223
224
225 /* Populate parent link of a given snapshot. */
226 void
virDomainSnapshotLinkParent(virDomainSnapshotObjList * snapshots,virDomainMomentObj * snap)227 virDomainSnapshotLinkParent(virDomainSnapshotObjList *snapshots,
228 virDomainMomentObj *snap)
229 {
230 return virDomainMomentLinkParent(snapshots->base, snap);
231 }
232
233
234 /* Populate parent link and child count of all snapshots, with all
235 * assigned defs having relations starting as 0/NULL. Return 0 on
236 * success, -1 if a parent is missing or if a circular relationship
237 * was requested. */
238 int
virDomainSnapshotUpdateRelations(virDomainSnapshotObjList * snapshots)239 virDomainSnapshotUpdateRelations(virDomainSnapshotObjList *snapshots)
240 {
241 return virDomainMomentUpdateRelations(snapshots->base);
242 }
243
244
245 int
virDomainSnapshotCheckCycles(virDomainSnapshotObjList * snapshots,virDomainSnapshotDef * def,const char * domname)246 virDomainSnapshotCheckCycles(virDomainSnapshotObjList *snapshots,
247 virDomainSnapshotDef *def,
248 const char *domname)
249 {
250 return virDomainMomentCheckCycles(snapshots->base, &def->parent, domname);
251 }
252
253
254 int
virDomainListSnapshots(virDomainSnapshotObjList * snapshots,virDomainMomentObj * from,virDomainPtr dom,virDomainSnapshotPtr ** snaps,unsigned int flags)255 virDomainListSnapshots(virDomainSnapshotObjList *snapshots,
256 virDomainMomentObj *from,
257 virDomainPtr dom,
258 virDomainSnapshotPtr **snaps,
259 unsigned int flags)
260 {
261 int count = virDomainSnapshotObjListNum(snapshots, from, flags);
262 virDomainSnapshotPtr *list = NULL;
263 char **names;
264 int ret = -1;
265 size_t i;
266
267 if (!snaps || count < 0)
268 return count;
269 names = g_new0(char *, count);
270 list = g_new0(virDomainSnapshotPtr, count + 1);
271
272 if (virDomainSnapshotObjListGetNames(snapshots, from, names, count,
273 flags) < 0)
274 goto cleanup;
275 for (i = 0; i < count; i++)
276 if ((list[i] = virGetDomainSnapshot(dom, names[i])) == NULL)
277 goto cleanup;
278
279 ret = count;
280 *snaps = list;
281
282 cleanup:
283 for (i = 0; i < count; i++)
284 VIR_FREE(names[i]);
285 VIR_FREE(names);
286 if (ret < 0 && list) {
287 for (i = 0; i < count; i++)
288 virObjectUnref(list[i]);
289 VIR_FREE(list);
290 }
291 return ret;
292 }
293