/* Unix SMB/Netbios implementation. Version 1.9. Samba utility functions Copyright (C) Andrew Tridgell 1992-1999 Copyright (C) Gerald Carter <jerry@samba.org> 2000 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. */ /**************************************************************** In order to make use of the GENERIC_LIST data structure, you should create wrapper functions around: BOOL generic_list_insert() void* generic_list_remove() void* generic_list_locate() The reason this is necessary is that the GENERIC_LIST uses a void pointer to store your data structure. This means that you get no type checking and can create a hetergenous list. However, you will need to have some way to determine the type of your data. If you are using a homogenous list, then wrapper functions are the easiest way. If you are creating a hetergenous list, then you will need to use the type field for your arbitrary identifiers. TODO: If neccessary, you can add a few generic_list_*() to do things like grab from the front (to implement a FIFO queue) or from the tail (to implement a FILO stack) ****************************************************************/ #include "includes.h" /* * list variables */ static GENERIC_LIST hnds; /**************************************************************** Initialize the list. This doesn't do much currently. Just make sure that you call it so we can determine wether the list is empty or not. ****************************************************************/ static void generic_list_init(GENERIC_LIST *l) { l->head = NULL; l->tail = NULL; l->length = 0; l->initialized = True; return; } /***************************************************************** Insert some data into the list (appended to the end of the list) *****************************************************************/ static BOOL generic_list_insert(GENERIC_LIST *l, void *item, uint8 type) { /* check for an emtpy list first */ if (l->length == 0) { if ((l->head = malloc(sizeof(struct _list_node))) == NULL) { DEBUG(0, ("ERROR: out of memory! Cannot allocate a list node!\n")); return False; } l->head->data = item; l->head->type = type; l->head->next = NULL; l->length++; l->tail = l->head; } /* we already have an existing list */ else { if ((l->tail->next = malloc(sizeof(struct _list_node))) == NULL) { DEBUG(0, ("ERROR: out of memory! Cannot allocate a list node!\n")); return False; } l->tail = l->tail->next; l->tail->next = NULL; l->tail->data = item; l->tail->type = type; l->length++; } /* return the list pointer in case this was the first node */ return True; } /**************************************************************** In order to locate an item in the list we need a pointer to a compare function for the data items. We will return the actual pointer to the item in the list. Not a copy of the item. ****************************************************************/ static void* generic_list_locate (GENERIC_LIST *l, void *search, BOOL(*cmp)(const void*,const void*)) { struct _list_node *item; /* loop through the list in linear order */ item = l->head; while (item != NULL) { if (cmp(search, item->data)) return item->data; else { item = item->next; } } return NULL; } /*************************************************************** In order to remove a node from the list, we will need a pointer to a compare function. The function will return a pointer to data in the removed node. **WARNING** It is the responsibility of the caller to save the pointer and destroy the data. ***************************************************************/ static void* generic_list_remove(GENERIC_LIST *l, void *search, BOOL(*cmp)(const void*,const void*)) { struct _list_node *item, *tag; void *data_ptr; /* loop through the list in linear order */ tag = NULL; item = l->head; while (item != NULL) { /* did we find it? If so remove the node */ if (cmp(search, item->data)) { /* found, so remove the node */ /* remove the first item in the list */ if (item == l->head) l->head = item->next; /* remove from the middle or the end */ else tag->next = item->next; /* check to see if we need to update the tail */ if (l->tail == item) l->tail = tag; l->length--; data_ptr = item->data; free(item); return data_ptr; } /* increment to the nbext node in the list */ else { tag = item; item = item->next; } } return NULL; } /************************************************************** copy a POLICY_HND *************************************************************/ BOOL copy_policy_hnd (POLICY_HND *dest, const POLICY_HND *src) { /* if we have no destination, return an error */ if (dest == NULL) return False; /* if the src handle is NULL, then copy 0x00 to the dest handle */ if (src == NULL) { /* if POLICY_HND internals ever changes, this will need to be fixed */ ZERO_STRUCTP(dest); return True; } *dest = *src; return True; } /* ------------------------------------------------------------- Functions to implement the RpcHandle list -------------------------------------------------------------- */ /*************************************************************** Return True if the to RPC_HND_NODEs are eqivalent in value. Return False if they are not. Since a POLICY_HND is really a UUID, two RPC_HND_NODES are considered to be the same if the POLICY_HND value matches. No ordering betweeen the two is attempted. **************************************************************/ BOOL compare_rpc_hnd_node(const RPC_HND_NODE *x, const RPC_HND_NODE *y) { /* only compare valid nodes */ if (x==NULL || y==NULL) return FALSE; /* if the POLICY_HND field(s) are ever changed, this will need to be updated. Probably should be a set of support function for dealing with POLICY_HND */ return (memcmp(&x->hnd, &y->hnd, sizeof(POLICY_HND)) == 0); } /*************************************************************** associate a POLICY_HND with a cli_connection **************************************************************/ BOOL RpcHndList_set_connection(const POLICY_HND *hnd, struct cli_connection *con) { RPC_HND_NODE *node = NULL; /* initialize the list if necessary */ if (!hnds.initialized) generic_list_init(&hnds); /* allocate a node to insert */ if ((node=(RPC_HND_NODE*)malloc(sizeof(RPC_HND_NODE))) == NULL) { DEBUG(0, ("ERROR: Unable to allocate memory for an RPC_HND_NODE!\n")); return False; } /* fill in the RPC_HND_NODE */ copy_policy_hnd (&node->hnd, hnd); node->cli = con; /* insert the node into the list: The 3rd parameter is set to 0 since we don't care anything about the type field */ return (generic_list_insert(&hnds, (void*)node, 0)); } /************************************************************************ delete a POLICY_HND (and associated cli_connection) from the list ***********************************************************************/ BOOL RpcHndList_del_connection(const POLICY_HND *hnd) { RPC_HND_NODE node, *located; /* return NULL if the list has not been initialized */ if (!hnds.initialized) return False; /* fill in the RPC_HND_NODE */ copy_policy_hnd (&node.hnd, hnd); node.cli = NULL; /* search for the POLICY_HND */ located = (RPC_HND_NODE*)generic_list_remove(&hnds, &node, (BOOL(*)(const void*, const void*))compare_rpc_hnd_node); if (located == NULL) return False; /* delete the information */ cli_connection_free(located->cli); free(located); return True; } /************************************************************************ search for a POLICY_HND and return a pointer to the associated cli_connection struct in the list **********************************************************************/ struct cli_connection* RpcHndList_get_connection(const POLICY_HND *hnd) { RPC_HND_NODE node, *located; /* return NULL if the list has not been initialized */ if (!hnds.initialized) return NULL; /* fill in the RPC_HND_NODE */ copy_policy_hnd (&node.hnd, hnd); node.cli = NULL; /* search for the POLICY_HND */ located = (RPC_HND_NODE*)generic_list_locate(&hnds, &node, (BOOL(*)(const void*, const void*))compare_rpc_hnd_node); if (located == NULL) return NULL; else return located->cli; }