#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include "nscd_db.h"
typedef struct nscd_hash {
nscd_db_entry_t db_entry;
struct nscd_hash *next_p;
struct nscd_hash *prev_p;
} nscd_hash_t;
struct nscd_db_s {
int array_size;
nscd_hash_t **hash_tbl_p;
};
struct cookie {
int idx;
nscd_hash_t *hash;
nscd_db_t *db;
};
static unsigned long
calc_hash(
const char *str)
{
unsigned int hval = 0;
char ch;
while (*str != '\0') {
unsigned int g;
ch = (char)*str++;
if (isupper(ch))
ch = _tolower(ch);
hval = (hval << 4) + ch;
if ((g = (hval & 0xf0000000)) != 0)
hval ^= g >> 24;
hval &= ~g;
}
return ((unsigned long)hval);
}
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)
{
int id_matched = 0;
nscd_db_entry_t *db_entry;
while (idx_p != NULL) {
db_entry = &((nscd_hash_t *)idx_p)->db_entry;
if (db_entry->type == type) {
if (strcasecmp(str, db_entry->name) == 0) {
switch (option) {
case NSCD_GET_FIRST_DB_ENTRY:
return (idx_p);
case NSCD_GET_EXACT_DB_ENTRY:
if (id_num == db_entry->id_num)
return (idx_p);
break;
case NSCD_GET_NEXT_DB_ENTRY:
if (id_num < 0)
return (idx_p);
if (id_matched == 1)
return (idx_p);
if (id_num == db_entry->id_num)
id_matched = 1;
break;
}
}
}
idx_p = idx_p->next_p;
}
return (NULL);
}
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)
{
unsigned long hash;
const nscd_hash_t *idx_p, *hash_p;
if (db == NULL || str == NULL)
return (NULL);
hash = calc_hash(str);
idx_p = db->hash_tbl_p[hash % db->array_size];
hash_p = scan_hash(type, str, idx_p, option, id_num);
return (&hash_p->db_entry);
}
nscd_rc_t
_nscd_add_db_entry(
nscd_db_t *db,
const char *str,
nscd_db_entry_t *entry,
nscd_db_option_t option)
{
int i;
unsigned long hash;
nscd_hash_t *next_p = NULL, *prev_p = NULL;
nscd_hash_t *idx_p, *hash_entry;
nscd_db_entry_t *db_entry;
hash = calc_hash(str);
i = hash % db->array_size;
idx_p = db->hash_tbl_p[i];
if (idx_p == NULL)
if (option == NSCD_ADD_DB_ENTRY_REPLACE)
return (NSCD_DB_ENTRY_NOT_FOUND);
while (idx_p != NULL) {
db_entry = &idx_p->db_entry;
switch (option) {
case NSCD_ADD_DB_ENTRY_FIRST:
next_p = idx_p;
goto add_entry;
case NSCD_ADD_DB_ENTRY_REPLACE:
if (db_entry->type != entry->type)
goto cont;
if (strcasecmp(db_entry->name, str) != 0)
goto cont;
if (db_entry->id_num == entry->id_num) {
prev_p = idx_p->prev_p;
next_p = idx_p->next_p;
free(idx_p);
goto add_entry;
}
goto cont;
case NSCD_ADD_DB_ENTRY_IF_NONE:
if (db_entry->type != entry->type)
break;
if (strcasecmp(db_entry->name, str) != 0)
break;
return (NSCD_DB_ENTRY_FOUND);
}
if (idx_p->next_p == NULL) {
if (option == NSCD_ADD_DB_ENTRY_LAST ||
option == NSCD_ADD_DB_ENTRY_IF_NONE) {
prev_p = idx_p;
goto add_entry;
}
}
cont:
idx_p = idx_p->next_p;
}
add_entry:
hash_entry = (nscd_hash_t *)entry;
hash_entry->prev_p = prev_p;
if (prev_p == NULL)
db->hash_tbl_p[i] = hash_entry;
else
prev_p->next_p = hash_entry;
hash_entry->next_p = next_p;
if (next_p != NULL)
next_p->prev_p = hash_entry;
return (NSCD_SUCCESS);
}
nscd_rc_t
_nscd_delete_db_entry(
nscd_db_t *db,
int type,
const char *str,
nscd_db_option_t option,
int id_num)
{
int i;
int del_more = 0;
unsigned long hash;
nscd_hash_t *idx_p, *next_p = NULL, *prev_p = NULL;
nscd_db_entry_t *db_entry;
hash = calc_hash(str);
i = hash % db->array_size;
idx_p = db->hash_tbl_p[i];
if (idx_p == NULL)
return (NSCD_SUCCESS);
while (idx_p != NULL) {
db_entry = &idx_p->db_entry;
if (db_entry->type != type)
goto cont;
if (strcasecmp(db_entry->name, str) != 0)
goto cont;
switch (option) {
case NSCD_DEL_FIRST_DB_ENTRY:
prev_p = idx_p->prev_p;
next_p = idx_p->next_p;
del_more = 0;
break;
case NSCD_DEL_EXACT_DB_ENTRY:
if (db_entry->id_num == id_num) {
prev_p = idx_p->prev_p;
next_p = idx_p->next_p;
del_more = 0;
} else
goto cont;
break;
case NSCD_DEL_ALL_DB_ENTRY:
prev_p = idx_p->prev_p;
next_p = idx_p->next_p;
break;
}
if (prev_p == NULL)
db->hash_tbl_p[i] = next_p;
else
prev_p->next_p = next_p;
if (next_p != NULL)
next_p->prev_p = prev_p;
free(idx_p);
if (del_more == 0)
break;
idx_p = next_p;
continue;
cont:
idx_p = idx_p->next_p;
}
return (NSCD_SUCCESS);
}
nscd_db_entry_t *
_nscd_alloc_db_entry(
int type,
const char *name,
int dataSize,
int num_data,
int num_array)
{
int size;
int array_o, data_o;
nscd_hash_t *hash;
void *p;
size = sizeof (*hash) + strlen(name) + 1;
array_o = size = roundup(size);
size += (num_data + num_array) * sizeof (void **);
size = roundup(size);
data_o = size;
size += dataSize;
hash = (nscd_hash_t *)calloc(1, size);
if (hash == NULL)
return (NULL);
hash->db_entry.num_data = num_data;
hash->db_entry.num_array = num_array;
hash->db_entry.type = type;
hash->db_entry.name = (char *)hash + sizeof (*hash);
p = (char *)hash + array_o;
hash->db_entry.data_array = (void **)p;
*(hash->db_entry.data_array) = (char *)hash + data_o;
(void) strcpy(hash->db_entry.name, name);
return (&hash->db_entry);
}
void
_nscd_delete_db_entry_cookie(
nscd_db_t *db,
void **cookie)
{
nscd_hash_t *hp;
struct cookie *c;
if (cookie == NULL || *cookie == NULL || db == NULL)
return;
c = *cookie;
if (db != c->db || c->hash == NULL ||
c->idx < 0 || c->idx >= db->array_size)
return;
hp = c->hash;
if (hp->prev_p == NULL) {
c->hash = NULL;
db->hash_tbl_p[c->idx] = hp->next_p;
c->idx--;
} else {
c->hash = hp->prev_p;
hp->prev_p->next_p = hp->next_p;
}
if (hp->next_p != NULL)
hp->next_p->prev_p = hp->prev_p;
free(hp);
}
nscd_db_t *
_nscd_alloc_db(
int size)
{
int sz;
nscd_db_t *db;
db = (nscd_db_t *)calloc(1, sizeof (nscd_db_t));
if (db == NULL)
return (NULL);
if (size == NSCD_DB_SIZE_LARGE)
sz = 67;
else if (size == NSCD_DB_SIZE_MEDIUM)
sz = 37;
else if (size == NSCD_DB_SIZE_SMALL)
sz = 13;
else if (size == NSCD_DB_SIZE_TINY)
sz = 3;
db->hash_tbl_p = (nscd_hash_t **)calloc(sz + 1,
sizeof (nscd_hash_t *));
if (db->hash_tbl_p == NULL) {
free(db);
return (NULL);
}
db->array_size = sz;
return (db);
}
void
_nscd_free_db(
nscd_db_t *db)
{
int i;
nscd_hash_t *hp, *next_p;
for (i = 0; i < db->array_size; i++) {
hp = db->hash_tbl_p[i];
while (hp != NULL) {
next_p = hp->next_p;
free(hp);
hp = next_p;
}
}
free(db->hash_tbl_p);
free(db);
}
nscd_db_entry_t *
_nscd_walk_db(
nscd_db_t *db,
void **cookie)
{
struct cookie *c;
if (cookie == NULL || db == NULL)
return (NULL);
if (*cookie != NULL) {
c = *cookie;
if (db != c->db ||
c->idx < -1 || c->idx >= db->array_size)
return (NULL);
if (c->hash != NULL)
c->hash = c->hash->next_p;
if (c->hash != NULL) {
return (&c->hash->db_entry);
}
} else {
c = (struct cookie *)calloc(1, sizeof (*c));
if (c == NULL)
return (NULL);
c->idx = -1;
c->hash = NULL;
c->db = db;
}
for (c->idx++; c->idx < db->array_size; c->idx++) {
c->hash = db->hash_tbl_p[c->idx];
if (c->hash != NULL)
break;
}
if (c->hash == NULL) {
free(c);
*cookie = NULL;
return (NULL);
}
*cookie = c;
return (&c->hash->db_entry);
}