mirror of
https://github.com/samba-team/samba.git
synced 2025-01-21 18:04:06 +03:00
6d66fb308a
This patch makes Samba compile cleanly with -Wwrite-strings. - That is, all string literals are marked as 'const'. These strings are always read only, this just marks them as such for passing to other functions. What is most supprising is that I didn't need to change more than a few lines of code (all in 'net', which got a small cleanup of net.h and extern variables). The rest is just adding a lot of 'const'. As far as I can tell, I have not added any new warnings - apart from making all of tdbutil.c's function const (so they warn for adding that const string to struct). Andrew Bartlett (This used to be commit 92a777d0eaa4fb3a1c7835816f93c6bdd456816d)
465 lines
11 KiB
C
465 lines
11 KiB
C
/*
|
|
* Unix SMB/CIFS implementation.
|
|
* Generic Abstract Data Types
|
|
* Copyright (C) Gerald Carter 2002.
|
|
*
|
|
* This program is free software; you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation; either version 2 of the License, or
|
|
* (at your option) any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program; if not, write to the Free Software
|
|
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
|
*/
|
|
|
|
#include "includes.h"
|
|
|
|
|
|
/**************************************************************************
|
|
Initialize the tree's root. The cmp_fn is a callback function used
|
|
for comparision of two children
|
|
*************************************************************************/
|
|
|
|
static BOOL trim_tree_keypath( char *path, char **base, char **new_path )
|
|
{
|
|
char *p;
|
|
|
|
*new_path = *base = NULL;
|
|
|
|
if ( !path )
|
|
return False;
|
|
|
|
*base = path;
|
|
|
|
p = strchr( path, '/' );
|
|
|
|
if ( p ) {
|
|
*p = '\0';
|
|
*new_path = p+1;
|
|
}
|
|
|
|
return True;
|
|
}
|
|
|
|
|
|
/**************************************************************************
|
|
Initialize the tree's root. The cmp_fn is a callback function used
|
|
for comparision of two children
|
|
*************************************************************************/
|
|
|
|
SORTED_TREE* sorted_tree_init( void *data_p,
|
|
int (cmp_fn)(void*, void*),
|
|
void (free_fn)(void*) )
|
|
{
|
|
SORTED_TREE *tree = NULL;
|
|
|
|
if ( !(tree = (SORTED_TREE*)malloc( sizeof(SORTED_TREE) )) )
|
|
return NULL;
|
|
|
|
ZERO_STRUCTP( tree );
|
|
|
|
tree->compare = cmp_fn;
|
|
tree->free = free_fn;
|
|
|
|
if ( !(tree->root = (TREE_NODE*)malloc( sizeof(TREE_NODE) )) ) {
|
|
SAFE_FREE( tree );
|
|
return NULL;
|
|
}
|
|
|
|
ZERO_STRUCTP( tree->root );
|
|
tree->root->data_p = data_p;
|
|
|
|
return tree;
|
|
}
|
|
|
|
|
|
/**************************************************************************
|
|
Delete a tree and free all allocated memory
|
|
*************************************************************************/
|
|
|
|
static void sorted_tree_destroy_children( TREE_NODE *root )
|
|
{
|
|
int i;
|
|
|
|
if ( !root )
|
|
return;
|
|
|
|
for ( i=0; i<root->num_children; i++ )
|
|
{
|
|
sorted_tree_destroy_children( root->children[i] );
|
|
}
|
|
|
|
SAFE_FREE( root->children );
|
|
SAFE_FREE( root->key );
|
|
|
|
return;
|
|
}
|
|
|
|
/**************************************************************************
|
|
Delete a tree and free all allocated memory
|
|
*************************************************************************/
|
|
|
|
void sorted_tree_destroy( SORTED_TREE *tree )
|
|
{
|
|
if ( tree->root )
|
|
sorted_tree_destroy_children( tree->root );
|
|
|
|
if ( tree->free )
|
|
tree->free( tree->root );
|
|
|
|
SAFE_FREE( tree );
|
|
}
|
|
|
|
/**************************************************************************
|
|
Find the next child given a key string
|
|
*************************************************************************/
|
|
|
|
static TREE_NODE* sorted_tree_birth_child( TREE_NODE *node, char* key )
|
|
{
|
|
TREE_NODE *infant = NULL;
|
|
TREE_NODE **siblings;
|
|
int i;
|
|
|
|
if ( !(infant = (TREE_NODE*)malloc( sizeof(TREE_NODE) )) )
|
|
return NULL;
|
|
|
|
ZERO_STRUCTP( infant );
|
|
|
|
infant->key = strdup( key );
|
|
infant->parent = node;
|
|
|
|
siblings = Realloc( node->children, sizeof(TREE_NODE*)*(node->num_children+1) );
|
|
|
|
if ( siblings )
|
|
node->children = siblings;
|
|
|
|
node->num_children++;
|
|
|
|
/* first child */
|
|
|
|
if ( node->num_children == 1 ) {
|
|
DEBUG(11,("sorted_tree_birth_child: First child of node [%s]! [%s]\n",
|
|
node->key ? node->key : "NULL", infant->key ));
|
|
node->children[0] = infant;
|
|
}
|
|
else
|
|
{
|
|
/*
|
|
* multiple siblings .... (at least 2 children)
|
|
*
|
|
* work from the end of the list forward
|
|
* The last child is not set at this point
|
|
* Insert the new infanct in ascending order
|
|
* from left to right
|
|
*/
|
|
|
|
for ( i = node->num_children-1; i>=1; i-- )
|
|
{
|
|
DEBUG(11,("sorted_tree_birth_child: Looking for crib; infant -> [%s], child -> [%s]\n",
|
|
infant->key, node->children[i-1]->key));
|
|
|
|
/* the strings should never match assuming that we
|
|
have called sorted_tree_find_child() first */
|
|
|
|
if ( StrCaseCmp( infant->key, node->children[i-1]->key ) > 0 ) {
|
|
DEBUG(11,("sorted_tree_birth_child: storing infant in i == [%d]\n",
|
|
i));
|
|
node->children[i] = infant;
|
|
break;
|
|
}
|
|
|
|
/* bump everything towards the end on slot */
|
|
|
|
node->children[i] = node->children[i-1];
|
|
}
|
|
|
|
DEBUG(11,("sorted_tree_birth_child: Exiting loop (i == [%d])\n", i ));
|
|
|
|
/* if we haven't found the correct slot yet, the child
|
|
will be first in the list */
|
|
|
|
if ( i == 0 )
|
|
node->children[0] = infant;
|
|
}
|
|
|
|
return infant;
|
|
}
|
|
|
|
/**************************************************************************
|
|
Find the next child given a key string
|
|
*************************************************************************/
|
|
|
|
static TREE_NODE* sorted_tree_find_child( TREE_NODE *node, char* key )
|
|
{
|
|
TREE_NODE *next = NULL;
|
|
int i, result;
|
|
|
|
if ( !node ) {
|
|
DEBUG(0,("sorted_tree_find_child: NULL node passed into function!\n"));
|
|
return NULL;
|
|
}
|
|
|
|
if ( !key ) {
|
|
DEBUG(0,("sorted_tree_find_child: NULL key string passed into function!\n"));
|
|
return NULL;
|
|
}
|
|
|
|
for ( i=0; i<node->num_children; i++ )
|
|
{
|
|
DEBUG(11,("sorted_tree_find_child: child key => [%s]\n",
|
|
node->children[i]->key));
|
|
|
|
result = StrCaseCmp( node->children[i]->key, key );
|
|
|
|
if ( result == 0 )
|
|
next = node->children[i];
|
|
|
|
/* if result > 0 then we've gone to far because
|
|
the list of children is sorted by key name
|
|
If result == 0, then we have a match */
|
|
|
|
if ( result > 0 )
|
|
break;
|
|
}
|
|
|
|
DEBUG(11,("sorted_tree_find_child: %s [%s]\n",
|
|
next ? "Found" : "Did not find", key ));
|
|
|
|
return next;
|
|
}
|
|
|
|
/**************************************************************************
|
|
Add a new node into the tree given a key path and a blob of data
|
|
*************************************************************************/
|
|
|
|
BOOL sorted_tree_add( SORTED_TREE *tree, const char *path, void *data_p )
|
|
{
|
|
char *str, *base, *path2;
|
|
TREE_NODE *current, *next;
|
|
BOOL ret = True;
|
|
|
|
DEBUG(8,("sorted_tree_add: Enter\n"));
|
|
|
|
if ( !path || *path != '/' ) {
|
|
DEBUG(0,("sorted_tree_add: Attempt to add a node with a bad path [%s]\n",
|
|
path ? path : "NULL" ));
|
|
return False;
|
|
}
|
|
|
|
if ( !tree ) {
|
|
DEBUG(0,("sorted_tree_add: Attempt to add a node to an uninitialized tree!\n"));
|
|
return False;
|
|
}
|
|
|
|
/* move past the first '/' */
|
|
|
|
path++;
|
|
path2 = strdup( path );
|
|
if ( !path2 ) {
|
|
DEBUG(0,("sorted_tree_add: strdup() failed on string [%s]!?!?!\n", path));
|
|
return False;
|
|
}
|
|
|
|
|
|
/*
|
|
* this works sort of like a 'mkdir -p' call, possibly
|
|
* creating an entire path to the new node at once
|
|
* The path should be of the form /<key1>/<key2>/...
|
|
*/
|
|
|
|
base = path2;
|
|
str = path2;
|
|
current = tree->root;
|
|
|
|
do {
|
|
/* break off the remaining part of the path */
|
|
|
|
str = strchr( str, '/' );
|
|
if ( str )
|
|
*str = '\0';
|
|
|
|
/* iterate to the next child--birth it if necessary */
|
|
|
|
next = sorted_tree_find_child( current, base );
|
|
if ( !next ) {
|
|
next = sorted_tree_birth_child( current, base );
|
|
if ( !next ) {
|
|
DEBUG(0,("sorted_tree_add: Failed to create new child!\n"));
|
|
ret = False;
|
|
goto done;
|
|
}
|
|
}
|
|
current = next;
|
|
|
|
/* setup the next part of the path */
|
|
|
|
base = str;
|
|
if ( base ) {
|
|
*base = '/';
|
|
base++;
|
|
str = base;
|
|
}
|
|
|
|
} while ( base != NULL );
|
|
|
|
current->data_p = data_p;
|
|
|
|
DEBUG(10,("sorted_tree_add: Successfully added node [%s] to tree\n",
|
|
path ));
|
|
|
|
DEBUG(8,("sorted_tree_add: Exit\n"));
|
|
|
|
done:
|
|
SAFE_FREE( path2 );
|
|
return ret;
|
|
}
|
|
|
|
|
|
/**************************************************************************
|
|
Recursive routine to print out all children of a TREE_NODE
|
|
*************************************************************************/
|
|
|
|
static void sorted_tree_print_children( TREE_NODE *node, int debug, const char *path )
|
|
{
|
|
int i;
|
|
int num_children;
|
|
pstring path2;
|
|
|
|
if ( !node )
|
|
return;
|
|
|
|
|
|
if ( node->key )
|
|
DEBUG(debug,("%s: [%s] (%s)\n", path ? path : "NULL", node->key,
|
|
node->data_p ? "data" : "NULL" ));
|
|
|
|
*path2 = '\0';
|
|
if ( path )
|
|
pstrcpy( path2, path );
|
|
pstrcat( path2, node->key ? node->key : "NULL" );
|
|
pstrcat( path2, "/" );
|
|
|
|
num_children = node->num_children;
|
|
for ( i=0; i<num_children; i++ )
|
|
sorted_tree_print_children( node->children[i], debug, path2 );
|
|
|
|
|
|
}
|
|
|
|
/**************************************************************************
|
|
Dump the kys for a tree to the log file
|
|
*************************************************************************/
|
|
|
|
void sorted_tree_print_keys( SORTED_TREE *tree, int debug )
|
|
{
|
|
int i;
|
|
int num_children = tree->root->num_children;
|
|
|
|
if ( tree->root->key )
|
|
DEBUG(debug,("ROOT/: [%s] (%s)\n", tree->root->key,
|
|
tree->root->data_p ? "data" : "NULL" ));
|
|
|
|
for ( i=0; i<num_children; i++ ) {
|
|
sorted_tree_print_children( tree->root->children[i], debug,
|
|
tree->root->key ? tree->root->key : "ROOT/" );
|
|
}
|
|
|
|
}
|
|
|
|
/**************************************************************************
|
|
return the data_p for for the node in tree matching the key string
|
|
The key string is the full path. We must break it apart and walk
|
|
the tree
|
|
*************************************************************************/
|
|
|
|
void* sorted_tree_find( SORTED_TREE *tree, char *key )
|
|
{
|
|
char *keystr, *base, *str, *p;
|
|
TREE_NODE *current;
|
|
void *result = NULL;
|
|
|
|
DEBUG(10,("sorted_tree_find: Enter [%s]\n", key ? key : "NULL" ));
|
|
|
|
/* sanity checks first */
|
|
|
|
if ( !key ) {
|
|
DEBUG(0,("sorted_tree_find: Attempt to search tree using NULL search string!\n"));
|
|
return NULL;
|
|
}
|
|
|
|
if ( !tree ) {
|
|
DEBUG(0,("sorted_tree_find: Attempt to search an uninitialized tree using string [%s]!\n",
|
|
key ? key : "NULL" ));
|
|
return NULL;
|
|
}
|
|
|
|
if ( !tree->root )
|
|
return NULL;
|
|
|
|
/* make a copy to play with */
|
|
|
|
if ( *key == '/' )
|
|
keystr = strdup( key+1 );
|
|
else
|
|
keystr = strdup( key );
|
|
|
|
if ( !keystr ) {
|
|
DEBUG(0,("sorted_tree_find: strdup() failed on string [%s]!?!?!\n", key));
|
|
return NULL;
|
|
}
|
|
|
|
/* start breaking the path apart */
|
|
|
|
p = keystr;
|
|
current = tree->root;
|
|
|
|
if ( tree->root->data_p )
|
|
result = tree->root->data_p;
|
|
|
|
do
|
|
{
|
|
/* break off the remaining part of the path */
|
|
|
|
trim_tree_keypath( p, &base, &str );
|
|
|
|
DEBUG(11,("sorted_tree_find: [loop] base => [%s], new_path => [%s]\n",
|
|
base, str));
|
|
|
|
/* iterate to the next child */
|
|
|
|
current = sorted_tree_find_child( current, base );
|
|
|
|
/*
|
|
* the idea is that the data_p for a parent should
|
|
* be inherited by all children, but allow it to be
|
|
* overridden farther down
|
|
*/
|
|
|
|
if ( current && current->data_p )
|
|
result = current->data_p;
|
|
|
|
/* reset the path pointer 'p' to the remaining part of the key string */
|
|
|
|
p = str;
|
|
|
|
} while ( str && current );
|
|
|
|
/* result should be the data_p from the lowest match node in the tree */
|
|
if ( result )
|
|
DEBUG(11,("sorted_tree_find: Found data_p!\n"));
|
|
|
|
SAFE_FREE( keystr );
|
|
|
|
DEBUG(10,("sorted_tree_find: Exit\n"));
|
|
|
|
return result;
|
|
}
|
|
|
|
|