2 * Unix SMB/CIFS implementation.
3 * Generic Abstract Data Types
4 * Copyright (C) Gerald Carter 2002.
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 3 of the License, or
9 * (at your option) any later version.
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.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, see <http://www.gnu.org/licenses/>.
22 #include "lib/util/debug.h"
23 #include "lib/util/samba_util.h"
24 #include "util/charset/charset.h"
25 #include "source3/include/smb_macros.h"
29 struct tree_node
*parent
;
30 struct tree_node
**children
;
37 struct tree_node
*root
;
40 /**************************************************************************
41 *************************************************************************/
43 static bool trim_tree_keypath( char *path
, char **base
, char **new_path
)
47 *new_path
= *base
= NULL
;
54 p
= strchr( path
, '\\' );
64 /**************************************************************************
65 Initialize the tree's root.
66 *************************************************************************/
68 struct sorted_tree
*pathtree_init(void *data_p
)
70 struct sorted_tree
*tree
= NULL
;
72 tree
= talloc_zero(NULL
, struct sorted_tree
);
77 tree
->root
= talloc_zero(tree
, struct tree_node
);
78 if (tree
->root
== NULL
) {
83 tree
->root
->data_p
= data_p
;
89 /**************************************************************************
90 Find the next child given a key string
91 *************************************************************************/
93 static struct tree_node
*pathtree_birth_child(struct tree_node
*node
,
96 struct tree_node
*infant
= NULL
;
97 struct tree_node
**siblings
;
100 infant
= talloc_zero(node
, struct tree_node
);
101 if (infant
== NULL
) {
105 infant
->key
= talloc_strdup( infant
, key
);
106 infant
->parent
= node
;
108 siblings
= talloc_realloc(node
, node
->children
, struct tree_node
*,
109 node
->num_children
+1);
112 node
->children
= siblings
;
114 node
->num_children
++;
118 if ( node
->num_children
== 1 ) {
119 DEBUG(11,("pathtree_birth_child: First child of node [%s]! [%s]\n",
120 node
->key
? node
->key
: "NULL", infant
->key
));
121 node
->children
[0] = infant
;
126 * multiple siblings .... (at least 2 children)
128 * work from the end of the list forward
129 * The last child is not set at this point
130 * Insert the new infanct in ascending order
134 for ( i
= node
->num_children
-1; i
>=1; i
-- )
136 DEBUG(11,("pathtree_birth_child: Looking for crib; infant -> [%s], child -> [%s]\n",
137 infant
->key
, node
->children
[i
-1]->key
));
139 /* the strings should never match assuming that we
140 have called pathtree_find_child() first */
142 if ( strcasecmp_m( infant
->key
, node
->children
[i
-1]->key
) > 0 ) {
143 DEBUG(11,("pathtree_birth_child: storing infant in i == [%d]\n",
145 node
->children
[i
] = infant
;
149 /* bump everything towards the end on slot */
151 node
->children
[i
] = node
->children
[i
-1];
154 DEBUG(11,("pathtree_birth_child: Exiting loop (i == [%d])\n", i
));
156 /* if we haven't found the correct slot yet, the child
157 will be first in the list */
160 node
->children
[0] = infant
;
166 /**************************************************************************
167 Find the next child given a key string
168 *************************************************************************/
170 static struct tree_node
*pathtree_find_child(struct tree_node
*node
,
173 struct tree_node
*next
= NULL
;
177 DEBUG(0,("pathtree_find_child: NULL node passed into function!\n"));
182 DEBUG(0,("pathtree_find_child: NULL key string passed into function!\n"));
186 for ( i
=0; i
<node
->num_children
; i
++ )
188 DEBUG(11,("pathtree_find_child: child key => [%s]\n",
189 node
->children
[i
]->key
));
191 result
= strcasecmp_m( node
->children
[i
]->key
, key
);
194 next
= node
->children
[i
];
196 /* if result > 0 then we've gone to far because
197 the list of children is sorted by key name
198 If result == 0, then we have a match */
204 DEBUG(11,("pathtree_find_child: %s [%s]\n",
205 next
? "Found" : "Did not find", key
));
210 /**************************************************************************
211 Add a new node into the tree given a key path and a blob of data
212 *************************************************************************/
214 bool pathtree_add(struct sorted_tree
*tree
, const char *path
, void *data_p
)
216 char *str
, *base
, *path2
;
217 struct tree_node
*current
, *next
;
220 DEBUG(8,("pathtree_add: Enter\n"));
222 if ( !path
|| *path
!= '\\' ) {
223 DEBUG(0,("pathtree_add: Attempt to add a node with a bad path [%s]\n",
224 path
? path
: "NULL" ));
229 DEBUG(0,("pathtree_add: Attempt to add a node to an uninitialized tree!\n"));
233 /* move past the first '\\' */
236 path2
= SMB_STRDUP( path
);
238 DEBUG(0,("pathtree_add: strdup() failed on string [%s]!?!?!\n", path
));
244 * this works sort of like a 'mkdir -p' call, possibly
245 * creating an entire path to the new node at once
246 * The path should be of the form /<key1>/<key2>/...
251 current
= tree
->root
;
254 /* break off the remaining part of the path */
256 str
= strchr( str
, '\\' );
260 /* iterate to the next child--birth it if necessary */
262 next
= pathtree_find_child( current
, base
);
264 next
= pathtree_birth_child( current
, base
);
266 DEBUG(0,("pathtree_add: Failed to create new child!\n"));
273 /* setup the next part of the path */
282 } while ( base
!= NULL
);
284 current
->data_p
= data_p
;
286 DEBUG(10,("pathtree_add: Successfully added node [%s] to tree\n",
289 DEBUG(8,("pathtree_add: Exit\n"));
297 /**************************************************************************
298 Recursive routine to print out all children of a struct tree_node
299 *************************************************************************/
301 static void pathtree_print_children(TALLOC_CTX
*ctx
,
302 struct tree_node
*node
,
314 DEBUG(debug
,("%s: [%s] (%s)\n", path
? path
: "NULL", node
->key
,
315 node
->data_p
? "data" : "NULL" ));
318 path2
= talloc_strdup(ctx
, path
);
324 path2
= talloc_asprintf(ctx
,
327 node
->key
? node
->key
: "NULL");
332 num_children
= node
->num_children
;
333 for ( i
=0; i
<num_children
; i
++ ) {
334 pathtree_print_children(ctx
, node
->children
[i
], debug
, path2
);
338 /**************************************************************************
339 Dump the kys for a tree to the log file
340 *************************************************************************/
342 void pathtree_print_keys(struct sorted_tree
*tree
, int debug
)
345 int num_children
= tree
->root
->num_children
;
347 if ( tree
->root
->key
)
348 DEBUG(debug
,("ROOT/: [%s] (%s)\n", tree
->root
->key
,
349 tree
->root
->data_p
? "data" : "NULL" ));
351 for ( i
=0; i
<num_children
; i
++ ) {
352 TALLOC_CTX
*ctx
= talloc_stackframe();
353 pathtree_print_children(ctx
, tree
->root
->children
[i
], debug
,
354 tree
->root
->key
? tree
->root
->key
: "ROOT/" );
360 /**************************************************************************
361 return the data_p for for the node in tree matching the key string
362 The key string is the full path. We must break it apart and walk
364 *************************************************************************/
366 void* pathtree_find(struct sorted_tree
*tree
, char *key
)
368 char *keystr
, *base
= NULL
, *str
= NULL
, *p
;
369 struct tree_node
*current
;
372 DEBUG(10,("pathtree_find: Enter [%s]\n", key
? key
: "NULL" ));
374 /* sanity checks first */
377 DEBUG(0,("pathtree_find: Attempt to search tree using NULL search string!\n"));
382 DEBUG(0,("pathtree_find: Attempt to search an uninitialized tree using string [%s]!\n",
383 key
? key
: "NULL" ));
390 /* make a copy to play with */
393 keystr
= SMB_STRDUP( key
+1 );
395 keystr
= SMB_STRDUP( key
);
398 DEBUG(0,("pathtree_find: strdup() failed on string [%s]!?!?!\n", key
));
402 /* start breaking the path apart */
405 current
= tree
->root
;
407 if ( tree
->root
->data_p
)
408 result
= tree
->root
->data_p
;
412 /* break off the remaining part of the path */
414 trim_tree_keypath( p
, &base
, &str
);
416 DEBUG(11,("pathtree_find: [loop] base => [%s], new_path => [%s]\n",
420 /* iterate to the next child */
422 current
= pathtree_find_child( current
, base
);
425 * the idea is that the data_p for a parent should
426 * be inherited by all children, but allow it to be
427 * overridden farther down
430 if ( current
&& current
->data_p
)
431 result
= current
->data_p
;
433 /* reset the path pointer 'p' to the remaining part of the key string */
437 } while ( str
&& current
);
439 /* result should be the data_p from the lowest match node in the tree */
441 DEBUG(11,("pathtree_find: Found data_p!\n"));
445 DEBUG(10,("pathtree_find: Exit\n"));