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