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 }
465