Coverage Report

Created: 2023-06-07 06:43

/src/net-snmp/snmplib/dir_utils.c
Line
Count
Source (jump to first uncovered line)
1
/* Portions of this file are subject to the following copyright(s).  See
2
 * the Net-SNMP's COPYING file for more details and other copyrights
3
 * that may apply:
4
 */
5
/*
6
 * Portions of this file are copyrighted by:
7
 * Copyright (C) 2007 Apple, Inc. All rights reserved.
8
 * Use is subject to license terms specified in the COPYING file
9
 * distributed with the Net-SNMP package.
10
 */
11
#include <net-snmp/net-snmp-config.h>
12
#include <net-snmp/net-snmp-features.h>
13
#include <net-snmp/net-snmp-includes.h>
14
15
#include <stdio.h>
16
#include <ctype.h>
17
#ifdef HAVE_STDLIB_H
18
#   include <stdlib.h>
19
#endif
20
#ifdef HAVE_UNISTD_H
21
#   include <unistd.h>
22
#endif
23
#ifdef HAVE_STRING_H
24
#   include <string.h>
25
#else
26
#  include <strings.h>
27
#endif
28
29
#include <sys/types.h>
30
#ifdef HAVE_LIMITS_H
31
#include <limits.h>
32
#endif
33
#ifdef HAVE_SYS_STAT_H
34
#include <sys/stat.h>
35
#endif
36
#ifdef HAVE_DIRENT_H
37
# include <dirent.h>
38
#endif
39
40
#include <errno.h>
41
42
#include <net-snmp/types.h>
43
#include <net-snmp/library/container.h>
44
#include <net-snmp/library/file_utils.h>
45
#include <net-snmp/library/dir_utils.h>
46
47
netsnmp_feature_child_of(container_directory, container_types);
48
#ifdef NETSNMP_FEATURE_REQUIRE_CONTAINER_DIRECTORY
49
netsnmp_feature_require(file_utils);
50
netsnmp_feature_require(container_free_all);
51
#endif /* NETSNMP_FEATURE_REQUIRE_CONTAINER_DIRECTORY */
52
53
#ifndef NETSNMP_FEATURE_REMOVE_CONTAINER_DIRECTORY
54
static int
55
_insert_nsfile( netsnmp_container *c, const char *name, struct stat *stats,
56
                u_int flags);
57
58
/*
59
 * read file names in a directory, with an optional filter
60
 */
61
netsnmp_container *
62
netsnmp_directory_container_read_some(netsnmp_container *user_container,
63
                                      const char *dirname,
64
                                      netsnmp_directory_filter *filter,
65
                                      void *filter_ctx, u_int flags)
66
0
{
67
0
    DIR               *dir;
68
0
    netsnmp_container *container = user_container;
69
0
    struct dirent     *file;
70
0
    char               path[SNMP_MAXPATH];
71
0
    size_t             dirname_len;
72
0
    int                rc;
73
0
    struct stat        statbuf;
74
0
    netsnmp_file       ns_file_tmp;
75
76
0
    if ((flags & NETSNMP_DIR_RELATIVE_PATH) && (flags & NETSNMP_DIR_RECURSE)) {
77
0
        DEBUGMSGTL(("directory:container",
78
0
                    "no support for relative path with recursion\n"));
79
0
        return NULL;
80
0
    }
81
82
0
    DEBUGMSGTL(("directory:container", "reading %s\n", dirname));
83
84
    /*
85
     * create the container, if needed
86
     */
87
0
    if (NULL == container) {
88
0
        if (flags & NETSNMP_DIR_NSFILE) {
89
0
            container = netsnmp_container_find("nsfile_directory_container:"
90
0
                                               "binary_array");
91
0
            if (container) {
92
0
                container->compare = (netsnmp_container_compare*)
93
0
                    netsnmp_file_compare_name;
94
0
                container->free_item = (netsnmp_container_obj_func *)
95
0
                    netsnmp_file_container_free;
96
0
            }
97
0
        }
98
0
        else
99
0
            container = netsnmp_container_find("directory_container:cstring");
100
0
        if (NULL == container)
101
0
            return NULL;
102
0
        container->container_name = strdup(dirname);
103
        /** default to unsorted */
104
0
        if (! (flags & NETSNMP_DIR_SORTED))
105
0
            CONTAINER_SET_OPTIONS(container, CONTAINER_KEY_UNSORTED, rc);
106
        /** default to duplicates not allowed */
107
0
        if (! (flags & NETSNMP_DIR_ALLOW_DUPLICATES))
108
0
           CONTAINER_SET_OPTIONS(container, CONTAINER_KEY_ALLOW_DUPLICATES, rc);
109
0
    }
110
111
0
    dir = opendir(dirname);
112
0
    if (NULL == dir) {
113
0
        DEBUGMSGTL(("directory:container", "  not a dir\n"));
114
0
        if (container != user_container)
115
0
            netsnmp_directory_container_free(container);
116
0
        return NULL;
117
0
    }
118
119
    /** copy dirname into path */
120
0
    if (flags & NETSNMP_DIR_RELATIVE_PATH)
121
0
        dirname_len = 0;
122
0
    else {
123
0
        dirname_len = strlen(dirname);
124
0
        strlcpy(path, dirname, sizeof(path));
125
0
        if ((dirname_len + 2) > sizeof(path)) {
126
            /** not enough room for files */
127
0
            closedir(dir);
128
0
            if (container != user_container)
129
0
                netsnmp_directory_container_free(container);
130
0
            return NULL;
131
0
        }
132
0
        path[dirname_len] = '/';
133
0
        path[++dirname_len] = '\0';
134
0
    }
135
136
    /** iterate over dir */
137
0
    while ((file = readdir(dir))) {
138
0
        if (file->d_name[0] == 0)
139
0
            continue;
140
141
        /** skip '.' and '..' */
142
0
        if ((file->d_name[0] == '.') &&
143
0
            ((file->d_name[1] == 0) ||
144
0
             ((file->d_name[1] == '.') && ((file->d_name[2] == 0)))))
145
0
            continue;
146
147
0
        strlcpy(&path[dirname_len], file->d_name, sizeof(path) - dirname_len);
148
0
        if (NULL != filter) {
149
0
            if (flags & NETSNMP_DIR_NSFILE_STATS) {
150
                /** use local vars for now */
151
0
                if (stat(path, &statbuf) != 0) {
152
0
                    snmp_log(LOG_ERR, "could not stat %s\n", file->d_name);
153
0
                    break;
154
0
                }
155
0
                ns_file_tmp.stats = &statbuf;
156
0
                ns_file_tmp.name = path;
157
0
                rc = (*filter)(&ns_file_tmp, filter_ctx);
158
0
            }
159
0
            else
160
0
                rc = (*filter)(path, filter_ctx);
161
0
            if (0 == rc) {
162
0
                DEBUGMSGTL(("directory:container:filtered", "%s\n",
163
0
                            file->d_name));
164
0
                continue;
165
0
            }
166
0
        }
167
168
0
        DEBUGMSGTL(("directory:container:found", "%s\n", path));
169
0
        if ((flags & NETSNMP_DIR_RECURSE) 
170
0
#if defined(HAVE_STRUCT_DIRENT_D_TYPE) && defined(DT_DIR)
171
0
            && (file->d_type == DT_DIR)
172
#elif defined(S_ISDIR)
173
            && (stat(file->d_name, &statbuf) != 0) && (S_ISDIR(statbuf.st_mode))
174
#endif
175
0
            ) {
176
            /** xxx add the dir as well? not for now.. maybe another flag? */
177
0
            netsnmp_directory_container_read(container, path, flags);
178
0
        }
179
0
        else if (flags & NETSNMP_DIR_NSFILE) {
180
0
            if (_insert_nsfile( container, file->d_name,
181
0
                                filter ? &statbuf : NULL, flags ) < 0)
182
0
                break;
183
0
        }
184
0
        else {
185
0
            char *dup = strdup(path);
186
0
            if (NULL == dup) {
187
0
                snmp_log(LOG_ERR,
188
0
                         "strdup failed while building directory container\n");
189
0
                break;
190
0
            }
191
0
            rc = CONTAINER_INSERT(container, dup);
192
0
            if (-1 == rc ) {
193
0
                DEBUGMSGTL(("directory:container", "  err adding %s\n", path));
194
0
                free(dup);
195
0
            }
196
0
        }
197
0
    } /* while */
198
199
0
    closedir(dir);
200
201
0
    rc = CONTAINER_SIZE(container);
202
0
    DEBUGMSGTL(("directory:container", "  container now has %d items\n", rc));
203
0
    if ((0 == rc) && !(flags & NETSNMP_DIR_EMPTY_OK)) {
204
0
        netsnmp_directory_container_free(container);
205
0
        return NULL;
206
0
    }
207
    
208
0
    return container;
209
0
}
210
211
void
212
netsnmp_directory_container_free(netsnmp_container *container)
213
0
{
214
0
    CONTAINER_FREE_ALL(container, NULL);
215
0
    CONTAINER_FREE(container);
216
0
}
217
218
static int
219
_insert_nsfile( netsnmp_container *c, const char *name, struct stat *stats,
220
                u_int flags)
221
0
{
222
0
    int           rc;
223
0
    netsnmp_file *ns_file = netsnmp_file_new(name, 0, 0, 0);
224
0
    if (NULL == ns_file) {
225
0
        snmp_log(LOG_ERR, "error creating ns_file\n");
226
0
        return -1;
227
0
    }
228
229
0
    if (flags & NETSNMP_DIR_NSFILE_STATS) {
230
0
        ns_file->stats = calloc(1,sizeof(*(ns_file->stats)));
231
0
        if (NULL == ns_file->stats) {
232
0
            snmp_log(LOG_ERR, "error creating stats for ns_file\n");
233
0
            netsnmp_file_release(ns_file);
234
0
            return -1;
235
0
        }
236
    
237
        /** use stats from earlier if we have them */
238
0
        if (stats) {
239
0
            memcpy(ns_file->stats, stats, sizeof(*stats));
240
0
        } else if (stat(ns_file->name, ns_file->stats) < 0) {
241
0
            snmp_log(LOG_ERR, "stat() failed for ns_file\n");
242
0
            netsnmp_file_release(ns_file);
243
0
            return -1;
244
0
        }
245
0
    }
246
247
0
    rc = CONTAINER_INSERT(c, ns_file);
248
0
    if (-1 == rc ) {
249
0
        DEBUGMSGTL(("directory:container", "  err adding %s\n", name));
250
0
        netsnmp_file_release(ns_file);
251
0
    }
252
253
0
    return 0;
254
0
}
255
#else  /* NETSNMP_FEATURE_REMOVE_CONTAINER_DIRECTORY */
256
netsnmp_feature_unused(container_directory);
257
#endif /* NETSNMP_FEATURE_REMOVE_CONTAINER_DIRECTORY */