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