]> git.proxmox.com Git - mirror_qemu.git/blame - qom/object.c
qom: clean up/optimize object_dynamic_cast
[mirror_qemu.git] / qom / object.c
CommitLineData
2f28d2ff
AL
1/*
2 * QEMU Object Model
3 *
4 * Copyright IBM, Corp. 2011
5 *
6 * Authors:
7 * Anthony Liguori <aliguori@us.ibm.com>
8 *
9 * This work is licensed under the terms of the GNU GPL, version 2 or later.
10 * See the COPYING file in the top-level directory.
11 */
12
13#include "qemu/object.h"
14#include "qemu-common.h"
57c9fafe
AL
15#include "qapi/qapi-visit-core.h"
16#include "hw/qdev.h"
17// FIXME remove above
2f28d2ff
AL
18
19#define MAX_INTERFACES 32
20
21typedef struct InterfaceImpl InterfaceImpl;
22typedef struct TypeImpl TypeImpl;
23
24struct InterfaceImpl
25{
26 const char *parent;
27 void (*interface_initfn)(ObjectClass *class, void *data);
28 TypeImpl *type;
29};
30
31struct TypeImpl
32{
33 const char *name;
34
35 size_t class_size;
36
37 size_t instance_size;
38
39 void (*class_init)(ObjectClass *klass, void *data);
40 void (*class_finalize)(ObjectClass *klass, void *data);
41
42 void *class_data;
43
44 void (*instance_init)(Object *obj);
45 void (*instance_finalize)(Object *obj);
46
47 bool abstract;
48
49 const char *parent;
50 TypeImpl *parent_type;
51
52 ObjectClass *class;
53
54 int num_interfaces;
55 InterfaceImpl interfaces[MAX_INTERFACES];
56};
57
58typedef struct Interface
59{
60 Object parent;
61 Object *obj;
62} Interface;
63
64#define INTERFACE(obj) OBJECT_CHECK(Interface, obj, TYPE_INTERFACE)
65
66static GHashTable *type_table_get(void)
67{
68 static GHashTable *type_table;
69
70 if (type_table == NULL) {
71 type_table = g_hash_table_new(g_str_hash, g_str_equal);
72 }
73
74 return type_table;
75}
76
77static void type_table_add(TypeImpl *ti)
78{
79 g_hash_table_insert(type_table_get(), (void *)ti->name, ti);
80}
81
82static TypeImpl *type_table_lookup(const char *name)
83{
84 return g_hash_table_lookup(type_table_get(), name);
85}
86
87TypeImpl *type_register(const TypeInfo *info)
88{
89 TypeImpl *ti = g_malloc0(sizeof(*ti));
90
91 g_assert(info->name != NULL);
92
73093354
AL
93 if (type_table_lookup(info->name) != NULL) {
94 fprintf(stderr, "Registering `%s' which already exists\n", info->name);
95 abort();
96 }
97
2f28d2ff
AL
98 ti->name = g_strdup(info->name);
99 ti->parent = g_strdup(info->parent);
100
101 ti->class_size = info->class_size;
102 ti->instance_size = info->instance_size;
103
104 ti->class_init = info->class_init;
105 ti->class_finalize = info->class_finalize;
106 ti->class_data = info->class_data;
107
108 ti->instance_init = info->instance_init;
109 ti->instance_finalize = info->instance_finalize;
110
111 ti->abstract = info->abstract;
112
113 if (info->interfaces) {
114 int i;
115
116 for (i = 0; info->interfaces[i].type; i++) {
117 ti->interfaces[i].parent = info->interfaces[i].type;
118 ti->interfaces[i].interface_initfn = info->interfaces[i].interface_initfn;
119 ti->num_interfaces++;
120 }
121 }
122
123 type_table_add(ti);
124
125 return ti;
126}
127
128TypeImpl *type_register_static(const TypeInfo *info)
129{
130 return type_register(info);
131}
132
133static TypeImpl *type_get_by_name(const char *name)
134{
135 if (name == NULL) {
136 return NULL;
137 }
138
139 return type_table_lookup(name);
140}
141
142static TypeImpl *type_get_parent(TypeImpl *type)
143{
144 if (!type->parent_type && type->parent) {
145 type->parent_type = type_get_by_name(type->parent);
146 g_assert(type->parent_type != NULL);
147 }
148
149 return type->parent_type;
150}
151
152static bool type_has_parent(TypeImpl *type)
153{
154 return (type->parent != NULL);
155}
156
157static size_t type_class_get_size(TypeImpl *ti)
158{
159 if (ti->class_size) {
160 return ti->class_size;
161 }
162
163 if (type_has_parent(ti)) {
164 return type_class_get_size(type_get_parent(ti));
165 }
166
167 return sizeof(ObjectClass);
168}
169
170static void type_class_interface_init(TypeImpl *ti, InterfaceImpl *iface)
171{
172 TypeInfo info = {
173 .instance_size = sizeof(Interface),
174 .parent = iface->parent,
175 .class_size = sizeof(InterfaceClass),
176 .class_init = iface->interface_initfn,
177 .abstract = true,
178 };
179 char *name = g_strdup_printf("<%s::%s>", ti->name, iface->parent);
180
181 info.name = name;
182 iface->type = type_register(&info);
183 g_free(name);
184}
185
186static void type_class_init(TypeImpl *ti)
187{
188 size_t class_size = sizeof(ObjectClass);
189 int i;
190
191 if (ti->class) {
192 return;
193 }
194
195 ti->class_size = type_class_get_size(ti);
196
197 ti->class = g_malloc0(ti->class_size);
198 ti->class->type = ti;
199
200 if (type_has_parent(ti)) {
201 TypeImpl *parent = type_get_parent(ti);
202
203 type_class_init(parent);
204
205 class_size = parent->class_size;
206 g_assert(parent->class_size <= ti->class_size);
207
208 memcpy((void *)ti->class + sizeof(ObjectClass),
209 (void *)parent->class + sizeof(ObjectClass),
210 parent->class_size - sizeof(ObjectClass));
211 }
212
213 memset((void *)ti->class + class_size, 0, ti->class_size - class_size);
214
215 for (i = 0; i < ti->num_interfaces; i++) {
216 type_class_interface_init(ti, &ti->interfaces[i]);
217 }
218
219 if (ti->class_init) {
220 ti->class_init(ti->class, ti->class_data);
221 }
222}
223
224static void object_interface_init(Object *obj, InterfaceImpl *iface)
225{
226 TypeImpl *ti = iface->type;
227 Interface *iface_obj;
228
229 iface_obj = INTERFACE(object_new(ti->name));
230 iface_obj->obj = obj;
231
232 obj->interfaces = g_slist_prepend(obj->interfaces, iface_obj);
233}
234
235static void object_init_with_type(Object *obj, TypeImpl *ti)
236{
237 int i;
238
239 if (type_has_parent(ti)) {
240 object_init_with_type(obj, type_get_parent(ti));
241 }
242
243 for (i = 0; i < ti->num_interfaces; i++) {
244 object_interface_init(obj, &ti->interfaces[i]);
245 }
246
247 if (ti->instance_init) {
248 ti->instance_init(obj);
249 }
250}
251
252void object_initialize_with_type(void *data, TypeImpl *type)
253{
254 Object *obj = data;
255
256 g_assert(type != NULL);
257 g_assert(type->instance_size >= sizeof(ObjectClass));
258
259 type_class_init(type);
260 g_assert(type->abstract == false);
261
262 memset(obj, 0, type->instance_size);
263 obj->class = type->class;
57c9fafe 264 QTAILQ_INIT(&obj->properties);
2f28d2ff
AL
265 object_init_with_type(obj, type);
266}
267
268void object_initialize(void *data, const char *typename)
269{
270 TypeImpl *type = type_get_by_name(typename);
271
272 object_initialize_with_type(data, type);
273}
274
57c9fafe
AL
275static void object_property_del_all(Object *obj)
276{
277 while (!QTAILQ_EMPTY(&obj->properties)) {
278 ObjectProperty *prop = QTAILQ_FIRST(&obj->properties);
279
280 QTAILQ_REMOVE(&obj->properties, prop, node);
281
282 if (prop->release) {
283 prop->release(obj, prop->name, prop->opaque);
284 }
285
286 g_free(prop->name);
287 g_free(prop->type);
288 g_free(prop);
289 }
290}
291
292static void object_property_del_child(Object *obj, Object *child, Error **errp)
293{
294 ObjectProperty *prop;
295
296 QTAILQ_FOREACH(prop, &obj->properties, node) {
297 if (!strstart(prop->type, "child<", NULL)) {
298 continue;
299 }
300
301 if (prop->opaque == child) {
302 object_property_del(obj, prop->name, errp);
303 }
304 }
305}
306
307void object_unparent(Object *obj)
308{
309 if (obj->parent) {
310 object_property_del_child(obj->parent, obj, NULL);
311 }
312}
313
2f28d2ff
AL
314static void object_deinit(Object *obj, TypeImpl *type)
315{
316 if (type->instance_finalize) {
317 type->instance_finalize(obj);
318 }
319
320 while (obj->interfaces) {
321 Interface *iface_obj = obj->interfaces->data;
322 obj->interfaces = g_slist_delete_link(obj->interfaces, obj->interfaces);
323 object_delete(OBJECT(iface_obj));
324 }
325
326 if (type_has_parent(type)) {
327 object_deinit(obj, type_get_parent(type));
328 }
57c9fafe
AL
329
330 object_unparent(obj);
2f28d2ff
AL
331}
332
333void object_finalize(void *data)
334{
335 Object *obj = data;
336 TypeImpl *ti = obj->class->type;
337
338 object_deinit(obj, ti);
57c9fafe 339 object_property_del_all(obj);
db85b575
AL
340
341 g_assert(obj->ref == 0);
2f28d2ff
AL
342}
343
344Object *object_new_with_type(Type type)
345{
346 Object *obj;
347
348 g_assert(type != NULL);
349
350 obj = g_malloc(type->instance_size);
351 object_initialize_with_type(obj, type);
db85b575 352 object_ref(obj);
2f28d2ff
AL
353
354 return obj;
355}
356
357Object *object_new(const char *typename)
358{
359 TypeImpl *ti = type_get_by_name(typename);
360
361 return object_new_with_type(ti);
362}
363
364void object_delete(Object *obj)
365{
db85b575
AL
366 object_unref(obj);
367 g_assert(obj->ref == 0);
2f28d2ff
AL
368 g_free(obj);
369}
370
acc4af3f 371static bool type_is_ancestor(TypeImpl *type, TypeImpl *target_type)
2f28d2ff 372{
acc4af3f 373 assert(target_type);
2f28d2ff
AL
374
375 /* Check if typename is a direct ancestor of type */
376 while (type) {
377 if (type == target_type) {
378 return true;
379 }
380
381 type = type_get_parent(type);
382 }
383
acc4af3f
PB
384 return false;
385}
2f28d2ff 386
acc4af3f
PB
387static bool object_is_type(Object *obj, const char *typename)
388{
389 TypeImpl *target_type;
2f28d2ff 390
acc4af3f
PB
391 if (typename == TYPE_OBJECT) {
392 return true;
393 }
394 target_type = type_get_by_name(typename);
395 return type_is_ancestor(obj->class->type, target_type);
2f28d2ff
AL
396}
397
398Object *object_dynamic_cast(Object *obj, const char *typename)
399{
400 GSList *i;
401
acc4af3f
PB
402 /* Check if typename is a direct ancestor. Special-case TYPE_OBJECT,
403 * we want to go back from interfaces to the parent.
404 */
405 if (typename && object_is_type(obj, typename)) {
406 return obj;
407 }
408
409 /* Check if obj is an interface and its containing object is a direct
410 * ancestor of typename. In principle we could do this test at the very
411 * beginning of object_dynamic_cast, avoiding a second call to
412 * object_is_type. However, casting between interfaces is relatively
413 * rare, and object_is_type(obj, TYPE_INTERFACE) would fail almost always.
414 *
415 * Perhaps we could add a magic value to the object header for increased
416 * (run-time) type safety and to speed up tests like this one. If we ever
417 * do that we can revisit the order here.
418 */
419 if (object_is_type(obj, TYPE_INTERFACE)) {
420 assert(!obj->interfaces);
421 obj = INTERFACE(obj)->obj;
422 if (object_is_type(obj, typename)) {
423 return obj;
424 }
425 }
426
427 if (typename == TYPE_OBJECT) {
2f28d2ff
AL
428 return obj;
429 }
430
431 /* Check if obj has an interface of typename */
432 for (i = obj->interfaces; i; i = i->next) {
433 Interface *iface = i->data;
434
435 if (object_is_type(OBJECT(iface), typename)) {
436 return OBJECT(iface);
437 }
438 }
439
2f28d2ff
AL
440 return NULL;
441}
442
443
444static void register_interface(void)
445{
446 static TypeInfo interface_info = {
447 .name = TYPE_INTERFACE,
448 .instance_size = sizeof(Interface),
449 .abstract = true,
450 };
451
452 type_register_static(&interface_info);
453}
454
455device_init(register_interface);
456
457Object *object_dynamic_cast_assert(Object *obj, const char *typename)
458{
459 Object *inst;
460
461 inst = object_dynamic_cast(obj, typename);
462
463 if (!inst) {
464 fprintf(stderr, "Object %p is not an instance of type %s\n",
465 obj, typename);
466 abort();
467 }
468
469 return inst;
470}
471
472ObjectClass *object_class_dynamic_cast(ObjectClass *class,
473 const char *typename)
474{
475 TypeImpl *target_type = type_get_by_name(typename);
476 TypeImpl *type = class->type;
477
478 while (type) {
479 if (type == target_type) {
480 return class;
481 }
482
483 type = type_get_parent(type);
484 }
485
486 return NULL;
487}
488
489ObjectClass *object_class_dynamic_cast_assert(ObjectClass *class,
490 const char *typename)
491{
492 ObjectClass *ret = object_class_dynamic_cast(class, typename);
493
494 if (!ret) {
495 fprintf(stderr, "Object %p is not an instance of type %s\n",
496 class, typename);
497 abort();
498 }
499
500 return ret;
501}
502
503const char *object_get_typename(Object *obj)
504{
505 return obj->class->type->name;
506}
507
508ObjectClass *object_get_class(Object *obj)
509{
510 return obj->class;
511}
512
513const char *object_class_get_name(ObjectClass *klass)
514{
515 return klass->type->name;
516}
517
518ObjectClass *object_class_by_name(const char *typename)
519{
520 TypeImpl *type = type_get_by_name(typename);
521
522 if (!type) {
523 return NULL;
524 }
525
526 type_class_init(type);
527
528 return type->class;
529}
530
531typedef struct OCFData
532{
533 void (*fn)(ObjectClass *klass, void *opaque);
93c511a1
AL
534 const char *implements_type;
535 bool include_abstract;
2f28d2ff
AL
536 void *opaque;
537} OCFData;
538
539static void object_class_foreach_tramp(gpointer key, gpointer value,
540 gpointer opaque)
541{
542 OCFData *data = opaque;
543 TypeImpl *type = value;
93c511a1 544 ObjectClass *k;
2f28d2ff
AL
545
546 type_class_init(type);
93c511a1 547 k = type->class;
2f28d2ff 548
93c511a1
AL
549 if (!data->include_abstract && type->abstract) {
550 return;
551 }
552
553 if (data->implements_type &&
554 !object_class_dynamic_cast(k, data->implements_type)) {
555 return;
556 }
557
558 data->fn(k, data->opaque);
2f28d2ff
AL
559}
560
561void object_class_foreach(void (*fn)(ObjectClass *klass, void *opaque),
93c511a1 562 const char *implements_type, bool include_abstract,
2f28d2ff
AL
563 void *opaque)
564{
93c511a1 565 OCFData data = { fn, implements_type, include_abstract, opaque };
2f28d2ff
AL
566
567 g_hash_table_foreach(type_table_get(), object_class_foreach_tramp, &data);
568}
57c9fafe
AL
569
570void object_ref(Object *obj)
571{
572 obj->ref++;
573}
574
575void object_unref(Object *obj)
576{
577 g_assert(obj->ref > 0);
578 obj->ref--;
579
580 /* parent always holds a reference to its children */
581 if (obj->ref == 0) {
582 object_finalize(obj);
583 }
584}
585
586void object_property_add(Object *obj, const char *name, const char *type,
587 ObjectPropertyAccessor *get,
588 ObjectPropertyAccessor *set,
589 ObjectPropertyRelease *release,
590 void *opaque, Error **errp)
591{
592 ObjectProperty *prop = g_malloc0(sizeof(*prop));
593
594 prop->name = g_strdup(name);
595 prop->type = g_strdup(type);
596
597 prop->get = get;
598 prop->set = set;
599 prop->release = release;
600 prop->opaque = opaque;
601
602 QTAILQ_INSERT_TAIL(&obj->properties, prop, node);
603}
604
605static ObjectProperty *object_property_find(Object *obj, const char *name)
606{
607 ObjectProperty *prop;
608
609 QTAILQ_FOREACH(prop, &obj->properties, node) {
610 if (strcmp(prop->name, name) == 0) {
611 return prop;
612 }
613 }
614
615 return NULL;
616}
617
618void object_property_del(Object *obj, const char *name, Error **errp)
619{
620 ObjectProperty *prop = object_property_find(obj, name);
621
622 QTAILQ_REMOVE(&obj->properties, prop, node);
623
624 prop->release(obj, prop->name, prop->opaque);
625
626 g_free(prop->name);
627 g_free(prop->type);
628 g_free(prop);
629}
630
631void object_property_get(Object *obj, Visitor *v, const char *name,
632 Error **errp)
633{
634 ObjectProperty *prop = object_property_find(obj, name);
635
636 if (prop == NULL) {
637 error_set(errp, QERR_PROPERTY_NOT_FOUND, "", name);
638 return;
639 }
640
641 if (!prop->get) {
642 error_set(errp, QERR_PERMISSION_DENIED);
643 } else {
644 prop->get(obj, v, prop->opaque, name, errp);
645 }
646}
647
648void object_property_set(Object *obj, Visitor *v, const char *name,
649 Error **errp)
650{
651 ObjectProperty *prop = object_property_find(obj, name);
652
653 if (prop == NULL) {
654 error_set(errp, QERR_PROPERTY_NOT_FOUND, "", name);
655 return;
656 }
657
658 if (!prop->set) {
659 error_set(errp, QERR_PERMISSION_DENIED);
660 } else {
661 prop->set(obj, v, prop->opaque, name, errp);
662 }
663}
664
665const char *object_property_get_type(Object *obj, const char *name, Error **errp)
666{
667 ObjectProperty *prop = object_property_find(obj, name);
668
669 if (prop == NULL) {
670 error_set(errp, QERR_PROPERTY_NOT_FOUND, "", name);
671 return NULL;
672 }
673
674 return prop->type;
675}
676
677Object *object_get_root(void)
678{
8b45d447 679 static Object *root;
57c9fafe 680
8b45d447
AL
681 if (!root) {
682 root = object_new("container");
57c9fafe
AL
683 }
684
8b45d447 685 return root;
57c9fafe
AL
686}
687
688static void object_get_child_property(Object *obj, Visitor *v, void *opaque,
689 const char *name, Error **errp)
690{
691 Object *child = opaque;
692 gchar *path;
693
694 path = object_get_canonical_path(child);
695 visit_type_str(v, &path, name, errp);
696 g_free(path);
697}
698
db85b575
AL
699static void object_finalize_child_property(Object *obj, const char *name,
700 void *opaque)
701{
702 Object *child = opaque;
703
704 object_unref(child);
705}
706
57c9fafe
AL
707void object_property_add_child(Object *obj, const char *name,
708 Object *child, Error **errp)
709{
710 gchar *type;
711
712 type = g_strdup_printf("child<%s>", object_get_typename(OBJECT(child)));
713
714 object_property_add(obj, name, type, object_get_child_property,
db85b575 715 NULL, object_finalize_child_property, child, errp);
57c9fafe
AL
716
717 object_ref(child);
718 g_assert(child->parent == NULL);
719 child->parent = obj;
720
721 g_free(type);
722}
723
724static void object_get_link_property(Object *obj, Visitor *v, void *opaque,
725 const char *name, Error **errp)
726{
727 Object **child = opaque;
728 gchar *path;
729
730 if (*child) {
731 path = object_get_canonical_path(*child);
732 visit_type_str(v, &path, name, errp);
733 g_free(path);
734 } else {
735 path = (gchar *)"";
736 visit_type_str(v, &path, name, errp);
737 }
738}
739
740static void object_set_link_property(Object *obj, Visitor *v, void *opaque,
741 const char *name, Error **errp)
742{
743 Object **child = opaque;
744 bool ambiguous = false;
745 const char *type;
746 char *path;
747
748 type = object_property_get_type(obj, name, NULL);
749
750 visit_type_str(v, &path, name, errp);
751
752 if (*child) {
753 object_unref(*child);
754 }
755
756 if (strcmp(path, "") != 0) {
757 Object *target;
758
759 target = object_resolve_path(path, &ambiguous);
760 if (target) {
761 gchar *target_type;
762
fe40e627
AL
763 target_type = g_strdup(&type[5]);
764 target_type[strlen(target_type) - 2] = 0;
765
766 if (object_dynamic_cast(target, target_type)) {
57c9fafe 767 object_ref(target);
fe40e627 768 *child = target;
57c9fafe
AL
769 } else {
770 error_set(errp, QERR_INVALID_PARAMETER_TYPE, name, type);
771 }
772
773 g_free(target_type);
774 } else {
775 error_set(errp, QERR_DEVICE_NOT_FOUND, path);
776 }
777 } else {
778 *child = NULL;
779 }
780
781 g_free(path);
782}
783
784void object_property_add_link(Object *obj, const char *name,
785 const char *type, Object **child,
786 Error **errp)
787{
788 gchar *full_type;
789
790 full_type = g_strdup_printf("link<%s>", type);
791
792 object_property_add(obj, name, full_type,
793 object_get_link_property,
794 object_set_link_property,
795 NULL, child, errp);
796
797 g_free(full_type);
798}
799
800gchar *object_get_canonical_path(Object *obj)
801{
802 Object *root = object_get_root();
803 char *newpath = NULL, *path = NULL;
804
805 while (obj != root) {
806 ObjectProperty *prop = NULL;
807
808 g_assert(obj->parent != NULL);
809
810 QTAILQ_FOREACH(prop, &obj->parent->properties, node) {
811 if (!strstart(prop->type, "child<", NULL)) {
812 continue;
813 }
814
815 if (prop->opaque == obj) {
816 if (path) {
817 newpath = g_strdup_printf("%s/%s", prop->name, path);
818 g_free(path);
819 path = newpath;
820 } else {
821 path = g_strdup(prop->name);
822 }
823 break;
824 }
825 }
826
827 g_assert(prop != NULL);
828
829 obj = obj->parent;
830 }
831
832 newpath = g_strdup_printf("/%s", path);
833 g_free(path);
834
835 return newpath;
836}
837
838static Object *object_resolve_abs_path(Object *parent,
839 gchar **parts,
840 int index)
841{
842 ObjectProperty *prop;
843 Object *child;
844
845 if (parts[index] == NULL) {
846 return parent;
847 }
848
849 if (strcmp(parts[index], "") == 0) {
850 return object_resolve_abs_path(parent, parts, index + 1);
851 }
852
853 prop = object_property_find(parent, parts[index]);
854 if (prop == NULL) {
855 return NULL;
856 }
857
858 child = NULL;
859 if (strstart(prop->type, "link<", NULL)) {
860 Object **pchild = prop->opaque;
861 if (*pchild) {
862 child = *pchild;
863 }
864 } else if (strstart(prop->type, "child<", NULL)) {
865 child = prop->opaque;
866 }
867
868 if (!child) {
869 return NULL;
870 }
871
872 return object_resolve_abs_path(child, parts, index + 1);
873}
874
875static Object *object_resolve_partial_path(Object *parent,
876 gchar **parts,
877 bool *ambiguous)
878{
879 Object *obj;
880 ObjectProperty *prop;
881
882 obj = object_resolve_abs_path(parent, parts, 0);
883
884 QTAILQ_FOREACH(prop, &parent->properties, node) {
885 Object *found;
886
887 if (!strstart(prop->type, "child<", NULL)) {
888 continue;
889 }
890
891 found = object_resolve_partial_path(prop->opaque, parts, ambiguous);
892 if (found) {
893 if (obj) {
894 if (ambiguous) {
895 *ambiguous = true;
896 }
897 return NULL;
898 }
899 obj = found;
900 }
901
902 if (ambiguous && *ambiguous) {
903 return NULL;
904 }
905 }
906
907 return obj;
908}
909
910Object *object_resolve_path(const char *path, bool *ambiguous)
911{
912 bool partial_path = true;
913 Object *obj;
914 gchar **parts;
915
916 parts = g_strsplit(path, "/", 0);
917 if (parts == NULL || parts[0] == NULL) {
918 g_strfreev(parts);
919 return object_get_root();
920 }
921
922 if (strcmp(parts[0], "") == 0) {
923 partial_path = false;
924 }
925
926 if (partial_path) {
927 if (ambiguous) {
928 *ambiguous = false;
929 }
930 obj = object_resolve_partial_path(object_get_root(), parts, ambiguous);
931 } else {
932 obj = object_resolve_abs_path(object_get_root(), parts, 1);
933 }
934
935 g_strfreev(parts);
936
937 return obj;
938}
939
940typedef struct StringProperty
941{
942 char *(*get)(Object *, Error **);
943 void (*set)(Object *, const char *, Error **);
944} StringProperty;
945
946static void object_property_get_str(Object *obj, Visitor *v, void *opaque,
947 const char *name, Error **errp)
948{
949 StringProperty *prop = opaque;
950 char *value;
951
952 value = prop->get(obj, errp);
953 if (value) {
954 visit_type_str(v, &value, name, errp);
955 g_free(value);
956 }
957}
958
959static void object_property_set_str(Object *obj, Visitor *v, void *opaque,
960 const char *name, Error **errp)
961{
962 StringProperty *prop = opaque;
963 char *value;
964 Error *local_err = NULL;
965
966 visit_type_str(v, &value, name, &local_err);
967 if (local_err) {
968 error_propagate(errp, local_err);
969 return;
970 }
971
972 prop->set(obj, value, errp);
973 g_free(value);
974}
975
976static void object_property_release_str(Object *obj, const char *name,
977 void *opaque)
978{
979 StringProperty *prop = opaque;
980 g_free(prop);
981}
982
983void object_property_add_str(Object *obj, const char *name,
984 char *(*get)(Object *, Error **),
985 void (*set)(Object *, const char *, Error **),
986 Error **errp)
987{
988 StringProperty *prop = g_malloc0(sizeof(*prop));
989
990 prop->get = get;
991 prop->set = set;
992
993 object_property_add(obj, name, "string",
994 get ? object_property_get_str : NULL,
995 set ? object_property_set_str : NULL,
996 object_property_release_str,
997 prop, errp);
998}