1 /*
   2  * CDDL HEADER START
   3  *
   4  * The contents of this file are subject to the terms of the
   5  * Common Development and Distribution License, Version 1.0 only
   6  * (the "License").  You may not use this file except in compliance
   7  * with the License.
   8  *
   9  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
  10  * or http://www.opensolaris.org/os/licensing.
  11  * See the License for the specific language governing permissions
  12  * and limitations under the License.
  13  *
  14  * When distributing Covered Code, include this CDDL HEADER in each
  15  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
  16  * If applicable, add the following below this CDDL HEADER, with the
  17  * fields enclosed by brackets "[]" replaced with your own identifying
  18  * information: Portions Copyright [yyyy] [name of copyright owner]
  19  *
  20  * CDDL HEADER END
  21  */
  22 /*
  23  * Copyright (c) 2002-2003, Network Appliance, Inc. All rights reserved.
  24  */
  25 
  26 /*
  27  * Copyright 2004 Sun Microsystems, Inc.  All rights reserved.
  28  * Use is subject to license terms.
  29  */
  30 
  31 #pragma ident   "%Z%%M% %I%     %E% SMI"
  32 
  33 /*
  34  *
  35  * MODULE: dat_dictionary.c
  36  *
  37  * PURPOSE: dictionary data structure
  38  *
  39  * $Id: dat_dictionary.c,v 1.11 2003/08/05 19:01:48 jlentini Exp $
  40  */
  41 
  42 
  43 #include "dat_dictionary.h"
  44 
  45 
  46 /*
  47  *
  48  * Structures
  49  *
  50  */
  51 
  52 typedef struct DAT_DICTIONARY_NODE
  53 {
  54     DAT_PROVIDER_INFO           key;
  55     DAT_DICTIONARY_DATA         data;
  56     struct DAT_DICTIONARY_NODE  *prev;
  57     struct DAT_DICTIONARY_NODE  *next;
  58 } DAT_DICTIONARY_NODE;
  59 
  60 
  61 struct DAT_DICTIONARY
  62 {
  63     DAT_DICTIONARY_NODE         *head;
  64     DAT_DICTIONARY_NODE         *tail;
  65     DAT_COUNT                   size;
  66 };
  67 
  68 /*
  69  *
  70  * Function Declarations
  71  *
  72  */
  73 
  74 static DAT_RETURN
  75 dat_dictionary_key_dup(
  76     const DAT_PROVIDER_INFO     *old_key,
  77     DAT_PROVIDER_INFO           *new_key);
  78 
  79 static DAT_BOOLEAN
  80 dat_dictionary_key_is_equal(
  81     const DAT_PROVIDER_INFO     *key_a,
  82     const DAT_PROVIDER_INFO     *key_b);
  83 
  84 
  85 /*
  86  *
  87  * External Functions
  88  *
  89  */
  90 
  91 
  92 /*
  93  * Function: dat_dictionary_create
  94  */
  95 
  96 DAT_RETURN
  97 dat_dictionary_create(
  98     OUT DAT_DICTIONARY **pp_dictionary)
  99 {
 100         DAT_DICTIONARY  *p_dictionary;
 101         DAT_RETURN status;
 102 
 103         dat_os_assert(NULL != pp_dictionary);
 104 
 105         status = DAT_SUCCESS;
 106 
 107         /* create the dictionary */
 108         p_dictionary = dat_os_alloc(sizeof (DAT_DICTIONARY));
 109         if (NULL == p_dictionary) {
 110                 status = DAT_ERROR(DAT_INSUFFICIENT_RESOURCES,
 111                     DAT_RESOURCE_MEMORY);
 112                 goto bail;
 113         }
 114 
 115         (void) dat_os_memset(p_dictionary, '\0', sizeof (DAT_DICTIONARY));
 116 
 117         /* create the head node */
 118         p_dictionary->head = dat_os_alloc(sizeof (DAT_DICTIONARY_NODE));
 119         if (NULL == p_dictionary->head) {
 120                 status = DAT_ERROR(DAT_INSUFFICIENT_RESOURCES,
 121                     DAT_RESOURCE_MEMORY);
 122                 goto bail;
 123         }
 124 
 125         (void) dat_os_memset(p_dictionary->head, '\0',
 126             sizeof (DAT_DICTIONARY_NODE));
 127 
 128         /* create the tail node */
 129         p_dictionary->tail = dat_os_alloc(sizeof (DAT_DICTIONARY_NODE));
 130         if (NULL == p_dictionary->tail)      {
 131                 status = DAT_ERROR(DAT_INSUFFICIENT_RESOURCES,
 132                     DAT_RESOURCE_MEMORY);
 133                 goto bail;
 134         }
 135 
 136         (void) dat_os_memset(p_dictionary->tail, '\0',
 137             sizeof (DAT_DICTIONARY_NODE));
 138 
 139         p_dictionary->head->next = p_dictionary->tail;
 140         p_dictionary->tail->prev = p_dictionary->head;
 141 
 142         *pp_dictionary = p_dictionary;
 143 
 144 bail:
 145         if (DAT_SUCCESS != status) {
 146                 if (NULL != p_dictionary) {
 147                         dat_os_free(p_dictionary, sizeof (DAT_DICTIONARY));
 148 
 149                         if (NULL != p_dictionary->head) {
 150                                 dat_os_free(p_dictionary->head,
 151                                     sizeof (DAT_DICTIONARY_NODE));
 152                         }
 153 
 154                         if (NULL != p_dictionary->tail) {
 155                                 dat_os_free(p_dictionary->tail,
 156                                     sizeof (DAT_DICTIONARY_NODE));
 157                         }
 158                 }
 159         }
 160 
 161         return (status);
 162 }
 163 
 164 
 165 /*
 166  * Function: dat_dictionary_destroy
 167  */
 168 
 169 DAT_RETURN
 170 dat_dictionary_destroy(
 171     IN  DAT_DICTIONARY *p_dictionary)
 172 {
 173         DAT_DICTIONARY_NODE *cur_node;
 174 
 175         dat_os_assert(NULL != p_dictionary);
 176 
 177         while (NULL != p_dictionary->head) {
 178                 cur_node = p_dictionary->head;
 179                 p_dictionary->head = cur_node->next;
 180 
 181                 dat_os_free(cur_node, sizeof (DAT_DICTIONARY_NODE));
 182         }
 183 
 184         dat_os_free(p_dictionary, sizeof (DAT_DICTIONARY));
 185 
 186         return (DAT_SUCCESS);
 187 }
 188 
 189 
 190 /*
 191  * Function: dat_dictionary_size
 192  */
 193 
 194 DAT_RETURN
 195 dat_dictionary_size(
 196     IN  DAT_DICTIONARY *p_dictionary,
 197     OUT DAT_COUNT *p_size)
 198 {
 199         dat_os_assert(NULL != p_dictionary);
 200         dat_os_assert(NULL != p_size);
 201 
 202         *p_size = p_dictionary->size;
 203 
 204         return (DAT_SUCCESS);
 205 }
 206 
 207 
 208 /*
 209  * Function: dat_dictionary_entry_create
 210  */
 211 
 212 DAT_RETURN
 213 dat_dictionary_entry_create(
 214     OUT DAT_DICTIONARY_ENTRY *p_entry)
 215 {
 216         DAT_DICTIONARY_NODE     *node;
 217         DAT_RETURN              dat_status;
 218 
 219         dat_os_assert(NULL != p_entry);
 220 
 221         dat_status = DAT_SUCCESS;
 222 
 223         node = dat_os_alloc(sizeof (DAT_DICTIONARY_NODE));
 224         if (NULL == node) {
 225                 dat_status = DAT_ERROR(DAT_INSUFFICIENT_RESOURCES,
 226                     DAT_RESOURCE_MEMORY);
 227                 goto bail;
 228         }
 229 
 230         *p_entry = node;
 231 
 232 bail:
 233         return (dat_status);
 234 }
 235 
 236 
 237 /*
 238  * Function: dat_dictionary_entry_destroy
 239  */
 240 
 241 DAT_RETURN
 242 dat_dictionary_entry_destroy(
 243     OUT DAT_DICTIONARY_ENTRY entry)
 244 {
 245         dat_os_free(entry, sizeof (DAT_DICTIONARY_NODE));
 246         return (DAT_SUCCESS);
 247 }
 248 
 249 
 250 /*
 251  * Function: dat_dictionary_insert
 252  */
 253 
 254 DAT_RETURN
 255 dat_dictionary_insert(
 256     IN  DAT_DICTIONARY *p_dictionary,
 257     IN  DAT_DICTIONARY_ENTRY entry,
 258     IN  const DAT_PROVIDER_INFO *key,
 259     IN  DAT_DICTIONARY_DATA data)
 260 {
 261         DAT_RETURN              dat_status;
 262         DAT_DICTIONARY_NODE *cur_node, *prev_node, *next_node;
 263 
 264         dat_os_assert(NULL != p_dictionary);
 265         dat_os_assert(NULL != entry);
 266 
 267         cur_node = entry;
 268 
 269         if (DAT_SUCCESS == dat_dictionary_search(p_dictionary, key, NULL)) {
 270                 dat_status = DAT_ERROR(DAT_PROVIDER_ALREADY_REGISTERED, 0);
 271                 goto bail;
 272         }
 273 
 274         dat_status = dat_dictionary_key_dup(key, &cur_node->key);
 275         if (DAT_SUCCESS != dat_status) {
 276                 goto bail;
 277         }
 278 
 279         /* insert node at end of list to preserve registration order */
 280         prev_node = p_dictionary->tail->prev;
 281         next_node = p_dictionary->tail;
 282 
 283         cur_node->data = data;
 284         cur_node->next = next_node;
 285         cur_node->prev = prev_node;
 286 
 287         prev_node->next = cur_node;
 288         next_node->prev = cur_node;
 289 
 290         p_dictionary->size++;
 291 
 292 bail:
 293         return (dat_status);
 294 }
 295 
 296 
 297 /*
 298  * Function: dat_dictionary_search
 299  */
 300 
 301 DAT_RETURN
 302 dat_dictionary_search(
 303     IN  DAT_DICTIONARY *p_dictionary,
 304     IN  const DAT_PROVIDER_INFO *key,
 305     OUT DAT_DICTIONARY_DATA *p_data)
 306 {
 307         DAT_DICTIONARY_NODE *cur_node;
 308         DAT_RETURN status;
 309 
 310         dat_os_assert(NULL != p_dictionary);
 311 
 312         status = DAT_ERROR(DAT_NAME_NOT_FOUND, 0);
 313 
 314         for (cur_node = p_dictionary->head->next;
 315                 p_dictionary->tail != cur_node;
 316                 cur_node = cur_node->next) {
 317                 if (DAT_TRUE == dat_dictionary_key_is_equal(&cur_node->key,
 318                     key)) {
 319                         if (NULL != p_data) {
 320                                 *p_data = cur_node->data;
 321                         }
 322 
 323                         status = DAT_SUCCESS;
 324                         goto bail;
 325                 }
 326         }
 327 
 328 bail:
 329         return (status);
 330 }
 331 
 332 
 333 /*
 334  * Function: dat_dictionary_enumerate
 335  */
 336 
 337 DAT_RETURN
 338 dat_dictionary_enumerate(
 339     IN  DAT_DICTIONARY *p_dictionary,
 340     IN  DAT_DICTIONARY_DATA array[],
 341     IN  DAT_COUNT array_size)
 342 {
 343         DAT_DICTIONARY_NODE *cur_node;
 344         DAT_COUNT i;
 345         DAT_RETURN status;
 346 
 347         dat_os_assert(NULL != p_dictionary);
 348         dat_os_assert(NULL != array);
 349 
 350         status = DAT_SUCCESS;
 351 
 352         if (array_size < p_dictionary->size) {
 353                 status = DAT_ERROR(DAT_INSUFFICIENT_RESOURCES, 0);
 354                 goto bail;
 355         }
 356 
 357         for (cur_node = p_dictionary->head->next, i = 0;
 358                 p_dictionary->tail != cur_node;
 359                 cur_node = cur_node->next, i++) {
 360                 array[i] = cur_node->data;
 361         }
 362 
 363 bail:
 364         return (status);
 365 }
 366 
 367 
 368 /*
 369  * Function: dat_dictionary_remove
 370  */
 371 
 372 DAT_RETURN
 373 dat_dictionary_remove(
 374     IN  DAT_DICTIONARY *p_dictionary,
 375     IN  DAT_DICTIONARY_ENTRY *p_entry,
 376     IN  const DAT_PROVIDER_INFO *key,
 377     OUT DAT_DICTIONARY_DATA *p_data)
 378 {
 379         DAT_DICTIONARY_NODE *cur_node, *prev_node, *next_node;
 380         DAT_RETURN status;
 381 
 382         dat_os_assert(NULL != p_dictionary);
 383         dat_os_assert(NULL != p_entry);
 384 
 385         status = DAT_ERROR(DAT_NAME_NOT_FOUND, 0);
 386 
 387         for (cur_node = p_dictionary->head->next;
 388                 p_dictionary->tail != cur_node;
 389                 cur_node = cur_node->next) {
 390                 if (DAT_TRUE == dat_dictionary_key_is_equal(&cur_node->key,
 391                     key)) {
 392                         if (NULL != p_data) {
 393                                 *p_data = cur_node->data;
 394                         }
 395 
 396                         prev_node = cur_node->prev;
 397                         next_node = cur_node->next;
 398 
 399                         prev_node->next = next_node;
 400                         next_node->prev = prev_node;
 401 
 402                         *p_entry = cur_node;
 403 
 404                         p_dictionary->size--;
 405 
 406                         status = DAT_SUCCESS;
 407                         goto bail;
 408                 }
 409         }
 410 
 411 bail:
 412         return (status);
 413 }
 414 
 415 
 416 /*
 417  *
 418  * Internal Function Definitions
 419  *
 420  */
 421 
 422 
 423 /*
 424  * Function: dat_dictionary_key_create
 425  */
 426 
 427 DAT_RETURN
 428 dat_dictionary_key_dup(
 429     const DAT_PROVIDER_INFO     *old_key,
 430     DAT_PROVIDER_INFO           *new_key)
 431 {
 432         dat_os_assert(NULL != old_key);
 433         dat_os_assert(NULL != new_key);
 434 
 435         (void) dat_os_strncpy(new_key->ia_name, old_key->ia_name,
 436             DAT_NAME_MAX_LENGTH);
 437         new_key->dapl_version_major = old_key->dapl_version_major;
 438         new_key->dapl_version_minor = old_key->dapl_version_minor;
 439         new_key->is_thread_safe = old_key->is_thread_safe;
 440 
 441         return (DAT_SUCCESS);
 442 }
 443 
 444 
 445 /*
 446  * Function: dat_dictionary_key_is_equal
 447  */
 448 
 449 DAT_BOOLEAN
 450 dat_dictionary_key_is_equal(
 451     const DAT_PROVIDER_INFO     *key_a,
 452     const DAT_PROVIDER_INFO     *key_b)
 453 {
 454         if ((dat_os_strlen(key_a->ia_name) == dat_os_strlen(key_b->ia_name)) &&
 455             (!dat_os_strncmp(key_a->ia_name, key_b->ia_name,
 456                 dat_os_strlen(key_a->ia_name))) &&
 457             (key_a->dapl_version_major == key_b->dapl_version_major) &&
 458             (key_a->dapl_version_minor == key_b->dapl_version_minor) &&
 459             (key_a->is_thread_safe == key_b->is_thread_safe)) {
 460                 return (DAT_TRUE);
 461         } else {
 462                 return (DAT_FALSE);
 463         }
 464 }