]> Git Repo - qemu.git/blame - qobject/block-qdict.c
qobject: Move block-specific qdict code to block-qdict.c
[qemu.git] / qobject / block-qdict.c
CommitLineData
0bcc8e5b
MA
1/*
2 * Special QDict functions used by the block layer
3 *
4 * Copyright (c) 2013-2018 Red Hat, Inc.
5 *
6 * This work is licensed under the terms of the GNU LGPL, version 2.1 or later.
7 * See the COPYING.LIB file in the top-level directory.
8 */
9
10#include "qemu/osdep.h"
11#include "block/qdict.h"
12#include "qapi/qmp/qlist.h"
13#include "qemu/cutils.h"
14#include "qapi/error.h"
15
16/**
17 * qdict_copy_default(): If no entry mapped by 'key' exists in 'dst' yet, the
18 * value of 'key' in 'src' is copied there (and the refcount increased
19 * accordingly).
20 */
21void qdict_copy_default(QDict *dst, QDict *src, const char *key)
22{
23 QObject *val;
24
25 if (qdict_haskey(dst, key)) {
26 return;
27 }
28
29 val = qdict_get(src, key);
30 if (val) {
31 qdict_put_obj(dst, key, qobject_ref(val));
32 }
33}
34
35/**
36 * qdict_set_default_str(): If no entry mapped by 'key' exists in 'dst' yet, a
37 * new QString initialised by 'val' is put there.
38 */
39void qdict_set_default_str(QDict *dst, const char *key, const char *val)
40{
41 if (qdict_haskey(dst, key)) {
42 return;
43 }
44
45 qdict_put_str(dst, key, val);
46}
47
48static void qdict_flatten_qdict(QDict *qdict, QDict *target,
49 const char *prefix);
50
51static void qdict_flatten_qlist(QList *qlist, QDict *target, const char *prefix)
52{
53 QObject *value;
54 const QListEntry *entry;
55 char *new_key;
56 int i;
57
58 /* This function is never called with prefix == NULL, i.e., it is always
59 * called from within qdict_flatten_q(list|dict)(). Therefore, it does not
60 * need to remove list entries during the iteration (the whole list will be
61 * deleted eventually anyway from qdict_flatten_qdict()). */
62 assert(prefix);
63
64 entry = qlist_first(qlist);
65
66 for (i = 0; entry; entry = qlist_next(entry), i++) {
67 value = qlist_entry_obj(entry);
68 new_key = g_strdup_printf("%s.%i", prefix, i);
69
70 if (qobject_type(value) == QTYPE_QDICT) {
71 qdict_flatten_qdict(qobject_to(QDict, value), target, new_key);
72 } else if (qobject_type(value) == QTYPE_QLIST) {
73 qdict_flatten_qlist(qobject_to(QList, value), target, new_key);
74 } else {
75 /* All other types are moved to the target unchanged. */
76 qdict_put_obj(target, new_key, qobject_ref(value));
77 }
78
79 g_free(new_key);
80 }
81}
82
83static void qdict_flatten_qdict(QDict *qdict, QDict *target, const char *prefix)
84{
85 QObject *value;
86 const QDictEntry *entry, *next;
87 char *new_key;
88 bool delete;
89
90 entry = qdict_first(qdict);
91
92 while (entry != NULL) {
93
94 next = qdict_next(qdict, entry);
95 value = qdict_entry_value(entry);
96 new_key = NULL;
97 delete = false;
98
99 if (prefix) {
100 new_key = g_strdup_printf("%s.%s", prefix, entry->key);
101 }
102
103 if (qobject_type(value) == QTYPE_QDICT) {
104 /* Entries of QDicts are processed recursively, the QDict object
105 * itself disappears. */
106 qdict_flatten_qdict(qobject_to(QDict, value), target,
107 new_key ? new_key : entry->key);
108 delete = true;
109 } else if (qobject_type(value) == QTYPE_QLIST) {
110 qdict_flatten_qlist(qobject_to(QList, value), target,
111 new_key ? new_key : entry->key);
112 delete = true;
113 } else if (prefix) {
114 /* All other objects are moved to the target unchanged. */
115 qdict_put_obj(target, new_key, qobject_ref(value));
116 delete = true;
117 }
118
119 g_free(new_key);
120
121 if (delete) {
122 qdict_del(qdict, entry->key);
123
124 /* Restart loop after modifying the iterated QDict */
125 entry = qdict_first(qdict);
126 continue;
127 }
128
129 entry = next;
130 }
131}
132
133/**
134 * qdict_flatten(): For each nested QDict with key x, all fields with key y
135 * are moved to this QDict and their key is renamed to "x.y". For each nested
136 * QList with key x, the field at index y is moved to this QDict with the key
137 * "x.y" (i.e., the reverse of what qdict_array_split() does).
138 * This operation is applied recursively for nested QDicts and QLists.
139 */
140void qdict_flatten(QDict *qdict)
141{
142 qdict_flatten_qdict(qdict, qdict, NULL);
143}
144
145/* extract all the src QDict entries starting by start into dst */
146void qdict_extract_subqdict(QDict *src, QDict **dst, const char *start)
147
148{
149 const QDictEntry *entry, *next;
150 const char *p;
151
152 *dst = qdict_new();
153 entry = qdict_first(src);
154
155 while (entry != NULL) {
156 next = qdict_next(src, entry);
157 if (strstart(entry->key, start, &p)) {
158 qdict_put_obj(*dst, p, qobject_ref(entry->value));
159 qdict_del(src, entry->key);
160 }
161 entry = next;
162 }
163}
164
165static int qdict_count_prefixed_entries(const QDict *src, const char *start)
166{
167 const QDictEntry *entry;
168 int count = 0;
169
170 for (entry = qdict_first(src); entry; entry = qdict_next(src, entry)) {
171 if (strstart(entry->key, start, NULL)) {
172 if (count == INT_MAX) {
173 return -ERANGE;
174 }
175 count++;
176 }
177 }
178
179 return count;
180}
181
182/**
183 * qdict_array_split(): This function moves array-like elements of a QDict into
184 * a new QList. Every entry in the original QDict with a key "%u" or one
185 * prefixed "%u.", where %u designates an unsigned integer starting at 0 and
186 * incrementally counting up, will be moved to a new QDict at index %u in the
187 * output QList with the key prefix removed, if that prefix is "%u.". If the
188 * whole key is just "%u", the whole QObject will be moved unchanged without
189 * creating a new QDict. The function terminates when there is no entry in the
190 * QDict with a prefix directly (incrementally) following the last one; it also
191 * returns if there are both entries with "%u" and "%u." for the same index %u.
192 * Example: {"0.a": 42, "0.b": 23, "1.x": 0, "4.y": 1, "o.o": 7, "2": 66}
193 * (or {"1.x": 0, "4.y": 1, "0.a": 42, "o.o": 7, "0.b": 23, "2": 66})
194 * => [{"a": 42, "b": 23}, {"x": 0}, 66]
195 * and {"4.y": 1, "o.o": 7} (remainder of the old QDict)
196 */
197void qdict_array_split(QDict *src, QList **dst)
198{
199 unsigned i;
200
201 *dst = qlist_new();
202
203 for (i = 0; i < UINT_MAX; i++) {
204 QObject *subqobj;
205 bool is_subqdict;
206 QDict *subqdict;
207 char indexstr[32], prefix[32];
208 size_t snprintf_ret;
209
210 snprintf_ret = snprintf(indexstr, 32, "%u", i);
211 assert(snprintf_ret < 32);
212
213 subqobj = qdict_get(src, indexstr);
214
215 snprintf_ret = snprintf(prefix, 32, "%u.", i);
216 assert(snprintf_ret < 32);
217
218 /* Overflow is the same as positive non-zero results */
219 is_subqdict = qdict_count_prefixed_entries(src, prefix);
220
221 /*
222 * There may be either a single subordinate object (named
223 * "%u") or multiple objects (each with a key prefixed "%u."),
224 * but not both.
225 */
226 if (!subqobj == !is_subqdict) {
227 break;
228 }
229
230 if (is_subqdict) {
231 qdict_extract_subqdict(src, &subqdict, prefix);
232 assert(qdict_size(subqdict) > 0);
233 } else {
234 qobject_ref(subqobj);
235 qdict_del(src, indexstr);
236 }
237
238 qlist_append_obj(*dst, subqobj ?: QOBJECT(subqdict));
239 }
240}
241
242/**
243 * qdict_split_flat_key:
244 * @key: the key string to split
245 * @prefix: non-NULL pointer to hold extracted prefix
246 * @suffix: non-NULL pointer to remaining suffix
247 *
248 * Given a flattened key such as 'foo.0.bar', split it into two parts
249 * at the first '.' separator. Allows double dot ('..') to escape the
250 * normal separator.
251 *
252 * e.g.
253 * 'foo.0.bar' -> prefix='foo' and suffix='0.bar'
254 * 'foo..0.bar' -> prefix='foo.0' and suffix='bar'
255 *
256 * The '..' sequence will be unescaped in the returned 'prefix'
257 * string. The 'suffix' string will be left in escaped format, so it
258 * can be fed back into the qdict_split_flat_key() key as the input
259 * later.
260 *
261 * The caller is responsible for freeing the string returned in @prefix
262 * using g_free().
263 */
264static void qdict_split_flat_key(const char *key, char **prefix,
265 const char **suffix)
266{
267 const char *separator;
268 size_t i, j;
269
270 /* Find first '.' separator, but if there is a pair '..'
271 * that acts as an escape, so skip over '..' */
272 separator = NULL;
273 do {
274 if (separator) {
275 separator += 2;
276 } else {
277 separator = key;
278 }
279 separator = strchr(separator, '.');
280 } while (separator && separator[1] == '.');
281
282 if (separator) {
283 *prefix = g_strndup(key, separator - key);
284 *suffix = separator + 1;
285 } else {
286 *prefix = g_strdup(key);
287 *suffix = NULL;
288 }
289
290 /* Unescape the '..' sequence into '.' */
291 for (i = 0, j = 0; (*prefix)[i] != '\0'; i++, j++) {
292 if ((*prefix)[i] == '.') {
293 assert((*prefix)[i + 1] == '.');
294 i++;
295 }
296 (*prefix)[j] = (*prefix)[i];
297 }
298 (*prefix)[j] = '\0';
299}
300
301/**
302 * qdict_is_list:
303 * @maybe_list: dict to check if keys represent list elements.
304 *
305 * Determine whether all keys in @maybe_list are valid list elements.
306 * If @maybe_list is non-zero in length and all the keys look like
307 * valid list indexes, this will return 1. If @maybe_list is zero
308 * length or all keys are non-numeric then it will return 0 to indicate
309 * it is a normal qdict. If there is a mix of numeric and non-numeric
310 * keys, or the list indexes are non-contiguous, an error is reported.
311 *
312 * Returns: 1 if a valid list, 0 if a dict, -1 on error
313 */
314static int qdict_is_list(QDict *maybe_list, Error **errp)
315{
316 const QDictEntry *ent;
317 ssize_t len = 0;
318 ssize_t max = -1;
319 int is_list = -1;
320 int64_t val;
321
322 for (ent = qdict_first(maybe_list); ent != NULL;
323 ent = qdict_next(maybe_list, ent)) {
324
325 if (qemu_strtoi64(ent->key, NULL, 10, &val) == 0) {
326 if (is_list == -1) {
327 is_list = 1;
328 } else if (!is_list) {
329 error_setg(errp,
330 "Cannot mix list and non-list keys");
331 return -1;
332 }
333 len++;
334 if (val > max) {
335 max = val;
336 }
337 } else {
338 if (is_list == -1) {
339 is_list = 0;
340 } else if (is_list) {
341 error_setg(errp,
342 "Cannot mix list and non-list keys");
343 return -1;
344 }
345 }
346 }
347
348 if (is_list == -1) {
349 assert(!qdict_size(maybe_list));
350 is_list = 0;
351 }
352
353 /* NB this isn't a perfect check - e.g. it won't catch
354 * a list containing '1', '+1', '01', '3', but that
355 * does not matter - we've still proved that the
356 * input is a list. It is up the caller to do a
357 * stricter check if desired */
358 if (len != (max + 1)) {
359 error_setg(errp, "List indices are not contiguous, "
360 "saw %zd elements but %zd largest index",
361 len, max);
362 return -1;
363 }
364
365 return is_list;
366}
367
368/**
369 * qdict_crumple:
370 * @src: the original flat dictionary (only scalar values) to crumple
371 *
372 * Takes a flat dictionary whose keys use '.' separator to indicate
373 * nesting, and values are scalars, and crumples it into a nested
374 * structure.
375 *
376 * To include a literal '.' in a key name, it must be escaped as '..'
377 *
378 * For example, an input of:
379 *
380 * { 'foo.0.bar': 'one', 'foo.0.wizz': '1',
381 * 'foo.1.bar': 'two', 'foo.1.wizz': '2' }
382 *
383 * will result in an output of:
384 *
385 * {
386 * 'foo': [
387 * { 'bar': 'one', 'wizz': '1' },
388 * { 'bar': 'two', 'wizz': '2' }
389 * ],
390 * }
391 *
392 * The following scenarios in the input dict will result in an
393 * error being returned:
394 *
395 * - Any values in @src are non-scalar types
396 * - If keys in @src imply that a particular level is both a
397 * list and a dict. e.g., "foo.0.bar" and "foo.eek.bar".
398 * - If keys in @src imply that a particular level is a list,
399 * but the indices are non-contiguous. e.g. "foo.0.bar" and
400 * "foo.2.bar" without any "foo.1.bar" present.
401 * - If keys in @src represent list indexes, but are not in
402 * the "%zu" format. e.g. "foo.+0.bar"
403 *
404 * Returns: either a QDict or QList for the nested data structure, or NULL
405 * on error
406 */
407QObject *qdict_crumple(const QDict *src, Error **errp)
408{
409 const QDictEntry *ent;
410 QDict *two_level, *multi_level = NULL;
411 QObject *dst = NULL, *child;
412 size_t i;
413 char *prefix = NULL;
414 const char *suffix = NULL;
415 int is_list;
416
417 two_level = qdict_new();
418
419 /* Step 1: split our totally flat dict into a two level dict */
420 for (ent = qdict_first(src); ent != NULL; ent = qdict_next(src, ent)) {
421 if (qobject_type(ent->value) == QTYPE_QDICT ||
422 qobject_type(ent->value) == QTYPE_QLIST) {
423 error_setg(errp, "Value %s is not a scalar",
424 ent->key);
425 goto error;
426 }
427
428 qdict_split_flat_key(ent->key, &prefix, &suffix);
429
430 child = qdict_get(two_level, prefix);
431 if (suffix) {
432 QDict *child_dict = qobject_to(QDict, child);
433 if (!child_dict) {
434 if (child) {
435 error_setg(errp, "Key %s prefix is already set as a scalar",
436 prefix);
437 goto error;
438 }
439
440 child_dict = qdict_new();
441 qdict_put_obj(two_level, prefix, QOBJECT(child_dict));
442 }
443
444 qdict_put_obj(child_dict, suffix, qobject_ref(ent->value));
445 } else {
446 if (child) {
447 error_setg(errp, "Key %s prefix is already set as a dict",
448 prefix);
449 goto error;
450 }
451 qdict_put_obj(two_level, prefix, qobject_ref(ent->value));
452 }
453
454 g_free(prefix);
455 prefix = NULL;
456 }
457
458 /* Step 2: optionally process the two level dict recursively
459 * into a multi-level dict */
460 multi_level = qdict_new();
461 for (ent = qdict_first(two_level); ent != NULL;
462 ent = qdict_next(two_level, ent)) {
463 QDict *dict = qobject_to(QDict, ent->value);
464 if (dict) {
465 child = qdict_crumple(dict, errp);
466 if (!child) {
467 goto error;
468 }
469
470 qdict_put_obj(multi_level, ent->key, child);
471 } else {
472 qdict_put_obj(multi_level, ent->key, qobject_ref(ent->value));
473 }
474 }
475 qobject_unref(two_level);
476 two_level = NULL;
477
478 /* Step 3: detect if we need to turn our dict into list */
479 is_list = qdict_is_list(multi_level, errp);
480 if (is_list < 0) {
481 goto error;
482 }
483
484 if (is_list) {
485 dst = QOBJECT(qlist_new());
486
487 for (i = 0; i < qdict_size(multi_level); i++) {
488 char *key = g_strdup_printf("%zu", i);
489
490 child = qdict_get(multi_level, key);
491 g_free(key);
492
493 if (!child) {
494 error_setg(errp, "Missing list index %zu", i);
495 goto error;
496 }
497
498 qlist_append_obj(qobject_to(QList, dst), qobject_ref(child));
499 }
500 qobject_unref(multi_level);
501 multi_level = NULL;
502 } else {
503 dst = QOBJECT(multi_level);
504 }
505
506 return dst;
507
508 error:
509 g_free(prefix);
510 qobject_unref(multi_level);
511 qobject_unref(two_level);
512 qobject_unref(dst);
513 return NULL;
514}
515
516/**
517 * qdict_array_entries(): Returns the number of direct array entries if the
518 * sub-QDict of src specified by the prefix in subqdict (or src itself for
519 * prefix == "") is valid as an array, i.e. the length of the created list if
520 * the sub-QDict would become empty after calling qdict_array_split() on it. If
521 * the array is not valid, -EINVAL is returned.
522 */
523int qdict_array_entries(QDict *src, const char *subqdict)
524{
525 const QDictEntry *entry;
526 unsigned i;
527 unsigned entries = 0;
528 size_t subqdict_len = strlen(subqdict);
529
530 assert(!subqdict_len || subqdict[subqdict_len - 1] == '.');
531
532 /* qdict_array_split() loops until UINT_MAX, but as we want to return
533 * negative errors, we only have a signed return value here. Any additional
534 * entries will lead to -EINVAL. */
535 for (i = 0; i < INT_MAX; i++) {
536 QObject *subqobj;
537 int subqdict_entries;
538 char *prefix = g_strdup_printf("%s%u.", subqdict, i);
539
540 subqdict_entries = qdict_count_prefixed_entries(src, prefix);
541
542 /* Remove ending "." */
543 prefix[strlen(prefix) - 1] = 0;
544 subqobj = qdict_get(src, prefix);
545
546 g_free(prefix);
547
548 if (subqdict_entries < 0) {
549 return subqdict_entries;
550 }
551
552 /* There may be either a single subordinate object (named "%u") or
553 * multiple objects (each with a key prefixed "%u."), but not both. */
554 if (subqobj && subqdict_entries) {
555 return -EINVAL;
556 } else if (!subqobj && !subqdict_entries) {
557 break;
558 }
559
560 entries += subqdict_entries ? subqdict_entries : 1;
561 }
562
563 /* Consider everything handled that isn't part of the given sub-QDict */
564 for (entry = qdict_first(src); entry; entry = qdict_next(src, entry)) {
565 if (!strstart(qdict_entry_key(entry), subqdict, NULL)) {
566 entries++;
567 }
568 }
569
570 /* Anything left in the sub-QDict that wasn't handled? */
571 if (qdict_size(src) != entries) {
572 return -EINVAL;
573 }
574
575 return i;
576}
577
578/**
579 * qdict_join(): Absorb the src QDict into the dest QDict, that is, move all
580 * elements from src to dest.
581 *
582 * If an element from src has a key already present in dest, it will not be
583 * moved unless overwrite is true.
584 *
585 * If overwrite is true, the conflicting values in dest will be discarded and
586 * replaced by the corresponding values from src.
587 *
588 * Therefore, with overwrite being true, the src QDict will always be empty when
589 * this function returns. If overwrite is false, the src QDict will be empty
590 * iff there were no conflicts.
591 */
592void qdict_join(QDict *dest, QDict *src, bool overwrite)
593{
594 const QDictEntry *entry, *next;
595
596 entry = qdict_first(src);
597 while (entry) {
598 next = qdict_next(src, entry);
599
600 if (overwrite || !qdict_haskey(dest, entry->key)) {
601 qdict_put_obj(dest, entry->key, qobject_ref(entry->value));
602 qdict_del(src, entry->key);
603 }
604
605 entry = next;
606 }
607}
608
609/**
610 * qdict_rename_keys(): Rename keys in qdict according to the replacements
611 * specified in the array renames. The array must be terminated by an entry
612 * with from = NULL.
613 *
614 * The renames are performed individually in the order of the array, so entries
615 * may be renamed multiple times and may or may not conflict depending on the
616 * order of the renames array.
617 *
618 * Returns true for success, false in error cases.
619 */
620bool qdict_rename_keys(QDict *qdict, const QDictRenames *renames, Error **errp)
621{
622 QObject *qobj;
623
624 while (renames->from) {
625 if (qdict_haskey(qdict, renames->from)) {
626 if (qdict_haskey(qdict, renames->to)) {
627 error_setg(errp, "'%s' and its alias '%s' can't be used at the "
628 "same time", renames->to, renames->from);
629 return false;
630 }
631
632 qobj = qdict_get(qdict, renames->from);
633 qdict_put_obj(qdict, renames->to, qobject_ref(qobj));
634 qdict_del(qdict, renames->from);
635 }
636
637 renames++;
638 }
639 return true;
640}
This page took 0.083357 seconds and 4 git commands to generate.