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