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
dat_dictionary_create(OUT DAT_DICTIONARY ** pp_dictionary)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
dat_dictionary_destroy(IN DAT_DICTIONARY * p_dictionary)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
dat_dictionary_size(IN DAT_DICTIONARY * p_dictionary,OUT DAT_COUNT * p_size)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
dat_dictionary_entry_create(OUT DAT_DICTIONARY_ENTRY * p_entry)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
dat_dictionary_entry_destroy(OUT DAT_DICTIONARY_ENTRY entry)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
dat_dictionary_insert(IN DAT_DICTIONARY * p_dictionary,IN DAT_DICTIONARY_ENTRY entry,IN const DAT_PROVIDER_INFO * key,IN DAT_DICTIONARY_DATA data)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
dat_dictionary_search(IN DAT_DICTIONARY * p_dictionary,IN const DAT_PROVIDER_INFO * key,OUT DAT_DICTIONARY_DATA * p_data)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
dat_dictionary_enumerate(IN DAT_DICTIONARY * p_dictionary,IN DAT_DICTIONARY_DATA array[],IN DAT_COUNT array_size)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
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)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
dat_dictionary_key_dup(const DAT_PROVIDER_INFO * old_key,DAT_PROVIDER_INFO * new_key)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
dat_dictionary_key_is_equal(const DAT_PROVIDER_INFO * key_a,const DAT_PROVIDER_INFO * key_b)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 }
468