/* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License, Version 1.0 only * (the "License"). You may not use this file except in compliance * with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* * Copyright (c) 2002-2003, Network Appliance, Inc. All rights reserved. */ /* * Copyright 2004 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ /* * Copyright (c) 2018, Joyent, Inc. */ /* * * MODULE: dat_dictionary.c * * PURPOSE: dictionary data structure * * $Id: dat_dictionary.c,v 1.11 2003/08/05 19:01:48 jlentini Exp $ */ #include "dat_dictionary.h" /* * * Structures * */ typedef struct DAT_DICTIONARY_NODE { DAT_PROVIDER_INFO key; DAT_DICTIONARY_DATA data; struct DAT_DICTIONARY_NODE *prev; struct DAT_DICTIONARY_NODE *next; } DAT_DICTIONARY_NODE; struct DAT_DICTIONARY { DAT_DICTIONARY_NODE *head; DAT_DICTIONARY_NODE *tail; DAT_COUNT size; }; /* * * Function Declarations * */ static DAT_RETURN dat_dictionary_key_dup( const DAT_PROVIDER_INFO *old_key, DAT_PROVIDER_INFO *new_key); static DAT_BOOLEAN dat_dictionary_key_is_equal( const DAT_PROVIDER_INFO *key_a, const DAT_PROVIDER_INFO *key_b); /* * * External Functions * */ /* * Function: dat_dictionary_create */ DAT_RETURN dat_dictionary_create( OUT DAT_DICTIONARY **pp_dictionary) { DAT_DICTIONARY *p_dictionary; DAT_RETURN status; dat_os_assert(NULL != pp_dictionary); status = DAT_SUCCESS; /* create the dictionary */ p_dictionary = dat_os_alloc(sizeof (DAT_DICTIONARY)); if (NULL == p_dictionary) { status = DAT_ERROR(DAT_INSUFFICIENT_RESOURCES, DAT_RESOURCE_MEMORY); goto bail; } (void) dat_os_memset(p_dictionary, '\0', sizeof (DAT_DICTIONARY)); /* create the head node */ p_dictionary->head = dat_os_alloc(sizeof (DAT_DICTIONARY_NODE)); if (NULL == p_dictionary->head) { status = DAT_ERROR(DAT_INSUFFICIENT_RESOURCES, DAT_RESOURCE_MEMORY); goto bail; } (void) dat_os_memset(p_dictionary->head, '\0', sizeof (DAT_DICTIONARY_NODE)); /* create the tail node */ p_dictionary->tail = dat_os_alloc(sizeof (DAT_DICTIONARY_NODE)); if (NULL == p_dictionary->tail) { status = DAT_ERROR(DAT_INSUFFICIENT_RESOURCES, DAT_RESOURCE_MEMORY); goto bail; } (void) dat_os_memset(p_dictionary->tail, '\0', sizeof (DAT_DICTIONARY_NODE)); p_dictionary->head->next = p_dictionary->tail; p_dictionary->tail->prev = p_dictionary->head; *pp_dictionary = p_dictionary; bail: if (DAT_SUCCESS != status) { if (NULL != p_dictionary) { if (NULL != p_dictionary->head) { dat_os_free(p_dictionary->head, sizeof (DAT_DICTIONARY_NODE)); } if (NULL != p_dictionary->tail) { dat_os_free(p_dictionary->tail, sizeof (DAT_DICTIONARY_NODE)); } dat_os_free(p_dictionary, sizeof (DAT_DICTIONARY)); } } return (status); } /* * Function: dat_dictionary_destroy */ DAT_RETURN dat_dictionary_destroy( IN DAT_DICTIONARY *p_dictionary) { DAT_DICTIONARY_NODE *cur_node; dat_os_assert(NULL != p_dictionary); while (NULL != p_dictionary->head) { cur_node = p_dictionary->head; p_dictionary->head = cur_node->next; dat_os_free(cur_node, sizeof (DAT_DICTIONARY_NODE)); } dat_os_free(p_dictionary, sizeof (DAT_DICTIONARY)); return (DAT_SUCCESS); } /* * Function: dat_dictionary_size */ DAT_RETURN dat_dictionary_size( IN DAT_DICTIONARY *p_dictionary, OUT DAT_COUNT *p_size) { dat_os_assert(NULL != p_dictionary); dat_os_assert(NULL != p_size); *p_size = p_dictionary->size; return (DAT_SUCCESS); } /* * Function: dat_dictionary_entry_create */ DAT_RETURN dat_dictionary_entry_create( OUT DAT_DICTIONARY_ENTRY *p_entry) { DAT_DICTIONARY_NODE *node; DAT_RETURN dat_status; dat_os_assert(NULL != p_entry); dat_status = DAT_SUCCESS; node = dat_os_alloc(sizeof (DAT_DICTIONARY_NODE)); if (NULL == node) { dat_status = DAT_ERROR(DAT_INSUFFICIENT_RESOURCES, DAT_RESOURCE_MEMORY); goto bail; } *p_entry = node; bail: return (dat_status); } /* * Function: dat_dictionary_entry_destroy */ DAT_RETURN dat_dictionary_entry_destroy( OUT DAT_DICTIONARY_ENTRY entry) { dat_os_free(entry, sizeof (DAT_DICTIONARY_NODE)); return (DAT_SUCCESS); } /* * Function: dat_dictionary_insert */ DAT_RETURN dat_dictionary_insert( IN DAT_DICTIONARY *p_dictionary, IN DAT_DICTIONARY_ENTRY entry, IN const DAT_PROVIDER_INFO *key, IN DAT_DICTIONARY_DATA data) { DAT_RETURN dat_status; DAT_DICTIONARY_NODE *cur_node, *prev_node, *next_node; dat_os_assert(NULL != p_dictionary); dat_os_assert(NULL != entry); cur_node = entry; if (DAT_SUCCESS == dat_dictionary_search(p_dictionary, key, NULL)) { dat_status = DAT_ERROR(DAT_PROVIDER_ALREADY_REGISTERED, 0); goto bail; } dat_status = dat_dictionary_key_dup(key, &cur_node->key); if (DAT_SUCCESS != dat_status) { goto bail; } /* insert node at end of list to preserve registration order */ prev_node = p_dictionary->tail->prev; next_node = p_dictionary->tail; cur_node->data = data; cur_node->next = next_node; cur_node->prev = prev_node; prev_node->next = cur_node; next_node->prev = cur_node; p_dictionary->size++; bail: return (dat_status); } /* * Function: dat_dictionary_search */ DAT_RETURN dat_dictionary_search( IN DAT_DICTIONARY *p_dictionary, IN const DAT_PROVIDER_INFO *key, OUT DAT_DICTIONARY_DATA *p_data) { DAT_DICTIONARY_NODE *cur_node; DAT_RETURN status; dat_os_assert(NULL != p_dictionary); status = DAT_ERROR(DAT_NAME_NOT_FOUND, 0); for (cur_node = p_dictionary->head->next; p_dictionary->tail != cur_node; cur_node = cur_node->next) { if (DAT_TRUE == dat_dictionary_key_is_equal(&cur_node->key, key)) { if (NULL != p_data) { *p_data = cur_node->data; } status = DAT_SUCCESS; goto bail; } } bail: return (status); } /* * Function: dat_dictionary_enumerate */ DAT_RETURN dat_dictionary_enumerate( IN DAT_DICTIONARY *p_dictionary, IN DAT_DICTIONARY_DATA array[], IN DAT_COUNT array_size) { DAT_DICTIONARY_NODE *cur_node; DAT_COUNT i; DAT_RETURN status; dat_os_assert(NULL != p_dictionary); dat_os_assert(NULL != array); status = DAT_SUCCESS; if (array_size < p_dictionary->size) { status = DAT_ERROR(DAT_INSUFFICIENT_RESOURCES, 0); goto bail; } for (cur_node = p_dictionary->head->next, i = 0; p_dictionary->tail != cur_node; cur_node = cur_node->next, i++) { array[i] = cur_node->data; } bail: return (status); } /* * Function: dat_dictionary_remove */ DAT_RETURN dat_dictionary_remove( IN DAT_DICTIONARY *p_dictionary, IN DAT_DICTIONARY_ENTRY *p_entry, IN const DAT_PROVIDER_INFO *key, OUT DAT_DICTIONARY_DATA *p_data) { DAT_DICTIONARY_NODE *cur_node, *prev_node, *next_node; DAT_RETURN status; dat_os_assert(NULL != p_dictionary); dat_os_assert(NULL != p_entry); status = DAT_ERROR(DAT_NAME_NOT_FOUND, 0); for (cur_node = p_dictionary->head->next; p_dictionary->tail != cur_node; cur_node = cur_node->next) { if (DAT_TRUE == dat_dictionary_key_is_equal(&cur_node->key, key)) { if (NULL != p_data) { *p_data = cur_node->data; } prev_node = cur_node->prev; next_node = cur_node->next; prev_node->next = next_node; next_node->prev = prev_node; *p_entry = cur_node; p_dictionary->size--; status = DAT_SUCCESS; goto bail; } } bail: return (status); } /* * * Internal Function Definitions * */ /* * Function: dat_dictionary_key_create */ DAT_RETURN dat_dictionary_key_dup( const DAT_PROVIDER_INFO *old_key, DAT_PROVIDER_INFO *new_key) { dat_os_assert(NULL != old_key); dat_os_assert(NULL != new_key); (void) dat_os_strncpy(new_key->ia_name, old_key->ia_name, DAT_NAME_MAX_LENGTH); new_key->dapl_version_major = old_key->dapl_version_major; new_key->dapl_version_minor = old_key->dapl_version_minor; new_key->is_thread_safe = old_key->is_thread_safe; return (DAT_SUCCESS); } /* * Function: dat_dictionary_key_is_equal */ DAT_BOOLEAN dat_dictionary_key_is_equal( const DAT_PROVIDER_INFO *key_a, const DAT_PROVIDER_INFO *key_b) { if ((dat_os_strlen(key_a->ia_name) == dat_os_strlen(key_b->ia_name)) && (!dat_os_strncmp(key_a->ia_name, key_b->ia_name, dat_os_strlen(key_a->ia_name))) && (key_a->dapl_version_major == key_b->dapl_version_major) && (key_a->dapl_version_minor == key_b->dapl_version_minor) && (key_a->is_thread_safe == key_b->is_thread_safe)) { return (DAT_TRUE); } else { return (DAT_FALSE); } }