Branch data Line data Source code
1 : : /* Copyright (c) 2009, 2010, 2011, 2012, 2014 Nicira, Inc.
2 : : *
3 : : * Licensed under the Apache License, Version 2.0 (the "License");
4 : : * you may not use this file except in compliance with the License.
5 : : * You may obtain a copy of the License at:
6 : : *
7 : : * http://www.apache.org/licenses/LICENSE-2.0
8 : : *
9 : : * Unless required by applicable law or agreed to in writing, software
10 : : * distributed under the License is distributed on an "AS IS" BASIS,
11 : : * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 : : * See the License for the specific language governing permissions and
13 : : * limitations under the License.
14 : : */
15 : :
16 : : #include <config.h>
17 : :
18 : : #include "ovsdb-data.h"
19 : :
20 : : #include <ctype.h>
21 : : #include <float.h>
22 : : #include <inttypes.h>
23 : : #include <limits.h>
24 : :
25 : : #include "openvswitch/dynamic-string.h"
26 : : #include "hash.h"
27 : : #include "ovs-thread.h"
28 : : #include "ovsdb-error.h"
29 : : #include "ovsdb-parser.h"
30 : : #include "openvswitch/json.h"
31 : : #include "openvswitch/shash.h"
32 : : #include "smap.h"
33 : : #include "sort.h"
34 : : #include "unicode.h"
35 : : #include "util.h"
36 : :
37 : : static struct json *
38 : 571176 : wrap_json(const char *name, struct json *wrapped)
39 : : {
40 : 571176 : return json_array_create_2(json_string_create(name), wrapped);
41 : : }
42 : :
43 : : /* Initializes 'atom' with the default value of the given 'type'.
44 : : *
45 : : * The default value for an atom is as defined in RFC 7047:
46 : : *
47 : : * - "integer" or "real": 0
48 : : *
49 : : * - "boolean": false
50 : : *
51 : : * - "string": "" (the empty string)
52 : : *
53 : : * - "uuid": 00000000-0000-0000-0000-000000000000
54 : : *
55 : : * The caller must eventually arrange for 'atom' to be destroyed (with
56 : : * ovsdb_atom_destroy()). */
57 : : void
58 : 953361 : ovsdb_atom_init_default(union ovsdb_atom *atom, enum ovsdb_atomic_type type)
59 : : {
60 [ - + + + : 953361 : switch (type) {
+ + - ]
61 : : case OVSDB_TYPE_VOID:
62 : 0 : OVS_NOT_REACHED();
63 : :
64 : : case OVSDB_TYPE_INTEGER:
65 : 297025 : atom->integer = 0;
66 : 297025 : break;
67 : :
68 : : case OVSDB_TYPE_REAL:
69 : 533 : atom->real = 0.0;
70 : 533 : break;
71 : :
72 : : case OVSDB_TYPE_BOOLEAN:
73 : 151926 : atom->boolean = false;
74 : 151926 : break;
75 : :
76 : : case OVSDB_TYPE_STRING:
77 : 290000 : atom->string = xmemdup("", 1);
78 : 290000 : break;
79 : :
80 : : case OVSDB_TYPE_UUID:
81 : 213877 : uuid_zero(&atom->uuid);
82 : 213877 : break;
83 : :
84 : : case OVSDB_N_TYPES:
85 : : default:
86 : 0 : OVS_NOT_REACHED();
87 : : }
88 : 953361 : }
89 : :
90 : : /* Returns a read-only atom of the given 'type' that has the default value for
91 : : * 'type'. The caller must not modify or free the returned atom.
92 : : *
93 : : * See ovsdb_atom_init_default() for an explanation of the default value of an
94 : : * atom. */
95 : : const union ovsdb_atom *
96 : 177 : ovsdb_atom_default(enum ovsdb_atomic_type type)
97 : : {
98 : : static union ovsdb_atom default_atoms[OVSDB_N_TYPES];
99 : : static struct ovsthread_once once = OVSTHREAD_ONCE_INITIALIZER;
100 : :
101 [ + + ]: 177 : if (ovsthread_once_start(&once)) {
102 : : int i;
103 : :
104 [ + + ]: 294 : for (i = 0; i < OVSDB_N_TYPES; i++) {
105 [ + + ]: 252 : if (i != OVSDB_TYPE_VOID) {
106 : 210 : ovsdb_atom_init_default(&default_atoms[i], i);
107 : : }
108 : : }
109 : 42 : ovsthread_once_done(&once);
110 : : }
111 : :
112 [ - + ]: 177 : ovs_assert(ovsdb_atomic_type_is_valid(type));
113 : 177 : return &default_atoms[type];
114 : : }
115 : :
116 : : /* Returns true if 'atom', which must have the given 'type', has the default
117 : : * value for that type.
118 : : *
119 : : * See ovsdb_atom_init_default() for an explanation of the default value of an
120 : : * atom. */
121 : : bool
122 : 426660 : ovsdb_atom_is_default(const union ovsdb_atom *atom,
123 : : enum ovsdb_atomic_type type)
124 : : {
125 [ - + + + : 426660 : switch (type) {
+ + - ]
126 : : case OVSDB_TYPE_VOID:
127 : 0 : OVS_NOT_REACHED();
128 : :
129 : : case OVSDB_TYPE_INTEGER:
130 : 83176 : return atom->integer == 0;
131 : :
132 : : case OVSDB_TYPE_REAL:
133 : 415 : return atom->real == 0.0;
134 : :
135 : : case OVSDB_TYPE_BOOLEAN:
136 : 50906 : return atom->boolean == false;
137 : :
138 : : case OVSDB_TYPE_STRING:
139 : 225330 : return atom->string[0] == '\0';
140 : :
141 : : case OVSDB_TYPE_UUID:
142 : 66833 : return uuid_is_zero(&atom->uuid);
143 : :
144 : : case OVSDB_N_TYPES:
145 : : default:
146 : 0 : OVS_NOT_REACHED();
147 : : }
148 : : }
149 : :
150 : : /* Initializes 'new' as a copy of 'old', with the given 'type'.
151 : : *
152 : : * The caller must eventually arrange for 'new' to be destroyed (with
153 : : * ovsdb_atom_destroy()). */
154 : : void
155 : 2557372 : ovsdb_atom_clone(union ovsdb_atom *new, const union ovsdb_atom *old,
156 : : enum ovsdb_atomic_type type)
157 : : {
158 [ - + + + : 2557372 : switch (type) {
+ + - ]
159 : : case OVSDB_TYPE_VOID:
160 : 0 : OVS_NOT_REACHED();
161 : :
162 : : case OVSDB_TYPE_INTEGER:
163 : 594807 : new->integer = old->integer;
164 : 594807 : break;
165 : :
166 : : case OVSDB_TYPE_REAL:
167 : 1114 : new->real = old->real;
168 : 1114 : break;
169 : :
170 : : case OVSDB_TYPE_BOOLEAN:
171 : 133387 : new->boolean = old->boolean;
172 : 133387 : break;
173 : :
174 : : case OVSDB_TYPE_STRING:
175 : 1347876 : new->string = xstrdup(old->string);
176 : 1347876 : break;
177 : :
178 : : case OVSDB_TYPE_UUID:
179 : 480188 : new->uuid = old->uuid;
180 : 480188 : break;
181 : :
182 : : case OVSDB_N_TYPES:
183 : : default:
184 : 0 : OVS_NOT_REACHED();
185 : : }
186 : 2557372 : }
187 : :
188 : : /* Swaps the contents of 'a' and 'b', which need not have the same type. */
189 : : void
190 : 4627996 : ovsdb_atom_swap(union ovsdb_atom *a, union ovsdb_atom *b)
191 : : {
192 : 4627996 : union ovsdb_atom tmp = *a;
193 : 4627996 : *a = *b;
194 : 4627996 : *b = tmp;
195 : 4627996 : }
196 : :
197 : : /* Returns a hash value for 'atom', which has the specified 'type', folding
198 : : * 'basis' into the calculation. */
199 : : uint32_t
200 : 262335 : ovsdb_atom_hash(const union ovsdb_atom *atom, enum ovsdb_atomic_type type,
201 : : uint32_t basis)
202 : : {
203 [ - + + + : 262335 : switch (type) {
+ + - ]
204 : : case OVSDB_TYPE_VOID:
205 : 0 : OVS_NOT_REACHED();
206 : :
207 : : case OVSDB_TYPE_INTEGER:
208 : 7037 : return hash_int(atom->integer, basis);
209 : :
210 : : case OVSDB_TYPE_REAL:
211 : 1439 : return hash_double(atom->real, basis);
212 : :
213 : : case OVSDB_TYPE_BOOLEAN:
214 : 1651 : return hash_boolean(atom->boolean, basis);
215 : :
216 : : case OVSDB_TYPE_STRING:
217 : 50206 : return hash_string(atom->string, basis);
218 : :
219 : : case OVSDB_TYPE_UUID:
220 : 202002 : return hash_int(uuid_hash(&atom->uuid), basis);
221 : :
222 : : case OVSDB_N_TYPES:
223 : : default:
224 : 0 : OVS_NOT_REACHED();
225 : : }
226 : : }
227 : :
228 : : /* Compares 'a' and 'b', which both have type 'type', and returns a
229 : : * strcmp()-like result. */
230 : : int
231 : 6263640 : ovsdb_atom_compare_3way(const union ovsdb_atom *a,
232 : : const union ovsdb_atom *b,
233 : : enum ovsdb_atomic_type type)
234 : : {
235 [ - + + + : 6263640 : switch (type) {
+ + - ]
236 : : case OVSDB_TYPE_VOID:
237 : 0 : OVS_NOT_REACHED();
238 : :
239 : : case OVSDB_TYPE_INTEGER:
240 [ + + ]: 385165 : return a->integer < b->integer ? -1 : a->integer > b->integer;
241 : :
242 : : case OVSDB_TYPE_REAL:
243 [ + + ]: 1517 : return a->real < b->real ? -1 : a->real > b->real;
244 : :
245 : : case OVSDB_TYPE_BOOLEAN:
246 : 21216 : return a->boolean - b->boolean;
247 : :
248 : : case OVSDB_TYPE_STRING:
249 : 3391692 : return strcmp(a->string, b->string);
250 : :
251 : : case OVSDB_TYPE_UUID:
252 : 2464050 : return uuid_compare_3way(&a->uuid, &b->uuid);
253 : :
254 : : case OVSDB_N_TYPES:
255 : : default:
256 : 0 : OVS_NOT_REACHED();
257 : : }
258 : : }
259 : :
260 : : static struct ovsdb_error *
261 : 397242 : unwrap_json(const struct json *json, const char *name,
262 : : enum json_type value_type, const struct json **value)
263 : : {
264 [ + + ]: 397242 : if (json->type != JSON_ARRAY
265 [ + - ]: 397241 : || json->u.array.n != 2
266 [ + - ]: 397241 : || json->u.array.elems[0]->type != JSON_STRING
267 [ + - ][ + + ]: 397241 : || (name && strcmp(json->u.array.elems[0]->u.string, name))
268 [ - + ]: 385059 : || json->u.array.elems[1]->type != value_type)
269 : : {
270 : 12183 : *value = NULL;
271 : 12183 : return ovsdb_syntax_error(json, NULL, "expected [\"%s\", <%s>]", name,
272 : : json_type_to_string(value_type));
273 : : }
274 : 385059 : *value = json->u.array.elems[1];
275 : 385059 : return NULL;
276 : : }
277 : :
278 : : static struct ovsdb_error *
279 : 155380 : parse_json_pair(const struct json *json,
280 : : const struct json **elem0, const struct json **elem1)
281 : : {
282 [ + - ][ - + ]: 155380 : if (json->type != JSON_ARRAY || json->u.array.n != 2) {
283 : 0 : return ovsdb_syntax_error(json, NULL, "expected 2-element array");
284 : : }
285 : 155380 : *elem0 = json->u.array.elems[0];
286 : 155380 : *elem1 = json->u.array.elems[1];
287 : 155380 : return NULL;
288 : : }
289 : :
290 : : static void
291 : 12305 : ovsdb_symbol_referenced(struct ovsdb_symbol *symbol,
292 : : const struct ovsdb_base_type *base)
293 : : {
294 [ - + ]: 12305 : ovs_assert(base->type == OVSDB_TYPE_UUID);
295 : :
296 [ + + ]: 12305 : if (base->u.uuid.refTableName) {
297 [ + + - ]: 12261 : switch (base->u.uuid.refType) {
298 : : case OVSDB_REF_STRONG:
299 : 11888 : symbol->strong_ref = true;
300 : 11888 : break;
301 : : case OVSDB_REF_WEAK:
302 : 373 : symbol->weak_ref = true;
303 : 373 : break;
304 : : }
305 : : }
306 : 12305 : }
307 : :
308 : : static struct ovsdb_error * OVS_WARN_UNUSED_RESULT
309 : 255901 : ovsdb_atom_parse_uuid(struct uuid *uuid, const struct json *json,
310 : : struct ovsdb_symbol_table *symtab,
311 : : const struct ovsdb_base_type *base)
312 : : {
313 : : struct ovsdb_error *error0;
314 : : const struct json *value;
315 : :
316 : 255901 : error0 = unwrap_json(json, "uuid", JSON_STRING, &value);
317 [ + + ]: 255901 : if (!error0) {
318 : 243730 : const char *uuid_string = json_string(value);
319 [ - + ]: 243730 : if (!uuid_from_string(uuid, uuid_string)) {
320 : 243730 : return ovsdb_syntax_error(json, NULL, "\"%s\" is not a valid UUID",
321 : : uuid_string);
322 : : }
323 [ + + ]: 12171 : } else if (symtab) {
324 : : struct ovsdb_error *error1;
325 : :
326 : 12169 : error1 = unwrap_json(json, "named-uuid", JSON_STRING, &value);
327 [ + - ]: 12169 : if (!error1) {
328 : : struct ovsdb_symbol *symbol;
329 : :
330 : 12169 : ovsdb_error_destroy(error0);
331 [ + + ]: 12169 : if (!ovsdb_parser_is_id(json_string(value))) {
332 : 1 : return ovsdb_syntax_error(json, NULL, "named-uuid string is "
333 : : "not a valid <id>");
334 : : }
335 : :
336 : 12168 : symbol = ovsdb_symbol_table_insert(symtab, json_string(value));
337 : 12168 : *uuid = symbol->uuid;
338 : 12168 : ovsdb_symbol_referenced(symbol, base);
339 : 12168 : return NULL;
340 : : }
341 : 0 : ovsdb_error_destroy(error1);
342 : : }
343 : :
344 : 255901 : return error0;
345 : : }
346 : :
347 : : static struct ovsdb_error * OVS_WARN_UNUSED_RESULT
348 : 1017506 : ovsdb_atom_from_json__(union ovsdb_atom *atom,
349 : : const struct ovsdb_base_type *base,
350 : : const struct json *json,
351 : : struct ovsdb_symbol_table *symtab)
352 : : {
353 : 1017506 : enum ovsdb_atomic_type type = base->type;
354 : :
355 [ - + + + : 1017506 : switch (type) {
+ + - ]
356 : : case OVSDB_TYPE_VOID:
357 : 0 : OVS_NOT_REACHED();
358 : :
359 : : case OVSDB_TYPE_INTEGER:
360 [ + + ]: 166707 : if (json->type == JSON_INTEGER) {
361 : 166706 : atom->integer = json->u.integer;
362 : 166706 : return NULL;
363 : : }
364 : 1 : break;
365 : :
366 : : case OVSDB_TYPE_REAL:
367 [ + + ]: 512 : if (json->type == JSON_INTEGER) {
368 : 327 : atom->real = json->u.integer;
369 : 327 : return NULL;
370 [ + - ]: 185 : } else if (json->type == JSON_REAL) {
371 : 185 : atom->real = json->u.real;
372 : 185 : return NULL;
373 : : }
374 : 0 : break;
375 : :
376 : : case OVSDB_TYPE_BOOLEAN:
377 [ + + ]: 6693 : if (json->type == JSON_TRUE) {
378 : 2020 : atom->boolean = true;
379 : 2020 : return NULL;
380 [ + + ]: 4673 : } else if (json->type == JSON_FALSE) {
381 : 4672 : atom->boolean = false;
382 : 4672 : return NULL;
383 : : }
384 : 1 : break;
385 : :
386 : : case OVSDB_TYPE_STRING:
387 [ + + ]: 587693 : if (json->type == JSON_STRING) {
388 : 587692 : atom->string = xstrdup(json->u.string);
389 : 587692 : return NULL;
390 : : }
391 : 1 : break;
392 : :
393 : : case OVSDB_TYPE_UUID:
394 : 255901 : return ovsdb_atom_parse_uuid(&atom->uuid, json, symtab, base);
395 : :
396 : : case OVSDB_N_TYPES:
397 : : default:
398 : 0 : OVS_NOT_REACHED();
399 : : }
400 : :
401 : 3 : return ovsdb_syntax_error(json, NULL, "expected %s",
402 : : ovsdb_atomic_type_to_string(type));
403 : : }
404 : :
405 : : /* Parses 'json' as an atom of the type described by 'base'. If successful,
406 : : * returns NULL and initializes 'atom' with the parsed atom. On failure,
407 : : * returns an error and the contents of 'atom' are indeterminate. The caller
408 : : * is responsible for freeing the error or the atom that is returned.
409 : : *
410 : : * Violations of constraints expressed by 'base' are treated as errors.
411 : : *
412 : : * If 'symtab' is nonnull, then named UUIDs in 'symtab' are accepted. Refer to
413 : : * RFC 7047 for information about this, and for the syntax that this function
414 : : * accepts. If 'base' is a reference and a symbol is parsed, then the symbol's
415 : : * 'strong_ref' or 'weak_ref' member is set to true, as appropriate. */
416 : : struct ovsdb_error *
417 : 1017506 : ovsdb_atom_from_json(union ovsdb_atom *atom,
418 : : const struct ovsdb_base_type *base,
419 : : const struct json *json,
420 : : struct ovsdb_symbol_table *symtab)
421 : : {
422 : : struct ovsdb_error *error;
423 : :
424 : 1017506 : error = ovsdb_atom_from_json__(atom, base, json, symtab);
425 [ + + ]: 1017506 : if (error) {
426 : 6 : return error;
427 : : }
428 : :
429 : 1017500 : error = ovsdb_atom_check_constraints(atom, base);
430 [ + + ]: 1017500 : if (error) {
431 : 51 : ovsdb_atom_destroy(atom, base->type);
432 : : }
433 : 1017500 : return error;
434 : : }
435 : :
436 : : /* Converts 'atom', of the specified 'type', to JSON format, and returns the
437 : : * JSON. The caller is responsible for freeing the returned JSON.
438 : : *
439 : : * Refer to RFC 7047 for the format of the JSON that this function produces. */
440 : : struct json *
441 : 1304963 : ovsdb_atom_to_json(const union ovsdb_atom *atom, enum ovsdb_atomic_type type)
442 : : {
443 [ - + + + : 1304963 : switch (type) {
+ + - ]
444 : : case OVSDB_TYPE_VOID:
445 : 0 : OVS_NOT_REACHED();
446 : :
447 : : case OVSDB_TYPE_INTEGER:
448 : 214754 : return json_integer_create(atom->integer);
449 : :
450 : : case OVSDB_TYPE_REAL:
451 : 649 : return json_real_create(atom->real);
452 : :
453 : : case OVSDB_TYPE_BOOLEAN:
454 : 11193 : return json_boolean_create(atom->boolean);
455 : :
456 : : case OVSDB_TYPE_STRING:
457 : 823780 : return json_string_create(atom->string);
458 : :
459 : : case OVSDB_TYPE_UUID:
460 : 254587 : return wrap_json("uuid", json_string_create_nocopy(
461 : 763761 : xasprintf(UUID_FMT, UUID_ARGS(&atom->uuid))));
462 : :
463 : : case OVSDB_N_TYPES:
464 : : default:
465 : 0 : OVS_NOT_REACHED();
466 : : }
467 : : }
468 : :
469 : : static char *
470 : 16880 : ovsdb_atom_from_string__(union ovsdb_atom *atom,
471 : : const struct ovsdb_base_type *base, const char *s,
472 : : struct ovsdb_symbol_table *symtab)
473 : : {
474 : 16880 : enum ovsdb_atomic_type type = base->type;
475 : :
476 [ - + + + : 16880 : switch (type) {
+ + - ]
477 : : case OVSDB_TYPE_VOID:
478 : 0 : OVS_NOT_REACHED();
479 : :
480 : : case OVSDB_TYPE_INTEGER: {
481 : : long long int integer;
482 [ + + ]: 2011 : if (!str_to_llong(s, 10, &integer)) {
483 : 2 : return xasprintf("\"%s\" is not a valid integer", s);
484 : : }
485 : 2009 : atom->integer = integer;
486 : : }
487 : 2009 : break;
488 : :
489 : : case OVSDB_TYPE_REAL:
490 [ - + ]: 17 : if (!str_to_double(s, &atom->real)) {
491 : 0 : return xasprintf("\"%s\" is not a valid real number", s);
492 : : }
493 : : /* Our JSON input routines map negative zero to zero, so do that here
494 : : * too for consistency. */
495 [ + + ]: 17 : if (atom->real == 0.0) {
496 : 6 : atom->real = 0.0;
497 : : }
498 : 17 : break;
499 : :
500 : : case OVSDB_TYPE_BOOLEAN:
501 [ + + ][ + - ]: 53 : if (!strcmp(s, "true") || !strcmp(s, "yes") || !strcmp(s, "on")
[ + - ]
502 [ - + ]: 18 : || !strcmp(s, "1")) {
503 : 35 : atom->boolean = true;
504 [ + + ][ + - ]: 18 : } else if (!strcmp(s, "false") || !strcmp(s, "no") || !strcmp(s, "off")
[ + - ]
505 [ - + ]: 1 : || !strcmp(s, "0")) {
506 : 17 : atom->boolean = false;
507 : : } else {
508 : 1 : return xasprintf("\"%s\" is not a valid boolean "
509 : : "(use \"true\" or \"false\")", s);
510 : : }
511 : 52 : break;
512 : :
513 : : case OVSDB_TYPE_STRING:
514 [ + + ]: 14624 : if (*s == '\0') {
515 : 1 : return xstrdup("An empty string is not valid as input; "
516 : : "use \"\" to represent the empty string");
517 [ + + ]: 14623 : } else if (*s == '"') {
518 : 238 : size_t s_len = strlen(s);
519 : :
520 [ + - ][ + + ]: 238 : if (s_len < 2 || s[s_len - 1] != '"') {
521 : 1 : return xasprintf("%s: missing quote at end of "
522 : : "quoted string", s);
523 [ + + ]: 237 : } else if (!json_string_unescape(s + 1, s_len - 2,
524 : : &atom->string)) {
525 : 2 : char *error = xasprintf("%s: %s", s, atom->string);
526 : 2 : free(atom->string);
527 : 237 : return error;
528 : : }
529 : : } else {
530 : 14385 : atom->string = xstrdup(s);
531 : : }
532 : 14620 : break;
533 : :
534 : : case OVSDB_TYPE_UUID:
535 [ + + ]: 175 : if (*s == '@') {
536 : 137 : struct ovsdb_symbol *symbol = ovsdb_symbol_table_insert(symtab, s);
537 : 137 : atom->uuid = symbol->uuid;
538 : 137 : ovsdb_symbol_referenced(symbol, base);
539 [ + + ]: 38 : } else if (!uuid_from_string(&atom->uuid, s)) {
540 : 1 : return xasprintf("\"%s\" is not a valid UUID", s);
541 : : }
542 : 174 : break;
543 : :
544 : : case OVSDB_N_TYPES:
545 : : default:
546 : 0 : OVS_NOT_REACHED();
547 : : }
548 : :
549 : 16872 : return NULL;
550 : : }
551 : :
552 : : /* Initializes 'atom' to a value of type 'base' parsed from 's', which takes
553 : : * one of the following forms:
554 : : *
555 : : * - OVSDB_TYPE_INTEGER: A decimal integer optionally preceded by a sign.
556 : : *
557 : : * - OVSDB_TYPE_REAL: A floating-point number in the format accepted by
558 : : * strtod().
559 : : *
560 : : * - OVSDB_TYPE_BOOLEAN: "true", "yes", "on", "1" for true, or "false",
561 : : * "no", "off", or "0" for false.
562 : : *
563 : : * - OVSDB_TYPE_STRING: A JSON string if it begins with a quote, otherwise
564 : : * an arbitrary string.
565 : : *
566 : : * - OVSDB_TYPE_UUID: A UUID in RFC 4122 format. If 'symtab' is nonnull,
567 : : * then an identifier beginning with '@' is also acceptable. If the
568 : : * named identifier is already in 'symtab', then the associated UUID is
569 : : * used; otherwise, a new, random UUID is used and added to the symbol
570 : : * table. If 'base' is a reference and a symbol is parsed, then the
571 : : * symbol's 'strong_ref' or 'weak_ref' member is set to true, as
572 : : * appropriate.
573 : : *
574 : : * Returns a null pointer if successful, otherwise an error message describing
575 : : * the problem. On failure, the contents of 'atom' are indeterminate. The
576 : : * caller is responsible for freeing the atom or the error.
577 : : */
578 : : char *
579 : 16880 : ovsdb_atom_from_string(union ovsdb_atom *atom,
580 : : const struct ovsdb_base_type *base, const char *s,
581 : : struct ovsdb_symbol_table *symtab)
582 : : {
583 : : struct ovsdb_error *error;
584 : : char *msg;
585 : :
586 : 16880 : msg = ovsdb_atom_from_string__(atom, base, s, symtab);
587 [ + + ]: 16880 : if (msg) {
588 : 8 : return msg;
589 : : }
590 : :
591 : 16872 : error = ovsdb_atom_check_constraints(atom, base);
592 [ + + ]: 16872 : if (error) {
593 : 3 : ovsdb_atom_destroy(atom, base->type);
594 : 3 : msg = ovsdb_error_to_string(error);
595 : 3 : ovsdb_error_destroy(error);
596 : : }
597 : 16872 : return msg;
598 : : }
599 : :
600 : : static bool
601 : 8265 : string_needs_quotes(const char *s)
602 : : {
603 : 8265 : const char *p = s;
604 : : unsigned char c;
605 : :
606 : 8265 : c = *p++;
607 [ + + ][ + + ]: 8265 : if (!isalpha(c) && c != '_') {
608 : 1126 : return true;
609 : : }
610 : :
611 [ + + ]: 48493 : while ((c = *p++) != '\0') {
612 [ + + ][ + + ]: 44007 : if (!isalpha(c) && c != '_' && c != '-' && c != '.') {
[ + + ][ + + ]
613 : 2653 : return true;
614 : : }
615 : : }
616 : :
617 [ + + ][ + + ]: 4486 : if (!strcmp(s, "true") || !strcmp(s, "false")) {
618 : 162 : return true;
619 : : }
620 : :
621 : 4324 : return false;
622 : : }
623 : :
624 : : /* Appends 'atom' (which has the given 'type') to 'out', in a format acceptable
625 : : * to ovsdb_atom_from_string(). */
626 : : void
627 : 16097 : ovsdb_atom_to_string(const union ovsdb_atom *atom, enum ovsdb_atomic_type type,
628 : : struct ds *out)
629 : : {
630 [ - + + + : 16097 : switch (type) {
+ + - ]
631 : : case OVSDB_TYPE_VOID:
632 : 0 : OVS_NOT_REACHED();
633 : :
634 : : case OVSDB_TYPE_INTEGER:
635 : 4264 : ds_put_format(out, "%"PRId64, atom->integer);
636 : 4264 : break;
637 : :
638 : : case OVSDB_TYPE_REAL:
639 : 30 : ds_put_format(out, "%.*g", DBL_DIG, atom->real);
640 : 30 : break;
641 : :
642 : : case OVSDB_TYPE_BOOLEAN:
643 [ + + ]: 509 : ds_put_cstr(out, atom->boolean ? "true" : "false");
644 : 509 : break;
645 : :
646 : : case OVSDB_TYPE_STRING:
647 [ + + ]: 8265 : if (string_needs_quotes(atom->string)) {
648 : : struct json json;
649 : :
650 : 3941 : json.type = JSON_STRING;
651 : 3941 : json.u.string = atom->string;
652 : 3941 : json_to_ds(&json, 0, out);
653 : : } else {
654 : 4324 : ds_put_cstr(out, atom->string);
655 : : }
656 : 8265 : break;
657 : :
658 : : case OVSDB_TYPE_UUID:
659 : 3029 : ds_put_format(out, UUID_FMT, UUID_ARGS(&atom->uuid));
660 : 3029 : break;
661 : :
662 : : case OVSDB_N_TYPES:
663 : : default:
664 : 0 : OVS_NOT_REACHED();
665 : : }
666 : 16097 : }
667 : :
668 : : /* Appends 'atom' (which has the given 'type') to 'out', in a bare string
669 : : * format that cannot be parsed uniformly back into a datum but is easier for
670 : : * shell scripts, etc., to deal with. */
671 : : void
672 : 1065 : ovsdb_atom_to_bare(const union ovsdb_atom *atom, enum ovsdb_atomic_type type,
673 : : struct ds *out)
674 : : {
675 [ + + ]: 1065 : if (type == OVSDB_TYPE_STRING) {
676 : 1000 : ds_put_cstr(out, atom->string);
677 : : } else {
678 : 65 : ovsdb_atom_to_string(atom, type, out);
679 : : }
680 : 1065 : }
681 : :
682 : : static struct ovsdb_error *
683 : 647315 : check_string_constraints(const char *s,
684 : : const struct ovsdb_string_constraints *c)
685 : : {
686 : : size_t n_chars;
687 : : char *msg;
688 : :
689 : 647315 : msg = utf8_validate(s, &n_chars);
690 [ + + ]: 647315 : if (msg) {
691 : : struct ovsdb_error *error;
692 : :
693 : 2 : error = ovsdb_error("constraint violation",
694 : : "not a valid UTF-8 string: %s", msg);
695 : 2 : free(msg);
696 : 2 : return error;
697 : : }
698 : :
699 [ + + ]: 647313 : if (n_chars < c->minLen) {
700 : 3 : return ovsdb_error(
701 : : "constraint violation",
702 : : "\"%s\" length %"PRIuSIZE" is less than minimum allowed "
703 : : "length %u", s, n_chars, c->minLen);
704 [ + + ]: 647310 : } else if (n_chars > c->maxLen) {
705 : 1 : return ovsdb_error(
706 : : "constraint violation",
707 : : "\"%s\" length %"PRIuSIZE" is greater than maximum allowed "
708 : : "length %u", s, n_chars, c->maxLen);
709 : : }
710 : :
711 : 647315 : return NULL;
712 : : }
713 : :
714 : : /* Checks whether 'atom' meets the constraints (if any) defined in 'base'.
715 : : * (base->type must specify 'atom''s type.) Returns a null pointer if the
716 : : * constraints are met, otherwise an error that explains the violation.
717 : : *
718 : : * Checking UUID constraints is deferred to transaction commit time, so this
719 : : * function does nothing for UUID constraints. */
720 : : struct ovsdb_error *
721 : 1166180 : ovsdb_atom_check_constraints(const union ovsdb_atom *atom,
722 : : const struct ovsdb_base_type *base)
723 : : {
724 [ + + ]: 1166180 : if (base->enum_
725 [ + + ]: 65914 : && ovsdb_datum_find_key(base->enum_, atom, base->type) == UINT_MAX) {
726 : : struct ovsdb_error *error;
727 : 18 : struct ds actual = DS_EMPTY_INITIALIZER;
728 : 18 : struct ds valid = DS_EMPTY_INITIALIZER;
729 : :
730 : 18 : ovsdb_atom_to_string(atom, base->type, &actual);
731 : 18 : ovsdb_datum_to_string(base->enum_,
732 : : ovsdb_base_type_get_enum_type(base->type),
733 : : &valid);
734 : 18 : error = ovsdb_error("constraint violation",
735 : : "%s is not one of the allowed values (%s)",
736 : : ds_cstr(&actual), ds_cstr(&valid));
737 : 18 : ds_destroy(&actual);
738 : 18 : ds_destroy(&valid);
739 : :
740 : 18 : return error;
741 : : }
742 : :
743 [ - + + + : 1166162 : switch (base->type) {
+ + - ]
744 : : case OVSDB_TYPE_VOID:
745 : 0 : OVS_NOT_REACHED();
746 : :
747 : : case OVSDB_TYPE_INTEGER:
748 [ + + ]: 199963 : if (atom->integer >= base->u.integer.min
749 [ + + ]: 199935 : && atom->integer <= base->u.integer.max) {
750 : 199927 : return NULL;
751 [ + + ]: 36 : } else if (base->u.integer.min != INT64_MIN) {
752 [ + + ]: 34 : if (base->u.integer.max != INT64_MAX) {
753 : 11 : return ovsdb_error("constraint violation",
754 : : "%"PRId64" is not in the valid range "
755 : : "%"PRId64" to %"PRId64" (inclusive)",
756 : : atom->integer,
757 : : base->u.integer.min, base->u.integer.max);
758 : : } else {
759 : 23 : return ovsdb_error("constraint violation",
760 : : "%"PRId64" is less than minimum allowed "
761 : : "value %"PRId64,
762 : : atom->integer, base->u.integer.min);
763 : : }
764 : : } else {
765 : 2 : return ovsdb_error("constraint violation",
766 : : "%"PRId64" is greater than maximum allowed "
767 : : "value %"PRId64,
768 : : atom->integer, base->u.integer.max);
769 : : }
770 : : OVS_NOT_REACHED();
771 : :
772 : : case OVSDB_TYPE_REAL:
773 [ + + ][ + + ]: 839 : if (atom->real >= base->u.real.min && atom->real <= base->u.real.max) {
774 : 828 : return NULL;
775 [ + + ]: 11 : } else if (base->u.real.min != -DBL_MAX) {
776 [ + + ]: 9 : if (base->u.real.max != DBL_MAX) {
777 : 7 : return ovsdb_error("constraint violation",
778 : : "%.*g is not in the valid range "
779 : : "%.*g to %.*g (inclusive)",
780 : : DBL_DIG, atom->real,
781 : : DBL_DIG, base->u.real.min,
782 : : DBL_DIG, base->u.real.max);
783 : : } else {
784 : 2 : return ovsdb_error("constraint violation",
785 : : "%.*g is less than minimum allowed "
786 : : "value %.*g",
787 : : DBL_DIG, atom->real,
788 : : DBL_DIG, base->u.real.min);
789 : : }
790 : : } else {
791 : 2 : return ovsdb_error("constraint violation",
792 : : "%.*g is greater than maximum allowed "
793 : : "value %.*g",
794 : : DBL_DIG, atom->real,
795 : : DBL_DIG, base->u.real.max);
796 : : }
797 : : OVS_NOT_REACHED();
798 : :
799 : : case OVSDB_TYPE_BOOLEAN:
800 : 17297 : return NULL;
801 : :
802 : : case OVSDB_TYPE_STRING:
803 : 647315 : return check_string_constraints(atom->string, &base->u.string);
804 : :
805 : : case OVSDB_TYPE_UUID:
806 : 300748 : return NULL;
807 : :
808 : : case OVSDB_N_TYPES:
809 : : default:
810 : 0 : OVS_NOT_REACHED();
811 : : }
812 : : }
813 : :
814 : : static union ovsdb_atom *
815 : 7479986 : alloc_default_atoms(enum ovsdb_atomic_type type, size_t n)
816 : : {
817 [ + + ][ + + ]: 7479986 : if (type != OVSDB_TYPE_VOID && n) {
818 : : union ovsdb_atom *atoms;
819 : : unsigned int i;
820 : :
821 : 953146 : atoms = xmalloc(n * sizeof *atoms);
822 [ + + ]: 1906292 : for (i = 0; i < n; i++) {
823 : 953146 : ovsdb_atom_init_default(&atoms[i], type);
824 : : }
825 : 953146 : return atoms;
826 : : } else {
827 : : /* Avoid wasting memory in the n == 0 case, because xmalloc(0) is
828 : : * treated as xmalloc(1). */
829 : 6526840 : return NULL;
830 : : }
831 : : }
832 : :
833 : : /* Initializes 'datum' as an empty datum. (An empty datum can be treated as
834 : : * any type.) */
835 : : void
836 : 245611 : ovsdb_datum_init_empty(struct ovsdb_datum *datum)
837 : : {
838 : 245611 : datum->n = 0;
839 : 245611 : datum->keys = NULL;
840 : 245611 : datum->values = NULL;
841 : 245611 : }
842 : :
843 : : /* Initializes 'datum' as a datum that has the default value for 'type'.
844 : : *
845 : : * The default value for a particular type is as defined in RFC 7047:
846 : : *
847 : : * - If n_min is 0, then the default value is the empty set (or map).
848 : : *
849 : : * - If n_min is 1, the default value is a single value or a single
850 : : * key-value pair, whose key and value are the defaults for their
851 : : * atomic types. (See ovsdb_atom_init_default() for details.)
852 : : *
853 : : * - n_min > 1 is invalid. See ovsdb_type_is_valid().
854 : : */
855 : : void
856 : 3739993 : ovsdb_datum_init_default(struct ovsdb_datum *datum,
857 : : const struct ovsdb_type *type)
858 : : {
859 : 3739993 : datum->n = type->n_min;
860 : 3739993 : datum->keys = alloc_default_atoms(type->key.type, datum->n);
861 : 3739993 : datum->values = alloc_default_atoms(type->value.type, datum->n);
862 : 3739993 : }
863 : :
864 : : /* Returns a read-only datum of the given 'type' that has the default value for
865 : : * 'type'. The caller must not modify or free the returned datum.
866 : : *
867 : : * See ovsdb_datum_init_default() for an explanation of the default value of a
868 : : * datum. */
869 : : const struct ovsdb_datum *
870 : 35954 : ovsdb_datum_default(const struct ovsdb_type *type)
871 : : {
872 [ + + ]: 35954 : if (type->n_min == 0) {
873 : : static const struct ovsdb_datum empty;
874 : 3145 : return ∅
875 [ + - ]: 32809 : } else if (type->n_min == 1) {
876 : : static struct ovsdb_datum default_data[OVSDB_N_TYPES][OVSDB_N_TYPES];
877 : : struct ovsdb_datum *d;
878 : 32809 : int kt = type->key.type;
879 : 32809 : int vt = type->value.type;
880 : :
881 [ - + ]: 32809 : ovs_assert(ovsdb_type_is_valid(type));
882 : :
883 : 32809 : d = &default_data[kt][vt];
884 [ + + ]: 32809 : if (!d->n) {
885 : 147 : d->n = 1;
886 : 147 : d->keys = CONST_CAST(union ovsdb_atom *, ovsdb_atom_default(kt));
887 [ + + ]: 147 : if (vt != OVSDB_TYPE_VOID) {
888 : 25 : d->values = CONST_CAST(union ovsdb_atom *,
889 : : ovsdb_atom_default(vt));
890 : : }
891 : : }
892 : 32809 : return d;
893 : : } else {
894 : 0 : OVS_NOT_REACHED();
895 : : }
896 : : }
897 : :
898 : : /* Returns true if 'datum', which must have the given 'type', has the default
899 : : * value for that type.
900 : : *
901 : : * See ovsdb_datum_init_default() for an explanation of the default value of a
902 : : * datum. */
903 : : bool
904 : 881905 : ovsdb_datum_is_default(const struct ovsdb_datum *datum,
905 : : const struct ovsdb_type *type)
906 : : {
907 : : size_t i;
908 : :
909 [ + + ]: 881905 : if (datum->n != type->n_min) {
910 : 130027 : return false;
911 : : }
912 [ + + ]: 852113 : for (i = 0; i < datum->n; i++) {
913 [ + + ]: 426660 : if (!ovsdb_atom_is_default(&datum->keys[i], type->key.type)) {
914 : 326425 : return false;
915 : : }
916 [ - + ]: 100235 : if (type->value.type != OVSDB_TYPE_VOID
917 [ # # ]: 0 : && !ovsdb_atom_is_default(&datum->values[i], type->value.type)) {
918 : 0 : return false;
919 : : }
920 : : }
921 : :
922 : 425453 : return true;
923 : : }
924 : :
925 : : static union ovsdb_atom *
926 : 5902194 : clone_atoms(const union ovsdb_atom *old, enum ovsdb_atomic_type type, size_t n)
927 : : {
928 [ + + ][ + + ]: 5902194 : if (type != OVSDB_TYPE_VOID && n) {
929 : : union ovsdb_atom *new;
930 : : unsigned int i;
931 : :
932 : 1575391 : new = xmalloc(n * sizeof *new);
933 [ + + ]: 3917558 : for (i = 0; i < n; i++) {
934 : 2342167 : ovsdb_atom_clone(&new[i], &old[i], type);
935 : : }
936 : 1575391 : return new;
937 : : } else {
938 : : /* Avoid wasting memory in the n == 0 case, because xmalloc(0) is
939 : : * treated as xmalloc(1). */
940 : 4326803 : return NULL;
941 : : }
942 : : }
943 : :
944 : : /* Initializes 'new' as a copy of 'old', with the given 'type'.
945 : : *
946 : : * The caller must eventually arrange for 'new' to be destroyed (with
947 : : * ovsdb_datum_destroy()). */
948 : : void
949 : 2951097 : ovsdb_datum_clone(struct ovsdb_datum *new, const struct ovsdb_datum *old,
950 : : const struct ovsdb_type *type)
951 : : {
952 : 2951097 : unsigned int n = old->n;
953 : 2951097 : new->n = n;
954 : 2951097 : new->keys = clone_atoms(old->keys, type->key.type, n);
955 : 2951097 : new->values = clone_atoms(old->values, type->value.type, n);
956 : 2951097 : }
957 : :
958 : : static void
959 : 15470706 : free_data(enum ovsdb_atomic_type type,
960 : : union ovsdb_atom *atoms, size_t n_atoms)
961 : : {
962 [ + + ]: 15470706 : if (ovsdb_atom_needs_destruction(type)) {
963 : : unsigned int i;
964 [ + + ]: 8451711 : for (i = 0; i < n_atoms; i++) {
965 : 2720897 : ovsdb_atom_destroy(&atoms[i], type);
966 : : }
967 : : }
968 : 15470706 : free(atoms);
969 : 15470706 : }
970 : :
971 : : /* Frees the data owned by 'datum', which must have the given 'type'.
972 : : *
973 : : * This does not actually call free(datum). If necessary, the caller must be
974 : : * responsible for that. */
975 : : void
976 : 7735353 : ovsdb_datum_destroy(struct ovsdb_datum *datum, const struct ovsdb_type *type)
977 : : {
978 : 7735353 : free_data(type->key.type, datum->keys, datum->n);
979 : 7735353 : free_data(type->value.type, datum->values, datum->n);
980 : 7735353 : }
981 : :
982 : : /* Swaps the contents of 'a' and 'b', which need not have the same type. */
983 : : void
984 : 544234 : ovsdb_datum_swap(struct ovsdb_datum *a, struct ovsdb_datum *b)
985 : : {
986 : 544234 : struct ovsdb_datum tmp = *a;
987 : 544234 : *a = *b;
988 : 544234 : *b = tmp;
989 : 544234 : }
990 : :
991 : : struct ovsdb_datum_sort_cbdata {
992 : : enum ovsdb_atomic_type key_type;
993 : : enum ovsdb_atomic_type value_type;
994 : : struct ovsdb_datum *datum;
995 : : };
996 : :
997 : : static int
998 : 3375211 : ovsdb_datum_sort_compare_cb(size_t a, size_t b, void *cbdata_)
999 : : {
1000 : 3375211 : struct ovsdb_datum_sort_cbdata *cbdata = cbdata_;
1001 : : int retval;
1002 : :
1003 : 3375211 : retval = ovsdb_atom_compare_3way(&cbdata->datum->keys[a],
1004 : 3375211 : &cbdata->datum->keys[b],
1005 : : cbdata->key_type);
1006 [ + + ][ + - ]: 3375211 : if (retval || cbdata->value_type == OVSDB_TYPE_VOID) {
1007 : 3375211 : return retval;
1008 : : }
1009 : :
1010 : 0 : return ovsdb_atom_compare_3way(&cbdata->datum->values[a],
1011 : 0 : &cbdata->datum->values[b],
1012 : : cbdata->value_type);
1013 : : }
1014 : :
1015 : : static void
1016 : 3645371 : ovsdb_datum_sort_swap_cb(size_t a, size_t b, void *cbdata_)
1017 : : {
1018 : 3645371 : struct ovsdb_datum_sort_cbdata *cbdata = cbdata_;
1019 : :
1020 : 3645371 : ovsdb_atom_swap(&cbdata->datum->keys[a], &cbdata->datum->keys[b]);
1021 [ + + ]: 3645371 : if (cbdata->datum->values) {
1022 : 982625 : ovsdb_atom_swap(&cbdata->datum->values[a], &cbdata->datum->values[b]);
1023 : : }
1024 : 3645371 : }
1025 : :
1026 : : static void
1027 : 222830 : ovsdb_datum_sort__(struct ovsdb_datum *datum, enum ovsdb_atomic_type key_type,
1028 : : enum ovsdb_atomic_type value_type)
1029 : : {
1030 : : struct ovsdb_datum_sort_cbdata cbdata;
1031 : :
1032 : 222830 : cbdata.key_type = key_type;
1033 : 222830 : cbdata.value_type = value_type;
1034 : 222830 : cbdata.datum = datum;
1035 : 222830 : sort(datum->n, ovsdb_datum_sort_compare_cb, ovsdb_datum_sort_swap_cb,
1036 : : &cbdata);
1037 : 222830 : }
1038 : :
1039 : : /* The keys in an ovsdb_datum must be unique and in sorted order. Most
1040 : : * functions that modify an ovsdb_datum maintain these invariants. For those
1041 : : * that don't, this function checks and restores these invariants for 'datum',
1042 : : * whose keys are of type 'key_type'.
1043 : : *
1044 : : * This function returns NULL if successful, otherwise an error message. The
1045 : : * caller must free the returned error when it is no longer needed. On error,
1046 : : * 'datum' is sorted but not unique. */
1047 : : struct ovsdb_error *
1048 : 728139 : ovsdb_datum_sort(struct ovsdb_datum *datum, enum ovsdb_atomic_type key_type)
1049 : : {
1050 : : size_t i;
1051 : :
1052 [ + + ]: 728139 : if (datum->n < 2) {
1053 : 576138 : return NULL;
1054 : : }
1055 : :
1056 : 152001 : ovsdb_datum_sort__(datum, key_type, OVSDB_TYPE_VOID);
1057 : :
1058 [ + + ]: 509012 : for (i = 0; i < datum->n - 1; i++) {
1059 [ + + ]: 357029 : if (ovsdb_atom_equals(&datum->keys[i], &datum->keys[i + 1],
1060 : : key_type)) {
1061 [ + + ]: 18 : if (datum->values) {
1062 : 2 : return ovsdb_error(NULL, "map contains duplicate key");
1063 : : } else {
1064 : 16 : return ovsdb_error(NULL, "set contains duplicate");
1065 : : }
1066 : : }
1067 : : }
1068 : 151983 : return NULL;
1069 : : }
1070 : :
1071 : : /* This function is the same as ovsdb_datum_sort(), except that the caller
1072 : : * knows that 'datum' is unique. The operation therefore "cannot fail", so
1073 : : * this function assert-fails if it actually does. */
1074 : : void
1075 : 76505 : ovsdb_datum_sort_assert(struct ovsdb_datum *datum,
1076 : : enum ovsdb_atomic_type key_type)
1077 : : {
1078 : 76505 : struct ovsdb_error *error = ovsdb_datum_sort(datum, key_type);
1079 [ - + ]: 76505 : if (error) {
1080 : 0 : OVS_NOT_REACHED();
1081 : : }
1082 : 76505 : }
1083 : :
1084 : : /* This is similar to ovsdb_datum_sort(), except that it drops duplicate keys
1085 : : * instead of reporting an error. In a map type, the smallest value among a
1086 : : * group of duplicate pairs is retained and the others are dropped.
1087 : : *
1088 : : * Returns the number of keys (or pairs) that were dropped. */
1089 : : size_t
1090 : 266106 : ovsdb_datum_sort_unique(struct ovsdb_datum *datum,
1091 : : enum ovsdb_atomic_type key_type,
1092 : : enum ovsdb_atomic_type value_type)
1093 : : {
1094 : : size_t src, dst;
1095 : :
1096 [ + + ]: 266106 : if (datum->n < 2) {
1097 : 195277 : return 0;
1098 : : }
1099 : :
1100 : 70829 : ovsdb_datum_sort__(datum, key_type, value_type);
1101 : :
1102 : 70829 : dst = 1;
1103 [ + + ]: 452025 : for (src = 1; src < datum->n; src++) {
1104 [ - + ]: 381196 : if (ovsdb_atom_equals(&datum->keys[src], &datum->keys[dst - 1],
1105 : : key_type)) {
1106 : 0 : ovsdb_atom_destroy(&datum->keys[src], key_type);
1107 [ # # ]: 0 : if (value_type != OVSDB_TYPE_VOID) {
1108 : 0 : ovsdb_atom_destroy(&datum->values[src], value_type);
1109 : : }
1110 : : } else {
1111 [ - + ]: 381196 : if (src != dst) {
1112 : 0 : datum->keys[dst] = datum->keys[src];
1113 [ # # ]: 0 : if (value_type != OVSDB_TYPE_VOID) {
1114 : 0 : datum->values[dst] = datum->values[src];
1115 : : }
1116 : : }
1117 : 381196 : dst++;
1118 : : }
1119 : : }
1120 : 70829 : datum->n = dst;
1121 : 70829 : return datum->n - src;
1122 : : }
1123 : :
1124 : : /* Checks that each of the atoms in 'datum' conforms to the constraints
1125 : : * specified by its 'type'. Returns an error if a constraint is violated,
1126 : : * otherwise a null pointer.
1127 : : *
1128 : : * This function is not commonly useful because the most ordinary way to obtain
1129 : : * a datum is ultimately via ovsdb_atom_from_string() or
1130 : : * ovsdb_atom_from_json(), which check constraints themselves. */
1131 : : struct ovsdb_error *
1132 : 123717 : ovsdb_datum_check_constraints(const struct ovsdb_datum *datum,
1133 : : const struct ovsdb_type *type)
1134 : : {
1135 : : struct ovsdb_error *error;
1136 : : unsigned int i;
1137 : :
1138 [ + + ]: 247427 : for (i = 0; i < datum->n; i++) {
1139 : 123717 : error = ovsdb_atom_check_constraints(&datum->keys[i], &type->key);
1140 [ + + ]: 123717 : if (error) {
1141 : 7 : return error;
1142 : : }
1143 : : }
1144 : :
1145 [ + + ]: 123710 : if (type->value.type != OVSDB_TYPE_VOID) {
1146 [ + + ]: 11594 : for (i = 0; i < datum->n; i++) {
1147 : 5797 : error = ovsdb_atom_check_constraints(&datum->values[i],
1148 : : &type->value);
1149 [ - + ]: 5797 : if (error) {
1150 : 0 : return error;
1151 : : }
1152 : : }
1153 : : }
1154 : :
1155 : 123710 : return NULL;
1156 : : }
1157 : :
1158 : : static struct ovsdb_error *
1159 : 641949 : ovsdb_datum_from_json__(struct ovsdb_datum *datum,
1160 : : const struct ovsdb_type *type,
1161 : : const struct json *json,
1162 : : struct ovsdb_symbol_table *symtab)
1163 : : {
1164 : : struct ovsdb_error *error;
1165 : :
1166 [ + + ]: 641949 : if (ovsdb_type_is_map(type)
1167 [ + + ]: 555589 : || (json->type == JSON_ARRAY
1168 [ + - ]: 192156 : && json->u.array.n > 0
1169 [ + - ]: 192156 : && json->u.array.elems[0]->type == JSON_STRING
1170 [ + + ]: 192156 : && !strcmp(json->u.array.elems[0]->u.string, "set"))) {
1171 : 129172 : bool is_map = ovsdb_type_is_map(type);
1172 [ + + ]: 129172 : const char *class = is_map ? "map" : "set";
1173 : : const struct json *inner;
1174 : : unsigned int i;
1175 : : size_t n;
1176 : :
1177 : 129172 : error = unwrap_json(json, class, JSON_ARRAY, &inner);
1178 [ + + ]: 129172 : if (error) {
1179 : 12 : return error;
1180 : : }
1181 : :
1182 : 129160 : n = inner->u.array.n;
1183 [ + - ][ - + ]: 129160 : if (n < type->n_min || n > type->n_max) {
1184 : 0 : return ovsdb_syntax_error(json, NULL, "%s must have %u to "
1185 : : "%u members but %"PRIuSIZE" are present",
1186 : : class, type->n_min, type->n_max, n);
1187 : : }
1188 : :
1189 : 129160 : datum->n = 0;
1190 : 129160 : datum->keys = xmalloc(n * sizeof *datum->keys);
1191 [ + + ]: 129160 : datum->values = is_map ? xmalloc(n * sizeof *datum->values) : NULL;
1192 [ + + ]: 461432 : for (i = 0; i < n; i++) {
1193 : 332272 : const struct json *element = inner->u.array.elems[i];
1194 : 332272 : const struct json *key = NULL;
1195 : 332272 : const struct json *value = NULL;
1196 : :
1197 [ + + ]: 332272 : if (!is_map) {
1198 : 176892 : key = element;
1199 : : } else {
1200 : 155380 : error = parse_json_pair(element, &key, &value);
1201 [ - + ]: 155380 : if (error) {
1202 : 0 : goto error;
1203 : : }
1204 : : }
1205 : :
1206 : 332272 : error = ovsdb_atom_from_json(&datum->keys[i], &type->key,
1207 : : key, symtab);
1208 [ - + ]: 332272 : if (error) {
1209 : 0 : goto error;
1210 : : }
1211 : :
1212 [ + + ]: 332272 : if (is_map) {
1213 : 155380 : error = ovsdb_atom_from_json(&datum->values[i],
1214 : : &type->value, value, symtab);
1215 [ - + ]: 155380 : if (error) {
1216 : 0 : ovsdb_atom_destroy(&datum->keys[i], type->key.type);
1217 : 0 : goto error;
1218 : : }
1219 : : }
1220 : :
1221 : 332272 : datum->n++;
1222 : : }
1223 : 129160 : return NULL;
1224 : :
1225 : : error:
1226 : 0 : ovsdb_datum_destroy(datum, type);
1227 : 129172 : return error;
1228 : : } else {
1229 : 512777 : datum->n = 1;
1230 : 512777 : datum->keys = xmalloc(sizeof *datum->keys);
1231 : 512777 : datum->values = NULL;
1232 : :
1233 : 512777 : error = ovsdb_atom_from_json(&datum->keys[0], &type->key,
1234 : : json, symtab);
1235 [ + + ]: 512777 : if (error) {
1236 : 15 : free(datum->keys);
1237 : : }
1238 : 512777 : return error;
1239 : : }
1240 : : }
1241 : :
1242 : : /* Parses 'json' as a datum of the type described by 'type'. If successful,
1243 : : * returns NULL and initializes 'datum' with the parsed datum. On failure,
1244 : : * returns an error and the contents of 'datum' are indeterminate. The caller
1245 : : * is responsible for freeing the error or the datum that is returned.
1246 : : *
1247 : : * Violations of constraints expressed by 'type' are treated as errors.
1248 : : *
1249 : : * If 'symtab' is nonnull, then named UUIDs in 'symtab' are accepted. Refer to
1250 : : * RFC 7047 for information about this, and for the syntax that this function
1251 : : * accepts. */
1252 : : struct ovsdb_error *
1253 : 641949 : ovsdb_datum_from_json(struct ovsdb_datum *datum,
1254 : : const struct ovsdb_type *type,
1255 : : const struct json *json,
1256 : : struct ovsdb_symbol_table *symtab)
1257 : : {
1258 : : struct ovsdb_error *error;
1259 : :
1260 : 641949 : error = ovsdb_datum_from_json__(datum, type, json, symtab);
1261 [ + + ]: 641949 : if (error) {
1262 : 27 : return error;
1263 : : }
1264 : :
1265 : 641922 : error = ovsdb_datum_sort(datum, type->key.type);
1266 [ + + ]: 641922 : if (error) {
1267 : 6 : ovsdb_datum_destroy(datum, type);
1268 : : }
1269 : 641922 : return error;
1270 : : }
1271 : :
1272 : : /* Parses 'json' as a datum of the type described by 'type' for internal
1273 : : * use. This function is similar to 'ovsdb_datum_from_json', except the
1274 : : * member size of set or map is not checked.
1275 : : *
1276 : : * The datum generated should be used then discard. It is not suitable
1277 : : * for storing into IDL because of the possible member size violation. */
1278 : : struct ovsdb_error *
1279 : 45829 : ovsdb_transient_datum_from_json(struct ovsdb_datum *datum,
1280 : : const struct ovsdb_type *type,
1281 : : const struct json *json)
1282 : : {
1283 : 45829 : struct ovsdb_type relaxed_type = *type;
1284 : :
1285 : 45829 : relaxed_type.n_min = 0;
1286 : 45829 : relaxed_type.n_max = UINT_MAX;
1287 : :
1288 : 45829 : return ovsdb_datum_from_json(datum, &relaxed_type, json, NULL);
1289 : : }
1290 : :
1291 : : /* Converts 'datum', of the specified 'type', to JSON format, and returns the
1292 : : * JSON. The caller is responsible for freeing the returned JSON.
1293 : : *
1294 : : * 'type' constraints on datum->n are ignored.
1295 : : *
1296 : : * Refer to RFC 7047 for the format of the JSON that this function produces. */
1297 : : struct json *
1298 : 895498 : ovsdb_datum_to_json(const struct ovsdb_datum *datum,
1299 : : const struct ovsdb_type *type)
1300 : : {
1301 [ + + ]: 895498 : if (ovsdb_type_is_map(type)) {
1302 : : struct json **elems;
1303 : : size_t i;
1304 : :
1305 : 129757 : elems = xmalloc(datum->n * sizeof *elems);
1306 [ + + ]: 295096 : for (i = 0; i < datum->n; i++) {
1307 : 165339 : elems[i] = json_array_create_2(
1308 : 165339 : ovsdb_atom_to_json(&datum->keys[i], type->key.type),
1309 : 165339 : ovsdb_atom_to_json(&datum->values[i], type->value.type));
1310 : : }
1311 : :
1312 : 129757 : return wrap_json("map", json_array_create(elems, datum->n));
1313 [ + + ]: 765741 : } else if (datum->n == 1) {
1314 : 578909 : return ovsdb_atom_to_json(&datum->keys[0], type->key.type);
1315 : : } else {
1316 : : struct json **elems;
1317 : : size_t i;
1318 : :
1319 : 186832 : elems = xmalloc(datum->n * sizeof *elems);
1320 [ + + ]: 582034 : for (i = 0; i < datum->n; i++) {
1321 : 395202 : elems[i] = ovsdb_atom_to_json(&datum->keys[i], type->key.type);
1322 : : }
1323 : :
1324 : 186832 : return wrap_json("set", json_array_create(elems, datum->n));
1325 : : }
1326 : : }
1327 : :
1328 : : static const char *
1329 : 20260 : skip_spaces(const char *p)
1330 : : {
1331 [ + + ]: 56305 : while (isspace((unsigned char) *p)) {
1332 : 36045 : p++;
1333 : : }
1334 : 20260 : return p;
1335 : : }
1336 : :
1337 : : static char *
1338 : 9357 : parse_atom_token(const char **s, const struct ovsdb_base_type *base,
1339 : : union ovsdb_atom *atom, struct ovsdb_symbol_table *symtab)
1340 : : {
1341 : : char *token, *error;
1342 : :
1343 : 9357 : error = ovsdb_token_parse(s, &token);
1344 [ + - ]: 9357 : if (!error) {
1345 : 9357 : error = ovsdb_atom_from_string(atom, base, token, symtab);
1346 : 9357 : free(token);
1347 : : }
1348 : 9357 : return error;
1349 : : }
1350 : :
1351 : : static char *
1352 : 9295 : parse_key_value(const char **s, const struct ovsdb_type *type,
1353 : : union ovsdb_atom *key, union ovsdb_atom *value,
1354 : : struct ovsdb_symbol_table *symtab)
1355 : : {
1356 : 9295 : const char *start = *s;
1357 : : char *error;
1358 : :
1359 : 9295 : error = parse_atom_token(s, &type->key, key, symtab);
1360 [ + + ][ + + ]: 9295 : if (!error && type->value.type != OVSDB_TYPE_VOID) {
1361 : 95 : *s = skip_spaces(*s);
1362 [ + + ]: 95 : if (**s == '=') {
1363 : 62 : (*s)++;
1364 : 62 : *s = skip_spaces(*s);
1365 : 62 : error = parse_atom_token(s, &type->value, value, symtab);
1366 : : } else {
1367 : 33 : error = xasprintf("%s: syntax error at \"%c\" expecting \"=\"",
1368 : 33 : start, **s);
1369 : : }
1370 [ + + ]: 95 : if (error) {
1371 : 33 : ovsdb_atom_destroy(key, type->key.type);
1372 : : }
1373 : : }
1374 : 9295 : return error;
1375 : : }
1376 : :
1377 : : static void
1378 : 9258 : free_key_value(const struct ovsdb_type *type,
1379 : : union ovsdb_atom *key, union ovsdb_atom *value)
1380 : : {
1381 : 9258 : ovsdb_atom_destroy(key, type->key.type);
1382 [ + + ]: 9258 : if (type->value.type != OVSDB_TYPE_VOID) {
1383 : 62 : ovsdb_atom_destroy(value, type->value.type);
1384 : : }
1385 : 9258 : }
1386 : :
1387 : : /* Initializes 'datum' as a datum of the given 'type', parsing its contents
1388 : : * from 's'. The format of 's' is a series of space or comma separated atoms
1389 : : * or, for a map, '='-delimited pairs of atoms. Each atom must in a format
1390 : : * acceptable to ovsdb_atom_from_string(). Optionally, a set may be enclosed
1391 : : * in "[]" or a map in "{}"; for an empty set or map these punctuators are
1392 : : * required.
1393 : : *
1394 : : * Optionally, a symbol table may be supplied as 'symtab'. It is passed to
1395 : : * ovsdb_atom_to_string(). */
1396 : : char *
1397 : 5868 : ovsdb_datum_from_string(struct ovsdb_datum *datum,
1398 : : const struct ovsdb_type *type, const char *s,
1399 : : struct ovsdb_symbol_table *symtab)
1400 : : {
1401 : 5868 : bool is_map = ovsdb_type_is_map(type);
1402 : : struct ovsdb_error *dberror;
1403 : : const char *p;
1404 : : int end_delim;
1405 : : char *error;
1406 : :
1407 : 5868 : ovsdb_datum_init_empty(datum);
1408 : :
1409 : : /* Swallow a leading delimiter if there is one. */
1410 : 5868 : p = skip_spaces(s);
1411 [ + + ][ + + ]: 5868 : if (*p == (is_map ? '{' : '[')) {
1412 [ + + ]: 680 : end_delim = is_map ? '}' : ']';
1413 : 680 : p = skip_spaces(p + 1);
1414 [ - + ]: 5188 : } else if (!*p) {
1415 [ # # ]: 0 : if (is_map) {
1416 : 0 : return xstrdup("use \"{}\" to specify the empty map");
1417 : : } else {
1418 : 0 : return xstrdup("use \"[]\" to specify the empty set");
1419 : : }
1420 : : } else {
1421 : 5188 : end_delim = 0;
1422 : : }
1423 : :
1424 [ + + ][ + + ]: 15126 : while (*p && *p != end_delim) {
1425 : : union ovsdb_atom key, value;
1426 : :
1427 [ - + ]: 9295 : if (ovsdb_token_is_delim(*p)) {
1428 : 0 : char *type_str = ovsdb_type_to_english(type);
1429 : 0 : error = xasprintf("%s: unexpected \"%c\" parsing %s",
1430 : 0 : s, *p, type_str);
1431 : 0 : free(type_str);
1432 : 37 : goto error;
1433 : : }
1434 : :
1435 : : /* Add to datum. */
1436 : 9295 : error = parse_key_value(&p, type, &key, &value, symtab);
1437 [ + + ]: 9295 : if (error) {
1438 : 37 : goto error;
1439 : : }
1440 : 9258 : ovsdb_datum_add_unsafe(datum, &key, &value, type);
1441 : 9258 : free_key_value(type, &key, &value);
1442 : :
1443 : : /* Skip optional white space and comma. */
1444 : 9258 : p = skip_spaces(p);
1445 [ + + ]: 9258 : if (*p == ',') {
1446 : 9258 : p = skip_spaces(p + 1);
1447 : : }
1448 : : }
1449 : :
1450 [ - + ]: 5831 : if (*p != end_delim) {
1451 : 0 : error = xasprintf("%s: missing \"%c\" at end of data", s, end_delim);
1452 : 0 : goto error;
1453 : : }
1454 [ + + ]: 5831 : if (end_delim) {
1455 : 680 : p = skip_spaces(p + 1);
1456 [ - + ]: 680 : if (*p) {
1457 : 0 : error = xasprintf("%s: trailing garbage after \"%c\"",
1458 : : s, end_delim);
1459 : 0 : goto error;
1460 : : }
1461 : : }
1462 : :
1463 [ - + ]: 5831 : if (datum->n < type->n_min) {
1464 [ # # ]: 0 : error = xasprintf("%s: %u %s specified but the minimum number is %u",
1465 : : s, datum->n, is_map ? "pair(s)" : "value(s)",
1466 : : type->n_min);
1467 : 0 : goto error;
1468 [ + + ]: 5831 : } else if (datum->n > type->n_max) {
1469 [ - + ]: 1 : error = xasprintf("%s: %u %s specified but the maximum number is %u",
1470 : : s, datum->n, is_map ? "pair(s)" : "value(s)",
1471 : : type->n_max);
1472 : 1 : goto error;
1473 : : }
1474 : :
1475 : 5830 : dberror = ovsdb_datum_sort(datum, type->key.type);
1476 [ + + ]: 5830 : if (dberror) {
1477 : 7 : ovsdb_error_destroy(dberror);
1478 [ + + ]: 7 : if (ovsdb_type_is_map(type)) {
1479 : 1 : error = xasprintf("%s: map contains duplicate key", s);
1480 : : } else {
1481 : 6 : error = xasprintf("%s: set contains duplicate value", s);
1482 : : }
1483 : 7 : goto error;
1484 : : }
1485 : :
1486 : 5823 : return NULL;
1487 : :
1488 : : error:
1489 : 45 : ovsdb_datum_destroy(datum, type);
1490 : 45 : ovsdb_datum_init_empty(datum);
1491 : 5868 : return error;
1492 : : }
1493 : :
1494 : : /* Appends to 'out' the 'datum' (with the given 'type') in a format acceptable
1495 : : * to ovsdb_datum_from_string(). */
1496 : : void
1497 : 23726 : ovsdb_datum_to_string(const struct ovsdb_datum *datum,
1498 : : const struct ovsdb_type *type, struct ds *out)
1499 : : {
1500 : 23726 : bool is_map = ovsdb_type_is_map(type);
1501 : : size_t i;
1502 : :
1503 [ + + ][ + + ]: 23726 : if (type->n_max > 1 || !datum->n) {
1504 [ + + ]: 12766 : ds_put_char(out, is_map ? '{' : '[');
1505 : : }
1506 [ + + ]: 37546 : for (i = 0; i < datum->n; i++) {
1507 [ + + ]: 13820 : if (i > 0) {
1508 : 1118 : ds_put_cstr(out, ", ");
1509 : : }
1510 : :
1511 : 13820 : ovsdb_atom_to_string(&datum->keys[i], type->key.type, out);
1512 [ + + ]: 13820 : if (is_map) {
1513 : 2096 : ds_put_char(out, '=');
1514 : 2096 : ovsdb_atom_to_string(&datum->values[i], type->value.type, out);
1515 : : }
1516 : : }
1517 [ + + ][ + + ]: 23726 : if (type->n_max > 1 || !datum->n) {
1518 [ + + ]: 12766 : ds_put_char(out, is_map ? '}' : ']');
1519 : : }
1520 : 23726 : }
1521 : :
1522 : : /* Appends to 'out' the 'datum' (with the given 'type') in a bare string format
1523 : : * that cannot be parsed uniformly back into a datum but is easier for shell
1524 : : * scripts, etc., to deal with. */
1525 : : void
1526 : 1065 : ovsdb_datum_to_bare(const struct ovsdb_datum *datum,
1527 : : const struct ovsdb_type *type, struct ds *out)
1528 : : {
1529 : 1065 : bool is_map = ovsdb_type_is_map(type);
1530 : : size_t i;
1531 : :
1532 [ + + ]: 2130 : for (i = 0; i < datum->n; i++) {
1533 [ - + ]: 1065 : if (i > 0) {
1534 : 0 : ds_put_cstr(out, " ");
1535 : : }
1536 : :
1537 : 1065 : ovsdb_atom_to_bare(&datum->keys[i], type->key.type, out);
1538 [ - + ]: 1065 : if (is_map) {
1539 : 0 : ds_put_char(out, '=');
1540 : 0 : ovsdb_atom_to_bare(&datum->values[i], type->value.type, out);
1541 : : }
1542 : : }
1543 : 1065 : }
1544 : :
1545 : : /* Initializes 'datum' as a string-to-string map whose contents are taken from
1546 : : * 'smap'. Destroys 'smap'. */
1547 : : void
1548 : 0 : ovsdb_datum_from_smap(struct ovsdb_datum *datum, struct smap *smap)
1549 : : {
1550 : : struct smap_node *node, *next;
1551 : : size_t i;
1552 : :
1553 : 0 : datum->n = smap_count(smap);
1554 : 0 : datum->keys = xmalloc(datum->n * sizeof *datum->keys);
1555 : 0 : datum->values = xmalloc(datum->n * sizeof *datum->values);
1556 : :
1557 : 0 : i = 0;
1558 [ # # ][ # # ]: 0 : SMAP_FOR_EACH_SAFE (node, next, smap) {
[ # # ]
1559 : 0 : smap_steal(smap, node,
1560 : 0 : &datum->keys[i].string, &datum->values[i].string);
1561 : 0 : i++;
1562 : : }
1563 [ # # ]: 0 : ovs_assert(i == datum->n);
1564 : :
1565 : 0 : smap_destroy(smap);
1566 : 0 : ovsdb_datum_sort_unique(datum, OVSDB_TYPE_STRING, OVSDB_TYPE_STRING);
1567 : 0 : }
1568 : :
1569 : : static uint32_t
1570 : 392398 : hash_atoms(enum ovsdb_atomic_type type, const union ovsdb_atom *atoms,
1571 : : unsigned int n, uint32_t basis)
1572 : : {
1573 [ + + ]: 392398 : if (type != OVSDB_TYPE_VOID) {
1574 : : unsigned int i;
1575 : :
1576 [ + + ]: 460848 : for (i = 0; i < n; i++) {
1577 : 262270 : basis = ovsdb_atom_hash(&atoms[i], type, basis);
1578 : : }
1579 : : }
1580 : 392398 : return basis;
1581 : : }
1582 : :
1583 : : uint32_t
1584 : 196199 : ovsdb_datum_hash(const struct ovsdb_datum *datum,
1585 : : const struct ovsdb_type *type, uint32_t basis)
1586 : : {
1587 : 196199 : basis = hash_atoms(type->key.type, datum->keys, datum->n, basis);
1588 : 196199 : basis ^= (type->key.type << 24) | (type->value.type << 16) | datum->n;
1589 : 196199 : basis = hash_atoms(type->value.type, datum->values, datum->n, basis);
1590 : 196199 : return basis;
1591 : : }
1592 : :
1593 : : static int
1594 : 2560259 : atom_arrays_compare_3way(const union ovsdb_atom *a,
1595 : : const union ovsdb_atom *b,
1596 : : enum ovsdb_atomic_type type,
1597 : : size_t n)
1598 : : {
1599 : : unsigned int i;
1600 : :
1601 [ + + ]: 4067920 : for (i = 0; i < n; i++) {
1602 : 1844211 : int cmp = ovsdb_atom_compare_3way(&a[i], &b[i], type);
1603 [ + + ]: 1844211 : if (cmp) {
1604 : 336550 : return cmp;
1605 : : }
1606 : : }
1607 : :
1608 : 2223709 : return 0;
1609 : : }
1610 : :
1611 : : bool
1612 : 2404990 : ovsdb_datum_equals(const struct ovsdb_datum *a,
1613 : : const struct ovsdb_datum *b,
1614 : : const struct ovsdb_type *type)
1615 : : {
1616 : 2404990 : return !ovsdb_datum_compare_3way(a, b, type);
1617 : : }
1618 : :
1619 : : int
1620 : 2406528 : ovsdb_datum_compare_3way(const struct ovsdb_datum *a,
1621 : : const struct ovsdb_datum *b,
1622 : : const struct ovsdb_type *type)
1623 : : {
1624 : : int cmp;
1625 : :
1626 [ + + ]: 2406528 : if (a->n != b->n) {
1627 [ + + ]: 256237 : return a->n < b->n ? -1 : 1;
1628 : : }
1629 : :
1630 : 2150291 : cmp = atom_arrays_compare_3way(a->keys, b->keys, type->key.type, a->n);
1631 [ + + ]: 2150291 : if (cmp) {
1632 : 318456 : return cmp;
1633 : : }
1634 : :
1635 : 1831835 : return (type->value.type == OVSDB_TYPE_VOID ? 0
1636 [ + + ]: 1831835 : : atom_arrays_compare_3way(a->values, b->values, type->value.type,
1637 : 409968 : a->n));
1638 : : }
1639 : :
1640 : : /* If 'key' is one of the keys in 'datum', returns its index within 'datum',
1641 : : * otherwise UINT_MAX. 'key.type' must be the type of the atoms stored in the
1642 : : * 'keys' array in 'datum'.
1643 : : */
1644 : : unsigned int
1645 : 70219 : ovsdb_datum_find_key(const struct ovsdb_datum *datum,
1646 : : const union ovsdb_atom *key,
1647 : : enum ovsdb_atomic_type key_type)
1648 : : {
1649 : 70219 : unsigned int low = 0;
1650 : 70219 : unsigned int high = datum->n;
1651 [ + + ]: 122960 : while (low < high) {
1652 : 119682 : unsigned int idx = (low + high) / 2;
1653 : 119682 : int cmp = ovsdb_atom_compare_3way(key, &datum->keys[idx], key_type);
1654 [ + + ]: 119682 : if (cmp < 0) {
1655 : 38680 : high = idx;
1656 [ + + ]: 81002 : } else if (cmp > 0) {
1657 : 14061 : low = idx + 1;
1658 : : } else {
1659 : 66941 : return idx;
1660 : : }
1661 : : }
1662 : 3278 : return UINT_MAX;
1663 : : }
1664 : :
1665 : : /* If 'key' and 'value' is one of the key-value pairs in 'datum', returns its
1666 : : * index within 'datum', otherwise UINT_MAX. 'key.type' must be the type of
1667 : : * the atoms stored in the 'keys' array in 'datum'. 'value_type' may be the
1668 : : * type of the 'values' atoms or OVSDB_TYPE_VOID to compare only keys.
1669 : : */
1670 : : unsigned int
1671 : 1408 : ovsdb_datum_find_key_value(const struct ovsdb_datum *datum,
1672 : : const union ovsdb_atom *key,
1673 : : enum ovsdb_atomic_type key_type,
1674 : : const union ovsdb_atom *value,
1675 : : enum ovsdb_atomic_type value_type)
1676 : : {
1677 : 1408 : unsigned int idx = ovsdb_datum_find_key(datum, key, key_type);
1678 [ + + ]: 1408 : if (idx != UINT_MAX
1679 [ + + ]: 684 : && value_type != OVSDB_TYPE_VOID
1680 [ + + ]: 425 : && !ovsdb_atom_equals(&datum->values[idx], value, value_type)) {
1681 : 81 : idx = UINT_MAX;
1682 : : }
1683 : 1408 : return idx;
1684 : : }
1685 : :
1686 : : /* If atom 'i' in 'a' is also in 'b', returns its index in 'b', otherwise
1687 : : * UINT_MAX. 'type' must be the type of 'a' and 'b', except that
1688 : : * type->value.type may be set to OVSDB_TYPE_VOID to compare keys but not
1689 : : * values. */
1690 : : static unsigned int
1691 : 1408 : ovsdb_datum_find(const struct ovsdb_datum *a, int i,
1692 : : const struct ovsdb_datum *b,
1693 : : const struct ovsdb_type *type)
1694 : : {
1695 [ + + ]: 1408 : return ovsdb_datum_find_key_value(b,
1696 : 2816 : &a->keys[i], type->key.type,
1697 : 2196 : a->values ? &a->values[i] : NULL,
1698 : : type->value.type);
1699 : : }
1700 : :
1701 : : /* Returns true if every element in 'a' is also in 'b', false otherwise. */
1702 : : bool
1703 : 725 : ovsdb_datum_includes_all(const struct ovsdb_datum *a,
1704 : : const struct ovsdb_datum *b,
1705 : : const struct ovsdb_type *type)
1706 : : {
1707 : : size_t i;
1708 : :
1709 [ + + ]: 725 : if (a->n > b->n) {
1710 : 209 : return false;
1711 : : }
1712 [ + + ]: 772 : for (i = 0; i < a->n; i++) {
1713 [ + + ]: 457 : if (ovsdb_datum_find(a, i, b, type) == UINT_MAX) {
1714 : 201 : return false;
1715 : : }
1716 : : }
1717 : 315 : return true;
1718 : : }
1719 : :
1720 : : /* Returns true if no element in 'a' is also in 'b', false otherwise. */
1721 : : bool
1722 : 496 : ovsdb_datum_excludes_all(const struct ovsdb_datum *a,
1723 : : const struct ovsdb_datum *b,
1724 : : const struct ovsdb_type *type)
1725 : : {
1726 : : size_t i;
1727 : :
1728 [ + + ]: 830 : for (i = 0; i < a->n; i++) {
1729 [ + + ]: 592 : if (ovsdb_datum_find(a, i, b, type) != UINT_MAX) {
1730 : 258 : return false;
1731 : : }
1732 : : }
1733 : 238 : return true;
1734 : : }
1735 : :
1736 : : static void
1737 : 1618 : ovsdb_datum_reallocate(struct ovsdb_datum *a, const struct ovsdb_type *type,
1738 : : unsigned int capacity)
1739 : : {
1740 : 1618 : a->keys = xrealloc(a->keys, capacity * sizeof *a->keys);
1741 [ + + ]: 1618 : if (type->value.type != OVSDB_TYPE_VOID) {
1742 : 1509 : a->values = xrealloc(a->values, capacity * sizeof *a->values);
1743 : : }
1744 : 1618 : }
1745 : :
1746 : : /* Removes the element with index 'idx' from 'datum', which has type 'type'.
1747 : : * If 'idx' is not the last element in 'datum', then the removed element is
1748 : : * replaced by the (former) last element.
1749 : : *
1750 : : * This function does not maintain ovsdb_datum invariants. Use
1751 : : * ovsdb_datum_sort() to check and restore these invariants. */
1752 : : void
1753 : 145 : ovsdb_datum_remove_unsafe(struct ovsdb_datum *datum, size_t idx,
1754 : : const struct ovsdb_type *type)
1755 : : {
1756 : 145 : ovsdb_atom_destroy(&datum->keys[idx], type->key.type);
1757 : 145 : datum->keys[idx] = datum->keys[datum->n - 1];
1758 [ + + ]: 145 : if (type->value.type != OVSDB_TYPE_VOID) {
1759 : 21 : ovsdb_atom_destroy(&datum->values[idx], type->value.type);
1760 : 21 : datum->values[idx] = datum->values[datum->n - 1];
1761 : : }
1762 : 145 : datum->n--;
1763 : 145 : }
1764 : :
1765 : : /* Adds the element with the given 'key' and 'value' to 'datum', which must
1766 : : * have the specified 'type'.
1767 : : *
1768 : : * This function always allocates memory, so it is not an efficient way to add
1769 : : * a number of elements to a datum.
1770 : : *
1771 : : * This function does not maintain ovsdb_datum invariants. Use
1772 : : * ovsdb_datum_sort() to check and restore these invariants. (But a datum with
1773 : : * 0 or 1 elements cannot violate the invariants anyhow.) */
1774 : : void
1775 : 149875 : ovsdb_datum_add_unsafe(struct ovsdb_datum *datum,
1776 : : const union ovsdb_atom *key,
1777 : : const union ovsdb_atom *value,
1778 : : const struct ovsdb_type *type)
1779 : : {
1780 : 149875 : size_t idx = datum->n++;
1781 : 149875 : datum->keys = xrealloc(datum->keys, datum->n * sizeof *datum->keys);
1782 : 149875 : ovsdb_atom_clone(&datum->keys[idx], key, type->key.type);
1783 [ + + ]: 149875 : if (type->value.type != OVSDB_TYPE_VOID) {
1784 : 60939 : datum->values = xrealloc(datum->values,
1785 : 60939 : datum->n * sizeof *datum->values);
1786 : 60939 : ovsdb_atom_clone(&datum->values[idx], value, type->value.type);
1787 : : }
1788 : 149875 : }
1789 : :
1790 : : void
1791 : 3662 : ovsdb_datum_union(struct ovsdb_datum *a, const struct ovsdb_datum *b,
1792 : : const struct ovsdb_type *type, bool replace)
1793 : : {
1794 : : unsigned int n;
1795 : : size_t bi;
1796 : :
1797 : 3662 : n = a->n;
1798 [ + + ]: 6058 : for (bi = 0; bi < b->n; bi++) {
1799 : : unsigned int ai;
1800 : :
1801 : 2396 : ai = ovsdb_datum_find_key(a, &b->keys[bi], type->key.type);
1802 [ + + ]: 2396 : if (ai == UINT_MAX) {
1803 [ + + ]: 2255 : if (n == a->n) {
1804 : 1618 : ovsdb_datum_reallocate(a, type, a->n + (b->n - bi));
1805 : : }
1806 : 2255 : ovsdb_atom_clone(&a->keys[n], &b->keys[bi], type->key.type);
1807 [ + + ]: 2255 : if (type->value.type != OVSDB_TYPE_VOID) {
1808 : 2136 : ovsdb_atom_clone(&a->values[n], &b->values[bi],
1809 : : type->value.type);
1810 : : }
1811 : 2255 : n++;
1812 [ - + ][ # # ]: 141 : } else if (replace && type->value.type != OVSDB_TYPE_VOID) {
1813 : 0 : ovsdb_atom_destroy(&a->values[ai], type->value.type);
1814 : 0 : ovsdb_atom_clone(&a->values[ai], &b->values[bi],
1815 : : type->value.type);
1816 : : }
1817 : : }
1818 [ + + ]: 3662 : if (n != a->n) {
1819 : : struct ovsdb_error *error;
1820 : 1618 : a->n = n;
1821 : 1618 : error = ovsdb_datum_sort(a, type->key.type);
1822 [ - + ]: 1618 : ovs_assert(!error);
1823 : : }
1824 : 3662 : }
1825 : :
1826 : : void
1827 : 157 : ovsdb_datum_subtract(struct ovsdb_datum *a, const struct ovsdb_type *a_type,
1828 : : const struct ovsdb_datum *b,
1829 : : const struct ovsdb_type *b_type)
1830 : : {
1831 : 157 : bool changed = false;
1832 : : size_t i;
1833 : :
1834 [ - + ]: 157 : ovs_assert(a_type->key.type == b_type->key.type);
1835 [ + + ][ - + ]: 157 : ovs_assert(a_type->value.type == b_type->value.type
1836 : : || b_type->value.type == OVSDB_TYPE_VOID);
1837 : :
1838 : : /* XXX The big-O of this could easily be improved. */
1839 [ + + ]: 516 : for (i = 0; i < a->n; ) {
1840 : 359 : unsigned int idx = ovsdb_datum_find(a, i, b, b_type);
1841 [ + + ]: 359 : if (idx != UINT_MAX) {
1842 : 89 : changed = true;
1843 : 89 : ovsdb_datum_remove_unsafe(a, i, a_type);
1844 : : } else {
1845 : 270 : i++;
1846 : : }
1847 : : }
1848 [ + + ]: 157 : if (changed) {
1849 : 81 : ovsdb_datum_sort_assert(a, a_type->key.type);
1850 : : }
1851 : 157 : }
1852 : :
1853 : : struct ovsdb_symbol_table *
1854 : 18938 : ovsdb_symbol_table_create(void)
1855 : : {
1856 : 18938 : struct ovsdb_symbol_table *symtab = xmalloc(sizeof *symtab);
1857 : 18938 : shash_init(&symtab->sh);
1858 : 18938 : return symtab;
1859 : : }
1860 : :
1861 : : void
1862 : 18743 : ovsdb_symbol_table_destroy(struct ovsdb_symbol_table *symtab)
1863 : : {
1864 [ + - ]: 18743 : if (symtab) {
1865 : 18743 : shash_destroy_free_data(&symtab->sh);
1866 : 18743 : free(symtab);
1867 : : }
1868 : 18743 : }
1869 : :
1870 : : struct ovsdb_symbol *
1871 : 45967 : ovsdb_symbol_table_get(const struct ovsdb_symbol_table *symtab,
1872 : : const char *name)
1873 : : {
1874 : 45967 : return shash_find_data(&symtab->sh, name);
1875 : : }
1876 : :
1877 : : struct ovsdb_symbol *
1878 : 16689 : ovsdb_symbol_table_put(struct ovsdb_symbol_table *symtab, const char *name,
1879 : : const struct uuid *uuid, bool created)
1880 : : {
1881 : : struct ovsdb_symbol *symbol;
1882 : :
1883 [ - + ]: 16689 : ovs_assert(!ovsdb_symbol_table_get(symtab, name));
1884 : 16689 : symbol = xmalloc(sizeof *symbol);
1885 : 16689 : symbol->uuid = *uuid;
1886 : 16689 : symbol->created = created;
1887 : 16689 : symbol->strong_ref = false;
1888 : 16689 : symbol->weak_ref = false;
1889 : 16689 : shash_add(&symtab->sh, name, symbol);
1890 : 16689 : return symbol;
1891 : : }
1892 : :
1893 : : struct ovsdb_symbol *
1894 : 28972 : ovsdb_symbol_table_insert(struct ovsdb_symbol_table *symtab,
1895 : : const char *name)
1896 : : {
1897 : : struct ovsdb_symbol *symbol;
1898 : :
1899 : 28972 : symbol = ovsdb_symbol_table_get(symtab, name);
1900 [ + + ]: 28972 : if (!symbol) {
1901 : : struct uuid uuid;
1902 : :
1903 : 16666 : uuid_generate(&uuid);
1904 : 16666 : symbol = ovsdb_symbol_table_put(symtab, name, &uuid, false);
1905 : : }
1906 : 28972 : return symbol;
1907 : : }
1908 : :
1909 : : /* APIs for Generating and apply diffs. */
1910 : :
1911 : : /* Generate a difference ovsdb_dataum between 'old' and 'new'.
1912 : : * 'new' can be regenerated by applying the difference to the 'old'.
1913 : : *
1914 : : * The diff operation is reversible. Given 'old',
1915 : : * 'new' can be recreated by applying diff to 'old'.
1916 : : *
1917 : : * Thus
1918 : : * Let d = 'old' diff 'new'
1919 : : * then 'new' = 'old' diff d
1920 : : *
1921 : : * The 'diff' datum is always safe; the orders of keys are maintained
1922 : : * since they are added in order. */
1923 : : void
1924 : 91089 : ovsdb_datum_diff(struct ovsdb_datum *diff,
1925 : : const struct ovsdb_datum *old,
1926 : : const struct ovsdb_datum *new,
1927 : : const struct ovsdb_type *type)
1928 : : {
1929 : : size_t oi, ni;
1930 : :
1931 : 91089 : ovsdb_datum_init_empty(diff);
1932 [ + + ]: 91089 : if (!ovsdb_type_is_composite(type)) {
1933 : 63468 : ovsdb_datum_clone(diff, new, type);
1934 : 63468 : return;
1935 : : }
1936 : :
1937 : : /* Generate the diff in O(n) time. */
1938 [ + + ][ + + ]: 136870 : for (oi = ni = 0; oi < old->n && ni < new->n; ) {
1939 : 109249 : int c = ovsdb_atom_compare_3way(&old->keys[oi], &new->keys[ni],
1940 : : type->key.type);
1941 [ + + ]: 109249 : if (c < 0) {
1942 : 30166 : ovsdb_datum_add_unsafe(diff, &old->keys[oi], &old->values[oi],
1943 : : type);
1944 : 30166 : oi++;
1945 [ + + ]: 79083 : } else if (c > 0) {
1946 : 5167 : ovsdb_datum_add_unsafe(diff, &new->keys[ni], &new->values[ni],
1947 : : type);
1948 : 5167 : ni++;
1949 : : } else {
1950 [ + + + + ]: 98819 : if (type->value.type != OVSDB_TYPE_VOID &&
1951 : 24903 : ovsdb_atom_compare_3way(&old->values[oi], &new->values[ni],
1952 : : type->value.type)) {
1953 : 18199 : ovsdb_datum_add_unsafe(diff, &new->keys[ni], &new->values[ni],
1954 : : type);
1955 : : }
1956 : 73916 : oi++; ni++;
1957 : : }
1958 : : }
1959 : :
1960 [ + + ]: 54040 : for (; oi < old->n; oi++) {
1961 : 26419 : ovsdb_datum_add_unsafe(diff, &old->keys[oi], &old->values[oi], type);
1962 : : }
1963 : :
1964 [ + + ]: 84776 : for (; ni < new->n; ni++) {
1965 : 57155 : ovsdb_datum_add_unsafe(diff, &new->keys[ni], &new->values[ni], type);
1966 : : }
1967 : : }
1968 : :
1969 : : /* Apply 'diff' to 'old' to regenerate 'new'.
1970 : : *
1971 : : * Return NULL if the 'new' is successfully generated, otherwise, return
1972 : : * ovsdb_error and the stat of 'new' is indeterministic. */
1973 : : struct ovsdb_error *
1974 : 45829 : ovsdb_datum_apply_diff(struct ovsdb_datum *new,
1975 : : const struct ovsdb_datum *old,
1976 : : const struct ovsdb_datum *diff,
1977 : : const struct ovsdb_type *type)
1978 : : {
1979 : 45829 : ovsdb_datum_init_empty(new);
1980 : 45829 : ovsdb_datum_diff(new, old, diff, type);
1981 : :
1982 : : /* Make sure member size of 'new' conforms to type. */
1983 [ + - ][ + + ]: 45829 : if (new->n < type->n_min || new->n > type->n_max) {
1984 : 2 : ovsdb_datum_destroy(new, type);
1985 : 2 : return ovsdb_error(NULL, "Datum crated by diff has size error");
1986 : : }
1987 : :
1988 : 45827 : return NULL;
1989 : : }
1990 : :
1991 : :
1992 : : /* Extracts a token from the beginning of 's' and returns a pointer just after
1993 : : * the token. Stores the token itself into '*outp', which the caller is
1994 : : * responsible for freeing (with free()).
1995 : : *
1996 : : * If 's[0]' is a delimiter, the returned token is the empty string.
1997 : : *
1998 : : * A token extends from 's' to the first delimiter, as defined by
1999 : : * ovsdb_token_is_delim(), or until the end of the string. A delimiter can be
2000 : : * escaped with a backslash, in which case the backslash does not appear in the
2001 : : * output. Double quotes also cause delimiters to be ignored, but the double
2002 : : * quotes are retained in the output. (Backslashes inside double quotes are
2003 : : * not removed, either.)
2004 : : */
2005 : : char *
2006 : 32525 : ovsdb_token_parse(const char **s, char **outp)
2007 : : {
2008 : : const char *p;
2009 : : struct ds out;
2010 : : bool in_quotes;
2011 : : char *error;
2012 : :
2013 : 32525 : ds_init(&out);
2014 : 32525 : in_quotes = false;
2015 [ + + ]: 302241 : for (p = *s; *p != '\0'; ) {
2016 : 295416 : int c = *p++;
2017 [ + + ]: 295416 : if (c == '\\') {
2018 [ + + ]: 10 : if (in_quotes) {
2019 : 8 : ds_put_char(&out, '\\');
2020 : : }
2021 [ - + ]: 10 : if (!*p) {
2022 : 0 : error = xasprintf("%s: backslash at end of argument", *s);
2023 : 0 : goto error;
2024 : : }
2025 : 10 : ds_put_char(&out, *p++);
2026 [ + + ][ + + ]: 295406 : } else if (!in_quotes && ovsdb_token_is_delim(c)) {
2027 : 25700 : p--;
2028 : 25700 : break;
2029 : : } else {
2030 : 269706 : ds_put_char(&out, c);
2031 [ + + ]: 269706 : if (c == '"') {
2032 : 438 : in_quotes = !in_quotes;
2033 : : }
2034 : : }
2035 : : }
2036 [ - + ]: 32525 : if (in_quotes) {
2037 : 0 : error = xasprintf("%s: quoted string extends past end of argument",
2038 : : *s);
2039 : 0 : goto error;
2040 : : }
2041 : 32525 : *outp = ds_cstr(&out);
2042 : 32525 : *s = p;
2043 : 32525 : return NULL;
2044 : :
2045 : : error:
2046 : 0 : ds_destroy(&out);
2047 : 0 : *outp = NULL;
2048 : 32525 : return error;
2049 : : }
2050 : :
2051 : : /* Returns true if 'c' delimits tokens, or if 'c' is 0, and false otherwise. */
2052 : : bool
2053 : 302283 : ovsdb_token_is_delim(unsigned char c)
2054 : : {
2055 : 302283 : return strchr(":=, []{}!<>", c) != NULL;
2056 : : }
|