xref: /onnv-gate/usr/src/lib/libnisdb/db_table.cc (revision 0:68f95e015346)
1*0Sstevel@tonic-gate /*
2*0Sstevel@tonic-gate  * CDDL HEADER START
3*0Sstevel@tonic-gate  *
4*0Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5*0Sstevel@tonic-gate  * Common Development and Distribution License, Version 1.0 only
6*0Sstevel@tonic-gate  * (the "License").  You may not use this file except in compliance
7*0Sstevel@tonic-gate  * with the License.
8*0Sstevel@tonic-gate  *
9*0Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10*0Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
11*0Sstevel@tonic-gate  * See the License for the specific language governing permissions
12*0Sstevel@tonic-gate  * and limitations under the License.
13*0Sstevel@tonic-gate  *
14*0Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
15*0Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16*0Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
17*0Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
18*0Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
19*0Sstevel@tonic-gate  *
20*0Sstevel@tonic-gate  * CDDL HEADER END
21*0Sstevel@tonic-gate  */
22*0Sstevel@tonic-gate /*
23*0Sstevel@tonic-gate  *	db_table.cc
24*0Sstevel@tonic-gate  *
25*0Sstevel@tonic-gate  * Copyright 2004 Sun Microsystems, Inc.  All rights reserved.
26*0Sstevel@tonic-gate  * Use is subject to license terms.
27*0Sstevel@tonic-gate  */
28*0Sstevel@tonic-gate 
29*0Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
30*0Sstevel@tonic-gate 
31*0Sstevel@tonic-gate #include <stdio.h>
32*0Sstevel@tonic-gate #include <malloc.h>
33*0Sstevel@tonic-gate #include <string.h>
34*0Sstevel@tonic-gate #include <stdlib.h>		/* srand48() */
35*0Sstevel@tonic-gate #include <lber.h>
36*0Sstevel@tonic-gate #include <ldap.h>
37*0Sstevel@tonic-gate #include "db_headers.h"
38*0Sstevel@tonic-gate #include "db_table.h"
39*0Sstevel@tonic-gate #include "db_pickle.h"    /* for dump and load */
40*0Sstevel@tonic-gate #include "db_entry.h"
41*0Sstevel@tonic-gate #include "nisdb_mt.h"
42*0Sstevel@tonic-gate 
43*0Sstevel@tonic-gate #include "ldap_parse.h"
44*0Sstevel@tonic-gate #include "ldap_util.h"
45*0Sstevel@tonic-gate #include "ldap_map.h"
46*0Sstevel@tonic-gate #include "ldap_xdr.h"
47*0Sstevel@tonic-gate #include "nis_hashitem.h"
48*0Sstevel@tonic-gate #include "nisdb_ldap.h"
49*0Sstevel@tonic-gate #include "nis_parse_ldap_conf.h"
50*0Sstevel@tonic-gate 
51*0Sstevel@tonic-gate static time_t	maxTimeT;
52*0Sstevel@tonic-gate 
53*0Sstevel@tonic-gate /*
54*0Sstevel@tonic-gate  * Find the largest (positive) value of time_t.
55*0Sstevel@tonic-gate  *
56*0Sstevel@tonic-gate  * If time_t is unsigned, the largest possible value is just ~0.
57*0Sstevel@tonic-gate  * However, if it's signed, then ~0 is negative. Since lint (for
58*0Sstevel@tonic-gate  * sure), and perhaps the compiler too, dislike comparing an
59*0Sstevel@tonic-gate  * unsigned quantity to see if it's less than zero, we compare
60*0Sstevel@tonic-gate  * to one instead. If negative, the largest possible value is
61*0Sstevel@tonic-gate  * th inverse of 2**(N-1), where N is the number of bits in a
62*0Sstevel@tonic-gate  * time_t.
63*0Sstevel@tonic-gate  */
64*0Sstevel@tonic-gate extern "C" {
65*0Sstevel@tonic-gate static void
__setMaxTimeT(void)66*0Sstevel@tonic-gate __setMaxTimeT(void)
67*0Sstevel@tonic-gate {
68*0Sstevel@tonic-gate 	unsigned char	b[sizeof (time_t)];
69*0Sstevel@tonic-gate 	int		i;
70*0Sstevel@tonic-gate 
71*0Sstevel@tonic-gate 	/* Compute ~0 for an unknown length integer */
72*0Sstevel@tonic-gate 	for (i = 0; i < sizeof (time_t); i++) {
73*0Sstevel@tonic-gate 		b[i] = 0xff;
74*0Sstevel@tonic-gate 	}
75*0Sstevel@tonic-gate 	/* Set maxTimeT to ~0 of appropriate length */
76*0Sstevel@tonic-gate 	(void) memcpy(&maxTimeT, b, sizeof (time_t));
77*0Sstevel@tonic-gate 
78*0Sstevel@tonic-gate 	if (maxTimeT < 1)
79*0Sstevel@tonic-gate 		maxTimeT = ~(1<<((8*sizeof (maxTimeT))-1));
80*0Sstevel@tonic-gate }
81*0Sstevel@tonic-gate #pragma init(__setMaxTimeT)
82*0Sstevel@tonic-gate }
83*0Sstevel@tonic-gate 
84*0Sstevel@tonic-gate /* How much to grow table by */
85*0Sstevel@tonic-gate #define	DB_TABLE_GROWTH_INCREMENT 1024
86*0Sstevel@tonic-gate 
87*0Sstevel@tonic-gate /* 0'th not used; might be confusing. */
88*0Sstevel@tonic-gate #define	DB_TABLE_START 1
89*0Sstevel@tonic-gate 
90*0Sstevel@tonic-gate /* prevents wrap around numbers from being passed */
91*0Sstevel@tonic-gate #define	CALLOC_LIMIT 536870911
92*0Sstevel@tonic-gate 
93*0Sstevel@tonic-gate /* Initial table sizes to use before using 1K increments. */
94*0Sstevel@tonic-gate /* This helps conserve memory usage when there are lots of small tables. */
95*0Sstevel@tonic-gate static int tabsizes[] = {
96*0Sstevel@tonic-gate 	16,
97*0Sstevel@tonic-gate 	128,
98*0Sstevel@tonic-gate 	512,
99*0Sstevel@tonic-gate 	DB_TABLE_GROWTH_INCREMENT,
100*0Sstevel@tonic-gate 	0
101*0Sstevel@tonic-gate 	};
102*0Sstevel@tonic-gate 
103*0Sstevel@tonic-gate /* Returns the next size to use for table */
104*0Sstevel@tonic-gate static long unsigned
get_new_table_size(long unsigned oldsize)105*0Sstevel@tonic-gate get_new_table_size(long unsigned oldsize)
106*0Sstevel@tonic-gate {
107*0Sstevel@tonic-gate 	long unsigned newsize = 0, n;
108*0Sstevel@tonic-gate 	if (oldsize == 0)
109*0Sstevel@tonic-gate 		newsize = tabsizes[0];
110*0Sstevel@tonic-gate 	else {
111*0Sstevel@tonic-gate 		for (n = 0; newsize = tabsizes[n++]; )
112*0Sstevel@tonic-gate 			if (oldsize == newsize) {
113*0Sstevel@tonic-gate 				newsize = tabsizes[n];	/* get next size */
114*0Sstevel@tonic-gate 				break;
115*0Sstevel@tonic-gate 			}
116*0Sstevel@tonic-gate 		if (newsize == 0)
117*0Sstevel@tonic-gate 			newsize = oldsize + DB_TABLE_GROWTH_INCREMENT;
118*0Sstevel@tonic-gate 	}
119*0Sstevel@tonic-gate 	return (newsize);
120*0Sstevel@tonic-gate }
121*0Sstevel@tonic-gate 
122*0Sstevel@tonic-gate 
123*0Sstevel@tonic-gate /* destructor */
~db_free_list()124*0Sstevel@tonic-gate db_free_list::~db_free_list()
125*0Sstevel@tonic-gate {
126*0Sstevel@tonic-gate 	WRITELOCKV(this, "w db_free_list::~db_free_list");
127*0Sstevel@tonic-gate 	reset();   /* free list entries */
128*0Sstevel@tonic-gate 	DESTROYRW(free_list);
129*0Sstevel@tonic-gate }
130*0Sstevel@tonic-gate 
131*0Sstevel@tonic-gate void
reset()132*0Sstevel@tonic-gate db_free_list::reset()
133*0Sstevel@tonic-gate {
134*0Sstevel@tonic-gate 	db_free_entry *current, *nextentry;
135*0Sstevel@tonic-gate 
136*0Sstevel@tonic-gate 	WRITELOCKV(this, "w db_free_list::reset");
137*0Sstevel@tonic-gate 	for (current = head; current != NULL; ) {
138*0Sstevel@tonic-gate 		nextentry = current->next;
139*0Sstevel@tonic-gate 		delete current;
140*0Sstevel@tonic-gate 		current = nextentry;
141*0Sstevel@tonic-gate 	}
142*0Sstevel@tonic-gate 	head = NULL;
143*0Sstevel@tonic-gate 	count = 0;
144*0Sstevel@tonic-gate 	WRITEUNLOCKV(this, "wu db_free_list::reset");
145*0Sstevel@tonic-gate }
146*0Sstevel@tonic-gate 
147*0Sstevel@tonic-gate /* Returns the location of a free entry, or NULL, if there aren't any. */
148*0Sstevel@tonic-gate entryp
pop()149*0Sstevel@tonic-gate db_free_list::pop()
150*0Sstevel@tonic-gate {
151*0Sstevel@tonic-gate 	WRITELOCK(this, NULL, "w db_free_list::pop");
152*0Sstevel@tonic-gate 	if (head == NULL) {
153*0Sstevel@tonic-gate 		WRITEUNLOCK(this, NULL, "wu db_free_list::pop");
154*0Sstevel@tonic-gate 		return (NULL);
155*0Sstevel@tonic-gate 	}
156*0Sstevel@tonic-gate 	db_free_entry* old_head = head;
157*0Sstevel@tonic-gate 	entryp found = head->where;
158*0Sstevel@tonic-gate 	head = head->next;
159*0Sstevel@tonic-gate 	delete old_head;
160*0Sstevel@tonic-gate 	--count;
161*0Sstevel@tonic-gate 	WRITEUNLOCK(this, found, "wu db_free_list::pop");
162*0Sstevel@tonic-gate 	return (found);
163*0Sstevel@tonic-gate }
164*0Sstevel@tonic-gate 
165*0Sstevel@tonic-gate /*
166*0Sstevel@tonic-gate  * Adds given location to the free list.
167*0Sstevel@tonic-gate  * Returns TRUE if successful, FALSE otherwise (when out of memory).
168*0Sstevel@tonic-gate */
169*0Sstevel@tonic-gate bool_t
push(entryp tabloc)170*0Sstevel@tonic-gate db_free_list::push(entryp tabloc)
171*0Sstevel@tonic-gate {
172*0Sstevel@tonic-gate 	db_free_entry * newentry = new db_free_entry;
173*0Sstevel@tonic-gate 
174*0Sstevel@tonic-gate 	WRITELOCK(this, FALSE, "w db_free_list::push");
175*0Sstevel@tonic-gate 	if (newentry == NULL) {
176*0Sstevel@tonic-gate 		WRITEUNLOCK(this, FALSE, "wu db_free_list::push");
177*0Sstevel@tonic-gate 	    FATAL3("db_free_list::push: cannot allocation space",
178*0Sstevel@tonic-gate 		    DB_MEMORY_LIMIT, FALSE);
179*0Sstevel@tonic-gate 	}
180*0Sstevel@tonic-gate 	newentry->where = tabloc;
181*0Sstevel@tonic-gate 	newentry->next = head;
182*0Sstevel@tonic-gate 	head = newentry;
183*0Sstevel@tonic-gate 	++count;
184*0Sstevel@tonic-gate 	WRITEUNLOCK(this, TRUE, "wu db_free_list::push");
185*0Sstevel@tonic-gate 	return (TRUE);
186*0Sstevel@tonic-gate }
187*0Sstevel@tonic-gate 
188*0Sstevel@tonic-gate /*
189*0Sstevel@tonic-gate  * Returns in a vector the information in the free list.
190*0Sstevel@tonic-gate  * Vector returned is of form: [n free cells][n1][n2][loc1], ..[locn].
191*0Sstevel@tonic-gate  * Leave the first 'n' cells free.
192*0Sstevel@tonic-gate  * n1 is the number of entries that should be in the freelist.
193*0Sstevel@tonic-gate  * n2 is the number of entries actually found in the freelist.
194*0Sstevel@tonic-gate  * [loc1...locn] are the entries.   n2 <= n1 because we never count beyond n1.
195*0Sstevel@tonic-gate  * It is up to the caller to free the returned vector when he is through.
196*0Sstevel@tonic-gate */
197*0Sstevel@tonic-gate long *
stats(int nslots)198*0Sstevel@tonic-gate db_free_list::stats(int nslots)
199*0Sstevel@tonic-gate {
200*0Sstevel@tonic-gate 	long	realcount = 0,
201*0Sstevel@tonic-gate 		i,
202*0Sstevel@tonic-gate 		liststart = nslots,		// start of freelist
203*0Sstevel@tonic-gate 		listend = nslots+count+2;	// end of freelist
204*0Sstevel@tonic-gate 	db_free_entry_p current = head;
205*0Sstevel@tonic-gate 
206*0Sstevel@tonic-gate 	READLOCK(this, NULL, "r db_free_list::stats");
207*0Sstevel@tonic-gate 
208*0Sstevel@tonic-gate 	long *answer = (long *)malloc((int)(listend)*sizeof (long));
209*0Sstevel@tonic-gate 	if (answer == 0) {
210*0Sstevel@tonic-gate 		READUNLOCK(this, NULL, "ru db_free_list::stats");
211*0Sstevel@tonic-gate 		FATAL3("db_free_list::stats:  cannot allocation space",
212*0Sstevel@tonic-gate 		    DB_MEMORY_LIMIT, NULL);
213*0Sstevel@tonic-gate 	}
214*0Sstevel@tonic-gate 
215*0Sstevel@tonic-gate 	answer[liststart] = count;  /* size of freelist */
216*0Sstevel@tonic-gate 
217*0Sstevel@tonic-gate 	for (i = liststart+2; i < listend && current != NULL; i++) {
218*0Sstevel@tonic-gate 		answer[i] = current->where;
219*0Sstevel@tonic-gate 		current = current->next;
220*0Sstevel@tonic-gate 		++realcount;
221*0Sstevel@tonic-gate 	}
222*0Sstevel@tonic-gate 
223*0Sstevel@tonic-gate 	answer[liststart+1] = realcount;
224*0Sstevel@tonic-gate 	READUNLOCK(this, answer, "ru db_free_list::stats");
225*0Sstevel@tonic-gate 	return (answer);
226*0Sstevel@tonic-gate }
227*0Sstevel@tonic-gate 
228*0Sstevel@tonic-gate 
229*0Sstevel@tonic-gate /* Set default values for the mapping structure */
230*0Sstevel@tonic-gate void
initMappingStruct(__nisdb_table_mapping_t * m)231*0Sstevel@tonic-gate db_table::initMappingStruct(__nisdb_table_mapping_t *m) {
232*0Sstevel@tonic-gate 	if (m == 0)
233*0Sstevel@tonic-gate 		return;
234*0Sstevel@tonic-gate 
235*0Sstevel@tonic-gate 	m->initTtlLo = (ldapDBTableMapping.initTtlLo > 0) ?
236*0Sstevel@tonic-gate 			ldapDBTableMapping.initTtlLo : (3600-1800);
237*0Sstevel@tonic-gate 	m->initTtlHi = (ldapDBTableMapping.initTtlHi > 0) ?
238*0Sstevel@tonic-gate 			ldapDBTableMapping.initTtlHi : (3600+1800);
239*0Sstevel@tonic-gate 	m->ttl = (ldapDBTableMapping.ttl > 0) ?
240*0Sstevel@tonic-gate 			ldapDBTableMapping.ttl : 3600;
241*0Sstevel@tonic-gate 	m->enumExpire = 0;
242*0Sstevel@tonic-gate 	m->fromLDAP = FALSE;
243*0Sstevel@tonic-gate 	m->toLDAP = FALSE;
244*0Sstevel@tonic-gate 	m->isMaster = FALSE;
245*0Sstevel@tonic-gate 	m->retrieveError = ldapDBTableMapping.retrieveError;
246*0Sstevel@tonic-gate 	m->retrieveErrorRetry.attempts =
247*0Sstevel@tonic-gate 		ldapDBTableMapping.retrieveErrorRetry.attempts;
248*0Sstevel@tonic-gate 	m->retrieveErrorRetry.timeout =
249*0Sstevel@tonic-gate 		ldapDBTableMapping.retrieveErrorRetry.timeout;
250*0Sstevel@tonic-gate 	m->storeError = ldapDBTableMapping.storeError;
251*0Sstevel@tonic-gate 	m->storeErrorRetry.attempts =
252*0Sstevel@tonic-gate 		ldapDBTableMapping.storeErrorRetry.attempts;
253*0Sstevel@tonic-gate 	m->storeErrorRetry.timeout =
254*0Sstevel@tonic-gate 		ldapDBTableMapping.storeErrorRetry.timeout;
255*0Sstevel@tonic-gate 	m->storeErrorDisp = ldapDBTableMapping.storeErrorDisp;
256*0Sstevel@tonic-gate 	m->refreshError = ldapDBTableMapping.refreshError;
257*0Sstevel@tonic-gate 	m->refreshErrorRetry.attempts =
258*0Sstevel@tonic-gate 		ldapDBTableMapping.refreshErrorRetry.attempts;
259*0Sstevel@tonic-gate 	m->refreshErrorRetry.timeout =
260*0Sstevel@tonic-gate 		ldapDBTableMapping.refreshErrorRetry.timeout;
261*0Sstevel@tonic-gate 	m->matchFetch = ldapDBTableMapping.matchFetch;
262*0Sstevel@tonic-gate 
263*0Sstevel@tonic-gate 	if (mapping.expire != 0)
264*0Sstevel@tonic-gate 		free(mapping.expire);
265*0Sstevel@tonic-gate 	m->expire = 0;
266*0Sstevel@tonic-gate 
267*0Sstevel@tonic-gate 	if (m->tm != 0)
268*0Sstevel@tonic-gate 		free(m->tm);
269*0Sstevel@tonic-gate 	m->tm = 0;
270*0Sstevel@tonic-gate 
271*0Sstevel@tonic-gate 	/*
272*0Sstevel@tonic-gate 	 * The 'objType' field obviously indicates the type of object.
273*0Sstevel@tonic-gate 	 * However, we also use it to tell us if we've retrieved mapping
274*0Sstevel@tonic-gate 	 * data from LDAP or not; in the latter case, 'objType' is
275*0Sstevel@tonic-gate 	 * NIS_BOGUS_OBJ. For purposes of maintaining expiration times,
276*0Sstevel@tonic-gate 	 * we may need to know if the object is a table or a directory
277*0Sstevel@tonic-gate 	 * _before_ we've retrieved any mapping data. Hence the 'expireType'
278*0Sstevel@tonic-gate 	 * field, which starts as NIS_BOGUS_OBJ (meaning, don't know, assume
279*0Sstevel@tonic-gate 	 * directory for now), and later is set to NIS_DIRECTORY_OBJ
280*0Sstevel@tonic-gate 	 * (always keep expiration data, in case one of the dir entries
281*0Sstevel@tonic-gate 	 * is mapped) or NIS_TABLE_OBJ (only need expiration data if
282*0Sstevel@tonic-gate 	 * tha table is mapped).
283*0Sstevel@tonic-gate 	 */
284*0Sstevel@tonic-gate 	m->objType = NIS_BOGUS_OBJ;
285*0Sstevel@tonic-gate 	m->expireType = NIS_BOGUS_OBJ;
286*0Sstevel@tonic-gate 	if (m->objName != 0)
287*0Sstevel@tonic-gate 		free(m->objName);
288*0Sstevel@tonic-gate 	m->objName = 0;
289*0Sstevel@tonic-gate }
290*0Sstevel@tonic-gate 
291*0Sstevel@tonic-gate void
db_table_ldap_init(void)292*0Sstevel@tonic-gate db_table::db_table_ldap_init(void) {
293*0Sstevel@tonic-gate 
294*0Sstevel@tonic-gate 	INITRW(table);
295*0Sstevel@tonic-gate 
296*0Sstevel@tonic-gate 	enumMode.flag = 0;
297*0Sstevel@tonic-gate 	enumCount.flag = 0;
298*0Sstevel@tonic-gate 	enumIndex.ptr = 0;
299*0Sstevel@tonic-gate 	enumArray.ptr = 0;
300*0Sstevel@tonic-gate 
301*0Sstevel@tonic-gate 	mapping.expire = 0;
302*0Sstevel@tonic-gate 	mapping.tm = 0;
303*0Sstevel@tonic-gate 	mapping.objName = 0;
304*0Sstevel@tonic-gate 	mapping.isDeferredTable = FALSE;
305*0Sstevel@tonic-gate 	(void) mutex_init(&mapping.enumLock, 0, 0);
306*0Sstevel@tonic-gate 	mapping.enumTid = 0;
307*0Sstevel@tonic-gate 	mapping.enumStat = -1;
308*0Sstevel@tonic-gate 	mapping.enumDeferred = 0;
309*0Sstevel@tonic-gate 	mapping.enumEntries = 0;
310*0Sstevel@tonic-gate 	mapping.enumTime = 0;
311*0Sstevel@tonic-gate }
312*0Sstevel@tonic-gate 
313*0Sstevel@tonic-gate /* db_table constructor */
db_table()314*0Sstevel@tonic-gate db_table::db_table() : freelist()
315*0Sstevel@tonic-gate {
316*0Sstevel@tonic-gate 	tab = NULL;
317*0Sstevel@tonic-gate 	table_size = 0;
318*0Sstevel@tonic-gate 	last_used = 0;
319*0Sstevel@tonic-gate 	count = 0;
320*0Sstevel@tonic-gate 
321*0Sstevel@tonic-gate 	db_table_ldap_init();
322*0Sstevel@tonic-gate 	initMappingStruct(&mapping);
323*0Sstevel@tonic-gate 
324*0Sstevel@tonic-gate /*  grow(); */
325*0Sstevel@tonic-gate }
326*0Sstevel@tonic-gate 
327*0Sstevel@tonic-gate /*
328*0Sstevel@tonic-gate  * db_table destructor:
329*0Sstevel@tonic-gate  * 1.  Get rid of contents of freelist
330*0Sstevel@tonic-gate  * 2.  delete all entries hanging off table
331*0Sstevel@tonic-gate  * 3.  get rid of table itself
332*0Sstevel@tonic-gate */
~db_table()333*0Sstevel@tonic-gate db_table::~db_table()
334*0Sstevel@tonic-gate {
335*0Sstevel@tonic-gate 	WRITELOCKV(this, "w db_table::~db_table");
336*0Sstevel@tonic-gate 	reset();
337*0Sstevel@tonic-gate 	DESTROYRW(table);
338*0Sstevel@tonic-gate }
339*0Sstevel@tonic-gate 
340*0Sstevel@tonic-gate /* reset size and pointers */
341*0Sstevel@tonic-gate void
reset()342*0Sstevel@tonic-gate db_table::reset()
343*0Sstevel@tonic-gate {
344*0Sstevel@tonic-gate 	int i, done = 0;
345*0Sstevel@tonic-gate 
346*0Sstevel@tonic-gate 	WRITELOCKV(this, "w db_table::reset");
347*0Sstevel@tonic-gate 	freelist.reset();
348*0Sstevel@tonic-gate 
349*0Sstevel@tonic-gate 	/* Add sanity check in case of table corruption */
350*0Sstevel@tonic-gate 	if (tab != NULL) {
351*0Sstevel@tonic-gate 		for (i = 0;
352*0Sstevel@tonic-gate 			i <= last_used && i < table_size && done < count;
353*0Sstevel@tonic-gate 			i++) {
354*0Sstevel@tonic-gate 			if (tab[i]) {
355*0Sstevel@tonic-gate 				free_entry(tab[i]);
356*0Sstevel@tonic-gate 				++done;
357*0Sstevel@tonic-gate 			}
358*0Sstevel@tonic-gate 		}
359*0Sstevel@tonic-gate 	}
360*0Sstevel@tonic-gate 
361*0Sstevel@tonic-gate 	delete tab;
362*0Sstevel@tonic-gate 	table_size = last_used = count = 0;
363*0Sstevel@tonic-gate 	tab = NULL;
364*0Sstevel@tonic-gate 	sfree(mapping.expire);
365*0Sstevel@tonic-gate 	mapping.expire = NULL;
366*0Sstevel@tonic-gate 	mapping.objType = NIS_BOGUS_OBJ;
367*0Sstevel@tonic-gate 	mapping.expireType = NIS_BOGUS_OBJ;
368*0Sstevel@tonic-gate 	sfree(mapping.objName);
369*0Sstevel@tonic-gate 	mapping.objName = 0;
370*0Sstevel@tonic-gate 	/* Leave other values of the mapping structure unchanged */
371*0Sstevel@tonic-gate 	enumMode.flag = 0;
372*0Sstevel@tonic-gate 	enumCount.flag = 0;
373*0Sstevel@tonic-gate 	sfree(enumIndex.ptr);
374*0Sstevel@tonic-gate 	enumIndex.ptr = 0;
375*0Sstevel@tonic-gate 	sfree(enumArray.ptr);
376*0Sstevel@tonic-gate 	enumArray.ptr = 0;
377*0Sstevel@tonic-gate 	WRITEUNLOCKV(this, "wu db_table::reset");
378*0Sstevel@tonic-gate }
379*0Sstevel@tonic-gate 
380*0Sstevel@tonic-gate db_status
allocateExpire(long oldSize,long newSize)381*0Sstevel@tonic-gate db_table::allocateExpire(long oldSize, long newSize) {
382*0Sstevel@tonic-gate 	time_t			*newExpire;
383*0Sstevel@tonic-gate 
384*0Sstevel@tonic-gate 	newExpire = (time_t *)realloc(mapping.expire,
385*0Sstevel@tonic-gate 				newSize * sizeof (mapping.expire[0]));
386*0Sstevel@tonic-gate 	if (newExpire != NULL) {
387*0Sstevel@tonic-gate 		/* Initialize new portion */
388*0Sstevel@tonic-gate 		(void) memset(&newExpire[oldSize], 0,
389*0Sstevel@tonic-gate 				(newSize-oldSize) * sizeof (newExpire[0]));
390*0Sstevel@tonic-gate 		mapping.expire = newExpire;
391*0Sstevel@tonic-gate 	} else {
392*0Sstevel@tonic-gate 		return (DB_MEMORY_LIMIT);
393*0Sstevel@tonic-gate 	}
394*0Sstevel@tonic-gate 
395*0Sstevel@tonic-gate 	return (DB_SUCCESS);
396*0Sstevel@tonic-gate }
397*0Sstevel@tonic-gate 
398*0Sstevel@tonic-gate db_status
allocateEnumArray(long oldSize,long newSize)399*0Sstevel@tonic-gate db_table::allocateEnumArray(long oldSize, long newSize) {
400*0Sstevel@tonic-gate 	entry_object	**newEnumArray;
401*0Sstevel@tonic-gate 	char		*myself = "db_table::allocateEnumArray";
402*0Sstevel@tonic-gate 
403*0Sstevel@tonic-gate 	if (enumCount.flag > 0) {
404*0Sstevel@tonic-gate 		if (enumIndex.ptr == 0) {
405*0Sstevel@tonic-gate 			enumIndex.ptr = (entryp *)am(myself, enumCount.flag *
406*0Sstevel@tonic-gate 						sizeof (entryp));
407*0Sstevel@tonic-gate 			if (enumIndex.ptr == 0)
408*0Sstevel@tonic-gate 				return (DB_MEMORY_LIMIT);
409*0Sstevel@tonic-gate 		}
410*0Sstevel@tonic-gate 		oldSize = 0;
411*0Sstevel@tonic-gate 		newSize = enumCount.flag;
412*0Sstevel@tonic-gate 	}
413*0Sstevel@tonic-gate 	newEnumArray = (entry_object **)realloc(enumArray.ptr,
414*0Sstevel@tonic-gate 			newSize * sizeof (entry_object *));
415*0Sstevel@tonic-gate 	if (newEnumArray != 0 && newSize > oldSize) {
416*0Sstevel@tonic-gate 		(void) memcpy(&newEnumArray[oldSize], &tab[oldSize],
417*0Sstevel@tonic-gate 			(newSize-oldSize) * sizeof (entry_object *));
418*0Sstevel@tonic-gate 		enumArray.ptr = newEnumArray;
419*0Sstevel@tonic-gate 	} else if (newEnumArray == 0) {
420*0Sstevel@tonic-gate 		return (DB_MEMORY_LIMIT);
421*0Sstevel@tonic-gate 	}
422*0Sstevel@tonic-gate 
423*0Sstevel@tonic-gate 	return (DB_SUCCESS);
424*0Sstevel@tonic-gate }
425*0Sstevel@tonic-gate 
426*0Sstevel@tonic-gate /* Expand the table.  Fatal error if insufficient memory. */
427*0Sstevel@tonic-gate void
grow()428*0Sstevel@tonic-gate db_table::grow()
429*0Sstevel@tonic-gate {
430*0Sstevel@tonic-gate 	WRITELOCKV(this, "w db_table::grow");
431*0Sstevel@tonic-gate 	long oldsize = table_size;
432*0Sstevel@tonic-gate 	entry_object_p *oldtab = tab;
433*0Sstevel@tonic-gate 	long i;
434*0Sstevel@tonic-gate 
435*0Sstevel@tonic-gate 	table_size = get_new_table_size(oldsize);
436*0Sstevel@tonic-gate 
437*0Sstevel@tonic-gate #ifdef DEBUG
438*0Sstevel@tonic-gate 	fprintf(stderr, "db_table GROWING to %d\n", table_size);
439*0Sstevel@tonic-gate #endif
440*0Sstevel@tonic-gate 
441*0Sstevel@tonic-gate 	if (table_size > CALLOC_LIMIT) {
442*0Sstevel@tonic-gate 		table_size = oldsize;
443*0Sstevel@tonic-gate 		WRITEUNLOCKV(this, "wu db_table::grow");
444*0Sstevel@tonic-gate 		FATAL("db_table::grow: table size exceeds calloc limit",
445*0Sstevel@tonic-gate 			DB_MEMORY_LIMIT);
446*0Sstevel@tonic-gate 	}
447*0Sstevel@tonic-gate 
448*0Sstevel@tonic-gate //  if ((tab = new entry_object_p[table_size]) == NULL)
449*0Sstevel@tonic-gate 	if ((tab = (entry_object_p*)
450*0Sstevel@tonic-gate 		calloc((unsigned int) table_size,
451*0Sstevel@tonic-gate 			sizeof (entry_object_p))) == NULL) {
452*0Sstevel@tonic-gate 		tab = oldtab;		// restore previous table info
453*0Sstevel@tonic-gate 		table_size = oldsize;
454*0Sstevel@tonic-gate 		WRITEUNLOCKV(this, "wu db_table::grow");
455*0Sstevel@tonic-gate 		FATAL("db_table::grow: cannot allocate space", DB_MEMORY_LIMIT);
456*0Sstevel@tonic-gate 	}
457*0Sstevel@tonic-gate 
458*0Sstevel@tonic-gate 	/*
459*0Sstevel@tonic-gate 	 * For directories, we may need the expire time array even if the
460*0Sstevel@tonic-gate 	 * directory itself isn't mapped. If the objType and expireType both
461*0Sstevel@tonic-gate 	 * are bogus, we don't  know yet if this is a table or a directory,
462*0Sstevel@tonic-gate 	 * and must proceed accordingly.
463*0Sstevel@tonic-gate 	 */
464*0Sstevel@tonic-gate 	if (mapping.objType == NIS_DIRECTORY_OBJ ||
465*0Sstevel@tonic-gate 			mapping.expireType != NIS_TABLE_OBJ ||
466*0Sstevel@tonic-gate 			mapping.fromLDAP) {
467*0Sstevel@tonic-gate 		db_status stat = allocateExpire(oldsize, table_size);
468*0Sstevel@tonic-gate 		if (stat != DB_SUCCESS) {
469*0Sstevel@tonic-gate 			free(tab);
470*0Sstevel@tonic-gate 			tab = oldtab;
471*0Sstevel@tonic-gate 			table_size = oldsize;
472*0Sstevel@tonic-gate 			WRITEUNLOCKV(this, "wu db_table::grow expire");
473*0Sstevel@tonic-gate 			FATAL(
474*0Sstevel@tonic-gate 		"db_table::grow: cannot allocate space for expire", stat);
475*0Sstevel@tonic-gate 		}
476*0Sstevel@tonic-gate 	}
477*0Sstevel@tonic-gate 
478*0Sstevel@tonic-gate 	if (oldtab != NULL) {
479*0Sstevel@tonic-gate 		for (i = 0; i < oldsize; i++) { // transfer old to new
480*0Sstevel@tonic-gate 			tab[i] = oldtab[i];
481*0Sstevel@tonic-gate 		}
482*0Sstevel@tonic-gate 		delete oldtab;
483*0Sstevel@tonic-gate 	}
484*0Sstevel@tonic-gate 
485*0Sstevel@tonic-gate 	if (enumMode.flag) {
486*0Sstevel@tonic-gate 		db_status stat = allocateEnumArray(oldsize, table_size);
487*0Sstevel@tonic-gate 		if (stat != DB_SUCCESS) {
488*0Sstevel@tonic-gate 			free(tab);
489*0Sstevel@tonic-gate 			tab = oldtab;
490*0Sstevel@tonic-gate 			table_size = oldsize;
491*0Sstevel@tonic-gate 			WRITEUNLOCKV(this, "wu db_table::grow enumArray");
492*0Sstevel@tonic-gate 			FATAL(
493*0Sstevel@tonic-gate 		"db_table::grow: cannot allocate space for enumArray", stat);
494*0Sstevel@tonic-gate 		}
495*0Sstevel@tonic-gate 	}
496*0Sstevel@tonic-gate 
497*0Sstevel@tonic-gate 	WRITEUNLOCKV(this, "wu db_table::grow");
498*0Sstevel@tonic-gate }
499*0Sstevel@tonic-gate 
500*0Sstevel@tonic-gate /*
501*0Sstevel@tonic-gate  * Return the first entry in table, also return its position in
502*0Sstevel@tonic-gate  * 'where'.  Return NULL in both if no next entry is found.
503*0Sstevel@tonic-gate  */
504*0Sstevel@tonic-gate entry_object*
first_entry(entryp * where)505*0Sstevel@tonic-gate db_table::first_entry(entryp * where)
506*0Sstevel@tonic-gate {
507*0Sstevel@tonic-gate 	ASSERTRHELD(table);
508*0Sstevel@tonic-gate 	if (count == 0 || tab == NULL) {  /* empty table */
509*0Sstevel@tonic-gate 		*where = NULL;
510*0Sstevel@tonic-gate 		return (NULL);
511*0Sstevel@tonic-gate 	} else {
512*0Sstevel@tonic-gate 		entryp i;
513*0Sstevel@tonic-gate 		for (i = DB_TABLE_START;
514*0Sstevel@tonic-gate 			i < table_size && i <= last_used; i++) {
515*0Sstevel@tonic-gate 			if (tab[i] != NULL) {
516*0Sstevel@tonic-gate 				*where = i;
517*0Sstevel@tonic-gate 				return (tab[i]);
518*0Sstevel@tonic-gate 			}
519*0Sstevel@tonic-gate 		}
520*0Sstevel@tonic-gate 	}
521*0Sstevel@tonic-gate 	*where = NULL;
522*0Sstevel@tonic-gate 	return (NULL);
523*0Sstevel@tonic-gate }
524*0Sstevel@tonic-gate 
525*0Sstevel@tonic-gate /*
526*0Sstevel@tonic-gate  * Return the next entry in table from 'prev', also return its position in
527*0Sstevel@tonic-gate  * 'newentry'.  Return NULL in both if no next entry is found.
528*0Sstevel@tonic-gate  */
529*0Sstevel@tonic-gate entry_object *
next_entry(entryp prev,entryp * newentry)530*0Sstevel@tonic-gate db_table::next_entry(entryp prev, entryp* newentry)
531*0Sstevel@tonic-gate {
532*0Sstevel@tonic-gate 	long i;
533*0Sstevel@tonic-gate 
534*0Sstevel@tonic-gate 	ASSERTRHELD(table);
535*0Sstevel@tonic-gate 	if (prev >= table_size || tab == NULL || tab[prev] == NULL)
536*0Sstevel@tonic-gate 		return (NULL);
537*0Sstevel@tonic-gate 	for (i = prev+1; i < table_size && i <= last_used; i++) {
538*0Sstevel@tonic-gate 		if (tab[i] != NULL) {
539*0Sstevel@tonic-gate 			*newentry = i;
540*0Sstevel@tonic-gate 			return (tab[i]);
541*0Sstevel@tonic-gate 		}
542*0Sstevel@tonic-gate 	}
543*0Sstevel@tonic-gate 	*newentry = NULL;
544*0Sstevel@tonic-gate 	return (NULL);
545*0Sstevel@tonic-gate }
546*0Sstevel@tonic-gate 
547*0Sstevel@tonic-gate /* Return entry at location 'where', NULL if location is invalid. */
548*0Sstevel@tonic-gate entry_object *
get_entry(entryp where)549*0Sstevel@tonic-gate db_table::get_entry(entryp where)
550*0Sstevel@tonic-gate {
551*0Sstevel@tonic-gate 	ASSERTRHELD(table);
552*0Sstevel@tonic-gate 	if (where < table_size && tab != NULL && tab[where] != NULL)
553*0Sstevel@tonic-gate 		return (tab[where]);
554*0Sstevel@tonic-gate 	else
555*0Sstevel@tonic-gate 		return (NULL);
556*0Sstevel@tonic-gate }
557*0Sstevel@tonic-gate 
558*0Sstevel@tonic-gate void
setEntryExp(entryp where,entry_obj * obj,int initialLoad)559*0Sstevel@tonic-gate db_table::setEntryExp(entryp where, entry_obj *obj, int initialLoad) {
560*0Sstevel@tonic-gate 	nis_object		*o;
561*0Sstevel@tonic-gate 	char			*myself = "db_table::setEntryExp";
562*0Sstevel@tonic-gate 
563*0Sstevel@tonic-gate 	/*
564*0Sstevel@tonic-gate 	 * If we don't know what type of object this is yet, we
565*0Sstevel@tonic-gate 	 * can find out now. If it's a directory, the pseudo-object
566*0Sstevel@tonic-gate 	 * in column zero will have the type "IN_DIRECTORY";
567*0Sstevel@tonic-gate 	 * otherwise, it's a table object.
568*0Sstevel@tonic-gate 	 */
569*0Sstevel@tonic-gate 	if (mapping.expireType == NIS_BOGUS_OBJ) {
570*0Sstevel@tonic-gate 		if (obj != 0) {
571*0Sstevel@tonic-gate 			if (obj->en_type != 0 &&
572*0Sstevel@tonic-gate 				strcmp(obj->en_type, "IN_DIRECTORY") == 0) {
573*0Sstevel@tonic-gate 				mapping.expireType = NIS_DIRECTORY_OBJ;
574*0Sstevel@tonic-gate 			} else {
575*0Sstevel@tonic-gate 				mapping.expireType = NIS_TABLE_OBJ;
576*0Sstevel@tonic-gate 				if (!mapping.fromLDAP) {
577*0Sstevel@tonic-gate 					free(mapping.expire);
578*0Sstevel@tonic-gate 					mapping.expire = 0;
579*0Sstevel@tonic-gate 				}
580*0Sstevel@tonic-gate 			}
581*0Sstevel@tonic-gate 		}
582*0Sstevel@tonic-gate 	}
583*0Sstevel@tonic-gate 
584*0Sstevel@tonic-gate 	/* Set the entry TTL */
585*0Sstevel@tonic-gate 	if (mapping.expire != NULL) {
586*0Sstevel@tonic-gate 		struct timeval	now;
587*0Sstevel@tonic-gate 		time_t		lo, hi, ttl;
588*0Sstevel@tonic-gate 
589*0Sstevel@tonic-gate 		(void) gettimeofday(&now, NULL);
590*0Sstevel@tonic-gate 		if (mapping.expireType == NIS_TABLE_OBJ) {
591*0Sstevel@tonic-gate 			lo = mapping.initTtlLo;
592*0Sstevel@tonic-gate 			hi = mapping.initTtlHi;
593*0Sstevel@tonic-gate 			ttl = mapping.ttl;
594*0Sstevel@tonic-gate 			/* TTL == 0 means always expired */
595*0Sstevel@tonic-gate 			if (ttl == 0)
596*0Sstevel@tonic-gate 				ttl = -1;
597*0Sstevel@tonic-gate 		} else {
598*0Sstevel@tonic-gate 			__nis_table_mapping_t	*t = 0;
599*0Sstevel@tonic-gate 
600*0Sstevel@tonic-gate 			o = unmakePseudoEntryObj(obj, 0);
601*0Sstevel@tonic-gate 			if (o != 0) {
602*0Sstevel@tonic-gate 				__nis_buffer_t	b = {0, 0};
603*0Sstevel@tonic-gate 
604*0Sstevel@tonic-gate 				bp2buf(myself, &b, "%s.%s",
605*0Sstevel@tonic-gate 					o->zo_name, o->zo_domain);
606*0Sstevel@tonic-gate 				t = getObjMapping(b.buf, 0, 1, 0, 0);
607*0Sstevel@tonic-gate 				sfree(b.buf);
608*0Sstevel@tonic-gate 				nis_destroy_object(o);
609*0Sstevel@tonic-gate 			}
610*0Sstevel@tonic-gate 
611*0Sstevel@tonic-gate 			if (t != 0) {
612*0Sstevel@tonic-gate 				lo = t->initTtlLo;
613*0Sstevel@tonic-gate 				hi = t->initTtlHi;
614*0Sstevel@tonic-gate 				ttl = t->ttl;
615*0Sstevel@tonic-gate 				/* TTL == 0 means always expired */
616*0Sstevel@tonic-gate 				if (ttl == 0)
617*0Sstevel@tonic-gate 					ttl = -1;
618*0Sstevel@tonic-gate 			} else {
619*0Sstevel@tonic-gate 				/*
620*0Sstevel@tonic-gate 				 * No expiration time initialization
621*0Sstevel@tonic-gate 				 * data. Cook up values that will
622*0Sstevel@tonic-gate 				 * result in mapping.expire[where]
623*0Sstevel@tonic-gate 				 * set to maxTimeT.
624*0Sstevel@tonic-gate 				 */
625*0Sstevel@tonic-gate 				hi = lo = ttl = maxTimeT - now.tv_sec;
626*0Sstevel@tonic-gate 			}
627*0Sstevel@tonic-gate 		}
628*0Sstevel@tonic-gate 
629*0Sstevel@tonic-gate 		if (initialLoad) {
630*0Sstevel@tonic-gate 			int	interval = hi - lo + 1;
631*0Sstevel@tonic-gate 			if (interval <= 1) {
632*0Sstevel@tonic-gate 				mapping.expire[where] = now.tv_sec + lo;
633*0Sstevel@tonic-gate 			} else {
634*0Sstevel@tonic-gate 				srand48(now.tv_sec);
635*0Sstevel@tonic-gate 				mapping.expire[where] = now.tv_sec +
636*0Sstevel@tonic-gate 							(lrand48() % interval);
637*0Sstevel@tonic-gate 			}
638*0Sstevel@tonic-gate 			if (mapping.enumExpire == 0 ||
639*0Sstevel@tonic-gate 					mapping.expire[where] <
640*0Sstevel@tonic-gate 							mapping.enumExpire)
641*0Sstevel@tonic-gate 				mapping.enumExpire = mapping.expire[where];
642*0Sstevel@tonic-gate 		} else {
643*0Sstevel@tonic-gate 			mapping.expire[where] = now.tv_sec + ttl;
644*0Sstevel@tonic-gate 		}
645*0Sstevel@tonic-gate 	}
646*0Sstevel@tonic-gate }
647*0Sstevel@tonic-gate 
648*0Sstevel@tonic-gate /*
649*0Sstevel@tonic-gate  * Add given entry to table in first available slot (either look in freelist
650*0Sstevel@tonic-gate  * or add to end of table) and return the the position of where the record
651*0Sstevel@tonic-gate  * is placed. 'count' is incremented if entry is added. Table may grow
652*0Sstevel@tonic-gate  * as a side-effect of the addition. Copy is made of input.
653*0Sstevel@tonic-gate */
654*0Sstevel@tonic-gate entryp
add_entry(entry_object * obj,int initialLoad)655*0Sstevel@tonic-gate db_table::add_entry(entry_object *obj, int initialLoad) {
656*0Sstevel@tonic-gate 	/*
657*0Sstevel@tonic-gate 	 * We're returning an index of the table array, so the caller
658*0Sstevel@tonic-gate 	 * should hold a lock until done with the index. To save us
659*0Sstevel@tonic-gate 	 * the bother of upgrading to a write lock, it might as well
660*0Sstevel@tonic-gate 	 * be a write lock to begin with.
661*0Sstevel@tonic-gate 	 */
662*0Sstevel@tonic-gate 	ASSERTWHELD(table);
663*0Sstevel@tonic-gate 	entryp where = freelist.pop();
664*0Sstevel@tonic-gate 	if (where == NULL) {				/* empty freelist */
665*0Sstevel@tonic-gate 		if (last_used >= (table_size-1))	/* full (> is for 0) */
666*0Sstevel@tonic-gate 			grow();
667*0Sstevel@tonic-gate 		where = ++last_used;
668*0Sstevel@tonic-gate 	}
669*0Sstevel@tonic-gate 	if (tab != NULL) {
670*0Sstevel@tonic-gate 		++count;
671*0Sstevel@tonic-gate 		setEntryExp(where, obj, initialLoad);
672*0Sstevel@tonic-gate 
673*0Sstevel@tonic-gate 		if (enumMode.flag)
674*0Sstevel@tonic-gate 			enumTouch(where);
675*0Sstevel@tonic-gate 		tab[where] = new_entry(obj);
676*0Sstevel@tonic-gate 		return (where);
677*0Sstevel@tonic-gate 	} else {
678*0Sstevel@tonic-gate 		return (NULL);
679*0Sstevel@tonic-gate 	}
680*0Sstevel@tonic-gate }
681*0Sstevel@tonic-gate 
682*0Sstevel@tonic-gate /*
683*0Sstevel@tonic-gate  * Replaces object at specified location by given entry.
684*0Sstevel@tonic-gate  * Returns TRUE if replacement successful; FALSE otherwise.
685*0Sstevel@tonic-gate  * There must something already at the specified location, otherwise,
686*0Sstevel@tonic-gate  * replacement fails. Copy is not made of the input.
687*0Sstevel@tonic-gate  * The pre-existing entry is freed.
688*0Sstevel@tonic-gate  */
689*0Sstevel@tonic-gate bool_t
replace_entry(entryp where,entry_object * obj)690*0Sstevel@tonic-gate db_table::replace_entry(entryp where, entry_object * obj)
691*0Sstevel@tonic-gate {
692*0Sstevel@tonic-gate 	ASSERTWHELD(table);
693*0Sstevel@tonic-gate 	if (where < DB_TABLE_START || where >= table_size ||
694*0Sstevel@tonic-gate 	    tab == NULL || tab[where] == NULL)
695*0Sstevel@tonic-gate 		return (FALSE);
696*0Sstevel@tonic-gate 	/* (Re-)set the entry TTL */
697*0Sstevel@tonic-gate 	setEntryExp(where, obj, 0);
698*0Sstevel@tonic-gate 
699*0Sstevel@tonic-gate 	if (enumMode.flag)
700*0Sstevel@tonic-gate 		enumTouch(where);
701*0Sstevel@tonic-gate 	free_entry(tab[where]);
702*0Sstevel@tonic-gate 	tab[where] = obj;
703*0Sstevel@tonic-gate 	return (TRUE);
704*0Sstevel@tonic-gate }
705*0Sstevel@tonic-gate 
706*0Sstevel@tonic-gate /*
707*0Sstevel@tonic-gate  * Deletes entry at specified location.  Returns TRUE if location is valid;
708*0Sstevel@tonic-gate  * FALSE if location is invalid, or the freed location cannot be added to
709*0Sstevel@tonic-gate  * the freelist.  'count' is decremented if the deletion occurs.  The object
710*0Sstevel@tonic-gate  * at that location is freed.
711*0Sstevel@tonic-gate  */
712*0Sstevel@tonic-gate bool_t
delete_entry(entryp where)713*0Sstevel@tonic-gate db_table::delete_entry(entryp where)
714*0Sstevel@tonic-gate {
715*0Sstevel@tonic-gate 	bool_t	ret = TRUE;
716*0Sstevel@tonic-gate 
717*0Sstevel@tonic-gate 	ASSERTWHELD(table);
718*0Sstevel@tonic-gate 	if (where < DB_TABLE_START || where >= table_size ||
719*0Sstevel@tonic-gate 	    tab == NULL || tab[where] == NULL)
720*0Sstevel@tonic-gate 		return (FALSE);
721*0Sstevel@tonic-gate 	if (mapping.expire != NULL) {
722*0Sstevel@tonic-gate 		mapping.expire[where] = 0;
723*0Sstevel@tonic-gate 	}
724*0Sstevel@tonic-gate 	if (enumMode.flag)
725*0Sstevel@tonic-gate 		enumTouch(where);
726*0Sstevel@tonic-gate 	free_entry(tab[where]);
727*0Sstevel@tonic-gate 	tab[where] = NULL;    /* very important to set it to null */
728*0Sstevel@tonic-gate 	--count;
729*0Sstevel@tonic-gate 	if (where == last_used) { /* simple case, deleting from end */
730*0Sstevel@tonic-gate 		--last_used;
731*0Sstevel@tonic-gate 		return (TRUE);
732*0Sstevel@tonic-gate 	} else {
733*0Sstevel@tonic-gate 		return (freelist.push(where));
734*0Sstevel@tonic-gate 	}
735*0Sstevel@tonic-gate 	return (ret);
736*0Sstevel@tonic-gate }
737*0Sstevel@tonic-gate 
738*0Sstevel@tonic-gate /*
739*0Sstevel@tonic-gate  * Returns statistics of table.
740*0Sstevel@tonic-gate  * [vector_size][table_size][last_used][count][freelist].
741*0Sstevel@tonic-gate  * It is up to the caller to free the returned vector when his is through.
742*0Sstevel@tonic-gate  * The free list is included if 'fl' is TRUE.
743*0Sstevel@tonic-gate */
744*0Sstevel@tonic-gate long *
stats(bool_t include_freelist)745*0Sstevel@tonic-gate db_table::stats(bool_t include_freelist)
746*0Sstevel@tonic-gate {
747*0Sstevel@tonic-gate 	long *answer;
748*0Sstevel@tonic-gate 
749*0Sstevel@tonic-gate 	READLOCK(this, NULL, "r db_table::stats");
750*0Sstevel@tonic-gate 	if (include_freelist)
751*0Sstevel@tonic-gate 		answer = freelist.stats(3);
752*0Sstevel@tonic-gate 	else {
753*0Sstevel@tonic-gate 		answer = (long *)malloc(3*sizeof (long));
754*0Sstevel@tonic-gate 	}
755*0Sstevel@tonic-gate 
756*0Sstevel@tonic-gate 	if (answer) {
757*0Sstevel@tonic-gate 		answer[0] = table_size;
758*0Sstevel@tonic-gate 		answer[1] = last_used;
759*0Sstevel@tonic-gate 		answer[2] = count;
760*0Sstevel@tonic-gate 	}
761*0Sstevel@tonic-gate 	READUNLOCK(this, answer, "ru db_table::stats");
762*0Sstevel@tonic-gate 	return (answer);
763*0Sstevel@tonic-gate }
764*0Sstevel@tonic-gate 
765*0Sstevel@tonic-gate bool_t
configure(char * tablePath)766*0Sstevel@tonic-gate db_table::configure(char *tablePath) {
767*0Sstevel@tonic-gate 	long		i;
768*0Sstevel@tonic-gate 	struct timeval	now;
769*0Sstevel@tonic-gate 	char		*myself = "db_table::configure";
770*0Sstevel@tonic-gate 
771*0Sstevel@tonic-gate 	(void) gettimeofday(&now, NULL);
772*0Sstevel@tonic-gate 
773*0Sstevel@tonic-gate 	WRITELOCK(this, FALSE, "db_table::configure w");
774*0Sstevel@tonic-gate 
775*0Sstevel@tonic-gate 	/* (Re-)initialize from global info */
776*0Sstevel@tonic-gate 	initMappingStruct(&mapping);
777*0Sstevel@tonic-gate 
778*0Sstevel@tonic-gate 	/* Retrieve table mapping for this table */
779*0Sstevel@tonic-gate 	mapping.tm = (__nis_table_mapping_t *)__nis_find_item_mt(
780*0Sstevel@tonic-gate 					tablePath, &ldapMappingList, 0, 0);
781*0Sstevel@tonic-gate 	if (mapping.tm != 0) {
782*0Sstevel@tonic-gate 		__nis_object_dn_t	*odn = mapping.tm->objectDN;
783*0Sstevel@tonic-gate 
784*0Sstevel@tonic-gate 		/*
785*0Sstevel@tonic-gate 		 * The mapping.fromLDAP and mapping.toLDAP fields serve as
786*0Sstevel@tonic-gate 		 * quick-references that tell us if mapping is enabled.
787*0Sstevel@tonic-gate 		 * Hence, initialize them appropriately from the table
788*0Sstevel@tonic-gate 		 * mapping objectDN.
789*0Sstevel@tonic-gate 		 */
790*0Sstevel@tonic-gate 		while (odn != 0 && (!mapping.fromLDAP || !mapping.toLDAP)) {
791*0Sstevel@tonic-gate 			if (odn->read.scope != LDAP_SCOPE_UNKNOWN)
792*0Sstevel@tonic-gate 				mapping.fromLDAP = TRUE;
793*0Sstevel@tonic-gate 			if (odn->write.scope != LDAP_SCOPE_UNKNOWN)
794*0Sstevel@tonic-gate 				mapping.toLDAP = TRUE;
795*0Sstevel@tonic-gate 			odn = (__nis_object_dn_t *)odn->next;
796*0Sstevel@tonic-gate 		}
797*0Sstevel@tonic-gate 
798*0Sstevel@tonic-gate 		/* Set the timeout values */
799*0Sstevel@tonic-gate 		mapping.initTtlLo = mapping.tm->initTtlLo;
800*0Sstevel@tonic-gate 		mapping.initTtlHi = mapping.tm->initTtlHi;
801*0Sstevel@tonic-gate 		mapping.ttl = mapping.tm->ttl;
802*0Sstevel@tonic-gate 
803*0Sstevel@tonic-gate 		mapping.objName = sdup(myself, T, mapping.tm->objName);
804*0Sstevel@tonic-gate 		if (mapping.objName == 0 && mapping.tm->objName != 0) {
805*0Sstevel@tonic-gate 			WRITEUNLOCK(this, FALSE,
806*0Sstevel@tonic-gate 				"db_table::configure wu objName");
807*0Sstevel@tonic-gate 			FATAL3("db_table::configure objName",
808*0Sstevel@tonic-gate 				DB_MEMORY_LIMIT, FALSE);
809*0Sstevel@tonic-gate 		}
810*0Sstevel@tonic-gate 	}
811*0Sstevel@tonic-gate 
812*0Sstevel@tonic-gate 	/*
813*0Sstevel@tonic-gate 	 * In order to initialize the expiration times, we need to know
814*0Sstevel@tonic-gate 	 * if 'this' represents a table or a directory. To that end, we
815*0Sstevel@tonic-gate 	 * find an entry in the table, and invoke setEntryExp() on it.
816*0Sstevel@tonic-gate 	 * As a side effect, setEntryExp() will examine the pseudo-object
817*0Sstevel@tonic-gate 	 * in the entry, and set the expireType accordingly.
818*0Sstevel@tonic-gate 	 */
819*0Sstevel@tonic-gate 	if (tab != 0) {
820*0Sstevel@tonic-gate 		for (i = 0; i <= last_used; i++) {
821*0Sstevel@tonic-gate 			if (tab[i] != NULL) {
822*0Sstevel@tonic-gate 				setEntryExp(i, tab[i], 1);
823*0Sstevel@tonic-gate 				break;
824*0Sstevel@tonic-gate 			}
825*0Sstevel@tonic-gate 		}
826*0Sstevel@tonic-gate 	}
827*0Sstevel@tonic-gate 
828*0Sstevel@tonic-gate 	/*
829*0Sstevel@tonic-gate 	 * If mapping from an LDAP repository, make sure we have the
830*0Sstevel@tonic-gate 	 * expiration time array.
831*0Sstevel@tonic-gate 	 */
832*0Sstevel@tonic-gate 	if ((mapping.expireType != NIS_TABLE_OBJ || mapping.fromLDAP) &&
833*0Sstevel@tonic-gate 			mapping.expire == NULL && table_size > 0 && tab != 0) {
834*0Sstevel@tonic-gate 		db_status stat = allocateExpire(0, table_size);
835*0Sstevel@tonic-gate 		if (stat != DB_SUCCESS) {
836*0Sstevel@tonic-gate 			WRITEUNLOCK(this, FALSE,
837*0Sstevel@tonic-gate 				"db_table::configure wu expire");
838*0Sstevel@tonic-gate 			FATAL3("db_table::configure expire",
839*0Sstevel@tonic-gate 				stat, FALSE);
840*0Sstevel@tonic-gate 		}
841*0Sstevel@tonic-gate 	} else if (mapping.expireType == NIS_TABLE_OBJ && !mapping.fromLDAP &&
842*0Sstevel@tonic-gate 			mapping.expire != NULL) {
843*0Sstevel@tonic-gate 		/* Not using expiration times */
844*0Sstevel@tonic-gate 		free(mapping.expire);
845*0Sstevel@tonic-gate 		mapping.expire = NULL;
846*0Sstevel@tonic-gate 	}
847*0Sstevel@tonic-gate 
848*0Sstevel@tonic-gate 	/*
849*0Sstevel@tonic-gate 	 * Set initial expire times for entries that don't already have one.
850*0Sstevel@tonic-gate 	 * Establish the enumeration expiration time to be the minimum of
851*0Sstevel@tonic-gate 	 * all expiration times in the table, though no larger than current
852*0Sstevel@tonic-gate 	 * time plus initTtlHi.
853*0Sstevel@tonic-gate 	 */
854*0Sstevel@tonic-gate 	if (mapping.expire != NULL) {
855*0Sstevel@tonic-gate 		int	interval = mapping.initTtlHi - mapping.initTtlLo + 1;
856*0Sstevel@tonic-gate 		time_t	enumXp = now.tv_sec + mapping.initTtlHi;
857*0Sstevel@tonic-gate 
858*0Sstevel@tonic-gate 		if (interval > 1)
859*0Sstevel@tonic-gate 			srand48(now.tv_sec);
860*0Sstevel@tonic-gate 		for (i = 0; i <= last_used; i++) {
861*0Sstevel@tonic-gate 			if (tab[i] != NULL && mapping.expire[i] == 0) {
862*0Sstevel@tonic-gate 				if (mapping.expireType == NIS_TABLE_OBJ) {
863*0Sstevel@tonic-gate 					if (interval > 1)
864*0Sstevel@tonic-gate 						mapping.expire[i] =
865*0Sstevel@tonic-gate 							now.tv_sec +
866*0Sstevel@tonic-gate 							(lrand48() % interval);
867*0Sstevel@tonic-gate 					else
868*0Sstevel@tonic-gate 						mapping.expire[i] =
869*0Sstevel@tonic-gate 							now.tv_sec +
870*0Sstevel@tonic-gate 							mapping.initTtlLo;
871*0Sstevel@tonic-gate 				} else {
872*0Sstevel@tonic-gate 					setEntryExp(i, tab[i], 1);
873*0Sstevel@tonic-gate 				}
874*0Sstevel@tonic-gate 			}
875*0Sstevel@tonic-gate 			if (enumXp > mapping.expire[i])
876*0Sstevel@tonic-gate 				enumXp = mapping.expire[i];
877*0Sstevel@tonic-gate 		}
878*0Sstevel@tonic-gate 		mapping.enumExpire = enumXp;
879*0Sstevel@tonic-gate 	}
880*0Sstevel@tonic-gate 
881*0Sstevel@tonic-gate 	WRITEUNLOCK(this, FALSE, "db_table::configure wu");
882*0Sstevel@tonic-gate 
883*0Sstevel@tonic-gate 	return (TRUE);
884*0Sstevel@tonic-gate }
885*0Sstevel@tonic-gate 
886*0Sstevel@tonic-gate /* Return TRUE if the entry at 'loc' hasn't expired */
887*0Sstevel@tonic-gate bool_t
cacheValid(entryp loc)888*0Sstevel@tonic-gate db_table::cacheValid(entryp loc) {
889*0Sstevel@tonic-gate 	bool_t		ret;
890*0Sstevel@tonic-gate 	struct timeval	now;
891*0Sstevel@tonic-gate 
892*0Sstevel@tonic-gate 	(void) gettimeofday(&now, 0);
893*0Sstevel@tonic-gate 
894*0Sstevel@tonic-gate 	READLOCK(this, FALSE, "db_table::cacheValid r");
895*0Sstevel@tonic-gate 
896*0Sstevel@tonic-gate 	if (loc < 0 || loc >= table_size || tab == 0 || tab[loc] == 0)
897*0Sstevel@tonic-gate 		ret = FALSE;
898*0Sstevel@tonic-gate 	else if (mapping.expire == 0 || mapping.expire[loc] >= now.tv_sec)
899*0Sstevel@tonic-gate 		ret = TRUE;
900*0Sstevel@tonic-gate 	else
901*0Sstevel@tonic-gate 		ret = FALSE;
902*0Sstevel@tonic-gate 
903*0Sstevel@tonic-gate 	READUNLOCK(this, ret, "db_table::cacheValid ru");
904*0Sstevel@tonic-gate 
905*0Sstevel@tonic-gate 	return (ret);
906*0Sstevel@tonic-gate }
907*0Sstevel@tonic-gate 
908*0Sstevel@tonic-gate /*
909*0Sstevel@tonic-gate  * If the supplied object has the same content as the one at 'loc',
910*0Sstevel@tonic-gate  * update the expiration time for the latter, and return TRUE.
911*0Sstevel@tonic-gate  */
912*0Sstevel@tonic-gate bool_t
dupEntry(entry_object * obj,entryp loc)913*0Sstevel@tonic-gate db_table::dupEntry(entry_object *obj, entryp loc) {
914*0Sstevel@tonic-gate 	if (obj == 0 || loc < 0 || loc >= table_size || tab == 0 ||
915*0Sstevel@tonic-gate 			tab[loc] == 0)
916*0Sstevel@tonic-gate 		return (FALSE);
917*0Sstevel@tonic-gate 
918*0Sstevel@tonic-gate 	if (sameEntry(obj, tab[loc])) {
919*0Sstevel@tonic-gate 		setEntryExp(loc, tab[loc], 0);
920*0Sstevel@tonic-gate 
921*0Sstevel@tonic-gate 		if (enumMode.flag > 0)
922*0Sstevel@tonic-gate 			enumTouch(loc);
923*0Sstevel@tonic-gate 		return (TRUE);
924*0Sstevel@tonic-gate 	}
925*0Sstevel@tonic-gate 
926*0Sstevel@tonic-gate 	return (FALSE);
927*0Sstevel@tonic-gate }
928*0Sstevel@tonic-gate 
929*0Sstevel@tonic-gate /*
930*0Sstevel@tonic-gate  * If enumeration mode is enabled, we keep a shadow array that initially
931*0Sstevel@tonic-gate  * starts out the same as 'tab'. Any update activity (add, remove, replace,
932*0Sstevel@tonic-gate  * or update timestamp) for an entry in the table means we delete the shadow
933*0Sstevel@tonic-gate  * array pointer. When ending enumeration mode, we return the shadow array.
934*0Sstevel@tonic-gate  * Any non-NULL entries in the array have not been updated since the start
935*0Sstevel@tonic-gate  * of the enum mode.
936*0Sstevel@tonic-gate  *
937*0Sstevel@tonic-gate  * The indended use is for enumeration of an LDAP container, where we
938*0Sstevel@tonic-gate  * will update all entries that currently exist in LDAP. The entries we
939*0Sstevel@tonic-gate  * don't update are those that don't exist in LDAP, and thus should be
940*0Sstevel@tonic-gate  * removed.
941*0Sstevel@tonic-gate  *
942*0Sstevel@tonic-gate  * Note that any LDAP query strictly speaking can be a partial enumeration
943*0Sstevel@tonic-gate  * (i.e., return more than one match). Since the query might also have
944*0Sstevel@tonic-gate  * matched multiple local DB entries, we need to do the same work as for
945*0Sstevel@tonic-gate  * enumeration for any query. In order to avoid having to work on the
946*0Sstevel@tonic-gate  * whole 'tab' array for simple queries (which we expect usually will
947*0Sstevel@tonic-gate  * match just one or at most a few entries), we have a "reduced" enum mode,
948*0Sstevel@tonic-gate  * where the caller supplies a count of the number of DB entries (derived
949*0Sstevel@tonic-gate  * from db_mindex::satisfy_query() or similar), and then uses enumSetup()
950*0Sstevel@tonic-gate  * to specify which 'tab' entries we're interested in.
951*0Sstevel@tonic-gate  */
952*0Sstevel@tonic-gate void
setEnumMode(long enumNum)953*0Sstevel@tonic-gate db_table::setEnumMode(long enumNum) {
954*0Sstevel@tonic-gate 	char	*myself = "setEnumMode";
955*0Sstevel@tonic-gate 
956*0Sstevel@tonic-gate 	enumMode.flag++;
957*0Sstevel@tonic-gate 	if (enumMode.flag == 1) {
958*0Sstevel@tonic-gate 		db_status	stat;
959*0Sstevel@tonic-gate 
960*0Sstevel@tonic-gate 		if (enumNum < 0)
961*0Sstevel@tonic-gate 			enumNum = 0;
962*0Sstevel@tonic-gate 		else if (enumNum >= table_size)
963*0Sstevel@tonic-gate 			enumNum = table_size;
964*0Sstevel@tonic-gate 
965*0Sstevel@tonic-gate 		enumCount.flag = enumNum;
966*0Sstevel@tonic-gate 
967*0Sstevel@tonic-gate 		stat = allocateEnumArray(0, table_size);
968*0Sstevel@tonic-gate 
969*0Sstevel@tonic-gate 		if (stat != DB_SUCCESS) {
970*0Sstevel@tonic-gate 			enumMode.flag = 0;
971*0Sstevel@tonic-gate 			enumCount.flag = 0;
972*0Sstevel@tonic-gate 			logmsg(MSG_NOTIMECHECK, LOG_ERR,
973*0Sstevel@tonic-gate 		"%s: No memory for enum check array; entry removal disabled",
974*0Sstevel@tonic-gate 				myself);
975*0Sstevel@tonic-gate 		}
976*0Sstevel@tonic-gate 	}
977*0Sstevel@tonic-gate }
978*0Sstevel@tonic-gate 
979*0Sstevel@tonic-gate void
clearEnumMode(void)980*0Sstevel@tonic-gate db_table::clearEnumMode(void) {
981*0Sstevel@tonic-gate 	if (enumMode.flag > 0) {
982*0Sstevel@tonic-gate 		enumMode.flag--;
983*0Sstevel@tonic-gate 		if (enumMode.flag == 0) {
984*0Sstevel@tonic-gate 			sfree(enumArray.ptr);
985*0Sstevel@tonic-gate 			enumArray.ptr = 0;
986*0Sstevel@tonic-gate 			if (enumCount.flag > 0) {
987*0Sstevel@tonic-gate 				sfree(enumIndex.ptr);
988*0Sstevel@tonic-gate 				enumIndex.ptr = 0;
989*0Sstevel@tonic-gate 				enumCount.flag = 0;
990*0Sstevel@tonic-gate 			}
991*0Sstevel@tonic-gate 		}
992*0Sstevel@tonic-gate 	}
993*0Sstevel@tonic-gate }
994*0Sstevel@tonic-gate 
995*0Sstevel@tonic-gate entry_object **
endEnumMode(long * numEa)996*0Sstevel@tonic-gate db_table::endEnumMode(long *numEa) {
997*0Sstevel@tonic-gate 	if (enumMode.flag > 0) {
998*0Sstevel@tonic-gate 		enumMode.flag--;
999*0Sstevel@tonic-gate 		if (enumMode.flag == 0) {
1000*0Sstevel@tonic-gate 			entry_obj	**ea = (entry_object **)enumArray.ptr;
1001*0Sstevel@tonic-gate 			long		nea;
1002*0Sstevel@tonic-gate 
1003*0Sstevel@tonic-gate 			enumArray.ptr = 0;
1004*0Sstevel@tonic-gate 
1005*0Sstevel@tonic-gate 			if (enumCount.flag > 0) {
1006*0Sstevel@tonic-gate 				nea = enumCount.flag;
1007*0Sstevel@tonic-gate 				enumCount.flag = 0;
1008*0Sstevel@tonic-gate 				sfree(enumIndex.ptr);
1009*0Sstevel@tonic-gate 				enumIndex.ptr = 0;
1010*0Sstevel@tonic-gate 			} else {
1011*0Sstevel@tonic-gate 				nea = table_size;
1012*0Sstevel@tonic-gate 			}
1013*0Sstevel@tonic-gate 
1014*0Sstevel@tonic-gate 			if (numEa != 0)
1015*0Sstevel@tonic-gate 				*numEa = nea;
1016*0Sstevel@tonic-gate 
1017*0Sstevel@tonic-gate 			return (ea);
1018*0Sstevel@tonic-gate 		}
1019*0Sstevel@tonic-gate 	}
1020*0Sstevel@tonic-gate 
1021*0Sstevel@tonic-gate 	if (numEa != 0)
1022*0Sstevel@tonic-gate 		*numEa = 0;
1023*0Sstevel@tonic-gate 
1024*0Sstevel@tonic-gate 	return (0);
1025*0Sstevel@tonic-gate }
1026*0Sstevel@tonic-gate 
1027*0Sstevel@tonic-gate /*
1028*0Sstevel@tonic-gate  * Set the appropriate entry in the enum array to NULL.
1029*0Sstevel@tonic-gate  */
1030*0Sstevel@tonic-gate void
enumTouch(entryp loc)1031*0Sstevel@tonic-gate db_table::enumTouch(entryp loc) {
1032*0Sstevel@tonic-gate 	if (loc < 0 || loc >= table_size)
1033*0Sstevel@tonic-gate 		return;
1034*0Sstevel@tonic-gate 
1035*0Sstevel@tonic-gate 	if (enumMode.flag > 0) {
1036*0Sstevel@tonic-gate 		if (enumCount.flag < 1) {
1037*0Sstevel@tonic-gate 			((entry_object **)enumArray.ptr)[loc] = 0;
1038*0Sstevel@tonic-gate 		} else {
1039*0Sstevel@tonic-gate 			int	i;
1040*0Sstevel@tonic-gate 
1041*0Sstevel@tonic-gate 			for (i = 0; i < enumCount.flag; i++) {
1042*0Sstevel@tonic-gate 				if (loc == ((entryp *)enumIndex.ptr)[i]) {
1043*0Sstevel@tonic-gate 					((entry_object **)enumArray.ptr)[i] = 0;
1044*0Sstevel@tonic-gate 					break;
1045*0Sstevel@tonic-gate 				}
1046*0Sstevel@tonic-gate 			}
1047*0Sstevel@tonic-gate 		}
1048*0Sstevel@tonic-gate 	}
1049*0Sstevel@tonic-gate }
1050*0Sstevel@tonic-gate 
1051*0Sstevel@tonic-gate /*
1052*0Sstevel@tonic-gate  * Add the entry indicated by 'loc' to the enumIndex array, at 'index'.
1053*0Sstevel@tonic-gate  */
1054*0Sstevel@tonic-gate void
enumSetup(entryp loc,long index)1055*0Sstevel@tonic-gate db_table::enumSetup(entryp loc, long index) {
1056*0Sstevel@tonic-gate 	if (enumMode.flag == 0 || loc < 0 || loc >= table_size ||
1057*0Sstevel@tonic-gate 			index < 0 || index >= enumCount.flag)
1058*0Sstevel@tonic-gate 		return;
1059*0Sstevel@tonic-gate 
1060*0Sstevel@tonic-gate 	((entryp *)enumIndex.ptr)[index] = loc;
1061*0Sstevel@tonic-gate 	((entry_object **)enumArray.ptr)[index] = tab[loc];
1062*0Sstevel@tonic-gate }
1063*0Sstevel@tonic-gate 
1064*0Sstevel@tonic-gate /*
1065*0Sstevel@tonic-gate  * Touch, i.e., update the expiration time for the entry. Also, if enum
1066*0Sstevel@tonic-gate  * mode is in effect, mark the entry used for enum purposes.
1067*0Sstevel@tonic-gate  */
1068*0Sstevel@tonic-gate void
touchEntry(entryp loc)1069*0Sstevel@tonic-gate db_table::touchEntry(entryp loc) {
1070*0Sstevel@tonic-gate 	if (loc < 0 || loc >= table_size || tab == 0 || tab[loc] == 0)
1071*0Sstevel@tonic-gate 		return;
1072*0Sstevel@tonic-gate 
1073*0Sstevel@tonic-gate 	setEntryExp(loc, tab[loc], 0);
1074*0Sstevel@tonic-gate 
1075*0Sstevel@tonic-gate 	enumTouch(loc);
1076*0Sstevel@tonic-gate }
1077*0Sstevel@tonic-gate 
1078*0Sstevel@tonic-gate /* ************************* pickle_table ********************* */
1079*0Sstevel@tonic-gate /* Does the actual writing to/from file specific for db_table structure. */
1080*0Sstevel@tonic-gate /*
1081*0Sstevel@tonic-gate  * This was a static earlier with the func name being transfer_aux. The
1082*0Sstevel@tonic-gate  * backup and restore project needed this to copy files over.
1083*0Sstevel@tonic-gate  */
1084*0Sstevel@tonic-gate bool_t
transfer_aux_table(XDR * x,pptr dp)1085*0Sstevel@tonic-gate transfer_aux_table(XDR* x, pptr dp)
1086*0Sstevel@tonic-gate {
1087*0Sstevel@tonic-gate 	return (xdr_db_table(x, (db_table*) dp));
1088*0Sstevel@tonic-gate }
1089*0Sstevel@tonic-gate 
1090*0Sstevel@tonic-gate class pickle_table: public pickle_file {
1091*0Sstevel@tonic-gate     public:
pickle_table(char * f,pickle_mode m)1092*0Sstevel@tonic-gate 	pickle_table(char *f, pickle_mode m) : pickle_file(f, m) {}
1093*0Sstevel@tonic-gate 
1094*0Sstevel@tonic-gate 	/* Transfers db_table structure pointed to by dp to/from file. */
transfer(db_table * dp)1095*0Sstevel@tonic-gate 	int transfer(db_table* dp)
1096*0Sstevel@tonic-gate 	{ return (pickle_file::transfer((pptr) dp, &transfer_aux_table)); }
1097*0Sstevel@tonic-gate };
1098*0Sstevel@tonic-gate 
1099*0Sstevel@tonic-gate /*
1100*0Sstevel@tonic-gate  * Writes the contents of table, including the all the entries, into the
1101*0Sstevel@tonic-gate  * specified file in XDR format.  May need to change this to use APPEND
1102*0Sstevel@tonic-gate  * mode instead.
1103*0Sstevel@tonic-gate  */
1104*0Sstevel@tonic-gate int
dump(char * file)1105*0Sstevel@tonic-gate db_table::dump(char *file)
1106*0Sstevel@tonic-gate {
1107*0Sstevel@tonic-gate 	int	ret;
1108*0Sstevel@tonic-gate 	READLOCK(this, -1, "r db_table::dump");
1109*0Sstevel@tonic-gate 	pickle_table f(file, PICKLE_WRITE);   /* may need to use APPEND mode */
1110*0Sstevel@tonic-gate 	int status = f.transfer(this);
1111*0Sstevel@tonic-gate 
1112*0Sstevel@tonic-gate 	if (status == 1)
1113*0Sstevel@tonic-gate 		ret = -1;
1114*0Sstevel@tonic-gate 	else
1115*0Sstevel@tonic-gate 		ret = status;
1116*0Sstevel@tonic-gate 	READUNLOCK(this, ret, "ru db_table::dump");
1117*0Sstevel@tonic-gate }
1118*0Sstevel@tonic-gate 
1119*0Sstevel@tonic-gate /* Constructor that loads in the table from the given file */
db_table(char * file)1120*0Sstevel@tonic-gate db_table::db_table(char *file)  : freelist()
1121*0Sstevel@tonic-gate {
1122*0Sstevel@tonic-gate 	pickle_table f(file, PICKLE_READ);
1123*0Sstevel@tonic-gate 	tab = NULL;
1124*0Sstevel@tonic-gate 	table_size = last_used = count = 0;
1125*0Sstevel@tonic-gate 
1126*0Sstevel@tonic-gate 	/* load  table */
1127*0Sstevel@tonic-gate 	if (f.transfer(this) < 0) {
1128*0Sstevel@tonic-gate 		/* fell through, something went wrong, initialize to null */
1129*0Sstevel@tonic-gate 		tab = NULL;
1130*0Sstevel@tonic-gate 		table_size = last_used = count = 0;
1131*0Sstevel@tonic-gate 		freelist.init();
1132*0Sstevel@tonic-gate 	}
1133*0Sstevel@tonic-gate 
1134*0Sstevel@tonic-gate 	db_table_ldap_init();
1135*0Sstevel@tonic-gate 	initMappingStruct(&mapping);
1136*0Sstevel@tonic-gate }
1137*0Sstevel@tonic-gate 
1138*0Sstevel@tonic-gate /* Returns whether location is valid. */
entry_exists_p(entryp i)1139*0Sstevel@tonic-gate bool_t db_table::entry_exists_p(entryp i) {
1140*0Sstevel@tonic-gate 	bool_t	ret = FALSE;
1141*0Sstevel@tonic-gate 	READLOCK(this, FALSE, "r db_table::entry_exists_p");
1142*0Sstevel@tonic-gate 	if (tab != NULL && i < table_size)
1143*0Sstevel@tonic-gate 		ret = tab[i] != NULL;
1144*0Sstevel@tonic-gate 	READUNLOCK(this, ret, "ru db_table::entry_exists_p");
1145*0Sstevel@tonic-gate 	return (ret);
1146*0Sstevel@tonic-gate }
1147*0Sstevel@tonic-gate 
1148*0Sstevel@tonic-gate /* Empty free list */
init()1149*0Sstevel@tonic-gate void db_free_list::init() {
1150*0Sstevel@tonic-gate 	WRITELOCKV(this, "w db_free_list::init");
1151*0Sstevel@tonic-gate 	head = NULL;
1152*0Sstevel@tonic-gate 	count = 0;
1153*0Sstevel@tonic-gate 	WRITEUNLOCKV(this, "wu db_free_list::init");
1154*0Sstevel@tonic-gate }
1155