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