17c478bdstevel@tonic-gate/*
27c478bdstevel@tonic-gate * CDDL HEADER START
37c478bdstevel@tonic-gate *
47c478bdstevel@tonic-gate * The contents of this file are subject to the terms of the
57c478bdstevel@tonic-gate * Common Development and Distribution License, Version 1.0 only
67c478bdstevel@tonic-gate * (the "License").  You may not use this file except in compliance
77c478bdstevel@tonic-gate * with the License.
87c478bdstevel@tonic-gate *
97c478bdstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
107c478bdstevel@tonic-gate * or http://www.opensolaris.org/os/licensing.
117c478bdstevel@tonic-gate * See the License for the specific language governing permissions
127c478bdstevel@tonic-gate * and limitations under the License.
137c478bdstevel@tonic-gate *
147c478bdstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each
157c478bdstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
167c478bdstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the
177c478bdstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying
187c478bdstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner]
197c478bdstevel@tonic-gate *
207c478bdstevel@tonic-gate * CDDL HEADER END
217c478bdstevel@tonic-gate */
227c478bdstevel@tonic-gate/*
237c478bdstevel@tonic-gate *	db_table.cc
247c478bdstevel@tonic-gate *
257c478bdstevel@tonic-gate * Copyright 2004 Sun Microsystems, Inc.  All rights reserved.
267c478bdstevel@tonic-gate * Use is subject to license terms.
27a87701eGary Mills *
28a87701eGary Mills * Copyright 2015 RackTop Systems.
2948bbca8Daniel Hoffman * Copyright (c) 2016 by Delphix. All rights reserved.
307c478bdstevel@tonic-gate */
317c478bdstevel@tonic-gate
327c478bdstevel@tonic-gate#include <stdio.h>
337c478bdstevel@tonic-gate#include <malloc.h>
347c478bdstevel@tonic-gate#include <string.h>
357c478bdstevel@tonic-gate#include <stdlib.h>		/* srand48() */
367c478bdstevel@tonic-gate#include <lber.h>
377c478bdstevel@tonic-gate#include <ldap.h>
387c478bdstevel@tonic-gate#include "db_headers.h"
397c478bdstevel@tonic-gate#include "db_table.h"
407c478bdstevel@tonic-gate#include "db_pickle.h"    /* for dump and load */
417c478bdstevel@tonic-gate#include "db_entry.h"
427c478bdstevel@tonic-gate#include "nisdb_mt.h"
437c478bdstevel@tonic-gate
447c478bdstevel@tonic-gate#include "ldap_parse.h"
457c478bdstevel@tonic-gate#include "ldap_util.h"
467c478bdstevel@tonic-gate#include "ldap_map.h"
477c478bdstevel@tonic-gate#include "ldap_xdr.h"
487c478bdstevel@tonic-gate#include "nis_hashitem.h"
497c478bdstevel@tonic-gate#include "nisdb_ldap.h"
507c478bdstevel@tonic-gate#include "nis_parse_ldap_conf.h"
517c478bdstevel@tonic-gate
527c478bdstevel@tonic-gatestatic time_t	maxTimeT;
537c478bdstevel@tonic-gate
547c478bdstevel@tonic-gate/*
557c478bdstevel@tonic-gate * Find the largest (positive) value of time_t.
567c478bdstevel@tonic-gate *
577c478bdstevel@tonic-gate * If time_t is unsigned, the largest possible value is just ~0.
587c478bdstevel@tonic-gate * However, if it's signed, then ~0 is negative. Since lint (for
597c478bdstevel@tonic-gate * sure), and perhaps the compiler too, dislike comparing an
607c478bdstevel@tonic-gate * unsigned quantity to see if it's less than zero, we compare
617c478bdstevel@tonic-gate * to one instead. If negative, the largest possible value is
627c478bdstevel@tonic-gate * th inverse of 2**(N-1), where N is the number of bits in a
637c478bdstevel@tonic-gate * time_t.
647c478bdstevel@tonic-gate */
657c478bdstevel@tonic-gateextern "C" {
667c478bdstevel@tonic-gatestatic void
677c478bdstevel@tonic-gate__setMaxTimeT(void)
687c478bdstevel@tonic-gate{
697c478bdstevel@tonic-gate	unsigned char	b[sizeof (time_t)];
707c478bdstevel@tonic-gate	int		i;
717c478bdstevel@tonic-gate
727c478bdstevel@tonic-gate	/* Compute ~0 for an unknown length integer */
737c478bdstevel@tonic-gate	for (i = 0; i < sizeof (time_t); i++) {
747c478bdstevel@tonic-gate		b[i] = 0xff;
757c478bdstevel@tonic-gate	}
767c478bdstevel@tonic-gate	/* Set maxTimeT to ~0 of appropriate length */
777c478bdstevel@tonic-gate	(void) memcpy(&maxTimeT, b, sizeof (time_t));
787c478bdstevel@tonic-gate
797c478bdstevel@tonic-gate	if (maxTimeT < 1)
80a87701eGary Mills		maxTimeT = ~(1L<<((8*sizeof (maxTimeT))-1));
817c478bdstevel@tonic-gate}
827c478bdstevel@tonic-gate#pragma init(__setMaxTimeT)
837c478bdstevel@tonic-gate}
847c478bdstevel@tonic-gate
857c478bdstevel@tonic-gate/* How much to grow table by */
867c478bdstevel@tonic-gate#define	DB_TABLE_GROWTH_INCREMENT 1024
877c478bdstevel@tonic-gate
887c478bdstevel@tonic-gate/* 0'th not used; might be confusing. */
897c478bdstevel@tonic-gate#define	DB_TABLE_START 1
907c478bdstevel@tonic-gate
917c478bdstevel@tonic-gate/* prevents wrap around numbers from being passed */
927c478bdstevel@tonic-gate#define	CALLOC_LIMIT 536870911
937c478bdstevel@tonic-gate
947c478bdstevel@tonic-gate/* Initial table sizes to use before using 1K increments. */
957c478bdstevel@tonic-gate/* This helps conserve memory usage when there are lots of small tables. */
967c478bdstevel@tonic-gatestatic int tabsizes[] = {
977c478bdstevel@tonic-gate	16,
987c478bdstevel@tonic-gate	128,
997c478bdstevel@tonic-gate	512,
1007c478bdstevel@tonic-gate	DB_TABLE_GROWTH_INCREMENT,
1017c478bdstevel@tonic-gate	0
1027c478bdstevel@tonic-gate	};
1037c478bdstevel@tonic-gate
1047c478bdstevel@tonic-gate/* Returns the next size to use for table */
1057c478bdstevel@tonic-gatestatic long unsigned
1067c478bdstevel@tonic-gateget_new_table_size(long unsigned oldsize)
1077c478bdstevel@tonic-gate{
1087c478bdstevel@tonic-gate	long unsigned newsize = 0, n;
1097c478bdstevel@tonic-gate	if (oldsize == 0)
1107c478bdstevel@tonic-gate		newsize = tabsizes[0];
1117c478bdstevel@tonic-gate	else {
1127c478bdstevel@tonic-gate		for (n = 0; newsize = tabsizes[n++]; )
1137c478bdstevel@tonic-gate			if (oldsize == newsize) {
1147c478bdstevel@tonic-gate				newsize = tabsizes[n];	/* get next size */
1157c478bdstevel@tonic-gate				break;
1167c478bdstevel@tonic-gate			}
1177c478bdstevel@tonic-gate		if (newsize == 0)
1187c478bdstevel@tonic-gate			newsize = oldsize + DB_TABLE_GROWTH_INCREMENT;
1197c478bdstevel@tonic-gate	}
1207c478bdstevel@tonic-gate	return (newsize);
1217c478bdstevel@tonic-gate}
1227c478bdstevel@tonic-gate
1237c478bdstevel@tonic-gate
1247c478bdstevel@tonic-gate/* destructor */
1257c478bdstevel@tonic-gatedb_free_list::~db_free_list()
1267c478bdstevel@tonic-gate{
1277c478bdstevel@tonic-gate	WRITELOCKV(this, "w db_free_list::~db_free_list");
1287c478bdstevel@tonic-gate	reset();   /* free list entries */
1297c478bdstevel@tonic-gate	DESTROYRW(free_list);
1307c478bdstevel@tonic-gate}
1317c478bdstevel@tonic-gate
1327c478bdstevel@tonic-gatevoid
1337c478bdstevel@tonic-gatedb_free_list::reset()
1347c478bdstevel@tonic-gate{
1357c478bdstevel@tonic-gate	db_free_entry *current, *nextentry;
1367c478bdstevel@tonic-gate
1377c478bdstevel@tonic-gate	WRITELOCKV(this, "w db_free_list::reset");
1387c478bdstevel@tonic-gate	for (current = head; current != NULL; ) {
1397c478bdstevel@tonic-gate		nextentry = current->next;
1407c478bdstevel@tonic-gate		delete current;
1417c478bdstevel@tonic-gate		current = nextentry;
1427c478bdstevel@tonic-gate	}
1437c478bdstevel@tonic-gate	head = NULL;
1447c478bdstevel@tonic-gate	count = 0;
1457c478bdstevel@tonic-gate	WRITEUNLOCKV(this, "wu db_free_list::reset");
1467c478bdstevel@tonic-gate}
1477c478bdstevel@tonic-gate
148bc30fb4Toomas Soome/* Returns the location of a free entry, or 0, if there aren't any. */
1497c478bdstevel@tonic-gateentryp
1507c478bdstevel@tonic-gatedb_free_list::pop()
1517c478bdstevel@tonic-gate{
152bc30fb4Toomas Soome	WRITELOCK(this, 0, "w db_free_list::pop");
1537c478bdstevel@tonic-gate	if (head == NULL) {
154bc30fb4Toomas Soome		WRITEUNLOCK(this, 0, "wu db_free_list::pop");
155bc30fb4Toomas Soome		return (0);
1567c478bdstevel@tonic-gate	}
1577c478bdstevel@tonic-gate	db_free_entry* old_head = head;
1587c478bdstevel@tonic-gate	entryp found = head->where;
1597c478bdstevel@tonic-gate	head = head->next;
1607c478bdstevel@tonic-gate	delete old_head;
1617c478bdstevel@tonic-gate	--count;
1627c478bdstevel@tonic-gate	WRITEUNLOCK(this, found, "wu db_free_list::pop");
1637c478bdstevel@tonic-gate	return (found);
1647c478bdstevel@tonic-gate}
1657c478bdstevel@tonic-gate
1667c478bdstevel@tonic-gate/*
1677c478bdstevel@tonic-gate * Adds given location to the free list.
1687c478bdstevel@tonic-gate * Returns TRUE if successful, FALSE otherwise (when out of memory).
1697c478bdstevel@tonic-gate*/
1707c478bdstevel@tonic-gatebool_t
1717c478bdstevel@tonic-gatedb_free_list::push(entryp tabloc)
1727c478bdstevel@tonic-gate{
1737c478bdstevel@tonic-gate	db_free_entry * newentry = new db_free_entry;
1747c478bdstevel@tonic-gate
1757c478bdstevel@tonic-gate	WRITELOCK(this, FALSE, "w db_free_list::push");
1767c478bdstevel@tonic-gate	if (newentry == NULL) {
1777c478bdstevel@tonic-gate		WRITEUNLOCK(this, FALSE, "wu db_free_list::push");
1787c478bdstevel@tonic-gate	    FATAL3("db_free_list::push: cannot allocation space",
1797c478bdstevel@tonic-gate		    DB_MEMORY_LIMIT, FALSE);
1807c478bdstevel@tonic-gate	}
1817c478bdstevel@tonic-gate	newentry->where = tabloc;
1827c478bdstevel@tonic-gate	newentry->next = head;
1837c478bdstevel@tonic-gate	head = newentry;
1847c478bdstevel@tonic-gate	++count;
1857c478bdstevel@tonic-gate	WRITEUNLOCK(this, TRUE, "wu db_free_list::push");
1867c478bdstevel@tonic-gate	return (TRUE);
1877c478bdstevel@tonic-gate}
1887c478bdstevel@tonic-gate
1897c478bdstevel@tonic-gate/*
1907c478bdstevel@tonic-gate * Returns in a vector the information in the free list.
1917c478bdstevel@tonic-gate * Vector returned is of form: [n free cells][n1][n2][loc1], ..[locn].
1927c478bdstevel@tonic-gate * Leave the first 'n' cells free.
1937c478bdstevel@tonic-gate * n1 is the number of entries that should be in the freelist.
1947c478bdstevel@tonic-gate * n2 is the number of entries actually found in the freelist.
1957c478bdstevel@tonic-gate * [loc1...locn] are the entries.   n2 <= n1 because we never count beyond n1.
19648bbca8Daniel Hoffman * It is up to the caller to free the returned vector when it is through.
1977c478bdstevel@tonic-gate*/
1987c478bdstevel@tonic-gatelong *
1997c478bdstevel@tonic-gatedb_free_list::stats(int nslots)
2007c478bdstevel@tonic-gate{
2017c478bdstevel@tonic-gate	long	realcount = 0,
2027c478bdstevel@tonic-gate		i,
2037c478bdstevel@tonic-gate		liststart = nslots,		// start of freelist
2047c478bdstevel@tonic-gate		listend = nslots+count+2;	// end of freelist
2057c478bdstevel@tonic-gate	db_free_entry_p current = head;
2067c478bdstevel@tonic-gate
2077c478bdstevel@tonic-gate	READLOCK(this, NULL, "r db_free_list::stats");
2087c478bdstevel@tonic-gate
2097c478bdstevel@tonic-gate	long *answer = (long *)malloc((int)(listend)*sizeof (long));
2107c478bdstevel@tonic-gate	if (answer == 0) {
2117c478bdstevel@tonic-gate		READUNLOCK(this, NULL, "ru db_free_list::stats");
2127c478bdstevel@tonic-gate		FATAL3("db_free_list::stats:  cannot allocation space",
2137c478bdstevel@tonic-gate		    DB_MEMORY_LIMIT, NULL);
2147c478bdstevel@tonic-gate	}
2157c478bdstevel@tonic-gate
2167c478bdstevel@tonic-gate	answer[liststart] = count;  /* size of freelist */
2177c478bdstevel@tonic-gate
2187c478bdstevel@tonic-gate	for (i = liststart+2; i < listend && current != NULL; i++) {
2197c478bdstevel@tonic-gate		answer[i] = current->where;
2207c478bdstevel@tonic-gate		current = current->next;
2217c478bdstevel@tonic-gate		++realcount;
2227c478bdstevel@tonic-gate	}
2237c478bdstevel@tonic-gate
2247c478bdstevel@tonic-gate	answer[liststart+1] = realcount;
2257c478bdstevel@tonic-gate	READUNLOCK(this, answer, "ru db_free_list::stats");
2267c478bdstevel@tonic-gate	return (answer);
2277c478bdstevel@tonic-gate}
2287c478bdstevel@tonic-gate
2297c478bdstevel@tonic-gate
2307c478bdstevel@tonic-gate/* Set default values for the mapping structure */
2317c478bdstevel@tonic-gatevoid
2327c478bdstevel@tonic-gatedb_table::initMappingStruct(__nisdb_table_mapping_t *m) {
2337c478bdstevel@tonic-gate	if (m == 0)
2347c478bdstevel@tonic-gate		return;
2357c478bdstevel@tonic-gate
2367c478bdstevel@tonic-gate	m->initTtlLo = (ldapDBTableMapping.initTtlLo > 0) ?
2377c478bdstevel@tonic-gate			ldapDBTableMapping.initTtlLo : (3600-1800);
2387c478bdstevel@tonic-gate	m->initTtlHi = (ldapDBTableMapping.initTtlHi > 0) ?
2397c478bdstevel@tonic-gate			ldapDBTableMapping.initTtlHi : (3600+1800);
2407c478bdstevel@tonic-gate	m->ttl = (ldapDBTableMapping.ttl > 0) ?
2417c478bdstevel@tonic-gate			ldapDBTableMapping.ttl : 3600;
2427c478bdstevel@tonic-gate	m->enumExpire = 0;
2437c478bdstevel@tonic-gate	m->fromLDAP = FALSE;
2447c478bdstevel@tonic-gate	m->toLDAP = FALSE;
2457c478bdstevel@tonic-gate	m->isMaster = FALSE;
2467c478bdstevel@tonic-gate	m->retrieveError = ldapDBTableMapping.retrieveError;
2477c478bdstevel@tonic-gate	m->retrieveErrorRetry.attempts =
2487c478bdstevel@tonic-gate		ldapDBTableMapping.retrieveErrorRetry.attempts;
2497c478bdstevel@tonic-gate	m->retrieveErrorRetry.timeout =
2507c478bdstevel@tonic-gate		ldapDBTableMapping.retrieveErrorRetry.timeout;
2517c478bdstevel@tonic-gate	m->storeError = ldapDBTableMapping.storeError;
2527c478bdstevel@tonic-gate	m->storeErrorRetry.attempts =
2537c478bdstevel@tonic-gate		ldapDBTableMapping.storeErrorRetry.attempts;
2547c478bdstevel@tonic-gate	m->storeErrorRetry.timeout =
2557c478bdstevel@tonic-gate		ldapDBTableMapping.storeErrorRetry.timeout;
2567c478bdstevel@tonic-gate	m->storeErrorDisp = ldapDBTableMapping.storeErrorDisp;
2577c478bdstevel@tonic-gate	m->refreshError = ldapDBTableMapping.refreshError;
2587c478bdstevel@tonic-gate	m->refreshErrorRetry.attempts =
2597c478bdstevel@tonic-gate		ldapDBTableMapping.refreshErrorRetry.attempts;
2607c478bdstevel@tonic-gate	m->refreshErrorRetry.timeout =
2617c478bdstevel@tonic-gate		ldapDBTableMapping.refreshErrorRetry.timeout;
2627c478bdstevel@tonic-gate	m->matchFetch = ldapDBTableMapping.matchFetch;
2637c478bdstevel@tonic-gate
2647c478bdstevel@tonic-gate	if (mapping.expire != 0)
2657c478bdstevel@tonic-gate		free(mapping.expire);
2667c478bdstevel@tonic-gate	m->expire = 0;
2677c478bdstevel@tonic-gate
2687c478bdstevel@tonic-gate	if (m->tm != 0)
2697c478bdstevel@tonic-gate		free(m->tm);
2707c478bdstevel@tonic-gate	m->tm = 0;
2717c478bdstevel@tonic-gate
2727c478bdstevel@tonic-gate	/*
2737c478bdstevel@tonic-gate	 * The 'objType' field obviously indicates the type of object.
2747c478bdstevel@tonic-gate	 * However, we also use it to tell us if we've retrieved mapping
2757c478bdstevel@tonic-gate	 * data from LDAP or not; in the latter case, 'objType' is
2767c478bdstevel@tonic-gate	 * NIS_BOGUS_OBJ. For purposes of maintaining expiration times,
2777c478bdstevel@tonic-gate	 * we may need to know if the object is a table or a directory
2787c478bdstevel@tonic-gate	 * _before_ we've retrieved any mapping data. Hence the 'expireType'
2797c478bdstevel@tonic-gate	 * field, which starts as NIS_BOGUS_OBJ (meaning, don't know, assume
2807c478bdstevel@tonic-gate	 * directory for now), and later is set to NIS_DIRECTORY_OBJ
2817c478bdstevel@tonic-gate	 * (always keep expiration data, in case one of the dir entries
2827c478bdstevel@tonic-gate	 * is mapped) or NIS_TABLE_OBJ (only need expiration data if
2837c478bdstevel@tonic-gate	 * tha table is mapped).
2847c478bdstevel@tonic-gate	 */
2857c478bdstevel@tonic-gate	m->objType = NIS_BOGUS_OBJ;
2867c478bdstevel@tonic-gate	m->expireType = NIS_BOGUS_OBJ;
2877c478bdstevel@tonic-gate	if (m->objName != 0)
2887c478bdstevel@tonic-gate		free(m->objName);
2897c478bdstevel@tonic-gate	m->objName = 0;
2907c478bdstevel@tonic-gate}
2917c478bdstevel@tonic-gate
2927c478bdstevel@tonic-gatevoid
2937c478bdstevel@tonic-gatedb_table::db_table_ldap_init(void) {
2947c478bdstevel@tonic-gate
2957c478bdstevel@tonic-gate	INITRW(table);
2967c478bdstevel@tonic-gate
2977c478bdstevel@tonic-gate	enumMode.flag = 0;
2987c478bdstevel@tonic-gate	enumCount.flag = 0;
2997c478bdstevel@tonic-gate	enumIndex.ptr = 0;
3007c478bdstevel@tonic-gate	enumArray.ptr = 0;
3017c478bdstevel@tonic-gate
3027c478bdstevel@tonic-gate	mapping.expire = 0;
3037c478bdstevel@tonic-gate	mapping.tm = 0;
3047c478bdstevel@tonic-gate	mapping.objName = 0;
3057c478bdstevel@tonic-gate	mapping.isDeferredTable = FALSE;
3067c478bdstevel@tonic-gate	(void) mutex_init(&mapping.enumLock, 0, 0);
3077c478bdstevel@tonic-gate	mapping.enumTid = 0;
3087c478bdstevel@tonic-gate	mapping.enumStat = -1;
3097c478bdstevel@tonic-gate	mapping.enumDeferred = 0;
3107c478bdstevel@tonic-gate	mapping.enumEntries = 0;
3117c478bdstevel@tonic-gate	mapping.enumTime = 0;
3127c478bdstevel@tonic-gate}
3137c478bdstevel@tonic-gate
3147c478bdstevel@tonic-gate/* db_table constructor */
3157c478bdstevel@tonic-gatedb_table::db_table() : freelist()
3167c478bdstevel@tonic-gate{
3177c478bdstevel@tonic-gate	tab = NULL;
3187c478bdstevel@tonic-gate	table_size = 0;
3197c478bdstevel@tonic-gate	last_used = 0;
3207c478bdstevel@tonic-gate	count = 0;
3217c478bdstevel@tonic-gate
3227c478bdstevel@tonic-gate	db_table_ldap_init();
3237c478bdstevel@tonic-gate	initMappingStruct(&mapping);
3247c478bdstevel@tonic-gate
3257c478bdstevel@tonic-gate/*  grow(); */
3267c478bdstevel@tonic-gate}
3277c478bdstevel@tonic-gate
3287c478bdstevel@tonic-gate/*
3297c478bdstevel@tonic-gate * db_table destructor:
3307c478bdstevel@tonic-gate * 1.  Get rid of contents of freelist
3317c478bdstevel@tonic-gate * 2.  delete all entries hanging off table
3327c478bdstevel@tonic-gate * 3.  get rid of table itself
3337c478bdstevel@tonic-gate*/
3347c478bdstevel@tonic-gatedb_table::~db_table()
3357c478bdstevel@tonic-gate{
3367c478bdstevel@tonic-gate	WRITELOCKV(this, "w db_table::~db_table");
3377c478bdstevel@tonic-gate	reset();
3387c478bdstevel@tonic-gate	DESTROYRW(table);
3397c478bdstevel@tonic-gate}
3407c478bdstevel@tonic-gate
3417c478bdstevel@tonic-gate/* reset size and pointers */
3427c478bdstevel@tonic-gatevoid
3437c478bdstevel@tonic-gatedb_table::reset()
3447c478bdstevel@tonic-gate{
3457c478bdstevel@tonic-gate	int i, done = 0;
3467c478bdstevel@tonic-gate
3477c478bdstevel@tonic-gate	WRITELOCKV(this, "w db_table::reset");
3487c478bdstevel@tonic-gate	freelist.reset();
3497c478bdstevel@tonic-gate
3507c478bdstevel@tonic-gate	/* Add sanity check in case of table corruption */
3517c478bdstevel@tonic-gate	if (tab != NULL) {
3527c478bdstevel@tonic-gate		for (i = 0;
3537c478bdstevel@tonic-gate			i <= last_used && i < table_size && done < count;
3547c478bdstevel@tonic-gate			i++) {
3557c478bdstevel@tonic-gate			if (tab[i]) {
3567c478bdstevel@tonic-gate				free_entry(tab[i]);
3577c478bdstevel@tonic-gate				++done;
3587c478bdstevel@tonic-gate			}
3597c478bdstevel@tonic-gate		}
3607c478bdstevel@tonic-gate	}
3617c478bdstevel@tonic-gate
3627c478bdstevel@tonic-gate	delete tab;
3637c478bdstevel@tonic-gate	table_size = last_used = count = 0;
3647c478bdstevel@tonic-gate	tab = NULL;
3657c478bdstevel@tonic-gate	sfree(mapping.expire);
3667c478bdstevel@tonic-gate	mapping.expire = NULL;
3677c478bdstevel@tonic-gate	mapping.objType = NIS_BOGUS_OBJ;
3687c478bdstevel@tonic-gate	mapping.expireType = NIS_BOGUS_OBJ;
3697c478bdstevel@tonic-gate	sfree(mapping.objName);
3707c478bdstevel@tonic-gate	mapping.objName = 0;
3717c478bdstevel@tonic-gate	/* Leave other values of the mapping structure unchanged */
3727c478bdstevel@tonic-gate	enumMode.flag = 0;
3737c478bdstevel@tonic-gate	enumCount.flag = 0;
3747c478bdstevel@tonic-gate	sfree(enumIndex.ptr);
3757c478bdstevel@tonic-gate	enumIndex.ptr = 0;
3767c478bdstevel@tonic-gate	sfree(enumArray.ptr);
3777c478bdstevel@tonic-gate	enumArray.ptr = 0;
3787c478bdstevel@tonic-gate	WRITEUNLOCKV(this, "wu db_table::reset");
3797c478bdstevel@tonic-gate}
3807c478bdstevel@tonic-gate
3817c478bdstevel@tonic-gatedb_status
3827c478bdstevel@tonic-gatedb_table::allocateExpire(long oldSize, long newSize) {
3837c478bdstevel@tonic-gate	time_t			*newExpire;
3847c478bdstevel@tonic-gate
3857c478bdstevel@tonic-gate	newExpire = (time_t *)realloc(mapping.expire,
3867c478bdstevel@tonic-gate				newSize * sizeof (mapping.expire[0]));
3877c478bdstevel@tonic-gate	if (newExpire != NULL) {
3887c478bdstevel@tonic-gate		/* Initialize new portion */
3897c478bdstevel@tonic-gate		(void) memset(&newExpire[oldSize], 0,
3907c478bdstevel@tonic-gate				(newSize-oldSize) * sizeof (newExpire[0]));
3917c478bdstevel@tonic-gate		mapping.expire = newExpire;
3927c478bdstevel@tonic-gate	} else {
3937c478bdstevel@tonic-gate		return (DB_MEMORY_LIMIT);
3947c478bdstevel@tonic-gate	}
3957c478bdstevel@tonic-gate
3967c478bdstevel@tonic-gate	return (DB_SUCCESS);
3977c478bdstevel@tonic-gate}
3987c478bdstevel@tonic-gate
3997c478bdstevel@tonic-gatedb_status
4007c478bdstevel@tonic-gatedb_table::allocateEnumArray(long oldSize, long newSize) {
4017c478bdstevel@tonic-gate	entry_object	**newEnumArray;
4028d0852bRichard Lowe	const char	*myself = "db_table::allocateEnumArray";
4037c478bdstevel@tonic-gate
4047c478bdstevel@tonic-gate	if (enumCount.flag > 0) {
4057c478bdstevel@tonic-gate		if (enumIndex.ptr == 0) {
4067c478bdstevel@tonic-gate			enumIndex.ptr = (entryp *)am(myself, enumCount.flag *
4077c478bdstevel@tonic-gate						sizeof (entryp));
4087c478bdstevel@tonic-gate			if (enumIndex.ptr == 0)
4097c478bdstevel@tonic-gate				return (DB_MEMORY_LIMIT);
4107c478bdstevel@tonic-gate		}
4117c478bdstevel@tonic-gate		oldSize = 0;
4127c478bdstevel@tonic-gate		newSize = enumCount.flag;
4137c478bdstevel@tonic-gate	}
4147c478bdstevel@tonic-gate	newEnumArray = (entry_object **)realloc(enumArray.ptr,
4157c478bdstevel@tonic-gate			newSize * sizeof (entry_object *));
4167c478bdstevel@tonic-gate	if (newEnumArray != 0 && newSize > oldSize) {
4177c478bdstevel@tonic-gate		(void) memcpy(&newEnumArray[oldSize], &tab[oldSize],
4187c478bdstevel@tonic-gate			(newSize-oldSize) * sizeof (entry_object *));
4197c478bdstevel@tonic-gate		enumArray.ptr = newEnumArray;
4207c478bdstevel@tonic-gate	} else if (newEnumArray == 0) {
4217c478bdstevel@tonic-gate		return (DB_MEMORY_LIMIT);
4227c478bdstevel@tonic-gate	}
4237c478bdstevel@tonic-gate
4247c478bdstevel@tonic-gate	return (DB_SUCCESS);
4257c478bdstevel@tonic-gate}
4267c478bdstevel@tonic-gate
4277c478bdstevel@tonic-gate/* Expand the table.  Fatal error if insufficient memory. */
4287c478bdstevel@tonic-gatevoid
4297c478bdstevel@tonic-gatedb_table::grow()
4307c478bdstevel@tonic-gate{
4317c478bdstevel@tonic-gate	WRITELOCKV(this, "w db_table::grow");
4327c478bdstevel@tonic-gate	long oldsize = table_size;
4337c478bdstevel@tonic-gate	entry_object_p *oldtab = tab;
4347c478bdstevel@tonic-gate	long i;
4357c478bdstevel@tonic-gate
4367c478bdstevel@tonic-gate	table_size = get_new_table_size(oldsize);
4377c478bdstevel@tonic-gate
4387c478bdstevel@tonic-gate#ifdef DEBUG
4397c478bdstevel@tonic-gate	fprintf(stderr, "db_table GROWING to %d\n", table_size);
4407c478bdstevel@tonic-gate#endif
4417c478bdstevel@tonic-gate
4427c478bdstevel@tonic-gate	if (table_size > CALLOC_LIMIT) {
4437c478bdstevel@tonic-gate		table_size = oldsize;
4447c478bdstevel@tonic-gate		WRITEUNLOCKV(this, "wu db_table::grow");
4457c478bdstevel@tonic-gate		FATAL("db_table::grow: table size exceeds calloc limit",
4467c478bdstevel@tonic-gate			DB_MEMORY_LIMIT);
4477c478bdstevel@tonic-gate	}
4487c478bdstevel@tonic-gate
4497c478bdstevel@tonic-gate//  if ((tab = new entry_object_p[table_size]) == NULL)
4507c478bdstevel@tonic-gate	if ((tab = (entry_object_p*)
4517c478bdstevel@tonic-gate		calloc((unsigned int) table_size,
4527c478bdstevel@tonic-gate			sizeof (entry_object_p))) == NULL) {
4537c478bdstevel@tonic-gate		tab = oldtab;		// restore previous table info
4547c478bdstevel@tonic-gate		table_size = oldsize;
4557c478bdstevel@tonic-gate		WRITEUNLOCKV(this, "wu db_table::grow");
4567c478bdstevel@tonic-gate		FATAL("db_table::grow: cannot allocate space", DB_MEMORY_LIMIT);
4577c478bdstevel@tonic-gate	}
4587c478bdstevel@tonic-gate
4597c478bdstevel@tonic-gate	/*
4607c478bdstevel@tonic-gate	 * For directories, we may need the expire time array even if the
4617c478bdstevel@tonic-gate	 * directory itself isn't mapped. If the objType and expireType both
4627c478bdstevel@tonic-gate	 * are bogus, we don't  know yet if this is a table or a directory,
4637c478bdstevel@tonic-gate	 * and must proceed accordingly.
4647c478bdstevel@tonic-gate	 */
4657c478bdstevel@tonic-gate	if (mapping.objType == NIS_DIRECTORY_OBJ ||
4667c478bdstevel@tonic-gate			mapping.expireType != NIS_TABLE_OBJ ||
4677c478bdstevel@tonic-gate			mapping.fromLDAP) {
4687c478bdstevel@tonic-gate		db_status stat = allocateExpire(oldsize, table_size);
4697c478bdstevel@tonic-gate		if (stat != DB_SUCCESS) {
4707c478bdstevel@tonic-gate			free(tab);
4717c478bdstevel@tonic-gate			tab = oldtab;
4727c478bdstevel@tonic-gate			table_size = oldsize;
4737c478bdstevel@tonic-gate			WRITEUNLOCKV(this, "wu db_table::grow expire");
4747c478bdstevel@tonic-gate			FATAL(
4757c478bdstevel@tonic-gate		"db_table::grow: cannot allocate space for expire", stat);
4767c478bdstevel@tonic-gate		}
4777c478bdstevel@tonic-gate	}
4787c478bdstevel@tonic-gate
4797c478bdstevel@tonic-gate	if (oldtab != NULL) {
4807c478bdstevel@tonic-gate		for (i = 0; i < oldsize; i++) { // transfer old to new
4817c478bdstevel@tonic-gate			tab[i] = oldtab[i];
4827c478bdstevel@tonic-gate		}
4837c478bdstevel@tonic-gate		delete oldtab;
4847c478bdstevel@tonic-gate	}
4857c478bdstevel@tonic-gate
4867c478bdstevel@tonic-gate	if (enumMode.flag) {
4877c478bdstevel@tonic-gate		db_status stat = allocateEnumArray(oldsize, table_size);
4887c478bdstevel@tonic-gate		if (stat != DB_SUCCESS) {
4897c478bdstevel@tonic-gate			free(tab);
4907c478bdstevel@tonic-gate			tab = oldtab;
4917c478bdstevel@tonic-gate			table_size = oldsize;
4927c478bdstevel@tonic-gate			WRITEUNLOCKV(this, "wu db_table::grow enumArray");
4937c478bdstevel@tonic-gate			FATAL(
4947c478bdstevel@tonic-gate		"db_table::grow: cannot allocate space for enumArray", stat);
4957c478bdstevel@tonic-gate		}
4967c478bdstevel@tonic-gate	}
4977c478bdstevel@tonic-gate
4987c478bdstevel@tonic-gate	WRITEUNLOCKV(this, "wu db_table::grow");
4997c478bdstevel@tonic-gate}
5007c478bdstevel@tonic-gate
5017c478bdstevel@tonic-gate/*
5027c478bdstevel@tonic-gate * Return the first entry in table, also return its position in
5037c478bdstevel@tonic-gate * 'where'.  Return NULL in both if no next entry is found.
5047c478bdstevel@tonic-gate */
5057c478bdstevel@tonic-gateentry_object*
5067c478bdstevel@tonic-gatedb_table::first_entry(entryp * where)
5077c478bdstevel@tonic-gate{
5087c478bdstevel@tonic-gate	ASSERTRHELD(table);
5097c478bdstevel@tonic-gate	if (count == 0 || tab == NULL) {  /* empty table */
510bc30fb4Toomas Soome		*where = 0;
5117c478bdstevel@tonic-gate		return (NULL);
5127c478bdstevel@tonic-gate	} else {
5137c478bdstevel@tonic-gate		entryp i;
5147c478bdstevel@tonic-gate		for (i = DB_TABLE_START;
5157c478bdstevel@tonic-gate			i < table_size && i <= last_used; i++) {
5167c478bdstevel@tonic-gate			if (tab[i] != NULL) {
5177c478bdstevel@tonic-gate				*where = i;
5187c478bdstevel@tonic-gate				return (tab[i]);
5197c478bdstevel@tonic-gate			}
5207c478bdstevel@tonic-gate		}
5217c478bdstevel@tonic-gate	}
522bc30fb4Toomas Soome	*where = 0;
5237c478bdstevel@tonic-gate	return (NULL);
5247c478bdstevel@tonic-gate}
5257c478bdstevel@tonic-gate
5267c478bdstevel@tonic-gate/*
5277c478bdstevel@tonic-gate * Return the next entry in table from 'prev', also return its position in
5287c478bdstevel@tonic-gate * 'newentry'.  Return NULL in both if no next entry is found.
5297c478bdstevel@tonic-gate */
5307c478bdstevel@tonic-gateentry_object *
5317c478bdstevel@tonic-gatedb_table::next_entry(entryp prev, entryp* newentry)
5327c478bdstevel@tonic-gate{
5337c478bdstevel@tonic-gate	long i;
5347c478bdstevel@tonic-gate
5357c478bdstevel@tonic-gate	ASSERTRHELD(table);
5367c478bdstevel@tonic-gate	if (prev >= table_size || tab == NULL || tab[prev] == NULL)
5377c478bdstevel@tonic-gate		return (NULL);
5387c478bdstevel@tonic-gate	for (i = prev+1; i < table_size && i <= last_used; i++) {
5397c478bdstevel@tonic-gate		if (tab[i] != NULL) {
5407c478bdstevel@tonic-gate			*newentry = i;
5417c478bdstevel@tonic-gate			return (tab[i]);
5427c478bdstevel@tonic-gate		}
5437c478bdstevel@tonic-gate	}
544bc30fb4Toomas Soome	*newentry = 0;
5457c478bdstevel@tonic-gate	return (NULL);
5467c478bdstevel@tonic-gate}
5477c478bdstevel@tonic-gate
5487c478bdstevel@tonic-gate/* Return entry at location 'where', NULL if location is invalid. */
5497c478bdstevel@tonic-gateentry_object *
5507c478bdstevel@tonic-gatedb_table::get_entry(entryp where)
5517c478bdstevel@tonic-gate{
5527c478bdstevel@tonic-gate	ASSERTRHELD(table);
5537c478bdstevel@tonic-gate	if (where < table_size && tab != NULL && tab[where] != NULL)
5547c478bdstevel@tonic-gate		return (tab[where]);
5557c478bdstevel@tonic-gate	else
5567c478bdstevel@tonic-gate		return (NULL);
5577c478bdstevel@tonic-gate}
5587c478bdstevel@tonic-gate
5597c478bdstevel@tonic-gatevoid
5607c478bdstevel@tonic-gatedb_table::setEntryExp(entryp where, entry_obj *obj, int initialLoad) {
5617c478bdstevel@tonic-gate	nis_object		*o;
5628d0852bRichard Lowe	const char		*myself = "db_table::setEntryExp";
5637c478bdstevel@tonic-gate
5647c478bdstevel@tonic-gate	/*
5657c478bdstevel@tonic-gate	 * If we don't know what type of object this is yet, we
5667c478bdstevel@tonic-gate	 * can find out now. If it's a directory, the pseudo-object
5677c478bdstevel@tonic-gate	 * in column zero will have the type "IN_DIRECTORY";
5687c478bdstevel@tonic-gate	 * otherwise, it's a table object.
5697c478bdstevel@tonic-gate	 */
5707c478bdstevel@tonic-gate	if (mapping.expireType == NIS_BOGUS_OBJ) {
5717c478bdstevel@tonic-gate		if (obj != 0) {
5727c478bdstevel@tonic-gate			if (obj->en_type != 0 &&
5737c478bdstevel@tonic-gate				strcmp(obj->en_type, "IN_DIRECTORY") == 0) {
5747c478bdstevel@tonic-gate				mapping.expireType = NIS_DIRECTORY_OBJ;
5757c478bdstevel@tonic-gate			} else {
5767c478bdstevel@tonic-gate				mapping.expireType = NIS_TABLE_OBJ;
5777c478bdstevel@tonic-gate				if (!mapping.fromLDAP) {
5787c478bdstevel@tonic-gate					free(mapping.expire);
5797c478bdstevel@tonic-gate					mapping.expire = 0;
5807c478bdstevel@tonic-gate				}
5817c478bdstevel@tonic-gate			}
5827c478bdstevel@tonic-gate		}
5837c478bdstevel@tonic-gate	}
5847c478bdstevel@tonic-gate
5857c478bdstevel@tonic-gate	/* Set the entry TTL */
5867c478bdstevel@tonic-gate	if (mapping.expire != NULL) {
5877c478bdstevel@tonic-gate		struct timeval	now;
5887c478bdstevel@tonic-gate		time_t		lo, hi, ttl;
5897c478bdstevel@tonic-gate
5907c478bdstevel@tonic-gate		(void) gettimeofday(&now, NULL);
5917c478bdstevel@tonic-gate		if (mapping.expireType == NIS_TABLE_OBJ) {
5927c478bdstevel@tonic-gate			lo = mapping.initTtlLo;
5937c478bdstevel@tonic-gate			hi = mapping.initTtlHi;
5947c478bdstevel@tonic-gate			ttl = mapping.ttl;
5957c478bdstevel@tonic-gate			/* TTL == 0 means always expired */
5967c478bdstevel@tonic-gate			if (ttl == 0)
5977c478bdstevel@tonic-gate				ttl = -1;
5987c478bdstevel@tonic-gate		} else {
5997c478bdstevel@tonic-gate			__nis_table_mapping_t	*t = 0;
6007c478bdstevel@tonic-gate
6017c478bdstevel@tonic-gate			o = unmakePseudoEntryObj(obj, 0);
6027c478bdstevel@tonic-gate			if (o != 0) {
6037c478bdstevel@tonic-gate				__nis_buffer_t	b = {0, 0};
6047c478bdstevel@tonic-gate
6057c478bdstevel@tonic-gate				bp2buf(myself, &b, "%s.%s",
6067c478bdstevel@tonic-gate					o->zo_name, o->zo_domain);
6077c478bdstevel@tonic-gate				t = getObjMapping(b.buf, 0, 1, 0, 0);
6087c478bdstevel@tonic-gate				sfree(b.buf);
6097c478bdstevel@tonic-gate				nis_destroy_object(o);
6107c478bdstevel@tonic-gate			}
6117c478bdstevel@tonic-gate
6127c478bdstevel@tonic-gate			if (t != 0) {
6137c478bdstevel@tonic-gate				lo = t->initTtlLo;
6147c478bdstevel@tonic-gate				hi = t->initTtlHi;
6157c478bdstevel@tonic-gate				ttl = t->ttl;
6167c478bdstevel@tonic-gate				/* TTL == 0 means always expired */
6177c478bdstevel@tonic-gate				if (ttl == 0)
6187c478bdstevel@tonic-gate					ttl = -1;
6197c478bdstevel@tonic-gate			} else {
6207c478bdstevel@tonic-gate				/*
6217c478bdstevel@tonic-gate				 * No expiration time initialization
6227c478bdstevel@tonic-gate				 * data. Cook up values that will
6237c478bdstevel@tonic-gate				 * result in mapping.expire[where]
6247c478bdstevel@tonic-gate				 * set to maxTimeT.
6257c478bdstevel@tonic-gate				 */
6267c478bdstevel@tonic-gate				hi = lo = ttl = maxTimeT - now.tv_sec;
6277c478bdstevel@tonic-gate			}
6287c478bdstevel@tonic-gate		}
6297c478bdstevel@tonic-gate
6307c478bdstevel@tonic-gate		if (initialLoad) {
6317c478bdstevel@tonic-gate			int	interval = hi - lo + 1;
6327c478bdstevel@tonic-gate			if (interval <= 1) {
6337c478bdstevel@tonic-gate				mapping.expire[where] = now.tv_sec + lo;
6347c478bdstevel@tonic-gate			} else {
6357c478bdstevel@tonic-gate				srand48(now.tv_sec);
6367c478bdstevel@tonic-gate				mapping.expire[where] = now.tv_sec +
6377c478bdstevel@tonic-gate							(lrand48() % interval);
6387c478bdstevel@tonic-gate			}
6397c478bdstevel@tonic-gate			if (mapping.enumExpire == 0 ||
6407c478bdstevel@tonic-gate					mapping.expire[where] <
6417c478bdstevel@tonic-gate							mapping.enumExpire)
6427c478bdstevel@tonic-gate				mapping.enumExpire = mapping.expire[where];
6437c478bdstevel@tonic-gate		} else {
6447c478bdstevel@tonic-gate			mapping.expire[where] = now.tv_sec + ttl;
6457c478bdstevel@tonic-gate		}
6467c478bdstevel@tonic-gate	}
6477c478bdstevel@tonic-gate}
6487c478bdstevel@tonic-gate
6497c478bdstevel@tonic-gate/*
6507c478bdstevel@tonic-gate * Add given entry to table in first available slot (either look in freelist
6517c478bdstevel@tonic-gate * or add to end of table) and return the the position of where the record
6527c478bdstevel@tonic-gate * is placed. 'count' is incremented if entry is added. Table may grow
6537c478bdstevel@tonic-gate * as a side-effect of the addition. Copy is made of input.
6547c478bdstevel@tonic-gate*/
6557c478bdstevel@tonic-gateentryp
6567c478bdstevel@tonic-gatedb_table::add_entry(entry_object *obj, int initialLoad) {
6577c478bdstevel@tonic-gate	/*
6587c478bdstevel@tonic-gate	 * We're returning an index of the table array, so the caller
6597c478bdstevel@tonic-gate	 * should hold a lock until done with the index. To save us
6607c478bdstevel@tonic-gate	 * the bother of upgrading to a write lock, it might as well
6617c478bdstevel@tonic-gate	 * be a write lock to begin with.
6627c478bdstevel@tonic-gate	 */
6637c478bdstevel@tonic-gate	ASSERTWHELD(table);
6647c478bdstevel@tonic-gate	entryp where = freelist.pop();
665bc30fb4Toomas Soome	if (where == 0) {				/* empty freelist */
6667c478bdstevel@tonic-gate		if (last_used >= (table_size-1))	/* full (> is for 0) */
6677c478bdstevel@tonic-gate			grow();
6687c478bdstevel@tonic-gate		where = ++last_used;
6697c478bdstevel@tonic-gate	}
6707c478bdstevel@tonic-gate	if (tab != NULL) {
6717c478bdstevel@tonic-gate		++count;
6727c478bdstevel@tonic-gate		setEntryExp(where, obj, initialLoad);
6737c478bdstevel@tonic-gate
6747c478bdstevel@tonic-gate		if (enumMode.flag)
6757c478bdstevel@tonic-gate			enumTouch(where);
6767c478bdstevel@tonic-gate		tab[where] = new_entry(obj);
6777c478bdstevel@tonic-gate		return (where);
6787c478bdstevel@tonic-gate	} else {
679bc30fb4Toomas Soome		return (0);
6807c478bdstevel@tonic-gate	}
6817c478bdstevel@tonic-gate}
6827c478bdstevel@tonic-gate
6837c478bdstevel@tonic-gate/*
6847c478bdstevel@tonic-gate * Replaces object at specified location by given entry.
6857c478bdstevel@tonic-gate * Returns TRUE if replacement successful; FALSE otherwise.
6867c478bdstevel@tonic-gate * There must something already at the specified location, otherwise,
6877c478bdstevel@tonic-gate * replacement fails. Copy is not made of the input.
6887c478bdstevel@tonic-gate * The pre-existing entry is freed.
6897c478bdstevel@tonic-gate */
6907c478bdstevel@tonic-gatebool_t
6917c478bdstevel@tonic-gatedb_table::replace_entry(entryp where, entry_object * obj)
6927c478bdstevel@tonic-gate{
6937c478bdstevel@tonic-gate	ASSERTWHELD(table);
6947c478bdstevel@tonic-gate	if (where < DB_TABLE_START || where >= table_size ||
6957c478bdstevel@tonic-gate	    tab == NULL || tab[where] == NULL)
6967c478bdstevel@tonic-gate		return (FALSE);
6977c478bdstevel@tonic-gate	/* (Re-)set the entry TTL */
6987c478bdstevel@tonic-gate	setEntryExp(where, obj, 0);
6997c478bdstevel@tonic-gate
7007c478bdstevel@tonic-gate	if (enumMode.flag)
7017c478bdstevel@tonic-gate		enumTouch(where);
7027c478bdstevel@tonic-gate	free_entry(tab[where]);
7037c478bdstevel@tonic-gate	tab[where] = obj;
7047c478bdstevel@tonic-gate	return (TRUE);
7057c478bdstevel@tonic-gate}
7067c478bdstevel@tonic-gate
7077c478bdstevel@tonic-gate/*
7087c478bdstevel@tonic-gate * Deletes entry at specified location.  Returns TRUE if location is valid;
7097c478bdstevel@tonic-gate * FALSE if location is invalid, or the freed location cannot be added to
7107c478bdstevel@tonic-gate * the freelist.  'count' is decremented if the deletion occurs.  The object
7117c478bdstevel@tonic-gate * at that location is freed.
7127c478bdstevel@tonic-gate */
7137c478bdstevel@tonic-gatebool_t
7147c478bdstevel@tonic-gatedb_table::delete_entry(entryp where)
7157c478bdstevel@tonic-gate{
7167c478bdstevel@tonic-gate	bool_t	ret = TRUE;
7177c478bdstevel@tonic-gate
7187c478bdstevel@tonic-gate	ASSERTWHELD(table);
7197c478bdstevel@tonic-gate	if (where < DB_TABLE_START || where >= table_size ||
7207c478bdstevel@tonic-gate	    tab == NULL || tab[where] == NULL)
7217c478bdstevel@tonic-gate		return (FALSE);
7227c478bdstevel@tonic-gate	if (mapping.expire != NULL) {
7237c478bdstevel@tonic-gate		mapping.expire[where] = 0;
7247c478bdstevel@tonic-gate	}
7257c478bdstevel@tonic-gate	if (enumMode.flag)
7267c478bdstevel@tonic-gate		enumTouch(where);
7277c478bdstevel@tonic-gate	free_entry(tab[where]);
7287c478bdstevel@tonic-gate	tab[where] = NULL;    /* very important to set it to null */
7297c478bdstevel@tonic-gate	--count;
7307c478bdstevel@tonic-gate	if (where == last_used) { /* simple case, deleting from end */
7317c478bdstevel@tonic-gate		--last_used;
7327c478bdstevel@tonic-gate		return (TRUE);
7337c478bdstevel@tonic-gate	} else {
7347c478bdstevel@tonic-gate		return (freelist.push(where));
7357c478bdstevel@tonic-gate	}
7367c478bdstevel@tonic-gate	return (ret);
7377c478bdstevel@tonic-gate}
7387c478bdstevel@tonic-gate
7397c478bdstevel@tonic-gate/*
7407c478bdstevel@tonic-gate * Returns statistics of table.
7417c478bdstevel@tonic-gate * [vector_size][table_size][last_used][count][freelist].
74248bbca8Daniel Hoffman * It is up to the caller to free the returned vector when it is through.
7437c478bdstevel@tonic-gate * The free list is included if 'fl' is TRUE.
7447c478bdstevel@tonic-gate*/
7457c478bdstevel@tonic-gatelong *
7467c478bdstevel@tonic-gatedb_table::stats(bool_t include_freelist)
7477c478bdstevel@tonic-gate{
7487c478bdstevel@tonic-gate	long *answer;
7497c478bdstevel@tonic-gate
7507c478bdstevel@tonic-gate	READLOCK(this, NULL, "r db_table::stats");
7517c478bdstevel@tonic-gate	if (include_freelist)
7527c478bdstevel@tonic-gate		answer = freelist.stats(3);
7537c478bdstevel@tonic-gate	else {
7547c478bdstevel@tonic-gate		answer = (long *)malloc(3*sizeof (long));
7557c478bdstevel@tonic-gate	}
7567c478bdstevel@tonic-gate
7577c478bdstevel@tonic-gate	if (answer) {
7587c478bdstevel@tonic-gate		answer[0] = table_size;
7597c478bdstevel@tonic-gate		answer[1] = last_used;
7607c478bdstevel@tonic-gate		answer[2] = count;
7617c478bdstevel@tonic-gate	}
7627c478bdstevel@tonic-gate	READUNLOCK(this, answer, "ru db_table::stats");
7637c478bdstevel@tonic-gate	return (answer);
7647c478bdstevel@tonic-gate}
7657c478bdstevel@tonic-gate
7667c478bdstevel@tonic-gatebool_t
7677c478bdstevel@tonic-gatedb_table::configure(char *tablePath) {
7687c478bdstevel@tonic-gate	long		i;
7697c478bdstevel@tonic-gate	struct timeval	now;
7708d0852bRichard Lowe	const char	*myself = "db_table::configure";
7717c478bdstevel@tonic-gate
7727c478bdstevel@tonic-gate	(void) gettimeofday(&now, NULL);
7737c478bdstevel@tonic-gate
7747c478bdstevel@tonic-gate	WRITELOCK(this, FALSE, "db_table::configure w");
7757c478bdstevel@tonic-gate
7767c478bdstevel@tonic-gate	/* (Re-)initialize from global info */
7777c478bdstevel@tonic-gate	initMappingStruct(&mapping);
7787c478bdstevel@tonic-gate
7797c478bdstevel@tonic-gate	/* Retrieve table mapping for this table */
7807c478bdstevel@tonic-gate	mapping.tm = (__nis_table_mapping_t *)__nis_find_item_mt(
7817c478bdstevel@tonic-gate					tablePath, &ldapMappingList, 0, 0);
7827c478bdstevel@tonic-gate	if (mapping.tm != 0) {
7837c478bdstevel@tonic-gate		__nis_object_dn_t	*odn = mapping.tm->objectDN;
7847c478bdstevel@tonic-gate
7857c478bdstevel@tonic-gate		/*
7867c478bdstevel@tonic-gate		 * The mapping.fromLDAP and mapping.toLDAP fields serve as
7877c478bdstevel@tonic-gate		 * quick-references that tell us if mapping is enabled.
7887c478bdstevel@tonic-gate		 * Hence, initialize them appropriately from the table
7897c478bdstevel@tonic-gate		 * mapping objectDN.
7907c478bdstevel@tonic-gate		 */
7917c478bdstevel@tonic-gate		while (odn != 0 && (!mapping.fromLDAP || !mapping.toLDAP)) {
7927c478bdstevel@tonic-gate			if (odn->read.scope != LDAP_SCOPE_UNKNOWN)
7937c478bdstevel@tonic-gate				mapping.fromLDAP = TRUE;
7947c478bdstevel@tonic-gate			if (odn->write.scope != LDAP_SCOPE_UNKNOWN)
7957c478bdstevel@tonic-gate				mapping.toLDAP = TRUE;
7967c478bdstevel@tonic-gate			odn = (__nis_object_dn_t *)odn->next;
7977c478bdstevel@tonic-gate		}
7987c478bdstevel@tonic-gate
7997c478bdstevel@tonic-gate		/* Set the timeout values */
8007c478bdstevel@tonic-gate		mapping.initTtlLo = mapping.tm->initTtlLo;
8017c478bdstevel@tonic-gate		mapping.initTtlHi = mapping.tm->initTtlHi;
8027c478bdstevel@tonic-gate		mapping.ttl = mapping.tm->ttl;
8037c478bdstevel@tonic-gate
8047c478bdstevel@tonic-gate		mapping.objName = sdup(myself, T, mapping.tm->objName);
8057c478bdstevel@tonic-gate		if (mapping.objName == 0 && mapping.tm->objName != 0) {
8067c478bdstevel@tonic-gate			WRITEUNLOCK(this, FALSE,
8077c478bdstevel@tonic-gate				"db_table::configure wu objName");
8087c478bdstevel@tonic-gate			FATAL3("db_table::configure objName",
8097c478bdstevel@tonic-gate				DB_MEMORY_LIMIT, FALSE);
8107c478bdstevel@tonic-gate		}
8117c478bdstevel@tonic-gate	}
8127c478bdstevel@tonic-gate
8137c478bdstevel@tonic-gate	/*
8147c478bdstevel@tonic-gate	 * In order to initialize the expiration times, we need to know
8157c478bdstevel@tonic-gate	 * if 'this' represents a table or a directory. To that end, we
8167c478bdstevel@tonic-gate	 * find an entry in the table, and invoke setEntryExp() on it.
8177c478bdstevel@tonic-gate	 * As a side effect, setEntryExp() will examine the pseudo-object
8187c478bdstevel@tonic-gate	 * in the entry, and set the expireType accordingly.
8197c478bdstevel@tonic-gate	 */
8207c478bdstevel@tonic-gate	if (tab != 0) {
8217c478bdstevel@tonic-gate		for (i = 0; i <= last_used; i++) {
8227c478bdstevel@tonic-gate			if (tab[i] != NULL) {
8237c478bdstevel@tonic-gate				setEntryExp(i, tab[i], 1);
8247c478bdstevel@tonic-gate				break;
8257c478bdstevel@tonic-gate			}
8267c478bdstevel@tonic-gate		}
8277c478bdstevel@tonic-gate	}
8287c478bdstevel@tonic-gate
8297c478bdstevel@tonic-gate	/*
8307c478bdstevel@tonic-gate	 * If mapping from an LDAP repository, make sure we have the
8317c478bdstevel@tonic-gate	 * expiration time array.
8327c478bdstevel@tonic-gate	 */
8337c478bdstevel@tonic-gate	if ((mapping.expireType != NIS_TABLE_OBJ || mapping.fromLDAP) &&
8347c478bdstevel@tonic-gate			mapping.expire == NULL && table_size > 0 && tab != 0) {
8357c478bdstevel@tonic-gate		db_status stat = allocateExpire(0, table_size);
8367c478bdstevel@tonic-gate		if (stat != DB_SUCCESS) {
8377c478bdstevel@tonic-gate			WRITEUNLOCK(this, FALSE,
8387c478bdstevel@tonic-gate				"db_table::configure wu expire");
8397c478bdstevel@tonic-gate			FATAL3("db_table::configure expire",
8407c478bdstevel@tonic-gate				stat, FALSE);
8417c478bdstevel@tonic-gate		}
8427c478bdstevel@tonic-gate	} else if (mapping.expireType == NIS_TABLE_OBJ && !mapping.fromLDAP &&
8437c478bdstevel@tonic-gate			mapping.expire != NULL) {
8447c478bdstevel@tonic-gate		/* Not using expiration times */
8457c478bdstevel@tonic-gate		free(mapping.expire);
8467c478bdstevel@tonic-gate		mapping.expire = NULL;
8477c478bdstevel@tonic-gate	}
8487c478bdstevel@tonic-gate
8497c478bdstevel@tonic-gate	/*
8507c478bdstevel@tonic-gate	 * Set initial expire times for entries that don't already have one.
8517c478bdstevel@tonic-gate	 * Establish the enumeration expiration time to be the minimum of
8527c478bdstevel@tonic-gate	 * all expiration times in the table, though no larger than current
8537c478bdstevel@tonic-gate	 * time plus initTtlHi.
8547c478bdstevel@tonic-gate	 */
8557c478bdstevel@tonic-gate	if (mapping.expire != NULL) {
8567c478bdstevel@tonic-gate		int	interval = mapping.initTtlHi - mapping.initTtlLo + 1;
8577c478bdstevel@tonic-gate		time_t	enumXp = now.tv_sec + mapping.initTtlHi;
8587c478bdstevel@tonic-gate
8597c478bdstevel@tonic-gate		if (interval > 1)
8607c478bdstevel@tonic-gate			srand48(now.tv_sec);
8617c478bdstevel@tonic-gate		for (i = 0; i <= last_used; i++) {
8627c478bdstevel@tonic-gate			if (tab[i] != NULL && mapping.expire[i] == 0) {
8637c478bdstevel@tonic-gate				if (mapping.expireType == NIS_TABLE_OBJ) {
8647c478bdstevel@tonic-gate					if (interval > 1)
8657c478bdstevel@tonic-gate						mapping.expire[i] =
8667c478bdstevel@tonic-gate							now.tv_sec +
8677c478bdstevel@tonic-gate							(lrand48() % interval);
8687c478bdstevel@tonic-gate					else
8697c478bdstevel@tonic-gate						mapping.expire[i] =
8707c478bdstevel@tonic-gate							now.tv_sec +
8717c478bdstevel@tonic-gate							mapping.initTtlLo;
8727c478bdstevel@tonic-gate				} else {
8737c478bdstevel@tonic-gate					setEntryExp(i, tab[i], 1);
8747c478bdstevel@tonic-gate				}
8757c478bdstevel@tonic-gate			}
8767c478bdstevel@tonic-gate			if (enumXp > mapping.expire[i])
8777c478bdstevel@tonic-gate				enumXp = mapping.expire[i];
8787c478bdstevel@tonic-gate		}
8797c478bdstevel@tonic-gate		mapping.enumExpire = enumXp;
8807c478bdstevel@tonic-gate	}
8817c478bdstevel@tonic-gate
8827c478bdstevel@tonic-gate	WRITEUNLOCK(this, FALSE, "db_table::configure wu");
8837c478bdstevel@tonic-gate
8847c478bdstevel@tonic-gate	return (TRUE);
8857c478bdstevel@tonic-gate}
8867c478bdstevel@tonic-gate
8877c478bdstevel@tonic-gate/* Return TRUE if the entry at 'loc' hasn't expired */
8887c478bdstevel@tonic-gatebool_t
8897c478bdstevel@tonic-gatedb_table::cacheValid(entryp loc) {
8907c478bdstevel@tonic-gate	bool_t		ret;
8917c478bdstevel@tonic-gate	struct timeval	now;
8927c478bdstevel@tonic-gate
8937c478bdstevel@tonic-gate	(void) gettimeofday(&now, 0);
8947c478bdstevel@tonic-gate
8957c478bdstevel@tonic-gate	READLOCK(this, FALSE, "db_table::cacheValid r");
8967c478bdstevel@tonic-gate
8977c478bdstevel@tonic-gate	if (loc < 0 || loc >= table_size || tab == 0 || tab[loc] == 0)
8987c478bdstevel@tonic-gate		ret = FALSE;
8997c478bdstevel@tonic-gate	else if (mapping.expire == 0 || mapping.expire[loc] >= now.tv_sec)
9007c478bdstevel@tonic-gate		ret = TRUE;
9017c478bdstevel@tonic-gate	else
9027c478bdstevel@tonic-gate		ret = FALSE;
9037c478bdstevel@tonic-gate
9047c478bdstevel@tonic-gate	READUNLOCK(this, ret, "db_table::cacheValid ru");
9057c478bdstevel@tonic-gate
9067c478bdstevel@tonic-gate	return (ret);
9077c478bdstevel@tonic-gate}
9087c478bdstevel@tonic-gate
9097c478bdstevel@tonic-gate/*
9107c478bdstevel@tonic-gate * If the supplied object has the same content as the one at 'loc',
9117c478bdstevel@tonic-gate * update the expiration time for the latter, and return TRUE.
9127c478bdstevel@tonic-gate */
9137c478bdstevel@tonic-gatebool_t
9147c478bdstevel@tonic-gatedb_table::dupEntry(entry_object *obj, entryp loc) {
9157c478bdstevel@tonic-gate	if (obj == 0 || loc < 0 || loc >= table_size || tab == 0 ||
9167c478bdstevel@tonic-gate			tab[loc] == 0)
9177c478bdstevel@tonic-gate		return (FALSE);
9187c478bdstevel@tonic-gate
9197c478bdstevel@tonic-gate	if (sameEntry(obj, tab[loc])) {
9207c478bdstevel@tonic-gate		setEntryExp(loc, tab[loc], 0);
9217c478bdstevel@tonic-gate
9227c478bdstevel@tonic-gate		if (enumMode.flag > 0)
9237c478bdstevel@tonic-gate			enumTouch(loc);
9247c478bdstevel@tonic-gate		return (TRUE);
9257c478bdstevel@tonic-gate	}
9267c478bdstevel@tonic-gate
9277c478bdstevel@tonic-gate	return (FALSE);
9287c478bdstevel@tonic-gate}
9297c478bdstevel@tonic-gate
9307c478bdstevel@tonic-gate/*
9317c478bdstevel@tonic-gate * If enumeration mode is enabled, we keep a shadow array that initially
9327c478bdstevel@tonic-gate * starts out the same as 'tab'. Any update activity (add, remove, replace,
9337c478bdstevel@tonic-gate * or update timestamp) for an entry in the table means we delete the shadow
9347c478bdstevel@tonic-gate * array pointer. When ending enumeration mode, we return the shadow array.
9357c478bdstevel@tonic-gate * Any non-NULL entries in the array have not been updated since the start
9367c478bdstevel@tonic-gate * of the enum mode.
9377c478bdstevel@tonic-gate *
9387c478bdstevel@tonic-gate * The indended use is for enumeration of an LDAP container, where we
9397c478bdstevel@tonic-gate * will update all entries that currently exist in LDAP. The entries we
9407c478bdstevel@tonic-gate * don't update are those that don't exist in LDAP, and thus should be
9417c478bdstevel@tonic-gate * removed.
9427c478bdstevel@tonic-gate *
9437c478bdstevel@tonic-gate * Note that any LDAP query strictly speaking can be a partial enumeration
9447c478bdstevel@tonic-gate * (i.e., return more than one match). Since the query might also have
9457c478bdstevel@tonic-gate * matched multiple local DB entries, we need to do the same work as for
9467c478bdstevel@tonic-gate * enumeration for any query. In order to avoid having to work on the
9477c478bdstevel@tonic-gate * whole 'tab' array for simple queries (which we expect usually will
9487c478bdstevel@tonic-gate * match just one or at most a few entries), we have a "reduced" enum mode,
9497c478bdstevel@tonic-gate * where the caller supplies a count of the number of DB entries (derived
9507c478bdstevel@tonic-gate * from db_mindex::satisfy_query() or similar), and then uses enumSetup()
9517c478bdstevel@tonic-gate * to specify which 'tab' entries we're interested in.
9527c478bdstevel@tonic-gate */
9537c478bdstevel@tonic-gatevoid
9547c478bdstevel@tonic-gatedb_table::setEnumMode(long enumNum) {
9558d0852bRichard Lowe	const char	*myself = "setEnumMode";
9567c478bdstevel@tonic-gate
9577c478bdstevel@tonic-gate	enumMode.flag++;
9587c478bdstevel@tonic-gate	if (enumMode.flag == 1) {
9597c478bdstevel@tonic-gate		db_status	stat;
9607c478bdstevel@tonic-gate
9617c478bdstevel@tonic-gate		if (enumNum < 0)
9627c478bdstevel@tonic-gate			enumNum = 0;
9637c478bdstevel@tonic-gate		else if (enumNum >= table_size)
9647c478bdstevel@tonic-gate			enumNum = table_size;
9657c478bdstevel@tonic-gate
9667c478bdstevel@tonic-gate		enumCount.flag = enumNum;
9677c478bdstevel@tonic-gate
9687c478bdstevel@tonic-gate		stat = allocateEnumArray(0, table_size);
9697c478bdstevel@tonic-gate
9707c478bdstevel@tonic-gate		if (stat != DB_SUCCESS) {
9717c478bdstevel@tonic-gate			enumMode.flag = 0;
9727c478bdstevel@tonic-gate			enumCount.flag = 0;
9737c478bdstevel@tonic-gate			logmsg(MSG_NOTIMECHECK, LOG_ERR,
9747c478bdstevel@tonic-gate		"%s: No memory for enum check array; entry removal disabled",
9757c478bdstevel@tonic-gate				myself);
9767c478bdstevel@tonic-gate		}
9777c478bdstevel@tonic-gate	}
9787c478bdstevel@tonic-gate}
9797c478bdstevel@tonic-gate
9807c478bdstevel@tonic-gatevoid
9817c478bdstevel@tonic-gatedb_table::clearEnumMode(void) {
9827c478bdstevel@tonic-gate	if (enumMode.flag > 0) {
9837c478bdstevel@tonic-gate		enumMode.flag--;
9847c478bdstevel@tonic-gate		if (enumMode.flag == 0) {
9857c478bdstevel@tonic-gate			sfree(enumArray.ptr);
9867c478bdstevel@tonic-gate			enumArray.ptr = 0;
9877c478bdstevel@tonic-gate			if (enumCount.flag > 0) {
9887c478bdstevel@tonic-gate				sfree(enumIndex.ptr);
9897c478bdstevel@tonic-gate				enumIndex.ptr = 0;
9907c478bdstevel@tonic-gate				enumCount.flag = 0;
9917c478bdstevel@tonic-gate			}
9927c478bdstevel@tonic-gate		}
9937c478bdstevel@tonic-gate	}
9947c478bdstevel@tonic-gate}
9957c478bdstevel@tonic-gate
9967c478bdstevel@tonic-gateentry_object **
9977c478bdstevel@tonic-gatedb_table::endEnumMode(long *numEa) {
9987c478bdstevel@tonic-gate	if (enumMode.flag > 0) {
9997c478bdstevel@tonic-gate		enumMode.flag--;
10007c478bdstevel@tonic-gate		if (enumMode.flag == 0) {
10017c478bdstevel@tonic-gate			entry_obj	**ea = (entry_object **)enumArray.ptr;
10027c478bdstevel@tonic-gate			long		nea;
10037c478bdstevel@tonic-gate
10047c478bdstevel@tonic-gate			enumArray.ptr = 0;
10057c478bdstevel@tonic-gate
10067c478bdstevel@tonic-gate			if (enumCount.flag > 0) {
10077c478bdstevel@tonic-gate				nea = enumCount.flag;
10087c478bdstevel@tonic-gate				enumCount.flag = 0;
10097c478bdstevel@tonic-gate				sfree(enumIndex.ptr);
10107c478bdstevel@tonic-gate				enumIndex.ptr = 0;
10117c478bdstevel@tonic-gate			} else {
10127c478bdstevel@tonic-gate				nea = table_size;
10137c478bdstevel@tonic-gate			}
10147c478bdstevel@tonic-gate
10157c478bdstevel@tonic-gate			if (numEa != 0)
10167c478bdstevel@tonic-gate				*numEa = nea;
10177c478bdstevel@tonic-gate
10187c478bdstevel@tonic-gate			return (ea);
10197c478bdstevel@tonic-gate		}
10207c478bdstevel@tonic-gate	}
10217c478bdstevel@tonic-gate
10227c478bdstevel@tonic-gate	if (numEa != 0)
10237c478bdstevel@tonic-gate		*numEa = 0;
10247c478bdstevel@tonic-gate
10257c478bdstevel@tonic-gate	return (0);
10267c478bdstevel@tonic-gate}
10277c478bdstevel@tonic-gate
10287c478bdstevel@tonic-gate/*
10297c478bdstevel@tonic-gate * Set the appropriate entry in the enum array to NULL.
10307c478bdstevel@tonic-gate */
10317c478bdstevel@tonic-gatevoid
10327c478bdstevel@tonic-gatedb_table::enumTouch(entryp loc) {
10337c478bdstevel@tonic-gate	if (loc < 0 || loc >= table_size)
10347c478bdstevel@tonic-gate		return;
10357c478bdstevel@tonic-gate
10367c478bdstevel@tonic-gate	if (enumMode.flag > 0) {
10377c478bdstevel@tonic-gate		if (enumCount.flag < 1) {
10387c478bdstevel@tonic-gate			((entry_object **)enumArray.ptr)[loc] = 0;
10397c478bdstevel@tonic-gate		} else {
10407c478bdstevel@tonic-gate			int	i;
10417c478bdstevel@tonic-gate
10427c478bdstevel@tonic-gate			for (i = 0; i < enumCount.flag; i++) {
10437c478bdstevel@tonic-gate				if (loc == ((entryp *)enumIndex.ptr)[i]) {
10447c478bdstevel@tonic-gate					((entry_object **)enumArray.ptr)[i] = 0;
10457c478bdstevel@tonic-gate					break;
10467c478bdstevel@tonic-gate				}
10477c478bdstevel@tonic-gate			}
10487c478bdstevel@tonic-gate		}
10497c478bdstevel@tonic-gate	}
10507c478bdstevel@tonic-gate}
10517c478bdstevel@tonic-gate
10527c478bdstevel@tonic-gate/*
10537c478bdstevel@tonic-gate * Add the entry indicated by 'loc' to the enumIndex array, at 'index'.
10547c478bdstevel@tonic-gate */
10557c478bdstevel@tonic-gatevoid
10567c478bdstevel@tonic-gatedb_table::enumSetup(entryp loc, long index) {
10577c478bdstevel@tonic-gate	if (enumMode.flag == 0 || loc < 0 || loc >= table_size ||
10587c478bdstevel@tonic-gate			index < 0 || index >= enumCount.flag)
10597c478bdstevel@tonic-gate		return;
10607c478bdstevel@tonic-gate
10617c478bdstevel@tonic-gate	((entryp *)enumIndex.ptr)[index] = loc;
10627c478bdstevel@tonic-gate	((entry_object **)enumArray.ptr)[index] = tab[loc];
10637c478bdstevel@tonic-gate}
10647c478bdstevel@tonic-gate
10657c478bdstevel@tonic-gate/*
10667c478bdstevel@tonic-gate * Touch, i.e., update the expiration time for the entry. Also, if enum
10677c478bdstevel@tonic-gate * mode is in effect, mark the entry used for enum purposes.
10687c478bdstevel@tonic-gate */
10697c478bdstevel@tonic-gatevoid
10707c478bdstevel@tonic-gatedb_table::touchEntry(entryp loc) {
10717c478bdstevel@tonic-gate	if (loc < 0 || loc >= table_size || tab == 0 || tab[loc] == 0)
10727c478bdstevel@tonic-gate		return;
10737c478bdstevel@tonic-gate
10747c478bdstevel@tonic-gate	setEntryExp(loc, tab[loc], 0);
10757c478bdstevel@tonic-gate
10767c478bdstevel@tonic-gate	enumTouch(loc);
10777c478bdstevel@tonic-gate}
10787c478bdstevel@tonic-gate
10797c478bdstevel@tonic-gate/* ************************* pickle_table ********************* */
10807c478bdstevel@tonic-gate/* Does the actual writing to/from file specific for db_table structure. */
10817c478bdstevel@tonic-gate/*
10827c478bdstevel@tonic-gate * This was a static earlier with the func name being transfer_aux. The
10837c478bdstevel@tonic-gate * backup and restore project needed this to copy files over.
10847c478bdstevel@tonic-gate */
10857c478bdstevel@tonic-gatebool_t
10867c478bdstevel@tonic-gatetransfer_aux_table(XDR* x, pptr dp)
10877c478bdstevel@tonic-gate{
10887c478bdstevel@tonic-gate	return (xdr_db_table(x, (db_table*) dp));
10897c478bdstevel@tonic-gate}
10907c478bdstevel@tonic-gate
10917c478bdstevel@tonic-gateclass pickle_table: public pickle_file {
10927c478bdstevel@tonic-gate    public:
10937c478bdstevel@tonic-gate	pickle_table(char *f, pickle_mode m) : pickle_file(f, m) {}
10947c478bdstevel@tonic-gate
10957c478bdstevel@tonic-gate	/* Transfers db_table structure pointed to by dp to/from file. */
10967c478bdstevel@tonic-gate	int transfer(db_table* dp)
10977c478bdstevel@tonic-gate	{ return (pickle_file::transfer((pptr) dp, &transfer_aux_table)); }
10987c478bdstevel@tonic-gate};
10997c478bdstevel@tonic-gate
11007c478bdstevel@tonic-gate/*
11017c478bdstevel@tonic-gate * Writes the contents of table, including the all the entries, into the
11027c478bdstevel@tonic-gate * specified file in XDR format.  May need to change this to use APPEND
11037c478bdstevel@tonic-gate * mode instead.
11047c478bdstevel@tonic-gate */
11057c478bdstevel@tonic-gateint
11067c478bdstevel@tonic-gatedb_table::dump(char *file)
11077c478bdstevel@tonic-gate{
11087c478bdstevel@tonic-gate	int	ret;
11097c478bdstevel@tonic-gate	READLOCK(this, -1, "r db_table::dump");
11107c478bdstevel@tonic-gate	pickle_table f(file, PICKLE_WRITE);   /* may need to use APPEND mode */
11117c478bdstevel@tonic-gate	int status = f.transfer(this);
11127c478bdstevel@tonic-gate
11137c478bdstevel@tonic-gate	if (status == 1)
11147c478bdstevel@tonic-gate		ret = -1;
11157c478bdstevel@tonic-gate	else
11167c478bdstevel@tonic-gate		ret = status;
11177c478bdstevel@tonic-gate	READUNLOCK(this, ret, "ru db_table::dump");
1118b3bec64Toomas Soome	return (ret);
11197c478bdstevel@tonic-gate}
11207c478bdstevel@tonic-gate
11217c478bdstevel@tonic-gate/* Constructor that loads in the table from the given file */
11227c478bdstevel@tonic-gatedb_table::db_table(char *file)  : freelist()
11237c478bdstevel@tonic-gate{
11247c478bdstevel@tonic-gate	pickle_table f(file, PICKLE_READ);
11257c478bdstevel@tonic-gate	tab = NULL;
11267c478bdstevel@tonic-gate	table_size = last_used = count = 0;
11277c478bdstevel@tonic-gate
11287c478bdstevel@tonic-gate	/* load  table */
11297c478bdstevel@tonic-gate	if (f.transfer(this) < 0) {
11307c478bdstevel@tonic-gate		/* fell through, something went wrong, initialize to null */
11317c478bdstevel@tonic-gate		tab = NULL;
11327c478bdstevel@tonic-gate		table_size = last_used = count = 0;
11337c478bdstevel@tonic-gate		freelist.init();
11347c478bdstevel@tonic-gate	}
11357c478bdstevel@tonic-gate
11367c478bdstevel@tonic-gate	db_table_ldap_init();
11377c478bdstevel@tonic-gate	initMappingStruct(&mapping);
11387c478bdstevel@tonic-gate}
11397c478bdstevel@tonic-gate
11407c478bdstevel@tonic-gate/* Returns whether location is valid. */
11417c478bdstevel@tonic-gatebool_t db_table::entry_exists_p(entryp i) {
11427c478bdstevel@tonic-gate	bool_t	ret = FALSE;
11437c478bdstevel@tonic-gate	READLOCK(this, FALSE, "r db_table::entry_exists_p");
11447c478bdstevel@tonic-gate	if (tab != NULL && i < table_size)
11457c478bdstevel@tonic-gate		ret = tab[i] != NULL;
11467c478bdstevel@tonic-gate	READUNLOCK(this, ret, "ru db_table::entry_exists_p");
11477c478bdstevel@tonic-gate	return (ret);
11487c478bdstevel@tonic-gate}
11497c478bdstevel@tonic-gate
11507c478bdstevel@tonic-gate/* Empty free list */
11517c478bdstevel@tonic-gatevoid db_free_list::init() {
11527c478bdstevel@tonic-gate	WRITELOCKV(this, "w db_free_list::init");
11537c478bdstevel@tonic-gate	head = NULL;
11547c478bdstevel@tonic-gate	count = 0;
11557c478bdstevel@tonic-gate	WRITEUNLOCKV(this, "wu db_free_list::init");
11567c478bdstevel@tonic-gate}
1157