new upstream release (3.3.0); modify package compatibility for Stretch
[ossec-hids.git] / src / shared / dirtree_op.c
1 /* Copyright (C) 2009 Trend Micro Inc.
2  * All rights reserved.
3  *
4  * This program is a free software; you can redistribute it
5  * and/or modify it under the terms of the GNU General Public
6  * License (version 2) as published by the FSF - Free Software
7  * Foundation.
8  */
9
10 /* Common API for dealing with directory trees */
11
12 #include "shared.h"
13
14 static OSDirTree *_OSTreeNode_Add(OSDirTree *tree, const char *str,
15                                   void *data, char sep) __attribute__((nonnull(2)));
16
17
18 /* Create the tree
19  * Returns NULL on error
20  */
21 OSDirTree *OSDirTree_Create()
22 {
23     OSDirTree *my_tree;
24
25     my_tree = (OSDirTree *) calloc(1, sizeof(OSDirTree));
26     if (!my_tree) {
27         return (NULL);
28     }
29
30     my_tree->first_node = NULL;
31     my_tree->last_node = NULL;
32
33     return (my_tree);
34 }
35
36 /* Get first node from tree (starting from parent)
37  * Returns null on invalid tree (not initialized)
38  */
39 OSTreeNode *OSDirTree_GetFirstNode(OSDirTree *tree)
40 {
41     return (tree->first_node);
42 }
43
44 /* Look for an entry in the middle of the tree
45  * Should not be called directly
46  */
47 static OSDirTree *_OSTreeNode_Add(OSDirTree *tree, const char *str,
48                                   void *data, char sep)
49 {
50     char *tmp_str;
51     OSTreeNode *newnode;
52     OSTreeNode *curnode;
53
54     /* Look for a next entry */
55     tmp_str = strchr(str, sep);
56     if (tmp_str) {
57         *tmp_str = '\0';
58     }
59
60     /* Create new tree */
61     if (!tree) {
62         tree = (OSDirTree *) calloc(1, sizeof(OSDirTree));
63         if (!tree) {
64             return (NULL);
65         }
66
67         tree->first_node = NULL;
68         tree->last_node = NULL;
69     }
70
71     curnode = tree->first_node;
72
73     /* Loop over all nodes */
74     while (curnode) {
75         if (strcmp(curnode->value, str) == 0) {
76             /* If we have other elements, keep going */
77             if (tmp_str) {
78                 curnode->child = _OSTreeNode_Add(curnode->child,
79                                                  tmp_str + 1, data, sep);
80             }
81             break;
82         }
83         curnode = curnode->next;
84     }
85
86     /* Add a new entry, if not found */
87     if (!curnode) {
88         os_calloc(1, sizeof(OSTreeNode), newnode);
89
90         if (!tree->first_node && !tree->last_node) {
91             tree->last_node = newnode;
92             tree->first_node = newnode;
93         } else {
94             tree->last_node->next = newnode;
95         }
96
97         newnode->next = NULL;
98         tree->last_node = newnode;
99         os_strdup(str, newnode->value);
100
101         /* If we have other elements, keep going */
102         if (tmp_str) {
103             newnode->child = _OSTreeNode_Add(newnode->child,
104                                              tmp_str + 1, data, sep);
105             newnode->data = NULL;
106         }
107         /* Otherwise, set the data in here */
108         else {
109             newnode->data = data;
110             newnode->child = NULL;
111         }
112     }
113
114     /* Fix the string back */
115     if (tmp_str) {
116         *tmp_str = sep;
117     }
118
119     return (tree);
120 }
121
122 /* Add a new string to the tree, setting the data at the final leaf.
123  * The tree will be divided by the "separator", where each token
124  * will delimit the child.
125  * For example, /etc/my/name.conf will become:
126  *              /etc/
127  *                   -> /my
128  *                        -> /name.conf
129  * Str must not be NULL.
130  */
131 void OSDirTree_AddToTree(OSDirTree *tree, const char *str, void *data, char sep)
132 {
133     char *tmp_str;
134     OSTreeNode *newnode;
135     OSTreeNode *curnode;
136
137     /* First character doesn't count as a separator */
138     tmp_str = strchr(str + 1, sep);
139     if (tmp_str) {
140         *tmp_str = '\0';
141     }
142
143     curnode = tree->first_node;
144     while (curnode) {
145         if (strcmp(str, curnode->value) == 0) {
146             /* If we have other elements, keep going */
147             if (tmp_str) {
148                 curnode->child = _OSTreeNode_Add(curnode->child,
149                                                  tmp_str + 1, data, sep);
150             }
151             break;
152         }
153
154         curnode = curnode->next;
155     }
156
157     /* If we didn't find an entry, create one */
158     if (!curnode) {
159         os_calloc(1, sizeof(OSTreeNode), newnode);
160         printf("XX Adding MAIN node: %s\n", str);
161
162         if (!tree->first_node && !tree->last_node) {
163             tree->last_node = newnode;
164             tree->first_node = newnode;
165         } else {
166             printf("XXX last new node: %s\n", tree->last_node->value);
167             tree->last_node->next = newnode;
168             tree->last_node = newnode;
169         }
170
171         newnode->next = NULL;
172         os_strdup(str, newnode->value);
173
174         /* If we have other elements, keep going */
175         if (tmp_str) {
176             newnode->child = _OSTreeNode_Add(newnode->child,
177                                              tmp_str + 1, data, sep);
178             newnode->data = NULL;
179         }
180         /* Otherwise, set the data in here */
181         else {
182             newnode->data = data;
183             newnode->child = NULL;
184         }
185     }
186
187     /* Fix the string back */
188     if (tmp_str) {
189         *tmp_str = sep;
190     }
191
192     return;
193 }
194
195 void *OSDirTree_SearchTree(const OSDirTree *tree, const char *str, char sep)
196 {
197     void *ret = NULL;
198     char *tmp_str;
199     const OSTreeNode *curnode;
200
201     /* First character doesn't count as a separator */
202     tmp_str = strchr(str + 1, sep);
203     if (tmp_str) {
204         *tmp_str = '\0';
205     }
206
207     printf("looking for: %s\n", str);
208
209     /* If our tree is not empty, look for the main entry */
210     curnode = tree->first_node;
211     while (curnode) {
212         printf("comparing: '%s' and '%s'\n", str, curnode->value);
213         if (strcmp(str, curnode->value) == 0) {
214             printf("found node: %s\n", str);
215
216             /* If we have other elements, keep going */
217             if (tmp_str) {
218                 ret = OSDirTree_SearchTree(curnode->child, tmp_str + 1, sep);
219             } else {
220                 ret = curnode->data;
221             }
222             break;
223         }
224
225         curnode = curnode->next;
226     }
227
228     /* Fix the string back */
229     if (tmp_str) {
230         *tmp_str = sep;
231     }
232
233     return (ret);
234 }