Coverage Report

Created: 2023-03-26 07:41

/src/openvswitch/lib/ovsdb-data.c
Line
Count
Source (jump to first uncovered line)
1
/* Copyright (c) 2009, 2010, 2011, 2012, 2014, 2016, 2017 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
wrap_json(const char *name, struct json *wrapped)
39
0
{
40
0
    return json_array_create_2(json_string_create(name), wrapped);
41
0
}
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
ovsdb_atom_init_default(union ovsdb_atom *atom, enum ovsdb_atomic_type type)
59
0
{
60
0
    switch (type) {
61
0
    case OVSDB_TYPE_VOID:
62
0
        OVS_NOT_REACHED();
63
64
0
    case OVSDB_TYPE_INTEGER:
65
0
        atom->integer = 0;
66
0
        break;
67
68
0
    case OVSDB_TYPE_REAL:
69
0
        atom->real = 0.0;
70
0
        break;
71
72
0
    case OVSDB_TYPE_BOOLEAN:
73
0
        atom->boolean = false;
74
0
        break;
75
76
0
    case OVSDB_TYPE_STRING:
77
0
        atom->s = ovsdb_atom_string_create_nocopy(xmemdup("", 1));
78
0
        break;
79
80
0
    case OVSDB_TYPE_UUID:
81
0
        uuid_zero(&atom->uuid);
82
0
        break;
83
84
0
    case OVSDB_N_TYPES:
85
0
    default:
86
0
        OVS_NOT_REACHED();
87
0
    }
88
0
}
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
ovsdb_atom_default(enum ovsdb_atomic_type type)
97
0
{
98
0
    static union ovsdb_atom default_atoms[OVSDB_N_TYPES];
99
0
    static struct ovsthread_once once = OVSTHREAD_ONCE_INITIALIZER;
100
101
0
    if (ovsthread_once_start(&once)) {
102
0
        int i;
103
104
0
        for (i = 0; i < OVSDB_N_TYPES; i++) {
105
0
            if (i != OVSDB_TYPE_VOID) {
106
0
                ovsdb_atom_init_default(&default_atoms[i], i);
107
0
            }
108
0
        }
109
0
        ovsthread_once_done(&once);
110
0
    }
111
112
0
    ovs_assert(ovsdb_atomic_type_is_valid(type));
113
0
    return &default_atoms[type];
114
0
}
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
ovsdb_atom_is_default(const union ovsdb_atom *atom,
123
                      enum ovsdb_atomic_type type)
124
0
{
125
0
    switch (type) {
126
0
    case OVSDB_TYPE_VOID:
127
0
        OVS_NOT_REACHED();
128
129
0
    case OVSDB_TYPE_INTEGER:
130
0
        return atom->integer == 0;
131
132
0
    case OVSDB_TYPE_REAL:
133
0
        return atom->real == 0.0;
134
135
0
    case OVSDB_TYPE_BOOLEAN:
136
0
        return atom->boolean == false;
137
138
0
    case OVSDB_TYPE_STRING:
139
0
        return json_string(atom->s)[0] == '\0';
140
141
0
    case OVSDB_TYPE_UUID:
142
0
        return uuid_is_zero(&atom->uuid);
143
144
0
    case OVSDB_N_TYPES:
145
0
    default:
146
0
        OVS_NOT_REACHED();
147
0
    }
148
0
}
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
ovsdb_atom_clone(union ovsdb_atom *new, const union ovsdb_atom *old,
156
                 enum ovsdb_atomic_type type)
157
0
{
158
0
    switch (type) {
159
0
    case OVSDB_TYPE_VOID:
160
0
        OVS_NOT_REACHED();
161
162
0
    case OVSDB_TYPE_INTEGER:
163
0
        new->integer = old->integer;
164
0
        break;
165
166
0
    case OVSDB_TYPE_REAL:
167
0
        new->real = old->real;
168
0
        break;
169
170
0
    case OVSDB_TYPE_BOOLEAN:
171
0
        new->boolean = old->boolean;
172
0
        break;
173
174
0
    case OVSDB_TYPE_STRING:
175
0
        new->s = json_clone(old->s);
176
0
        break;
177
178
0
    case OVSDB_TYPE_UUID:
179
0
        new->uuid = old->uuid;
180
0
        break;
181
182
0
    case OVSDB_N_TYPES:
183
0
    default:
184
0
        OVS_NOT_REACHED();
185
0
    }
186
0
}
187
188
/* Swaps the contents of 'a' and 'b', which need not have the same type. */
189
void
190
ovsdb_atom_swap(union ovsdb_atom *a, union ovsdb_atom *b)
191
0
{
192
0
    union ovsdb_atom tmp = *a;
193
0
    *a = *b;
194
0
    *b = tmp;
195
0
}
196
197
/* Returns a hash value for 'atom', which has the specified 'type', folding
198
 * 'basis' into the calculation. */
199
uint32_t
200
ovsdb_atom_hash(const union ovsdb_atom *atom, enum ovsdb_atomic_type type,
201
                uint32_t basis)
202
0
{
203
0
    switch (type) {
204
0
    case OVSDB_TYPE_VOID:
205
0
        OVS_NOT_REACHED();
206
207
0
    case OVSDB_TYPE_INTEGER:
208
0
        return hash_int(atom->integer, basis);
209
210
0
    case OVSDB_TYPE_REAL:
211
0
        return hash_double(atom->real, basis);
212
213
0
    case OVSDB_TYPE_BOOLEAN:
214
0
        return hash_boolean(atom->boolean, basis);
215
216
0
    case OVSDB_TYPE_STRING:
217
0
        return json_hash(atom->s, basis);
218
219
0
    case OVSDB_TYPE_UUID:
220
0
        return hash_int(uuid_hash(&atom->uuid), basis);
221
222
0
    case OVSDB_N_TYPES:
223
0
    default:
224
0
        OVS_NOT_REACHED();
225
0
    }
226
0
}
227
228
/* Compares 'a' and 'b', which both have type 'type', and returns a
229
 * strcmp()-like result. */
230
int
231
ovsdb_atom_compare_3way(const union ovsdb_atom *a,
232
                        const union ovsdb_atom *b,
233
                        enum ovsdb_atomic_type type)
234
0
{
235
0
    switch (type) {
236
0
    case OVSDB_TYPE_VOID:
237
0
        OVS_NOT_REACHED();
238
239
0
    case OVSDB_TYPE_INTEGER:
240
0
        return a->integer < b->integer ? -1 : a->integer > b->integer;
241
242
0
    case OVSDB_TYPE_REAL:
243
0
        return a->real < b->real ? -1 : a->real > b->real;
244
245
0
    case OVSDB_TYPE_BOOLEAN:
246
0
        return a->boolean - b->boolean;
247
248
0
    case OVSDB_TYPE_STRING:
249
0
        return a->s == b->s ? 0 : strcmp(json_string(a->s), json_string(b->s));
250
251
0
    case OVSDB_TYPE_UUID:
252
0
        return uuid_compare_3way(&a->uuid, &b->uuid);
253
254
0
    case OVSDB_N_TYPES:
255
0
    default:
256
0
        OVS_NOT_REACHED();
257
0
    }
258
0
}
259
260
static struct ovsdb_error *
261
unwrap_json(const struct json *json, const char *name,
262
            enum json_type value_type, const struct json **value)
263
0
{
264
0
    if (json->type != JSON_ARRAY
265
0
        || json->array.n != 2
266
0
        || json->array.elems[0]->type != JSON_STRING
267
0
        || (name && strcmp(json->array.elems[0]->string, name))
268
0
        || json->array.elems[1]->type != value_type)
269
0
    {
270
0
        *value = NULL;
271
0
        return ovsdb_syntax_error(json, NULL, "expected [\"%s\", <%s>]", name,
272
0
                                  json_type_to_string(value_type));
273
0
    }
274
0
    *value = json->array.elems[1];
275
0
    return NULL;
276
0
}
277
278
static struct ovsdb_error *
279
parse_json_pair(const struct json *json,
280
                const struct json **elem0, const struct json **elem1)
281
0
{
282
0
    if (json->type != JSON_ARRAY || json->array.n != 2) {
283
0
        return ovsdb_syntax_error(json, NULL, "expected 2-element array");
284
0
    }
285
0
    *elem0 = json->array.elems[0];
286
0
    *elem1 = json->array.elems[1];
287
0
    return NULL;
288
0
}
289
290
static void
291
ovsdb_symbol_referenced(struct ovsdb_symbol *symbol,
292
                        const struct ovsdb_base_type *base)
293
0
{
294
0
    ovs_assert(base->type == OVSDB_TYPE_UUID);
295
296
0
    if (base->uuid.refTableName) {
297
0
        switch (base->uuid.refType) {
298
0
        case OVSDB_REF_STRONG:
299
0
            symbol->strong_ref = true;
300
0
            break;
301
0
        case OVSDB_REF_WEAK:
302
0
            symbol->weak_ref = true;
303
0
            break;
304
0
        }
305
0
    }
306
0
}
307
308
static union ovsdb_atom *
309
alloc_default_atoms(enum ovsdb_atomic_type type, size_t n)
310
0
{
311
0
    if (type != OVSDB_TYPE_VOID && n) {
312
0
        union ovsdb_atom *atoms;
313
0
        unsigned int i;
314
315
0
        atoms = xmalloc(n * sizeof *atoms);
316
0
        for (i = 0; i < n; i++) {
317
0
            ovsdb_atom_init_default(&atoms[i], type);
318
0
        }
319
0
        return atoms;
320
0
    } else {
321
        /* Avoid wasting memory in the n == 0 case, because xmalloc(0) is
322
         * treated as xmalloc(1). */
323
0
        return NULL;
324
0
    }
325
0
}
326
327
static struct ovsdb_error * OVS_WARN_UNUSED_RESULT
328
ovsdb_atom_parse_uuid(struct uuid *uuid, const struct json *json,
329
                      struct ovsdb_symbol_table *symtab,
330
                      const struct ovsdb_base_type *base)
331
0
{
332
0
    struct ovsdb_error *error0;
333
0
    const struct json *value;
334
335
0
    error0 = unwrap_json(json, "uuid", JSON_STRING, &value);
336
0
    if (!error0) {
337
0
        const char *uuid_string = json_string(value);
338
0
        if (!uuid_from_string(uuid, uuid_string)) {
339
0
            return ovsdb_syntax_error(json, NULL, "\"%s\" is not a valid UUID",
340
0
                                      uuid_string);
341
0
        }
342
0
    } else if (symtab) {
343
0
        struct ovsdb_error *error1;
344
345
0
        error1 = unwrap_json(json, "named-uuid", JSON_STRING, &value);
346
0
        if (!error1) {
347
0
            struct ovsdb_symbol *symbol;
348
349
0
            ovsdb_error_destroy(error0);
350
0
            if (!ovsdb_parser_is_id(json_string(value))) {
351
0
                return ovsdb_syntax_error(json, NULL, "named-uuid string is "
352
0
                                          "not a valid <id>");
353
0
            }
354
355
0
            symbol = ovsdb_symbol_table_insert(symtab, json_string(value));
356
0
            *uuid = symbol->uuid;
357
0
            ovsdb_symbol_referenced(symbol, base);
358
0
            return NULL;
359
0
        }
360
0
        ovsdb_error_destroy(error1);
361
0
    }
362
363
0
    return error0;
364
0
}
365
366
static struct ovsdb_error * OVS_WARN_UNUSED_RESULT
367
ovsdb_atom_from_json__(union ovsdb_atom *atom,
368
                       const struct ovsdb_base_type *base,
369
                       const struct json *json,
370
                       struct ovsdb_symbol_table *symtab)
371
0
{
372
0
    enum ovsdb_atomic_type type = base->type;
373
374
0
    switch (type) {
375
0
    case OVSDB_TYPE_VOID:
376
0
        OVS_NOT_REACHED();
377
378
0
    case OVSDB_TYPE_INTEGER:
379
0
        if (json->type == JSON_INTEGER) {
380
0
            atom->integer = json->integer;
381
0
            return NULL;
382
0
        }
383
0
        break;
384
385
0
    case OVSDB_TYPE_REAL:
386
0
        if (json->type == JSON_INTEGER) {
387
0
            atom->real = json->integer;
388
0
            return NULL;
389
0
        } else if (json->type == JSON_REAL) {
390
0
            atom->real = json->real;
391
0
            return NULL;
392
0
        }
393
0
        break;
394
395
0
    case OVSDB_TYPE_BOOLEAN:
396
0
        if (json->type == JSON_TRUE) {
397
0
            atom->boolean = true;
398
0
            return NULL;
399
0
        } else if (json->type == JSON_FALSE) {
400
0
            atom->boolean = false;
401
0
            return NULL;
402
0
        }
403
0
        break;
404
405
0
    case OVSDB_TYPE_STRING:
406
0
        if (json->type == JSON_STRING) {
407
0
            atom->s = json_clone(json);
408
0
            return NULL;
409
0
        }
410
0
        break;
411
412
0
    case OVSDB_TYPE_UUID:
413
0
        return ovsdb_atom_parse_uuid(&atom->uuid, json, symtab, base);
414
415
0
    case OVSDB_N_TYPES:
416
0
    default:
417
0
        OVS_NOT_REACHED();
418
0
    }
419
420
0
    return ovsdb_syntax_error(json, NULL, "expected %s",
421
0
                              ovsdb_atomic_type_to_string(type));
422
0
}
423
424
/* Parses 'json' as an atom of the type described by 'base'.  If successful,
425
 * returns NULL and initializes 'atom' with the parsed atom.  On failure,
426
 * returns an error and the contents of 'atom' are indeterminate.  The caller
427
 * is responsible for freeing the error or the atom that is returned.
428
 *
429
 * Violations of constraints expressed by 'base' are treated as errors.
430
 *
431
 * If 'symtab' is nonnull, then named UUIDs in 'symtab' are accepted.  Refer to
432
 * RFC 7047 for information about this, and for the syntax that this function
433
 * accepts.  If 'base' is a reference and a symbol is parsed, then the symbol's
434
 * 'strong_ref' or 'weak_ref' member is set to true, as appropriate. */
435
struct ovsdb_error *
436
ovsdb_atom_from_json(union ovsdb_atom *atom,
437
                     const struct ovsdb_base_type *base,
438
                     const struct json *json,
439
                     struct ovsdb_symbol_table *symtab)
440
0
{
441
0
    struct ovsdb_error *error;
442
443
0
    error = ovsdb_atom_from_json__(atom, base, json, symtab);
444
0
    if (error) {
445
0
        return error;
446
0
    }
447
448
0
    error = ovsdb_atom_check_constraints(atom, base);
449
0
    if (error) {
450
0
        ovsdb_atom_destroy(atom, base->type);
451
0
    }
452
0
    return error;
453
0
}
454
455
/* Converts 'atom', of the specified 'type', to JSON format, and returns the
456
 * JSON.  The caller is responsible for freeing the returned JSON.
457
 *
458
 * If 'allow_shallow_copies' is false, deep copy of the string JSON object
459
 * will be used.  Useful when the same string object is accessed by multiple
460
 * threads as deep copy will not change the reference counter of the original
461
 * JSON string.
462
 *
463
 * Refer to RFC 7047 for the format of the JSON that this function produces. */
464
static struct json *
465
ovsdb_atom_to_json__(const union ovsdb_atom *atom, enum ovsdb_atomic_type type,
466
                     bool allow_shallow_copies)
467
0
{
468
0
    switch (type) {
469
0
    case OVSDB_TYPE_VOID:
470
0
        OVS_NOT_REACHED();
471
472
0
    case OVSDB_TYPE_INTEGER:
473
0
        return json_integer_create(atom->integer);
474
475
0
    case OVSDB_TYPE_REAL:
476
0
        return json_real_create(atom->real);
477
478
0
    case OVSDB_TYPE_BOOLEAN:
479
0
        return json_boolean_create(atom->boolean);
480
481
0
    case OVSDB_TYPE_STRING:
482
0
        return allow_shallow_copies ? json_clone(atom->s)
483
0
                                    : json_deep_clone(atom->s);
484
485
0
    case OVSDB_TYPE_UUID:
486
0
        return wrap_json("uuid", json_string_create_nocopy(
487
0
                             xasprintf(UUID_FMT, UUID_ARGS(&atom->uuid))));
488
489
0
    case OVSDB_N_TYPES:
490
0
    default:
491
0
        OVS_NOT_REACHED();
492
0
    }
493
0
}
494
495
struct json *
496
ovsdb_atom_to_json(const union ovsdb_atom *atom, enum ovsdb_atomic_type type)
497
0
{
498
0
    return ovsdb_atom_to_json__(atom, type, true);
499
0
}
500
501
static struct json *
502
ovsdb_atom_to_json_deep(const union ovsdb_atom *atom,
503
                        enum ovsdb_atomic_type type)
504
0
{
505
0
    return ovsdb_atom_to_json__(atom, type, false);
506
0
}
507
508
static char *
509
ovsdb_atom_from_string__(union ovsdb_atom *atom,
510
                         union ovsdb_atom **range_end_atom,
511
                         const struct ovsdb_base_type *base, const char *s,
512
                         struct ovsdb_symbol_table *symtab)
513
0
{
514
0
    enum ovsdb_atomic_type type = base->type;
515
516
0
    switch (type) {
517
0
    case OVSDB_TYPE_VOID:
518
0
        OVS_NOT_REACHED();
519
520
0
    case OVSDB_TYPE_INTEGER: {
521
0
        long long int integer, end;
522
0
        if (range_end_atom
523
0
            && str_to_llong_range(s, 10, &integer, &end)) {
524
0
            if (end < integer) {
525
0
                return xasprintf("\"%s\" is not a valid range. "
526
0
                    "Range end cannot be before start.", s);
527
0
            }
528
0
            *range_end_atom = alloc_default_atoms(type, 1);
529
0
            if (!(*range_end_atom)) {
530
0
                return xasprintf("\"%s\" is not a valid range", s);
531
0
            }
532
0
            (*range_end_atom)->integer = end;
533
0
        } else if (!str_to_llong(s, 10, &integer)) {
534
0
            return xasprintf("\"%s\" is not a valid integer or range", s);
535
0
        }
536
0
        atom->integer = integer;
537
0
    }
538
0
        break;
539
540
0
    case OVSDB_TYPE_REAL:
541
0
        if (!str_to_double(s, &atom->real)) {
542
0
            return xasprintf("\"%s\" is not a valid real number", s);
543
0
        }
544
        /* Our JSON input routines map negative zero to zero, so do that here
545
         * too for consistency. */
546
0
        if (atom->real == 0.0) {
547
0
            atom->real = 0.0;
548
0
        }
549
0
        break;
550
551
0
    case OVSDB_TYPE_BOOLEAN:
552
0
        if (!strcmp(s, "true") || !strcmp(s, "yes") || !strcmp(s, "on")
553
0
            || !strcmp(s, "1")) {
554
0
            atom->boolean = true;
555
0
        } else if (!strcmp(s, "false") || !strcmp(s, "no") || !strcmp(s, "off")
556
0
                   || !strcmp(s, "0")) {
557
0
            atom->boolean = false;
558
0
        } else {
559
0
            return xasprintf("\"%s\" is not a valid boolean "
560
0
                             "(use \"true\" or \"false\")", s);
561
0
        }
562
0
        break;
563
564
0
    case OVSDB_TYPE_STRING:
565
0
        if (*s == '\0') {
566
0
            return xstrdup("An empty string is not valid as input; "
567
0
                           "use \"\" to represent the empty string");
568
0
        } else if (*s == '"') {
569
0
            size_t s_len = strlen(s);
570
571
0
            if (s_len < 2 || s[s_len - 1] != '"') {
572
0
                return xasprintf("%s: missing quote at end of "
573
0
                                 "quoted string", s);
574
0
            } else {
575
0
                char *res;
576
0
                if (json_string_unescape(s + 1, s_len - 2, &res)) {
577
0
                    atom->s = ovsdb_atom_string_create_nocopy(res);
578
0
                } else {
579
0
                    char *error = xasprintf("%s: %s", s, res);
580
0
                    free(res);
581
0
                    return error;
582
0
                }
583
0
            }
584
0
        } else {
585
0
            atom->s = ovsdb_atom_string_create(s);
586
0
        }
587
0
        break;
588
589
0
    case OVSDB_TYPE_UUID:
590
0
        if (*s == '@') {
591
0
            struct ovsdb_symbol *symbol = ovsdb_symbol_table_insert(symtab, s);
592
0
            atom->uuid = symbol->uuid;
593
0
            ovsdb_symbol_referenced(symbol, base);
594
0
        } else if (!uuid_from_string(&atom->uuid, s)) {
595
0
            return xasprintf("\"%s\" is not a valid UUID", s);
596
0
        }
597
0
        break;
598
599
0
    case OVSDB_N_TYPES:
600
0
    default:
601
0
        OVS_NOT_REACHED();
602
0
    }
603
604
0
    return NULL;
605
0
}
606
607
/* Initializes 'atom' and optionally 'range_end_atom' to a value of type 'base'
608
 * parsed from 's', which takes one of the following forms:
609
 *
610
 *      - OVSDB_TYPE_INTEGER: A decimal integer optionally preceded by a sign
611
 *        or two decimal integers optionally preceded by a sign and separated
612
 *        by a hyphen, representing inclusive range of integers
613
 *        ['atom', 'range_end_atom'].
614
 *
615
 *      - OVSDB_TYPE_REAL: A floating-point number in the format accepted by
616
 *        strtod().
617
 *
618
 *      - OVSDB_TYPE_BOOLEAN: "true", "yes", "on", "1" for true, or "false",
619
 *        "no", "off", or "0" for false.
620
 *
621
 *      - OVSDB_TYPE_STRING: A JSON string if it begins with a quote, otherwise
622
 *        an arbitrary string.
623
 *
624
 *      - OVSDB_TYPE_UUID: A UUID in RFC 4122 format.  If 'symtab' is nonnull,
625
 *        then an identifier beginning with '@' is also acceptable.  If the
626
 *        named identifier is already in 'symtab', then the associated UUID is
627
 *        used; otherwise, a new, random UUID is used and added to the symbol
628
 *        table.  If 'base' is a reference and a symbol is parsed, then the
629
 *        symbol's 'strong_ref' or 'weak_ref' member is set to true, as
630
 *        appropriate.
631
 *
632
 * Returns a null pointer if successful, otherwise an error message describing
633
 * the problem.  On failure, the contents of 'atom' are indeterminate.  The
634
 * caller is responsible for freeing the atom or the error.
635
 *
636
 * Does not attempt to parse range if 'range_end_atom' is a null pointer.
637
 * Dynamically allocates ovdsb_atom and stores its address in '*range_end_atom'
638
 * if successfully parses range. Caller is responsible for deallocating
639
 * the memory by calling 'ovsdb_atom_destroy' and then 'free' on the address.
640
 * Does not allocate memory and sets '*range_end_atom' to a null pointer
641
 * if does not parse a range or fails for any reason.
642
 */
643
char *
644
ovsdb_atom_from_string(union ovsdb_atom *atom,
645
                       union ovsdb_atom **range_end_atom,
646
                       const struct ovsdb_base_type *base, const char *s,
647
                       struct ovsdb_symbol_table *symtab)
648
0
{
649
0
    struct ovsdb_error *error;
650
0
    char *msg;
651
652
0
    if (range_end_atom) {
653
0
        *range_end_atom = NULL;
654
0
    }
655
656
0
    msg = ovsdb_atom_from_string__(atom, range_end_atom, base, s, symtab);
657
0
    if (msg) {
658
0
        return msg;
659
0
    }
660
661
0
    error = ovsdb_atom_check_constraints(atom, base);
662
663
0
    if (!error && range_end_atom && *range_end_atom) {
664
        /* Check range constraints */
665
0
        int64_t start = atom->integer;
666
0
        int64_t end = (*range_end_atom)->integer;
667
0
        if (base->enum_) {
668
0
            for (int64_t i = start + 1; i <= end; i++) {
669
0
                union ovsdb_atom ai = { .integer = i };
670
0
                error = ovsdb_atom_check_constraints(&ai, base);
671
0
                if (error) {
672
0
                    break;
673
0
                }
674
0
            }
675
0
        } else {
676
0
            error = ovsdb_atom_check_constraints(*range_end_atom, base);
677
0
        }
678
679
0
        if (!error) {
680
0
            error = ovsdb_atom_range_check_size(start, end);
681
0
        }
682
0
    }
683
684
0
    if (error) {
685
0
        ovsdb_atom_destroy(atom, base->type);
686
0
        if (range_end_atom && *range_end_atom) {
687
0
            ovsdb_atom_destroy(*range_end_atom, base->type);
688
0
            free(*range_end_atom);
689
0
            *range_end_atom = NULL;
690
0
        }
691
0
        msg = ovsdb_error_to_string_free(error);
692
0
    }
693
0
    return msg;
694
0
}
695
696
static bool
697
string_needs_quotes(const char *s)
698
0
{
699
0
    const char *p = s;
700
0
    unsigned char c;
701
0
    struct uuid uuid;
702
703
0
    c = *p++;
704
0
    if (!isalpha(c) && c != '_') {
705
0
        return true;
706
0
    }
707
708
0
    while ((c = *p++) != '\0') {
709
0
        if (!isalpha(c) && !isdigit(c) && c != '_' && c != '-' && c != '.') {
710
0
            return true;
711
0
        }
712
0
    }
713
714
0
    if (!strcmp(s, "true") || !strcmp(s, "false")) {
715
0
        return true;
716
0
    }
717
718
0
    if (uuid_from_string(&uuid, s)) {
719
0
        return true;
720
0
    }
721
722
0
    return false;
723
0
}
724
725
/* Appends 'atom' (which has the given 'type') to 'out', in a format acceptable
726
 * to ovsdb_atom_from_string().  */
727
void
728
ovsdb_atom_to_string(const union ovsdb_atom *atom, enum ovsdb_atomic_type type,
729
                     struct ds *out)
730
0
{
731
0
    switch (type) {
732
0
    case OVSDB_TYPE_VOID:
733
0
        OVS_NOT_REACHED();
734
735
0
    case OVSDB_TYPE_INTEGER:
736
0
        ds_put_format(out, "%"PRId64, atom->integer);
737
0
        break;
738
739
0
    case OVSDB_TYPE_REAL:
740
0
        ds_put_format(out, "%.*g", DBL_DIG, atom->real);
741
0
        break;
742
743
0
    case OVSDB_TYPE_BOOLEAN:
744
0
        ds_put_cstr(out, atom->boolean ? "true" : "false");
745
0
        break;
746
747
0
    case OVSDB_TYPE_STRING:
748
0
        if (string_needs_quotes(json_string(atom->s))) {
749
0
            json_to_ds(atom->s, 0, out);
750
0
        } else {
751
0
            ds_put_cstr(out, json_string(atom->s));
752
0
        }
753
0
        break;
754
755
0
    case OVSDB_TYPE_UUID:
756
0
        ds_put_format(out, UUID_FMT, UUID_ARGS(&atom->uuid));
757
0
        break;
758
759
0
    case OVSDB_N_TYPES:
760
0
    default:
761
0
        OVS_NOT_REACHED();
762
0
    }
763
0
}
764
765
/* Appends 'atom' (which has the given 'type') to 'out', in a bare string
766
 * format that cannot be parsed uniformly back into a datum but is easier for
767
 * shell scripts, etc., to deal with. */
768
void
769
ovsdb_atom_to_bare(const union ovsdb_atom *atom, enum ovsdb_atomic_type type,
770
                   struct ds *out)
771
0
{
772
0
    if (type == OVSDB_TYPE_STRING) {
773
0
        ds_put_cstr(out, json_string(atom->s));
774
0
    } else {
775
0
        ovsdb_atom_to_string(atom, type, out);
776
0
    }
777
0
}
778
779
static struct ovsdb_error *
780
check_string_constraints(const char *s,
781
                         const struct ovsdb_string_constraints *c)
782
0
{
783
0
    size_t n_chars;
784
0
    char *msg;
785
786
0
    msg = utf8_validate(s, &n_chars);
787
0
    if (msg) {
788
0
        struct ovsdb_error *error;
789
790
0
        error = ovsdb_error("constraint violation",
791
0
                            "not a valid UTF-8 string: %s", msg);
792
0
        free(msg);
793
0
        return error;
794
0
    }
795
796
0
    if (n_chars < c->minLen) {
797
0
        return ovsdb_error(
798
0
            "constraint violation",
799
0
            "\"%s\" length %"PRIuSIZE" is less than minimum allowed "
800
0
            "length %u", s, n_chars, c->minLen);
801
0
    } else if (n_chars > c->maxLen) {
802
0
        return ovsdb_error(
803
0
            "constraint violation",
804
0
            "\"%s\" length %"PRIuSIZE" is greater than maximum allowed "
805
0
            "length %u", s, n_chars, c->maxLen);
806
0
    }
807
808
0
    return NULL;
809
0
}
810
811
/* Checks whether 'atom' meets the constraints (if any) defined in 'base'.
812
 * (base->type must specify 'atom''s type.)  Returns a null pointer if the
813
 * constraints are met, otherwise an error that explains the violation.
814
 *
815
 * Checking UUID constraints is deferred to transaction commit time, so this
816
 * function does nothing for UUID constraints. */
817
struct ovsdb_error *
818
ovsdb_atom_check_constraints(const union ovsdb_atom *atom,
819
                             const struct ovsdb_base_type *base)
820
0
{
821
0
    if (base->enum_
822
0
        && !ovsdb_datum_find_key(base->enum_, atom, base->type, NULL)) {
823
0
        struct ovsdb_error *error;
824
0
        struct ds actual = DS_EMPTY_INITIALIZER;
825
0
        struct ds valid = DS_EMPTY_INITIALIZER;
826
827
0
        ovsdb_atom_to_string(atom, base->type, &actual);
828
0
        ovsdb_datum_to_string(base->enum_,
829
0
                              ovsdb_base_type_get_enum_type(base->type),
830
0
                              &valid);
831
0
        error = ovsdb_error("constraint violation",
832
0
                            "%s is not one of the allowed values (%s)",
833
0
                            ds_cstr(&actual), ds_cstr(&valid));
834
0
        ds_destroy(&actual);
835
0
        ds_destroy(&valid);
836
837
0
        return error;
838
0
    }
839
840
0
    switch (base->type) {
841
0
    case OVSDB_TYPE_VOID:
842
0
        OVS_NOT_REACHED();
843
844
0
    case OVSDB_TYPE_INTEGER:
845
0
        if (atom->integer >= base->integer.min
846
0
            && atom->integer <= base->integer.max) {
847
0
            return NULL;
848
0
        } else if (base->integer.min != INT64_MIN) {
849
0
            if (base->integer.max != INT64_MAX) {
850
0
                return ovsdb_error("constraint violation",
851
0
                                   "%"PRId64" is not in the valid range "
852
0
                                   "%"PRId64" to %"PRId64" (inclusive)",
853
0
                                   atom->integer,
854
0
                                   base->integer.min, base->integer.max);
855
0
            } else {
856
0
                return ovsdb_error("constraint violation",
857
0
                                   "%"PRId64" is less than minimum allowed "
858
0
                                   "value %"PRId64,
859
0
                                   atom->integer, base->integer.min);
860
0
            }
861
0
        } else {
862
0
            return ovsdb_error("constraint violation",
863
0
                               "%"PRId64" is greater than maximum allowed "
864
0
                               "value %"PRId64,
865
0
                               atom->integer, base->integer.max);
866
0
        }
867
0
        OVS_NOT_REACHED();
868
869
0
    case OVSDB_TYPE_REAL:
870
0
        if (atom->real >= base->real.min && atom->real <= base->real.max) {
871
0
            return NULL;
872
0
        } else if (base->real.min != -DBL_MAX) {
873
0
            if (base->real.max != DBL_MAX) {
874
0
                return ovsdb_error("constraint violation",
875
0
                                   "%.*g is not in the valid range "
876
0
                                   "%.*g to %.*g (inclusive)",
877
0
                                   DBL_DIG, atom->real,
878
0
                                   DBL_DIG, base->real.min,
879
0
                                   DBL_DIG, base->real.max);
880
0
            } else {
881
0
                return ovsdb_error("constraint violation",
882
0
                                   "%.*g is less than minimum allowed "
883
0
                                   "value %.*g",
884
0
                                   DBL_DIG, atom->real,
885
0
                                   DBL_DIG, base->real.min);
886
0
            }
887
0
        } else {
888
0
            return ovsdb_error("constraint violation",
889
0
                               "%.*g is greater than maximum allowed "
890
0
                               "value %.*g",
891
0
                               DBL_DIG, atom->real,
892
0
                               DBL_DIG, base->real.max);
893
0
        }
894
0
        OVS_NOT_REACHED();
895
896
0
    case OVSDB_TYPE_BOOLEAN:
897
0
        return NULL;
898
899
0
    case OVSDB_TYPE_STRING:
900
0
        return check_string_constraints(json_string(atom->s), &base->string);
901
902
0
    case OVSDB_TYPE_UUID:
903
0
        return NULL;
904
905
0
    case OVSDB_N_TYPES:
906
0
    default:
907
0
        OVS_NOT_REACHED();
908
0
    }
909
0
}
910

911
/* Initializes 'datum' as an empty datum.  (An empty datum can be treated as
912
 * any type.) */
913
void
914
ovsdb_datum_init_empty(struct ovsdb_datum *datum)
915
0
{
916
0
    datum->n = 0;
917
0
    datum->keys = NULL;
918
0
    datum->values = NULL;
919
0
    datum->refcnt = NULL;
920
0
}
921
922
/* Initializes 'datum' as a datum that has the default value for 'type'.
923
 *
924
 * The default value for a particular type is as defined in RFC 7047:
925
 *
926
 *    - If n_min is 0, then the default value is the empty set (or map).
927
 *
928
 *    - If n_min is 1, the default value is a single value or a single
929
 *      key-value pair, whose key and value are the defaults for their
930
 *      atomic types.  (See ovsdb_atom_init_default() for details.)
931
 *
932
 *    - n_min > 1 is invalid.  See ovsdb_type_is_valid().
933
 */
934
void
935
ovsdb_datum_init_default(struct ovsdb_datum *datum,
936
                         const struct ovsdb_type *type)
937
0
{
938
0
    datum->n = type->n_min;
939
0
    datum->keys = alloc_default_atoms(type->key.type, datum->n);
940
0
    datum->values = alloc_default_atoms(type->value.type, datum->n);
941
0
    datum->refcnt = NULL;
942
0
}
943
944
/* Returns a read-only datum of the given 'type' that has the default value for
945
 * 'type'.  The caller must not modify or free the returned datum.
946
 *
947
 * See ovsdb_datum_init_default() for an explanation of the default value of a
948
 * datum. */
949
const struct ovsdb_datum *
950
ovsdb_datum_default(const struct ovsdb_type *type)
951
0
{
952
0
    if (type->n_min == 0) {
953
0
        static unsigned int refcnt = 1;
954
0
        static const struct ovsdb_datum empty = { .refcnt = &refcnt };
955
0
        return &empty;
956
0
    } else if (type->n_min == 1) {
957
0
        static struct ovsdb_datum default_data[OVSDB_N_TYPES][OVSDB_N_TYPES];
958
0
        static unsigned int refcnt[OVSDB_N_TYPES][OVSDB_N_TYPES];
959
0
        struct ovsdb_datum *d;
960
0
        int kt = type->key.type;
961
0
        int vt = type->value.type;
962
963
0
        ovs_assert(ovsdb_type_is_valid(type));
964
965
0
        d = &default_data[kt][vt];
966
0
        if (!d->n) {
967
0
            d->n = 1;
968
0
            d->keys = CONST_CAST(union ovsdb_atom *, ovsdb_atom_default(kt));
969
0
            if (vt != OVSDB_TYPE_VOID) {
970
0
                d->values = CONST_CAST(union ovsdb_atom *,
971
0
                                       ovsdb_atom_default(vt));
972
0
            }
973
0
            d->refcnt = &refcnt[kt][vt];
974
0
            *d->refcnt = 1;
975
0
        }
976
0
        return d;
977
0
    } else {
978
0
        OVS_NOT_REACHED();
979
0
    }
980
0
}
981
982
/* Returns true if 'datum', which must have the given 'type', has the default
983
 * value for that type.
984
 *
985
 * See ovsdb_datum_init_default() for an explanation of the default value of a
986
 * datum. */
987
bool
988
ovsdb_datum_is_default(const struct ovsdb_datum *datum,
989
                       const struct ovsdb_type *type)
990
0
{
991
0
    size_t i;
992
993
0
    if (datum->n != type->n_min) {
994
0
        return false;
995
0
    }
996
0
    for (i = 0; i < datum->n; i++) {
997
0
        if (!ovsdb_atom_is_default(&datum->keys[i], type->key.type)) {
998
0
            return false;
999
0
        }
1000
0
        if (type->value.type != OVSDB_TYPE_VOID
1001
0
            && !ovsdb_atom_is_default(&datum->values[i], type->value.type)) {
1002
0
            return false;
1003
0
        }
1004
0
    }
1005
1006
0
    return true;
1007
0
}
1008
1009
static union ovsdb_atom *
1010
clone_atoms(const union ovsdb_atom *old, enum ovsdb_atomic_type type, size_t n)
1011
0
{
1012
0
    if (type != OVSDB_TYPE_VOID && n) {
1013
0
        union ovsdb_atom *new;
1014
0
        unsigned int i;
1015
1016
0
        new = xmalloc(n * sizeof *new);
1017
0
        for (i = 0; i < n; i++) {
1018
0
            ovsdb_atom_clone(&new[i], &old[i], type);
1019
0
        }
1020
0
        return new;
1021
0
    } else {
1022
        /* Avoid wasting memory in the n == 0 case, because xmalloc(0) is
1023
         * treated as xmalloc(1). */
1024
0
        return NULL;
1025
0
    }
1026
0
}
1027
1028
/* Initializes 'new' as a shallow copy of 'old_'.
1029
 *
1030
 * The caller must eventually arrange for 'new' to be destroyed (with
1031
 * ovsdb_datum_destroy()).  The caller must call ovsdb_datum_unshare()
1032
 * before attempting direct modifications of the 'new' or 'old_', i.e.
1033
 * modifications outside of the ovsdb_datum_* API. */
1034
void
1035
ovsdb_datum_clone(struct ovsdb_datum *new, const struct ovsdb_datum *old_)
1036
0
{
1037
0
    struct ovsdb_datum *old = CONST_CAST(struct ovsdb_datum *, old_);
1038
1039
0
    if (!old->refcnt) {
1040
0
        old->refcnt = xmalloc(sizeof *old->refcnt);
1041
0
        *old->refcnt = 1;
1042
0
    }
1043
0
    memcpy(new, old, sizeof *new);
1044
0
    (*new->refcnt)++;
1045
0
}
1046
1047
static void
1048
free_data(enum ovsdb_atomic_type type,
1049
          union ovsdb_atom *atoms, size_t n_atoms)
1050
0
{
1051
0
    if (!atoms) {
1052
0
        return;
1053
0
    }
1054
1055
0
    if (ovsdb_atom_needs_destruction(type)) {
1056
0
        unsigned int i;
1057
0
        for (i = 0; i < n_atoms; i++) {
1058
0
            ovsdb_atom_destroy(&atoms[i], type);
1059
0
        }
1060
0
    }
1061
0
    free(atoms);
1062
0
}
1063
1064
/* Frees the data owned by 'datum', which must have the given 'type'.
1065
 *
1066
 * This does not actually call free(datum).  If necessary, the caller must be
1067
 * responsible for that. */
1068
void
1069
ovsdb_datum_destroy(struct ovsdb_datum *datum, const struct ovsdb_type *type)
1070
0
{
1071
0
    if (!datum->refcnt || !--(*datum->refcnt)) {
1072
0
        free_data(type->key.type, datum->keys, datum->n);
1073
0
        free_data(type->value.type, datum->values, datum->n);
1074
0
        free(datum->refcnt);
1075
0
    }
1076
0
}
1077
1078
/* This function should be called before attempting direct modifications
1079
 * of the 'datum', i.e. modifications outside of the ovsdb_datum_* API. */
1080
void
1081
ovsdb_datum_unshare(struct ovsdb_datum *datum, const struct ovsdb_type *type)
1082
0
{
1083
0
    if (!datum->refcnt || *datum->refcnt == 1) {
1084
0
        return;
1085
0
    }
1086
0
    datum->keys = clone_atoms(datum->keys, type->key.type, datum->n);
1087
0
    datum->values = clone_atoms(datum->values, type->value.type, datum->n);
1088
0
    (*datum->refcnt)--;
1089
0
    datum->refcnt = NULL;
1090
0
}
1091
1092
/* Swaps the contents of 'a' and 'b', which need not have the same type. */
1093
void
1094
ovsdb_datum_swap(struct ovsdb_datum *a, struct ovsdb_datum *b)
1095
0
{
1096
0
    struct ovsdb_datum tmp = *a;
1097
0
    *a = *b;
1098
0
    *b = tmp;
1099
0
}
1100
1101
struct ovsdb_datum_sort_cbdata {
1102
    enum ovsdb_atomic_type key_type;
1103
    enum ovsdb_atomic_type value_type;
1104
    struct ovsdb_datum *datum;
1105
};
1106
1107
static int
1108
ovsdb_datum_sort_compare_cb(size_t a, size_t b, void *cbdata_)
1109
0
{
1110
0
    struct ovsdb_datum_sort_cbdata *cbdata = cbdata_;
1111
0
    int retval;
1112
1113
0
    retval = ovsdb_atom_compare_3way(&cbdata->datum->keys[a],
1114
0
                                     &cbdata->datum->keys[b],
1115
0
                                     cbdata->key_type);
1116
0
    if (retval || cbdata->value_type == OVSDB_TYPE_VOID) {
1117
0
        return retval;
1118
0
    }
1119
1120
0
    return ovsdb_atom_compare_3way(&cbdata->datum->values[a],
1121
0
                                   &cbdata->datum->values[b],
1122
0
                                   cbdata->value_type);
1123
0
}
1124
1125
static void
1126
ovsdb_datum_sort_swap_cb(size_t a, size_t b, void *cbdata_)
1127
0
{
1128
0
    struct ovsdb_datum_sort_cbdata *cbdata = cbdata_;
1129
1130
0
    ovsdb_atom_swap(&cbdata->datum->keys[a], &cbdata->datum->keys[b]);
1131
0
    if (cbdata->datum->values) {
1132
0
        ovsdb_atom_swap(&cbdata->datum->values[a], &cbdata->datum->values[b]);
1133
0
    }
1134
0
}
1135
1136
static void
1137
ovsdb_datum_sort__(struct ovsdb_datum *datum, enum ovsdb_atomic_type key_type,
1138
                   enum ovsdb_atomic_type value_type)
1139
0
{
1140
0
    struct ovsdb_datum_sort_cbdata cbdata;
1141
1142
0
    cbdata.key_type = key_type;
1143
0
    cbdata.value_type = value_type;
1144
0
    cbdata.datum = datum;
1145
0
    sort(datum->n, ovsdb_datum_sort_compare_cb, ovsdb_datum_sort_swap_cb,
1146
0
         &cbdata);
1147
0
}
1148
1149
/* The keys in an ovsdb_datum must be unique and in sorted order.  Most
1150
 * functions that modify an ovsdb_datum maintain these invariants.  For those
1151
 * that don't, this function checks and restores these invariants for 'datum',
1152
 * whose keys are of type 'key_type'.
1153
 *
1154
 * This function returns NULL if successful, otherwise an error message.  The
1155
 * caller must free the returned error when it is no longer needed.  On error,
1156
 * 'datum' is sorted but not unique. */
1157
struct ovsdb_error *
1158
ovsdb_datum_sort(struct ovsdb_datum *datum, const struct ovsdb_type *type)
1159
0
{
1160
0
    size_t i;
1161
1162
0
    if (datum->n < 2) {
1163
0
        return NULL;
1164
0
    }
1165
1166
0
    ovsdb_datum_unshare(datum, type);
1167
1168
0
    ovsdb_datum_sort__(datum, type->key.type, OVSDB_TYPE_VOID);
1169
1170
0
    for (i = 0; i < datum->n - 1; i++) {
1171
0
        if (ovsdb_atom_equals(&datum->keys[i], &datum->keys[i + 1],
1172
0
                              type->key.type)) {
1173
0
            if (datum->values) {
1174
0
                return ovsdb_error(NULL, "map contains duplicate key");
1175
0
            } else {
1176
0
                return ovsdb_error(NULL, "set contains duplicate");
1177
0
            }
1178
0
        }
1179
0
    }
1180
0
    return NULL;
1181
0
}
1182
1183
/* This function is the same as ovsdb_datum_sort(), except that the caller
1184
 * knows that 'datum' is unique.  The operation therefore "cannot fail", so
1185
 * this function assert-fails if it actually does. */
1186
void
1187
ovsdb_datum_sort_assert(struct ovsdb_datum *datum,
1188
                        const struct ovsdb_type *type)
1189
0
{
1190
0
    struct ovsdb_error *error = ovsdb_datum_sort(datum, type);
1191
0
    if (error) {
1192
0
        OVS_NOT_REACHED();
1193
0
    }
1194
0
}
1195
1196
/* This is similar to ovsdb_datum_sort(), except that it drops duplicate keys
1197
 * instead of reporting an error.  In a map type, the smallest value among a
1198
 * group of duplicate pairs is retained and the others are dropped.
1199
 *
1200
 * Returns the number of keys (or pairs) that were dropped. */
1201
size_t
1202
ovsdb_datum_sort_unique(struct ovsdb_datum *datum,
1203
                        const struct ovsdb_type *type)
1204
0
{
1205
0
    size_t src, dst;
1206
1207
0
    if (datum->n < 2) {
1208
0
        return 0;
1209
0
    }
1210
1211
0
    ovsdb_datum_unshare(datum, type);
1212
0
    ovsdb_datum_sort__(datum, type->key.type, type->value.type);
1213
1214
0
    dst = 1;
1215
0
    for (src = 1; src < datum->n; src++) {
1216
0
        if (ovsdb_atom_equals(&datum->keys[src], &datum->keys[dst - 1],
1217
0
                              type->key.type)) {
1218
0
            ovsdb_atom_destroy(&datum->keys[src], type->key.type);
1219
0
            if (type->value.type != OVSDB_TYPE_VOID) {
1220
0
                ovsdb_atom_destroy(&datum->values[src], type->value.type);
1221
0
            }
1222
0
        } else {
1223
0
            if (src != dst) {
1224
0
                datum->keys[dst] = datum->keys[src];
1225
0
                if (type->value.type != OVSDB_TYPE_VOID) {
1226
0
                    datum->values[dst] = datum->values[src];
1227
0
                }
1228
0
            }
1229
0
            dst++;
1230
0
        }
1231
0
    }
1232
0
    datum->n = dst;
1233
0
    return datum->n - src;
1234
0
}
1235
1236
/* Checks that each of the atoms in 'datum' conforms to the constraints
1237
 * specified by its 'type'.  Returns an error if a constraint is violated,
1238
 * otherwise a null pointer.
1239
 *
1240
 * This function is not commonly useful because the most ordinary way to obtain
1241
 * a datum is ultimately via ovsdb_atom_from_string() or
1242
 * ovsdb_atom_from_json(), which check constraints themselves. */
1243
struct ovsdb_error *
1244
ovsdb_datum_check_constraints(const struct ovsdb_datum *datum,
1245
                              const struct ovsdb_type *type)
1246
0
{
1247
0
    struct ovsdb_error *error;
1248
0
    unsigned int i;
1249
1250
0
    for (i = 0; i < datum->n; i++) {
1251
0
        error = ovsdb_atom_check_constraints(&datum->keys[i], &type->key);
1252
0
        if (error) {
1253
0
            return error;
1254
0
        }
1255
0
    }
1256
1257
0
    if (type->value.type != OVSDB_TYPE_VOID) {
1258
0
        for (i = 0; i < datum->n; i++) {
1259
0
            error = ovsdb_atom_check_constraints(&datum->values[i],
1260
0
                                                 &type->value);
1261
0
            if (error) {
1262
0
                return error;
1263
0
            }
1264
0
        }
1265
0
    }
1266
1267
0
    return NULL;
1268
0
}
1269
1270
static struct ovsdb_error *
1271
ovsdb_datum_from_json__(struct ovsdb_datum *datum,
1272
                        const struct ovsdb_type *type,
1273
                        const struct json *json,
1274
                        struct ovsdb_symbol_table *symtab)
1275
0
{
1276
0
    struct ovsdb_error *error;
1277
1278
0
    if (ovsdb_type_is_map(type)
1279
0
        || (json->type == JSON_ARRAY
1280
0
            && json->array.n > 0
1281
0
            && json->array.elems[0]->type == JSON_STRING
1282
0
            && !strcmp(json->array.elems[0]->string, "set"))) {
1283
0
        bool is_map = ovsdb_type_is_map(type);
1284
0
        const char *class = is_map ? "map" : "set";
1285
0
        const struct json *inner;
1286
0
        unsigned int i;
1287
0
        size_t n;
1288
1289
0
        error = unwrap_json(json, class, JSON_ARRAY, &inner);
1290
0
        if (error) {
1291
0
            return error;
1292
0
        }
1293
1294
0
        n = inner->array.n;
1295
0
        if (n < type->n_min || n > type->n_max) {
1296
0
            if (type->n_min == 1 && type->n_max == 1) {
1297
0
                return ovsdb_syntax_error(json, NULL, "%s must have exactly "
1298
0
                                          "one member but %"PRIuSIZE" "
1299
0
                                          "are present", class, n);
1300
0
            } else {
1301
0
                return ovsdb_syntax_error(json, NULL, "%s must have %u to "
1302
0
                                          "%u members but %"PRIuSIZE" are "
1303
0
                                          "present",
1304
0
                                          class, type->n_min, type->n_max, n);
1305
0
            }
1306
0
        }
1307
1308
0
        datum->n = 0;
1309
0
        datum->keys = xmalloc(n * sizeof *datum->keys);
1310
0
        datum->values = is_map ? xmalloc(n * sizeof *datum->values) : NULL;
1311
0
        datum->refcnt = NULL;
1312
0
        for (i = 0; i < n; i++) {
1313
0
            const struct json *element = inner->array.elems[i];
1314
0
            const struct json *key = NULL;
1315
0
            const struct json *value = NULL;
1316
1317
0
            if (!is_map) {
1318
0
                key = element;
1319
0
            } else {
1320
0
                error = parse_json_pair(element, &key, &value);
1321
0
                if (error) {
1322
0
                    goto error;
1323
0
                }
1324
0
            }
1325
1326
0
            error = ovsdb_atom_from_json(&datum->keys[i], &type->key,
1327
0
                                         key, symtab);
1328
0
            if (error) {
1329
0
                goto error;
1330
0
            }
1331
1332
0
            if (is_map) {
1333
0
                error = ovsdb_atom_from_json(&datum->values[i],
1334
0
                                             &type->value, value, symtab);
1335
0
                if (error) {
1336
0
                    ovsdb_atom_destroy(&datum->keys[i], type->key.type);
1337
0
                    goto error;
1338
0
                }
1339
0
            }
1340
1341
0
            datum->n++;
1342
0
        }
1343
0
        return NULL;
1344
1345
0
    error:
1346
0
        ovsdb_datum_destroy(datum, type);
1347
0
        return error;
1348
0
    } else {
1349
0
        datum->n = 1;
1350
0
        datum->keys = xmalloc(sizeof *datum->keys);
1351
0
        datum->values = NULL;
1352
0
        datum->refcnt = NULL;
1353
1354
0
        error = ovsdb_atom_from_json(&datum->keys[0], &type->key,
1355
0
                                     json, symtab);
1356
0
        if (error) {
1357
0
            free(datum->keys);
1358
0
        }
1359
0
        return error;
1360
0
    }
1361
0
}
1362
1363
/* Parses 'json' as a datum of the type described by 'type'.  If successful,
1364
 * returns NULL and initializes 'datum' with the parsed datum.  On failure,
1365
 * returns an error and the contents of 'datum' are indeterminate.  The caller
1366
 * is responsible for freeing the error or the datum that is returned.
1367
 *
1368
 * Violations of constraints expressed by 'type' are treated as errors.
1369
 *
1370
 * If 'symtab' is nonnull, then named UUIDs in 'symtab' are accepted.  Refer to
1371
 * RFC 7047 for information about this, and for the syntax that this function
1372
 * accepts. */
1373
struct ovsdb_error * OVS_WARN_UNUSED_RESULT
1374
ovsdb_datum_from_json(struct ovsdb_datum *datum,
1375
                      const struct ovsdb_type *type,
1376
                      const struct json *json,
1377
                      struct ovsdb_symbol_table *symtab)
1378
0
{
1379
0
    struct ovsdb_error *error;
1380
1381
0
    error = ovsdb_datum_from_json__(datum, type, json, symtab);
1382
0
    if (error) {
1383
0
        return error;
1384
0
    }
1385
1386
0
    error = ovsdb_datum_sort(datum, type);
1387
0
    if (error) {
1388
0
        ovsdb_datum_destroy(datum, type);
1389
0
    }
1390
0
    return error;
1391
0
}
1392
1393
/* Parses 'json' as a datum of the type described by 'type' for internal
1394
 * use. This function is similar to 'ovsdb_datum_from_json', except the
1395
 * member size of set or map is not checked.
1396
 *
1397
 * The datum generated should be used then discard. It is not suitable
1398
 * for storing into IDL because of the possible member size violation.  */
1399
struct ovsdb_error * OVS_WARN_UNUSED_RESULT
1400
ovsdb_transient_datum_from_json(struct ovsdb_datum *datum,
1401
                                const struct ovsdb_type *type,
1402
                                const struct json *json)
1403
0
{
1404
0
    struct ovsdb_type relaxed_type = *type;
1405
1406
0
    relaxed_type.n_min = 0;
1407
0
    relaxed_type.n_max = UINT_MAX;
1408
1409
0
    return ovsdb_datum_from_json(datum, &relaxed_type, json, NULL);
1410
0
}
1411
1412
/* Parses 'json' as a datum of the type described by 'type', but ignoring all
1413
 * constraints. */
1414
struct ovsdb_error * OVS_WARN_UNUSED_RESULT
1415
ovsdb_unconstrained_datum_from_json(struct ovsdb_datum *datum,
1416
                                    const struct ovsdb_type *type,
1417
                                    const struct json *json)
1418
0
{
1419
0
    struct ovsdb_type relaxed_type;
1420
1421
0
    ovsdb_base_type_init(&relaxed_type.key, type->key.type);
1422
0
    ovsdb_base_type_init(&relaxed_type.value, type->value.type);
1423
0
    relaxed_type.n_min = 0;
1424
0
    relaxed_type.n_max = UINT_MAX;
1425
1426
0
    return ovsdb_datum_from_json(datum, &relaxed_type, json, NULL);
1427
0
}
1428
1429
static struct json *
1430
ovsdb_base_to_json(const union ovsdb_atom *atom,
1431
                   const struct ovsdb_base_type *base,
1432
                   bool use_row_names,
1433
                   bool allow_shallow_copies)
1434
0
{
1435
0
    if (!use_row_names
1436
0
        || base->type != OVSDB_TYPE_UUID
1437
0
        || !base->uuid.refTableName) {
1438
0
        return allow_shallow_copies
1439
0
               ? ovsdb_atom_to_json(atom, base->type)
1440
0
               : ovsdb_atom_to_json_deep(atom, base->type);
1441
0
    } else {
1442
0
        return json_array_create_2(
1443
0
            json_string_create("named-uuid"),
1444
0
            json_string_create_nocopy(ovsdb_data_row_name(&atom->uuid)));
1445
0
    }
1446
0
}
1447
1448
static struct json *
1449
ovsdb_datum_to_json__(const struct ovsdb_datum *datum,
1450
                      const struct ovsdb_type *type,
1451
                      bool use_row_names,
1452
                      bool allow_shallow_copies)
1453
0
{
1454
0
    if (ovsdb_type_is_map(type)) {
1455
0
        struct json **elems;
1456
0
        size_t i;
1457
1458
0
        elems = xmalloc(datum->n * sizeof *elems);
1459
0
        for (i = 0; i < datum->n; i++) {
1460
0
            elems[i] = json_array_create_2(
1461
0
                ovsdb_base_to_json(&datum->keys[i], &type->key,
1462
0
                                   use_row_names, allow_shallow_copies),
1463
0
                ovsdb_base_to_json(&datum->values[i], &type->value,
1464
0
                                   use_row_names, allow_shallow_copies));
1465
0
        }
1466
1467
0
        return wrap_json("map", json_array_create(elems, datum->n));
1468
0
    } else if (datum->n == 1) {
1469
0
        return ovsdb_base_to_json(&datum->keys[0], &type->key,
1470
0
                                  use_row_names, allow_shallow_copies);
1471
0
    } else {
1472
0
        struct json **elems;
1473
0
        size_t i;
1474
1475
0
        elems = xmalloc(datum->n * sizeof *elems);
1476
0
        for (i = 0; i < datum->n; i++) {
1477
0
            elems[i] = ovsdb_base_to_json(&datum->keys[i], &type->key,
1478
0
                                          use_row_names, allow_shallow_copies);
1479
0
        }
1480
1481
0
        return wrap_json("set", json_array_create(elems, datum->n));
1482
0
    }
1483
0
}
1484
1485
/* Converts 'datum', of the specified 'type', to JSON format, and returns the
1486
 * JSON.  The caller is responsible for freeing the returned JSON.
1487
 *
1488
 * 'type' constraints on datum->n are ignored.
1489
 *
1490
 * Refer to RFC 7047 for the format of the JSON that this function produces. */
1491
struct json *
1492
ovsdb_datum_to_json(const struct ovsdb_datum *datum,
1493
                    const struct ovsdb_type *type)
1494
0
{
1495
0
    return ovsdb_datum_to_json__(datum, type, false, true);
1496
0
}
1497
1498
struct json *
1499
ovsdb_datum_to_json_deep(const struct ovsdb_datum *datum,
1500
                         const struct ovsdb_type *type)
1501
0
{
1502
0
    return ovsdb_datum_to_json__(datum, type, false, false);
1503
0
}
1504
1505
struct json *
1506
ovsdb_datum_to_json_with_row_names(const struct ovsdb_datum *datum,
1507
                                   const struct ovsdb_type *type)
1508
0
{
1509
0
    return ovsdb_datum_to_json__(datum, type, true, true);
1510
0
}
1511
1512
static const char *
1513
skip_spaces(const char *p)
1514
0
{
1515
0
    while (isspace((unsigned char) *p)) {
1516
0
        p++;
1517
0
    }
1518
0
    return p;
1519
0
}
1520
1521
static char *
1522
parse_atom_token(const char **s, const struct ovsdb_base_type *base,
1523
                 union ovsdb_atom *atom, union ovsdb_atom **range_end_atom,
1524
                 struct ovsdb_symbol_table *symtab)
1525
0
{
1526
0
    char *token, *error;
1527
1528
0
    error = ovsdb_token_parse(s, &token);
1529
0
    if (!error) {
1530
0
        error = ovsdb_atom_from_string(atom, range_end_atom,
1531
0
                                       base, token, symtab);
1532
0
        free(token);
1533
0
    }
1534
0
    return error;
1535
0
}
1536
1537
static char *
1538
parse_key_value(const char **s, const struct ovsdb_type *type,
1539
                union ovsdb_atom *key, union ovsdb_atom *value,
1540
                struct ovsdb_symbol_table *symtab,
1541
                union ovsdb_atom **range_end_key)
1542
0
{
1543
0
    const char *start = *s;
1544
0
    char *error;
1545
1546
0
    error = parse_atom_token(s, &type->key, key, range_end_key, symtab);
1547
1548
0
    if (!error && type->value.type != OVSDB_TYPE_VOID) {
1549
0
        *s = skip_spaces(*s);
1550
0
        if (**s == '=') {
1551
0
            (*s)++;
1552
0
            *s = skip_spaces(*s);
1553
0
            error = parse_atom_token(s, &type->value, value, NULL, symtab);
1554
0
        } else {
1555
0
            error = xasprintf("%s: syntax error at \"%c\" expecting \"=\"",
1556
0
                              start, **s);
1557
0
        }
1558
0
        if (error) {
1559
0
            ovsdb_atom_destroy(key, type->key.type);
1560
0
            if (range_end_key && *range_end_key) {
1561
0
                ovsdb_atom_destroy(*range_end_key, type->key.type);
1562
0
                free(*range_end_key);
1563
0
                *range_end_key = NULL;
1564
0
            }
1565
0
        }
1566
0
    }
1567
0
    return error;
1568
0
}
1569
1570
static void
1571
free_key_value_range(const struct ovsdb_type *type,
1572
                     union ovsdb_atom *key, union ovsdb_atom *value,
1573
                     union ovsdb_atom **range_end_atom)
1574
0
{
1575
0
    ovsdb_atom_destroy(key, type->key.type);
1576
0
    if (type->value.type != OVSDB_TYPE_VOID) {
1577
0
        ovsdb_atom_destroy(value, type->value.type);
1578
0
    }
1579
0
    if (range_end_atom && *range_end_atom) {
1580
0
        ovsdb_atom_destroy(*range_end_atom, type->key.type);
1581
0
        free(*range_end_atom);
1582
0
        *range_end_atom = NULL;
1583
0
    }
1584
0
}
1585
1586
/* Initializes 'datum' as a datum of the given 'type', parsing its contents
1587
 * from 's'.  The format of 's' is a series of space or comma separated atoms
1588
 * or, for a map, '='-delimited pairs of atoms.  Each atom must in a format
1589
 * acceptable to ovsdb_atom_from_string().  Optionally, a set may be enclosed
1590
 * in "[]" or a map in "{}"; for an empty set or map these punctuators are
1591
 * required.
1592
 *
1593
 * Optionally, a symbol table may be supplied as 'symtab'.  It is passed to
1594
 * ovsdb_atom_to_string(). */
1595
char *
1596
ovsdb_datum_from_string(struct ovsdb_datum *datum,
1597
                        const struct ovsdb_type *type, const char *s,
1598
                        struct ovsdb_symbol_table *symtab)
1599
0
{
1600
0
    bool is_map = ovsdb_type_is_map(type);
1601
0
    struct ovsdb_error *dberror;
1602
0
    const char *p;
1603
0
    int end_delim;
1604
0
    char *error;
1605
1606
0
    ovsdb_datum_init_empty(datum);
1607
1608
    /* Swallow a leading delimiter if there is one. */
1609
0
    p = skip_spaces(s);
1610
0
    if (*p == (is_map ? '{' : '[')) {
1611
0
        end_delim = is_map ? '}' : ']';
1612
0
        p = skip_spaces(p + 1);
1613
0
    } else if (!*p) {
1614
0
        if (is_map) {
1615
0
            return xstrdup("use \"{}\" to specify the empty map");
1616
0
        } else {
1617
0
            return xstrdup("use \"[]\" to specify the empty set");
1618
0
        }
1619
0
    } else {
1620
0
        end_delim = 0;
1621
0
    }
1622
1623
0
    while (*p && *p != end_delim) {
1624
0
        union ovsdb_atom key, value;
1625
0
        union ovsdb_atom *range_end_key = NULL;
1626
1627
0
        if (ovsdb_token_is_delim(*p)) {
1628
0
            char *type_str = ovsdb_type_to_english(type);
1629
0
            error = xasprintf("%s: unexpected \"%c\" parsing %s",
1630
0
                              s, *p, type_str);
1631
0
            free(type_str);
1632
0
            goto error;
1633
0
        }
1634
1635
        /* Add to datum. */
1636
0
        error = parse_key_value(&p, type, &key, &value,
1637
0
                                symtab, &range_end_key);
1638
0
        if (error) {
1639
0
            goto error;
1640
0
        }
1641
0
        ovsdb_datum_add_unsafe(datum, &key, &value, type, range_end_key);
1642
0
        free_key_value_range(type, &key, &value, &range_end_key);
1643
1644
        /* Skip optional white space and comma. */
1645
0
        p = skip_spaces(p);
1646
0
        if (*p == ',') {
1647
0
            p = skip_spaces(p + 1);
1648
0
        }
1649
0
    }
1650
1651
0
    if (*p != end_delim) {
1652
0
        error = xasprintf("%s: missing \"%c\" at end of data", s, end_delim);
1653
0
        goto error;
1654
0
    }
1655
0
    if (end_delim) {
1656
0
        p = skip_spaces(p + 1);
1657
0
        if (*p) {
1658
0
            error = xasprintf("%s: trailing garbage after \"%c\"",
1659
0
                              s, end_delim);
1660
0
            goto error;
1661
0
        }
1662
0
    }
1663
1664
0
    if (datum->n < type->n_min) {
1665
0
        error = xasprintf("%s: %u %s specified but the minimum number is %u",
1666
0
                          s, datum->n, is_map ? "pair(s)" : "value(s)",
1667
0
                          type->n_min);
1668
0
        goto error;
1669
0
    } else if (datum->n > type->n_max) {
1670
0
        error = xasprintf("%s: %u %s specified but the maximum number is %u",
1671
0
                          s, datum->n, is_map ? "pair(s)" : "value(s)",
1672
0
            type->n_max);
1673
0
        goto error;
1674
0
    }
1675
1676
0
    dberror = ovsdb_datum_sort(datum, type);
1677
0
    if (dberror) {
1678
0
        ovsdb_error_destroy(dberror);
1679
0
        if (ovsdb_type_is_map(type)) {
1680
0
            error = xasprintf("%s: map contains duplicate key", s);
1681
0
        } else {
1682
0
            error = xasprintf("%s: set contains duplicate value", s);
1683
0
        }
1684
0
        goto error;
1685
0
    }
1686
1687
0
    return NULL;
1688
1689
0
error:
1690
0
    ovsdb_datum_destroy(datum, type);
1691
0
    ovsdb_datum_init_empty(datum);
1692
0
    return error;
1693
0
}
1694
1695
/* Appends to 'out' the 'datum' (with the given 'type') in a format acceptable
1696
 * to ovsdb_datum_from_string(). */
1697
void
1698
ovsdb_datum_to_string(const struct ovsdb_datum *datum,
1699
                      const struct ovsdb_type *type, struct ds *out)
1700
0
{
1701
0
    bool is_map = ovsdb_type_is_map(type);
1702
0
    size_t i;
1703
1704
0
    if (type->n_max > 1 || !datum->n) {
1705
0
        ds_put_char(out, is_map ? '{' : '[');
1706
0
    }
1707
0
    for (i = 0; i < datum->n; i++) {
1708
0
        if (i > 0) {
1709
0
            ds_put_cstr(out, ", ");
1710
0
        }
1711
1712
0
        ovsdb_atom_to_string(&datum->keys[i], type->key.type, out);
1713
0
        if (is_map) {
1714
0
            ds_put_char(out, '=');
1715
0
            ovsdb_atom_to_string(&datum->values[i], type->value.type, out);
1716
0
        }
1717
0
    }
1718
0
    if (type->n_max > 1 || !datum->n) {
1719
0
        ds_put_char(out, is_map ? '}' : ']');
1720
0
    }
1721
0
}
1722
1723
/* Appends to 'out' the 'datum' (with the given 'type') in a bare string format
1724
 * that cannot be parsed uniformly back into a datum but is easier for shell
1725
 * scripts, etc., to deal with. */
1726
void
1727
ovsdb_datum_to_bare(const struct ovsdb_datum *datum,
1728
                    const struct ovsdb_type *type, struct ds *out)
1729
0
{
1730
0
    bool is_map = ovsdb_type_is_map(type);
1731
0
    size_t i;
1732
1733
0
    for (i = 0; i < datum->n; i++) {
1734
0
        if (i > 0) {
1735
0
            ds_put_cstr(out, " ");
1736
0
        }
1737
1738
0
        ovsdb_atom_to_bare(&datum->keys[i], type->key.type, out);
1739
0
        if (is_map) {
1740
0
            ds_put_char(out, '=');
1741
0
            ovsdb_atom_to_bare(&datum->values[i], type->value.type, out);
1742
0
        }
1743
0
    }
1744
0
}
1745
1746
/* Initializes 'datum' as a string-to-string map whose contents are copied from
1747
 * 'smap', which is not modified. */
1748
void
1749
ovsdb_datum_from_smap(struct ovsdb_datum *datum, const struct smap *smap)
1750
0
{
1751
0
    datum->n = smap_count(smap);
1752
0
    datum->keys = xmalloc(datum->n * sizeof *datum->keys);
1753
0
    datum->values = xmalloc(datum->n * sizeof *datum->values);
1754
0
    datum->refcnt = NULL;
1755
1756
0
    struct smap_node *node;
1757
0
    size_t i = 0;
1758
0
    SMAP_FOR_EACH (node, smap) {
1759
0
        datum->keys[i].s = ovsdb_atom_string_create(node->key);
1760
0
        datum->values[i].s = ovsdb_atom_string_create(node->value);
1761
0
        i++;
1762
0
    }
1763
0
    ovs_assert(i == datum->n);
1764
1765
0
    struct ovsdb_type type = {
1766
0
        OVSDB_BASE_STRING_INIT, OVSDB_BASE_STRING_INIT,
1767
0
        0, UINT_MAX
1768
0
    };
1769
0
    ovsdb_datum_sort_unique(datum, &type);
1770
0
}
1771
1772
struct ovsdb_error * OVS_WARN_UNUSED_RESULT
1773
ovsdb_datum_convert(struct ovsdb_datum *dst,
1774
                    const struct ovsdb_type *dst_type,
1775
                    const struct ovsdb_datum *src,
1776
                    const struct ovsdb_type *src_type)
1777
0
{
1778
0
    struct json *json = ovsdb_datum_to_json(src, src_type);
1779
0
    struct ovsdb_error *error = ovsdb_datum_from_json(dst, dst_type, json,
1780
0
                                                      NULL);
1781
0
    json_destroy(json);
1782
0
    return error;
1783
0
}
1784
1785
static uint32_t
1786
hash_atoms(enum ovsdb_atomic_type type, const union ovsdb_atom *atoms,
1787
           unsigned int n, uint32_t basis)
1788
0
{
1789
0
    if (type != OVSDB_TYPE_VOID) {
1790
0
        unsigned int i;
1791
1792
0
        for (i = 0; i < n; i++) {
1793
0
            basis = ovsdb_atom_hash(&atoms[i], type, basis);
1794
0
        }
1795
0
    }
1796
0
    return basis;
1797
0
}
1798
1799
uint32_t
1800
ovsdb_datum_hash(const struct ovsdb_datum *datum,
1801
                 const struct ovsdb_type *type, uint32_t basis)
1802
0
{
1803
0
    basis = hash_atoms(type->key.type, datum->keys, datum->n, basis);
1804
0
    basis ^= (type->key.type << 24) | (type->value.type << 16) | datum->n;
1805
0
    basis = hash_atoms(type->value.type, datum->values, datum->n, basis);
1806
0
    return basis;
1807
0
}
1808
1809
static int
1810
atom_arrays_compare_3way(const union ovsdb_atom *a,
1811
                         const union ovsdb_atom *b,
1812
                         enum ovsdb_atomic_type type,
1813
                         size_t n)
1814
0
{
1815
0
    unsigned int i;
1816
1817
0
    for (i = 0; i < n; i++) {
1818
0
        int cmp = ovsdb_atom_compare_3way(&a[i], &b[i], type);
1819
0
        if (cmp) {
1820
0
            return cmp;
1821
0
        }
1822
0
    }
1823
1824
0
    return 0;
1825
0
}
1826
1827
bool
1828
ovsdb_datum_equals(const struct ovsdb_datum *a,
1829
                   const struct ovsdb_datum *b,
1830
                   const struct ovsdb_type *type)
1831
0
{
1832
0
    return !ovsdb_datum_compare_3way(a, b, type);
1833
0
}
1834
1835
int
1836
ovsdb_datum_compare_3way(const struct ovsdb_datum *a,
1837
                         const struct ovsdb_datum *b,
1838
                         const struct ovsdb_type *type)
1839
0
{
1840
0
    int cmp;
1841
1842
0
    if (a->n != b->n) {
1843
0
        return a->n < b->n ? -1 : 1;
1844
0
    }
1845
1846
0
    if (a->refcnt && a->refcnt == b->refcnt) {
1847
0
        return 0;
1848
0
    }
1849
1850
0
    cmp = atom_arrays_compare_3way(a->keys, b->keys, type->key.type, a->n);
1851
0
    if (cmp) {
1852
0
        return cmp;
1853
0
    }
1854
1855
0
    return (type->value.type == OVSDB_TYPE_VOID ? 0
1856
0
            : atom_arrays_compare_3way(a->values, b->values, type->value.type,
1857
0
                                       a->n));
1858
0
}
1859
1860
/* If 'key' is one of the keys in 'datum', returns 'true' and sets '*pos' to
1861
 * its index within 'datum', otherwise returns 'false' and sets '*pos' to the
1862
 * index where 'key' should have been.  'key.type' must be the type of the
1863
 * atoms stored in the 'keys' array in 'datum'.
1864
 */
1865
bool
1866
ovsdb_datum_find_key(const struct ovsdb_datum *datum,
1867
                     const union ovsdb_atom *key,
1868
                     enum ovsdb_atomic_type key_type,
1869
                     unsigned int *pos)
1870
0
{
1871
0
    unsigned int low = 0;
1872
0
    unsigned int high = datum->n;
1873
0
    while (low < high) {
1874
0
        unsigned int idx = (low + high) / 2;
1875
0
        int cmp = ovsdb_atom_compare_3way(key, &datum->keys[idx], key_type);
1876
0
        if (cmp < 0) {
1877
0
            high = idx;
1878
0
        } else if (cmp > 0) {
1879
0
            low = idx + 1;
1880
0
        } else {
1881
0
            if (pos) {
1882
0
                *pos = idx;
1883
0
            }
1884
0
            return true;
1885
0
        }
1886
0
    }
1887
0
    if (pos) {
1888
0
        *pos = low;
1889
0
    }
1890
0
    return false;
1891
0
}
1892
1893
/* If 'key' and 'value' is one of the key-value pairs in 'datum', returns its
1894
 * index within 'datum', otherwise UINT_MAX.  'key.type' must be the type of
1895
 * the atoms stored in the 'keys' array in 'datum'.  'value_type' may be the
1896
 * type of the 'values' atoms or OVSDB_TYPE_VOID to compare only keys.
1897
 */
1898
unsigned int
1899
ovsdb_datum_find_key_value(const struct ovsdb_datum *datum,
1900
                           const union ovsdb_atom *key,
1901
                           enum ovsdb_atomic_type key_type,
1902
                           const union ovsdb_atom *value,
1903
                           enum ovsdb_atomic_type value_type)
1904
0
{
1905
0
    unsigned int idx;
1906
1907
0
    if (!ovsdb_datum_find_key(datum, key, key_type, &idx)
1908
0
        || (value_type != OVSDB_TYPE_VOID
1909
0
            && !ovsdb_atom_equals(&datum->values[idx], value, value_type))) {
1910
0
        idx = UINT_MAX;
1911
0
    }
1912
0
    return idx;
1913
0
}
1914
1915
/* If atom 'i' in 'a' is also in 'b', returns its index in 'b', otherwise
1916
 * UINT_MAX.  'type' must be the type of 'a' and 'b', except that
1917
 * type->value.type may be set to OVSDB_TYPE_VOID to compare keys but not
1918
 * values. */
1919
static unsigned int
1920
ovsdb_datum_find(const struct ovsdb_datum *a, int i,
1921
                 const struct ovsdb_datum *b,
1922
                 const struct ovsdb_type *type)
1923
0
{
1924
0
    return ovsdb_datum_find_key_value(b,
1925
0
                                      &a->keys[i], type->key.type,
1926
0
                                      a->values ? &a->values[i] : NULL,
1927
0
                                      type->value.type);
1928
0
}
1929
1930
/* Returns true if every element in 'a' is also in 'b', false otherwise. */
1931
bool
1932
ovsdb_datum_includes_all(const struct ovsdb_datum *a,
1933
                         const struct ovsdb_datum *b,
1934
                         const struct ovsdb_type *type)
1935
0
{
1936
0
    size_t i;
1937
1938
0
    if (a->n > b->n) {
1939
0
        return false;
1940
0
    }
1941
0
    for (i = 0; i < a->n; i++) {
1942
0
        if (ovsdb_datum_find(a, i, b, type) == UINT_MAX) {
1943
0
            return false;
1944
0
        }
1945
0
    }
1946
0
    return true;
1947
0
}
1948
1949
/* Returns true if no element in 'a' is also in 'b', false otherwise. */
1950
bool
1951
ovsdb_datum_excludes_all(const struct ovsdb_datum *a,
1952
                         const struct ovsdb_datum *b,
1953
                         const struct ovsdb_type *type)
1954
0
{
1955
0
    size_t i;
1956
1957
0
    for (i = 0; i < a->n; i++) {
1958
0
        if (ovsdb_datum_find(a, i, b, type) != UINT_MAX) {
1959
0
            return false;
1960
0
        }
1961
0
    }
1962
0
    return true;
1963
0
}
1964
1965
static void
1966
ovsdb_datum_reallocate(struct ovsdb_datum *a, const struct ovsdb_type *type,
1967
                       unsigned int capacity)
1968
0
{
1969
0
    ovsdb_datum_unshare(a, type);
1970
1971
0
    a->keys = xrealloc(a->keys, capacity * sizeof *a->keys);
1972
0
    if (type->value.type != OVSDB_TYPE_VOID) {
1973
0
        a->values = xrealloc(a->values, capacity * sizeof *a->values);
1974
0
    }
1975
0
}
1976
1977
/* Removes the element with index 'idx' from 'datum', which has type 'type'.
1978
 * If 'idx' is not the last element in 'datum', then the removed element is
1979
 * replaced by the (former) last element.
1980
 *
1981
 * This function does not maintain ovsdb_datum invariants.  Use
1982
 * ovsdb_datum_sort() to check and restore these invariants. */
1983
void
1984
ovsdb_datum_remove_unsafe(struct ovsdb_datum *datum, size_t idx,
1985
                          const struct ovsdb_type *type)
1986
0
{
1987
0
    ovsdb_datum_unshare(datum, type);
1988
1989
0
    ovsdb_atom_destroy(&datum->keys[idx], type->key.type);
1990
0
    datum->keys[idx] = datum->keys[datum->n - 1];
1991
0
    if (type->value.type != OVSDB_TYPE_VOID) {
1992
0
        ovsdb_atom_destroy(&datum->values[idx], type->value.type);
1993
0
        datum->values[idx] = datum->values[datum->n - 1];
1994
0
    }
1995
0
    datum->n--;
1996
0
}
1997
1998
/* Adds the element with the given 'key' and 'value' to 'datum', which must
1999
 * have the specified 'type'. Optionally if 'range_end_atom' is not
2000
 * a null pointer, adds a set of integers to 'datum' from inclusive
2001
 * range ['key', 'range_end_atom'].
2002
 *
2003
 * This function always allocates memory, so it is not an efficient way to add
2004
 * a number of elements to a datum.
2005
 *
2006
 * When adding a range of integers, this function allocates the memory once
2007
 * for the whole range.
2008
 *
2009
 * This function does not maintain ovsdb_datum invariants.  Use
2010
 * ovsdb_datum_sort() to check and restore these invariants.  (But a datum with
2011
 * 0 or 1 elements cannot violate the invariants anyhow.) */
2012
void
2013
ovsdb_datum_add_unsafe(struct ovsdb_datum *datum,
2014
                       const union ovsdb_atom *key,
2015
                       const union ovsdb_atom *value,
2016
                       const struct ovsdb_type *type,
2017
                       const union ovsdb_atom *range_end_atom)
2018
0
{
2019
0
    size_t idx = datum->n;
2020
2021
0
    ovsdb_datum_unshare(datum, type);
2022
2023
0
    datum->n += range_end_atom ?
2024
0
                (range_end_atom->integer - key->integer + 1) : 1;
2025
0
    datum->keys = xrealloc(datum->keys, datum->n * sizeof *datum->keys);
2026
0
    if (range_end_atom && key->integer <= range_end_atom->integer) {
2027
0
        for (int64_t i = key->integer; i <= range_end_atom->integer; i++) {
2028
0
            datum->keys[idx++].integer = i;
2029
0
        }
2030
0
    } else {
2031
0
        ovsdb_atom_clone(&datum->keys[idx], key, type->key.type);
2032
0
        if (type->value.type != OVSDB_TYPE_VOID) {
2033
0
            datum->values = xrealloc(datum->values,
2034
0
                                     datum->n * sizeof *datum->values);
2035
0
            ovsdb_atom_clone(&datum->values[idx], value, type->value.type);
2036
0
        }
2037
0
    }
2038
0
}
2039
2040
void
2041
ovsdb_datum_add_from_index_unsafe(struct ovsdb_datum *dst,
2042
                                  const struct ovsdb_datum *src,
2043
                                  size_t idx,
2044
                                  const struct ovsdb_type *type)
2045
0
{
2046
0
    const union ovsdb_atom *key = &src->keys[idx];
2047
0
    const union ovsdb_atom *value = type->value.type != OVSDB_TYPE_VOID
2048
0
                                    ? &src->values[idx]
2049
0
                                    : NULL;
2050
0
    ovsdb_datum_add_unsafe(dst, key, value, type, NULL);
2051
0
}
2052
2053
/* Adds 'n' atoms starting from index 'start_idx' from 'src' to the end of
2054
 * 'dst'.  'dst' should have enough memory allocated to hold the additional
2055
 * 'n' atoms.  Atoms are not cloned, i.e. 'dst' will reference the same data.
2056
 * Caller also should take care of the result being sorted. */
2057
static void
2058
ovsdb_datum_push_unsafe(struct ovsdb_datum *dst,
2059
                        const struct ovsdb_datum *src,
2060
                        unsigned int start_idx, unsigned int n,
2061
                        const struct ovsdb_type *type)
2062
0
{
2063
0
    if (n == 0) {
2064
0
        return;
2065
0
    }
2066
2067
0
    ovsdb_datum_unshare(dst, type);
2068
2069
0
    memcpy(&dst->keys[dst->n], &src->keys[start_idx], n * sizeof src->keys[0]);
2070
0
    if (type->value.type != OVSDB_TYPE_VOID) {
2071
0
        memcpy(&dst->values[dst->n], &src->values[start_idx],
2072
0
               n * sizeof src->values[0]);
2073
0
    }
2074
0
    dst->n += n;
2075
0
}
2076
2077
void
2078
ovsdb_datum_union(struct ovsdb_datum *a, const struct ovsdb_datum *b,
2079
                  const struct ovsdb_type *type)
2080
0
{
2081
0
    struct ovsdb_datum result;
2082
0
    unsigned int copied, pos;
2083
2084
0
    ovsdb_datum_unshare(a, type);
2085
0
    ovsdb_datum_init_empty(&result);
2086
2087
0
    copied = 0;
2088
0
    for (size_t bi = 0; bi < b->n; bi++) {
2089
0
        if (ovsdb_datum_find_key(a, &b->keys[bi], type->key.type, &pos)) {
2090
            /* Atom with the same key already exists. */
2091
0
            continue;
2092
0
        }
2093
0
        if (!result.keys) {
2094
0
            ovsdb_datum_reallocate(&result, type, a->n + (b->n - bi));
2095
0
        }
2096
0
        if (pos > copied) {
2097
            /* Need to copy some atoms from 'a' first. */
2098
0
            ovsdb_datum_push_unsafe(&result, a, copied, pos - copied, type);
2099
0
            copied = pos;
2100
0
        }
2101
        /* Inserting new atom from 'b'. */
2102
0
        ovsdb_atom_clone(&result.keys[result.n], &b->keys[bi], type->key.type);
2103
0
        if (type->value.type != OVSDB_TYPE_VOID) {
2104
0
            ovsdb_atom_clone(&result.values[result.n], &b->values[bi],
2105
0
                             type->value.type);
2106
0
        }
2107
0
        result.n++;
2108
0
    }
2109
0
    if (!result.keys) {
2110
        /* 'a' doesn't need to be changed. */
2111
0
        return;
2112
0
    }
2113
0
    if (a->n > copied) {
2114
        /* Copying remaining atoms. */
2115
0
        ovsdb_datum_push_unsafe(&result, a, copied, a->n - copied, type);
2116
0
    }
2117
    /* All atoms are copied now. */
2118
0
    a->n = 0;
2119
2120
0
    ovsdb_datum_swap(&result, a);
2121
0
    ovsdb_datum_destroy(&result, type);
2122
0
}
2123
2124
void
2125
ovsdb_datum_subtract(struct ovsdb_datum *a, const struct ovsdb_type *a_type,
2126
                     const struct ovsdb_datum *b,
2127
                     const struct ovsdb_type *b_type)
2128
0
{
2129
0
    unsigned int *idx, ai;
2130
0
    size_t n_idx;
2131
2132
0
    ovs_assert(a_type->key.type == b_type->key.type);
2133
0
    ovs_assert(a_type->value.type == b_type->value.type
2134
0
               || b_type->value.type == OVSDB_TYPE_VOID);
2135
2136
0
    ovsdb_datum_unshare(a, a_type);
2137
2138
0
    idx = xmalloc(b->n * sizeof *idx);
2139
0
    n_idx = 0;
2140
0
    for (size_t bi = 0; bi < b->n; bi++) {
2141
0
        ai = ovsdb_datum_find(b, bi, a, b_type);
2142
0
        if (ai == UINT_MAX) {
2143
            /* No such atom in 'a'. */
2144
0
            continue;
2145
0
        }
2146
        /* Not destroying right away since ovsdb_datum_find() will use them. */
2147
0
        idx[n_idx++] = ai;
2148
0
    }
2149
0
    if (!n_idx) {
2150
0
        free(idx);
2151
0
        return;
2152
0
    }
2153
2154
0
    struct ovsdb_datum result;
2155
2156
0
    ovsdb_datum_init_empty(&result);
2157
0
    ovsdb_datum_reallocate(&result, a_type, a->n - n_idx);
2158
2159
0
    unsigned int start_idx = 0;
2160
0
    for (size_t i = 0; i < n_idx; i++) {
2161
0
        ai = idx[i];
2162
2163
        /* Destroying atom. */
2164
0
        ovsdb_atom_destroy(&a->keys[ai], a_type->key.type);
2165
0
        if (a_type->value.type != OVSDB_TYPE_VOID) {
2166
0
            ovsdb_atom_destroy(&a->values[ai], a_type->value.type);
2167
0
        }
2168
2169
        /* Copy non-removed atoms from 'a' to result. */
2170
0
        ovsdb_datum_push_unsafe(&result, a, start_idx, ai - start_idx, a_type);
2171
0
        start_idx = idx[i] + 1;
2172
0
    }
2173
    /* Copying remaining atoms. */
2174
0
    ovsdb_datum_push_unsafe(&result, a, start_idx, a->n - start_idx, a_type);
2175
0
    a->n = 0;
2176
2177
0
    ovsdb_datum_swap(&result, a);
2178
0
    ovsdb_datum_destroy(&result, a_type);
2179
0
    free(idx);
2180
0
}
2181

2182
struct ovsdb_symbol_table *
2183
ovsdb_symbol_table_create(void)
2184
0
{
2185
0
    struct ovsdb_symbol_table *symtab = xmalloc(sizeof *symtab);
2186
0
    shash_init(&symtab->sh);
2187
0
    return symtab;
2188
0
}
2189
2190
void
2191
ovsdb_symbol_table_destroy(struct ovsdb_symbol_table *symtab)
2192
0
{
2193
0
    if (symtab) {
2194
0
        shash_destroy_free_data(&symtab->sh);
2195
0
        free(symtab);
2196
0
    }
2197
0
}
2198
2199
struct ovsdb_symbol *
2200
ovsdb_symbol_table_get(const struct ovsdb_symbol_table *symtab,
2201
                       const char *name)
2202
0
{
2203
0
    return shash_find_data(&symtab->sh, name);
2204
0
}
2205
2206
struct ovsdb_symbol *
2207
ovsdb_symbol_table_put(struct ovsdb_symbol_table *symtab, const char *name,
2208
                       const struct uuid *uuid, bool created)
2209
0
{
2210
0
    struct ovsdb_symbol *symbol;
2211
2212
0
    ovs_assert(!ovsdb_symbol_table_get(symtab, name));
2213
0
    symbol = xmalloc(sizeof *symbol);
2214
0
    symbol->uuid = *uuid;
2215
0
    symbol->created = created;
2216
0
    symbol->strong_ref = false;
2217
0
    symbol->weak_ref = false;
2218
0
    shash_add(&symtab->sh, name, symbol);
2219
0
    return symbol;
2220
0
}
2221
2222
struct ovsdb_symbol *
2223
ovsdb_symbol_table_insert(struct ovsdb_symbol_table *symtab,
2224
                          const char *name)
2225
0
{
2226
0
    struct ovsdb_symbol *symbol;
2227
2228
0
    symbol = ovsdb_symbol_table_get(symtab, name);
2229
0
    if (!symbol) {
2230
0
        struct uuid uuid;
2231
2232
0
        uuid_generate(&uuid);
2233
0
        symbol = ovsdb_symbol_table_put(symtab, name, &uuid, false);
2234
0
    }
2235
0
    return symbol;
2236
0
}
2237

2238
/* APIs for Generating and apply diffs.  */
2239
2240
/* Find what needs to be added to and removed from 'old' to construct 'new'.
2241
 *
2242
 * The 'added' and 'removed' datums are always safe; the orders of keys are
2243
 * maintained since they are added in order.   */
2244
void
2245
ovsdb_datum_added_removed(struct ovsdb_datum *added,
2246
                          struct ovsdb_datum *removed,
2247
                          const struct ovsdb_datum *old,
2248
                          const struct ovsdb_datum *new,
2249
                          const struct ovsdb_type *type)
2250
0
{
2251
0
    size_t oi, ni;
2252
2253
0
    ovsdb_datum_init_empty(added);
2254
0
    ovsdb_datum_init_empty(removed);
2255
0
    if (!ovsdb_type_is_composite(type)) {
2256
0
        ovsdb_datum_clone(removed, old);
2257
0
        ovsdb_datum_clone(added, new);
2258
0
        return;
2259
0
    }
2260
2261
    /* Generate the diff in O(n) time. */
2262
0
    for (oi = ni = 0; oi < old->n && ni < new->n;) {
2263
0
        int c = ovsdb_atom_compare_3way(&old->keys[oi], &new->keys[ni],
2264
0
                                        type->key.type);
2265
0
        if (c < 0) {
2266
0
            ovsdb_datum_add_from_index_unsafe(removed, old, oi, type);
2267
0
            oi++;
2268
0
        } else if (c > 0) {
2269
0
            ovsdb_datum_add_from_index_unsafe(added, new, ni, type);
2270
0
            ni++;
2271
0
        } else {
2272
0
            if (type->value.type != OVSDB_TYPE_VOID &&
2273
0
                ovsdb_atom_compare_3way(&old->values[oi], &new->values[ni],
2274
0
                                        type->value.type)) {
2275
0
                ovsdb_datum_add_unsafe(removed, &old->keys[oi],
2276
0
                                       &old->values[oi], type, NULL);
2277
0
                ovsdb_datum_add_unsafe(added, &new->keys[ni], &new->values[ni],
2278
0
                                       type, NULL);
2279
0
            }
2280
0
            oi++; ni++;
2281
0
        }
2282
0
    }
2283
2284
0
    for (; oi < old->n; oi++) {
2285
0
        ovsdb_datum_add_from_index_unsafe(removed, old, oi, type);
2286
0
    }
2287
2288
0
    for (; ni < new->n; ni++) {
2289
0
        ovsdb_datum_add_from_index_unsafe(added, new, ni, type);
2290
0
    }
2291
0
}
2292
2293
2294
/* Generate a difference ovsdb_dataum between 'old' and 'new'.
2295
 * 'new' can be regenerated by applying the difference to the 'old'.
2296
 *
2297
 * The diff operation is reversible. Given 'old',
2298
 * 'new' can be recreated by applying diff to 'old'.
2299
 *
2300
 * Thus
2301
 *     Let  d = 'old' diff 'new'
2302
 *     then 'new' = 'old' diff d
2303
 *
2304
 * The 'diff' datum is always safe; the orders of keys are maintained
2305
 * since they are added in order.   */
2306
void
2307
ovsdb_datum_diff(struct ovsdb_datum *diff,
2308
                 const struct ovsdb_datum *old,
2309
                 const struct ovsdb_datum *new,
2310
                 const struct ovsdb_type *type)
2311
0
{
2312
0
    size_t oi, ni;
2313
2314
0
    ovsdb_datum_init_empty(diff);
2315
0
    if (!ovsdb_type_is_composite(type)) {
2316
0
        ovsdb_datum_clone(diff, new);
2317
0
        return;
2318
0
    }
2319
2320
    /* Generate the diff in O(n) time. */
2321
0
    for (oi = ni = 0; oi < old->n && ni < new->n; ) {
2322
0
        int c = ovsdb_atom_compare_3way(&old->keys[oi], &new->keys[ni],
2323
0
                                        type->key.type);
2324
0
        if (c < 0) {
2325
0
            ovsdb_datum_add_from_index_unsafe(diff, old, oi, type);
2326
0
            oi++;
2327
0
        } else if (c > 0) {
2328
0
            ovsdb_datum_add_from_index_unsafe(diff, new, ni, type);
2329
0
            ni++;
2330
0
        } else {
2331
0
            if (type->value.type != OVSDB_TYPE_VOID &&
2332
0
                ovsdb_atom_compare_3way(&old->values[oi], &new->values[ni],
2333
0
                                        type->value.type)) {
2334
0
                ovsdb_datum_add_unsafe(diff, &new->keys[ni], &new->values[ni],
2335
0
                                       type, NULL);
2336
0
            }
2337
0
            oi++; ni++;
2338
0
        }
2339
0
    }
2340
2341
0
    for (; oi < old->n; oi++) {
2342
0
        ovsdb_datum_add_from_index_unsafe(diff, old, oi, type);
2343
0
    }
2344
2345
0
    for (; ni < new->n; ni++) {
2346
0
        ovsdb_datum_add_from_index_unsafe(diff, new, ni, type);
2347
0
    }
2348
0
}
2349
2350
/* Apply 'diff' to 'a'.
2351
 *
2352
 * Return NULL if the 'a' is successfully updated, otherwise, return
2353
 * ovsdb_error. */
2354
struct ovsdb_error *
2355
ovsdb_datum_apply_diff_in_place(struct ovsdb_datum *a,
2356
                                const struct ovsdb_datum *diff,
2357
                                const struct ovsdb_type *type)
2358
0
{
2359
0
    struct ovsdb_error *error = NULL;
2360
0
    struct ovsdb_datum result;
2361
0
    size_t i, new_size;
2362
0
    unsigned int *idx, pos;
2363
0
    enum {
2364
0
        DIFF_OP_ADD,
2365
0
        DIFF_OP_REMOVE,
2366
0
        DIFF_OP_UPDATE,
2367
0
    } *operation;
2368
2369
0
    if (!ovsdb_type_is_composite(type)) {
2370
0
        ovsdb_datum_destroy(a, type);
2371
0
        ovsdb_datum_clone(a, diff);
2372
0
        return NULL;
2373
0
    }
2374
2375
0
    ovsdb_datum_unshare(a, type);
2376
2377
0
    operation = xmalloc(diff->n * sizeof *operation);
2378
0
    idx = xmalloc(diff->n * sizeof *idx);
2379
0
    new_size = a->n;
2380
0
    for (i = 0; i < diff->n; i++) {
2381
0
        if (!ovsdb_datum_find_key(a, &diff->keys[i], type->key.type, &pos)) {
2382
0
            operation[i] = DIFF_OP_ADD;
2383
0
            new_size++;
2384
0
        } else if (type->value.type != OVSDB_TYPE_VOID
2385
0
                   && !ovsdb_atom_equals(&diff->values[i], &a->values[pos],
2386
0
                                         type->value.type)) {
2387
0
            operation[i] = DIFF_OP_UPDATE;
2388
0
        } else {
2389
0
            operation[i] = DIFF_OP_REMOVE;
2390
0
            new_size--;
2391
0
        }
2392
0
        idx[i] = pos;
2393
0
    }
2394
2395
    /* Make sure member size of 'new' conforms to type. */
2396
0
    if (new_size < type->n_min || new_size > type->n_max) {
2397
0
        error = ovsdb_error(NULL, "Datum crated by diff has size error");
2398
0
        goto exit;
2399
0
    }
2400
2401
0
    ovsdb_datum_init_empty(&result);
2402
0
    ovsdb_datum_reallocate(&result, type, new_size);
2403
2404
0
    unsigned int copied = 0;
2405
0
    for (i = 0; i < diff->n; i++) {
2406
0
        pos = idx[i];
2407
2408
0
        if (copied < pos) {
2409
            /* Copying all atoms that should go before the current one. */
2410
0
            ovsdb_datum_push_unsafe(&result, a, copied, pos - copied, type);
2411
0
            copied = pos;
2412
0
        }
2413
2414
0
        switch (operation[i]) {
2415
0
        case DIFF_OP_UPDATE:
2416
0
        case DIFF_OP_ADD:
2417
            /* Inserting new atom from 'diff'. */
2418
0
            ovsdb_atom_clone(&result.keys[result.n],
2419
0
                             &diff->keys[i], type->key.type);
2420
0
            if (type->value.type != OVSDB_TYPE_VOID) {
2421
0
                ovsdb_atom_clone(&result.values[result.n],
2422
0
                                 &diff->values[i], type->value.type);
2423
0
            }
2424
0
            result.n++;
2425
0
            if (operation[i] != DIFF_OP_UPDATE) {
2426
0
                break;
2427
0
            }
2428
            /* fall through */
2429
2430
0
        case DIFF_OP_REMOVE:
2431
            /* Destroying atom. */
2432
0
            ovsdb_atom_destroy(&a->keys[pos], type->key.type);
2433
0
            if (type->value.type != OVSDB_TYPE_VOID) {
2434
0
                ovsdb_atom_destroy(&a->values[pos], type->value.type);
2435
0
            }
2436
0
            copied++; /* Skipping removed atom. */
2437
0
            break;
2438
0
        }
2439
0
    }
2440
    /* Copying remaining atoms. */
2441
0
    ovsdb_datum_push_unsafe(&result, a, copied, a->n - copied, type);
2442
0
    a->n = 0;
2443
2444
0
    ovsdb_datum_swap(&result, a);
2445
0
    ovsdb_datum_destroy(&result, type);
2446
0
exit:
2447
0
    free(operation);
2448
0
    free(idx);
2449
0
    return error;
2450
0
}
2451
2452
/* Apply 'diff' to 'old' to regenerate 'new'.
2453
 *
2454
 * Return NULL if the 'new' is successfully generated, otherwise, return
2455
 * ovsdb_error and the stat of 'new' is indeterministic. */
2456
struct ovsdb_error *
2457
ovsdb_datum_apply_diff(struct ovsdb_datum *new,
2458
                       const struct ovsdb_datum *old,
2459
                       const struct ovsdb_datum *diff,
2460
                       const struct ovsdb_type *type)
2461
0
{
2462
0
    ovsdb_datum_diff(new, old, diff, type);
2463
2464
    /* Make sure member size of 'new' conforms to type. */
2465
0
    if (new->n < type->n_min || new->n > type->n_max) {
2466
0
        ovsdb_datum_destroy(new, type);
2467
0
        return ovsdb_error(NULL, "Datum crated by diff has size error");
2468
0
    }
2469
2470
0
    return NULL;
2471
0
}
2472
2473

2474
/* Extracts a token from the beginning of 's' and returns a pointer just after
2475
 * the token.  Stores the token itself into '*outp', which the caller is
2476
 * responsible for freeing (with free()).
2477
 *
2478
 * If 's[0]' is a delimiter, the returned token is the empty string.
2479
 *
2480
 * A token extends from 's' to the first delimiter, as defined by
2481
 * ovsdb_token_is_delim(), or until the end of the string.  A delimiter can be
2482
 * escaped with a backslash, in which case the backslash does not appear in the
2483
 * output.  Double quotes also cause delimiters to be ignored, but the double
2484
 * quotes are retained in the output.  (Backslashes inside double quotes are
2485
 * not removed, either.)
2486
 */
2487
char *
2488
ovsdb_token_parse(const char **s, char **outp)
2489
0
{
2490
0
    const char *p;
2491
0
    struct ds out;
2492
0
    bool in_quotes;
2493
0
    char *error;
2494
2495
0
    ds_init(&out);
2496
0
    in_quotes = false;
2497
0
    for (p = *s; *p != '\0'; ) {
2498
0
        int c = *p++;
2499
0
        if (c == '\\') {
2500
0
            if (in_quotes) {
2501
0
                ds_put_char(&out, '\\');
2502
0
            }
2503
0
            if (!*p) {
2504
0
                error = xasprintf("%s: backslash at end of argument", *s);
2505
0
                goto error;
2506
0
            }
2507
0
            ds_put_char(&out, *p++);
2508
0
        } else if (!in_quotes && ovsdb_token_is_delim(c)) {
2509
0
            p--;
2510
0
            break;
2511
0
        } else {
2512
0
            ds_put_char(&out, c);
2513
0
            if (c == '"') {
2514
0
                in_quotes = !in_quotes;
2515
0
            }
2516
0
        }
2517
0
    }
2518
0
    if (in_quotes) {
2519
0
        error = xasprintf("%s: quoted string extends past end of argument",
2520
0
                          *s);
2521
0
        goto error;
2522
0
    }
2523
0
    *outp = ds_cstr(&out);
2524
0
    *s = p;
2525
0
    return NULL;
2526
2527
0
error:
2528
0
    ds_destroy(&out);
2529
0
    *outp = NULL;
2530
0
    return error;
2531
0
}
2532
2533
/* Returns true if 'c' delimits tokens, or if 'c' is 0, and false otherwise. */
2534
bool
2535
ovsdb_token_is_delim(unsigned char c)
2536
0
{
2537
0
    return strchr(":=, []{}!<>", c) != NULL;
2538
0
}
2539
2540
struct ovsdb_error *
2541
ovsdb_atom_range_check_size(int64_t range_start, int64_t range_end)
2542
0
{
2543
0
    if ((uint64_t) range_end - (uint64_t) range_start
2544
0
        >= MAX_OVSDB_ATOM_RANGE_SIZE) {
2545
0
        return ovsdb_error("constraint violation",
2546
0
                           "Range \"%"PRId64"-%"PRId64"\" is too big. "
2547
0
                           "Maximum allowed size is %d.",
2548
0
                           range_start, range_end, MAX_OVSDB_ATOM_RANGE_SIZE);
2549
0
    }
2550
0
    return NULL;
2551
0
}
2552

2553
char *
2554
ovsdb_data_row_name(const struct uuid *uuid)
2555
0
{
2556
0
    char *name;
2557
0
    char *p;
2558
2559
0
    name = xasprintf("row"UUID_FMT, UUID_ARGS(uuid));
2560
0
    for (p = name; *p != '\0'; p++) {
2561
0
        if (*p == '-') {
2562
0
            *p = '_';
2563
0
        }
2564
0
    }
2565
2566
0
    return name;
2567
0
}