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