Coverage Report

Created: 2026-01-10 06:37

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/net-snmp/snmplib/container_binary_array.c
Line
Count
Source
1
/*
2
 * container_binary_array.c
3
 *
4
 * see comments in header file.
5
 *
6
 * Portions of this file are subject to the following copyright(s).  See
7
 * the Net-SNMP's COPYING file for more details and other copyrights
8
 * that may apply:
9
 *
10
 * Portions of this file are copyrighted by:
11
 * Copyright (c) 2016 VMware, Inc. All rights reserved.
12
 * Use is subject to license terms specified in the COPYING file
13
 * distributed with the Net-SNMP package.
14
 */
15
16
#include <net-snmp/net-snmp-config.h>
17
18
#ifdef HAVE_IO_H
19
#include <io.h>
20
#endif
21
#include <stdio.h>
22
#ifdef HAVE_STDLIB_H
23
#include <stdlib.h>
24
#endif
25
#ifdef HAVE_STDINT_H
26
#include <stdint.h>
27
#endif
28
#ifdef HAVE_MALLOC_H
29
#include <malloc.h>
30
#endif
31
#include <sys/types.h>
32
#ifdef HAVE_STRING_H
33
#include <string.h>
34
#else
35
#include <strings.h>
36
#endif
37
38
#include <net-snmp/net-snmp-includes.h>
39
#include <net-snmp/types.h>
40
#include <net-snmp/library/snmp_api.h>
41
#include <net-snmp/library/container.h>
42
#include <net-snmp/library/container_binary_array.h>
43
#include <net-snmp/library/tools.h>
44
#include <net-snmp/library/snmp_assert.h>
45
#include "factory.h"
46
47
typedef struct binary_array_table_s {
48
    size_t                     max_size;   /* Size of the current data table */
49
    size_t                     count;      /* Index of the next free entry */
50
    int                        dirty;
51
    void                     **data;       /* The table itself */
52
} binary_array_table;
53
54
typedef struct binary_array_iterator_s {
55
    netsnmp_iterator base;
56
57
    size_t           pos;
58
} binary_array_iterator;
59
60
static netsnmp_iterator *_ba_iterator_get(netsnmp_container *c);
61
62
static int
63
Sort_Array(netsnmp_container *c)
64
0
{
65
0
    binary_array_table *t = (binary_array_table*)c->container_data;
66
0
    netsnmp_assert(t!=NULL);
67
0
    netsnmp_assert(c->compare!=NULL);
68
69
0
    if (c->flags & CONTAINER_KEY_UNSORTED)
70
0
        return 0;
71
72
0
    if (t->dirty) {
73
        /*
74
         * Sort the table 
75
         */
76
0
        qsort(t->data, t->count, sizeof(t->data[0]), c->compare);
77
0
        t->dirty = 0;
78
79
        /*
80
         * no way to know if it actually changed... just assume so.
81
         */
82
0
        ++c->sync;
83
0
    }
84
85
0
    return 1;
86
0
}
87
88
static int
89
linear_search(const void *val, netsnmp_container *c)
90
0
{
91
0
    binary_array_table *t = (binary_array_table*)c->container_data;
92
0
    size_t             pos = 0;
93
94
0
    if (!t->count)
95
0
        return -1;
96
97
0
    if (! (c->flags & CONTAINER_KEY_UNSORTED)) {
98
0
        snmp_log(LOG_ERR, "linear search on sorted container %s?!?\n",
99
0
                 c->container_name);
100
0
        return -1;
101
0
    }
102
103
0
    for (; pos < t->count; ++pos) {
104
0
        if (c->compare(t->data[pos], val) == 0)
105
0
            return pos;
106
0
    }
107
108
0
    return -1;
109
0
}
110
111
static int
112
binary_search(const void *val, netsnmp_container *c, int exact, size_t *next)
113
170k
{
114
170k
    binary_array_table *t = (binary_array_table*)c->container_data;
115
170k
    size_t             len = t->count;
116
170k
    size_t             half;
117
170k
    size_t             first = 0;
118
170k
    size_t             middle = 0; /* init not needed; keeps compiler happy */
119
170k
    int                result = 0; /* init not needed; keeps compiler happy */
120
121
170k
    if (!len) {
122
0
        if (NULL != next)
123
0
            *next = 0;
124
0
        return -1;
125
0
    }
126
127
170k
    if (c->flags & CONTAINER_KEY_UNSORTED) {
128
0
        if (!exact) {
129
0
            snmp_log(LOG_ERR, "non-exact search on unsorted container %s?!?\n",
130
0
                     c->container_name);
131
0
            return -1;
132
0
        }
133
0
        return linear_search(val, c);
134
0
    }
135
136
170k
    if (t->dirty)
137
0
        Sort_Array(c);
138
139
684k
    while (len > 0) {
140
569k
        half = len >> 1;
141
569k
        middle = first + half;
142
569k
        if ((result = c->compare(t->data[middle], val)) < 0) {
143
192k
            first = middle + 1;
144
192k
            len = len - half - 1;
145
376k
        } else if (result == 0) {
146
55.7k
            first = middle;
147
55.7k
            break;
148
321k
        } else {
149
321k
            len = half;
150
321k
        }
151
569k
    }
152
153
170k
    if (first >= t->count) {
154
13.9k
        if (exact && NULL != next)
155
6.98k
            *next = t->count;
156
13.9k
        return -1;
157
13.9k
    }
158
159
156k
    if (first != middle) {
160
        /* last compare wasn't against first, so get actual result */
161
87.0k
        result = c->compare(t->data[first], val);
162
87.0k
    }
163
164
156k
    if(result == 0) {
165
55.7k
        if (exact && NULL != next)
166
122
            *next = first+1;
167
55.5k
        else if (!exact && ++first == t->count) {
168
0
            if (NULL != next)
169
0
                *next = first;
170
0
            first = -1;
171
0
        }
172
101k
    } else if(exact) {
173
101k
        if (NULL != next) {
174
31.6k
            if (result > 0)
175
31.6k
                *next = first;
176
0
            else
177
0
                *next = t->count;
178
31.6k
        }
179
101k
        first = -1;
180
101k
    }
181
182
156k
    return first;
183
170k
}
184
185
NETSNMP_STATIC_INLINE binary_array_table *
186
netsnmp_binary_array_initialize(void)
187
34.6k
{
188
34.6k
    binary_array_table *t;
189
190
34.6k
    t = SNMP_MALLOC_TYPEDEF(binary_array_table);
191
34.6k
    if (t == NULL)
192
0
        return NULL;
193
194
34.6k
    t->max_size = 0;
195
34.6k
    t->count = 0;
196
34.6k
    t->dirty = 0;
197
34.6k
    t->data = NULL;
198
199
34.6k
    return t;
200
34.6k
}
201
202
void
203
netsnmp_binary_array_release(netsnmp_container *c)
204
34.6k
{
205
34.6k
    binary_array_table *t = (binary_array_table*)c->container_data;
206
34.6k
    SNMP_FREE(t->data);
207
34.6k
    SNMP_FREE(t);
208
34.6k
    SNMP_FREE(c->container_name);
209
34.6k
    SNMP_FREE(c);
210
34.6k
}
211
212
/**
213
 * Set or test the options of a binary array container.
214
 * @param c: Container.
215
 * @param set: Set (1) or test (0).
216
 * @param flags: Zero or more CONTAINER_KEY_* flags.
217
 */
218
int
219
netsnmp_binary_array_options_set(netsnmp_container *c, int set, u_int flags)
220
13.9k
{
221
13.9k
#define BA_FLAGS (CONTAINER_KEY_ALLOW_DUPLICATES|CONTAINER_KEY_UNSORTED)
222
223
13.9k
    if (set) {
224
13.9k
        if ((flags & BA_FLAGS) == flags) {
225
            /** if turning off unsorted, do sort */
226
13.9k
            int sort = ((c->flags & CONTAINER_KEY_UNSORTED) &&
227
0
                        ! (flags & CONTAINER_KEY_UNSORTED));
228
13.9k
            c->flags = flags;
229
13.9k
            if (sort) {
230
0
                binary_array_table *t = (binary_array_table*)c->container_data;
231
0
                t->dirty = 1; /* force sort */
232
0
                Sort_Array(c);
233
0
            }
234
13.9k
            return flags;
235
13.9k
        } else {
236
0
            return -1; /* unsupported flag */
237
0
        }
238
13.9k
    } else {
239
0
        return ((c->flags & flags) == flags);
240
0
    }
241
13.9k
}
242
243
NETSNMP_STATIC_INLINE size_t
244
netsnmp_binary_array_count(netsnmp_container *c)
245
3.43k
{
246
3.43k
    binary_array_table *t = (binary_array_table*)c->container_data;
247
    /*
248
     * return count
249
     */
250
3.43k
    return t ? t->count : 0;
251
3.43k
}
252
253
NETSNMP_STATIC_INLINE void           *
254
netsnmp_binary_array_get(netsnmp_container *c, const void *key, int exact)
255
135k
{
256
135k
    binary_array_table *t = (binary_array_table*)c->container_data;
257
135k
    int             index = 0;
258
259
    /*
260
     * if there is no data, return NULL;
261
     */
262
135k
    if (!t->count)
263
3.48k
        return NULL;
264
265
    /*
266
     * if the table is dirty, sort it.
267
     */
268
132k
    if (t->dirty)
269
0
        Sort_Array(c);
270
271
    /*
272
     * if there is a key, search. Otherwise default is 0;
273
     */
274
132k
    if (key) {
275
132k
        if ((index = binary_search(key, c, exact, NULL)) == -1)
276
76.4k
            return NULL;
277
55.5k
        if (!exact &&
278
0
            c->flags & CONTAINER_KEY_ALLOW_DUPLICATES) {
279
0
            int result;
280
281
            /*
282
             * If duplicates are allowed, we have to be extra
283
             * sure that we didn't just increment to a duplicate,
284
             * thus causing a getnext loop.
285
             */
286
0
            result = c->compare(t->data[index], key);
287
0
            while (result == 0) {
288
0
    DEBUGMSGTL(("container","skipping duplicate key in %s\n",
289
0
              c->container_name));
290
0
                if (++index == t->count)
291
0
                   return NULL;
292
0
                result = c->compare(t->data[index], key);
293
0
            }
294
0
        }
295
55.5k
    }
296
297
55.5k
    return t->data[index];
298
132k
}
299
300
static int
301
netsnmp_binary_array_get_at(netsnmp_container *c, size_t pos, void **entry)
302
0
{
303
0
    binary_array_table *t = (binary_array_table*)c->container_data;
304
305
    /*
306
     * if there is no data, return NULL;
307
     */
308
0
    if (!t->count || pos >= t->count || NULL == entry)
309
0
        return -1;
310
311
0
    *entry = t->data[pos];
312
313
0
    return 0;
314
0
}
315
316
/**
317
 * Returns 1 if and only if the elements in @c are sorted in ascending order.
318
 *
319
 * To do: stop calling this function after
320
 * https://github.com/net-snmp/net-snmp/issues/107 and
321
 * https://github.com/net-snmp/net-snmp/issues/293 have been fixed.
322
 */
323
static int _ba_is_sorted(const netsnmp_container *c)
324
42.1k
{
325
    /*
326
     * The code below has been commented out because it negatively affects
327
     * performance.
328
     */
329
#if 0
330
    const binary_array_table *t = c->container_data;
331
    int i;
332
333
    for (i = 0; i + 1 < t->count; ++i)
334
        if (c->compare(t->data[i], t->data[i + 1]) > 0)
335
            return 0;
336
#endif
337
338
42.1k
    return 1;
339
42.1k
}
340
341
int
342
netsnmp_binary_array_remove_at(netsnmp_container *c, size_t index, void **save)
343
0
{
344
0
    binary_array_table *t = (binary_array_table*)c->container_data;
345
346
0
    if (save)
347
0
        *save = NULL;
348
    
349
    /*
350
     * if there is no data, return NULL;
351
     */
352
0
    if (!t->count)
353
0
        return -1;
354
355
    /*
356
     * find old data and save it, if ptr provided
357
     */
358
0
    if (save)
359
0
        *save = t->data[index];
360
361
    /*
362
     * if entry was last item, just decrement count
363
     */
364
0
    --t->count;
365
0
    if (index != t->count) {
366
        /*
367
         * otherwise, shift array down
368
         */
369
0
        memmove(&t->data[index], &t->data[index+1],
370
0
                sizeof(void*) * (t->count - index));
371
372
0
        ++c->sync;
373
0
    }
374
375
0
    netsnmp_assert(t->dirty || _ba_is_sorted(c));
376
377
0
    return 0;
378
0
}
379
380
int
381
netsnmp_binary_array_remove(netsnmp_container *c, const void *key, void **save)
382
0
{
383
0
    binary_array_table *t = (binary_array_table*)c->container_data;
384
0
    int                index = 0;
385
386
0
    if (save)
387
0
        *save = NULL;
388
    
389
    /*
390
     * if there is no data, return NULL;
391
     */
392
0
    if (!t->count)
393
0
        return 0;
394
395
    /*
396
     * if the table is dirty, sort it.
397
     */
398
0
    if (t->dirty)
399
0
        Sort_Array(c);
400
401
    /*
402
     * search
403
     */
404
0
    if ((index = binary_search(key, c, 1, NULL)) == -1)
405
0
        return -1;
406
407
0
    return netsnmp_binary_array_remove_at(c, (size_t)index, save);
408
0
}
409
410
NETSNMP_STATIC_INLINE void
411
netsnmp_binary_array_for_each(netsnmp_container *c,
412
                              netsnmp_container_obj_func *fe,
413
                              void *context, int sort)
414
3.48k
{
415
3.48k
    binary_array_table *t = (binary_array_table*)c->container_data;
416
3.48k
    size_t             i;
417
418
3.48k
    if (sort && t->dirty)
419
0
        Sort_Array(c);
420
421
45.3k
    for (i = 0; i < t->count; ++i)
422
41.8k
        (*fe) (t->data[i], context);
423
3.48k
}
424
425
NETSNMP_STATIC_INLINE void
426
netsnmp_binary_array_clear(netsnmp_container *c,
427
                           netsnmp_container_obj_func *fe,
428
                           void *context)
429
31.1k
{
430
31.1k
    binary_array_table *t = (binary_array_table*)c->container_data;
431
432
31.1k
    if( NULL != fe ) {
433
17.2k
        size_t             i;
434
435
17.2k
        for (i = 0; i < t->count; ++i)
436
0
            (*fe) (t->data[i], context);
437
17.2k
    }
438
439
31.1k
    t->count = 0;
440
31.1k
    t->dirty = 0;
441
31.1k
    ++c->sync;
442
31.1k
}
443
444
static int
445
_ba_resize_check(binary_array_table *t)
446
42.1k
{
447
42.1k
    size_t new_max;
448
42.1k
    void ** new_data;
449
42.1k
    if (t->max_size > t->count)
450
35.1k
        return 0; /* resize not needed */
451
452
    /*
453
     * Table is full, so extend it to double the size, or use 10 elements
454
     * if it is empty.
455
     */
456
6.98k
    new_max = t->max_size > 0 ? 2 * t->max_size : 10;
457
6.98k
    new_data = (void**) realloc(t->data, new_max * sizeof(void*));
458
6.98k
    if (new_data == NULL) {
459
0
        snmp_log(LOG_ERR, "malloc failed in _ba_resize_check\n");
460
0
        return -1; /* error */
461
0
    }
462
463
6.98k
    memset(new_data + t->max_size, 0x0,
464
6.98k
           (new_max - t->max_size) * sizeof(void*));
465
466
6.98k
    t->data = new_data;
467
6.98k
    t->max_size = new_max;
468
469
6.98k
    return 1; /* resized */
470
6.98k
}
471
472
static int
473
netsnmp_binary_array_insert_before(netsnmp_container *c, size_t index,
474
                                   const void *entry, int dirty)
475
42.1k
{
476
42.1k
    binary_array_table *t = (binary_array_table*)c->container_data;
477
478
42.1k
    if (NULL == entry)
479
0
        return -1;
480
481
42.1k
    if (index > t->count) {
482
0
        DEBUGMSGTL(("container:insert:before", "index out of range\n"));
483
0
        return -1;
484
0
    }
485
486
     /*
487
      * check if we need to resize the array
488
      */
489
42.1k
    _ba_resize_check(t);
490
491
42.1k
    netsnmp_assert(t->count < t->max_size);
492
493
    /*
494
     * shift array
495
     */
496
42.1k
    memmove(&t->data[index+1], &t->data[index],
497
42.1k
            sizeof(void*) * (t->count - index));
498
499
    /*
500
     * Insert the new entry into the data array
501
     */
502
42.1k
    t->data[index] = NETSNMP_REMOVE_CONST(void *, entry);
503
42.1k
    ++t->count;
504
505
42.1k
    netsnmp_assert(index < t->count);
506
42.1k
    netsnmp_assert(t->count <= t->max_size);
507
508
42.1k
    if (dirty)
509
0
        t->dirty = 1;
510
511
42.1k
    netsnmp_assert(t->dirty || _ba_is_sorted(c));
512
513
42.1k
    ++c->sync;
514
515
42.1k
    return 0;
516
42.1k
}
517
518
NETSNMP_STATIC_INLINE int
519
netsnmp_binary_array_insert(netsnmp_container *c, const void *const_entry)
520
42.2k
{
521
42.2k
    binary_array_table *t = (binary_array_table*)c->container_data;
522
42.2k
    const int duplicates_allowed = c->flags & CONTAINER_KEY_ALLOW_DUPLICATES;
523
42.2k
    const int sorted = !(c->flags & CONTAINER_KEY_UNSORTED);
524
42.2k
    int             i = -2;
525
42.2k
    size_t          next, pos;
526
42.2k
    void           *entry = NETSNMP_REMOVE_CONST(void *, const_entry);
527
528
42.2k
    if (NULL == entry)
529
0
        return -1;
530
531
    /*
532
     * check key if we have at least 1 item and duplicates aren't allowed
533
     */
534
42.2k
    if (!duplicates_allowed && t->count) {
535
38.7k
        i = binary_search(entry, c, 1, &next);
536
38.7k
        if (i >= 0) {
537
122
            DEBUGMSGTL(("container","not inserting duplicate key\n"));
538
122
            return -1;
539
122
        }
540
38.7k
    }
541
 
542
    /*
543
     * if unsorted, just add at the end
544
     */
545
42.1k
    if (!sorted) {
546
0
        pos = t->count;
547
42.1k
    } else {
548
        /** if we haven't searched for key yet, do it now */
549
42.1k
        if (-2 == i) {
550
3.49k
            if (0 == t->count) {
551
3.49k
                next = 0;
552
3.49k
                i = -1;
553
3.49k
            } else {
554
0
                i = binary_search(entry, c, 1, &next);
555
0
            }
556
3.49k
        }
557
558
42.1k
        pos = next;
559
        /* if key found, advance past any duplicates */
560
42.1k
        if (duplicates_allowed && i >= 0)
561
0
            while (pos < t->count && c->compare(t->data[pos], entry) == 0)
562
0
                ++pos;
563
42.1k
    }
564
565
42.1k
    return netsnmp_binary_array_insert_before(c, pos, entry, !sorted);
566
42.2k
}
567
568
/**********************************************************************
569
 *
570
 * Special case support for subsets
571
 *
572
 */
573
static int
574
binary_search_for_start(netsnmp_index *val, netsnmp_container *c)
575
0
{
576
0
    binary_array_table *t = (binary_array_table*)c->container_data;
577
0
    size_t             len = t->count;
578
0
    size_t             half;
579
0
    size_t             middle;
580
0
    size_t             first = 0;
581
0
    int                result = 0;
582
583
0
    if (!len)
584
0
        return -1;
585
586
0
    if (t->dirty)
587
0
        Sort_Array(c);
588
589
0
    while (len > 0) {
590
0
        half = len >> 1;
591
0
        middle = first + half;
592
0
        if ((result = c->ncompare(t->data[middle], val)) < 0) {
593
0
            first = middle + 1;
594
0
            len = len - half - 1;
595
0
        } else
596
0
            len = half;
597
0
    }
598
599
0
    if ((first >= t->count) ||
600
0
        c->ncompare(t->data[first], val) != 0)
601
0
        return -1;
602
603
0
    return first;
604
0
}
605
606
void          **
607
netsnmp_binary_array_get_subset(netsnmp_container *c, void *key, int *len)
608
0
{
609
0
    binary_array_table *t;
610
0
    void          **subset;
611
0
    int             start, end, subset_size;
612
0
    size_t          i;
613
614
    /*
615
     * if there is no data, return NULL;
616
     */
617
0
    if (!c || !key || !len)
618
0
        return NULL;
619
620
0
    t = (binary_array_table*)c->container_data;
621
0
    netsnmp_assert(c->ncompare);
622
0
    if (!t->count || !c->ncompare)
623
0
        return NULL;
624
625
    /*
626
     * if the table is dirty, sort it.
627
     */
628
0
    if (t->dirty)
629
0
        Sort_Array(c);
630
631
    /*
632
     * find matching items
633
     */
634
0
    start = end = binary_search_for_start((netsnmp_index *)key, c);
635
    /*
636
     * Although start == end, Coverity doesn't seem to realize this. Hence
637
     * check both 'start' and 'end'.
638
     */
639
0
    if (start < 0 || end < 0 || start >= INT_MAX - 1 || end >= INT_MAX - 1)
640
0
        return NULL;
641
642
0
    for (i = start + 1; i < t->count; ++i) {
643
0
        if (0 != c->ncompare(t->data[i], key))
644
0
            break;
645
0
        if (end >= INT_MAX - 1)
646
0
            break;
647
0
        ++end;
648
0
    }
649
650
0
    *len = end - start + 1;
651
0
    if (*len <= 0 || *len > INT_MAX / sizeof(void*))
652
0
        return NULL;
653
654
0
    subset_size = *len * sizeof(void *);
655
0
    subset = malloc(subset_size);
656
0
    if (subset)
657
0
        memcpy(subset, &t->data[start], subset_size);
658
659
0
    return subset;
660
0
}
661
662
/**********************************************************************
663
 *
664
 * container
665
 *
666
 */
667
static void *
668
_ba_find(netsnmp_container *container, const void *data)
669
135k
{
670
135k
    return netsnmp_binary_array_get(container, data, 1);
671
135k
}
672
673
static void *
674
_ba_find_next(netsnmp_container *container, const void *data)
675
0
{
676
0
    return netsnmp_binary_array_get(container, data, 0);
677
0
}
678
679
static int
680
_ba_insert(netsnmp_container *container, const void *data)
681
42.2k
{
682
42.2k
    return netsnmp_binary_array_insert(container, data);
683
42.2k
}
684
685
static int
686
_ba_insert_before(netsnmp_container *container, size_t index, void *data)
687
0
{
688
    /** don't trust users direct-acces inserts, mark array dirty */
689
0
    return netsnmp_binary_array_insert_before(container, index, data, 1);
690
0
}
691
692
static int
693
_ba_remove(netsnmp_container *container, const void *data)
694
0
{
695
0
    return netsnmp_binary_array_remove(container,data, NULL);
696
0
}
697
698
static int
699
_ba_free(netsnmp_container *container)
700
34.6k
{
701
34.6k
    netsnmp_binary_array_release(container);
702
34.6k
    return 0;
703
34.6k
}
704
705
static size_t
706
_ba_size(netsnmp_container *container)
707
3.43k
{
708
3.43k
    return netsnmp_binary_array_count(container);
709
3.43k
}
710
711
static void
712
_ba_for_each(netsnmp_container *container, netsnmp_container_obj_func *f,
713
             void *context)
714
3.48k
{
715
3.48k
    netsnmp_binary_array_for_each(container, f, context, 1);
716
3.48k
}
717
718
static void
719
_ba_clear(netsnmp_container *container, netsnmp_container_obj_func *f,
720
             void *context)
721
31.1k
{
722
31.1k
    netsnmp_binary_array_clear(container, f, context);
723
31.1k
}
724
725
static netsnmp_void_array *
726
_ba_get_subset(netsnmp_container *container, void *data)
727
0
{
728
0
    netsnmp_void_array * va;
729
0
    void ** rtn;
730
0
    int len;
731
732
0
    rtn = netsnmp_binary_array_get_subset(container, data, &len);
733
0
    if (NULL==rtn)
734
0
        return NULL;
735
    
736
0
    va = SNMP_MALLOC_TYPEDEF(netsnmp_void_array);
737
0
    if (va == NULL) {
738
0
        free(rtn);
739
0
        return NULL;
740
0
    }
741
    
742
0
    va->size = len;
743
0
    va->array = rtn;
744
745
0
    return va;
746
0
}
747
748
static int _ba_options(netsnmp_container *c, int set, u_int flags)
749
13.9k
{
750
13.9k
    return netsnmp_binary_array_options_set(c, set, flags);
751
13.9k
}
752
753
static netsnmp_container *
754
_ba_duplicate(netsnmp_container *c, void *ctx, u_int flags)
755
0
{
756
0
    netsnmp_container *dup;
757
0
    binary_array_table *dupt, *t;
758
759
0
    if (flags) {
760
0
        snmp_log(LOG_ERR, "binary arry duplicate does not supprt flags yet\n");
761
0
        return NULL;
762
0
    }
763
764
0
    dup = netsnmp_container_get_binary_array();
765
0
    if (NULL == dup) {
766
0
        snmp_log(LOG_ERR," no memory for binary array duplicate\n");
767
0
        return NULL;
768
0
    }
769
    /*
770
     * deal with container stuff
771
     */
772
0
    if (netsnmp_container_data_dup(dup, c) != 0) {
773
0
        netsnmp_binary_array_release(dup);
774
0
        return NULL;
775
0
    }
776
777
    /*
778
     * deal with data
779
     */
780
0
    dupt = (binary_array_table*)dup->container_data;
781
0
    t = (binary_array_table*)c->container_data;
782
783
0
    dupt->max_size = t->max_size;
784
0
    dupt->count = t->count;
785
0
    dupt->dirty = t->dirty;
786
787
    /*
788
     * shallow copy
789
     */
790
0
    dupt->data = (void**) malloc(dupt->max_size * sizeof(void*));
791
0
    if (NULL == dupt->data) {
792
0
        snmp_log(LOG_ERR, "no memory for binary array duplicate\n");
793
0
        netsnmp_binary_array_release(dup);
794
0
        return NULL;
795
0
    }
796
797
0
    memcpy(dupt->data, t->data, dupt->max_size * sizeof(void*));
798
799
0
    return dup;
800
0
}
801
802
netsnmp_container *
803
netsnmp_container_get_binary_array(void)
804
34.6k
{
805
    /*
806
     * allocate memory
807
     */
808
34.6k
    netsnmp_container *c = SNMP_MALLOC_TYPEDEF(netsnmp_container);
809
34.6k
    if (NULL==c) {
810
0
        snmp_log(LOG_ERR, "couldn't allocate memory\n");
811
0
        return NULL;
812
0
    }
813
814
34.6k
    c->container_data = netsnmp_binary_array_initialize();
815
34.6k
    if (NULL == c->container_data) {
816
0
        free(c);
817
0
        snmp_log(LOG_ERR, "couldn't allocate memory for container_data\n");
818
0
        return NULL;
819
0
    }
820
821
    /*
822
     * NOTE: CHANGES HERE MUST BE DUPLICATED IN duplicate AS WELL!!
823
     */
824
34.6k
    netsnmp_init_container(c, NULL, _ba_free, _ba_size, NULL, _ba_insert,
825
34.6k
                           _ba_remove, _ba_find);
826
34.6k
    c->find_next = _ba_find_next;
827
34.6k
    c->get_subset = _ba_get_subset;
828
34.6k
    c->get_iterator = _ba_iterator_get;
829
34.6k
    c->for_each = _ba_for_each;
830
34.6k
    c->clear = _ba_clear;
831
34.6k
    c->options = _ba_options;
832
34.6k
    c->duplicate = _ba_duplicate;
833
34.6k
    c->get_at = netsnmp_binary_array_get_at;
834
34.6k
    c->remove_at = netsnmp_binary_array_remove_at;
835
34.6k
    c->insert_before = _ba_insert_before;
836
837
34.6k
    return c;
838
34.6k
}
839
840
netsnmp_factory *
841
netsnmp_container_get_binary_array_factory(void)
842
3.48k
{
843
3.48k
    static netsnmp_factory f = { "binary_array",
844
3.48k
                                 netsnmp_container_get_binary_array };
845
    
846
3.48k
    return &f;
847
3.48k
}
848
849
void
850
netsnmp_container_binary_array_init(void)
851
3.48k
{
852
3.48k
    netsnmp_container_register("binary_array",
853
3.48k
                               netsnmp_container_get_binary_array_factory());
854
3.48k
}
855
856
/**********************************************************************
857
 *
858
 * iterator
859
 *
860
 */
861
NETSNMP_STATIC_INLINE binary_array_table *
862
_ba_it2cont(binary_array_iterator *it)
863
10
{
864
10
    if(NULL == it) {
865
0
        netsnmp_assert(NULL != it);
866
0
        return NULL;
867
0
    }
868
10
    if(NULL == it->base.container) {
869
0
        netsnmp_assert(NULL != it->base.container);
870
0
        return NULL;
871
0
    }
872
10
    if(NULL == it->base.container->container_data) {
873
0
        netsnmp_assert(NULL != it->base.container->container_data);
874
0
        return NULL;
875
0
    }
876
877
10
    return (binary_array_table*)(it->base.container->container_data);
878
10
}
879
880
NETSNMP_STATIC_INLINE void *
881
_ba_iterator_position(binary_array_iterator *it, size_t pos)
882
5
{
883
5
    binary_array_table *t = _ba_it2cont(it);
884
5
    if (NULL == t)
885
0
        return t; /* msg already logged */
886
887
5
    if(it->base.container->sync != it->base.sync) {
888
0
        DEBUGMSGTL(("container:iterator", "out of sync\n"));
889
0
        return NULL;
890
0
    }
891
    
892
5
    if(0 == t->count) {
893
5
        DEBUGMSGTL(("container:iterator", "empty\n"));
894
5
        return NULL;
895
5
    }
896
0
    else if(pos >= t->count) {
897
0
        DEBUGMSGTL(("container:iterator", "end of container\n"));
898
0
        return NULL;
899
0
    }
900
901
0
    return t->data[ pos ];
902
5
}
903
904
static void *
905
_ba_iterator_curr(netsnmp_iterator *nit)
906
0
{
907
0
    binary_array_iterator *it = (void *)nit;
908
909
0
    if(NULL == it) {
910
0
        netsnmp_assert(NULL != it);
911
0
        return NULL;
912
0
    }
913
914
0
    return _ba_iterator_position(it, it->pos);
915
0
}
916
917
static void *
918
_ba_iterator_first(netsnmp_iterator *nit)
919
5
{
920
5
    binary_array_iterator *it = (void *)nit;
921
922
5
    return _ba_iterator_position(it, 0);
923
5
}
924
925
static void *
926
_ba_iterator_next(netsnmp_iterator *nit)
927
0
{
928
0
    binary_array_iterator *it = (void *)nit;
929
930
0
    if(NULL == it) {
931
0
        netsnmp_assert(NULL != it);
932
0
        return NULL;
933
0
    }
934
935
0
    ++it->pos;
936
937
0
    return _ba_iterator_position(it, it->pos);
938
0
}
939
940
static void *
941
_ba_iterator_last(netsnmp_iterator *nit)
942
0
{
943
0
    binary_array_iterator *it = (void *)nit;
944
0
    binary_array_table* t = _ba_it2cont(it);
945
0
    if(NULL == t) {
946
0
        netsnmp_assert(NULL != t);
947
0
        return NULL;
948
0
    }
949
    
950
0
    return _ba_iterator_position(it, t->count - 1 );
951
0
}
952
953
static int
954
_ba_iterator_remove(netsnmp_iterator *nit)
955
0
{
956
0
    binary_array_iterator *it = (void *)nit;
957
0
    binary_array_table* t = _ba_it2cont(it);
958
959
0
    if(NULL == t) {
960
0
        netsnmp_assert(NULL != t);
961
0
        return -1;
962
0
    }
963
964
    /*
965
     * since this iterator was used for the remove, keep it in sync with
966
     * the container. Also, back up one so that next will be the position
967
     * that was just removed.
968
     */
969
0
    ++it->base.sync;
970
0
    return netsnmp_binary_array_remove_at(it->base.container, it->pos--, NULL);
971
972
0
}
973
974
static int
975
_ba_iterator_reset(netsnmp_iterator *nit)
976
5
{
977
5
    binary_array_iterator *it = (void *)nit;
978
5
    binary_array_table* t = _ba_it2cont(it);
979
5
    if(NULL == t) {
980
0
        netsnmp_assert(NULL != t);
981
0
        return -1;
982
0
    }
983
984
5
    if (t->dirty)
985
0
        Sort_Array(it->base.container);
986
987
    /*
988
     * save sync count, to make sure container doesn't change while
989
     * iterator is in use.
990
     */
991
5
    it->base.sync = it->base.container->sync;
992
993
5
    it->pos = 0;
994
995
5
    return 0;
996
5
}
997
998
static int
999
_ba_iterator_release(netsnmp_iterator *it)
1000
5
{
1001
5
    free(it);
1002
1003
5
    return 0;
1004
5
}
1005
1006
static netsnmp_iterator *
1007
_ba_iterator_get(netsnmp_container *c)
1008
5
{
1009
5
    binary_array_iterator* it;
1010
1011
5
    if(NULL == c)
1012
0
        return NULL;
1013
1014
5
    it = SNMP_MALLOC_TYPEDEF(binary_array_iterator);
1015
5
    if(NULL == it)
1016
0
        return NULL;
1017
1018
5
    it->base.container = c;
1019
    
1020
5
    it->base.first = _ba_iterator_first;
1021
5
    it->base.next = _ba_iterator_next;
1022
5
    it->base.curr = _ba_iterator_curr;
1023
5
    it->base.last = _ba_iterator_last;
1024
5
    it->base.remove = _ba_iterator_remove;
1025
5
    it->base.reset = _ba_iterator_reset;
1026
5
    it->base.release = _ba_iterator_release;
1027
1028
5
    (void)_ba_iterator_reset(&it->base);
1029
1030
5
    return &it->base;
1031
5
}