xref: /illumos-gate/usr/src/cmd/nscd/nscd_dbimpl.c (revision fa845c5d)
1cb5caa98Sdjl /*
2cb5caa98Sdjl  * CDDL HEADER START
3cb5caa98Sdjl  *
4cb5caa98Sdjl  * The contents of this file are subject to the terms of the
5cb5caa98Sdjl  * Common Development and Distribution License (the "License").
6cb5caa98Sdjl  * You may not use this file except in compliance with the License.
7cb5caa98Sdjl  *
8cb5caa98Sdjl  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9cb5caa98Sdjl  * or http://www.opensolaris.org/os/licensing.
10cb5caa98Sdjl  * See the License for the specific language governing permissions
11cb5caa98Sdjl  * and limitations under the License.
12cb5caa98Sdjl  *
13cb5caa98Sdjl  * When distributing Covered Code, include this CDDL HEADER in each
14cb5caa98Sdjl  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15cb5caa98Sdjl  * If applicable, add the following below this CDDL HEADER, with the
16cb5caa98Sdjl  * fields enclosed by brackets "[]" replaced with your own identifying
17cb5caa98Sdjl  * information: Portions Copyright [yyyy] [name of copyright owner]
18cb5caa98Sdjl  *
19cb5caa98Sdjl  * CDDL HEADER END
20cb5caa98Sdjl  */
21cb5caa98Sdjl /*
22cb5caa98Sdjl  * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
23cb5caa98Sdjl  * Use is subject to license terms.
24cb5caa98Sdjl  */
25cb5caa98Sdjl 
26cb5caa98Sdjl #include <stdio.h>
27cb5caa98Sdjl #include <stdlib.h>
28cb5caa98Sdjl #include <string.h>
29cb5caa98Sdjl #include <ctype.h>
30cb5caa98Sdjl #include "nscd_db.h"
31cb5caa98Sdjl 
32cb5caa98Sdjl /*
33cb5caa98Sdjl  * This file implements the database functionality used by the
34cb5caa98Sdjl  * switch and configuration components. The implementation is
35cb5caa98Sdjl  * based on hash and has table. If the need arises in the future,
36cb5caa98Sdjl  * the code in this file can be changed to use other algorithms.
37cb5caa98Sdjl  * The following lists the functions implemented:
38cb5caa98Sdjl  *
39cb5caa98Sdjl  * _nscd_add_db_entry
40cb5caa98Sdjl  * _nscd_delete_db_entry
41cb5caa98Sdjl  * _nscd_get_db_entry
42cb5caa98Sdjl  * _nscd_alloc_db
43cb5caa98Sdjl  * _nscd_free_db
44cb5caa98Sdjl  * _nscd_walk_db
45cb5caa98Sdjl  * _nscd_delete_db_entry_cookie
46cb5caa98Sdjl  */
47cb5caa98Sdjl 
48cb5caa98Sdjl /*
49cb5caa98Sdjl  * This structure defines an instance of the hash entry
50cb5caa98Sdjl  * which implements the nscd database entry. The
51cb5caa98Sdjl  * db_entry field should always be the first one in
52cb5caa98Sdjl  * the structure.
53cb5caa98Sdjl  */
54cb5caa98Sdjl typedef struct nscd_hash {
55cb5caa98Sdjl 	nscd_db_entry_t		db_entry;
56cb5caa98Sdjl 	struct nscd_hash	*next_p;
57cb5caa98Sdjl 	struct nscd_hash	*prev_p;
58cb5caa98Sdjl } nscd_hash_t;
59cb5caa98Sdjl 
60cb5caa98Sdjl /*
61cb5caa98Sdjl  * This structure defines a nscd database which
62cb5caa98Sdjl  * is implemented as an array of nscd_hash_t.
63cb5caa98Sdjl  */
64cb5caa98Sdjl struct nscd_db_s {
65cb5caa98Sdjl 	int		array_size; /* number of elements in hash_tbl_p */
66cb5caa98Sdjl 	nscd_hash_t	**hash_tbl_p;
67cb5caa98Sdjl };
68cb5caa98Sdjl 
69cb5caa98Sdjl /*
70cb5caa98Sdjl  * This cookie structure is used to iterate through the
71cb5caa98Sdjl  * database entries contained in a nscd database.
72cb5caa98Sdjl  */
73cb5caa98Sdjl struct cookie {
74cb5caa98Sdjl 	int		idx;	/* the current bucket */
75cb5caa98Sdjl 	nscd_hash_t	*hash;	/* the current hash entry */
76cb5caa98Sdjl 	nscd_db_t	*db;    /* the database */
77cb5caa98Sdjl };
78cb5caa98Sdjl 
79cb5caa98Sdjl /*
80cb5caa98Sdjl  * FUNCTION: calc_hash
81cb5caa98Sdjl  *
82cb5caa98Sdjl  * Calculate a hash for a string based on the elf_hash
83cb5caa98Sdjl  * algorithm, hash is case insensitive. Uses tolower
84cb5caa98Sdjl  * instead of _tolower because of I18N.
85cb5caa98Sdjl  */
86cb5caa98Sdjl static unsigned long
calc_hash(const char * str)87cb5caa98Sdjl calc_hash(
88cb5caa98Sdjl 	const char	*str)
89cb5caa98Sdjl {
90cb5caa98Sdjl 	unsigned int	hval = 0;
91cb5caa98Sdjl 	char		ch;
92cb5caa98Sdjl 
93*fa845c5dSToomas Soome 	while (*str != '\0') {
94cb5caa98Sdjl 		unsigned int	g;
95cb5caa98Sdjl 
96cb5caa98Sdjl 		ch = (char)*str++;
97cb5caa98Sdjl 		if (isupper(ch))
98cb5caa98Sdjl 			ch = _tolower(ch);
99cb5caa98Sdjl 		hval = (hval << 4) + ch;
100cb5caa98Sdjl 		if ((g = (hval & 0xf0000000)) != 0)
101cb5caa98Sdjl 			hval ^= g >> 24;
102cb5caa98Sdjl 		hval &= ~g;
103cb5caa98Sdjl 	}
104cb5caa98Sdjl 	return ((unsigned long)hval);
105cb5caa98Sdjl }
106cb5caa98Sdjl 
107cb5caa98Sdjl /*
108cb5caa98Sdjl  * FUNCTION: scan_hash
109cb5caa98Sdjl  *
110cb5caa98Sdjl  * Scan a hash table for a matching hash entry. Assume 'str' is
111cb5caa98Sdjl  * not NULL. If option is NSCD_GET_NEXT_DB_ENTRY and id_num
112cb5caa98Sdjl  * is less than zero, then treats the option as NSCD_GET_FIRST_DB_ENTRY.
113cb5caa98Sdjl  */
114cb5caa98Sdjl 
115cb5caa98Sdjl static const nscd_hash_t *
scan_hash(int type,const char * str,const nscd_hash_t * idx_p,nscd_db_option_t option,int id_num)116cb5caa98Sdjl scan_hash(
117cb5caa98Sdjl 	int			type,
118cb5caa98Sdjl 	const char		*str,
119cb5caa98Sdjl 	const nscd_hash_t	*idx_p,
120cb5caa98Sdjl 	nscd_db_option_t	option,
121cb5caa98Sdjl 	int			id_num)
122cb5caa98Sdjl {
123cb5caa98Sdjl 	int			id_matched = 0;
124cb5caa98Sdjl 	nscd_db_entry_t		*db_entry;
125cb5caa98Sdjl 
126cb5caa98Sdjl 	while (idx_p != NULL) {
127cb5caa98Sdjl 		db_entry = &((nscd_hash_t *)idx_p)->db_entry;
128cb5caa98Sdjl 		if (db_entry->type == type) {
129cb5caa98Sdjl 			if (strcasecmp(str, db_entry->name) == 0) {
130cb5caa98Sdjl 				switch (option) {
131cb5caa98Sdjl 				case NSCD_GET_FIRST_DB_ENTRY:
132cb5caa98Sdjl 					return (idx_p);
133cb5caa98Sdjl 				case NSCD_GET_EXACT_DB_ENTRY:
134cb5caa98Sdjl 					if (id_num == db_entry->id_num)
135cb5caa98Sdjl 						return (idx_p);
136cb5caa98Sdjl 					break;
137cb5caa98Sdjl 				case NSCD_GET_NEXT_DB_ENTRY:
138cb5caa98Sdjl 					if (id_num < 0)
139cb5caa98Sdjl 						return (idx_p);
140cb5caa98Sdjl 					if (id_matched == 1)
141cb5caa98Sdjl 						return (idx_p);
142cb5caa98Sdjl 					if (id_num == db_entry->id_num)
143cb5caa98Sdjl 						id_matched = 1;
144cb5caa98Sdjl 					break;
145cb5caa98Sdjl 				}
146cb5caa98Sdjl 			}
147cb5caa98Sdjl 		}
148cb5caa98Sdjl 		idx_p = idx_p->next_p;
149cb5caa98Sdjl 	}
150cb5caa98Sdjl 	return (NULL);
151cb5caa98Sdjl }
152cb5caa98Sdjl 
153cb5caa98Sdjl /*
154cb5caa98Sdjl  * FUNCTION: _nscd_get_db_entry
155cb5caa98Sdjl  *
156cb5caa98Sdjl  * Find a nscd database entry from a nscd database.
157cb5caa98Sdjl  */
158cb5caa98Sdjl const nscd_db_entry_t *
_nscd_get_db_entry(const nscd_db_t * db,int type,const char * str,nscd_db_option_t option,int id_num)159cb5caa98Sdjl _nscd_get_db_entry(
160cb5caa98Sdjl 	const nscd_db_t		*db,
161cb5caa98Sdjl 	int			type,
162cb5caa98Sdjl 	const char		*str,
163cb5caa98Sdjl 	nscd_db_option_t	option,
164cb5caa98Sdjl 	int			id_num)
165cb5caa98Sdjl {
166cb5caa98Sdjl 	unsigned long		hash;
167cb5caa98Sdjl 	const nscd_hash_t	*idx_p, *hash_p;
168cb5caa98Sdjl 
169cb5caa98Sdjl 	if (db == NULL || str == NULL)
170cb5caa98Sdjl 		return (NULL);
171cb5caa98Sdjl 
172cb5caa98Sdjl 	hash = calc_hash(str);
173cb5caa98Sdjl 	idx_p = db->hash_tbl_p[hash % db->array_size];
174cb5caa98Sdjl 
175cb5caa98Sdjl 	hash_p = scan_hash(type, str, idx_p, option, id_num);
176cb5caa98Sdjl 
177cb5caa98Sdjl 	return (&hash_p->db_entry);
178cb5caa98Sdjl }
179cb5caa98Sdjl 
180cb5caa98Sdjl /*
181cb5caa98Sdjl  * FUNCTION: _nscd_add_db_entry
182cb5caa98Sdjl  *
183cb5caa98Sdjl  * Add a nscd database entry to a nscd database. This function
184cb5caa98Sdjl  * is not MT safe. The caller should lock the database to
185cb5caa98Sdjl  * prevent concurrent updates done by other threads.
186cb5caa98Sdjl  */
187cb5caa98Sdjl nscd_rc_t
_nscd_add_db_entry(nscd_db_t * db,const char * str,nscd_db_entry_t * entry,nscd_db_option_t option)188cb5caa98Sdjl _nscd_add_db_entry(
189cb5caa98Sdjl 	nscd_db_t		*db,
190*fa845c5dSToomas Soome 	const char		*str,
191cb5caa98Sdjl 	nscd_db_entry_t		*entry,
192cb5caa98Sdjl 	nscd_db_option_t	option)
193cb5caa98Sdjl {
194cb5caa98Sdjl 	int			i;
195cb5caa98Sdjl 	unsigned long		hash;
196cb5caa98Sdjl 	nscd_hash_t		*next_p = NULL, *prev_p = NULL;
197cb5caa98Sdjl 	nscd_hash_t		*idx_p, *hash_entry;
198cb5caa98Sdjl 	nscd_db_entry_t		*db_entry;
199cb5caa98Sdjl 
200cb5caa98Sdjl 	/* find the bucket */
201cb5caa98Sdjl 	hash = calc_hash(str);
202cb5caa98Sdjl 	i = hash % db->array_size;
203cb5caa98Sdjl 	idx_p = db->hash_tbl_p[i];
204cb5caa98Sdjl 
205cb5caa98Sdjl 	/* can not replace nothing */
206cb5caa98Sdjl 	if (idx_p == NULL)
207cb5caa98Sdjl 		if (option == NSCD_ADD_DB_ENTRY_REPLACE)
208cb5caa98Sdjl 			return (NSCD_DB_ENTRY_NOT_FOUND);
209cb5caa98Sdjl 
210cb5caa98Sdjl 	while (idx_p != NULL) {
211cb5caa98Sdjl 		db_entry = &idx_p->db_entry;
212cb5caa98Sdjl 		switch (option) {
213cb5caa98Sdjl 
214cb5caa98Sdjl 		case NSCD_ADD_DB_ENTRY_FIRST:
215cb5caa98Sdjl 			next_p = idx_p;
216cb5caa98Sdjl 			goto add_entry;
217cb5caa98Sdjl 
218cb5caa98Sdjl 		case NSCD_ADD_DB_ENTRY_REPLACE:
219cb5caa98Sdjl 			if (db_entry->type != entry->type)
220cb5caa98Sdjl 				goto cont;
221cb5caa98Sdjl 			if (strcasecmp(db_entry->name, str) != 0)
222cb5caa98Sdjl 				goto cont;
223cb5caa98Sdjl 
224cb5caa98Sdjl 			if (db_entry->id_num == entry->id_num) {
225cb5caa98Sdjl 				prev_p = idx_p->prev_p;
226cb5caa98Sdjl 				next_p = idx_p->next_p;
227cb5caa98Sdjl 				free(idx_p);
228cb5caa98Sdjl 				goto add_entry;
229cb5caa98Sdjl 			}
230cb5caa98Sdjl 			goto cont;
231cb5caa98Sdjl 
232cb5caa98Sdjl 		case NSCD_ADD_DB_ENTRY_IF_NONE:
233cb5caa98Sdjl 			if (db_entry->type != entry->type)
234cb5caa98Sdjl 				break;
235cb5caa98Sdjl 			if (strcasecmp(db_entry->name, str) != 0)
236cb5caa98Sdjl 				break;
237cb5caa98Sdjl 			return (NSCD_DB_ENTRY_FOUND);
238cb5caa98Sdjl 		}
239cb5caa98Sdjl 
240cb5caa98Sdjl 		if (idx_p->next_p == NULL) {
241cb5caa98Sdjl 			if (option == NSCD_ADD_DB_ENTRY_LAST ||
242*fa845c5dSToomas Soome 			    option == NSCD_ADD_DB_ENTRY_IF_NONE) {
243cb5caa98Sdjl 				prev_p = idx_p;
244cb5caa98Sdjl 				goto add_entry;
245cb5caa98Sdjl 			}
246cb5caa98Sdjl 		}
247cb5caa98Sdjl 
248cb5caa98Sdjl 		cont:
249cb5caa98Sdjl 		idx_p = idx_p->next_p;
250cb5caa98Sdjl 	}
251cb5caa98Sdjl 
252cb5caa98Sdjl 	add_entry:
253cb5caa98Sdjl 
254cb5caa98Sdjl 	/*
255cb5caa98Sdjl 	 * the nscd_entry_t field should be the first field
256cb5caa98Sdjl 	 * in a nscd_hash_t
257cb5caa98Sdjl 	 */
258cb5caa98Sdjl 	hash_entry = (nscd_hash_t *)entry;
259cb5caa98Sdjl 
260cb5caa98Sdjl 	/* update the prev link list */
261cb5caa98Sdjl 	hash_entry->prev_p = prev_p;
262cb5caa98Sdjl 	if (prev_p == NULL)
263cb5caa98Sdjl 		db->hash_tbl_p[i] = hash_entry;
264cb5caa98Sdjl 	else
265cb5caa98Sdjl 		prev_p->next_p = hash_entry;
266cb5caa98Sdjl 
267cb5caa98Sdjl 	/* update the next link list */
268cb5caa98Sdjl 	hash_entry->next_p = next_p;
269cb5caa98Sdjl 	if (next_p != NULL)
270cb5caa98Sdjl 		next_p->prev_p = hash_entry;
271cb5caa98Sdjl 
272cb5caa98Sdjl 	return (NSCD_SUCCESS);
273cb5caa98Sdjl }
274cb5caa98Sdjl 
275cb5caa98Sdjl /*
276cb5caa98Sdjl  * FUNCTION: _nscd_delete_db_entry
277cb5caa98Sdjl  *
278cb5caa98Sdjl  * Delete a nscd database entry from a nscd database. This
279cb5caa98Sdjl  * function is not MT safe. The caller should lock the
280cb5caa98Sdjl  * database to prevent concurrent updates done by other
281cb5caa98Sdjl  * threads.
282cb5caa98Sdjl  */
283cb5caa98Sdjl nscd_rc_t
_nscd_delete_db_entry(nscd_db_t * db,int type,const char * str,nscd_db_option_t option,int id_num)284cb5caa98Sdjl _nscd_delete_db_entry(
285cb5caa98Sdjl 	nscd_db_t		*db,
286cb5caa98Sdjl 	int			type,
287cb5caa98Sdjl 	const char		*str,
288cb5caa98Sdjl 	nscd_db_option_t	option,
289cb5caa98Sdjl 	int			id_num)
290cb5caa98Sdjl {
291cb5caa98Sdjl 	int			i;
292cb5caa98Sdjl 	int			del_more = 0;
293cb5caa98Sdjl 	unsigned long		hash;
294cb5caa98Sdjl 	nscd_hash_t		*idx_p, *next_p = NULL, *prev_p = NULL;
295cb5caa98Sdjl 	nscd_db_entry_t		*db_entry;
296cb5caa98Sdjl 
297cb5caa98Sdjl 	/* find the bucket */
298cb5caa98Sdjl 	hash = calc_hash(str);
299cb5caa98Sdjl 	i = hash % db->array_size;
300cb5caa98Sdjl 	idx_p = db->hash_tbl_p[i];
301cb5caa98Sdjl 
302cb5caa98Sdjl 	/* delete nothing always works */
303cb5caa98Sdjl 	if (idx_p == NULL)
304cb5caa98Sdjl 		return (NSCD_SUCCESS);
305cb5caa98Sdjl 
306cb5caa98Sdjl 	while (idx_p != NULL) {
307cb5caa98Sdjl 		db_entry = &idx_p->db_entry;
308cb5caa98Sdjl 		if (db_entry->type != type)
309cb5caa98Sdjl 			goto cont;
310cb5caa98Sdjl 		if (strcasecmp(db_entry->name, str) != 0)
311cb5caa98Sdjl 			goto cont;
312cb5caa98Sdjl 
313cb5caa98Sdjl 		switch (option) {
314cb5caa98Sdjl 
315cb5caa98Sdjl 		case NSCD_DEL_FIRST_DB_ENTRY:
316cb5caa98Sdjl 			prev_p = idx_p->prev_p;
317cb5caa98Sdjl 			next_p = idx_p->next_p;
318cb5caa98Sdjl 			del_more = 0;
319cb5caa98Sdjl 			break;
320cb5caa98Sdjl 
321cb5caa98Sdjl 		case NSCD_DEL_EXACT_DB_ENTRY:
322cb5caa98Sdjl 			if (db_entry->id_num == id_num) {
323cb5caa98Sdjl 				prev_p = idx_p->prev_p;
324cb5caa98Sdjl 				next_p = idx_p->next_p;
325cb5caa98Sdjl 				del_more = 0;
326cb5caa98Sdjl 			} else
327cb5caa98Sdjl 				goto cont;
328cb5caa98Sdjl 			break;
329cb5caa98Sdjl 
330cb5caa98Sdjl 		case NSCD_DEL_ALL_DB_ENTRY:
331cb5caa98Sdjl 			prev_p = idx_p->prev_p;
332cb5caa98Sdjl 			next_p = idx_p->next_p;
333cb5caa98Sdjl 			break;
334cb5caa98Sdjl 		}
335cb5caa98Sdjl 
336cb5caa98Sdjl 		if (prev_p == NULL)
337cb5caa98Sdjl 			db->hash_tbl_p[i] = next_p;
338cb5caa98Sdjl 		else
339cb5caa98Sdjl 			prev_p->next_p = next_p;
340cb5caa98Sdjl 
341cb5caa98Sdjl 		if (next_p != NULL)
342cb5caa98Sdjl 			next_p->prev_p = prev_p;
343cb5caa98Sdjl 
344cb5caa98Sdjl 		free(idx_p);
345cb5caa98Sdjl 
346cb5caa98Sdjl 		if (del_more == 0)
347cb5caa98Sdjl 			break;
348cb5caa98Sdjl 		/*
349cb5caa98Sdjl 		 * only when option == NSCD_DEL_ALL_DB_ENTRY
350cb5caa98Sdjl 		 * will we get here. next_p should be set to
351cb5caa98Sdjl 		 * idx_p->next_p beforehand
352cb5caa98Sdjl 		 */
353cb5caa98Sdjl 		idx_p = next_p;
354cb5caa98Sdjl 		continue;
355cb5caa98Sdjl 
356cb5caa98Sdjl 		cont:
357cb5caa98Sdjl 
358cb5caa98Sdjl 		idx_p = idx_p->next_p;
359cb5caa98Sdjl 	}
360cb5caa98Sdjl 
361cb5caa98Sdjl 	return (NSCD_SUCCESS);
362cb5caa98Sdjl }
363cb5caa98Sdjl 
364cb5caa98Sdjl /*
365cb5caa98Sdjl  * FUNCTION: _nscd_alloc_db_entry
366cb5caa98Sdjl  *
367cb5caa98Sdjl  * Allocate and return the memory for a database entry
368cb5caa98Sdjl  * so the caller can insert data and then add it to the
369cb5caa98Sdjl  * database.
370cb5caa98Sdjl  */
371cb5caa98Sdjl nscd_db_entry_t *
_nscd_alloc_db_entry(int type,const char * name,int dataSize,int num_data,int num_array)372cb5caa98Sdjl _nscd_alloc_db_entry(
373cb5caa98Sdjl 	int			type,
374*fa845c5dSToomas Soome 	const char		*name,
375cb5caa98Sdjl 	int			dataSize,
376cb5caa98Sdjl 	int			num_data,
377cb5caa98Sdjl 	int			num_array)
378cb5caa98Sdjl {
379cb5caa98Sdjl 	int			size;
380cb5caa98Sdjl 	int			array_o, data_o;
381cb5caa98Sdjl 	nscd_hash_t		*hash;
382cb5caa98Sdjl 	void			*p;
383cb5caa98Sdjl 
384cb5caa98Sdjl 	/* first part: hash data structure and name string */
385cb5caa98Sdjl 	size = sizeof (*hash) + strlen(name) + 1;
386cb5caa98Sdjl 	array_o = size = roundup(size);
387cb5caa98Sdjl 
388cb5caa98Sdjl 	/* second part: pointer array to data */
389cb5caa98Sdjl 	size += (num_data  + num_array) * sizeof (void **);
390cb5caa98Sdjl 	size = roundup(size);
391cb5caa98Sdjl 
392cb5caa98Sdjl 	/* third part: actual data */
393cb5caa98Sdjl 	data_o = size;
394cb5caa98Sdjl 	size += dataSize;
395cb5caa98Sdjl 
396cb5caa98Sdjl 	/* allocate the memory */
397cb5caa98Sdjl 	hash = (nscd_hash_t *)calloc(1, size);
398cb5caa98Sdjl 
399cb5caa98Sdjl 	if (hash == NULL)
400cb5caa98Sdjl 		return (NULL);
401cb5caa98Sdjl 
402cb5caa98Sdjl 	/* init the entry based on caller's input */
403cb5caa98Sdjl 	hash->db_entry.num_data = num_data;
404cb5caa98Sdjl 	hash->db_entry.num_array = num_array;
405cb5caa98Sdjl 	hash->db_entry.type = type;
406cb5caa98Sdjl 	hash->db_entry.name = (char *)hash + sizeof (*hash);
407cb5caa98Sdjl 	p = (char *)hash + array_o;
408cb5caa98Sdjl 	hash->db_entry.data_array = (void **)p;
409cb5caa98Sdjl 	*(hash->db_entry.data_array) = (char *)hash + data_o;
410cb5caa98Sdjl 	(void) strcpy(hash->db_entry.name, name);
411cb5caa98Sdjl 
412cb5caa98Sdjl 	return (&hash->db_entry);
413cb5caa98Sdjl }
414cb5caa98Sdjl 
415cb5caa98Sdjl /*
416cb5caa98Sdjl  * FUNCTION: _nscd_delete_db_entry_cookie
417cb5caa98Sdjl  *
418cb5caa98Sdjl  * Delete a database entry using the information from
419cb5caa98Sdjl  * the input 'cookie'.
420cb5caa98Sdjl  */
421cb5caa98Sdjl void
_nscd_delete_db_entry_cookie(nscd_db_t * db,void ** cookie)422cb5caa98Sdjl _nscd_delete_db_entry_cookie(
423cb5caa98Sdjl 	nscd_db_t	*db,
424cb5caa98Sdjl 	void		**cookie)
425cb5caa98Sdjl {
426cb5caa98Sdjl 	nscd_hash_t	*hp;
427cb5caa98Sdjl 	struct cookie	*c;
428cb5caa98Sdjl 
429cb5caa98Sdjl 	/* snaity check */
430cb5caa98Sdjl 	if (cookie == NULL || *cookie == NULL || db == NULL)
431cb5caa98Sdjl 		return;
432cb5caa98Sdjl 	c = *cookie;
433cb5caa98Sdjl 
434cb5caa98Sdjl 	/* more snaity check */
435cb5caa98Sdjl 	if (db != c->db || c->hash == NULL ||
436*fa845c5dSToomas Soome 	    c->idx < 0 || c->idx >= db->array_size)
437cb5caa98Sdjl 		return;
438cb5caa98Sdjl 
439cb5caa98Sdjl 	/* retrieve the hash entry from the cookie */
440cb5caa98Sdjl 	hp = c->hash;
441cb5caa98Sdjl 
442cb5caa98Sdjl 	/*
443cb5caa98Sdjl 	 * Update the next/previous link list.
444cb5caa98Sdjl 	 * Need to update c->hash as well, in case
445cb5caa98Sdjl 	 * the cookie is also used in a walk-db
446cb5caa98Sdjl 	 * loop. This is to make sure that the
447cb5caa98Sdjl 	 * next _nscd_walk_db() call will
448cb5caa98Sdjl 	 * find the (updated) next hash entry in line.
449cb5caa98Sdjl 	 */
450cb5caa98Sdjl 	if (hp->prev_p == NULL)	{
451cb5caa98Sdjl 		/*
452cb5caa98Sdjl 		 * make sure the current bucket will be
453cb5caa98Sdjl 		 * walked again if _nscd_walk_db is
454cb5caa98Sdjl 		 * called next
455cb5caa98Sdjl 		 */
456cb5caa98Sdjl 		c->hash = NULL;
457cb5caa98Sdjl 		db->hash_tbl_p[c->idx] = hp->next_p;
458cb5caa98Sdjl 		c->idx--;
459cb5caa98Sdjl 
460cb5caa98Sdjl 	} else {
461cb5caa98Sdjl 		c->hash = hp->prev_p;
462cb5caa98Sdjl 		hp->prev_p->next_p = hp->next_p;
463cb5caa98Sdjl 	}
464cb5caa98Sdjl 	if (hp->next_p != NULL)
465cb5caa98Sdjl 		hp->next_p->prev_p = hp->prev_p;
466cb5caa98Sdjl 
467cb5caa98Sdjl 	/* delete the entry */
468cb5caa98Sdjl 	free(hp);
469cb5caa98Sdjl }
470cb5caa98Sdjl 
471cb5caa98Sdjl /*
472cb5caa98Sdjl  * FUNCTION: _nscd_alloc_db
473cb5caa98Sdjl  *
474cb5caa98Sdjl  * Allocate the space for a nscd database.
475cb5caa98Sdjl  *
476cb5caa98Sdjl  * The input argument, size, indicates the size of the database.
477cb5caa98Sdjl  * NSCD_DB_SIZE_LARGE specifies an bucket array of size 67,
478cb5caa98Sdjl  * NSCD_DB_SIZE_MEDIUM specifies an bucket array of size 37,
479cb5caa98Sdjl  * NSCD_DB_SIZE_SMALL specifies an bucket array of size 13,
480cb5caa98Sdjl  * NSCD_DB_SIZE_TINY specifies an bucket array of size 3.
481cb5caa98Sdjl  */
482cb5caa98Sdjl nscd_db_t *
_nscd_alloc_db(int size)483cb5caa98Sdjl _nscd_alloc_db(
484cb5caa98Sdjl 	int		size)
485cb5caa98Sdjl {
486cb5caa98Sdjl 	int		sz;
487cb5caa98Sdjl 	nscd_db_t	*db;
488cb5caa98Sdjl 
489cb5caa98Sdjl 	/* allocate the database */
490cb5caa98Sdjl 	db = (nscd_db_t *)calloc(1, sizeof (nscd_db_t));
491cb5caa98Sdjl 	if (db == NULL)
492cb5caa98Sdjl 		return (NULL);
493cb5caa98Sdjl 
494cb5caa98Sdjl 	/* allocate the bucket array */
495cb5caa98Sdjl 	if (size == NSCD_DB_SIZE_LARGE)
496cb5caa98Sdjl 		sz = 67;
497cb5caa98Sdjl 	else if (size == NSCD_DB_SIZE_MEDIUM)
498cb5caa98Sdjl 		sz = 37;
499cb5caa98Sdjl 	else if (size == NSCD_DB_SIZE_SMALL)
500cb5caa98Sdjl 		sz = 13;
501cb5caa98Sdjl 	else if (size == NSCD_DB_SIZE_TINY)
502cb5caa98Sdjl 		sz = 3;
503cb5caa98Sdjl 	db->hash_tbl_p = (nscd_hash_t  **)calloc(sz + 1,
504*fa845c5dSToomas Soome 	    sizeof (nscd_hash_t *));
505cb5caa98Sdjl 	if (db->hash_tbl_p == NULL) {
506cb5caa98Sdjl 		free(db);
507cb5caa98Sdjl 		return (NULL);
508cb5caa98Sdjl 	}
509cb5caa98Sdjl 
510cb5caa98Sdjl 	db->array_size = sz;
511cb5caa98Sdjl 
512cb5caa98Sdjl 	return (db);
513cb5caa98Sdjl }
514cb5caa98Sdjl 
515cb5caa98Sdjl /*
516cb5caa98Sdjl  * FUNCTION: _nscd_free_db
517cb5caa98Sdjl  *
518cb5caa98Sdjl  * Delete a nscd database.
519cb5caa98Sdjl  */
520cb5caa98Sdjl void
_nscd_free_db(nscd_db_t * db)521cb5caa98Sdjl _nscd_free_db(
522cb5caa98Sdjl 	nscd_db_t	*db)
523cb5caa98Sdjl {
524cb5caa98Sdjl 	int		i;
525cb5caa98Sdjl 	nscd_hash_t	*hp, *next_p;
526cb5caa98Sdjl 
527cb5caa98Sdjl 	/*
528cb5caa98Sdjl 	 * find non-empty buckets and for each one of them,
529cb5caa98Sdjl 	 * delete all the database entries in it's link list
530cb5caa98Sdjl 	 */
531cb5caa98Sdjl 	for (i = 0; i < db->array_size; i++) {
532cb5caa98Sdjl 
533cb5caa98Sdjl 		hp = db->hash_tbl_p[i];
534cb5caa98Sdjl 
535cb5caa98Sdjl 		while (hp != NULL) {
536cb5caa98Sdjl 			next_p = hp->next_p;
537cb5caa98Sdjl 			free(hp);
538cb5caa98Sdjl 			hp = next_p;
539cb5caa98Sdjl 		}
540cb5caa98Sdjl 	}
541cb5caa98Sdjl 
542cb5caa98Sdjl 	/* free the bucket array */
543cb5caa98Sdjl 	free(db->hash_tbl_p);
544cb5caa98Sdjl 
545cb5caa98Sdjl 	free(db);
546cb5caa98Sdjl }
547cb5caa98Sdjl 
548cb5caa98Sdjl /*
549cb5caa98Sdjl  * FUNCTION: _nscd_walk_db
550cb5caa98Sdjl  *
551cb5caa98Sdjl  * Iterate through the database entries contained in
552cb5caa98Sdjl  * a nscd database and return one entry at a time.
553cb5caa98Sdjl  * The cookie structure is used to indicate the
554cb5caa98Sdjl  * location of the returned entry for the next call
555cb5caa98Sdjl  * to this function. For the very first call, *cookie
556cb5caa98Sdjl  * should be set to NULL. For subsequent calls, the one
557cb5caa98Sdjl  * returned by the previous call sould be used.
558cb5caa98Sdjl  */
559cb5caa98Sdjl nscd_db_entry_t *
_nscd_walk_db(nscd_db_t * db,void ** cookie)560cb5caa98Sdjl _nscd_walk_db(
561cb5caa98Sdjl 	nscd_db_t	*db,
562cb5caa98Sdjl 	void		**cookie)
563cb5caa98Sdjl {
564cb5caa98Sdjl 	struct cookie	*c;
565cb5caa98Sdjl 
566cb5caa98Sdjl 	/* sanity check */
567cb5caa98Sdjl 	if (cookie == NULL || db == NULL)
568cb5caa98Sdjl 		return (NULL);
569cb5caa98Sdjl 
570cb5caa98Sdjl 	if (*cookie != NULL) {
571cb5caa98Sdjl 
572cb5caa98Sdjl 		c = *cookie;
573cb5caa98Sdjl 
574cb5caa98Sdjl 		/*
575cb5caa98Sdjl 		 * More sanity check. _nscd_delete_db_entry_cookie()
576cb5caa98Sdjl 		 * could change c->idx to -1.
577cb5caa98Sdjl 		 */
578cb5caa98Sdjl 		if (db != c->db ||
579*fa845c5dSToomas Soome 		    c->idx < -1 || c->idx >= db->array_size)
580cb5caa98Sdjl 			return (NULL);
581cb5caa98Sdjl 
582cb5caa98Sdjl 		/* is there a next entry ? */
583cb5caa98Sdjl 		if (c->hash != NULL)
584cb5caa98Sdjl 			c->hash = c->hash->next_p;
585cb5caa98Sdjl 
586cb5caa98Sdjl 		/* yes, return it */
587cb5caa98Sdjl 		if (c->hash != NULL) {
588cb5caa98Sdjl 			return (&c->hash->db_entry);
589cb5caa98Sdjl 		}
590cb5caa98Sdjl 	} else {
591cb5caa98Sdjl 		c = (struct cookie *)calloc(1, sizeof (*c));
592cb5caa98Sdjl 		if (c == NULL)
593cb5caa98Sdjl 			return (NULL);
594cb5caa98Sdjl 		c->idx = -1;
595cb5caa98Sdjl 		c->hash = NULL;
596cb5caa98Sdjl 		c->db = db;
597cb5caa98Sdjl 	}
598cb5caa98Sdjl 
599cb5caa98Sdjl 	/* find the first non-empty bucket */
600cb5caa98Sdjl 	for (c->idx++; c->idx < db->array_size; c->idx++) {
601cb5caa98Sdjl 		c->hash = db->hash_tbl_p[c->idx];
602cb5caa98Sdjl 		if (c->hash != NULL)
603cb5caa98Sdjl 			break;
604cb5caa98Sdjl 	}
605cb5caa98Sdjl 
606cb5caa98Sdjl 	/* no (more) non-empty bucket, we are done */
607cb5caa98Sdjl 	if (c->hash == NULL) {
608cb5caa98Sdjl 		free(c);
609cb5caa98Sdjl 		*cookie = NULL;
610cb5caa98Sdjl 		return (NULL);
611cb5caa98Sdjl 	}
612cb5caa98Sdjl 
613cb5caa98Sdjl 	*cookie = c;
614cb5caa98Sdjl 	return (&c->hash->db_entry);
615cb5caa98Sdjl }
616