Coverage Report

Created: 2025-07-12 06:35

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