diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms index a2addca9c3..6331f1a734 100644 --- a/src/libvirt_private.syms +++ b/src/libvirt_private.syms @@ -1933,6 +1933,7 @@ virJSONValueObjectAppendNumberUlong; virJSONValueObjectAppendString; virJSONValueObjectCreate; virJSONValueObjectCreateVArgs; +virJSONValueObjectDeflatten; virJSONValueObjectForeachKeyValue; virJSONValueObjectGet; virJSONValueObjectGetArray; diff --git a/src/util/virjson.c b/src/util/virjson.c index 76d1d36f17..3c3a54bc7c 100644 --- a/src/util/virjson.c +++ b/src/util/virjson.c @@ -1965,3 +1965,64 @@ virJSONStringReformat(const char *jsonstr, virJSONValueFree(json); return ret; } + + +static int +virJSONValueObjectDeflattenWorker(const char *key, + virJSONValuePtr value, + void *opaque) +{ + virJSONValuePtr retobj = opaque; + virJSONValuePtr newval = NULL; + const char *newkey; + + if (!(newkey = STRSKIP(key, "file."))) { + virReportError(VIR_ERR_INVALID_ARG, "%s", + _("JSON object is neither nested nor flattened")); + return -1; + } + + if (!(newval = virJSONValueCopy(value))) + return -1; + + if (virJSONValueObjectAppend(retobj, newkey, newval) < 0) { + virJSONValueFree(newval); + return -1; + } + + return 0; +} + + +/** + * virJSONValueObjectDeflatten: + * + * In some cases it's possible to nest JSON objects by prefixing object members + * with the parent object name followed by the dot and then the attribute name + * rather than directly using a nested value object (e.g qemu's JSON + * pseudo-protocol in backing file definition). + * + * This function will attempt to reverse the process and provide a nested json + * hierarchy so that the parsers can be kept simple and we still can use the + * weird syntax some users might use. + * + * Currently this function will flatten out just the 'file.' prefix into a new + * tree. Any other syntax will be rejected. + */ +virJSONValuePtr +virJSONValueObjectDeflatten(virJSONValuePtr json) +{ + virJSONValuePtr ret; + + if (!(ret = virJSONValueNewObject())) + return NULL; + + if (virJSONValueObjectForeachKeyValue(json, + virJSONValueObjectDeflattenWorker, + ret) < 0) { + virJSONValueFree(ret); + return NULL; + } + + return ret; +} diff --git a/src/util/virjson.h b/src/util/virjson.h index c9d9752de1..e89a776ab5 100644 --- a/src/util/virjson.h +++ b/src/util/virjson.h @@ -186,4 +186,6 @@ virJSONValuePtr virJSONValueCopy(const virJSONValue *in); char *virJSONStringReformat(const char *jsonstr, bool pretty); +virJSONValuePtr virJSONValueObjectDeflatten(virJSONValuePtr json); + #endif /* __VIR_JSON_H_ */ diff --git a/src/util/virstoragefile.c b/src/util/virstoragefile.c index f0ed5c6bd4..52c5301fff 100644 --- a/src/util/virstoragefile.c +++ b/src/util/virstoragefile.c @@ -3244,69 +3244,6 @@ static const struct virStorageSourceJSONDriverParser jsonParsers[] = { }; -static int -virStorageSourceParseBackingJSONDeflattenWorker(const char *key, - virJSONValuePtr value, - void *opaque) -{ - virJSONValuePtr retobj = opaque; - virJSONValuePtr newval = NULL; - const char *newkey; - - if (!(newkey = STRSKIP(key, "file."))) { - virReportError(VIR_ERR_INVALID_ARG, "%s", - _("JSON backing file syntax is neither nested nor " - "flattened")); - return -1; - } - - if (!(newval = virJSONValueCopy(value))) - return -1; - - if (virJSONValueObjectAppend(retobj, newkey, newval) < 0) { - virJSONValueFree(newval); - return -1; - } - - return 0; -} - - -/** - * virStorageSourceParseBackingJSONDeflatten: - * - * The json: pseudo-protocol syntax in qemu allows multiple approaches to - * describe nesting of the values. This is due to the lax handling of the string - * in qemu and the fact that internally qemu is flattening the values using '.'. - * - * This allows to specify nested json strings either using nested json objects - * or prefixing object members with the parent object name followed by the dot. - * - * This function will attempt to reverse the process and provide a nested json - * hierarchy so that the parsers can be kept simple and we still can use the - * weird syntax some users might use. - * - * Currently this function will flatten out just the 'file.' prefix into a new - * tree. Any other syntax will be rejected. - */ -static virJSONValuePtr -virStorageSourceParseBackingJSONDeflatten(virJSONValuePtr json) -{ - virJSONValuePtr ret; - - if (!(ret = virJSONValueNewObject())) - return NULL; - - if (virJSONValueObjectForeachKeyValue(json, - virStorageSourceParseBackingJSONDeflattenWorker, - ret) < 0) { - virJSONValueFree(ret); - return NULL; - } - - return ret; -} - static int virStorageSourceParseBackingJSONInternal(virStorageSourcePtr src, @@ -3320,7 +3257,7 @@ virStorageSourceParseBackingJSONInternal(virStorageSourcePtr src, int ret = -1; if (!(file = virJSONValueObjectGetObject(json, "file"))) { - if (!(fixedroot = virStorageSourceParseBackingJSONDeflatten(json))) + if (!(fixedroot = virJSONValueObjectDeflatten(json))) goto cleanup; file = fixedroot;