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