Coverage Report

Created: 2026-08-13 09:19

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