Coverage Report

Created: 2024-05-20 06:31

/src/clamav/libclamav/table.c
Line
Count
Source (jump to first uncovered line)
1
/*
2
 *  Copyright (C) 2013-2024 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
3
 *  Copyright (C) 2007-2013 Sourcefire, Inc.
4
 *
5
 *  Authors: Nigel Horne
6
 *
7
 *  This program is free software; you can redistribute it and/or modify
8
 *  it under the terms of the GNU General Public License version 2 as
9
 *  published by the Free Software Foundation.
10
 *
11
 *  This program is distributed in the hope that it will be useful,
12
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
13
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14
 *  GNU General Public License for more details.
15
 *
16
 *  You should have received a copy of the GNU General Public License
17
 *  along with this program; if not, write to the Free Software
18
 *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
19
 *  MA 02110-1301, USA.
20
 *
21
 * TODO: Allow individual items to be updated or removed
22
 *
23
 * It is up to the caller to create a mutex for the table if needed
24
 */
25
26
#if HAVE_CONFIG_H
27
#include "clamav-config.h"
28
#endif
29
30
#include <stdlib.h>
31
#include <string.h>
32
#ifdef HAVE_STRINGS_H
33
#include <strings.h>
34
#endif
35
#include <assert.h>
36
37
#include "clamav.h"
38
#include "table.h"
39
#include "others.h"
40
41
struct table *
42
tableCreate(void)
43
36.3k
{
44
36.3k
    return (struct table *)calloc(1, sizeof(struct table));
45
36.3k
}
46
47
void tableDestroy(table_t *table)
48
36.3k
{
49
36.3k
    tableEntry *tableItem;
50
51
36.3k
    assert(table != NULL);
52
53
36.3k
    tableItem = table->tableHead;
54
55
108k
    while (tableItem) {
56
72.6k
        tableEntry *tableNext = tableItem->next;
57
58
72.6k
        if (tableItem->key)
59
72.6k
            free(tableItem->key);
60
72.6k
        free(tableItem);
61
62
72.6k
        tableItem = tableNext;
63
72.6k
    }
64
65
36.3k
    free(table);
66
36.3k
}
67
68
/*
69
 * Returns the value, or -1 for failure
70
 */
71
int tableInsert(table_t *table, const char *key, int value)
72
72.7k
{
73
72.7k
    const int v = tableFind(table, key);
74
75
72.7k
    if (v > 0)                            /* duplicate key */
76
0
        return (v == value) ? value : -1; /* allow real dups */
77
78
72.7k
    assert(value != -1); /* that would confuse us */
79
80
72.7k
    if (table->tableHead == NULL)
81
36.3k
        table->tableLast = table->tableHead = (tableEntry *)malloc(sizeof(tableEntry));
82
36.4k
    else {
83
        /*
84
         * Re-use deleted items
85
         */
86
36.4k
        if (table->flags & TABLE_HAS_DELETED_ENTRIES) {
87
0
            tableEntry *tableItem;
88
89
0
            assert(table->tableHead != NULL);
90
91
0
            for (tableItem = table->tableHead; tableItem; tableItem = tableItem->next)
92
0
                if (tableItem->key == NULL) {
93
                    /* This item has been deleted */
94
0
                    tableItem->key   = cli_safer_strdup(key);
95
0
                    tableItem->value = value;
96
0
                    return value;
97
0
                }
98
99
0
            table->flags &= ~TABLE_HAS_DELETED_ENTRIES;
100
0
        }
101
102
36.4k
        table->tableLast = table->tableLast->next =
103
36.4k
            (tableEntry *)malloc(sizeof(tableEntry));
104
36.4k
    }
105
106
72.7k
    if (table->tableLast == NULL) {
107
0
        cli_dbgmsg("tableInsert: Unable to allocate memory for table\n");
108
0
        return -1;
109
0
    }
110
111
72.7k
    table->tableLast->next  = NULL;
112
72.7k
    table->tableLast->key   = cli_safer_strdup(key);
113
72.7k
    table->tableLast->value = value;
114
115
72.7k
    return value;
116
72.7k
}
117
118
/*
119
 * Returns the value - -1 for not found. This means the value of a valid key
120
 *  can't be -1 :-(
121
 *
122
 * Linear search. Since tables are rarely more than 3 or 4 in size, and never
123
 *  reach double figures, there's no need for optimization
124
 */
125
int tableFind(const table_t *table, const char *key)
126
19.6M
{
127
19.6M
    const tableEntry *tableItem;
128
#ifdef CL_DEBUG
129
    int cost;
130
#endif
131
132
19.6M
    assert(table != NULL);
133
134
19.6M
    if (key == NULL)
135
0
        return -1; /* not treated as a fatal error */
136
137
#ifdef CL_DEBUG
138
    cost = 0;
139
#endif
140
141
90.0M
    for (tableItem = table->tableHead; tableItem; tableItem = tableItem->next) {
142
#ifdef CL_DEBUG
143
        cost++;
144
#endif
145
79.3M
        if (tableItem->key && (strcasecmp(tableItem->key, key) == 0)) {
146
#ifdef CL_DEBUG
147
            cli_dbgmsg("tableFind: Cost of '%s' = %d\n", key, cost);
148
#endif
149
8.89M
            return tableItem->value;
150
8.89M
        }
151
79.3M
    }
152
153
10.7M
    return -1; /* not found */
154
19.6M
}
155
156
/*
157
 * Change a value in the table. If the key isn't in the table insert it
158
 * Returns -1 for error, otherwise the new value
159
 */
160
int tableUpdate(table_t *table, const char *key, int new_value)
161
0
{
162
0
    tableEntry *tableItem;
163
164
0
    assert(table != NULL);
165
166
0
    if (key == NULL)
167
0
        return -1; /* not treated as a fatal error */
168
169
0
    for (tableItem = table->tableHead; tableItem; tableItem = tableItem->next)
170
0
        if (tableItem->key && (strcasecmp(tableItem->key, key) == 0)) {
171
0
            tableItem->value = new_value;
172
0
            return new_value;
173
0
        }
174
175
    /* not found */
176
0
    return tableInsert(table, key, new_value);
177
0
}
178
179
/*
180
 * Remove an item from the table
181
 */
182
void tableRemove(table_t *table, const char *key)
183
0
{
184
0
    tableEntry *tableItem;
185
186
0
    assert(table != NULL);
187
188
0
    if (key == NULL)
189
0
        return; /* not treated as a fatal error */
190
191
0
    for (tableItem = table->tableHead; tableItem; tableItem = tableItem->next)
192
0
        if (tableItem->key && (strcasecmp(tableItem->key, key) == 0)) {
193
0
            free(tableItem->key);
194
0
            tableItem->key = NULL;
195
0
            table->flags |= TABLE_HAS_DELETED_ENTRIES;
196
            /* don't break, duplicate keys are allowed */
197
0
        }
198
0
}
199
200
void tableIterate(table_t *table, void (*callback)(char *key, int value, void *arg), void *arg)
201
0
{
202
0
    tableEntry *tableItem;
203
204
0
    if (table == NULL)
205
0
        return;
206
207
0
    for (tableItem = table->tableHead; tableItem; tableItem = tableItem->next)
208
0
        if (tableItem->key) /* check node has not been deleted */
209
0
            (*callback)(tableItem->key, tableItem->value, arg);
210
0
}