27
38
static bool trim_tree_keypath( char *path, char **base, char **new_path )
31
42
*new_path = *base = NULL;
38
p = strchr( path, '/' );
49
p = strchr( path, '\\' );
49
59
/**************************************************************************
50
Initialize the tree's root. The cmp_fn is a callback function used
51
for comparision of two children
60
Initialize the tree's root.
52
61
*************************************************************************/
54
SORTED_TREE* pathtree_init( void *data_p, int (cmp_fn)(void*, void*) )
63
struct sorted_tree *pathtree_init(void *data_p)
56
SORTED_TREE *tree = NULL;
58
if ( !(tree = TALLOC_ZERO_P(NULL, SORTED_TREE)) )
65
struct sorted_tree *tree = NULL;
67
tree = talloc_zero(NULL, struct sorted_tree);
61
tree->compare = cmp_fn;
63
if ( !(tree->root = TALLOC_ZERO_P(tree, TREE_NODE)) ) {
72
tree->root = talloc_zero(tree, struct tree_node);
73
if (tree->root == NULL) {
64
74
TALLOC_FREE( tree );
68
78
tree->root->data_p = data_p;
75
85
Find the next child given a key string
76
86
*************************************************************************/
78
static TREE_NODE* pathtree_birth_child( TREE_NODE *node, char* key )
88
static struct tree_node *pathtree_birth_child(struct tree_node *node,
80
TREE_NODE *infant = NULL;
91
struct tree_node *infant = NULL;
92
struct tree_node **siblings;
84
if ( !(infant = TALLOC_ZERO_P( node, TREE_NODE)) )
95
infant = talloc_zero(node, struct tree_node);
87
100
infant->key = talloc_strdup( infant, key );
88
101
infant->parent = node;
90
siblings = TALLOC_REALLOC_ARRAY( node, node->children, TREE_NODE *, node->num_children+1 );
103
siblings = talloc_realloc(node, node->children, struct tree_node *,
104
node->num_children+1);
93
107
node->children = siblings;
95
109
node->num_children++;
99
113
if ( node->num_children == 1 ) {
100
114
DEBUG(11,("pathtree_birth_child: First child of node [%s]! [%s]\n",
101
115
node->key ? node->key : "NULL", infant->key ));
111
125
* Insert the new infanct in ascending order
112
126
* from left to right
115
129
for ( i = node->num_children-1; i>=1; i-- )
117
131
DEBUG(11,("pathtree_birth_child: Looking for crib; infant -> [%s], child -> [%s]\n",
118
132
infant->key, node->children[i-1]->key));
120
134
/* the strings should never match assuming that we
121
135
have called pathtree_find_child() first */
123
137
if ( StrCaseCmp( infant->key, node->children[i-1]->key ) > 0 ) {
124
138
DEBUG(11,("pathtree_birth_child: storing infant in i == [%d]\n",
126
140
node->children[i] = infant;
130
144
/* bump everything towards the end on slot */
132
146
node->children[i] = node->children[i-1];
135
149
DEBUG(11,("pathtree_birth_child: Exiting loop (i == [%d])\n", i ));
137
151
/* if we haven't found the correct slot yet, the child
138
152
will be first in the list */
141
155
node->children[0] = infant;
148
162
Find the next child given a key string
149
163
*************************************************************************/
151
static TREE_NODE* pathtree_find_child( TREE_NODE *node, char* key )
165
static struct tree_node *pathtree_find_child(struct tree_node *node,
153
TREE_NODE *next = NULL;
168
struct tree_node *next = NULL;
157
172
DEBUG(0,("pathtree_find_child: NULL node passed into function!\n"));
162
177
DEBUG(0,("pathtree_find_child: NULL key string passed into function!\n"));
166
181
for ( i=0; i<node->num_children; i++ )
168
183
DEBUG(11,("pathtree_find_child: child key => [%s]\n",
169
184
node->children[i]->key));
171
186
result = StrCaseCmp( node->children[i]->key, key );
173
188
if ( result == 0 )
174
189
next = node->children[i];
176
191
/* if result > 0 then we've gone to far because
177
192
the list of children is sorted by key name
178
193
If result == 0, then we have a match */
180
195
if ( result > 0 )
184
199
DEBUG(11,("pathtree_find_child: %s [%s]\n",
185
200
next ? "Found" : "Did not find", key ));
191
206
Add a new node into the tree given a key path and a blob of data
192
207
*************************************************************************/
194
WERROR pathtree_add( SORTED_TREE *tree, const char *path, void *data_p )
209
WERROR pathtree_add(struct sorted_tree *tree, const char *path, void *data_p)
196
211
char *str, *base, *path2;
197
TREE_NODE *current, *next;
212
struct tree_node *current, *next;
198
213
WERROR ret = WERR_OK;
200
215
DEBUG(8,("pathtree_add: Enter\n"));
202
if ( !path || *path != '/' ) {
217
if ( !path || *path != '\\' ) {
203
218
DEBUG(0,("pathtree_add: Attempt to add a node with a bad path [%s]\n",
204
219
path ? path : "NULL" ));
205
220
return WERR_INVALID_PARAM;
209
224
DEBUG(0,("pathtree_add: Attempt to add a node to an uninitialized tree!\n"));
210
225
return WERR_INVALID_PARAM;
213
/* move past the first '/' */
228
/* move past the first '\\' */
216
231
path2 = SMB_STRDUP( path );
218
233
DEBUG(0,("pathtree_add: strdup() failed on string [%s]!?!?!\n", path));
219
234
return WERR_NOMEM;
224
239
* this works sort of like a 'mkdir -p' call, possibly
225
240
* creating an entire path to the new node at once
226
241
* The path should be of the form /<key1>/<key2>/...
231
246
current = tree->root;
234
249
/* break off the remaining part of the path */
236
str = strchr( str, '/' );
251
str = strchr( str, '\\' );
240
255
/* iterate to the next child--birth it if necessary */
242
257
next = pathtree_find_child( current, base );
244
259
next = pathtree_birth_child( current, base );
253
268
/* setup the next part of the path */
262
277
} while ( base != NULL );
264
279
current->data_p = data_p;
266
281
DEBUG(10,("pathtree_add: Successfully added node [%s] to tree\n",
277
292
/**************************************************************************
278
Recursive routine to print out all children of a TREE_NODE
293
Recursive routine to print out all children of a struct tree_node
279
294
*************************************************************************/
281
296
static void pathtree_print_children(TALLOC_CTX *ctx,
297
struct tree_node *node,
284
299
const char *path )
319
334
Dump the kys for a tree to the log file
320
335
*************************************************************************/
322
void pathtree_print_keys( SORTED_TREE *tree, int debug )
337
void pathtree_print_keys(struct sorted_tree *tree, int debug )
325
340
int num_children = tree->root->num_children;
344
359
*************************************************************************/
346
void* pathtree_find( SORTED_TREE *tree, char *key )
361
void* pathtree_find(struct sorted_tree *tree, char *key )
348
363
char *keystr, *base = NULL, *str = NULL, *p;
364
struct tree_node *current;
350
365
void *result = NULL;
352
367
DEBUG(10,("pathtree_find: Enter [%s]\n", key ? key : "NULL" ));
354
369
/* sanity checks first */
357
372
DEBUG(0,("pathtree_find: Attempt to search tree using NULL search string!\n"));
362
377
DEBUG(0,("pathtree_find: Attempt to search an uninitialized tree using string [%s]!\n",
363
378
key ? key : "NULL" ));
367
382
if ( !tree->root )
370
385
/* make a copy to play with */
373
388
keystr = SMB_STRDUP( key+1 );
375
390
keystr = SMB_STRDUP( key );
378
393
DEBUG(0,("pathtree_find: strdup() failed on string [%s]!?!?!\n", key));
382
397
/* start breaking the path apart */
385
400
current = tree->root;
387
402
if ( tree->root->data_p )
388
403
result = tree->root->data_p;
392
407
/* break off the remaining part of the path */
394
409
trim_tree_keypath( p, &base, &str );
396
411
DEBUG(11,("pathtree_find: [loop] base => [%s], new_path => [%s]\n",
397
412
base ? base : "",
398
413
str ? str : ""));
400
415
/* iterate to the next child */
402
417
current = pathtree_find_child( current, base );
405
420
* the idea is that the data_p for a parent should
406
421
* be inherited by all children, but allow it to be
407
422
* overridden farther down
410
425
if ( current && current->data_p )
411
426
result = current->data_p;
413
428
/* reset the path pointer 'p' to the remaining part of the key string */
417
432
} while ( str && current );
419
434
/* result should be the data_p from the lowest match node in the tree */
421
436
DEBUG(11,("pathtree_find: Found data_p!\n"));
423
438
SAFE_FREE( keystr );
425
440
DEBUG(10,("pathtree_find: Exit\n"));