qemu

FORK: QEMU emulator
git clone https://git.neptards.moe/neptards/qemu.git
Log | Files | Refs | Submodules | LICENSE

qapi-clone-visitor.c (5559B)


      1 /*
      2  * Copy one QAPI object to another
      3  *
      4  * Copyright (C) 2016 Red Hat, Inc.
      5  *
      6  * This work is licensed under the terms of the GNU GPL, version 2 or later.
      7  * See the COPYING file in the top-level directory.
      8  *
      9  */
     10 
     11 #include "qemu/osdep.h"
     12 #include "qapi/clone-visitor.h"
     13 #include "qapi/visitor-impl.h"
     14 #include "qapi/error.h"
     15 #include "qapi/qmp/qnull.h"
     16 
     17 struct QapiCloneVisitor {
     18     Visitor visitor;
     19     size_t depth;
     20 };
     21 
     22 static QapiCloneVisitor *to_qcv(Visitor *v)
     23 {
     24     return container_of(v, QapiCloneVisitor, visitor);
     25 }
     26 
     27 static bool qapi_clone_start_struct(Visitor *v, const char *name, void **obj,
     28                                     size_t size, Error **errp)
     29 {
     30     QapiCloneVisitor *qcv = to_qcv(v);
     31 
     32     if (!obj) {
     33         assert(qcv->depth);
     34         /* Only possible when visiting an alternate's object
     35          * branch. Nothing further to do here, since the earlier
     36          * visit_start_alternate() already copied memory. */
     37         return true;
     38     }
     39 
     40     *obj = g_memdup(*obj, size);
     41     qcv->depth++;
     42     return true;
     43 }
     44 
     45 static void qapi_clone_end(Visitor *v, void **obj)
     46 {
     47     QapiCloneVisitor *qcv = to_qcv(v);
     48 
     49     assert(qcv->depth);
     50     if (obj) {
     51         qcv->depth--;
     52     }
     53 }
     54 
     55 static bool qapi_clone_start_list(Visitor *v, const char *name,
     56                                   GenericList **listp, size_t size,
     57                                   Error **errp)
     58 {
     59     return qapi_clone_start_struct(v, name, (void **)listp, size, errp);
     60 }
     61 
     62 static GenericList *qapi_clone_next_list(Visitor *v, GenericList *tail,
     63                                          size_t size)
     64 {
     65     QapiCloneVisitor *qcv = to_qcv(v);
     66 
     67     assert(qcv->depth);
     68     /* Unshare the tail of the list cloned by g_memdup() */
     69     tail->next = g_memdup(tail->next, size);
     70     return tail->next;
     71 }
     72 
     73 static bool qapi_clone_start_alternate(Visitor *v, const char *name,
     74                                        GenericAlternate **obj, size_t size,
     75                                        Error **errp)
     76 {
     77     return qapi_clone_start_struct(v, name, (void **)obj, size, errp);
     78 }
     79 
     80 static bool qapi_clone_type_int64(Visitor *v, const char *name, int64_t *obj,
     81                                   Error **errp)
     82 {
     83     QapiCloneVisitor *qcv = to_qcv(v);
     84 
     85     assert(qcv->depth);
     86     /* Value was already cloned by g_memdup() */
     87     return true;
     88 }
     89 
     90 static bool qapi_clone_type_uint64(Visitor *v, const char *name,
     91                                    uint64_t *obj, Error **errp)
     92 {
     93     QapiCloneVisitor *qcv = to_qcv(v);
     94 
     95     assert(qcv->depth);
     96     /* Value was already cloned by g_memdup() */
     97     return true;
     98 }
     99 
    100 static bool qapi_clone_type_bool(Visitor *v, const char *name, bool *obj,
    101                                  Error **errp)
    102 {
    103     QapiCloneVisitor *qcv = to_qcv(v);
    104 
    105     assert(qcv->depth);
    106     /* Value was already cloned by g_memdup() */
    107     return true;
    108 }
    109 
    110 static bool qapi_clone_type_str(Visitor *v, const char *name, char **obj,
    111                                 Error **errp)
    112 {
    113     QapiCloneVisitor *qcv = to_qcv(v);
    114 
    115     assert(qcv->depth);
    116     /*
    117      * Pointer was already cloned by g_memdup; create fresh copy.
    118      * Note that as long as qobject-output-visitor accepts NULL instead of
    119      * "", then we must do likewise. However, we want to obey the
    120      * input visitor semantics of never producing NULL when the empty
    121      * string is intended.
    122      */
    123     *obj = g_strdup(*obj ?: "");
    124     return true;
    125 }
    126 
    127 static bool qapi_clone_type_number(Visitor *v, const char *name, double *obj,
    128                                    Error **errp)
    129 {
    130     QapiCloneVisitor *qcv = to_qcv(v);
    131 
    132     assert(qcv->depth);
    133     /* Value was already cloned by g_memdup() */
    134     return true;
    135 }
    136 
    137 static bool qapi_clone_type_null(Visitor *v, const char *name, QNull **obj,
    138                                  Error **errp)
    139 {
    140     QapiCloneVisitor *qcv = to_qcv(v);
    141 
    142     assert(qcv->depth);
    143     *obj = qnull();
    144     return true;
    145 }
    146 
    147 static void qapi_clone_free(Visitor *v)
    148 {
    149     g_free(v);
    150 }
    151 
    152 static Visitor *qapi_clone_visitor_new(void)
    153 {
    154     QapiCloneVisitor *v;
    155 
    156     v = g_malloc0(sizeof(*v));
    157 
    158     v->visitor.type = VISITOR_CLONE;
    159     v->visitor.start_struct = qapi_clone_start_struct;
    160     v->visitor.end_struct = qapi_clone_end;
    161     v->visitor.start_list = qapi_clone_start_list;
    162     v->visitor.next_list = qapi_clone_next_list;
    163     v->visitor.end_list = qapi_clone_end;
    164     v->visitor.start_alternate = qapi_clone_start_alternate;
    165     v->visitor.end_alternate = qapi_clone_end;
    166     v->visitor.type_int64 = qapi_clone_type_int64;
    167     v->visitor.type_uint64 = qapi_clone_type_uint64;
    168     v->visitor.type_bool = qapi_clone_type_bool;
    169     v->visitor.type_str = qapi_clone_type_str;
    170     v->visitor.type_number = qapi_clone_type_number;
    171     v->visitor.type_null = qapi_clone_type_null;
    172     v->visitor.free = qapi_clone_free;
    173 
    174     return &v->visitor;
    175 }
    176 
    177 void *qapi_clone(const void *src, bool (*visit_type)(Visitor *, const char *,
    178                                                      void **, Error **))
    179 {
    180     Visitor *v;
    181     void *dst = (void *) src; /* Cast away const */
    182 
    183     if (!src) {
    184         return NULL;
    185     }
    186 
    187     v = qapi_clone_visitor_new();
    188     visit_type(v, NULL, &dst, &error_abort);
    189     visit_free(v);
    190     return dst;
    191 }
    192 
    193 void qapi_clone_members(void *dst, const void *src, size_t sz,
    194                         bool (*visit_type_members)(Visitor *, void *,
    195                                                    Error **))
    196 {
    197     Visitor *v;
    198 
    199     v = qapi_clone_visitor_new();
    200     memcpy(dst, src, sz);
    201     to_qcv(v)->depth++;
    202     visit_type_members(v, dst, &error_abort);
    203     visit_free(v);
    204 }