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