BEWARE: the backend will be compiled.
the backend will NOT be invoked, yet.
the backend CANNOT be invoked, yet, because it is NOT yet
integrated into the new initialization/startup environment
of the slapd server.
--- /dev/null
+XSRCS = version.c
+SRCS = idl.c add.c search.c cache.c dbcache.c dn2id.c id2entry.c \
+ index.c id2children.c nextid.c abandon.c compare.c group.c \
+ modify.c modrdn.c delete.c init.c config.c bind.c attr.c \
+ filterindex.c unbind.c kerberos.c close.c alias.c startup.c \
+ timing.c porter.c txn.c
+OBJS = idl.o add.o search.o cache.o dbcache.o dn2id.o id2entry.o \
+ index.o id2children.o nextid.o abandon.o compare.o group.o \
+ modify.o modrdn.o delete.o init.o config.o bind.o attr.o \
+ filterindex.o unbind.o kerberos.o close.o alias.o startup.o \
+ timing.o porter.o txn.o
+
+LDAP_INCDIR= ../../../include
+LDAP_LIBDIR= ../../../libraries
+
+BUILD_OPT = "--enable-bdb2"
+BUILD_SRV = @BUILD_BDB2@
+
+XINCPATH = -I.. -I$(srcdir)/..
+
+PROGRAMS = libback-bdb2.a
+
+all-local-srv: FORCE
+ $(MAKE) $(MFLAGS) libback-bdb2.a
+
+libback-bdb2.a: version.o
+ $(AR) ruv $@ $(OBJS) version.o
+ @$(RANLIB) $@
+ @touch ../.backend
+
+version.c: $(OBJS) $(LDAP_LIBDEPEND)
+ $(RM) $@
+ (u=$${USER-root} v=`$(CAT) $(VERSIONFILE)` d=`$(PWD)` \
+ h=`$(HOSTNAME)` t=`$(DATE)`; \
+ $(SED) -e "s|%WHEN%|$${t}|" \
+ -e "s|%WHOANDWHERE%|$${u}@$${h}:$${d}|" \
+ -e "s|%VERSION%|$${v}|" \
+ < $(srcdir)/Version.c > $@)
--- /dev/null
+/*
+ * Copyright (c) 1995 Regents of the University of Michigan.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that this notice is preserved and that due credit is given
+ * to the University of Michigan at Ann Arbor. The name of the University
+ * may not be used to endorse or promote products derived from this
+ * software without specific prior written permission. This software
+ * is provided ``as is'' without express or implied warranty.
+ */
+
+static char Versionstr[] = " bdb2 backend %VERSION% (%WHEN%)\n\t%WHOANDWHERE%\n";
--- /dev/null
+/* abandon.c - ldbm backend abandon routine */
+
+#include "portable.h"
+
+#include <stdio.h>
+#include <sys/time.h>
+#include <unistd.h>
+
+#include <ac/string.h>
+
+#include "slap.h"
+#include "back-bdb2.h"
+
+
+/*ARGSUSED*/
+static int
+bdb2i_back_abandon_internal(
+ Backend *be,
+ Connection *c,
+ Operation *o,
+ int msgid )
+{
+ return 0;
+}
+
+
+int
+bdb2_back_abandon(
+ Backend *be,
+ Connection *c,
+ Operation *o,
+ int msgid )
+{
+ struct timeval time1, time2;
+ char *elapsed_time;
+ int ret;
+
+ gettimeofday( &time1, NULL );
+
+ ret = bdb2i_back_abandon_internal( be, c, o, msgid );
+
+ if ( bdb2i_do_timing ) {
+
+ gettimeofday( &time2, NULL);
+ elapsed_time = bdb2i_elapsed( time1, time2 );
+ Debug( LDAP_DEBUG_ANY, "ABND elapsed=%s\n",
+ elapsed_time, 0, 0 );
+ free( elapsed_time );
+
+ }
+
+ return( ret );
+}
+
+
--- /dev/null
+/* add.c - ldap bdb2 back-end add routine */
+
+#include "portable.h"
+
+#include <stdio.h>
+
+#include <ac/socket.h>
+#include <ac/string.h>
+
+#include "slap.h"
+#include "back-bdb2.h"
+#include "proto-back-bdb2.h"
+
+static int
+bdb2i_back_add_internal(
+ Backend *be,
+ Connection *conn,
+ Operation *op,
+ Entry *e
+)
+{
+ struct ldbminfo *li = (struct ldbminfo *) be->be_private;
+ char *pdn;
+ Entry *p = NULL;
+ int rootlock = 0;
+ int rc = -1;
+
+ Debug(LDAP_DEBUG_ARGS, "==> bdb2i_back_add: %s\n", e->e_dn, 0, 0);
+
+ /* nobody else can add until we lock our parent */
+ ldap_pvt_thread_mutex_lock(&li->li_add_mutex);
+
+ if ( ( bdb2i_dn2id( be, e->e_ndn ) ) != NOID ) {
+ ldap_pvt_thread_mutex_unlock(&li->li_add_mutex);
+ entry_free( e );
+ send_ldap_result( conn, op, LDAP_ALREADY_EXISTS, "", "" );
+ return( -1 );
+ }
+
+ if ( global_schemacheck && oc_schema_check( e ) != 0 ) {
+ ldap_pvt_thread_mutex_unlock(&li->li_add_mutex);
+
+ Debug( LDAP_DEBUG_TRACE, "entry failed schema check\n",
+ 0, 0, 0 );
+
+ entry_free( e );
+ send_ldap_result( conn, op, LDAP_OBJECT_CLASS_VIOLATION, "",
+ "" );
+ return( -1 );
+ }
+
+ /*
+ * Get the parent dn and see if the corresponding entry exists.
+ * If the parent does not exist, only allow the "root" user to
+ * add the entry.
+ */
+
+ if ( (pdn = dn_parent( be, e->e_ndn )) != NULL ) {
+ char *matched = NULL;
+
+ /* get parent with writer lock */
+ if ( (p = bdb2i_dn2entry_w( be, pdn, &matched )) == NULL ) {
+ ldap_pvt_thread_mutex_unlock(&li->li_add_mutex);
+ Debug( LDAP_DEBUG_TRACE, "parent does not exist\n", 0,
+ 0, 0 );
+ send_ldap_result( conn, op, LDAP_NO_SUCH_OBJECT,
+ matched, "" );
+
+ if ( matched != NULL ) {
+ free( matched );
+ }
+
+ entry_free( e );
+ free( pdn );
+ return -1;
+ }
+
+ /* don't need the add lock anymore */
+ ldap_pvt_thread_mutex_unlock(&li->li_add_mutex);
+
+ free(pdn);
+
+ if ( matched != NULL ) {
+ free( matched );
+ }
+
+ if ( ! access_allowed( be, conn, op, p,
+ "children", NULL, ACL_WRITE ) )
+ {
+ Debug( LDAP_DEBUG_TRACE, "no access to parent\n", 0,
+ 0, 0 );
+ send_ldap_result( conn, op, LDAP_INSUFFICIENT_ACCESS,
+ "", "" );
+
+ /* free parent and writer lock */
+ bdb2i_cache_return_entry_w( &li->li_cache, p );
+
+ entry_free( e );
+ return -1;
+ }
+
+ } else {
+ /* no parent, must be adding entry to root */
+ if ( ! be_isroot( be, op->o_ndn ) ) {
+ ldap_pvt_thread_mutex_unlock(&li->li_add_mutex);
+ Debug( LDAP_DEBUG_TRACE, "no parent & not root\n", 0,
+ 0, 0 );
+ send_ldap_result( conn, op, LDAP_INSUFFICIENT_ACCESS,
+ "", "" );
+
+ entry_free( e );
+ return -1;
+ }
+
+ /*
+ * no parent, acquire the root write lock
+ * and release the add lock.
+ */
+ ldap_pvt_thread_mutex_lock(&li->li_root_mutex);
+ rootlock = 1;
+ ldap_pvt_thread_mutex_unlock(&li->li_add_mutex);
+ }
+
+ /* acquire required reader/writer lock */
+ if (entry_rdwr_lock(e, 1)) {
+ if( p != NULL) {
+ /* free parent and writer lock */
+ bdb2i_cache_return_entry_w( &li->li_cache, p );
+ }
+
+ if ( rootlock ) {
+ /* release root lock */
+ ldap_pvt_thread_mutex_unlock(&li->li_root_mutex);
+ }
+
+ Debug( LDAP_DEBUG_ANY, "add: could not lock entry\n",
+ 0, 0, 0 );
+
+ entry_free(e);
+
+ send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR, "", "" );
+ return( -1 );
+ }
+
+ e->e_id = bdb2i_next_id( be );
+
+ /*
+ * Try to add the entry to the cache, assign it a new dnid
+ * This should only fail if the entry already exists.
+ */
+
+ if ( bdb2i_cache_add_entry_lock( &li->li_cache, e, ENTRY_STATE_CREATING )
+ != 0 ) {
+ if( p != NULL) {
+ /* free parent and writer lock */
+ bdb2i_cache_return_entry_w( &li->li_cache, p );
+ }
+ if ( rootlock ) {
+ /* release root lock */
+ ldap_pvt_thread_mutex_unlock(&li->li_root_mutex);
+ }
+
+ Debug( LDAP_DEBUG_ANY, "cache_add_entry_lock failed\n", 0, 0,
+ 0 );
+ bdb2i_next_id_return( be, e->e_id );
+
+ entry_rdwr_unlock(e, 1);
+ entry_free( e );
+
+ send_ldap_result( conn, op, LDAP_ALREADY_EXISTS, "", "" );
+ return( -1 );
+ }
+
+ /*
+ * add it to the id2children index for the parent
+ */
+
+ if ( bdb2i_id2children_add( be, p, e ) != 0 ) {
+ Debug( LDAP_DEBUG_TRACE, "bdb2i_id2children_add failed\n", 0,
+ 0, 0 );
+ send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR, "", "" );
+
+ goto return_results;
+ }
+
+ /*
+ * Add the entry to the attribute indexes, then add it to
+ * the id2children index, dn2id index, and the id2entry index.
+ */
+
+ /* attribute indexes */
+ if ( bdb2i_index_add_entry( be, e ) != 0 ) {
+ Debug( LDAP_DEBUG_TRACE, "bdb2i_index_add_entry failed\n", 0,
+ 0, 0 );
+ send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR, "", "" );
+
+ goto return_results;
+ }
+
+ /* dn2id index */
+ if ( bdb2i_dn2id_add( be, e->e_ndn, e->e_id ) != 0 ) {
+ Debug( LDAP_DEBUG_TRACE, "bdb2i_dn2id_add failed\n", 0,
+ 0, 0 );
+ send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR, "", "" );
+
+ goto return_results;
+ }
+
+ /* id2entry index */
+ if ( bdb2i_id2entry_add( be, e ) != 0 ) {
+ Debug( LDAP_DEBUG_TRACE, "bdb2i_id2entry_add failed\n", 0,
+ 0, 0 );
+ (void) bdb2i_dn2id_delete( be, e->e_ndn );
+ send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR, "", "" );
+
+ goto return_results;
+ }
+
+ send_ldap_result( conn, op, LDAP_SUCCESS, "", "" );
+ rc = 0;
+
+return_results:;
+ if (p != NULL) {
+ /* free parent and writer lock */
+ bdb2i_cache_return_entry_w( &li->li_cache, p );
+
+ }
+
+ if ( rootlock ) {
+ /* release root lock */
+ ldap_pvt_thread_mutex_unlock(&li->li_root_mutex);
+ }
+
+ bdb2i_cache_set_state( &li->li_cache, e, 0 );
+
+ /* free entry and writer lock */
+ bdb2i_cache_return_entry_w( &li->li_cache, e );
+
+ return( rc );
+}
+
+
+int
+bdb2_back_add(
+ Backend *be,
+ Connection *conn,
+ Operation *op,
+ Entry *e
+)
+{
+ DB_LOCK lock;
+ struct ldbminfo *li = (struct ldbminfo *) be->be_private;
+
+ struct timeval time1, time2;
+ char *elapsed_time;
+ int ret;
+
+ gettimeofday( &time1, NULL );
+
+ if ( bdb2i_enter_backend_w( &li->li_db_env, &lock ) != 0 ) {
+
+ send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR, "", "" );
+ return( -1 );
+
+ }
+
+ /* check, if a new default attribute index will be created,
+ in which case we have to open the index file BEFORE TP */
+ if ( bdb2i_with_dbenv )
+ bdb2i_check_default_attr_index_add( li, e );
+
+ ret = bdb2i_back_add_internal( be, conn, op, e );
+
+ (void) bdb2i_leave_backend( &li->li_db_env, lock );
+
+ if ( bdb2i_do_timing ) {
+
+ gettimeofday( &time2, NULL);
+ elapsed_time = bdb2i_elapsed( time1, time2 );
+ Debug( LDAP_DEBUG_ANY, "conn=%d op=%d ADD elapsed=%s\n",
+ conn->c_connid, op->o_opid, elapsed_time );
+ free( elapsed_time );
+
+ }
+
+ return( ret );
+}
+
+
--- /dev/null
+/*
+ * Copyright (c) 1998 Will Ballantyne, ITSD, Government of BC
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that this notice is preserved and that due credit is given
+ * to ITSD, Government of BC. The name of ITSD
+ * may not be used to endorse or promote products derived from this
+ * software without specific prior written permission. This software
+ * is provided ``as is'' without express or implied warranty.
+ */
+
+#include "portable.h"
+
+#include <stdio.h>
+#include <string.h>
+#include <ac/socket.h> /* Get struct sockaddr for slap.h */
+#include "slap.h"
+#include "back-bdb2.h"
+#include "proto-back-bdb2.h"
+
+/*
+ * given an alias object, dereference it to its end point.
+ * Entry returned has reader lock or is NULL. Starting entry is not released.
+ */
+Entry *bdb2i_derefAlias_r ( Backend *be,
+ Connection *conn,
+ Operation *op,
+ Entry *e)
+{
+ /* to free cache entries */
+ struct ldbminfo *li = (struct ldbminfo *) be->be_private;
+ Attribute *a;
+ int depth;
+ char **pastAliases;
+ char *matched;
+ Entry *origDN = e;
+
+ if (!e) return NULL; /* be sure we have a starting entry */
+
+ Debug( LDAP_DEBUG_TRACE, "<= checking for alias for dn %s\n", e->e_dn, 0, 0 );
+
+ /*
+ * try to deref fully, up to a maximum depth. If the max depth exceeded
+ * then send an error
+ */
+ for ( depth = 0;
+ ( ( a = attr_find( e->e_attrs, "aliasedobjectname" ) ) != NULL) &&
+ ( depth < be->be_maxDerefDepth );
+ ++depth)
+ {
+
+ /*
+ * make sure there is a defined aliasedobjectname.
+ * can only have one value so just use first value (0) in the attr list.
+ */
+ if (a->a_vals[0] && a->a_vals[0]->bv_val) {
+ char *newDN, *oldDN;
+
+ Debug( LDAP_DEBUG_TRACE, "<= %s is an alias for %s\n",
+ e->e_dn, a->a_vals[0]->bv_val, 0 );
+ newDN = ch_strdup (a->a_vals[0]->bv_val);
+ oldDN = ch_strdup (e->e_ndn);
+
+ /*
+ * release past lock if not original
+ */
+ if ( (depth > 0) && e ) {
+ bdb2i_cache_return_entry_r(&li->li_cache, e);
+ }
+
+ /* make sure new and old DN are not same to avoid loops */
+ dn_normalize_case (newDN);
+ if ( strcmp (newDN, oldDN) == 0 ) {
+
+ Debug( LDAP_DEBUG_TRACE,
+ "<= %s alias is same as current %s\n",
+ oldDN, newDN, 0 );
+ send_ldap_result( conn, op, LDAP_ALIAS_PROBLEM, "",
+ "Circular alias" );
+ free (newDN);
+ free (oldDN);
+ break;
+ }
+
+ /* make sure new and original are not same to avoid deadlocks */
+ if ( strcmp (newDN, origDN->e_ndn) == 0 ) {
+ Debug( LDAP_DEBUG_TRACE,
+ "<= %s alias is same as original %s\n",
+ oldDN, origDN->e_ndn, 0 );
+ send_ldap_result( conn, op, LDAP_ALIAS_PROBLEM, "",
+ "Circular alias" );
+ free (newDN);
+ free (oldDN);
+ break;
+ }
+
+ /*
+ * ok, so what happens if there is an alias in the DN of a dereferenced
+ * alias object?
+ */
+ if ( (e = bdb2i_dn2entry_r( be, newDN, &matched )) == NULL ) {
+
+ /* could not deref return error */
+ Debug( LDAP_DEBUG_TRACE,
+ "<= %s is a dangling alias to %s\n",
+ oldDN, newDN, 0 );
+ send_ldap_result( conn, op, LDAP_ALIAS_DEREF_PROBLEM, "",
+ "Dangling Alias" );
+
+ if(matched != NULL) free(matched);
+ free (newDN);
+ free (oldDN);
+ break;
+ }
+
+ free (newDN);
+ free (oldDN);
+ }
+ else {
+ /*
+ * there was an aliasedobjectname defined but no data.
+ * this can't happen, right?
+ */
+ Debug( LDAP_DEBUG_TRACE,
+ "<= %s has no data in aliasedobjectname attribute\n",
+ (e && e->e_dn) ? e->e_dn : "(null)", 0, 0 );
+ send_ldap_result( conn, op, LDAP_ALIAS_PROBLEM, "",
+ "Alias missing aliasedobjectname" );
+ break;
+ }
+ }
+
+ /*
+ * warn if we pulled out due to exceeding the maximum deref depth
+ */
+ if ( depth >= be->be_maxDerefDepth ) {
+ Debug( LDAP_DEBUG_TRACE,
+ "<= deref(\"%s\") exceeded maximum deref depth (%d) at \"%s\"\n",
+ origDN->e_dn ? origDN->e_dn : "(null)",
+ be->be_maxDerefDepth,
+ (e && e->e_ndn) ? e->e_ndn : "(null)");
+ send_ldap_result( conn, op, LDAP_ALIAS_DEREF_PROBLEM, "",
+ "Maximum alias dereference depth exceeded" );
+ }
+
+ return e;
+}
+
+/*
+ * given a DN fully deref it and return the real DN or original DN if it fails
+ * This involves finding the last matched part then reconstructing forward
+ * e.g.
+ * ou=MyOU,o=MyAliasedOrg,c=MyCountry where o=MyAliasedOrg is an alias for o=MyOrg
+ * loop starts with newDN = ou=MyOU,o=MyAliasedOrg,c=MyCountry
+ * dn2entry_r on newDN gives null entry and o=MyAliasedOrg,c=MyCountry matched
+ * dn2entry_r on matched gives o=MyAliasedOrg,c=MyCountry entry
+ * remainder is ou=MyOU
+ * dereferencing o=MyAliasedOrg,c=MyCountry yields entry o=MyOrg,c=MyCountry
+ * release lock on o=MyAliasedOrg,c=MyCountry entry
+ * reconstructed dn is ou=MyOU,o=MyOrg,c=MyCountry
+ * release lock on o=MyOrg,c=MyCountry entry
+ */
+char *bdb2i_derefDN ( Backend *be,
+ Connection *conn,
+ Operation *op,
+ char *dn
+)
+{
+ struct ldbminfo *li = (struct ldbminfo *) be->be_private;
+ char *matched = 0;
+ char *newDN = NULL;
+ int depth, i;
+ Entry *eMatched;
+ Entry *eDeref;
+ Entry *eNew;
+
+ if (!dn) return NULL;
+
+ Debug( LDAP_DEBUG_TRACE,
+ "<= dereferencing dn: \"%s\"\n",
+ dn, 0, 0 );
+
+ newDN = ch_strdup ( dn );
+
+ /* while we don't have a matched dn, deref the DN */
+ for ( depth = 0;
+ ( (eMatched = bdb2i_dn2entry_r( be, newDN, &matched )) == NULL) &&
+ (depth < be->be_maxDerefDepth);
+ ++depth ) {
+
+ if ((matched != NULL) && *matched) {
+ char *submatch;
+
+ /*
+ * make sure there actually is an entry for the matched part
+ */
+ if ( (eMatched = bdb2i_dn2entry_r( be, matched, &submatch )) != NULL) {
+ char *remainder; /* part before the aliased part */
+ int rlen = strlen(newDN) - strlen(matched);
+
+ Debug( LDAP_DEBUG_TRACE, "<= matched %s\n", matched, 0, 0 );
+
+ remainder = ch_malloc (rlen + 1);
+ strncpy ( remainder, newDN, rlen );
+ remainder[rlen] = '\0';
+
+ Debug( LDAP_DEBUG_TRACE, "<= remainder %s\n", remainder, 0, 0 );
+
+ if ((eNew = bdb2i_derefAlias_r( be, conn, op, eMatched )) == NULL) {
+ free (matched);
+ matched = NULL;
+ free (newDN);
+ newDN = NULL;
+ free (remainder);
+ remainder = NULL;
+
+ bdb2i_cache_return_entry_r(&li->li_cache, eMatched);
+ eMatched = NULL;
+ break; /* no associated entry, dont deref */
+ }
+ else {
+
+ Debug( LDAP_DEBUG_TRACE, "<= l&g we have %s vs %s \n", matched, eNew->e_dn, 0 );
+
+ i = strcasecmp (matched, eNew->e_dn);
+ /* free reader lock */
+ bdb2i_cache_return_entry_r(&li->li_cache, eNew);
+
+ free (matched);
+ matched = NULL;
+
+ if (! i) {
+ /* newDN same as old so not an alias, no need to go further */
+ free (newDN);
+ newDN = NULL;
+ free (remainder);
+
+ bdb2i_cache_return_entry_r(&li->li_cache, eMatched);
+ eMatched = NULL;
+ break;
+ }
+
+ /*
+ * we have dereferenced the aliased part so put
+ * the new dn together
+ */
+ free (newDN);
+ newDN = ch_malloc (strlen(eMatched->e_dn) + rlen + 1);
+ strcpy (newDN, remainder);
+ strcat (newDN, eMatched->e_dn);
+ Debug( LDAP_DEBUG_TRACE, "<= expanded to %s\n", newDN, 0, 0 );
+
+ free (remainder);
+ }
+ /* free reader lock */
+ bdb2i_cache_return_entry_r(&li->li_cache, eMatched);
+ }
+ else {
+ if(submatch != NULL) free(submatch);
+ break; /* there was no entry for the matched part */
+ }
+ }
+ else {
+ break; /* there was no matched part */
+ }
+ }
+
+ /* release lock if a match terminated the loop, there should be no
+ * outstanding locks at this point
+ */
+ if(eMatched != NULL) {
+ /* free reader lock */
+ bdb2i_cache_return_entry_r(&li->li_cache, eMatched);
+ }
+
+ /*
+ * the final part of the DN might be an alias so try to dereference it.
+ * e.g. if we had started with dn = o=MyAliasedOrg,c=MyCountry the dn would match
+ * and the above loop complete but we would still be left with an aliased DN.
+ */
+ if ( (eNew = bdb2i_dn2entry_r( be, newDN, &matched )) != NULL) {
+ if ((eDeref = bdb2i_derefAlias_r( be, conn, op, eNew )) != NULL) {
+ free (newDN);
+ newDN = ch_strdup (eDeref->e_dn);
+ /* free reader lock */
+ bdb2i_cache_return_entry_r(&li->li_cache, eDeref);
+ }
+ /* free reader lock */
+ bdb2i_cache_return_entry_r(&li->li_cache, eNew);
+ }
+ if (matched != NULL) free(matched);
+
+ /*
+ * warn if we exceeded the max depth as the resulting DN may not be dereferenced
+ */
+ if (depth >= be->be_maxDerefDepth) {
+ if (newDN) {
+ Debug( LDAP_DEBUG_TRACE,
+ "<= max deref depth exceeded in derefDN for \"%s\", result \"%s\"\n",
+ dn, newDN, 0 );
+ free (newDN);
+ newDN = NULL;
+ } else {
+ Debug( LDAP_DEBUG_TRACE,
+ "<= max deref depth exceeded in derefDN for \"%s\", result NULL\n",
+ dn, 0, 0 );
+ }
+ send_ldap_result( conn, op, LDAP_ALIAS_DEREF_PROBLEM, "",
+ "Maximum alias dereference depth exceeded for base" );
+ }
+
+ if (newDN == NULL) {
+ newDN = ch_strdup ( dn );
+ }
+
+ Debug( LDAP_DEBUG_TRACE, "<= returning deref DN of \"%s\"\n", newDN, 0, 0 );
+
+ return newDN;
+}
--- /dev/null
+/* attr.c - backend routines for dealing with attributes */
+
+#include "portable.h"
+
+#include <stdio.h>
+
+#include <ac/socket.h>
+#include <ac/string.h>
+
+#include "slap.h"
+#include "back-bdb2.h"
+
+static int
+ainfo_type_cmp(
+ char *type,
+ struct attrinfo *a
+)
+{
+ return( strcasecmp( type, a->ai_type ) );
+}
+
+static int
+ainfo_cmp(
+ struct attrinfo *a,
+ struct attrinfo *b
+)
+{
+ return( strcasecmp( a->ai_type, b->ai_type ) );
+}
+
+/*
+ * Called when a duplicate "index" line is encountered.
+ *
+ * returns 1 => original from init code, indexmask updated
+ * 2 => original not from init code, warn the user
+ */
+
+static int
+ainfo_dup(
+ struct attrinfo *a,
+ struct attrinfo *b
+)
+{
+ /*
+ * if the duplicate definition is because we initialized the attr,
+ * just add what came from the config file. otherwise, complain.
+ */
+ if ( a->ai_indexmask & INDEX_FROMINIT ) {
+ a->ai_indexmask |= b->ai_indexmask;
+
+ return( 1 );
+ }
+
+ return( 2 );
+}
+
+void
+bdb2i_attr_masks(
+ struct ldbminfo *li,
+ char *type,
+ int *indexmask,
+ int *syntaxmask
+)
+{
+ struct attrinfo *a;
+
+ *indexmask = 0;
+ *syntaxmask = 0;
+ if ( (a = (struct attrinfo *) avl_find( li->li_attrs, type,
+ ainfo_type_cmp )) == NULL ) {
+ if ( (a = (struct attrinfo *) avl_find( li->li_attrs, "default",
+ ainfo_type_cmp )) == NULL ) {
+ return;
+ }
+ }
+ *indexmask = a->ai_indexmask;
+ if ( strcasecmp( a->ai_type, "default" ) == 0 ) {
+ *syntaxmask = attr_syntax( type );
+ } else {
+ *syntaxmask = a->ai_syntaxmask;
+ }
+}
+
+
+/* BDB2 changed */
+void
+bdb2i_attr_index_config(
+ struct ldbminfo *li,
+ char *fname,
+ int lineno,
+ int argc,
+ char **argv,
+ int init
+)
+{
+ int i, j;
+ char **attrs, **indexes;
+ struct attrinfo *a;
+
+ attrs = str2charray( argv[0], "," );
+ if ( argc > 1 ) {
+ indexes = str2charray( argv[1], "," );
+ }
+ for ( i = 0; attrs[i] != NULL; i++ ) {
+ a = (struct attrinfo *) ch_malloc( sizeof(struct attrinfo) );
+ a->ai_type = ch_strdup( attrs[i] );
+ a->ai_syntaxmask = attr_syntax( a->ai_type );
+ if ( argc == 1 ) {
+ a->ai_indexmask = (INDEX_PRESENCE | INDEX_EQUALITY |
+ INDEX_APPROX | INDEX_SUB);
+ } else {
+ a->ai_indexmask = 0;
+ for ( j = 0; indexes[j] != NULL; j++ ) {
+ if ( strncasecmp( indexes[j], "pres", 4 )
+ == 0 ) {
+ a->ai_indexmask |= INDEX_PRESENCE;
+ } else if ( strncasecmp( indexes[j], "eq", 2 )
+ == 0 ) {
+ a->ai_indexmask |= INDEX_EQUALITY;
+ } else if ( strncasecmp( indexes[j], "approx",
+ 6 ) == 0 ) {
+ a->ai_indexmask |= INDEX_APPROX;
+ } else if ( strncasecmp( indexes[j], "sub", 3 )
+ == 0 ) {
+ a->ai_indexmask |= INDEX_SUB;
+ } else if ( strncasecmp( indexes[j], "none", 4 )
+ == 0 ) {
+ if ( a->ai_indexmask != 0 ) {
+ fprintf( stderr,
+"%s: line %d: index type \"none\" cannot be combined with other types\n",
+ fname, lineno );
+ }
+ a->ai_indexmask = 0;
+ } else {
+ fprintf( stderr,
+ "%s: line %d: unknown index type \"%s\" (ignored)\n",
+ fname, lineno, indexes[j] );
+ fprintf( stderr,
+ "valid index types are \"pres\", \"eq\", \"approx\", or \"sub\"\n" );
+ }
+ }
+ }
+ if ( init ) {
+ a->ai_indexmask |= INDEX_FROMINIT;
+ } else {
+ if ( a->ai_indexmask )
+ bdb2i_txn_attr_config( li, a->ai_type, 0 );
+ }
+
+ switch (avl_insert( &li->li_attrs, (caddr_t) a, ainfo_cmp, ainfo_dup )) {
+ case 1: /* duplicate - updating init version */
+ free( a->ai_type );
+ free( (char *) a );
+ break;
+
+ case 2: /* user duplicate - ignore and warn */
+ fprintf( stderr,
+ "%s: line %d: duplicate index definition for attr \"%s\" (ignored)\n",
+ fname, lineno, a->ai_type );
+ free( a->ai_type );
+ free( (char *) a );
+ break;
+
+ default:; /* inserted ok */
+ /* FALL */
+ }
+ }
+ charray_free( attrs );
+ if ( argc > 1 )
+ charray_free( indexes );
+}
--- /dev/null
+/* back-bdb2.h - ldap bdb2 back-end header file */
+
+#ifndef _BACK_BDB2_H_
+#define _BACK_BDB2_H_
+
+#include "ldbm.h"
+#include "db.h"
+
+LDAP_BEGIN_DECL
+
+#define DEFAULT_CACHE_SIZE 1000
+
+/* since DEFAULT_DB_PAGE_SIZE is 1K, we have 128K,
+ which is suggested by Sleepycat */
+#define DEFAULT_DBCACHE_SIZE (128 * DEFAULT_DB_PAGE_SIZE)
+
+#define DEFAULT_DB_DIRECTORY "/usr/tmp"
+#define DEFAULT_MODE 0600
+
+#define SUBLEN 3
+
+/*
+ * there is a single index for each attribute. these prefixes insure
+ * that there is no collision among keys.
+ */
+#define EQ_PREFIX '=' /* prefix for equality keys */
+#define APPROX_PREFIX '~' /* prefix for approx keys */
+#define SUB_PREFIX '*' /* prefix for substring keys */
+#define CONT_PREFIX '\\' /* prefix for continuation keys */
+
+#define UNKNOWN_PREFIX '?' /* prefix for unknown keys */
+
+#define DEFAULT_BLOCKSIZE 8192
+
+/*
+ * This structure represents an id block on disk and an id list
+ * in core.
+ *
+ * The fields have the following meanings:
+ *
+ * b_nmax maximum number of ids in this block. if this is == ALLIDSBLOCK,
+ * then this block represents all ids.
+ * b_nids current number of ids in use in this block. if this
+ * is == INDBLOCK, then this block is an indirect block
+ * containing a list of other blocks containing actual ids.
+ * the list is terminated by an id of NOID.
+ * b_ids a list of the actual ids themselves
+ */
+
+typedef ID ID_BLOCK;
+
+#define ID_BLOCK_NMAX_OFFSET 0
+#define ID_BLOCK_NIDS_OFFSET 1
+#define ID_BLOCK_IDS_OFFSET 2
+
+/* all ID_BLOCK macros operate on a pointer to a ID_BLOCK */
+
+#define ID_BLOCK_NMAX(b) ((b)[ID_BLOCK_NMAX_OFFSET])
+#define ID_BLOCK_NIDS(b) ((b)[ID_BLOCK_NIDS_OFFSET])
+#define ID_BLOCK_ID(b, n) ((b)[ID_BLOCK_IDS_OFFSET+(n)])
+
+#define ID_BLOCK_NOID(b, n) (ID_BLOCK_ID((b),(n)) == NOID)
+
+#define ID_BLOCK_ALLIDS_VALUE 0
+#define ID_BLOCK_ALLIDS(b) (ID_BLOCK_NMAX(b) == ID_BLOCK_ALLIDS_VALUE)
+
+#define ID_BLOCK_INDIRECT_VALUE 0
+#define ID_BLOCK_INDIRECT(b) (ID_BLOCK_NIDS(b) == ID_BLOCK_INDIRECT_VALUE)
+
+/* for the in-core cache of entries */
+struct cache {
+ int c_maxsize;
+ int c_cursize;
+ Avlnode *c_dntree;
+ Avlnode *c_idtree;
+ Entry *c_lruhead; /* lru - add accessed entries here */
+ Entry *c_lrutail; /* lru - rem lru entries from here */
+ ldap_pvt_thread_mutex_t c_mutex;
+};
+
+/* for the cache of open index files (re-used for txn) */
+struct dbcache {
+ int dbc_refcnt;
+ int dbc_maxids;
+ int dbc_maxindirect;
+ time_t dbc_lastref;
+ long dbc_blksize;
+ char *dbc_name;
+ LDBM dbc_db;
+
+ struct dbcache *next;
+};
+
+typedef struct dbcache BDB2_TXN_FILES;
+
+
+/* for the cache of attribute information (which are indexed, etc.) */
+struct attrinfo {
+ char *ai_type; /* type name (cn, sn, ...) */
+ int ai_indexmask; /* how the attr is indexed */
+#define INDEX_PRESENCE 0x01
+#define INDEX_EQUALITY 0x02
+#define INDEX_APPROX 0x04
+#define INDEX_SUB 0x08
+#define INDEX_UNKNOWN 0x10
+#define INDEX_FROMINIT 0x20
+ int ai_syntaxmask; /* what kind of syntax */
+/* ...from slap.h...
+#define SYNTAX_CIS 0x01
+#define SYNTAX_CES 0x02
+#define SYNTAX_BIN 0x04
+ ... etc. ...
+*/
+};
+
+#define MAXDBCACHE 10
+
+/* this could be made an option */
+#ifndef SLAPD_NEXTID_CHUNK
+#define SLAPD_NEXTID_CHUNK 32
+#endif
+
+
+/* TP stuff */
+
+typedef struct _bdb2_txn_head {
+
+ /* counter and timer to control checkpoints */
+ size_t txn_cnt;
+ time_t txn_chkp;
+
+ /* a list of all DB files in use */
+ BDB2_TXN_FILES *dbFiles;
+
+ /* for performance reasons we have pointers to fixed descriptors */
+ BDB2_TXN_FILES *dbFileHandle[4];
+#define BDB2_DB_DN_FILE 0
+#define BDB2_DB_DN2ID_FILE 1
+#define BDB2_DB_ID2ENTRY_FILE 2
+#define BDB2_DB_ID2CHILDREN_FILE 3
+#define BDB2_DB_OC_IDX_FILE 4
+
+ /* is the default attribute index set to non-none */
+ int withDefIDX;
+#define BDB2_WITH_DEF_IDX 1
+
+} BDB2_TXN_HEAD;
+
+
+/* end of TP stuff */
+
+struct ldbminfo {
+ ID li_nextid;
+#if SLAPD_NEXTID_CHUNK > 1
+ ID li_nextid_wrote;
+#endif
+ char *li_nextid_file;
+ ldap_pvt_thread_mutex_t li_root_mutex;
+ ldap_pvt_thread_mutex_t li_add_mutex;
+ ldap_pvt_thread_mutex_t li_nextid_mutex;
+ int li_mode;
+ char *li_directory;
+ struct cache li_cache;
+ Avlnode *li_attrs;
+ int li_dbcachesize;
+ int li_dbcachewsync;
+ struct dbcache li_dbcache[MAXDBCACHE];
+ ldap_pvt_thread_mutex_t li_dbcache_mutex;
+ ldap_pvt_thread_cond_t li_dbcache_cv;
+
+ /* Berkeley DB2 Environment */
+ DB_ENV li_db_env;
+ char *li_dbhome;
+ BDB2_TXN_HEAD li_txn_head;
+
+};
+
+
+extern int bdb2i_with_dbenv;
+
+#include "proto-back-bdb2.h"
+
+LDAP_END_DECL
+
+#endif /* _back_bdb2_h_ */
--- /dev/null
+/* bind.c - bdb2 backend bind and unbind routines */
+
+#include "portable.h"
+
+#include <stdio.h>
+
+#include <ac/krb.h>
+#include <ac/socket.h>
+#include <ac/string.h>
+#include <ac/unistd.h>
+
+#include "slap.h"
+#include "back-bdb2.h"
+#include "proto-back-bdb2.h"
+
+#include <lutil.h>
+
+#ifdef HAVE_KERBEROS
+extern int bdb2i_krbv4_ldap_auth();
+#endif
+
+static int
+crypted_value_find(
+ struct berval **vals,
+ struct berval *v,
+ int syntax,
+ int normalize,
+ struct berval *cred
+)
+{
+ int i;
+ for ( i = 0; vals[i] != NULL; i++ ) {
+ if ( syntax != SYNTAX_BIN ) {
+ int result;
+
+#ifdef SLAPD_CRYPT
+ ldap_pvt_thread_mutex_lock( &crypt_mutex );
+#endif
+
+ result = lutil_passwd(
+ (char*) cred->bv_val,
+ (char*) vals[i]->bv_val);
+
+#ifdef SLAPD_CRYPT
+ ldap_pvt_thread_mutex_unlock( &crypt_mutex );
+#endif
+
+ return result;
+
+ } else {
+ if ( value_cmp( vals[i], v, syntax, normalize ) == 0 ) {
+ return( 0 );
+ }
+ }
+ }
+
+ return( 1 );
+}
+
+static int
+bdb2i_back_bind_internal(
+ Backend *be,
+ Connection *conn,
+ Operation *op,
+ char *dn,
+ int method,
+ struct berval *cred,
+ char** edn
+)
+{
+ struct ldbminfo *li = (struct ldbminfo *) be->be_private;
+ Entry *e;
+ Attribute *a;
+ int rc;
+ char *matched;
+#ifdef HAVE_KERBEROS
+ char krbname[MAX_K_NAME_SZ + 1];
+ AUTH_DAT ad;
+#endif
+
+ Debug(LDAP_DEBUG_ARGS, "==> bdb2_back_bind: dn: %s\n", dn, 0, 0);
+
+ *edn = NULL;
+
+ /* get entry with reader lock */
+ if ( (e = bdb2i_dn2entry_r( be, dn, &matched )) == NULL ) {
+ /* allow noauth binds */
+ if ( method == LDAP_AUTH_SIMPLE && cred->bv_len == 0 ) {
+ /*
+ * bind successful, but return 1 so we don't
+ * authorize based on noauth credentials
+ */
+ send_ldap_result( conn, op, LDAP_SUCCESS, NULL, NULL );
+ rc = 1;
+ } else if ( be_isroot_pw( be, dn, cred ) ) {
+ /* front end will send result */
+ *edn = ch_strdup( be_root_dn( be ) );
+ rc = 0;
+ } else {
+ send_ldap_result( conn, op, LDAP_NO_SUCH_OBJECT, matched, NULL );
+ rc = 1;
+ }
+ if ( matched != NULL ) {
+ free( matched );
+ }
+ return( rc );
+ }
+
+ *edn = ch_strdup( e->e_dn );
+
+ /* check for deleted */
+
+ switch ( method ) {
+ case LDAP_AUTH_SIMPLE:
+ if ( cred->bv_len == 0 ) {
+ send_ldap_result( conn, op, LDAP_SUCCESS, NULL, NULL );
+
+ /* stop front end from sending result */
+ rc = 1;
+ goto return_results;
+ } else if ( be_isroot_pw( be, dn, cred ) ) {
+ /* front end will send result */
+ *edn = ch_strdup( be_root_dn( be ) );
+ rc = 0;
+ goto return_results;
+ }
+
+ if ( (a = attr_find( e->e_attrs, "userpassword" )) == NULL ) {
+ if ( be_isroot_pw( be, dn, cred ) ) {
+ /* front end will send result */
+ *edn = ch_strdup( be_root_dn( be ) );
+ rc = 0;
+ goto return_results;
+ }
+ send_ldap_result( conn, op, LDAP_INAPPROPRIATE_AUTH,
+ NULL, NULL );
+ rc = 1;
+ goto return_results;
+ }
+
+ if ( crypted_value_find( a->a_vals, cred, a->a_syntax, 0, cred ) != 0 )
+ {
+ if ( be_isroot_pw( be, dn, cred ) ) {
+ /* front end will send result */
+ *edn = ch_strdup( be_root_dn( be ) );
+ rc = 0;
+ goto return_results;
+ }
+ send_ldap_result( conn, op, LDAP_INVALID_CREDENTIALS,
+ NULL, NULL );
+ rc = 1;
+ goto return_results;
+ }
+ rc = 0;
+ break;
+
+#ifdef HAVE_KERBEROS
+ case LDAP_AUTH_KRBV41:
+ if ( bdb2i_krbv4_ldap_auth( be, cred, &ad ) != LDAP_SUCCESS ) {
+ send_ldap_result( conn, op, LDAP_INVALID_CREDENTIALS,
+ NULL, NULL );
+ rc = 0;
+ goto return_results;
+ }
+ sprintf( krbname, "%s%s%s@%s", ad.pname, *ad.pinst ? "."
+ : "", ad.pinst, ad.prealm );
+ if ( (a = attr_find( e->e_attrs, "krbname" )) == NULL ) {
+ /*
+ * no krbName values present: check against DN
+ */
+ if ( strcasecmp( dn, krbname ) == 0 ) {
+ rc = 0; /* XXX wild ass guess */
+ break;
+ }
+ send_ldap_result( conn, op, LDAP_INAPPROPRIATE_AUTH,
+ NULL, NULL );
+ rc = 1;
+ goto return_results;
+ } else { /* look for krbName match */
+ struct berval krbval;
+
+ krbval.bv_val = krbname;
+ krbval.bv_len = strlen( krbname );
+
+ if ( value_find( a->a_vals, &krbval, a->a_syntax, 3 ) != 0 ) {
+ send_ldap_result( conn, op,
+ LDAP_INVALID_CREDENTIALS, NULL, NULL );
+ rc = 1;
+ goto return_results;
+ }
+ }
+ rc = 0;
+ break;
+
+ case LDAP_AUTH_KRBV42:
+ send_ldap_result( conn, op, LDAP_SUCCESS, NULL, NULL );
+ /* stop front end from sending result */
+ rc = 1;
+ goto return_results;
+#endif
+
+ default:
+ send_ldap_result( conn, op, LDAP_STRONG_AUTH_NOT_SUPPORTED,
+ NULL, "auth method not supported" );
+ rc = 1;
+ goto return_results;
+ }
+
+return_results:;
+ /* free entry and reader lock */
+ bdb2i_cache_return_entry_r( &li->li_cache, e );
+
+ /* front end with send result on success (rc==0) */
+ return( rc );
+}
+
+
+int
+bdb2_back_bind(
+ Backend *be,
+ Connection *conn,
+ Operation *op,
+ char *dn,
+ int method,
+ struct berval *cred,
+ char** edn
+)
+{
+ DB_LOCK lock;
+ struct ldbminfo *li = (struct ldbminfo *) be->be_private;
+
+ struct timeval time1, time2;
+ char *elapsed_time;
+ int ret;
+
+ gettimeofday( &time1, NULL );
+
+ if ( bdb2i_enter_backend_r( &li->li_db_env, &lock ) != 0 ) {
+
+ send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR, "", "" );
+ return( 1 );
+
+ }
+
+ ret = bdb2i_back_bind_internal( be, conn, op, dn, method, cred, edn );
+
+ (void) bdb2i_leave_backend( &li->li_db_env, lock );
+
+ if ( bdb2i_do_timing ) {
+
+ gettimeofday( &time2, NULL);
+ elapsed_time = bdb2i_elapsed( time1, time2 );
+ Debug( LDAP_DEBUG_ANY, "conn=%d op=%d BIND elapsed=%s\n",
+ conn->c_connid, op->o_opid, elapsed_time );
+ free( elapsed_time );
+
+ }
+
+ return( ret );
+}
+
+
--- /dev/null
+/* cache.c - routines to maintain an in-core cache of entries */
+
+#include "portable.h"
+
+#include <stdio.h>
+
+#include <ac/errno.h>
+#include <ac/string.h>
+#include <ac/socket.h>
+
+#include "slap.h"
+
+#include "back-bdb2.h"
+
+static int cache_delete_entry_internal(struct cache *cache, Entry *e);
+#ifdef LDAP_DEBUG
+static void lru_print(struct cache *cache);
+#endif
+
+/*
+ * the cache has three entry points (ways to find things):
+ *
+ * by entry e.g., if you already have an entry from the cache
+ * and want to delete it. (really by entry ptr)
+ * by dn e.g., when looking for the base object of a search
+ * by id e.g., for search candidates
+ *
+ * these correspond to three different avl trees that are maintained.
+ */
+
+static int
+cache_entry_cmp( Entry *e1, Entry *e2 )
+{
+ return( e1 < e2 ? -1 : (e1 > e2 ? 1 : 0) );
+}
+
+static int
+cache_entrydn_cmp( Entry *e1, Entry *e2 )
+{
+ /* compare their normalized UPPERCASED dn's */
+ return( strcmp( e1->e_ndn, e2->e_ndn ) );
+}
+
+static int
+cache_entryid_cmp( Entry *e1, Entry *e2 )
+{
+ return( e1->e_id < e2->e_id ? -1 : (e1->e_id > e2->e_id ? 1 : 0) );
+}
+
+void
+bdb2i_cache_set_state( struct cache *cache, Entry *e, int state )
+{
+ /* set cache mutex */
+ ldap_pvt_thread_mutex_lock( &cache->c_mutex );
+
+ e->e_state = state;
+
+ /* free cache mutex */
+ ldap_pvt_thread_mutex_unlock( &cache->c_mutex );
+}
+
+#ifdef not_used
+static void
+cache_return_entry( struct cache *cache, Entry *e )
+{
+ /* set cache mutex */
+ ldap_pvt_thread_mutex_lock( &cache->c_mutex );
+
+ if ( --e->e_refcnt == 0 && e->e_state == ENTRY_STATE_DELETED ) {
+ entry_free( e );
+ }
+
+ /* free cache mutex */
+ ldap_pvt_thread_mutex_unlock( &cache->c_mutex );
+}
+#endif
+
+static void
+cache_return_entry_rw( struct cache *cache, Entry *e, int rw )
+{
+ Debug( LDAP_DEBUG_TRACE, "====> cache_return_entry_%s\n",
+ rw ? "w" : "r", 0, 0);
+
+ /* set cache mutex */
+ ldap_pvt_thread_mutex_lock( &cache->c_mutex );
+
+ entry_rdwr_unlock(e, rw);;
+
+ if ( --e->e_refcnt == 0 && e->e_state == ENTRY_STATE_DELETED ) {
+ entry_free( e );
+ }
+
+ /* free cache mutex */
+ ldap_pvt_thread_mutex_unlock( &cache->c_mutex );
+}
+
+void
+bdb2i_cache_return_entry_r( struct cache *cache, Entry *e )
+{
+ cache_return_entry_rw(cache, e, 0);
+}
+
+void
+bdb2i_cache_return_entry_w( struct cache *cache, Entry *e )
+{
+ cache_return_entry_rw(cache, e, 1);
+}
+
+
+#define LRU_DELETE( cache, e ) { \
+ if ( e->e_lruprev != NULL ) { \
+ e->e_lruprev->e_lrunext = e->e_lrunext; \
+ } else { \
+ cache->c_lruhead = e->e_lrunext; \
+ } \
+ if ( e->e_lrunext != NULL ) { \
+ e->e_lrunext->e_lruprev = e->e_lruprev; \
+ } else { \
+ cache->c_lrutail = e->e_lruprev; \
+ } \
+}
+
+#define LRU_ADD( cache, e ) { \
+ e->e_lrunext = cache->c_lruhead; \
+ if ( e->e_lrunext != NULL ) { \
+ e->e_lrunext->e_lruprev = e; \
+ } \
+ cache->c_lruhead = e; \
+ e->e_lruprev = NULL; \
+ if ( cache->c_lrutail == NULL ) { \
+ cache->c_lrutail = e; \
+ } \
+}
+
+/*
+ * cache_create_entry_lock - create an entry in the cache, and lock it.
+ * returns: 0 entry has been created and locked
+ * 1 entry already existed
+ * -1 something bad happened
+ */
+int
+bdb2i_cache_add_entry_lock(
+ struct cache *cache,
+ Entry *e,
+ int state
+)
+{
+ int i, rc;
+ Entry *ee;
+
+ /* set cache mutex */
+ ldap_pvt_thread_mutex_lock( &cache->c_mutex );
+
+ if ( avl_insert( &cache->c_dntree, (caddr_t) e,
+ cache_entrydn_cmp, avl_dup_error ) != 0 )
+ {
+ Debug( LDAP_DEBUG_TRACE,
+ "====> cache_add_entry lock: entry %20s id %lu already in dn cache\n",
+ e->e_dn, e->e_id, 0 );
+
+ /* free cache mutex */
+ ldap_pvt_thread_mutex_unlock( &cache->c_mutex );
+ return( 1 );
+ }
+
+ /* id tree */
+ if ( avl_insert( &cache->c_idtree, (caddr_t) e,
+ cache_entryid_cmp, avl_dup_error ) != 0 )
+ {
+ Debug( LDAP_DEBUG_ANY,
+ "====> entry %20s id %lu already in id cache\n",
+ e->e_dn, e->e_id, 0 );
+
+ /* delete from dn tree inserted above */
+ if ( avl_delete( &cache->c_dntree, (caddr_t) e,
+ cache_entrydn_cmp ) == NULL )
+ {
+ Debug( LDAP_DEBUG_ANY, "====> can't delete from dn cache\n",
+ 0, 0, 0 );
+ }
+
+ /* free cache mutex */
+ ldap_pvt_thread_mutex_unlock( &cache->c_mutex );
+ return( -1 );
+ }
+
+ e->e_state = state;
+ e->e_refcnt = 1;
+
+ /* lru */
+ LRU_ADD( cache, e );
+ if ( ++cache->c_cursize > cache->c_maxsize ) {
+ /*
+ * find the lru entry not currently in use and delete it.
+ * in case a lot of entries are in use, only look at the
+ * first 10 on the tail of the list.
+ */
+ i = 0;
+ while ( cache->c_lrutail != NULL && cache->c_lrutail->e_refcnt
+ != 0 && i < 10 ) {
+ /* move this in-use entry to the front of the q */
+ ee = cache->c_lrutail;
+ LRU_DELETE( cache, ee );
+ LRU_ADD( cache, ee );
+ i++;
+ }
+
+ /*
+ * found at least one to delete - try to get back under
+ * the max cache size.
+ */
+ while ( cache->c_lrutail != NULL && cache->c_lrutail->e_refcnt
+ == 0 && cache->c_cursize > cache->c_maxsize ) {
+ e = cache->c_lrutail;
+
+ /* XXX check for writer lock - should also check no readers pending */
+#ifdef LDAP_DEBUG
+ assert(!ldap_pvt_thread_rdwr_active(&e->e_rdwr));
+#endif
+
+ /* delete from cache and lru q */
+ rc = cache_delete_entry_internal( cache, e );
+
+ entry_free( e );
+ }
+ }
+
+ /* free cache mutex */
+ ldap_pvt_thread_mutex_unlock( &cache->c_mutex );
+ return( 0 );
+}
+
+/*
+ * cache_find_entry_dn2id - find an entry in the cache, given dn
+ */
+
+ID
+bdb2i_cache_find_entry_dn2id(
+ Backend *be,
+ struct cache *cache,
+ char *dn
+)
+{
+ struct ldbminfo *li = (struct ldbminfo *) be->be_private;
+ Entry e, *ep;
+ ID id;
+
+ /* set cache mutex */
+ ldap_pvt_thread_mutex_lock( &cache->c_mutex );
+
+ e.e_dn = dn;
+ e.e_ndn = dn_normalize_case( ch_strdup( dn ) );
+
+ if ( (ep = (Entry *) avl_find( cache->c_dntree, (caddr_t) &e,
+ cache_entrydn_cmp )) != NULL )
+ {
+ /*
+ * ep now points to an unlocked entry
+ * we do not need to lock the entry if we only
+ * check the state, refcnt, LRU, and id.
+ */
+ free(e.e_ndn);
+
+ Debug(LDAP_DEBUG_TRACE, "====> cache_find_entry_dn2id: found dn: %s\n",
+ dn, 0, 0);
+
+ /*
+ * entry is deleted or not fully created yet
+ */
+ if ( ep->e_state == ENTRY_STATE_DELETED ||
+ ep->e_state == ENTRY_STATE_CREATING )
+ {
+ /* free cache mutex */
+ ldap_pvt_thread_mutex_unlock( &cache->c_mutex );
+ return( NOID );
+ }
+
+ /* lru */
+ LRU_DELETE( cache, ep );
+ LRU_ADD( cache, ep );
+
+ /* save id */
+ id = ep->e_id;
+
+ /* free cache mutex */
+ ldap_pvt_thread_mutex_unlock( &cache->c_mutex );
+
+ return( id );
+ }
+
+ free(e.e_ndn);
+
+ /* free cache mutex */
+ ldap_pvt_thread_mutex_unlock( &cache->c_mutex );
+
+ return( NOID );
+}
+
+/*
+ * cache_find_entry_id - find an entry in the cache, given id
+ */
+
+Entry *
+bdb2i_cache_find_entry_id(
+ struct cache *cache,
+ ID id,
+ int rw
+)
+{
+ Entry e;
+ Entry *ep;
+
+ e.e_id = id;
+
+try_again:
+ /* set cache mutex */
+ ldap_pvt_thread_mutex_lock( &cache->c_mutex );
+
+ if ( (ep = (Entry *) avl_find( cache->c_idtree, (caddr_t) &e,
+ cache_entryid_cmp )) != NULL )
+ {
+ Debug(LDAP_DEBUG_TRACE,
+ "====> cache_find_entry_dn2id: found id: %ld rw: %d\n",
+ id, rw, 0);
+
+ /*
+ * entry is deleted or not fully created yet
+ */
+ if ( ep->e_state == ENTRY_STATE_DELETED ||
+ ep->e_state == ENTRY_STATE_CREATING )
+ {
+ /* free cache mutex */
+ ldap_pvt_thread_mutex_unlock( &cache->c_mutex );
+ return( NULL );
+ }
+
+ /* acquire reader lock */
+ if ( entry_rdwr_trylock(ep, rw) == LDAP_PVT_THREAD_EBUSY ) {
+ /* could not acquire entry lock...
+ * owner cannot free as we have the cache locked.
+ * so, unlock the cache, yield, and try again.
+ */
+
+ /* free cache mutex */
+ ldap_pvt_thread_mutex_unlock( &cache->c_mutex );
+ ldap_pvt_thread_yield();
+ goto try_again;
+ }
+
+ /* lru */
+ LRU_DELETE( cache, ep );
+ LRU_ADD( cache, ep );
+
+ ep->e_refcnt++;
+
+ /* free cache mutex */
+ ldap_pvt_thread_mutex_unlock( &cache->c_mutex );
+
+ return( ep );
+ }
+
+ /* free cache mutex */
+ ldap_pvt_thread_mutex_unlock( &cache->c_mutex );
+
+ return( NULL );
+}
+
+/*
+ * cache_delete_entry - delete the entry e from the cache. the caller
+ * should have obtained e (increasing its ref count) via a call to one
+ * of the cache_find_* routines. the caller should *not* call the
+ * cache_return_entry() routine prior to calling cache_delete_entry().
+ * it performs this function.
+ *
+ * returns: 0 e was deleted ok
+ * 1 e was not in the cache
+ * -1 something bad happened
+ */
+int
+bdb2i_cache_delete_entry(
+ struct cache *cache,
+ Entry *e
+)
+{
+ int rc;
+
+ Debug( LDAP_DEBUG_TRACE, "====> cache_delete_entry:\n", 0, 0, 0 );
+
+ /* XXX check for writer lock - should also check no readers pending */
+#ifdef LDAP_DEBUG
+ assert(ldap_pvt_thread_rdwr_writers(&e->e_rdwr));
+#endif
+
+ /* set cache mutex */
+ ldap_pvt_thread_mutex_lock( &cache->c_mutex );
+
+ rc = cache_delete_entry_internal( cache, e );
+
+ /* free cache mutex */
+ ldap_pvt_thread_mutex_unlock( &cache->c_mutex );
+ return( rc );
+}
+
+static int
+cache_delete_entry_internal(
+ struct cache *cache,
+ Entry *e
+)
+{
+ int rc = 0; /* return code */
+
+ /* dn tree */
+ if ( avl_delete( &cache->c_dntree, (caddr_t) e, cache_entrydn_cmp )
+ == NULL )
+ {
+ rc = -1;
+ }
+
+ /* id tree */
+ if ( avl_delete( &cache->c_idtree, (caddr_t) e, cache_entryid_cmp )
+ == NULL )
+ {
+ rc = -1;
+ }
+
+ if (rc != 0) {
+ return rc;
+ }
+
+ /* lru */
+ LRU_DELETE( cache, e );
+ cache->c_cursize--;
+
+ /*
+ * flag entry to be freed later by a call to cache_return_entry()
+ */
+ e->e_state = ENTRY_STATE_DELETED;
+
+ return( 0 );
+}
+
+#ifdef LDAP_DEBUG
+
+static void
+lru_print( struct cache *cache )
+{
+ Entry *e;
+
+ fprintf( stderr, "LRU queue (head to tail):\n" );
+ for ( e = cache->c_lruhead; e != NULL; e = e->e_lrunext ) {
+ fprintf( stderr, "\tdn %20s id %lu refcnt %d\n", e->e_dn,
+ e->e_id, e->e_refcnt );
+ }
+ fprintf( stderr, "LRU queue (tail to head):\n" );
+ for ( e = cache->c_lrutail; e != NULL; e = e->e_lruprev ) {
+ fprintf( stderr, "\tdn %20s id %lu refcnt %d\n", e->e_dn,
+ e->e_id, e->e_refcnt );
+ }
+}
+
+#endif
+
--- /dev/null
+/* close.c - close bdb2 backend */
+
+#include "portable.h"
+
+#include <stdio.h>
+
+#include <ac/socket.h>
+
+#include "slap.h"
+#include "back-bdb2.h"
+
+static int
+bdb2i_back_db_close_internal( Backend *be )
+{
+ Debug( LDAP_DEBUG_TRACE, "bdb2 backend saving nextid\n", 0, 0, 0 );
+ if ( bdb2i_next_id_save( be ) < 0 ) {
+ Debug( LDAP_DEBUG_ANY, "bdb2 backend nextid save failed!\n", 0, 0, 0 );
+ }
+
+ Debug( LDAP_DEBUG_TRACE, "bdb2 backend syncing\n", 0, 0, 0 );
+ bdb2i_cache_flush_all( be );
+ Debug( LDAP_DEBUG_TRACE, "bdb2 backend done syncing\n", 0, 0, 0 );
+
+ return 0;
+}
+
+
+int
+bdb2_back_db_close( Backend *be )
+{
+ struct timeval time1, time2;
+ char *elapsed_time;
+ int ret;
+
+ gettimeofday( &time1, NULL );
+
+ ret = bdb2i_back_db_close_internal( be );
+
+ if ( bdb2i_do_timing ) {
+
+ gettimeofday( &time2, NULL);
+ elapsed_time = bdb2i_elapsed( time1, time2 );
+ Debug( LDAP_DEBUG_ANY, "CLOSE elapsed=%s\n",
+ elapsed_time, 0, 0 );
+ free( elapsed_time );
+
+ }
+
+ return( ret );
+}
+
+
--- /dev/null
+/* compare.c - bdb2 backend compare routine */
+
+#include "portable.h"
+
+#include <stdio.h>
+
+#include <ac/socket.h>
+#include <ac/string.h>
+
+#include "slap.h"
+#include "back-bdb2.h"
+#include "proto-back-bdb2.h"
+
+static int
+bdb2i_back_compare_internal(
+ Backend *be,
+ Connection *conn,
+ Operation *op,
+ char *dn,
+ Ava *ava
+)
+{
+ struct ldbminfo *li = (struct ldbminfo *) be->be_private;
+ char *matched;
+ Entry *e;
+ Attribute *a;
+ int rc;
+
+ /* get entry with reader lock */
+ if ( (e = bdb2i_dn2entry_r( be, dn, &matched )) == NULL ) {
+ send_ldap_result( conn, op, LDAP_NO_SUCH_OBJECT, matched, "" );
+
+ if(matched == NULL) free(matched);
+ return( 1 );
+ }
+
+ /* check for deleted */
+ if ( ! access_allowed( be, conn, op, e,
+ ava->ava_type, &ava->ava_value, ACL_COMPARE ) )
+ {
+ send_ldap_result( conn, op, LDAP_INSUFFICIENT_ACCESS, "", "" );
+ rc = 1;
+ goto return_results;
+ }
+
+ if ( (a = attr_find( e->e_attrs, ava->ava_type )) == NULL ) {
+ send_ldap_result( conn, op, LDAP_NO_SUCH_ATTRIBUTE, "", "" );
+ rc = 1;
+ goto return_results;
+ }
+
+ if ( value_find( a->a_vals, &ava->ava_value, a->a_syntax, 1 ) == 0 )
+ send_ldap_result( conn, op, LDAP_COMPARE_TRUE, "", "" );
+ else
+ send_ldap_result( conn, op, LDAP_COMPARE_FALSE, "", "" );
+
+ rc = 0;
+
+return_results:;
+ bdb2i_cache_return_entry_r( &li->li_cache, e );
+ return( rc );
+}
+
+
+int
+bdb2_back_compare(
+ Backend *be,
+ Connection *conn,
+ Operation *op,
+ char *dn,
+ Ava *ava
+)
+{
+ DB_LOCK lock;
+ struct ldbminfo *li = (struct ldbminfo *) be->be_private;
+
+ struct timeval time1, time2;
+ char *elapsed_time;
+ int ret;
+
+ gettimeofday( &time1, NULL );
+
+ if ( bdb2i_enter_backend_r( &li->li_db_env, &lock ) != 0 ) {
+
+ send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR, "", "" );
+ return( 1 );
+
+ }
+
+ ret = bdb2i_back_compare_internal( be, conn, op, dn, ava );
+
+ (void) bdb2i_leave_backend( &li->li_db_env, lock );
+
+ if ( bdb2i_do_timing ) {
+
+ gettimeofday( &time2, NULL);
+ elapsed_time = bdb2i_elapsed( time1, time2 );
+ Debug( LDAP_DEBUG_ANY, "conn=%d op=%d CMP elapsed=%s\n",
+ conn->c_connid, op->o_opid, elapsed_time );
+ free( elapsed_time );
+
+ }
+
+ return( ret );
+}
+
+
--- /dev/null
+/* config.c - bdb2 backend configuration file routine */
+
+#include "portable.h"
+
+#include <stdio.h>
+
+#include <ac/socket.h>
+#include <ac/string.h>
+
+#include "slap.h"
+#include "back-bdb2.h"
+
+static int
+bdb2i_back_db_config_internal(
+ Backend *be,
+ char *fname,
+ int lineno,
+ int argc,
+ char **argv
+)
+{
+ struct ldbminfo *li = (struct ldbminfo *) be->be_private;
+
+ if ( li == NULL ) {
+ fprintf( stderr, "%s: line %d: ldbm backend info is null!\n",
+ fname, lineno );
+ return( 1 );
+ }
+
+ /* directory where database files live */
+ if ( strcasecmp( argv[0], "directory" ) == 0 ) {
+ if ( argc < 2 ) {
+ fprintf( stderr,
+ "%s: line %d: missing dir in \"directory <dir>\" line\n",
+ fname, lineno );
+ return( 1 );
+ }
+ li->li_directory = ch_strdup( argv[1] );
+
+ li->li_nextid_file =
+ ch_malloc( strlen(li->li_directory) + sizeof("/NEXTID") );
+
+ strcpy(li->li_nextid_file, li->li_directory);
+ strcat(li->li_nextid_file, "/NEXTID");
+
+ /* mode with which to create new database files */
+ } else if ( strcasecmp( argv[0], "mode" ) == 0 ) {
+ if ( argc < 2 ) {
+ fprintf( stderr,
+ "%s: line %d: missing mode in \"mode <mode>\" line\n",
+ fname, lineno );
+ return( 1 );
+ }
+ li->li_mode = strtol( argv[1], NULL, 0 );
+
+ /* attribute to index */
+ } else if ( strcasecmp( argv[0], "index" ) == 0 ) {
+ if ( argc < 2 ) {
+ fprintf( stderr,
+"%s: line %d: missing attr in \"index <attr> [pres,eq,approx,sub]\" line\n",
+ fname, lineno );
+ return( 1 );
+ } else if ( argc > 3 ) {
+ fprintf( stderr,
+"%s: line %d: extra junk after \"index <attr> [pres,eq,approx,sub]\" line (ignored)\n",
+ fname, lineno );
+ }
+ bdb2i_attr_index_config( li, fname, lineno, argc - 1, &argv[1], 0 );
+
+ /* size of the cache in entries */
+ } else if ( strcasecmp( argv[0], "cachesize" ) == 0 ) {
+ if ( argc < 2 ) {
+ fprintf( stderr,
+ "%s: line %d: missing size in \"cachesize <size>\" line\n",
+ fname, lineno );
+ return( 1 );
+ }
+ li->li_cache.c_maxsize = atoi( argv[1] );
+
+ /* size of each dbcache in bytes */
+ } else if ( strcasecmp( argv[0], "dbcachesize" ) == 0 ) {
+ if ( argc < 2 ) {
+ fprintf( stderr,
+ "%s: line %d: missing size in \"dbcachesize <size>\" line\n",
+ fname, lineno );
+ return( 1 );
+ }
+ li->li_dbcachesize = atoi( argv[1] );
+ /* we should at least have the suggested 128k */
+ if ( li->li_dbcachesize < DEFAULT_DBCACHE_SIZE )
+ li->li_dbcachesize = DEFAULT_DBCACHE_SIZE;
+
+ /* no write sync */
+ } else if ( strcasecmp( argv[0], "dbcachenowsync" ) == 0 ) {
+ li->li_dbcachewsync = 0;
+
+ /* anything else */
+ } else {
+ fprintf( stderr,
+"%s: line %d: unknown directive \"%s\" in ldbm database definition (ignored)\n",
+ fname, lineno, argv[0] );
+ }
+
+ return 0;
+}
+
+
+int
+bdb2_back_db_config(
+ Backend *be,
+ char *fname,
+ int lineno,
+ int argc,
+ char **argv
+)
+{
+ struct timeval time1, time2;
+ char *elapsed_time;
+ int ret;
+
+ gettimeofday( &time1, NULL );
+
+ ret = bdb2i_back_db_config_internal( be, fname, lineno, argc, argv );
+
+ if ( bdb2i_do_timing ) {
+
+ gettimeofday( &time2, NULL);
+ elapsed_time = bdb2i_elapsed( time1, time2 );
+ Debug( LDAP_DEBUG_ANY, "CONFIG elapsed=%s\n",
+ elapsed_time, 0, 0 );
+ free( elapsed_time );
+
+ }
+
+ return( ret );
+}
+
+
--- /dev/null
+/* ldbmcache.c - maintain a cache of open bdb2 files */
+
+#include "portable.h"
+
+#include <stdio.h>
+
+#include <ac/errno.h>
+#include <ac/socket.h>
+#include <ac/string.h>
+#include <ac/time.h>
+
+#include <sys/stat.h>
+
+#ifdef HAVE_SYS_PARAM_H
+#include <sys/param.h>
+#endif
+
+#include "ldapconfig.h"
+#include "slap.h"
+#include "back-bdb2.h"
+
+#define ldbm_open_env( buf, flags, mode, dbcachesize, env ) \
+ ldbm_open( (buf), (flags), (mode), (dbcachesize) )
+
+struct dbcache *
+bdb2i_cache_open(
+ Backend *be,
+ char *name,
+ char *suffix,
+ int flags
+)
+{
+ struct ldbminfo *li = (struct ldbminfo *) be->be_private;
+ int i, lru;
+ time_t oldtime, curtime;
+ char buf[MAXPATHLEN];
+ LDBM db;
+ struct stat st;
+ int dbcachesize;
+
+ /* sprintf( buf, "%s%s%s%s", li->li_directory, DEFAULT_DIRSEP, name, suffix ); */
+ sprintf( buf, "%s%s", name, suffix );
+
+ /* if in slapd, all files are open, so return handle from file cache */
+ if ( bdb2i_with_dbenv )
+ return( bdb2i_get_db_file_cache( li, buf ));
+
+ Debug( LDAP_DEBUG_TRACE, "=> bdb2i_cache_open( \"%s\", %d, %o )\n", buf,
+ flags, li->li_mode );
+
+ lru = 0;
+ ldap_pvt_thread_mutex_lock( ¤ttime_mutex );
+ curtime = currenttime;
+ ldap_pvt_thread_mutex_unlock( ¤ttime_mutex );
+ oldtime = curtime;
+
+ ldap_pvt_thread_mutex_lock( &li->li_dbcache_mutex );
+ for ( i = 0; i < MAXDBCACHE && li->li_dbcache[i].dbc_name != NULL;
+ i++ ) {
+ /* already open - return it */
+ if ( strcmp( li->li_dbcache[i].dbc_name, buf ) == 0 ) {
+ li->li_dbcache[i].dbc_refcnt++;
+ Debug( LDAP_DEBUG_TRACE,
+ "<= bdb2i_cache_open (cache %d)\n", i, 0, 0 );
+ ldap_pvt_thread_mutex_unlock( &li->li_dbcache_mutex );
+ return( &li->li_dbcache[i] );
+ }
+
+ /* keep track of lru db */
+ if ( li->li_dbcache[i].dbc_lastref < oldtime &&
+ li->li_dbcache[i].dbc_refcnt == 0 ) {
+ lru = i;
+ oldtime = li->li_dbcache[i].dbc_lastref;
+ }
+ }
+
+ /* no empty slots, not already open - close lru and use that slot */
+ if ( i == MAXDBCACHE ) {
+ i = lru;
+ if ( li->li_dbcache[i].dbc_refcnt != 0 ) {
+ Debug( LDAP_DEBUG_ANY,
+ "bdb2i_cache_open no unused db to close - waiting\n",
+ 0, 0, 0 );
+ lru = -1;
+ while ( lru == -1 ) {
+ ldap_pvt_thread_cond_wait( &li->li_dbcache_cv,
+ &li->li_dbcache_mutex );
+ for ( i = 0; i < MAXDBCACHE; i++ ) {
+ if ( li->li_dbcache[i].dbc_refcnt
+ == 0 ) {
+ lru = i;
+ break;
+ }
+ }
+ }
+ i = lru;
+ }
+ ldbm_close( li->li_dbcache[i].dbc_db );
+ free( li->li_dbcache[i].dbc_name );
+ li->li_dbcache[i].dbc_name = NULL;
+ }
+
+ dbcachesize = li->li_dbcachesize;
+
+ if ( bdb2i_with_dbenv ) dbcachesize = 0;
+ if ( (li->li_dbcache[i].dbc_db = ldbm_open_env( buf, flags, li->li_mode,
+ dbcachesize, &li->li_db_env )) == NULL ) {
+
+ Debug( LDAP_DEBUG_TRACE,
+ "<= bdb2i_cache_open NULL \"%s\" errno %d reason \"%s\")\n",
+ buf, errno, errno > -1 && errno < sys_nerr ?
+ sys_errlist[errno] : "unknown" );
+ ldap_pvt_thread_mutex_unlock( &li->li_dbcache_mutex );
+ return( NULL );
+ }
+ li->li_dbcache[i].dbc_name = ch_strdup( buf );
+ li->li_dbcache[i].dbc_refcnt = 1;
+ li->li_dbcache[i].dbc_lastref = curtime;
+ if ( stat( buf, &st ) == 0 ) {
+ li->li_dbcache[i].dbc_blksize = st.st_blksize;
+ } else {
+ li->li_dbcache[i].dbc_blksize = DEFAULT_BLOCKSIZE;
+ }
+ li->li_dbcache[i].dbc_maxids = (li->li_dbcache[i].dbc_blksize /
+ sizeof(ID)) - ID_BLOCK_IDS_OFFSET;
+ li->li_dbcache[i].dbc_maxindirect = (SLAPD_LDBM_MIN_MAXIDS /
+ li->li_dbcache[i].dbc_maxids) + 1;
+
+ Debug( LDAP_DEBUG_ARGS,
+ "bdb2i_cache_open (blksize %ld) (maxids %d) (maxindirect %d)\n",
+ li->li_dbcache[i].dbc_blksize, li->li_dbcache[i].dbc_maxids,
+ li->li_dbcache[i].dbc_maxindirect );
+ Debug( LDAP_DEBUG_TRACE, "<= bdb2i_cache_open (opened %d)\n", i, 0, 0 );
+ ldap_pvt_thread_mutex_unlock( &li->li_dbcache_mutex );
+ return( &li->li_dbcache[i] );
+}
+
+void
+bdb2i_cache_close( Backend *be, struct dbcache *db )
+{
+ struct ldbminfo *li = (struct ldbminfo *) be->be_private;
+
+ /* if in slapd, all files stay open and we have only
+ readers or one writer */
+ if ( bdb2i_with_dbenv ) return;
+
+ ldap_pvt_thread_mutex_lock( &li->li_dbcache_mutex );
+ if ( --db->dbc_refcnt == 0 ) {
+ ldap_pvt_thread_cond_signal( &li->li_dbcache_cv );
+ }
+ ldap_pvt_thread_mutex_unlock( &li->li_dbcache_mutex );
+}
+
+void
+bdb2i_cache_really_close( Backend *be, struct dbcache *db )
+{
+ struct ldbminfo *li = (struct ldbminfo *) be->be_private;
+
+ /* if in slapd, all files stay open and we have only
+ readers or one writer */
+ if ( bdb2i_with_dbenv ) return;
+
+ ldap_pvt_thread_mutex_lock( &li->li_dbcache_mutex );
+ if ( --db->dbc_refcnt == 0 ) {
+ ldap_pvt_thread_cond_signal( &li->li_dbcache_cv );
+ ldbm_close( db->dbc_db );
+ free( db->dbc_name );
+ db->dbc_name = NULL;
+ }
+ ldap_pvt_thread_mutex_unlock( &li->li_dbcache_mutex );
+}
+
+void
+bdb2i_cache_flush_all( Backend *be )
+{
+ struct ldbminfo *li = (struct ldbminfo *) be->be_private;
+ int i;
+
+ /* if in slapd, syncing is done by TP */
+ if ( bdb2i_with_dbenv ) return;
+
+ ldap_pvt_thread_mutex_lock( &li->li_dbcache_mutex );
+ for ( i = 0; i < MAXDBCACHE; i++ ) {
+ if ( li->li_dbcache[i].dbc_name != NULL ) {
+ Debug( LDAP_DEBUG_TRACE, "ldbm flushing db (%s)\n",
+ li->li_dbcache[i].dbc_name, 0, 0 );
+ ldbm_sync( li->li_dbcache[i].dbc_db );
+ }
+ }
+ ldap_pvt_thread_mutex_unlock( &li->li_dbcache_mutex );
+}
+
+Datum
+bdb2i_cache_fetch(
+ struct dbcache *db,
+ Datum key
+)
+{
+ Datum data;
+
+ ldbm_datum_init( data );
+
+ data = ldbm_fetch( db->dbc_db, key );
+
+ return( data );
+}
+
+int
+bdb2i_cache_store(
+ struct dbcache *db,
+ Datum key,
+ Datum data,
+ int flags
+)
+{
+ int rc;
+
+#ifdef LDBM_DEBUG
+ Statslog( LDAP_DEBUG_STATS,
+ "=> bdb2i_cache_store(): key.dptr=%s, key.dsize=%d\n",
+ key.dptr, key.dsize, 0, 0, 0 );
+
+ Statslog( LDAP_DEBUG_STATS,
+ "=> bdb2i_cache_store(): key.dptr=0x%08x, data.dptr=0x%0 8x\n",
+ key.dptr, data.dptr, 0, 0, 0 );
+
+ Statslog( LDAP_DEBUG_STATS,
+ "=> bdb2i_cache_store(): data.dptr=%s, data.dsize=%d\n",
+ data.dptr, data.dsize, 0, 0, 0 );
+
+ Statslog( LDAP_DEBUG_STATS,
+ "=> bdb2i_cache_store(): flags=0x%08x\n",
+ flags, 0, 0, 0, 0 );
+#endif /* LDBM_DEBUG */
+
+ rc = ldbm_store( db->dbc_db, key, data, flags );
+
+ return( rc );
+}
+
+int
+bdb2i_cache_delete(
+ struct dbcache *db,
+ Datum key
+)
+{
+ int rc;
+
+ rc = ldbm_delete( db->dbc_db, key );
+
+ return( rc );
+}
--- /dev/null
+/* delete.c - bdb2 backend delete routine */
+
+#include "portable.h"
+
+#include <stdio.h>
+
+#include <ac/string.h>
+#include <ac/socket.h>
+
+#include "slap.h"
+#include "back-bdb2.h"
+#include "proto-back-bdb2.h"
+
+static int
+bdb2i_back_delete_internal(
+ Backend *be,
+ Connection *conn,
+ Operation *op,
+ char *dn
+)
+{
+ struct ldbminfo *li = (struct ldbminfo *) be->be_private;
+ char *matched = NULL;
+ char *pdn = NULL;
+ Entry *e, *p = NULL;
+ int rootlock = 0;
+ int rc = -1;
+
+ Debug(LDAP_DEBUG_ARGS, "==> bdb2i_back_delete: %s\n", dn, 0, 0);
+
+ /* get entry with writer lock */
+ if ( (e = bdb2i_dn2entry_w( be, dn, &matched )) == NULL ) {
+ Debug(LDAP_DEBUG_ARGS, "<=- bdb2i_back_delete: no such object %s\n",
+ dn, 0, 0);
+ send_ldap_result( conn, op, LDAP_NO_SUCH_OBJECT, matched, "" );
+ if ( matched != NULL ) {
+ free( matched );
+ }
+ return( -1 );
+ }
+
+ /* check for deleted */
+
+ if ( bdb2i_has_children( be, e ) ) {
+ Debug(LDAP_DEBUG_ARGS, "<=- bdb2i_back_delete: non leaf %s\n",
+ dn, 0, 0);
+ send_ldap_result( conn, op, LDAP_NOT_ALLOWED_ON_NONLEAF, "",
+ "" );
+ goto return_results;
+ }
+
+#ifdef SLAPD_CHILD_MODIFICATION_WITH_ENTRY_ACL
+ if ( ! access_allowed( be, conn, op, e,
+ "entry", NULL, ACL_WRITE ) )
+ {
+ Debug(LDAP_DEBUG_ARGS,
+ "<=- bdb2i_back_delete: insufficient access %s\n",
+ dn, 0, 0);
+ send_ldap_result( conn, op, LDAP_INSUFFICIENT_ACCESS, "", "" );
+ goto return_results;
+ }
+#endif
+
+ /* delete from parent's id2children entry */
+ if( (pdn = dn_parent( be, dn )) != NULL ) {
+ if( (p = bdb2i_dn2entry_w( be, pdn, &matched )) == NULL) {
+ Debug( LDAP_DEBUG_TRACE,
+ "<=- bdb2i_back_delete: parent does not exist\n", 0, 0, 0);
+ send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR,
+ "", "");
+ goto return_results;
+ }
+
+#ifndef SLAPD_CHILD_MODIFICATION_WITH_ENTRY_ACL
+ /* check parent for "children" acl */
+ if ( ! access_allowed( be, conn, op, p,
+ "children", NULL, ACL_WRITE ) )
+ {
+ Debug( LDAP_DEBUG_TRACE,
+ "<=- bdb2i_back_delete: no access to parent\n", 0, 0, 0 );
+ send_ldap_result( conn, op, LDAP_INSUFFICIENT_ACCESS,
+ "", "" );
+ goto return_results;
+ }
+#endif
+
+ } else {
+ /* no parent, must be root to delete */
+ if( ! be_isroot( be, op->o_ndn ) ) {
+ Debug( LDAP_DEBUG_TRACE,
+ "<=- bdb2i_back_delete: no parent & not root\n", 0, 0, 0);
+ send_ldap_result( conn, op, LDAP_INSUFFICIENT_ACCESS,
+ "", "");
+ goto return_results;
+ }
+
+ ldap_pvt_thread_mutex_lock(&li->li_root_mutex);
+ rootlock = 1;
+ }
+
+ if ( bdb2i_id2children_remove( be, p, e ) != 0 ) {
+ Debug(LDAP_DEBUG_ARGS,
+ "<=- bdb2i_back_delete: operations error %s\n",
+ dn, 0, 0);
+ send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR, "","" );
+ goto return_results;
+ }
+
+ /* delete from dn2id mapping */
+ if ( bdb2i_dn2id_delete( be, e->e_dn ) != 0 ) {
+ Debug(LDAP_DEBUG_ARGS,
+ "<=- bdb2i_back_delete: operations error %s\n",
+ dn, 0, 0);
+ send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR, "", "" );
+ goto return_results;
+ }
+
+ /* delete from disk and cache */
+ if ( bdb2i_id2entry_delete( be, e ) != 0 ) {
+ Debug(LDAP_DEBUG_ARGS,
+ "<=- bdb2i_back_delete: operations error %s\n",
+ dn, 0, 0);
+ send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR, "", "" );
+ goto return_results;
+ }
+
+ send_ldap_result( conn, op, LDAP_SUCCESS, "", "" );
+ rc = 0;
+
+return_results:;
+ if ( pdn != NULL ) free(pdn);
+
+ if( p != NULL ) {
+ /* free parent and writer lock */
+ bdb2i_cache_return_entry_w( &li->li_cache, p );
+
+ }
+
+ if ( rootlock ) {
+ /* release root lock */
+ ldap_pvt_thread_mutex_unlock(&li->li_root_mutex);
+ }
+
+ /* free entry and writer lock */
+ bdb2i_cache_return_entry_w( &li->li_cache, e );
+
+ if ( matched != NULL ) free(matched);
+
+ return rc;
+}
+
+
+int
+bdb2_back_delete(
+ Backend *be,
+ Connection *conn,
+ Operation *op,
+ char *dn
+)
+{
+ DB_LOCK lock;
+ struct ldbminfo *li = (struct ldbminfo *) be->be_private;
+
+ struct timeval time1, time2;
+ char *elapsed_time;
+ int ret;
+
+ gettimeofday( &time1, NULL );
+
+ if ( bdb2i_enter_backend_w( &li->li_db_env, &lock ) != 0 ) {
+
+ send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR, "", "" );
+ return( -1 );
+
+ }
+
+ ret = bdb2i_back_delete_internal( be, conn, op, dn );
+
+ (void) bdb2i_leave_backend( &li->li_db_env, lock );
+
+ if ( bdb2i_do_timing ) {
+
+ gettimeofday( &time2, NULL);
+ elapsed_time = bdb2i_elapsed( time1, time2 );
+ Debug( LDAP_DEBUG_ANY, "conn=%d op=%d DEL elapsed=%s\n",
+ conn->c_connid, op->o_opid, elapsed_time );
+ free( elapsed_time );
+
+ }
+
+ return( ret );
+}
+
+
--- /dev/null
+/* dn2id.c - routines to deal with the dn2id index */
+
+#include "portable.h"
+
+#include <stdio.h>
+
+#include <ac/string.h>
+#include <ac/socket.h>
+
+#include "slap.h"
+#include "back-bdb2.h"
+#include "proto-back-bdb2.h"
+
+int
+bdb2i_dn2id_add(
+ Backend *be,
+ char *dn,
+ ID id
+)
+{
+ int rc, flags;
+ struct dbcache *db;
+ Datum key, data;
+ struct ldbminfo *li = (struct ldbminfo *) be->be_private;
+
+ ldbm_datum_init( key );
+ ldbm_datum_init( data );
+
+ Debug( LDAP_DEBUG_TRACE, "=> bdb2i_dn2id_add( \"%s\", %ld )\n", dn, id, 0 );
+
+ if ( (db = bdb2i_cache_open( be, "dn2id", LDBM_SUFFIX, LDBM_WRCREAT ))
+ == NULL ) {
+ Debug( LDAP_DEBUG_ANY, "Could not open/create dn2id%s\n",
+ LDBM_SUFFIX, 0, 0 );
+ return( -1 );
+ }
+
+ dn = ch_strdup( dn );
+ dn_normalize_case( dn );
+
+ key.dptr = dn;
+ key.dsize = strlen( dn ) + 1;
+ data.dptr = (char *) &id;
+ data.dsize = sizeof(ID);
+
+ flags = LDBM_INSERT;
+ if ( li->li_dbcachewsync ) flags |= LDBM_SYNC;
+
+ rc = bdb2i_cache_store( db, key, data, flags );
+
+ free( dn );
+ bdb2i_cache_close( be, db );
+
+ Debug( LDAP_DEBUG_TRACE, "<= bdb2i_dn2id_add %d\n", rc, 0, 0 );
+ return( rc );
+}
+
+ID
+bdb2i_dn2id(
+ Backend *be,
+ char *dn
+)
+{
+ struct ldbminfo *li = (struct ldbminfo *) be->be_private;
+ struct dbcache *db;
+ ID id;
+ Datum key, data;
+
+ ldbm_datum_init( key );
+ ldbm_datum_init( data );
+
+ dn = ch_strdup( dn );
+ Debug( LDAP_DEBUG_TRACE, "=> bdb2i_dn2id( \"%s\" )\n", dn, 0, 0 );
+ dn_normalize_case( dn );
+
+ /* first check the cache */
+ if ( (id = bdb2i_cache_find_entry_dn2id( be, &li->li_cache, dn )) != NOID ) {
+ free( dn );
+ Debug( LDAP_DEBUG_TRACE, "<= bdb2i_dn2id %lu (in cache)\n", id,
+ 0, 0 );
+ return( id );
+ }
+
+ if ( (db = bdb2i_cache_open( be, "dn2id", LDBM_SUFFIX, LDBM_WRCREAT ))
+ == NULL ) {
+ free( dn );
+ Debug( LDAP_DEBUG_ANY, "<= bdb2i_dn2id could not open dn2id%s\n",
+ LDBM_SUFFIX, 0, 0 );
+ return( NOID );
+ }
+
+ key.dptr = dn;
+ key.dsize = strlen( dn ) + 1;
+
+ data = bdb2i_cache_fetch( db, key );
+
+ bdb2i_cache_close( be, db );
+ free( dn );
+
+ if ( data.dptr == NULL ) {
+ Debug( LDAP_DEBUG_TRACE, "<= bdb2i_dn2id NOID\n", 0, 0, 0 );
+ return( NOID );
+ }
+
+ (void) memcpy( (char *) &id, data.dptr, sizeof(ID) );
+
+ ldbm_datum_free( db->dbc_db, data );
+
+ Debug( LDAP_DEBUG_TRACE, "<= bdb2i_dn2id %lu\n", id, 0, 0 );
+ return( id );
+}
+
+int
+bdb2i_dn2id_delete(
+ Backend *be,
+ char *dn
+)
+{
+ struct ldbminfo *li = (struct ldbminfo *) be->be_private;
+ struct dbcache *db;
+ Datum key;
+ int rc;
+
+ ldbm_datum_init( key );
+
+ Debug( LDAP_DEBUG_TRACE, "=> bdb2i_dn2id_delete( \"%s\" )\n", dn, 0, 0 );
+
+ if ( (db = bdb2i_cache_open( be, "dn2id", LDBM_SUFFIX, LDBM_WRCREAT ))
+ == NULL ) {
+ Debug( LDAP_DEBUG_ANY,
+ "<= bdb2i_dn2id_delete could not open dn2id%s\n", LDBM_SUFFIX,
+ 0, 0 );
+ return( -1 );
+ }
+
+ dn = ch_strdup( dn );
+ dn_normalize_case( dn );
+ key.dptr = dn;
+ key.dsize = strlen( dn ) + 1;
+
+ rc = bdb2i_cache_delete( db, key );
+
+ free( dn );
+
+ bdb2i_cache_close( be, db );
+
+ Debug( LDAP_DEBUG_TRACE, "<= bdb2i_dn2id_delete %d\n", rc, 0, 0 );
+ return( rc );
+}
+
+/*
+ * dn2entry - look up dn in the cache/indexes and return the corresponding
+ * entry.
+ */
+
+static Entry *
+dn2entry(
+ Backend *be,
+ char *dn,
+ char **matched,
+ int rw
+)
+{
+ struct ldbminfo *li = (struct ldbminfo *) be->be_private;
+ ID id;
+ Entry *e = NULL;
+ char *pdn;
+
+ Debug(LDAP_DEBUG_TRACE, "dn2entry_%s: dn: \"%s\"\n",
+ rw ? "w" : "r", dn, 0);
+
+ *matched = NULL;
+
+ if ( (id = bdb2i_dn2id( be, dn )) != NOID &&
+ (e = bdb2i_id2entry( be, id, rw )) != NULL )
+ {
+ return( e );
+ }
+
+ if ( id != NOID ) {
+ Debug(LDAP_DEBUG_ANY,
+ "dn2entry_%s: no entry for valid id (%lu), dn \"%s\"\n",
+ rw ? "w" : "r", id, dn);
+ /* must have been deleted from underneath us */
+ /* treat as if NOID was found */
+ }
+
+ /* stop when we get to the suffix */
+ if ( be_issuffix( be, dn ) ) {
+ return( NULL );
+ }
+
+ /* entry does not exist - see how much of the dn does exist */
+ if ( (pdn = dn_parent( be, dn )) != NULL ) {
+ /* get entry with reader lock */
+ if ( (e = bdb2i_dn2entry_r( be, pdn, matched )) != NULL ) {
+ if(*matched != NULL) {
+ free(*matched);
+ }
+ *matched = pdn;
+ /* free entry with reader lock */
+ bdb2i_cache_return_entry_r( &li->li_cache, e );
+ } else {
+ free( pdn );
+ }
+ }
+
+ return( NULL );
+}
+
+Entry *
+bdb2i_dn2entry_r(
+ Backend *be,
+ char *dn,
+ char **matched
+)
+{
+ return( dn2entry( be, dn, matched, 0 ) );
+}
+
+Entry *
+bdb2i_dn2entry_w(
+ Backend *be,
+ char *dn,
+ char **matched
+)
+{
+ return( dn2entry( be, dn, matched, 1 ) );
+}
+
+
+
--- /dev/null
+#ifndef _BDB2_EXTERNAL_H
+#define _BDB2_EXTERNAL_H
+
+LDAP_BEGIN_DECL
+
+extern int bdb2_back_initialize LDAP_P(( BackendInfo *bi ));
+extern int bdb2_back_open LDAP_P(( BackendInfo *bi ));
+extern int bdb2_back_close LDAP_P(( BackendInfo *bi ));
+extern int bdb2_back_destroy LDAP_P(( BackendInfo *bi ));
+
+extern int bdb2_back_db_init LDAP_P(( BackendDB *bd ));
+extern int bdb2_back_db_open LDAP_P(( BackendDB *bd ));
+extern int bdb2_back_db_close LDAP_P(( BackendDB *bd ));
+extern int bdb2_back_db_destroy LDAP_P(( BackendDB *bd ));
+
+extern int bdb2_back_db_config LDAP_P(( BackendDB *bd,
+ char *fname, int lineno, int argc, char **argv ));
+
+extern int bdb2_back_bind LDAP_P(( BackendDB *bd,
+ Connection *conn, Operation *op,
+ char *dn, int method, struct berval *cred, char** edn ));
+
+extern int bdb2_back_unbind LDAP_P(( BackendDB *bd,
+ Connection *conn, Operation *op ));
+
+extern int bdb2_back_search LDAP_P(( BackendDB *bd,
+ Connection *conn, Operation *op,
+ char *base, int scope, int deref, int sizelimit, int timelimit,
+ Filter *filter, char *filterstr, char **attrs, int attrsonly ));
+
+extern int bdb2_back_compare LDAP_P((BackendDB *bd,
+ Connection *conn, Operation *op,
+ char *dn, Ava *ava ));
+
+extern int bdb2_back_modify LDAP_P(( BackendDB *bd,
+ Connection *conn, Operation *op,
+ char *dn, LDAPModList *ml ));
+
+extern int bdb2_back_modrdn LDAP_P(( BackendDB *bd,
+ Connection *conn, Operation *op,
+ char *dn, char*newrdn, int deleteoldrdn ));
+
+extern int bdb2_back_add LDAP_P(( BackendDB *bd,
+ Connection *conn, Operation *op, Entry *e ));
+
+extern int bdb2_back_delete LDAP_P(( BackendDB *bd,
+ Connection *conn, Operation *op, char *dn ));
+
+extern int bdb2_back_abandon LDAP_P(( BackendDB *bd,
+ Connection *conn, Operation *op, int msgid ));
+
+extern int bdb2_back_group LDAP_P(( BackendDB *bd,
+ Entry *target, char* gr_ndn, char* op_ndn,
+ char* objectclassValue, char* groupattrName));
+
+LDAP_END_DECL
+
+#endif /* _BDB2_EXTERNAL_H */
+
--- /dev/null
+/* filterindex.c - generate the list of candidate entries from a filter */
+
+#include "portable.h"
+
+#include <stdio.h>
+
+#include <ac/socket.h>
+#include <ac/string.h>
+
+#include "slap.h"
+#include "back-bdb2.h"
+
+static ID_BLOCK *ava_candidates( Backend *be, Ava *ava, int type );
+static ID_BLOCK *presence_candidates( Backend *be, char *type );
+static ID_BLOCK *approx_candidates( Backend *be, Ava *ava );
+static ID_BLOCK *list_candidates( Backend *be, Filter *flist, int ftype );
+static ID_BLOCK *substring_candidates( Backend *be, Filter *f );
+static ID_BLOCK *substring_comp_candidates( Backend *be, char *type, char *val, int prepost );
+
+/*
+ * test_filter - test a filter against a single entry.
+ * returns 0 filter matched
+ * -1 filter did not match
+ * >0 an ldap error code
+ */
+
+ID_BLOCK *
+bdb2i_filter_candidates(
+ Backend *be,
+ Filter *f
+)
+{
+ ID_BLOCK *result, *tmp1, *tmp2;
+
+ Debug( LDAP_DEBUG_TRACE, "=> bdb2i_filter_candidates\n", 0, 0, 0 );
+
+ result = NULL;
+ switch ( f->f_choice ) {
+ case LDAP_FILTER_EQUALITY:
+ Debug( LDAP_DEBUG_FILTER, "\tEQUALITY\n", 0, 0, 0 );
+ result = ava_candidates( be, &f->f_ava, LDAP_FILTER_EQUALITY );
+ break;
+
+ case LDAP_FILTER_SUBSTRINGS:
+ Debug( LDAP_DEBUG_FILTER, "\tSUBSTRINGS\n", 0, 0, 0 );
+ result = substring_candidates( be, f );
+ break;
+
+ case LDAP_FILTER_GE:
+ Debug( LDAP_DEBUG_FILTER, "\tGE\n", 0, 0, 0 );
+ result = ava_candidates( be, &f->f_ava, LDAP_FILTER_GE );
+ break;
+
+ case LDAP_FILTER_LE:
+ Debug( LDAP_DEBUG_FILTER, "\tLE\n", 0, 0, 0 );
+ result = ava_candidates( be, &f->f_ava, LDAP_FILTER_LE );
+ break;
+
+ case LDAP_FILTER_PRESENT:
+ Debug( LDAP_DEBUG_FILTER, "\tPRESENT\n", 0, 0, 0 );
+ result = presence_candidates( be, f->f_type );
+ break;
+
+ case LDAP_FILTER_APPROX:
+ Debug( LDAP_DEBUG_FILTER, "\tAPPROX\n", 0, 0, 0 );
+ result = approx_candidates( be, &f->f_ava );
+ break;
+
+ case LDAP_FILTER_AND:
+ Debug( LDAP_DEBUG_FILTER, "\tAND\n", 0, 0, 0 );
+ result = list_candidates( be, f->f_and, LDAP_FILTER_AND );
+ break;
+
+ case LDAP_FILTER_OR:
+ Debug( LDAP_DEBUG_FILTER, "\tOR\n", 0, 0, 0 );
+ result = list_candidates( be, f->f_or, LDAP_FILTER_OR );
+ break;
+
+ case LDAP_FILTER_NOT:
+ Debug( LDAP_DEBUG_FILTER, "\tNOT\n", 0, 0, 0 );
+ tmp1 = bdb2i_idl_allids( be );
+ tmp2 = bdb2i_filter_candidates( be, f->f_not );
+ result = bdb2i_idl_notin( be, tmp1, tmp2 );
+ bdb2i_idl_free( tmp2 );
+ bdb2i_idl_free( tmp1 );
+ break;
+ }
+
+ Debug( LDAP_DEBUG_TRACE, "<= bdb2i_filter_candidates %lu\n",
+ result ? ID_BLOCK_NIDS(result) : 0, 0, 0 );
+ return( result );
+}
+
+static ID_BLOCK *
+ava_candidates(
+ Backend *be,
+ Ava *ava,
+ int type
+)
+{
+ ID_BLOCK *idl;
+
+ Debug( LDAP_DEBUG_TRACE, "=> ava_candidates 0x%x\n", type, 0, 0 );
+
+ switch ( type ) {
+ case LDAP_FILTER_EQUALITY:
+ idl = bdb2i_index_read( be, ava->ava_type, INDEX_EQUALITY,
+ ava->ava_value.bv_val );
+ break;
+
+ case LDAP_FILTER_GE:
+ idl = bdb2i_idl_allids( be );
+ break;
+
+ case LDAP_FILTER_LE:
+ idl = bdb2i_idl_allids( be );
+ break;
+ }
+
+ Debug( LDAP_DEBUG_TRACE, "<= ava_candidates %lu\n",
+ idl ? ID_BLOCK_NIDS(idl) : 0, 0, 0 );
+ return( idl );
+}
+
+static ID_BLOCK *
+presence_candidates(
+ Backend *be,
+ char *type
+)
+{
+ ID_BLOCK *idl;
+
+ Debug( LDAP_DEBUG_TRACE, "=> presence_candidates\n", 0, 0, 0 );
+
+ idl = bdb2i_index_read( be, type, 0, "*" );
+
+ Debug( LDAP_DEBUG_TRACE, "<= presence_candidates %lu\n",
+ idl ? ID_BLOCK_NIDS(idl) : 0, 0, 0 );
+ return( idl );
+}
+
+static ID_BLOCK *
+approx_candidates(
+ Backend *be,
+ Ava *ava
+)
+{
+ char *w, *c;
+ ID_BLOCK *idl, *tmp;
+
+ Debug( LDAP_DEBUG_TRACE, "=> approx_candidates\n", 0, 0, 0 );
+
+ idl = NULL;
+ for ( w = first_word( ava->ava_value.bv_val ); w != NULL;
+ w = next_word( w ) ) {
+ c = phonetic( w );
+ if ( (tmp = bdb2i_index_read( be, ava->ava_type, INDEX_APPROX, c ))
+ == NULL ) {
+ free( c );
+ bdb2i_idl_free( idl );
+ Debug( LDAP_DEBUG_TRACE, "<= approx_candidates NULL\n",
+ 0, 0, 0 );
+ return( NULL );
+ }
+ free( c );
+
+ if ( idl == NULL ) {
+ idl = tmp;
+ } else {
+ idl = bdb2i_idl_intersection( be, idl, tmp );
+ }
+ }
+
+ Debug( LDAP_DEBUG_TRACE, "<= approx_candidates %lu\n",
+ idl ? ID_BLOCK_NIDS(idl) : 0, 0, 0 );
+ return( idl );
+}
+
+static ID_BLOCK *
+list_candidates(
+ Backend *be,
+ Filter *flist,
+ int ftype
+)
+{
+ ID_BLOCK *idl, *tmp, *tmp2;
+ Filter *f;
+
+ Debug( LDAP_DEBUG_TRACE, "=> list_candidates 0x%x\n", ftype, 0, 0 );
+
+ idl = NULL;
+ for ( f = flist; f != NULL; f = f->f_next ) {
+ if ( (tmp = bdb2i_filter_candidates( be, f )) == NULL &&
+ ftype == LDAP_FILTER_AND ) {
+ Debug( LDAP_DEBUG_TRACE,
+ "<= list_candidates NULL\n", 0, 0, 0 );
+ bdb2i_idl_free( idl );
+ return( NULL );
+ }
+
+ tmp2 = idl;
+ if ( idl == NULL ) {
+ idl = tmp;
+ } else if ( ftype == LDAP_FILTER_AND ) {
+ idl = bdb2i_idl_intersection( be, idl, tmp );
+ bdb2i_idl_free( tmp );
+ bdb2i_idl_free( tmp2 );
+ } else {
+ idl = bdb2i_idl_union( be, idl, tmp );
+ bdb2i_idl_free( tmp );
+ bdb2i_idl_free( tmp2 );
+ }
+ }
+
+ Debug( LDAP_DEBUG_TRACE, "<= list_candidates %lu\n",
+ idl ? ID_BLOCK_NIDS(idl) : 0, 0, 0 );
+ return( idl );
+}
+
+static ID_BLOCK *
+substring_candidates(
+ Backend *be,
+ Filter *f
+)
+{
+ int i;
+ ID_BLOCK *idl, *tmp, *tmp2;
+
+ Debug( LDAP_DEBUG_TRACE, "=> substring_candidates\n", 0, 0, 0 );
+
+ idl = NULL;
+
+ /* initial */
+ if ( f->f_sub_initial != NULL ) {
+ if ( (int) strlen( f->f_sub_initial ) < SUBLEN - 1 ) {
+ idl = bdb2i_idl_allids( be );
+ } else if ( (idl = substring_comp_candidates( be, f->f_sub_type,
+ f->f_sub_initial, '^' )) == NULL ) {
+ return( NULL );
+ }
+ }
+
+ /* final */
+ if ( f->f_sub_final != NULL ) {
+ if ( (int) strlen( f->f_sub_final ) < SUBLEN - 1 ) {
+ tmp = bdb2i_idl_allids( be );
+ } else if ( (tmp = substring_comp_candidates( be, f->f_sub_type,
+ f->f_sub_final, '$' )) == NULL ) {
+ bdb2i_idl_free( idl );
+ return( NULL );
+ }
+
+ if ( idl == NULL ) {
+ idl = tmp;
+ } else {
+ tmp2 = idl;
+ idl = bdb2i_idl_intersection( be, idl, tmp );
+ bdb2i_idl_free( tmp );
+ bdb2i_idl_free( tmp2 );
+ }
+ }
+
+ for ( i = 0; f->f_sub_any != NULL && f->f_sub_any[i] != NULL; i++ ) {
+ if ( (int) strlen( f->f_sub_any[i] ) < SUBLEN ) {
+ tmp = bdb2i_idl_allids( be );
+ } else if ( (tmp = substring_comp_candidates( be, f->f_sub_type,
+ f->f_sub_any[i], 0 )) == NULL ) {
+ bdb2i_idl_free( idl );
+ return( NULL );
+ }
+
+ if ( idl == NULL ) {
+ idl = tmp;
+ } else {
+ tmp2 = idl;
+ idl = bdb2i_idl_intersection( be, idl, tmp );
+ bdb2i_idl_free( tmp );
+ bdb2i_idl_free( tmp2 );
+ }
+ }
+
+ Debug( LDAP_DEBUG_TRACE, "<= substring_candidates %lu\n",
+ idl ? ID_BLOCK_NIDS(idl) : 0, 0, 0 );
+ return( idl );
+}
+
+static ID_BLOCK *
+substring_comp_candidates(
+ Backend *be,
+ char *type,
+ char *val,
+ int prepost
+)
+{
+ int i, len;
+ ID_BLOCK *idl, *tmp, *tmp2;
+ char *p;
+ char buf[SUBLEN + 1];
+
+ Debug( LDAP_DEBUG_TRACE, "=> substring_comp_candidates\n", 0, 0, 0 );
+
+ len = strlen( val );
+ idl = NULL;
+
+ /* prepend ^ for initial substring */
+ if ( prepost == '^' ) {
+ buf[0] = '^';
+ for ( i = 0; i < SUBLEN - 1; i++ ) {
+ buf[i + 1] = val[i];
+ }
+ buf[SUBLEN] = '\0';
+
+ if ( (idl = bdb2i_index_read( be, type, INDEX_SUB, buf )) == NULL ) {
+ return( NULL );
+ }
+ } else if ( prepost == '$' ) {
+ p = val + len - SUBLEN + 1;
+ for ( i = 0; i < SUBLEN - 1; i++ ) {
+ buf[i] = p[i];
+ }
+ buf[SUBLEN - 1] = '$';
+ buf[SUBLEN] = '\0';
+
+ if ( (idl = bdb2i_index_read( be, type, INDEX_SUB, buf )) == NULL ) {
+ return( NULL );
+ }
+ }
+
+ for ( p = val; p < (val + len - SUBLEN + 1); p++ ) {
+ for ( i = 0; i < SUBLEN; i++ ) {
+ buf[i] = p[i];
+ }
+ buf[SUBLEN] = '\0';
+
+ if ( (tmp = bdb2i_index_read( be, type, INDEX_SUB, buf )) == NULL ) {
+ bdb2i_idl_free( idl );
+ return( NULL );
+ }
+
+ if ( idl == NULL ) {
+ idl = tmp;
+ } else {
+ tmp2 = idl;
+ idl = bdb2i_idl_intersection( be, idl, tmp );
+ bdb2i_idl_free( tmp );
+ bdb2i_idl_free( tmp2 );
+ }
+ }
+
+ Debug( LDAP_DEBUG_TRACE, "<= substring_comp_candidates %lu\n",
+ idl ? ID_BLOCK_NIDS(idl) : 0, 0, 0 );
+ return( idl );
+}
--- /dev/null
+/* group.c - bdb2 backend acl group routine */
+
+#include "portable.h"
+
+#include <stdio.h>
+
+#include <ac/socket.h>
+#include <ac/string.h>
+
+#include "slap.h"
+#include "back-bdb2.h"
+#include "proto-back-bdb2.h"
+
+
+#ifdef SLAPD_ACLGROUPS
+/* return 0 IFF op_dn is a value in member attribute
+ * of entry with gr_dn AND that entry has an objectClass
+ * value of groupOfNames
+ */
+static int
+bdb2i_back_group_internal(
+ Backend *be,
+ Entry *target,
+ char *gr_ndn,
+ char *op_ndn,
+ char *objectclassValue,
+ char *groupattrName
+)
+{
+ struct ldbminfo *li = (struct ldbminfo *) be->be_private;
+ Entry *e;
+ char *matched;
+ Attribute *objectClass;
+ Attribute *member;
+ int rc;
+
+ Debug( LDAP_DEBUG_TRACE,
+ "=> bdb2i_back_group: gr dn: \"%s\"\n",
+ gr_ndn, 0, 0 );
+ Debug( LDAP_DEBUG_TRACE,
+ "=> bdb2i_back_group: op dn: \"%s\"\n",
+ op_ndn, 0, 0 );
+ Debug( LDAP_DEBUG_TRACE,
+ "=> bdb2i_back_group: objectClass: \"%s\" attrName: \"%s\"\n",
+ objectclassValue, groupattrName, 0 );
+
+ Debug( LDAP_DEBUG_TRACE,
+ "=> bdb2i_back_group: tr dn: \"%s\"\n",
+ target->e_ndn, 0, 0 );
+
+ if (strcmp(target->e_ndn, gr_ndn) == 0) {
+ /* we already have a LOCKED copy of the entry */
+ e = target;
+ Debug( LDAP_DEBUG_ARGS,
+ "=> bdb2i_back_group: target is group: \"%s\"\n",
+ gr_ndn, 0, 0 );
+ } else {
+ /* can we find group entry with reader lock */
+ if ((e = bdb2i_dn2entry_r(be, gr_ndn, &matched )) == NULL) {
+ Debug( LDAP_DEBUG_TRACE,
+ "=> bdb2i_back_group: cannot find group: \"%s\" matched: \"%s\"\n",
+ gr_ndn, (matched ? matched : ""), 0 );
+ if (matched != NULL)
+ free(matched);
+ return( 1 );
+ }
+ Debug( LDAP_DEBUG_ARGS,
+ "=> bdb2i_back_group: found group: \"%s\"\n",
+ gr_ndn, 0, 0 );
+ }
+
+
+ /* check for deleted */
+
+ /* find it's objectClass and member attribute values
+ * make sure this is a group entry
+ * finally test if we can find op_dn in the member attribute value list *
+ */
+
+ rc = 1;
+ if ((objectClass = attr_find(e->e_attrs, "objectclass")) == NULL) {
+ Debug( LDAP_DEBUG_TRACE, "<= bdb2i_back_group: failed to find objectClass\n", 0, 0, 0 );
+ }
+ else if ((member = attr_find(e->e_attrs, groupattrName)) == NULL) {
+ Debug( LDAP_DEBUG_TRACE, "<= bdb2i_back_group: failed to find %s\n", groupattrName, 0, 0 );
+ }
+ else {
+ struct berval bvObjectClass;
+ struct berval bvMembers;
+
+ Debug( LDAP_DEBUG_ARGS, "<= bdb2i_back_group: found objectClass and %s\n", groupattrName, 0, 0 );
+
+ bvObjectClass.bv_val = objectclassValue;
+ bvObjectClass.bv_len = strlen( bvObjectClass.bv_val );
+
+ bvMembers.bv_val = op_ndn;
+ bvMembers.bv_len = strlen( op_ndn );
+
+ if (value_find(objectClass->a_vals, &bvObjectClass, SYNTAX_CIS, 1) != 0) {
+ Debug( LDAP_DEBUG_TRACE,
+ "<= bdb2i_back_group: failed to find %s in objectClass\n",
+ objectclassValue, 0, 0 );
+ }
+ else if (value_find(member->a_vals, &bvMembers, SYNTAX_CIS, 1) != 0) {
+ Debug( LDAP_DEBUG_ACL,
+ "<= bdb2i_back_group: \"%s\" not in \"%s\": %s\n",
+ op_ndn, gr_ndn, groupattrName );
+ }
+ else {
+ Debug( LDAP_DEBUG_ACL,
+ "<= bdb2i_back_group: \"%s\" is in \"%s\": %s\n",
+ op_ndn, gr_ndn, groupattrName );
+ rc = 0;
+ }
+ }
+
+ if( target != e ) {
+ /* free entry and reader lock */
+ bdb2i_cache_return_entry_r( &li->li_cache, e );
+ }
+
+ Debug( LDAP_DEBUG_ARGS, "bdb2i_back_group: rc: %d\n", rc, 0, 0 );
+ return(rc);
+}
+
+
+int
+bdb2_back_group(
+ Backend *be,
+ Entry *target,
+ char *gr_ndn,
+ char *op_ndn,
+ char *objectclassValue,
+ char *groupattrName
+)
+{
+ DB_LOCK lock;
+ struct ldbminfo *li = (struct ldbminfo *) be->be_private;
+
+ struct timeval time1, time2;
+ char *elapsed_time;
+ int ret;
+
+ gettimeofday( &time1, NULL );
+
+ if ( bdb2i_enter_backend_r( &li->li_db_env, &lock ) != 0 ) {
+
+ return( 1 );
+
+ }
+
+ ret = bdb2i_back_group_internal( be, target, gr_ndn, op_ndn,
+ objectclassValue, groupattrName );
+
+ (void) bdb2i_leave_backend( &li->li_db_env, lock );
+
+ if ( bdb2i_do_timing ) {
+
+ gettimeofday( &time2, NULL);
+ elapsed_time = bdb2i_elapsed( time1, time2 );
+ Debug( LDAP_DEBUG_ANY, "GRP elapsed=%s\n",
+ elapsed_time, 0, 0 );
+ free( elapsed_time );
+
+ }
+
+ return( ret );
+}
+
+#endif /* SLAPD_ACLGROUPS */
+
--- /dev/null
+/* id2children.c - routines to deal with the id2children index */
+
+#include "portable.h"
+
+#include <stdio.h>
+#include <ac/string.h>
+
+#include <ac/socket.h>
+
+#include "slap.h"
+#include "back-bdb2.h"
+
+int
+bdb2i_id2children_add(
+ Backend *be,
+ Entry *p,
+ Entry *e
+)
+{
+ struct dbcache *db;
+ Datum key;
+ int len, rc;
+ ID_BLOCK *idl;
+ char buf[20];
+
+ ldbm_datum_init( key );
+
+ Debug( LDAP_DEBUG_TRACE, "=> bdb2i_id2children_add( %lu, %lu )\n",
+ p ? p->e_id : 0, e->e_id, 0 );
+
+ if ( (db = bdb2i_cache_open( be, "id2children", LDBM_SUFFIX,
+ LDBM_WRCREAT )) == NULL ) {
+ Debug( LDAP_DEBUG_ANY,
+ "<= bdb2i_id2children_add -1 could not open \"id2children%s\"\n",
+ LDBM_SUFFIX, 0, 0 );
+ return( -1 );
+ }
+
+ sprintf( buf, "%c%ld", EQ_PREFIX, p ? p->e_id : 0 );
+ key.dptr = buf;
+ key.dsize = strlen( buf ) + 1;
+
+ if ( bdb2i_idl_insert_key( be, db, key, e->e_id ) != 0 ) {
+ Debug( LDAP_DEBUG_TRACE, "<= bdb2i_id2children_add -1 (idl_insert)\n",
+ 0, 0, 0 );
+ bdb2i_cache_close( be, db );
+ return( -1 );
+ }
+
+ bdb2i_cache_close( be, db );
+
+ Debug( LDAP_DEBUG_TRACE, "<= bdb2i_id2children_add 0\n", 0, 0, 0 );
+ return( 0 );
+}
+
+
+int
+bdb2i_id2children_remove(
+ Backend *be,
+ Entry *p,
+ Entry *e
+)
+{
+ struct dbcache *db;
+ Datum key;
+ int len, rc;
+ ID_BLOCK *idl;
+ char buf[20];
+
+ Debug( LDAP_DEBUG_TRACE, "=> bdb2i_id2children_remove( %lu, %lu )\n",
+ p ? p->e_id : 0, e->e_id, 0 );
+
+ if ( (db = bdb2i_cache_open( be, "id2children", LDBM_SUFFIX,
+ LDBM_WRCREAT )) == NULL ) {
+ Debug( LDAP_DEBUG_ANY,
+ "<= bdb2i_id2children_remove -1 could not open \"id2children%s\"\n",
+ LDBM_SUFFIX, 0, 0 );
+ return( -1 );
+ }
+
+ ldbm_datum_init( key );
+ sprintf( buf, "%c%ld", EQ_PREFIX, p ? p->e_id : 0 );
+ key.dptr = buf;
+ key.dsize = strlen( buf ) + 1;
+
+ if ( bdb2i_idl_delete_key( be, db, key, e->e_id ) != 0 ) {
+ Debug( LDAP_DEBUG_TRACE, "<= bdb2i_id2children_remove -1 (idl_delete)\n",
+ 0, 0, 0 );
+ bdb2i_cache_close( be, db );
+ return( -1 );
+ }
+
+ bdb2i_cache_close( be, db );
+
+ Debug( LDAP_DEBUG_TRACE, "<= bdb2i_id2children_remove 0\n", 0, 0, 0 );
+ return( 0 );
+}
+
+int
+bdb2i_has_children(
+ Backend *be,
+ Entry *p
+)
+{
+ struct dbcache *db;
+ Datum key;
+ int rc = 0;
+ ID_BLOCK *idl;
+ char buf[20];
+
+ ldbm_datum_init( key );
+
+ Debug( LDAP_DEBUG_TRACE, "=> bdb2i_has_children( %lu )\n", p->e_id , 0, 0 );
+
+ if ( (db = bdb2i_cache_open( be, "id2children", LDBM_SUFFIX,
+ LDBM_WRCREAT )) == NULL ) {
+ Debug( LDAP_DEBUG_ANY,
+ "<= bdb2i_has_children -1 could not open \"id2children%s\"\n",
+ LDBM_SUFFIX, 0, 0 );
+ return( 0 );
+ }
+
+ sprintf( buf, "%c%ld", EQ_PREFIX, p->e_id );
+ key.dptr = buf;
+ key.dsize = strlen( buf ) + 1;
+
+ idl = bdb2i_idl_fetch( be, db, key );
+
+ bdb2i_cache_close( be, db );
+
+ if( idl != NULL ) {
+ bdb2i_idl_free( idl );
+ rc = 1;
+ }
+
+ Debug( LDAP_DEBUG_TRACE, "<= bdb2i_has_children( %lu ): %s\n",
+ p->e_id, rc ? "yes" : "no", 0 );
+ return( rc );
+}
--- /dev/null
+/* id2entry.c - routines to deal with the id2entry index */
+
+#include "portable.h"
+
+#include <stdio.h>
+
+#include <ac/socket.h>
+
+#include "slap.h"
+#include "back-bdb2.h"
+
+int
+bdb2i_id2entry_add( Backend *be, Entry *e )
+{
+ struct ldbminfo *li = (struct ldbminfo *) be->be_private;
+ struct dbcache *db;
+ Datum key, data;
+ int len, rc, flags;
+
+ ldbm_datum_init( key );
+ ldbm_datum_init( data );
+
+ Debug( LDAP_DEBUG_TRACE, "=> bdb2i_id2entry_add( %lu, \"%s\" )\n", e->e_id,
+ e->e_dn, 0 );
+
+ if ( (db = bdb2i_cache_open( be, "id2entry", LDBM_SUFFIX, LDBM_WRCREAT ))
+ == NULL ) {
+ Debug( LDAP_DEBUG_ANY, "Could not open/create id2entry%s\n",
+ LDBM_SUFFIX, 0, 0 );
+ return( -1 );
+ }
+
+ key.dptr = (char *) &e->e_id;
+ key.dsize = sizeof(ID);
+
+ ldap_pvt_thread_mutex_lock( &entry2str_mutex );
+ data.dptr = entry2str( e, &len, 1 );
+ data.dsize = len + 1;
+
+ /* store it */
+ flags = LDBM_REPLACE;
+ if ( li->li_dbcachewsync ) flags |= LDBM_SYNC;
+ rc = bdb2i_cache_store( db, key, data, flags );
+
+ ldap_pvt_thread_mutex_unlock( &entry2str_mutex );
+
+ bdb2i_cache_close( be, db );
+ (void) bdb2i_cache_add_entry_lock( &li->li_cache, e, 0 );
+
+ Debug( LDAP_DEBUG_TRACE, "<= bdb2i_id2entry_add %d\n", rc, 0, 0 );
+
+ /* XXX should entries be born locked, i.e. apply writer lock here? */
+ return( rc );
+}
+
+int
+bdb2i_id2entry_delete( Backend *be, Entry *e )
+{
+ struct ldbminfo *li = (struct ldbminfo *) be->be_private;
+ struct dbcache *db;
+ Datum key;
+ int rc;
+
+ Debug(LDAP_DEBUG_TRACE, "=> bdb2i_id2entry_delete( %lu, \"%s\" )\n", e->e_id,
+ e->e_dn, 0 );
+
+#ifdef LDAP_DEBUG
+ /* check for writer lock */
+ assert(ldap_pvt_thread_rdwr_writers(&e->e_rdwr));
+#endif
+
+ ldbm_datum_init( key );
+
+ if ( (db = bdb2i_cache_open( be, "id2entry", LDBM_SUFFIX, LDBM_WRCREAT ))
+ == NULL ) {
+ Debug( LDAP_DEBUG_ANY, "Could not open/create id2entry%s\n",
+ LDBM_SUFFIX, 0, 0 );
+ return( -1 );
+ }
+
+ if ( bdb2i_cache_delete_entry( &li->li_cache, e ) != 0 ) {
+ Debug(LDAP_DEBUG_ANY, "could not delete %lu (%s) from cache\n",
+ e->e_id, e->e_dn, 0 );
+ }
+
+ key.dptr = (char *) &e->e_id;
+ key.dsize = sizeof(ID);
+
+ rc = bdb2i_cache_delete( db, key );
+
+ bdb2i_cache_close( be, db );
+
+ Debug( LDAP_DEBUG_TRACE, "<= bdb2i_id2entry_delete %d\n", rc, 0, 0 );
+ return( rc );
+}
+
+/* XXX returns entry with reader/writer lock */
+Entry *
+bdb2i_id2entry( Backend *be, ID id, int rw )
+{
+ struct ldbminfo *li = (struct ldbminfo *) be->be_private;
+ struct dbcache *db;
+ Datum key, data;
+ Entry *e;
+
+ ldbm_datum_init( key );
+ ldbm_datum_init( data );
+
+ Debug( LDAP_DEBUG_TRACE, "=> bdb2i_id2entry_%s( %ld )\n",
+ rw ? "w" : "r", id, 0 );
+
+ if ( (e = bdb2i_cache_find_entry_id( &li->li_cache, id, rw )) != NULL ) {
+ Debug( LDAP_DEBUG_TRACE, "<= bdb2i_id2entry_%s 0x%lx (cache)\n",
+ rw ? "w" : "r", (unsigned long)e, 0 );
+ return( e );
+ }
+
+ if ( (db = bdb2i_cache_open( be, "id2entry", LDBM_SUFFIX, LDBM_WRCREAT ))
+ == NULL ) {
+ Debug( LDAP_DEBUG_ANY, "Could not open id2entry%s\n",
+ LDBM_SUFFIX, 0, 0 );
+ return( NULL );
+ }
+
+ key.dptr = (char *) &id;
+ key.dsize = sizeof(ID);
+
+ data = bdb2i_cache_fetch( db, key );
+
+ if ( data.dptr == NULL ) {
+ Debug( LDAP_DEBUG_TRACE, "<= bdb2i_id2entry_%s( %ld ) not found\n",
+ rw ? "w" : "r", id, 0 );
+ bdb2i_cache_close( be, db );
+ return( NULL );
+ }
+
+ e = str2entry( data.dptr );
+
+ ldbm_datum_free( db->dbc_db, data );
+ bdb2i_cache_close( be, db );
+
+ if ( e == NULL ) {
+ Debug( LDAP_DEBUG_TRACE, "<= bdb2i_id2entry_%s( %ld ) (failed)\n",
+ rw ? "w" : "r", id, 0 );
+ return( NULL );
+ }
+
+ /* acquire required reader/writer lock */
+ if (entry_rdwr_lock(e, rw)) {
+ /* XXX set DELETE flag?? */
+ entry_free(e);
+ return(NULL);
+ }
+
+ e->e_id = id;
+ (void) bdb2i_cache_add_entry_lock( &li->li_cache, e, 0 );
+
+ Debug( LDAP_DEBUG_TRACE, "<= bdb2i_id2entry_%s( %ld ) (disk)\n",
+ rw ? "w" : "r", id, 0 );
+ return( e );
+}
+
+Entry *
+bdb2i_id2entry_r( Backend *be, ID id )
+{
+ return( bdb2i_id2entry( be, id, 0 ) );
+}
+
+Entry *
+bdb2i_id2entry_w( Backend *be, ID id )
+{
+ return( bdb2i_id2entry( be, id, 1 ) );
+}
+
--- /dev/null
+/* idl.c - ldap id list handling routines */
+
+#include "portable.h"
+
+#include <stdio.h>
+
+#include <ac/string.h>
+#include <ac/socket.h>
+
+#include "ldapconfig.h"
+#include "slap.h"
+#include "back-bdb2.h"
+
+static ID_BLOCK* idl_dup( ID_BLOCK *idl );
+
+/* Allocate an ID_BLOCK with room for nids ids */
+ID_BLOCK *
+bdb2i_idl_alloc( int nids )
+{
+ ID_BLOCK *new;
+
+ /* nmax + nids + space for the ids */
+ new = (ID_BLOCK *) ch_calloc( (ID_BLOCK_IDS_OFFSET + nids), sizeof(ID) );
+ ID_BLOCK_NMAX(new) = nids;
+ ID_BLOCK_NIDS(new) = 0;
+
+ return( new );
+}
+
+
+/* Allocate an empty ALLIDS ID_BLOCK */
+ID_BLOCK *
+bdb2i_idl_allids( Backend *be )
+{
+ ID_BLOCK *idl;
+
+ idl = bdb2i_idl_alloc( 0 );
+ ID_BLOCK_NMAX(idl) = ID_BLOCK_ALLIDS_VALUE;
+ ID_BLOCK_NIDS(idl) = bdb2i_next_id_get( be );
+
+ return( idl );
+}
+
+
+/* Free an ID_BLOCK */
+void
+bdb2i_idl_free( ID_BLOCK *idl )
+{
+ if ( idl == NULL ) {
+ Debug( LDAP_DEBUG_TRACE,
+ "bdb2i_idl_free: called with NULL pointer\n",
+ 0, 0, 0 );
+ return;
+ }
+
+ free( (char *) idl );
+}
+
+
+/* Fetch an single ID_BLOCK from the cache */
+static ID_BLOCK *
+idl_fetch_one(
+ Backend *be,
+ struct dbcache *db,
+ Datum key
+)
+{
+ Datum data;
+ ID_BLOCK *idl;
+
+ ldbm_datum_init( data );
+
+ /* Debug( LDAP_DEBUG_TRACE, "=> idl_fetch_one\n", 0, 0, 0 ); */
+
+ data = bdb2i_cache_fetch( db, key );
+
+ if( data.dptr == NULL ) {
+ return NULL;
+ }
+
+ idl = idl_dup( (ID_BLOCK *) data.dptr);
+ ldbm_datum_free( db->dbc_db, data );
+
+ return( idl );
+}
+
+
+/* Fetch a set of ID_BLOCKs from the cache
+ * if not INDIRECT
+ * if block return is an ALLIDS block,
+ * return an new ALLIDS block
+ * otherwise
+ * return block
+ * construct super block from all blocks referenced by INDIRECT block
+ * return super block
+ */
+ID_BLOCK *
+bdb2i_idl_fetch(
+ Backend *be,
+ struct dbcache *db,
+ Datum key
+)
+{
+ Datum data;
+ ID_BLOCK *idl;
+ ID_BLOCK **tmp;
+ char *kstr;
+ int i, nids;
+
+ idl = idl_fetch_one( be, db, key );
+
+ if ( idl == NULL ) {
+ return NULL;
+ }
+
+ if ( ID_BLOCK_ALLIDS(idl) ) {
+ /* all ids block */
+ /* make sure we have the current value of highest id */
+ bdb2i_idl_free( idl );
+ idl = bdb2i_idl_allids( be );
+
+ return( idl );
+ }
+
+ if ( ! ID_BLOCK_INDIRECT( idl ) ) {
+ /* regular block */
+ return( idl );
+ }
+
+ /*
+ * this is an indirect block which points to other blocks.
+ * we need to read in all the blocks it points to and construct
+ * a big id list containing all the ids, which we will return.
+ */
+
+ /* count the number of blocks & allocate space for pointers to them */
+ for ( i = 0; !ID_BLOCK_NOID(idl, i); i++ )
+ ; /* NULL */
+ tmp = (ID_BLOCK **) ch_malloc( (i + 1) * sizeof(ID_BLOCK *) );
+
+ /* read in all the blocks */
+ kstr = (char *) ch_malloc( key.dsize + 20 );
+ nids = 0;
+ for ( i = 0; !ID_BLOCK_NOID(idl, i); i++ ) {
+ ldbm_datum_init( data );
+
+ sprintf( kstr, "%c%s%ld", CONT_PREFIX, key.dptr, ID_BLOCK_ID(idl, i) );
+ data.dptr = kstr;
+ data.dsize = strlen( kstr ) + 1;
+
+ if ( (tmp[i] = idl_fetch_one( be, db, data )) == NULL ) {
+ Debug( LDAP_DEBUG_ANY,
+ "idl_fetch of (%s) returns NULL\n", data.dptr, 0, 0 );
+ continue;
+ }
+
+ nids += ID_BLOCK_NIDS(tmp[i]);
+ }
+ tmp[i] = NULL;
+ free( kstr );
+ bdb2i_idl_free( idl );
+
+ /* allocate space for the big block */
+ idl = bdb2i_idl_alloc( nids );
+ ID_BLOCK_NIDS(idl) = nids;
+ nids = 0;
+
+ /* copy in all the ids from the component blocks */
+ for ( i = 0; tmp[i] != NULL; i++ ) {
+ if ( tmp[i] == NULL ) {
+ continue;
+ }
+
+ SAFEMEMCPY(
+ (char *) &ID_BLOCK_ID(idl, nids),
+ (char *) &ID_BLOCK_ID(tmp[i], 0),
+ ID_BLOCK_NIDS(tmp[i]) * sizeof(ID) );
+ nids += ID_BLOCK_NIDS(tmp[i]);
+
+ bdb2i_idl_free( tmp[i] );
+ }
+ free( (char *) tmp );
+
+ Debug( LDAP_DEBUG_TRACE, "<= bdb2i_idl_fetch %lu ids (%lu max)\n",
+ ID_BLOCK_NIDS(idl), ID_BLOCK_NMAX(idl), 0 );
+ return( idl );
+}
+
+
+/* store a single block */
+static int
+idl_store(
+ Backend *be,
+ struct dbcache *db,
+ Datum key,
+ ID_BLOCK *idl
+)
+{
+ int rc, flags;
+ Datum data;
+ struct ldbminfo *li = (struct ldbminfo *) be->be_private;
+
+ ldbm_datum_init( data );
+
+ /* Debug( LDAP_DEBUG_TRACE, "=> idl_store\n", 0, 0, 0 ); */
+
+ data.dptr = (char *) idl;
+ data.dsize = (ID_BLOCK_IDS_OFFSET + ID_BLOCK_NMAX(idl)) * sizeof(ID);
+
+#ifdef LDBM_DEBUG
+ Statslog( LDAP_DEBUG_STATS, "<= idl_store(): rc=%d\n",
+ rc, 0, 0, 0, 0 );
+#endif
+
+ flags = LDBM_REPLACE;
+ if( li->li_dbcachewsync ) flags |= LDBM_SYNC;
+ rc = bdb2i_cache_store( db, key, data, flags );
+
+ /* Debug( LDAP_DEBUG_TRACE, "<= idl_store %d\n", rc, 0, 0 ); */
+ return( rc );
+}
+
+
+/* split the block at id
+ * locate ID greater than or equal to id.
+ */
+static void
+idl_split_block(
+ ID_BLOCK *b,
+ ID id,
+ ID_BLOCK **right,
+ ID_BLOCK **left
+)
+{
+ unsigned int nr, nl;
+
+ /* find where to split the block *//* XXX linear search XXX */
+ for ( nr = 0; nr < ID_BLOCK_NIDS(b) && id > ID_BLOCK_ID(b, nr); nr++ )
+ ; /* NULL */
+
+ nl = ID_BLOCK_NIDS(b) - nr;
+
+ *right = bdb2i_idl_alloc( nr == 0 ? 1 : nr );
+ *left = bdb2i_idl_alloc( nl + (nr == 0 ? 0 : 1));
+
+ /*
+ * everything before the id being inserted in the first block
+ * unless there is nothing, in which case the id being inserted
+ * goes there.
+ */
+ if ( nr == 0 ) {
+ ID_BLOCK_NIDS(*right) = 1;
+ ID_BLOCK_ID(*right, 0) = id;
+ } else {
+ SAFEMEMCPY(
+ (char *) &ID_BLOCK_ID(*right, 0),
+ (char *) &ID_BLOCK_ID(b, 0),
+ nr * sizeof(ID) );
+ ID_BLOCK_NIDS(*right) = nr;
+ ID_BLOCK_ID(*left, 0) = id;
+ }
+
+ /* the id being inserted & everything after in the second block */
+ SAFEMEMCPY(
+ (char *) &ID_BLOCK_ID(*left, (nr == 0 ? 0 : 1)),
+ (char *) &ID_BLOCK_ID(b, nr),
+ nl * sizeof(ID) );
+ ID_BLOCK_NIDS(*left) = nl + (nr == 0 ? 0 : 1);
+}
+
+
+/*
+ * idl_change_first - called when an indirect block's first key has
+ * changed, meaning it needs to be stored under a new key, and the
+ * header block pointing to it needs updating.
+ */
+static int
+idl_change_first(
+ Backend *be,
+ struct dbcache *db,
+ Datum hkey, /* header block key */
+ ID_BLOCK *h, /* header block */
+ int pos, /* pos in h to update */
+ Datum bkey, /* data block key */
+ ID_BLOCK *b /* data block */
+)
+{
+ int rc;
+
+ /* Debug( LDAP_DEBUG_TRACE, "=> idl_change_first\n", 0, 0, 0 ); */
+
+ /* delete old key block */
+ if ( (rc = bdb2i_cache_delete( db, bkey )) != 0 ) {
+ Debug( LDAP_DEBUG_ANY,
+ "ldbm_delete of (%s) returns %d\n", bkey.dptr, rc,
+ 0 );
+ return( rc );
+ }
+
+ /* write block with new key */
+ sprintf( bkey.dptr, "%c%s%ld", CONT_PREFIX, hkey.dptr, ID_BLOCK_ID(b, 0) );
+ bkey.dsize = strlen( bkey.dptr ) + 1;
+ if ( (rc = idl_store( be, db, bkey, b )) != 0 ) {
+ Debug( LDAP_DEBUG_ANY,
+ "idl_store of (%s) returns %d\n", bkey.dptr, rc, 0 );
+ return( rc );
+ }
+
+ /* update + write indirect header block */
+ ID_BLOCK_ID(h, pos) = ID_BLOCK_ID(b, 0);
+ if ( (rc = idl_store( be, db, hkey, h )) != 0 ) {
+ Debug( LDAP_DEBUG_ANY,
+ "idl_store of (%s) returns %d\n", hkey.dptr, rc, 0 );
+ return( rc );
+ }
+
+ return( 0 );
+}
+
+
+int
+bdb2i_idl_insert_key(
+ Backend *be,
+ struct dbcache *db,
+ Datum key,
+ ID id
+)
+{
+ int i, j, first, rc;
+ ID_BLOCK *idl, *tmp, *tmp2, *tmp3;
+ char *kstr;
+ Datum k2;
+
+ ldbm_datum_init( k2 );
+
+ if ( (idl = idl_fetch_one( be, db, key )) == NULL ) {
+#ifdef LDBM_DEBUG
+ Statslog( LDAP_DEBUG_STATS, "=> bdb2i_idl_insert_key(): no key yet\n",
+ 0, 0, 0, 0, 0 );
+#endif
+
+ idl = bdb2i_idl_alloc( 1 );
+ ID_BLOCK_ID(idl, ID_BLOCK_NIDS(idl)++) = id;
+ rc = idl_store( be, db, key, idl );
+
+ bdb2i_idl_free( idl );
+ return( rc );
+ }
+
+ if ( ID_BLOCK_ALLIDS( idl ) ) {
+ /* ALLIDS */
+ bdb2i_idl_free( idl );
+ return 0;
+ }
+
+ if ( ! ID_BLOCK_INDIRECT( idl ) ) {
+ /* regular block */
+ switch ( bdb2i_idl_insert( &idl, id, db->dbc_maxids ) ) {
+ case 0: /* id inserted - store the updated block */
+ case 1:
+ rc = idl_store( be, db, key, idl );
+ break;
+
+ case 2: /* id already there - nothing to do */
+ rc = 0;
+ break;
+
+ case 3: /* id not inserted - block must be split */
+ /* check threshold for marking this an all-id block */
+ if ( db->dbc_maxindirect < 2 ) {
+ bdb2i_idl_free( idl );
+ idl = bdb2i_idl_allids( be );
+ rc = idl_store( be, db, key, idl );
+ bdb2i_idl_free( idl );
+
+ return( rc );
+ }
+
+ idl_split_block( idl, id, &tmp, &tmp2 );
+ bdb2i_idl_free( idl );
+
+ /* create the header indirect block */
+ idl = bdb2i_idl_alloc( 3 );
+ ID_BLOCK_NMAX(idl) = 3;
+ ID_BLOCK_NIDS(idl) = ID_BLOCK_INDIRECT_VALUE;
+ ID_BLOCK_ID(idl, 0) = ID_BLOCK_ID(tmp, 0);
+ ID_BLOCK_ID(idl, 1) = ID_BLOCK_ID(tmp2, 0);
+ ID_BLOCK_ID(idl, 2) = NOID;
+
+ /* store it */
+ rc = idl_store( be, db, key, idl );
+
+ /* store the first id block */
+ kstr = (char *) ch_malloc( key.dsize + 20 );
+ sprintf( kstr, "%c%s%ld", CONT_PREFIX, key.dptr,
+ ID_BLOCK_ID(tmp, 0) );
+ k2.dptr = kstr;
+ k2.dsize = strlen( kstr ) + 1;
+ rc = idl_store( be, db, k2, tmp );
+
+ /* store the second id block */
+ sprintf( kstr, "%c%s%ld", CONT_PREFIX, key.dptr,
+ ID_BLOCK_ID(tmp2, 0) );
+ k2.dptr = kstr;
+ k2.dsize = strlen( kstr ) + 1;
+ rc = idl_store( be, db, k2, tmp2 );
+
+ free( kstr );
+ bdb2i_idl_free( tmp );
+ bdb2i_idl_free( tmp2 );
+ break;
+ }
+
+ bdb2i_idl_free( idl );
+ return( rc );
+ }
+
+ /*
+ * this is an indirect block which points to other blocks.
+ * we need to read in the block into which the id should be
+ * inserted, then insert the id and store the block. we might
+ * have to split the block if it is full, which means we also
+ * need to write a new "header" block.
+ */
+
+ /* select the block to try inserting into *//* XXX linear search XXX */
+ for ( i = 0; !ID_BLOCK_NOID(idl, i) && id > ID_BLOCK_ID(idl, i); i++ )
+ ; /* NULL */
+ if ( i != 0 ) {
+ i--;
+ first = 0;
+ } else {
+ first = 1;
+ }
+
+ /* get the block */
+ kstr = (char *) ch_malloc( key.dsize + 20 );
+ sprintf( kstr, "%c%s%ld", CONT_PREFIX, key.dptr, ID_BLOCK_ID(idl, i) );
+ k2.dptr = kstr;
+ k2.dsize = strlen( kstr ) + 1;
+ if ( (tmp = idl_fetch_one( be, db, k2 )) == NULL ) {
+ Debug( LDAP_DEBUG_ANY, "nonexistent continuation block (%s)\n",
+ k2.dptr, 0, 0 );
+ free( kstr );
+ return( -1 );
+ }
+
+ /* insert the id */
+ switch ( bdb2i_idl_insert( &tmp, id, db->dbc_maxids ) ) {
+ case 0: /* id inserted ok */
+ if ( (rc = idl_store( be, db, k2, tmp )) != 0 ) {
+ Debug( LDAP_DEBUG_ANY,
+ "idl_store of (%s) returns %d\n", k2.dptr, rc, 0 );
+ }
+ break;
+
+ case 1: /* id inserted - first id in block has changed */
+ /*
+ * key for this block has changed, so we have to
+ * write the block under the new key, delete the
+ * old key block + update and write the indirect
+ * header block.
+ */
+
+ rc = idl_change_first( be, db, key, idl, i, k2, tmp );
+ break;
+
+ case 2: /* id not inserted - already there */
+ break;
+
+ case 3: /* id not inserted - block is full */
+ /*
+ * first, see if it will fit in the next block,
+ * without splitting, unless we're trying to insert
+ * into the beginning of the first block.
+ */
+
+ /* is there a next block? */
+ if ( !first && !ID_BLOCK_NOID(idl, i + 1) ) {
+ /* read it in */
+ sprintf( kstr, "%c%s%ld", CONT_PREFIX, key.dptr,
+ ID_BLOCK_ID(idl, i + 1) );
+ k2.dptr = kstr;
+ k2.dsize = strlen( kstr ) + 1;
+ if ( (tmp2 = idl_fetch_one( be, db, k2 )) == NULL ) {
+ Debug( LDAP_DEBUG_ANY,
+ "idl_fetch_one (%s) returns NULL\n",
+ k2.dptr, 0, 0 );
+ break;
+ }
+
+ switch ( (rc = bdb2i_idl_insert( &tmp2, id,
+ db->dbc_maxids )) ) {
+ case 1: /* id inserted first in block */
+ rc = idl_change_first( be, db, key, idl,
+ i + 1, k2, tmp2 );
+ /* FALL */
+
+ case 2: /* id already there - how? */
+ case 0: /* id inserted */
+ if ( rc == 2 ) {
+ Debug( LDAP_DEBUG_ANY,
+ "id %lu already in next block\n",
+ id, 0, 0 );
+ }
+ free( kstr );
+ bdb2i_idl_free( tmp );
+ bdb2i_idl_free( tmp2 );
+ bdb2i_idl_free( idl );
+ return( 0 );
+
+ case 3: /* split the original block */
+ bdb2i_idl_free( tmp2 );
+ break;
+ }
+
+ }
+
+ /*
+ * must split the block, write both new blocks + update
+ * and write the indirect header block.
+ */
+
+ /* count how many indirect blocks *//* XXX linear count XXX */
+ for ( j = 0; !ID_BLOCK_NOID(idl, j); j++ )
+ ; /* NULL */
+
+ /* check it against all-id thresholed */
+ if ( j + 1 > db->dbc_maxindirect ) {
+ /*
+ * we've passed the all-id threshold, meaning
+ * that this set of blocks should be replaced
+ * by a single "all-id" block. our job: delete
+ * all the indirect blocks, and replace the header
+ * block by an all-id block.
+ */
+
+ /* delete all indirect blocks */
+ for ( j = 0; !ID_BLOCK_NOID(idl, j); j++ ) {
+ sprintf( kstr, "%c%s%ld", CONT_PREFIX, key.dptr,
+ ID_BLOCK_ID(idl, j) );
+ k2.dptr = kstr;
+ k2.dsize = strlen( kstr ) + 1;
+
+ rc = bdb2i_cache_delete( db, k2 );
+ }
+
+ /* store allid block in place of header block */
+ bdb2i_idl_free( idl );
+ idl = bdb2i_idl_allids( be );
+ rc = idl_store( be, db, key, idl );
+
+ free( kstr );
+ bdb2i_idl_free( idl );
+ bdb2i_idl_free( tmp );
+ return( rc );
+ }
+
+ idl_split_block( tmp, id, &tmp2, &tmp3 );
+ bdb2i_idl_free( tmp );
+
+ /* create a new updated indirect header block */
+ tmp = bdb2i_idl_alloc( ID_BLOCK_NMAX(idl) + 1 );
+ ID_BLOCK_NIDS(tmp) = ID_BLOCK_INDIRECT_VALUE;
+ /* everything up to the split block */
+ SAFEMEMCPY(
+ (char *) &ID_BLOCK_ID(tmp, 0),
+ (char *) &ID_BLOCK_ID(idl, 0),
+ i * sizeof(ID) );
+ /* the two new blocks */
+ ID_BLOCK_ID(tmp, i) = ID_BLOCK_ID(tmp2, 0);
+ ID_BLOCK_ID(tmp, i + 1) = ID_BLOCK_ID(tmp3, 0);
+ /* everything after the split block */
+ SAFEMEMCPY(
+ (char *) &ID_BLOCK_ID(tmp, i + 2),
+ (char *) &ID_BLOCK_ID(idl, i + 1),
+ (ID_BLOCK_NMAX(idl) - i - 1) * sizeof(ID) );
+
+ /* store the header block */
+ rc = idl_store( be, db, key, tmp );
+
+ /* store the first id block */
+ sprintf( kstr, "%c%s%ld", CONT_PREFIX, key.dptr,
+ ID_BLOCK_ID(tmp2, 0) );
+ k2.dptr = kstr;
+ k2.dsize = strlen( kstr ) + 1;
+ rc = idl_store( be, db, k2, tmp2 );
+
+ /* store the second id block */
+ sprintf( kstr, "%c%s%ld", CONT_PREFIX, key.dptr,
+ ID_BLOCK_ID(tmp3, 0) );
+ k2.dptr = kstr;
+ k2.dsize = strlen( kstr ) + 1;
+ rc = idl_store( be, db, k2, tmp3 );
+
+ bdb2i_idl_free( tmp2 );
+ bdb2i_idl_free( tmp3 );
+ break;
+ }
+
+ free( kstr );
+ bdb2i_idl_free( tmp );
+ bdb2i_idl_free( idl );
+ return( rc );
+}
+
+
+/*
+ * bdb2i_idl_insert - insert an id into an id list.
+ *
+ * returns
+ * 0 id inserted
+ * 1 id inserted, first id in block has changed
+ * 2 id not inserted, already there
+ * 3 id not inserted, block must be split
+ */
+int
+bdb2i_idl_insert( ID_BLOCK **idl, ID id, int maxids )
+{
+ unsigned int i, j;
+
+ if ( ID_BLOCK_ALLIDS( *idl ) ) {
+ return( 2 ); /* already there */
+ }
+
+ /* is it already there? *//* XXX linear search XXX */
+ for ( i = 0; i < ID_BLOCK_NIDS(*idl) && id > ID_BLOCK_ID(*idl, i); i++ ) {
+ ; /* NULL */
+ }
+ if ( i < ID_BLOCK_NIDS(*idl) && ID_BLOCK_ID(*idl, i) == id ) {
+ return( 2 ); /* already there */
+ }
+
+ /* do we need to make room for it? */
+ if ( ID_BLOCK_NIDS(*idl) == ID_BLOCK_NMAX(*idl) ) {
+ /* make room or indicate block needs splitting */
+ if ( ID_BLOCK_NMAX(*idl) >= maxids ) {
+ return( 3 ); /* block needs splitting */
+ }
+
+ ID_BLOCK_NMAX(*idl) *= 2;
+ if ( ID_BLOCK_NMAX(*idl) > maxids ) {
+ ID_BLOCK_NMAX(*idl) = maxids;
+ }
+ *idl = (ID_BLOCK *) ch_realloc( (char *) *idl,
+ (ID_BLOCK_NMAX(*idl) + ID_BLOCK_IDS_OFFSET) * sizeof(ID) );
+ }
+
+ /* make a slot for the new id *//* XXX bubble move XXX */
+ for ( j = ID_BLOCK_NIDS(*idl); j != i; j-- ) {
+ ID_BLOCK_ID(*idl, j) = ID_BLOCK_ID(*idl, j-1);
+ }
+ ID_BLOCK_ID(*idl, i) = id;
+ ID_BLOCK_NIDS(*idl)++;
+ (void) memset(
+ (char *) &ID_BLOCK_ID((*idl), ID_BLOCK_NIDS(*idl)),
+ '\0',
+ (ID_BLOCK_NMAX(*idl) - ID_BLOCK_NIDS(*idl)) * sizeof(ID) );
+
+ return( i == 0 ? 1 : 0 ); /* inserted - first id changed or not */
+}
+
+
+int
+bdb2i_idl_delete_key (
+ Backend *be,
+ struct dbcache *db,
+ Datum key,
+ ID id
+)
+{
+ Datum data;
+ ID_BLOCK *idl, *tmp;
+ unsigned i;
+ int j, nids;
+ char *kstr;
+
+ if ( (idl = idl_fetch_one( be, db, key ) ) == NULL )
+ {
+ /* It wasn't found. Hmm... */
+ return -1;
+ }
+
+ if ( ID_BLOCK_ALLIDS( idl ) ) {
+ bdb2i_idl_free( idl );
+ return 0;
+ }
+
+ if ( ! ID_BLOCK_INDIRECT( idl ) ) {
+ for ( i=0; i < ID_BLOCK_NIDS(idl); i++ ) {
+ if ( ID_BLOCK_ID(idl, i) == id ) {
+ if( --ID_BLOCK_NIDS(idl) == 0 ) {
+ bdb2i_cache_delete( db, key );
+
+ } else {
+ SAFEMEMCPY (
+ &ID_BLOCK_ID(idl, i),
+ &ID_BLOCK_ID(idl, i+1),
+ (ID_BLOCK_NIDS(idl)-i) * sizeof(ID) );
+
+ ID_BLOCK_ID(idl, ID_BLOCK_NIDS(idl)) = NOID;
+
+ idl_store( be, db, key, idl );
+ }
+
+ return 0;
+ }
+ /* We didn't find the ID. Hmmm... */
+ }
+ return -1;
+ }
+
+ /* We have to go through an indirect block and find the ID
+ in the list of IDL's
+ */
+ for ( nids = 0; !ID_BLOCK_NOID(idl, nids); nids++ )
+ ; /* NULL */
+ kstr = (char *) ch_malloc( key.dsize + 20 );
+ for ( j = 0; !ID_BLOCK_NOID(idl, j); j++ )
+ {
+ ldbm_datum_init( data );
+ sprintf( kstr, "%c%s%ld", CONT_PREFIX, key.dptr, ID_BLOCK_ID(idl, j) );
+ data.dptr = kstr;
+ data.dsize = strlen( kstr ) + 1;
+
+ if ( (tmp = idl_fetch_one( be, db, data )) == NULL ) {
+ Debug( LDAP_DEBUG_ANY,
+ "bdb2i_idl_fetch of (%s) returns NULL\n", data.dptr, 0, 0 );
+ continue;
+ }
+ /*
+ Now try to find the ID in tmp
+ */
+ for ( i=0; i < ID_BLOCK_NIDS(tmp); i++ )
+ {
+ if ( ID_BLOCK_ID(tmp, i) == id )
+ {
+ SAFEMEMCPY(
+ &ID_BLOCK_ID(tmp, i),
+ &ID_BLOCK_ID(tmp, i+1),
+ (ID_BLOCK_NIDS(tmp)-(i+1)) * sizeof(ID));
+ ID_BLOCK_ID(tmp, ID_BLOCK_NIDS(tmp)-1 ) = NOID;
+ ID_BLOCK_NIDS(tmp)--;
+
+ if ( ID_BLOCK_NIDS(tmp) ) {
+ idl_store ( be, db, data, tmp );
+
+ } else {
+ bdb2i_cache_delete( db, data );
+ SAFEMEMCPY(
+ &ID_BLOCK_ID(idl, j),
+ &ID_BLOCK_ID(idl, j+1),
+ (nids-(j+1)) * sizeof(ID));
+ ID_BLOCK_ID(idl, nids-1) = NOID;
+ nids--;
+ if ( ! nids )
+ bdb2i_cache_delete( db, key );
+ else
+ idl_store( be, db, key, idl );
+ }
+ free( kstr );
+ return 0;
+ }
+ }
+ }
+ free( kstr );
+ return -1;
+}
+
+
+/* return a duplicate of a single ID_BLOCK */
+static ID_BLOCK *
+idl_dup( ID_BLOCK *idl )
+{
+ ID_BLOCK *new;
+
+ if ( idl == NULL ) {
+ return( NULL );
+ }
+
+ new = bdb2i_idl_alloc( ID_BLOCK_NMAX(idl) );
+ SAFEMEMCPY(
+ (char *) new,
+ (char *) idl,
+ (ID_BLOCK_NMAX(idl) + ID_BLOCK_IDS_OFFSET) * sizeof(ID) );
+
+ return( new );
+}
+
+
+/* return the smaller ID_BLOCK */
+static ID_BLOCK *
+idl_min( ID_BLOCK *a, ID_BLOCK *b )
+{
+ return( ID_BLOCK_NIDS(a) > ID_BLOCK_NIDS(b) ? b : a );
+}
+
+
+/*
+ * bdb2i_idl_intersection - return a intersection b
+ */
+ID_BLOCK *
+bdb2i_idl_intersection(
+ Backend *be,
+ ID_BLOCK *a,
+ ID_BLOCK *b
+)
+{
+ unsigned int ai, bi, ni;
+ ID_BLOCK *n;
+
+ if ( a == NULL || b == NULL ) {
+ return( NULL );
+ }
+ if ( ID_BLOCK_ALLIDS( a ) ) {
+ return( idl_dup( b ) );
+ }
+ if ( ID_BLOCK_ALLIDS( b ) ) {
+ return( idl_dup( a ) );
+ }
+
+ n = idl_dup( idl_min( a, b ) );
+
+ for ( ni = 0, ai = 0, bi = 0; ai < ID_BLOCK_NIDS(a); ai++ ) {
+ for ( ;
+ bi < ID_BLOCK_NIDS(b) && ID_BLOCK_ID(b, bi) < ID_BLOCK_ID(a, ai);
+ bi++ )
+ {
+ ; /* NULL */
+ }
+
+ if ( bi == ID_BLOCK_NIDS(b) ) {
+ break;
+ }
+
+ if ( ID_BLOCK_ID(b, bi) == ID_BLOCK_ID(a, ai) ) {
+ ID_BLOCK_ID(n, ni++) = ID_BLOCK_ID(a, ai);
+ }
+ }
+
+ if ( ni == 0 ) {
+ bdb2i_idl_free( n );
+ return( NULL );
+ }
+ ID_BLOCK_NIDS(n) = ni;
+
+ return( n );
+}
+
+
+/*
+ * bdb2i_idl_union - return a union b
+ */
+ID_BLOCK *
+bdb2i_idl_union(
+ Backend *be,
+ ID_BLOCK *a,
+ ID_BLOCK *b
+)
+{
+ unsigned int ai, bi, ni;
+ ID_BLOCK *n;
+
+ if ( a == NULL ) {
+ return( idl_dup( b ) );
+ }
+ if ( b == NULL ) {
+ return( idl_dup( a ) );
+ }
+ if ( ID_BLOCK_ALLIDS( a ) || ID_BLOCK_ALLIDS( b ) ) {
+ return( bdb2i_idl_allids( be ) );
+ }
+
+ if ( ID_BLOCK_NIDS(b) < ID_BLOCK_NIDS(a) ) {
+ n = a;
+ a = b;
+ b = n;
+ }
+
+ n = bdb2i_idl_alloc( ID_BLOCK_NIDS(a) + ID_BLOCK_NIDS(b) );
+
+ for ( ni = 0, ai = 0, bi = 0;
+ ai < ID_BLOCK_NIDS(a) && bi < ID_BLOCK_NIDS(b);
+ )
+ {
+ if ( ID_BLOCK_ID(a, ai) < ID_BLOCK_ID(b, bi) ) {
+ ID_BLOCK_ID(n, ni++) = ID_BLOCK_ID(a, ai++);
+
+ } else if ( ID_BLOCK_ID(b, bi) < ID_BLOCK_ID(a, ai) ) {
+ ID_BLOCK_ID(n, ni++) = ID_BLOCK_ID(b, bi++);
+
+ } else {
+ ID_BLOCK_ID(n, ni++) = ID_BLOCK_ID(a, ai);
+ ai++, bi++;
+ }
+ }
+
+ for ( ; ai < ID_BLOCK_NIDS(a); ai++ ) {
+ ID_BLOCK_ID(n, ni++) = ID_BLOCK_ID(a, ai);
+ }
+ for ( ; bi < ID_BLOCK_NIDS(b); bi++ ) {
+ ID_BLOCK_ID(n, ni++) = ID_BLOCK_ID(b, bi);
+ }
+ ID_BLOCK_NIDS(n) = ni;
+
+ return( n );
+}
+
+
+/*
+ * bdb2i_idl_notin - return a intersection ~b (or a minus b)
+ */
+ID_BLOCK *
+bdb2i_idl_notin(
+ Backend *be,
+ ID_BLOCK *a,
+ ID_BLOCK *b
+)
+{
+ unsigned int ni, ai, bi;
+ ID_BLOCK *n;
+
+ if ( a == NULL ) {
+ return( NULL );
+ }
+ if ( b == NULL || ID_BLOCK_ALLIDS( b )) {
+ return( idl_dup( a ) );
+ }
+
+ if ( ID_BLOCK_ALLIDS( a ) ) {
+ n = bdb2i_idl_alloc( SLAPD_LDBM_MIN_MAXIDS );
+ ni = 0;
+
+ for ( ai = 1, bi = 0;
+ ai < ID_BLOCK_NIDS(a) && ni < ID_BLOCK_NMAX(n) && bi < ID_BLOCK_NMAX(b);
+ ai++ )
+ {
+ if ( ID_BLOCK_ID(b, bi) == ai ) {
+ bi++;
+ } else {
+ ID_BLOCK_ID(n, ni++) = ai;
+ }
+ }
+
+ for ( ; ai < ID_BLOCK_NIDS(a) && ni < ID_BLOCK_NMAX(n); ai++ ) {
+ ID_BLOCK_ID(n, ni++) = ai;
+ }
+
+ if ( ni == ID_BLOCK_NMAX(n) ) {
+ bdb2i_idl_free( n );
+ return( bdb2i_idl_allids( be ) );
+ } else {
+ ID_BLOCK_NIDS(n) = ni;
+ return( n );
+ }
+ }
+
+ n = idl_dup( a );
+
+ ni = 0;
+ for ( ai = 0, bi = 0; ai < ID_BLOCK_NIDS(a); ai++ ) {
+ for ( ;
+ bi < ID_BLOCK_NIDS(b) && ID_BLOCK_ID(b, bi) < ID_BLOCK_ID(a, ai);
+ bi++ )
+ {
+ ; /* NULL */
+ }
+
+ if ( bi == ID_BLOCK_NIDS(b) ) {
+ break;
+ }
+
+ if ( ID_BLOCK_ID(b, bi) != ID_BLOCK_ID(a, ai) ) {
+ ID_BLOCK_ID(n, ni++) = ID_BLOCK_ID(a, ai);
+ }
+ }
+
+ for ( ; ai < ID_BLOCK_NIDS(a); ai++ ) {
+ ID_BLOCK_ID(n, ni++) = ID_BLOCK_ID(a, ai);
+ }
+ ID_BLOCK_NIDS(n) = ni;
+
+ return( n );
+}
+
+
+/* return the first ID in the block
+ * if ALLIDS block
+ * NIDS > 1 return 1
+ * otherwise return NOID
+ * otherwise return first ID
+ */
+ID
+bdb2i_idl_firstid( ID_BLOCK *idl )
+{
+ if ( idl == NULL || ID_BLOCK_NIDS(idl) == 0 ) {
+ return( NOID );
+ }
+
+ if ( ID_BLOCK_ALLIDS( idl ) ) {
+ return( ID_BLOCK_NIDS(idl) > 1 ? 1 : NOID );
+ }
+
+ return( ID_BLOCK_ID(idl, 0) );
+}
+
+
+/* return next ID after id
+ * if ALLIDS block, increment id.
+ * if id < NIDS return id
+ * otherwise NOID.
+ * otherwise SEARCH for next id (ugh!)
+ */
+ID
+bdb2i_idl_nextid( ID_BLOCK *idl, ID id )
+{
+ unsigned int i;
+
+ if ( ID_BLOCK_ALLIDS( idl ) ) {
+ return( ++id < ID_BLOCK_NIDS(idl) ? id : NOID );
+ }
+
+ for ( i = 0; i < ID_BLOCK_NIDS(idl) && ID_BLOCK_ID(idl, i) <= id; i++ ) {
+ ; /* NULL */
+ }
+
+ if ( i >= ID_BLOCK_NIDS(idl) ) {
+ return( NOID );
+ } else {
+ return( ID_BLOCK_ID(idl, i) );
+ }
+}
--- /dev/null
+/* index.c - routines for dealing with attribute indexes */
+
+#include "portable.h"
+
+#include <stdio.h>
+
+#include <ac/string.h>
+#include <ac/socket.h>
+
+#include "slap.h"
+#include "back-bdb2.h"
+
+static int add_value(Backend *be, struct dbcache *db, char *type, int indextype, char *val, ID id);
+static int index2prefix(int indextype);
+
+int
+bdb2i_index_add_entry(
+ Backend *be,
+ Entry *e
+)
+{
+ Attribute *ap;
+ char *dnval;
+ struct berval bv;
+ struct berval *bvals[2];
+
+ Debug( LDAP_DEBUG_TRACE, "=> index_add( %ld, \"%s\" )\n", e->e_id,
+ e->e_dn, 0 );
+
+ /*
+ * dn index entry - make it look like an attribute so it works
+ * with bdb2i_index_add_values() call
+ */
+
+ bv.bv_val = ch_strdup( e->e_dn );
+ bv.bv_len = strlen( bv.bv_val );
+ (void) dn_normalize_case( bv.bv_val );
+ bvals[0] = &bv;
+ bvals[1] = NULL;
+
+ /* add the dn to the indexes */
+ bdb2i_index_add_values( be, "dn", bvals, e->e_id );
+
+ free( bv.bv_val );
+
+ /* add each attribute to the indexes */
+ for ( ap = e->e_attrs; ap != NULL; ap = ap->a_next ) {
+ bdb2i_index_add_values( be, ap->a_type, ap->a_vals, e->e_id );
+ }
+
+ Debug( LDAP_DEBUG_TRACE, "<= index_add( %ld, \"%s\" ) 0\n", e->e_id,
+ e->e_dn, 0 );
+ return( 0 );
+}
+
+int
+bdb2i_index_add_mods(
+ Backend *be,
+ LDAPModList *ml,
+ ID id
+)
+{
+ int rc;
+
+ for ( ; ml != NULL; ml = ml->ml_next ) {
+ LDAPMod *mod = &ml->ml_mod;
+
+ switch ( mod->mod_op & ~LDAP_MOD_BVALUES ) {
+ case LDAP_MOD_ADD:
+ case LDAP_MOD_REPLACE:
+ rc = bdb2i_index_add_values( be, mod->mod_type,
+ mod->mod_bvalues, id );
+ break;
+
+ case LDAP_MOD_DELETE:
+ rc = 0;
+ break;
+ }
+
+ if ( rc != 0 ) {
+ return( rc );
+ }
+ }
+
+ return( 0 );
+}
+
+ID_BLOCK *
+bdb2i_index_read(
+ Backend *be,
+ char *type,
+ int indextype,
+ char *val
+)
+{
+ struct dbcache *db;
+ Datum key;
+ ID_BLOCK *idl;
+ int indexmask, syntax;
+ char prefix;
+ char *realval, *tmpval;
+ char buf[BUFSIZ];
+
+ ldbm_datum_init( key );
+
+ prefix = index2prefix( indextype );
+ Debug( LDAP_DEBUG_TRACE, "=> bdb2i_index_read( \"%s\" \"%c\" \"%s\" )\n",
+ type, prefix, val );
+
+ bdb2i_attr_masks( be->be_private, type, &indexmask, &syntax );
+ if ( ! (indextype & indexmask) ) {
+ idl = bdb2i_idl_allids( be );
+ Debug( LDAP_DEBUG_TRACE,
+ "<= bdb2i_index_read %lu candidates (allids - not indexed)\n",
+ idl ? ID_BLOCK_NIDS(idl) : 0, 0, 0 );
+ return( idl );
+ }
+
+ attr_normalize( type );
+ if ( (db = bdb2i_cache_open( be, type, LDBM_SUFFIX, LDBM_WRCREAT ))
+ == NULL ) {
+ Debug( LDAP_DEBUG_ANY,
+ "<= bdb2i_index_read NULL (could not open %s%s)\n", type,
+ LDBM_SUFFIX, 0 );
+ return( NULL );
+ }
+
+ realval = val;
+ tmpval = NULL;
+ if ( prefix != UNKNOWN_PREFIX ) {
+ unsigned int len = strlen( val );
+
+ if ( (len + 2) < sizeof(buf) ) {
+ realval = buf;
+ } else {
+ /* value + prefix + null */
+ tmpval = (char *) ch_malloc( len + 2 );
+ realval = tmpval;
+ }
+ realval[0] = prefix;
+ strcpy( &realval[1], val );
+ }
+
+ key.dptr = realval;
+ key.dsize = strlen( realval ) + 1;
+
+ idl = bdb2i_idl_fetch( be, db, key );
+ if ( tmpval != NULL ) {
+ free( tmpval );
+ }
+
+ bdb2i_cache_close( be, db );
+
+ Debug( LDAP_DEBUG_TRACE, "<= bdb2i_index_read %lu candidates\n",
+ idl ? ID_BLOCK_NIDS(idl) : 0, 0, 0 );
+ return( idl );
+}
+
+static int
+add_value(
+ Backend *be,
+ struct dbcache *db,
+ char *type,
+ int indextype,
+ char *val,
+ ID id
+)
+{
+ int rc;
+ Datum key;
+ ID_BLOCK *idl;
+ char prefix;
+ char *realval, *tmpval, *s;
+ char buf[BUFSIZ];
+
+ ldbm_datum_init( key );
+
+ prefix = index2prefix( indextype );
+ Debug( LDAP_DEBUG_TRACE, "=> add_value( \"%c%s\" )\n", prefix, val, 0 );
+
+ realval = val;
+ tmpval = NULL;
+ idl = NULL;
+ if ( prefix != UNKNOWN_PREFIX ) {
+ unsigned int len = strlen( val );
+
+ if ( (len + 2) < sizeof(buf) ) {
+ realval = buf;
+ } else {
+ /* value + prefix + null */
+ tmpval = (char *) ch_malloc( len + 2 );
+ realval = tmpval;
+ }
+ realval[0] = prefix;
+ strcpy( &realval[1], val );
+ }
+
+ key.dptr = realval;
+ key.dsize = strlen( realval ) + 1;
+
+ rc = bdb2i_idl_insert_key( be, db, key, id );
+
+ if ( tmpval != NULL ) {
+ free( tmpval );
+ }
+ bdb2i_idl_free( idl );
+
+ ldap_pvt_thread_yield();
+
+ /* Debug( LDAP_DEBUG_TRACE, "<= add_value %d\n", rc, 0, 0 ); */
+ return( rc );
+}
+
+int
+bdb2i_index_add_values(
+ Backend *be,
+ char *type,
+ struct berval **vals,
+ ID id
+)
+{
+ char *val, *p, *code, *w;
+ unsigned i, j, len;
+ int indexmask, syntax;
+ char buf[SUBLEN + 1];
+ char vbuf[BUFSIZ];
+ char *bigbuf;
+ struct dbcache *db;
+
+ Debug( LDAP_DEBUG_TRACE, "=> bdb2i_index_add_values( \"%s\", %ld )\n", type,
+ id, 0 );
+
+ bdb2i_attr_masks( be->be_private, type, &indexmask, &syntax );
+ if ( indexmask == 0 ) {
+ return( 0 );
+ }
+
+ if ( (db = bdb2i_cache_open( be, type, LDBM_SUFFIX, LDBM_WRCREAT ))
+ == NULL ) {
+ Debug( LDAP_DEBUG_ANY,
+ "<= bdb2i_index_add_values -1 (could not open/create %s%s)\n",
+ type, LDBM_SUFFIX, 0 );
+ return( -1 );
+ }
+
+ for ( i = 0; vals[i] != NULL; i++ ) {
+ /*
+ * presence index entry
+ */
+ if ( indexmask & INDEX_PRESENCE ) {
+ add_value( be, db, type, INDEX_PRESENCE, "*", id );
+ }
+
+ Debug( LDAP_DEBUG_TRACE, "*** bdb2i_index_add_values syntax 0x%x syntax bin 0x%x\n",
+ syntax, SYNTAX_BIN, 0 );
+ if ( syntax & SYNTAX_BIN ) {
+ bdb2i_cache_close( be, db );
+ return( 0 );
+ }
+
+ bigbuf = NULL;
+ len = vals[i]->bv_len;
+
+ /* value + null */
+ if ( len + 2 > sizeof(vbuf) ) {
+ bigbuf = (char *) ch_malloc( len + 1 );
+ val = bigbuf;
+ } else {
+ val = vbuf;
+ }
+ (void) memcpy( val, vals[i]->bv_val, len );
+ val[len] = '\0';
+
+ value_normalize( val, syntax );
+
+ /*
+ * equality index entry
+ */
+ if ( indexmask & INDEX_EQUALITY ) {
+ add_value( be, db, type, INDEX_EQUALITY, val, id );
+ }
+
+ /*
+ * approximate index entry
+ */
+ if ( indexmask & INDEX_APPROX ) {
+ for ( w = first_word( val ); w != NULL;
+ w = next_word( w ) ) {
+ if ( (code = phonetic( w )) != NULL ) {
+ add_value( be, db, type, INDEX_APPROX,
+ code, id );
+ free( code );
+ }
+ }
+ }
+
+ /*
+ * substrings index entry
+ */
+ if ( indexmask & INDEX_SUB ) {
+ /* leading and trailing */
+ if ( len > SUBLEN - 2 ) {
+ buf[0] = '^';
+ for ( j = 0; j < SUBLEN - 1; j++ ) {
+ buf[j + 1] = val[j];
+ }
+ buf[SUBLEN] = '\0';
+
+ add_value( be, db, type, INDEX_SUB, buf, id );
+
+ p = val + len - SUBLEN + 1;
+ for ( j = 0; j < SUBLEN - 1; j++ ) {
+ buf[j] = p[j];
+ }
+ buf[SUBLEN - 1] = '$';
+ buf[SUBLEN] = '\0';
+
+ add_value( be, db, type, INDEX_SUB, buf, id );
+ }
+
+ /* any */
+ for ( p = val; p < (val + len - SUBLEN + 1); p++ ) {
+ for ( j = 0; j < SUBLEN; j++ ) {
+ buf[j] = p[j];
+ }
+ buf[SUBLEN] = '\0';
+
+ add_value( be, db, type, INDEX_SUB, buf, id );
+ }
+ }
+
+ if ( bigbuf != NULL ) {
+ free( bigbuf );
+ }
+ }
+ bdb2i_cache_close( be, db );
+
+ return( 0 );
+}
+
+static int
+index2prefix( int indextype )
+{
+ int prefix;
+
+ switch ( indextype ) {
+ case INDEX_EQUALITY:
+ prefix = EQ_PREFIX;
+ break;
+ case INDEX_APPROX:
+ prefix = APPROX_PREFIX;
+ break;
+ case INDEX_SUB:
+ prefix = SUB_PREFIX;
+ break;
+ default:
+ prefix = UNKNOWN_PREFIX;
+ break;
+ }
+
+ return( prefix );
+}
--- /dev/null
+/* init.c - initialize bdb2 backend */
+
+#include "portable.h"
+
+#include <stdio.h>
+
+#include <ac/string.h>
+#include <ac/socket.h>
+
+#include "slap.h"
+#include "back-bdb2.h"
+
+
+int
+bdb2_back_initialize(
+ BackendInfo *bi
+)
+{
+ bi->bi_open = bdb2_back_open;
+ bi->bi_config = NULL;
+ bi->bi_close = bdb2_back_close;
+ bi->bi_destroy = bdb2_back_destroy;
+
+ bi->bi_db_init = bdb2_back_db_init;
+ bi->bi_db_config = bdb2_back_db_config;
+ bi->bi_db_open = bdb2_back_db_open;
+ bi->bi_db_close = bdb2_back_db_close;
+ bi->bi_db_destroy = bdb2_back_db_destroy;
+
+ bi->bi_op_bind = bdb2_back_bind;
+ bi->bi_op_unbind = bdb2_back_unbind;
+ bi->bi_op_search = bdb2_back_search;
+ bi->bi_op_compare = bdb2_back_compare;
+ bi->bi_op_modify = bdb2_back_modify;
+ bi->bi_op_modrdn = bdb2_back_modrdn;
+ bi->bi_op_add = bdb2_back_add;
+ bi->bi_op_delete = bdb2_back_delete;
+ bi->bi_op_abandon = bdb2_back_abandon;
+
+ bi->bi_acl_group = bdb2_back_group;
+
+ return 0;
+}
+
+int
+bdb2_back_destroy(
+ BackendInfo *bi
+)
+{
+ return 0;
+}
+
+int
+bdb2_back_open(
+ BackendInfo *bi
+)
+{
+ int rc;
+
+ /* initialize the underlying database system */
+ rc = bdb2_initialize();
+
+ return rc;
+}
+
+int
+bdb2_back_close(
+ BackendInfo *bi
+)
+{
+ /* close the underlying database system */
+ bdb2_shutdown();
+
+ return 0;
+}
+
+/* BDB2 changed */
+static int
+bdb2i_back_db_init_internal(
+ Backend *be
+)
+{
+ struct ldbminfo *li;
+ char *argv[ 4 ];
+ int i;
+
+ /* allocate backend-specific stuff */
+ li = (struct ldbminfo *) ch_calloc( 1, sizeof(struct ldbminfo) );
+
+ /* arrange to read nextid later (on first request for it) */
+ li->li_nextid = NOID;
+#if SLAPD_NEXTID_CHUNCK > 1
+ li->li_nextid_wrote = NOID
+#endif
+
+ /* default cache size */
+ li->li_cache.c_maxsize = DEFAULT_CACHE_SIZE;
+
+ /* default database cache size */
+ li->li_dbcachesize = DEFAULT_DBCACHE_SIZE;
+
+ /* default cache mode is sync on write */
+ li->li_dbcachewsync = 1;
+
+ /* default file creation mode */
+ li->li_mode = DEFAULT_MODE;
+
+ /* default database directory */
+ li->li_directory = DEFAULT_DB_DIRECTORY;
+
+ /* always index dn, id2children, objectclass (used in some searches) */
+ argv[ 0 ] = "dn";
+ argv[ 1 ] = "dn";
+ argv[ 2 ] = NULL;
+ attr_syntax_config( "ldbm dn initialization", 0, 2, argv );
+ argv[ 0 ] = "dn";
+ argv[ 1 ] = "sub";
+ argv[ 2 ] = "eq";
+ argv[ 3 ] = NULL;
+ bdb2i_attr_index_config( li, "ldbm dn initialization", 0, 3, argv, 1 );
+ argv[ 0 ] = "id2children";
+ argv[ 1 ] = "eq";
+ argv[ 2 ] = NULL;
+ bdb2i_attr_index_config( li, "ldbm id2children initialization", 0, 2, argv,
+ 1 );
+ argv[ 0 ] = "objectclass";
+ argv[ 1 ] = ch_strdup( "pres,eq" );
+ argv[ 2 ] = NULL;
+ bdb2i_attr_index_config( li, "ldbm objectclass initialization", 0, 2, argv,
+ 1 );
+ free( argv[ 1 ] );
+
+ /* initialize various mutex locks & condition variables */
+ ldap_pvt_thread_mutex_init( &li->li_root_mutex );
+ ldap_pvt_thread_mutex_init( &li->li_add_mutex );
+ ldap_pvt_thread_mutex_init( &li->li_cache.c_mutex );
+ ldap_pvt_thread_mutex_init( &li->li_nextid_mutex );
+ ldap_pvt_thread_mutex_init( &li->li_dbcache_mutex );
+ ldap_pvt_thread_cond_init( &li->li_dbcache_cv );
+
+ /* initialize the TP file head */
+ bdb2i_txn_head_init( &li->li_txn_head );
+
+ be->be_private = li;
+
+ return 0;
+}
+
+
+int
+bdb2_back_db_init(
+ Backend *be
+)
+{
+ struct timeval time1, time2;
+ char *elapsed_time;
+ int ret;
+
+ gettimeofday( &time1, NULL );
+
+ ret = bdb2i_back_db_init_internal( be );
+
+ if ( bdb2i_do_timing ) {
+
+ gettimeofday( &time2, NULL);
+ elapsed_time = bdb2i_elapsed( time1, time2 );
+ Debug( LDAP_DEBUG_ANY, "INIT elapsed=%s\n",
+ elapsed_time, 0, 0 );
+ free( elapsed_time );
+
+ }
+
+ return( ret );
+}
+
+
+int
+bdb2_back_db_open(
+ BackendDB *be
+)
+{
+ return 0;
+}
+
+int
+bdb2_back_db_destroy(
+ BackendDB *be
+)
+{
+ /* should free/destroy every in be_private */
+ free( be->be_private );
+ be->be_private = NULL;
+ return 0;
+}
+
+
--- /dev/null
+/* kerberos.c - bdb2 backend kerberos bind routines */
+
+#include "portable.h"
+
+#ifdef HAVE_KERBEROS
+
+#include <stdio.h>
+
+#include <ac/krb.h>
+#include <ac/socket.h>
+#include <ac/string.h>
+
+#include "slap.h"
+#include "back-bdb2.h"
+
+#define LDAP_KRB_PRINCIPAL "ldapserver"
+
+extern char *ldap_srvtab;
+extern Attribute *attr_find();
+
+bdb2i_krbv4_ldap_auth(
+ Backend *be,
+ struct berval *cred,
+ AUTH_DAT *ad
+)
+{
+ KTEXT_ST k;
+ KTEXT ktxt = &k;
+ char instance[INST_SZ];
+ int err;
+
+ Debug( LDAP_DEBUG_TRACE, "=> kerberosv4_ldap_auth\n", 0, 0, 0 );
+
+ SAFEMEMCPY( ktxt->dat, cred->bv_val, cred->bv_len );
+ ktxt->length = cred->bv_len;
+
+ strcpy( instance, "*" );
+ if ( (err = krb_rd_req( ktxt, LDAP_KRB_PRINCIPAL, instance, 0L, ad,
+ ldap_srvtab )) != KSUCCESS ) {
+ Debug( LDAP_DEBUG_ANY, "krb_rd_req failed (%s)\n",
+ krb_err_txt[err], 0, 0 );
+ return( LDAP_INVALID_CREDENTIALS );
+ }
+
+ return( LDAP_SUCCESS );
+}
+
+#endif /* kerberos */
--- /dev/null
+/* modify.c - bdb2 backend modify routine */
+
+#include "portable.h"
+
+#include <stdio.h>
+
+#include <ac/string.h>
+#include <ac/socket.h>
+
+#include "slap.h"
+#include "back-bdb2.h"
+#include "proto-back-bdb2.h"
+
+static int add_values(Entry *e, LDAPMod *mod, char *dn);
+static int delete_values(Entry *e, LDAPMod *mod, char *dn);
+static int replace_values(Entry *e, LDAPMod *mod, char *dn);
+
+static int
+bdb2i_back_modify_internal(
+ Backend *be,
+ Connection *conn,
+ Operation *op,
+ char *dn,
+ LDAPModList *modlist
+)
+{
+ struct ldbminfo *li = (struct ldbminfo *) be->be_private;
+ char *matched;
+ LDAPModList *ml;
+ Entry *e;
+ int i, err;
+
+ Debug(LDAP_DEBUG_ARGS, "bdb2i_back_modify:\n", 0, 0, 0);
+
+ if ( (e = bdb2i_dn2entry_w( be, dn, &matched )) == NULL ) {
+ send_ldap_result( conn, op, LDAP_NO_SUCH_OBJECT, matched,
+ NULL );
+ if ( matched != NULL ) {
+ free( matched );
+ }
+ return( -1 );
+ }
+
+ if ( (err = acl_check_modlist( be, conn, op, e, modlist )) != LDAP_SUCCESS ) {
+ send_ldap_result( conn, op, err, NULL, NULL );
+ goto error_return;
+ }
+
+ for ( ml = modlist; ml != NULL; ml = ml->ml_next ) {
+ LDAPMod *mod = &ml->ml_mod;
+
+ switch ( mod->mod_op & ~LDAP_MOD_BVALUES ) {
+ case LDAP_MOD_ADD:
+ err = add_values( e, mod, op->o_ndn );
+ break;
+
+ case LDAP_MOD_DELETE:
+ err = delete_values( e, mod, op->o_ndn );
+ break;
+
+ case LDAP_MOD_REPLACE:
+ err = replace_values( e, mod, op->o_ndn );
+ break;
+ }
+
+ if ( err != LDAP_SUCCESS ) {
+ /* unlock entry, delete from cache */
+ send_ldap_result( conn, op, err, NULL, NULL );
+ goto error_return;
+ }
+ }
+
+ /* check that the entry still obeys the schema */
+ if ( global_schemacheck && oc_schema_check( e ) != 0 ) {
+ Debug( LDAP_DEBUG_ANY, "entry failed schema check\n", 0, 0, 0 );
+ send_ldap_result( conn, op, LDAP_OBJECT_CLASS_VIOLATION, NULL, NULL );
+ goto error_return;
+ }
+
+ /* check for abandon */
+ ldap_pvt_thread_mutex_lock( &op->o_abandonmutex );
+ if ( op->o_abandon ) {
+ ldap_pvt_thread_mutex_unlock( &op->o_abandonmutex );
+ goto error_return;
+ }
+ ldap_pvt_thread_mutex_unlock( &op->o_abandonmutex );
+
+ /* modify indexes */
+ if ( bdb2i_index_add_mods( be, modlist, e->e_id ) != 0 ) {
+ send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR, NULL, NULL );
+ goto error_return;
+ }
+
+ /* check for abandon */
+ ldap_pvt_thread_mutex_lock( &op->o_abandonmutex );
+ if ( op->o_abandon ) {
+ ldap_pvt_thread_mutex_unlock( &op->o_abandonmutex );
+ goto error_return;
+ }
+ ldap_pvt_thread_mutex_unlock( &op->o_abandonmutex );
+
+ /* change the entry itself */
+ if ( bdb2i_id2entry_add( be, e ) != 0 ) {
+ send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR, NULL, NULL );
+ goto error_return;
+ }
+
+ send_ldap_result( conn, op, LDAP_SUCCESS, NULL, NULL );
+ bdb2i_cache_return_entry_w( &li->li_cache, e );
+ return( 0 );
+
+error_return:;
+ bdb2i_cache_return_entry_w( &li->li_cache, e );
+ return( -1 );
+}
+
+
+int
+bdb2_back_modify(
+ Backend *be,
+ Connection *conn,
+ Operation *op,
+ char *dn,
+ LDAPModList *modlist
+)
+{
+ DB_LOCK lock;
+ struct ldbminfo *li = (struct ldbminfo *) be->be_private;
+
+ struct timeval time1, time2;
+ char *elapsed_time;
+ int ret;
+
+ gettimeofday( &time1, NULL );
+
+ if ( bdb2i_enter_backend_w( &li->li_db_env, &lock ) != 0 ) {
+
+ send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR, "", "" );
+ return( -1 );
+
+ }
+
+ /* check, if a new default attribute index will be created,
+ in which case we have to open the index file BEFORE TP */
+ if ( bdb2i_with_dbenv )
+ bdb2i_check_default_attr_index_mod( li, modlist );
+
+ ret = bdb2i_back_modify_internal( be, conn, op, dn, modlist );
+
+ (void) bdb2i_leave_backend( &li->li_db_env, lock );
+
+ if ( bdb2i_do_timing ) {
+
+ gettimeofday( &time2, NULL);
+ elapsed_time = bdb2i_elapsed( time1, time2 );
+ Debug( LDAP_DEBUG_ANY, "conn=%d op=%d MOD elapsed=%s\n",
+ conn->c_connid, op->o_opid, elapsed_time );
+ free( elapsed_time );
+
+ }
+
+ return( ret );
+}
+
+
+static int
+add_values(
+ Entry *e,
+ LDAPMod *mod,
+ char *dn
+)
+{
+ int i;
+ Attribute *a;
+
+ /* check if the values we're adding already exist */
+ if ( (a = attr_find( e->e_attrs, mod->mod_type )) != NULL ) {
+ for ( i = 0; mod->mod_bvalues[i] != NULL; i++ ) {
+ if ( value_find( a->a_vals, mod->mod_bvalues[i],
+ a->a_syntax, 3 ) == 0 ) {
+ return( LDAP_TYPE_OR_VALUE_EXISTS );
+ }
+ }
+ }
+
+ /* no - add them */
+ if( attr_merge( e, mod->mod_type, mod->mod_bvalues ) != 0 ) {
+ return( LDAP_CONSTRAINT_VIOLATION );
+ }
+
+ return( LDAP_SUCCESS );
+}
+
+static int
+delete_values(
+ Entry *e,
+ LDAPMod *mod,
+ char *dn
+)
+{
+ int i, j, k, found;
+ Attribute *a;
+
+ /* delete the entire attribute */
+ if ( mod->mod_bvalues == NULL ) {
+ Debug( LDAP_DEBUG_ARGS, "removing entire attribute %s\n",
+ mod->mod_type, 0, 0 );
+ return( attr_delete( &e->e_attrs, mod->mod_type ) ?
+ LDAP_NO_SUCH_ATTRIBUTE : LDAP_SUCCESS );
+ }
+
+ /* delete specific values - find the attribute first */
+ if ( (a = attr_find( e->e_attrs, mod->mod_type )) == NULL ) {
+ Debug( LDAP_DEBUG_ARGS, "could not find attribute %s\n",
+ mod->mod_type, 0, 0 );
+ return( LDAP_NO_SUCH_ATTRIBUTE );
+ }
+
+ /* find each value to delete */
+ for ( i = 0; mod->mod_bvalues[i] != NULL; i++ ) {
+ found = 0;
+ for ( j = 0; a->a_vals[j] != NULL; j++ ) {
+ if ( value_cmp( mod->mod_bvalues[i], a->a_vals[j],
+ a->a_syntax, 3 ) != 0 ) {
+ continue;
+ }
+ found = 1;
+
+ /* found a matching value - delete it */
+ ber_bvfree( a->a_vals[j] );
+ for ( k = j + 1; a->a_vals[k] != NULL; k++ ) {
+ a->a_vals[k - 1] = a->a_vals[k];
+ }
+ a->a_vals[k - 1] = NULL;
+ break;
+ }
+
+ /* looked through them all w/o finding it */
+ if ( ! found ) {
+ Debug( LDAP_DEBUG_ARGS,
+ "could not find value for attr %s\n",
+ mod->mod_type, 0, 0 );
+ return( LDAP_NO_SUCH_ATTRIBUTE );
+ }
+ }
+
+ return( LDAP_SUCCESS );
+}
+
+static int
+replace_values(
+ Entry *e,
+ LDAPMod *mod,
+ char *dn
+)
+{
+ (void) attr_delete( &e->e_attrs, mod->mod_type );
+
+ if ( attr_merge( e, mod->mod_type, mod->mod_bvalues ) != 0 ) {
+ return( LDAP_CONSTRAINT_VIOLATION );
+ }
+
+ return( LDAP_SUCCESS );
+}
--- /dev/null
+/* modrdn.c - bdb2 backend modrdn routine */
+
+#include "portable.h"
+
+#include <stdio.h>
+
+#include <ac/string.h>
+#include <ac/socket.h>
+
+#include "slap.h"
+#include "back-bdb2.h"
+#include "proto-back-bdb2.h"
+
+static int
+bdb2i_back_modrdn_internal(
+ Backend *be,
+ Connection *conn,
+ Operation *op,
+ char *dn,
+ char *newrdn,
+ int deleteoldrdn
+)
+{
+ struct ldbminfo *li = (struct ldbminfo *) be->be_private;
+ char *matched = NULL;
+ char *p_dn = NULL, *p_ndn = NULL;
+ char *new_dn = NULL, *new_ndn = NULL;
+ char sep[2];
+ Entry *e, *p = NULL;
+ int rootlock = 0;
+ int rc = -1;
+
+ /* get entry with writer lock */
+ if ( (e = bdb2i_dn2entry_w( be, dn, &matched )) == NULL ) {
+ send_ldap_result( conn, op, LDAP_NO_SUCH_OBJECT, matched, "" );
+ if ( matched != NULL ) {
+ free( matched );
+ }
+ return( -1 );
+ }
+
+#ifdef SLAPD_CHILD_MODIFICATION_WITH_ENTRY_ACL
+ /* check parent for "children" acl */
+ if ( ! access_allowed( be, conn, op, e,
+ "entry", NULL, ACL_WRITE ) )
+ {
+ Debug( LDAP_DEBUG_TRACE, "no access to entry\n", 0,
+ 0, 0 );
+ send_ldap_result( conn, op, LDAP_INSUFFICIENT_ACCESS,
+ "", "" );
+ goto return_results;
+ }
+#endif
+
+ if ( (p_ndn = dn_parent( be, e->e_ndn )) != NULL ) {
+ /* parent + rdn + separator(s) + null */
+ if( (p = bdb2i_dn2entry_w( be, p_ndn, &matched )) == NULL) {
+ Debug( LDAP_DEBUG_TRACE, "parent does not exist\n",
+ 0, 0, 0);
+ send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR,
+ "", "");
+ goto return_results;
+ }
+
+#ifndef SLAPD_CHILD_MODIFICATION_WITH_ENTRY_ACL
+ /* check parent for "children" acl */
+ if ( ! access_allowed( be, conn, op, p,
+ "children", NULL, ACL_WRITE ) )
+ {
+ Debug( LDAP_DEBUG_TRACE, "no access to parent\n", 0,
+ 0, 0 );
+ send_ldap_result( conn, op, LDAP_INSUFFICIENT_ACCESS,
+ "", "" );
+ goto return_results;
+ }
+#endif
+
+ p_dn = dn_parent( be, e->e_dn );
+ new_dn = (char *) ch_malloc( strlen( p_dn ) + strlen( newrdn )
+ + 3 );
+ if ( dn_type( e->e_dn ) == DN_X500 ) {
+ strcpy( new_dn, newrdn );
+ strcat( new_dn, ", " );
+ strcat( new_dn, p_dn );
+ } else {
+ char *s;
+ strcpy( new_dn, newrdn );
+ s = strchr( newrdn, '\0' );
+ s--;
+ if ( *s != '.' && *s != '@' ) {
+ if ( (s = strpbrk( dn, ".@" )) != NULL ) {
+ sep[0] = *s;
+ sep[1] = '\0';
+ strcat( new_dn, sep );
+ }
+ }
+ strcat( new_dn, p_dn );
+ }
+
+ } else {
+ /* no parent, modrdn entry directly under root */
+ if( ! be_isroot( be, op->o_ndn ) ) {
+ Debug( LDAP_DEBUG_TRACE, "no parent & not root\n",
+ 0, 0, 0);
+ send_ldap_result( conn, op, LDAP_INSUFFICIENT_ACCESS,
+ "", "");
+ goto return_results;
+ }
+
+ ldap_pvt_thread_mutex_lock(&li->li_root_mutex);
+ rootlock = 1;
+
+ new_dn = ch_strdup( newrdn );
+ }
+
+ new_ndn = dn_normalize_case( ch_strdup( new_dn ) );
+
+ if ( (bdb2i_dn2id ( be, new_ndn ) ) != NOID ) {
+ send_ldap_result( conn, op, LDAP_ALREADY_EXISTS, NULL, NULL );
+ goto return_results;
+ }
+
+ /* check for abandon */
+ ldap_pvt_thread_mutex_lock( &op->o_abandonmutex );
+ if ( op->o_abandon ) {
+ ldap_pvt_thread_mutex_unlock( &op->o_abandonmutex );
+ goto return_results;
+ }
+ ldap_pvt_thread_mutex_unlock( &op->o_abandonmutex );
+
+ /* add new one */
+ if ( bdb2i_dn2id_add( be, new_ndn, e->e_id ) != 0 ) {
+ send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR, NULL, NULL );
+ goto return_results;
+ }
+
+ /* delete old one */
+ if ( bdb2i_dn2id_delete( be, e->e_ndn ) != 0 ) {
+ send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR, NULL, NULL );
+ goto return_results;
+ }
+
+ (void) bdb2i_cache_delete_entry( &li->li_cache, e );
+ free( e->e_dn );
+ free( e->e_ndn );
+ e->e_dn = new_dn;
+ e->e_ndn = new_ndn;
+
+ /* XXX
+ * At some point here we need to update the attribute values in
+ * the entry itself that were effected by this RDN change
+ * (respecting the value of the deleteoldrdn parameter).
+ *
+ * Since the code to do this has not yet been written, treat this
+ * omission as a (documented) bug.
+ */
+
+ /* id2entry index */
+ if ( bdb2i_id2entry_add( be, e ) != 0 ) {
+ entry_free( e );
+ send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR, "", "" );
+ goto return_results;
+ }
+
+ send_ldap_result( conn, op, LDAP_SUCCESS, NULL, NULL );
+ rc = 0;
+
+return_results:
+ if( new_dn != NULL ) free( new_dn );
+ if( new_ndn != NULL ) free( new_ndn );
+ if( p_dn != NULL ) free( p_dn );
+ if( p_ndn != NULL ) free( p_ndn );
+
+ if( matched != NULL ) free( matched );
+
+ if( p != NULL ) {
+ /* free parent and writer lock */
+ bdb2i_cache_return_entry_w( &li->li_cache, p );
+
+ }
+
+ if ( rootlock ) {
+ /* release root writer lock */
+ ldap_pvt_thread_mutex_unlock(&li->li_root_mutex);
+ }
+
+ /* free entry and writer lock */
+ bdb2i_cache_return_entry_w( &li->li_cache, e );
+ return( rc );
+}
+
+
+int
+bdb2_back_modrdn(
+ Backend *be,
+ Connection *conn,
+ Operation *op,
+ char *dn,
+ char *newrdn,
+ int deleteoldrdn
+)
+{
+ DB_LOCK lock;
+ struct ldbminfo *li = (struct ldbminfo *) be->be_private;
+
+ struct timeval time1, time2;
+ char *elapsed_time;
+ int ret;
+
+ gettimeofday( &time1, NULL );
+
+ if ( bdb2i_enter_backend_w( &li->li_db_env, &lock ) != 0 ) {
+
+ send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR, "", "" );
+ return( -1 );
+
+ }
+
+ ret = bdb2i_back_modrdn_internal( be, conn, op, dn,
+ newrdn, deleteoldrdn );
+
+ (void) bdb2i_leave_backend( &li->li_db_env, lock );
+
+ if ( bdb2i_do_timing ) {
+
+ gettimeofday( &time2, NULL);
+ elapsed_time = bdb2i_elapsed( time1, time2 );
+ Debug( LDAP_DEBUG_ANY, "conn=%d op=%d MODRDN elapsed=%s\n",
+ conn->c_connid, op->o_opid, elapsed_time );
+ free( elapsed_time );
+
+ }
+
+ return( ret );
+}
+
+
--- /dev/null
+/* id.c - keep track of the next id to be given out */
+
+#include "portable.h"
+
+#include <stdio.h>
+
+#include <ac/socket.h>
+
+#ifdef HAVE_SYS_PARAM_H
+#include <sys/param.h>
+#endif
+
+#include "slap.h"
+#include "back-bdb2.h"
+
+static ID
+next_id_read( Backend *be )
+{
+ struct ldbminfo *li = (struct ldbminfo *) be->be_private;
+ ID id;
+ char buf[20];
+ char* file = li->li_nextid_file;
+ FILE* fp;
+
+ if ( (fp = fopen( file, "r" )) == NULL ) {
+ Debug( LDAP_DEBUG_ANY,
+ "next_id_read: could not open \"%s\"\n",
+ file, 0, 0 );
+ return NOID;
+ }
+
+ if ( fgets( buf, sizeof(buf), fp ) == NULL ) {
+ Debug( LDAP_DEBUG_ANY,
+ "next_id_read: could not fgets nextid from \"%s\"\n",
+ file, 0, 0 );
+ fclose( fp );
+ return NOID;
+ }
+
+ id = atol( buf );
+ fclose( fp );
+
+ if(id < 1) {
+ Debug( LDAP_DEBUG_ANY,
+ "next_id_read %lu: atol(%s) return non-positive integer\n",
+ id, buf, 0 );
+ return NOID;
+ }
+
+ return id;
+}
+
+static int
+next_id_write( Backend *be, ID id )
+{
+ struct ldbminfo *li = (struct ldbminfo *) be->be_private;
+ char buf[20];
+ char* file = li->li_nextid_file;
+ FILE* fp;
+ int rc;
+
+ if ( (fp = fopen( file, "w" )) == NULL ) {
+ Debug( LDAP_DEBUG_ANY, "next_id_write(%lu): could not open \"%s\"\n",
+ id, file, 0 );
+ return -1;
+ }
+
+ rc = 0;
+
+ if ( fprintf( fp, "%ld\n", id ) == EOF ) {
+ Debug( LDAP_DEBUG_ANY, "next_id_write(%lu): cannot fprintf\n",
+ id, 0, 0 );
+ rc = -1;
+ }
+
+ if( fclose( fp ) != 0 ) {
+ Debug( LDAP_DEBUG_ANY, "next_id_write %lu: cannot fclose\n",
+ id, 0, 0 );
+ rc = -1;
+ }
+
+ return rc;
+}
+
+int
+bdb2i_next_id_save( Backend *be )
+{
+ struct ldbminfo *li = (struct ldbminfo *) be->be_private;
+ ID id = next_id_get( be );
+ int rc = next_id_write( be, id );
+
+ if (rc == 0) {
+ li->li_nextid_wrote = id;
+ }
+
+ return rc;
+}
+
+ID
+bdb2i_next_id( Backend *be )
+{
+ struct ldbminfo *li = (struct ldbminfo *) be->be_private;
+ ID id;
+
+ ldap_pvt_thread_mutex_lock( &li->li_nextid_mutex );
+
+ /* first time in here since startup - try to read the nexid */
+ if ( li->li_nextid == NOID ) {
+ li->li_nextid = next_id_read( be );
+
+ if ( li->li_nextid == NOID ) {
+ li->li_nextid = 1;
+ }
+
+#if SLAPD_NEXTID_CHUNK > 1
+ li->li_nextid_wrote = li->li_nextid;
+#endif
+ }
+
+ id = li->li_nextid++;
+
+#if SLAPD_NEXTID_CHUNK > 1
+ if ( li->li_nextid > li->li_nextid_wrote ) {
+ li->li_nextid_wrote += SLAPD_NEXTID_CHUNK;
+ (void) next_id_write( be, li->li_nextid_wrote );
+ }
+#else
+ (void) next_id_write( be, li->li_nextid );
+#endif
+
+ ldap_pvt_thread_mutex_unlock( &li->li_nextid_mutex );
+ return( id );
+}
+
+void
+bdb2i_next_id_return( Backend *be, ID id )
+{
+#ifdef SLAPD_NEXTID_RETURN
+ struct ldbminfo *li = (struct ldbminfo *) be->be_private;
+
+ ldap_pvt_thread_mutex_lock( &li->li_nextid_mutex );
+
+ if ( id != li->li_nextid - 1 ) {
+ ldap_pvt_thread_mutex_unlock( &li->li_nextid_mutex );
+ return;
+ }
+
+ li->li_nextid--;
+
+#if !( SLAPD_NEXTID_CHUCK > 1 )
+ (void) next_id_write( be, li->li_nextid );
+#endif
+
+ ldap_pvt_thread_mutex_unlock( &li->li_nextid_mutex );
+#endif
+}
+
+ID
+bdb2i_next_id_get( Backend *be )
+{
+ struct ldbminfo *li = (struct ldbminfo *) be->be_private;
+ ID id;
+
+ ldap_pvt_thread_mutex_lock( &li->li_nextid_mutex );
+
+ /* first time in here since startup - try to read the nexid */
+ if ( li->li_nextid == NOID ) {
+ li->li_nextid = next_id_read( be );
+
+ if ( li->li_nextid == NOID ) {
+ li->li_nextid = 1;
+ }
+
+#if SLAPD_NEXTID_CHUNK > 1
+ li->li_nextid_wrote = li->li_nextid;
+#endif
+ }
+
+ id = li->li_nextid;
+
+ ldap_pvt_thread_mutex_unlock( &li->li_nextid_mutex );
+
+ return( id );
+}
--- /dev/null
+/* porter.c - port functions of the bdb2 backend */
+
+#include "portable.h"
+
+#include <stdio.h>
+#include <errno.h>
+
+#include <ac/string.h>
+
+#include "slap.h"
+#include "back-bdb2.h"
+
+#define PORTER_OBJ "bdb2_backend"
+
+int bdb2i_with_dbenv = 0;
+
+
+static int
+bdb2i_enter_backend( DB_ENV *dbEnv, DB_LOCK *lock, int writer )
+{
+ u_int32_t locker;
+ db_lockmode_t lock_type;
+ DBT lock_dbt;
+ int ret;
+
+ if ( !bdb2i_with_dbenv ) return( 0 );
+
+ if ( ( ret = lock_id( dbEnv->lk_info, &locker )) != 0 ) {
+
+ Debug( LDAP_DEBUG_ANY,
+ "bdb2i_enter_backend(): unable to get locker id -- %s\n",
+ strerror( ret ), 0, 0 );
+ return( ret );
+
+ }
+
+ lock_type = writer ? DB_LOCK_WRITE : DB_LOCK_READ;
+ lock_dbt.data = PORTER_OBJ;
+ lock_dbt.size = strlen( PORTER_OBJ );
+
+ switch ( ( ret = lock_get( dbEnv->lk_info, locker, 0, &lock_dbt,
+ lock_type, lock ))) {
+
+ case 0:
+ Debug( LDAP_DEBUG_ANY, "bdb2i_enter_backend() -- %s lock granted\n",
+ writer ? "write" : "read", 0, 0 );
+ break;
+
+ case DB_LOCK_NOTGRANTED:
+ Debug( LDAP_DEBUG_ANY,
+ "bdb2i_enter_backend() -- %s lock NOT granted\n",
+ writer ? "write" : "read", 0, 0 );
+ break;
+
+ case DB_LOCK_DEADLOCK:
+ Debug( LDAP_DEBUG_ANY,
+ "bdb2i_enter_backend() -- %s lock returned DEADLOCK\n",
+ writer ? "write" : "read", 0, 0 );
+ break;
+
+ default:
+ Debug( LDAP_DEBUG_ANY,
+ "bdb2i_enter_backend() -- %s lock returned ERROR: %s\n",
+ writer ? "write" : "read", strerror( errno ), 0 );
+ ret = errno;
+ break;
+
+ }
+
+ return( ret );
+}
+
+
+int
+bdb2i_enter_backend_r( DB_ENV *dbEnv, DB_LOCK *lock )
+{
+ return( bdb2i_enter_backend( dbEnv, lock, 0 ));
+}
+
+
+int
+bdb2i_enter_backend_w( DB_ENV *dbEnv, DB_LOCK *lock )
+{
+ return( bdb2i_enter_backend( dbEnv, lock, 1 ));
+}
+
+
+int
+bdb2i_leave_backend( DB_ENV *dbEnv, DB_LOCK lock )
+{
+ int ret;
+
+ if ( !bdb2i_with_dbenv ) return( 0 );
+
+ switch( ( ret = lock_put( dbEnv->lk_info, lock ))) {
+
+ case 0:
+ Debug( LDAP_DEBUG_ANY, "bdb2i_leave_backend() -- lock released\n",
+ 0, 0, 0 );
+ break;
+
+ case DB_LOCK_NOTHELD:
+ Debug( LDAP_DEBUG_ANY,
+ "bdb2i_leave_backend() -- lock NOT held\n",
+ 0, 0, 0 );
+ break;
+
+ case DB_LOCK_DEADLOCK:
+ Debug( LDAP_DEBUG_ANY,
+ "bdb2i_leave_backend() -- lock returned DEADLOCK\n",
+ 0, 0, 0 );
+ break;
+
+ default:
+ Debug( LDAP_DEBUG_ANY,
+ "bdb2i_leave_backend() -- lock returned ERROR: %s\n",
+ strerror( errno ), 0, 0 );
+ ret = errno;
+ break;
+
+ }
+
+ return( ret );
+
+}
+
+
--- /dev/null
+#ifndef _PROTO_BACK_BDB2
+#define _PROTO_BACK_BDB2
+
+#include <ldap_cdefs.h>
+
+#include "external.h"
+
+LDAP_BEGIN_DECL
+
+/*
+ * alias.c
+ */
+Entry *bdb2i_derefAlias_r LDAP_P((
+ Backend *be,
+ Connection *conn,
+ Operation *op,
+ Entry *e ));
+char *bdb2i_derefDN LDAP_P((
+ Backend *be,
+ Connection *conn,
+ Operation *op,
+ char *dn ));
+
+/*
+ * attr.c
+ */
+
+void bdb2i_attr_masks LDAP_P(( struct ldbminfo *li, char *type, int *indexmask,
+ int *syntaxmask ));
+void bdb2i_attr_index_config LDAP_P(( struct ldbminfo *li, char *fname,
+ int lineno, int argc, char **argv, int init ));
+
+/*
+ * cache.c
+ */
+
+void bdb2i_cache_set_state LDAP_P(( struct cache *cache, Entry *e, int state ));
+void bdb2i_cache_return_entry_r LDAP_P(( struct cache *cache, Entry *e ));
+void bdb2i_cache_return_entry_w LDAP_P(( struct cache *cache, Entry *e ));
+int bdb2i_cache_add_entry_lock LDAP_P(( struct cache *cache, Entry *e,
+ int state ));
+ID bdb2i_cache_find_entry_dn2id LDAP_P(( Backend *be, struct cache *cache,
+ char *dn ));
+Entry * bdb2i_cache_find_entry_id LDAP_P(( struct cache *cache, ID id, int rw ));
+int bdb2i_cache_delete_entry LDAP_P(( struct cache *cache, Entry *e ));
+
+/*
+ * dbcache.c
+ */
+
+struct dbcache * bdb2i_cache_open LDAP_P(( Backend *be, char *name, char *suffix,
+ int flags ));
+void bdb2i_cache_close LDAP_P(( Backend *be, struct dbcache *db ));
+void bdb2i_cache_really_close LDAP_P(( Backend *be, struct dbcache *db ));
+void bdb2i_cache_flush_all LDAP_P(( Backend *be ));
+Datum bdb2i_cache_fetch LDAP_P(( struct dbcache *db, Datum key ));
+int bdb2i_cache_store LDAP_P(( struct dbcache *db, Datum key, Datum data, int flags ));
+int bdb2i_cache_delete LDAP_P(( struct dbcache *db, Datum key ));
+
+/*
+ * dn2id.c
+ */
+
+int bdb2i_dn2id_add LDAP_P(( Backend *be, char *dn, ID id ));
+ID bdb2i_dn2id LDAP_P(( Backend *be, char *dn ));
+int bdb2i_dn2id_delete LDAP_P(( Backend *be, char *dn ));
+Entry * bdb2i_dn2entry_r LDAP_P(( Backend *be, char *dn, char **matched ));
+Entry * bdb2i_dn2entry_w LDAP_P(( Backend *be, char *dn, char **matched ));
+
+/*
+ * filterindex.c
+ */
+
+ID_BLOCK * bdb2i_filter_candidates LDAP_P(( Backend *be, Filter *f ));
+
+/*
+ * id2children.c
+ */
+
+int bdb2i_id2children_add LDAP_P(( Backend *be, Entry *p, Entry *e ));
+int bdb2i_id2children_remove LDAP_P(( Backend *be, Entry *p, Entry *e ));
+int bdb2i_has_children LDAP_P(( Backend *be, Entry *p ));
+
+/*
+ * id2entry.c
+ */
+
+int bdb2i_id2entry_add LDAP_P(( Backend *be, Entry *e ));
+int bdb2i_id2entry_delete LDAP_P(( Backend *be, Entry *e ));
+Entry * bdb2i_id2entry LDAP_P(( Backend *be, ID id, int rw ));
+Entry * bdb2i_id2entry_r LDAP_P(( Backend *be, ID id ));
+Entry * bdb2i_id2entry_w LDAP_P(( Backend *be, ID id ));
+
+/*
+ * idl.c
+ */
+
+ID_BLOCK * bdb2i_idl_alloc LDAP_P(( int nids ));
+ID_BLOCK * bdb2i_idl_allids LDAP_P(( Backend *be ));
+void bdb2i_idl_free LDAP_P(( ID_BLOCK *idl ));
+ID_BLOCK * bdb2i_idl_fetch LDAP_P(( Backend *be, struct dbcache *db, Datum key ));
+int bdb2i_idl_insert_key LDAP_P(( Backend *be, struct dbcache *db, Datum key, ID id ));
+int bdb2i_idl_insert LDAP_P(( ID_BLOCK **idl, ID id, int maxids ));
+int bdb2i_idl_delete_key LDAP_P(( Backend *be, struct dbcache *db, Datum key, ID id ));
+ID_BLOCK * bdb2i_idl_intersection LDAP_P(( Backend *be, ID_BLOCK *a, ID_BLOCK *b ));
+ID_BLOCK * bdb2i_idl_union LDAP_P(( Backend *be, ID_BLOCK *a, ID_BLOCK *b ));
+ID_BLOCK * bdb2i_idl_notin LDAP_P(( Backend *be, ID_BLOCK *a, ID_BLOCK *b ));
+ID bdb2i_idl_firstid LDAP_P(( ID_BLOCK *idl ));
+ID bdb2i_idl_nextid LDAP_P(( ID_BLOCK *idl, ID id ));
+
+/*
+ * index.c
+ */
+
+int bdb2i_index_add_entry LDAP_P(( Backend *be, Entry *e ));
+int bdb2i_index_add_mods LDAP_P(( Backend *be, LDAPModList *ml, ID id ));
+ID_BLOCK * bdb2i_index_read LDAP_P(( Backend *be, char *type, int indextype, char *val ));
+int bdb2i_index_add_values LDAP_P(( Backend *be, char *type, struct berval **vals, ID id ));
+
+/*
+ * kerberos.c
+ */
+
+#ifdef HAVE_KERBEROS
+/* bdb2i_krbv4_ldap_auth LDAP_P(( Backend *be, struct berval *cred, AUTH_DAT *ad )); */
+#endif
+
+/*
+ * nextid.c
+ */
+
+ID bdb2i_next_id LDAP_P(( Backend *be ));
+void bdb2i_next_id_return LDAP_P(( Backend *be, ID id ));
+ID bdb2i_next_id_get LDAP_P(( Backend *be ));
+int bdb2i_next_id_save LDAP_P(( Backend *be ));
+
+/*
+ * timing.c
+ */
+
+char *bdb2i_elapsed LDAP_P(( struct timeval firsttime,
+ struct timeval secondtime ));
+
+/*
+ * porter.c
+ */
+
+int bdb2i_enter_backend_r LDAP_P(( DB_ENV *dbEnv, DB_LOCK *lock ));
+int bdb2i_enter_backend_w LDAP_P(( DB_ENV *dbEnv, DB_LOCK *lock ));
+int bdb2i_leave_backend LDAP_P(( DB_ENV *dbEnv, DB_LOCK lock ));
+
+/*
+ * txn.c
+ */
+
+void bdb2i_txn_head_init LDAP_P(( BDB2_TXN_HEAD *head ));
+void bdb2i_txn_attr_config LDAP_P((
+ struct ldbminfo *li,
+ char *attr,
+ int open ));
+void bdb2i_txn_open_files LDAP_P(( struct ldbminfo *li ));
+void bdb2i_txn_close_files LDAP_P(( BDB2_TXN_HEAD *head ));
+BDB2_TXN_FILES *bdb2i_get_db_file_cache LDAP_P((
+ struct ldbminfo *li,
+ char *name ));
+void bdb2i_check_additional_attr_index LDAP_P(( struct ldbminfo *li ));
+void bdb2i_check_default_attr_index_add LDAP_P((
+ struct ldbminfo *li,
+ Entry *e ));
+void bdb2i_check_default_attr_index_mod LDAP_P((
+ struct ldbminfo *li,
+ LDAPModList *modlist ));
+
+
+
+LDAP_END_DECL
+#endif
--- /dev/null
+/* search.c - bdb2 backend search function */
+
+#include "portable.h"
+
+#include <stdio.h>
+
+#include <ac/string.h>
+#include <ac/socket.h>
+
+#include "slap.h"
+#include "back-bdb2.h"
+#include "proto-back-bdb2.h"
+
+static ID_BLOCK *base_candidates(Backend *be, Connection *conn, Operation *op, char *base, Filter *filter, char **attrs, int attrsonly, char **matched, int *err);
+static ID_BLOCK *onelevel_candidates(Backend *be, Connection *conn, Operation *op, char *base, Filter *filter, char **attrs, int attrsonly, char **matched, int *err);
+static ID_BLOCK *subtree_candidates(Backend *be, Connection *conn, Operation *op, char *base, Filter *filter, char **attrs, int attrsonly, char **matched, Entry *e, int *err, int lookupbase);
+
+#define GRABSIZE BUFSIZ
+
+#define MAKE_SPACE( n ) { \
+ if ( rcur + n > rbuf + rmaxsize ) { \
+ int offset = rcur - rbuf; \
+ rbuf = ch_realloc( rbuf, rmaxsize + GRABSIZE ); \
+ rmaxsize += GRABSIZE; \
+ rcur = rbuf + offset; \
+ } \
+}
+
+static int
+bdb2i_back_search_internal(
+ Backend *be,
+ Connection *conn,
+ Operation *op,
+ char *base,
+ int scope,
+ int deref,
+ int slimit,
+ int tlimit,
+ Filter *filter,
+ char *filterstr,
+ char **attrs,
+ int attrsonly
+)
+{
+ struct ldbminfo *li = (struct ldbminfo *) be->be_private;
+ int err;
+ time_t stoptime;
+ ID_BLOCK *candidates;
+ ID id;
+ Entry *e;
+ Attribute *ref;
+ char *matched = NULL;
+ int rmaxsize, nrefs;
+ char *rbuf, *rcur, *r;
+ int nentries = 0;
+ char *realBase;
+
+ Debug(LDAP_DEBUG_ARGS, "=> bdb2i_back_search\n", 0, 0, 0);
+
+ if ( tlimit == 0 && be_isroot( be, op->o_ndn ) ) {
+ tlimit = -1; /* allow root to set no limit */
+ } else {
+ tlimit = (tlimit > be->be_timelimit || tlimit < 1) ?
+ be->be_timelimit : tlimit;
+ stoptime = op->o_time + tlimit;
+ }
+ if ( slimit == 0 && be_isroot( be, op->o_ndn ) ) {
+ slimit = -1; /* allow root to set no limit */
+ } else {
+ slimit = (slimit > be->be_sizelimit || slimit < 1) ?
+ be->be_sizelimit : slimit;
+ }
+
+ /*
+ * check and apply aliasing where the dereferencing applies to
+ * the subordinates of the base
+ */
+
+ switch ( deref ) {
+ case LDAP_DEREF_FINDING:
+ case LDAP_DEREF_ALWAYS:
+ realBase = bdb2i_derefDN ( be, conn, op, base );
+ break;
+ default:
+ realBase = ch_strdup(base);
+ }
+
+ (void) dn_normalize_case( realBase );
+
+ Debug( LDAP_DEBUG_TRACE, "using base \"%s\"\n",
+ realBase, 0, 0 );
+
+ switch ( scope ) {
+ case LDAP_SCOPE_BASE:
+ candidates = base_candidates( be, conn, op, realBase, filter,
+ attrs, attrsonly, &matched, &err );
+ break;
+
+ case LDAP_SCOPE_ONELEVEL:
+ candidates = onelevel_candidates( be, conn, op, realBase, filter,
+ attrs, attrsonly, &matched, &err );
+ break;
+
+ case LDAP_SCOPE_SUBTREE:
+ candidates = subtree_candidates( be, conn, op, realBase, filter,
+ attrs, attrsonly, &matched, NULL, &err, 1 );
+ break;
+
+ default:
+ send_ldap_result( conn, op, LDAP_PROTOCOL_ERROR, "",
+ "Bad scope" );
+ if( realBase != NULL) {
+ free( realBase );
+ }
+ return( -1 );
+ }
+
+ /* null candidates means we could not find the base object */
+ if ( candidates == NULL ) {
+ send_ldap_result( conn, op, err, matched, "" );
+ if ( matched != NULL ) {
+ free( matched );
+ }
+ if( realBase != NULL) {
+ free( realBase );
+ }
+ return( -1 );
+ }
+
+ if ( matched != NULL ) {
+ free( matched );
+ }
+
+ rmaxsize = 0;
+ nrefs = 0;
+ rbuf = rcur = NULL;
+ MAKE_SPACE( sizeof("Referral:") + 1 );
+ strcpy( rbuf, "Referral:" );
+ rcur = strchr( rbuf, '\0' );
+ for ( id = bdb2i_idl_firstid( candidates ); id != NOID;
+ id = bdb2i_idl_nextid( candidates, id ) ) {
+ /* check for abandon */
+ ldap_pvt_thread_mutex_lock( &op->o_abandonmutex );
+ if ( op->o_abandon ) {
+ ldap_pvt_thread_mutex_unlock( &op->o_abandonmutex );
+ bdb2i_idl_free( candidates );
+ free( rbuf );
+ if( realBase != NULL) {
+ free( realBase );
+ }
+ return( 0 );
+ }
+ ldap_pvt_thread_mutex_unlock( &op->o_abandonmutex );
+
+ /* check time limit */
+ ldap_pvt_thread_mutex_lock( ¤ttime_mutex );
+ time( ¤ttime );
+ if ( tlimit != -1 && currenttime > stoptime ) {
+ ldap_pvt_thread_mutex_unlock( ¤ttime_mutex );
+ send_ldap_search_result( conn, op,
+ LDAP_TIMELIMIT_EXCEEDED, NULL, nrefs > 0 ? rbuf :
+ NULL, nentries );
+ bdb2i_idl_free( candidates );
+ free( rbuf );
+ if( realBase != NULL) {
+ free( realBase );
+ }
+ return( 0 );
+ }
+ ldap_pvt_thread_mutex_unlock( ¤ttime_mutex );
+
+ /* get the entry with reader lock */
+ if ( (e = bdb2i_id2entry_r( be, id )) == NULL ) {
+ Debug( LDAP_DEBUG_ARGS, "candidate %lu not found\n",
+ id, 0, 0 );
+ continue;
+ }
+
+ /*
+ * if it's a referral, add it to the list of referrals. only do
+ * this for subtree searches, and don't check the filter explicitly
+ * here since it's only a candidate anyway.
+ */
+ if ( scope == LDAP_SCOPE_SUBTREE &&
+ e->e_ndn != NULL &&
+ strncmp( e->e_ndn, "REF=", 4 ) == 0 &&
+ (ref = attr_find( e->e_attrs, "ref" )) != NULL )
+ {
+ int i, len;
+
+ if ( ref->a_vals == NULL ) {
+ Debug( LDAP_DEBUG_ANY, "null ref in (%s)\n",
+ e->e_dn, 0, 0 );
+ } else {
+ for ( i = 0; ref->a_vals[i] != NULL; i++ ) {
+ /* referral + newline + null */
+ MAKE_SPACE( ref->a_vals[i]->bv_len + 2 );
+ *rcur++ = '\n';
+ strncpy( rcur, ref->a_vals[i]->bv_val,
+ ref->a_vals[i]->bv_len );
+ rcur = rcur + ref->a_vals[i]->bv_len;
+ *rcur = '\0';
+ nrefs++;
+ }
+ }
+
+ /* otherwise it's an entry - see if it matches the filter */
+ } else {
+ /* if it matches the filter and scope, send it */
+ if ( test_filter( be, conn, op, e, filter ) == 0 ) {
+ int scopeok;
+ char *dn;
+
+ /* check scope */
+ scopeok = 1;
+ if ( scope == LDAP_SCOPE_ONELEVEL ) {
+ if ( (dn = dn_parent( be, e->e_dn )) != NULL ) {
+ (void) dn_normalize_case( dn );
+ scopeok = (dn == realBase)
+ ? 1
+ : (strcmp( dn, realBase ) ? 0 : 1 );
+ free( dn );
+ } else {
+ scopeok = (realBase == NULL || *realBase == '\0');
+ }
+ } else if ( scope == LDAP_SCOPE_SUBTREE ) {
+ dn = ch_strdup( e->e_ndn );
+ scopeok = dn_issuffix( dn, realBase );
+ free( dn );
+ }
+
+ if ( scopeok ) {
+ /* check size limit */
+ if ( --slimit == -1 ) {
+ bdb2i_cache_return_entry_r( &li->li_cache, e );
+ send_ldap_search_result( conn, op,
+ LDAP_SIZELIMIT_EXCEEDED, NULL,
+ nrefs > 0 ? rbuf : NULL, nentries );
+ bdb2i_idl_free( candidates );
+ free( rbuf );
+
+ if( realBase != NULL) {
+ free( realBase );
+ }
+ return( 0 );
+ }
+
+ /*
+ * check and apply aliasing where the dereferencing applies to
+ * the subordinates of the base
+ */
+ switch ( deref ) {
+ case LDAP_DEREF_SEARCHING:
+ case LDAP_DEREF_ALWAYS:
+ {
+ Entry *newe = bdb2i_derefAlias_r( be, conn, op, e );
+ if ( newe == NULL ) { /* problem with the alias */
+ bdb2i_cache_return_entry_r( &li->li_cache, e );
+ e = NULL;
+ }
+ else if ( newe != e ) { /* reassign e */
+ bdb2i_cache_return_entry_r( &li->li_cache, e );
+ e = newe;
+ }
+ }
+ break;
+ }
+
+ if (e) {
+ switch ( send_search_entry( be, conn, op, e,
+ attrs, attrsonly ) ) {
+ case 0: /* entry sent ok */
+ nentries++;
+ break;
+ case 1: /* entry not sent */
+ break;
+ case -1: /* connection closed */
+ bdb2i_cache_return_entry_r( &li->li_cache, e );
+ bdb2i_idl_free( candidates );
+ free( rbuf );
+
+ if( realBase != NULL) {
+ free( realBase );
+ }
+ return( 0 );
+ }
+ }
+ }
+ }
+ }
+
+ if( e != NULL ) {
+ /* free reader lock */
+ bdb2i_cache_return_entry_r( &li->li_cache, e );
+ }
+
+ ldap_pvt_thread_yield();
+ }
+ bdb2i_idl_free( candidates );
+ if ( nrefs > 0 ) {
+ send_ldap_search_result( conn, op, LDAP_PARTIAL_RESULTS, NULL,
+ rbuf, nentries );
+ } else {
+ send_ldap_search_result( conn, op, LDAP_SUCCESS, NULL, NULL,
+ nentries );
+ }
+ free( rbuf );
+
+ if( realBase != NULL) {
+ free( realBase );
+ }
+
+ return( 0 );
+}
+
+
+int
+bdb2_back_search(
+ Backend *be,
+ Connection *conn,
+ Operation *op,
+ char *base,
+ int scope,
+ int deref,
+ int slimit,
+ int tlimit,
+ Filter *filter,
+ char *filterstr,
+ char **attrs,
+ int attrsonly
+)
+{
+ DB_LOCK lock;
+ struct ldbminfo *li = (struct ldbminfo *) be->be_private;
+
+ struct timeval time1, time2;
+ char *elapsed_time;
+ int ret;
+
+ gettimeofday( &time1, NULL );
+
+ if ( bdb2i_enter_backend_r( &li->li_db_env, &lock ) != 0 ) {
+
+ send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR, "", "" );
+ return( -1 );
+
+ }
+
+ ret = bdb2i_back_search_internal( be, conn, op, base, scope, deref,
+ slimit, tlimit, filter, filterstr, attrs, attrsonly );
+
+ (void) bdb2i_leave_backend( &li->li_db_env, lock );
+
+ if ( bdb2i_do_timing ) {
+
+ gettimeofday( &time2, NULL);
+ elapsed_time = bdb2i_elapsed( time1, time2 );
+ Debug( LDAP_DEBUG_ANY, "conn=%d op=%d SRCH elapsed=%s\n",
+ conn->c_connid, op->o_opid, elapsed_time );
+ free( elapsed_time );
+
+ }
+
+ return( ret );
+}
+
+
+static ID_BLOCK *
+base_candidates(
+ Backend *be,
+ Connection *conn,
+ Operation *op,
+ char *base,
+ Filter *filter,
+ char **attrs,
+ int attrsonly,
+ char **matched,
+ int *err
+)
+{
+ struct ldbminfo *li = (struct ldbminfo *) be->be_private;
+ int rc;
+ ID id;
+ ID_BLOCK *idl;
+ Entry *e;
+
+ Debug(LDAP_DEBUG_TRACE, "base_candidates: base: \"%s\"\n", base, 0, 0);
+
+ *err = LDAP_SUCCESS;
+
+ /* get entry with reader lock */
+ if ( (e = bdb2i_dn2entry_r( be, base, matched )) == NULL ) {
+ *err = LDAP_NO_SUCH_OBJECT;
+ return( NULL );
+ }
+
+ /* check for deleted */
+
+ idl = bdb2i_idl_alloc( 1 );
+ bdb2i_idl_insert( &idl, e->e_id, 1 );
+
+
+ /* free reader lock */
+ bdb2i_cache_return_entry_r( &li->li_cache, e );
+
+ return( idl );
+}
+
+static ID_BLOCK *
+onelevel_candidates(
+ Backend *be,
+ Connection *conn,
+ Operation *op,
+ char *base,
+ Filter *filter,
+ char **attrs,
+ int attrsonly,
+ char **matched,
+ int *err
+)
+{
+ struct ldbminfo *li = (struct ldbminfo *) be->be_private;
+ Entry *e = NULL;
+ Filter *f;
+ char buf[20];
+ ID_BLOCK *candidates;
+
+ Debug(LDAP_DEBUG_TRACE, "onelevel_candidates: base: \"%s\"\n", base, 0, 0);
+
+ *err = LDAP_SUCCESS;
+
+ /* get the base object with reader lock */
+ if ( base != NULL && *base != '\0' &&
+ (e = bdb2i_dn2entry_r( be, base, matched )) == NULL )
+ {
+ *err = LDAP_NO_SUCH_OBJECT;
+ return( NULL );
+ }
+
+ /*
+ * modify the filter to be something like this:
+ *
+ * parent=baseobject & originalfilter
+ */
+
+ f = (Filter *) ch_malloc( sizeof(Filter) );
+ f->f_next = NULL;
+ f->f_choice = LDAP_FILTER_AND;
+ f->f_and = (Filter *) ch_malloc( sizeof(Filter) );
+ f->f_and->f_choice = LDAP_FILTER_EQUALITY;
+ f->f_and->f_ava.ava_type = ch_strdup( "id2children" );
+ sprintf( buf, "%ld", e != NULL ? e->e_id : 0 );
+ f->f_and->f_ava.ava_value.bv_val = ch_strdup( buf );
+ f->f_and->f_ava.ava_value.bv_len = strlen( buf );
+ f->f_and->f_next = filter;
+
+ /* from here, it's just like subtree_candidates */
+ candidates = subtree_candidates( be, conn, op, base, f, attrs,
+ attrsonly, matched, e, err, 0 );
+
+ /* free up just the filter stuff we allocated above */
+ f->f_and->f_next = NULL;
+ filter_free( f );
+
+ /* free entry and reader lock */
+ if( e != NULL ) {
+ bdb2i_cache_return_entry_r( &li->li_cache, e );
+ }
+ return( candidates );
+}
+
+static ID_BLOCK *
+subtree_candidates(
+ Backend *be,
+ Connection *conn,
+ Operation *op,
+ char *base,
+ Filter *filter,
+ char **attrs,
+ int attrsonly,
+ char **matched,
+ Entry *e,
+ int *err,
+ int lookupbase
+)
+{
+ struct ldbminfo *li = (struct ldbminfo *) be->be_private;
+ Filter *f, **filterarg_ptr;
+ ID_BLOCK *candidates;
+
+ Debug(LDAP_DEBUG_TRACE, "subtree_candidates: base: \"%s\" %s\n",
+ base ? base : "NULL", lookupbase ? "lookupbase" : "", 0);
+
+ /*
+ * get the base object - unless we already have it (from one-level).
+ * also, unless this is a one-level search or a subtree search
+ * starting at the very top of our subtree, we need to modify the
+ * filter to be something like this:
+ *
+ * dn=*baseobjectdn & (originalfilter | ref=*)
+ *
+ * the "objectclass=referral" part is used to select referrals to return
+ */
+
+ *err = LDAP_SUCCESS;
+ f = NULL;
+ if ( lookupbase ) {
+ e = NULL;
+
+ if ( base != NULL && *base != '\0' &&
+ (e = bdb2i_dn2entry_r( be, base, matched )) == NULL )
+ {
+ *err = LDAP_NO_SUCH_OBJECT;
+ return( NULL );
+ }
+
+ if (e) {
+ bdb2i_cache_return_entry_r( &li->li_cache, e );
+ }
+
+ f = (Filter *) ch_malloc( sizeof(Filter) );
+ f->f_next = NULL;
+ f->f_choice = LDAP_FILTER_OR;
+ f->f_or = (Filter *) ch_malloc( sizeof(Filter) );
+ f->f_or->f_choice = LDAP_FILTER_EQUALITY;
+ f->f_or->f_avtype = ch_strdup( "objectclass" );
+ /* Patch to use normalized uppercase */
+ f->f_or->f_avvalue.bv_val = ch_strdup( "REFERRAL" );
+ f->f_or->f_avvalue.bv_len = strlen( "REFERRAL" );
+ filterarg_ptr = &f->f_or->f_next;
+ *filterarg_ptr = filter;
+ filter = f;
+
+ if ( ! be_issuffix( be, base ) ) {
+ f = (Filter *) ch_malloc( sizeof(Filter) );
+ f->f_next = NULL;
+ f->f_choice = LDAP_FILTER_AND;
+ f->f_and = (Filter *) ch_malloc( sizeof(Filter) );
+ f->f_and->f_choice = LDAP_FILTER_SUBSTRINGS;
+ f->f_and->f_sub_type = ch_strdup( "dn" );
+ f->f_and->f_sub_initial = NULL;
+ f->f_and->f_sub_any = NULL;
+ f->f_and->f_sub_final = ch_strdup( base );
+ value_normalize( f->f_and->f_sub_final, SYNTAX_CIS );
+ f->f_and->f_next = filter;
+ filter = f;
+ }
+ }
+
+ candidates = bdb2i_filter_candidates( be, filter );
+
+ /* free up just the parts we allocated above */
+ if ( f != NULL ) {
+ *filterarg_ptr = NULL;
+ filter_free( f );
+ }
+
+ return( candidates );
+}
--- /dev/null
+/* startup.c - startup bdb2 backend */
+
+#include "portable.h"
+
+#include <stdio.h>
+
+#include <ac/string.h>
+#include <ac/socket.h>
+
+#include "ldapconfig.h"
+#include "slap.h"
+#include "back-bdb2.h"
+
+#include "db.h"
+
+static void remove_old_locks( char *home );
+
+
+static void
+bdb2i_db_errcall( char *prefix, char *message )
+{
+ Debug( LDAP_DEBUG_ANY, "dbd2_db_errcall(): %s %s", prefix, message, 0 );
+}
+
+
+void
+bdb2i_back_startup_internal(
+ Backend *be
+)
+{
+ struct ldbminfo *li = (struct ldbminfo *) be->be_private;
+ DB_ENV *dbEnv = &li->li_db_env;
+ int envFlags = DB_CREATE | DB_THREAD | DB_INIT_LOCK | DB_INIT_MPOOL;
+ int err = 0;
+ char *home;
+ char datadir[MAXPATHLEN];
+ char *config[2] = { datadir, NULL };
+
+ /* if the data directory is not an absolute path, have it relative
+ to the current working directory (which should not be configured !) */
+ if ( *li->li_directory != *DEFAULT_DIRSEP ) {
+ char cwd[MAXPATHLEN];
+
+ (void) getcwd( cwd, MAXPATHLEN );
+ sprintf( cwd, "%s%s%s", cwd, DEFAULT_DIRSEP, li->li_directory );
+ free( li->li_directory );
+ li->li_directory = strdup( cwd );
+
+ }
+
+ /* set the DB home directory to the configured one, or the data dir */
+ if ( li->li_dbhome ) {
+
+ if ( *li->li_dbhome != *DEFAULT_DIRSEP ) {
+ char cwd[MAXPATHLEN];
+
+ (void) getcwd( cwd, MAXPATHLEN );
+ sprintf( cwd, "%s%s%s", cwd, DEFAULT_DIRSEP, li->li_dbhome );
+ free( li->li_dbhome );
+ li->li_dbhome = strdup( cwd );
+
+ }
+ home = li->li_dbhome;
+
+ } else {
+
+ home = li->li_directory;
+
+ }
+
+ /* set the DATA_DIR */
+ sprintf( datadir, "DB_DATA_DIR %s", li->li_directory );
+
+ /* general initialization of the environment */
+ memset( dbEnv, 0, sizeof( DB_ENV ));
+ dbEnv->db_errcall = bdb2i_db_errcall;
+ dbEnv->db_errpfx = "==>";
+
+ /* initialize the lock subsystem */
+ dbEnv->lk_max = 0;
+
+ /* remove old locking tables */
+ remove_old_locks( home );
+
+ /* initialize the mpool subsystem */
+ dbEnv->mp_size = (size_t) li->li_dbcachesize;
+
+ /* now do the db_appinit */
+ if ( ( err = db_appinit( home, config, dbEnv, envFlags )) ) {
+ char error[BUFSIZ];
+
+ if ( err < 0 ) sprintf( error, "%ld\n", (long) err );
+ else sprintf( error, "%s\n", strerror( err ));
+
+ fprintf( stderr,
+ "bdb2i_back_startup(): FATAL error in db_appinit() : %s\n",
+ error );
+ exit( 1 );
+
+ }
+
+ bdb2i_with_dbenv = 1;
+
+ /* if there are more index files, add them to the DB file list */
+ bdb2i_check_additional_attr_index( li );
+
+ /* now open all DB files */
+ bdb2i_txn_open_files( li );
+
+}
+
+
+static void
+bdb2i_back_shutdown_internal(
+ Backend *be
+)
+{
+ struct ldbminfo *li = (struct ldbminfo *) be->be_private;
+ DB_ENV *dbEnv = &li->li_db_env;
+ int err;
+
+ /* close all DB files */
+ bdb2i_txn_close_files( &li->li_txn_head );
+
+ /* remove old locking tables */
+ dbEnv->db_errpfx = "bdb2i_back_shutdown(): lock_unlink:";
+ if ( ( err = lock_unlink( NULL, 1, dbEnv )) != 0 )
+ Debug( LDAP_DEBUG_ANY, "bdb2i_back_shutdown(): lock_unlink: %s\n",
+ strerror( err ), 0, 0);
+
+ /* remove old memory pool */
+ dbEnv->db_errpfx = "bdb2i_back_shutdown(): memp_unlink:";
+ if ( ( err = memp_unlink( NULL, 1, dbEnv )) != 0 )
+ Debug( LDAP_DEBUG_ANY, "bdb2i_back_shutdown(): memp_unlink: %s\n",
+ strerror( err ), 0, 0);
+
+ (void) db_appexit( &li->li_db_env );
+
+}
+
+
+void
+bdb2_back_startup(
+ Backend *be
+)
+{
+ struct timeval time1, time2;
+ char *elapsed_time;
+
+ gettimeofday( &time1, NULL );
+
+ bdb2i_back_startup_internal( be );
+
+ if ( bdb2i_do_timing ) {
+
+ gettimeofday( &time2, NULL);
+ elapsed_time = bdb2i_elapsed( time1, time2 );
+ Debug( LDAP_DEBUG_ANY, "START elapsed=%s\n",
+ elapsed_time, 0, 0 );
+ free( elapsed_time );
+
+ }
+}
+
+
+void
+bdb2_back_shutdown(
+ Backend *be
+)
+{
+ struct timeval time1, time2;
+ char *elapsed_time;
+
+ gettimeofday( &time1, NULL );
+
+ bdb2i_back_shutdown_internal( be );
+
+ if ( bdb2i_do_timing ) {
+
+ gettimeofday( &time2, NULL);
+ elapsed_time = bdb2i_elapsed( time1, time2 );
+ Debug( LDAP_DEBUG_ANY, "SHUTDOWN elapsed=%s\n",
+ elapsed_time, 0, 0 );
+ free( elapsed_time );
+
+ }
+}
+
+
+static void
+remove_old_locks( char *home )
+{
+ DB_ENV dbEnv;
+ int err;
+
+ memset( &dbEnv, 0, sizeof( DB_ENV ));
+ dbEnv.db_errcall = stderr;
+ dbEnv.db_errpfx = "remove_old_locks(): db_appinit:";
+ dbEnv.lk_max = 0;
+
+ if ( ( err = db_appinit( home, NULL, &dbEnv, 0 )) != 0 )
+ Debug( LDAP_DEBUG_ANY, "remove_old_locks(): db_appinit: %s\n",
+ strerror( err ), 0, 0);
+
+ dbEnv.db_errpfx = "remove_old_locks(): lock_unlink:";
+ if ( ( err = lock_unlink( NULL, 1, &dbEnv )) != 0 )
+ Debug( LDAP_DEBUG_ANY, "remove_old_locks(): lock_unlink: %s\n",
+ strerror( err ), 0, 0);
+
+ dbEnv.db_errpfx = "remove_old_locks(): db_appexit:";
+ if ( ( err = db_appexit( &dbEnv )) != 0 )
+ Debug( LDAP_DEBUG_ANY, "remove_old_locks(): db_appexit: %s\n",
+ strerror( err ), 0, 0);
+
+}
+
+
--- /dev/null
+/* timing.c - timing bdb2 backend */
+
+#include "portable.h"
+
+#include <stdio.h>
+#include <sys/time.h>
+#include <unistd.h>
+
+#include <ac/string.h>
+
+#include "slap.h"
+#include "back-bdb2.h"
+
+
+int bdb2i_do_timing = 0;
+
+
+char *
+bdb2i_elapsed( struct timeval firsttime, struct timeval secondtime )
+{
+ long int elapsedmicrosec, elapsedsec;
+ char elapsed_string[BUFSIZ];
+
+ elapsedsec = secondtime.tv_sec - firsttime.tv_sec;
+ elapsedmicrosec = secondtime.tv_usec - firsttime.tv_usec;
+ if(elapsedmicrosec < 0) {
+ elapsedmicrosec += 1000000;
+ elapsedsec -= 1;
+ }
+
+ sprintf( elapsed_string, "%ld.%.6ld", elapsedsec, elapsedmicrosec );
+ return( strdup( elapsed_string ));
+}
+
+
--- /dev/null
+/* txn.c - TP support functions of the bdb2 backend */
+
+#include "txn.h"
+
+
+void
+bdb2i_txn_head_init( BDB2_TXN_HEAD *head )
+{
+ int dbFile;
+ BDB2_TXN_FILES **fileNodeH;
+
+ /* for each fixed DB file allocate a file descriptor node and
+ initialize the file's name */
+ fileNodeH = &head->dbFiles;
+ for ( dbFile = BDB2_DB_DN_FILE; dbFile <= BDB2_DB_OC_IDX_FILE; dbFile++ ) {
+
+ char fileName[MAXPATHLEN];
+
+ *fileNodeH = head->dbFileHandle[dbFile] =
+ (BDB2_TXN_FILES *) ch_calloc( 1, sizeof( BDB2_TXN_FILES ));
+ if ( *fileNodeH == NULL ) {
+
+ Debug( LDAP_DEBUG_ANY, "bdb2i_txn_head_init(): out of memory!\n",
+ 0, 0, 0 );
+ exit( 1 );
+
+ }
+
+ sprintf( fileName, "%s%s", bdb2i_fixed_filenames[dbFile], LDBM_SUFFIX );
+ (*fileNodeH)->dbc_name = strdup( fileName );
+
+ fileNodeH = &(*fileNodeH)->next;
+
+ }
+
+}
+
+
+static void
+bdb2i_init_db_file_cache( struct ldbminfo *li, BDB2_TXN_FILES *fileinfo )
+{
+ time_t curtime;
+ struct stat st;
+ char buf[MAXPATHLEN];
+
+ pthread_mutex_lock( ¤ttime_mutex );
+ curtime = currenttime;
+ pthread_mutex_unlock( ¤ttime_mutex );
+
+ fileinfo->dbc_refcnt = 1;
+ fileinfo->dbc_lastref = curtime;
+
+ sprintf( buf, "%s%s%s", li->li_directory, DEFAULT_DIRSEP,
+ fileinfo->dbc_name );
+ if ( stat( buf, &st ) == 0 ) {
+ fileinfo->dbc_blksize = st.st_blksize;
+ } else {
+ fileinfo->dbc_blksize = DEFAULT_BLOCKSIZE;
+ }
+
+ fileinfo->dbc_maxids = ( fileinfo->dbc_blksize / sizeof( ID )) - 2;
+ fileinfo->dbc_maxindirect = ( SLAPD_LDBM_MIN_MAXIDS /
+ fileinfo->dbc_maxids ) + 1;
+
+}
+
+
+void
+bdb2i_txn_attr_config(
+ struct ldbminfo *li,
+ char *attr,
+ int open )
+{
+ BDB2_TXN_HEAD *head = &li->li_txn_head;
+
+ /* the "attribute" 'default' is special */
+ if ( strcasecmp( attr, "default" )) {
+
+ /* create a new index file node, if the index is not known already */
+ BDB2_TXN_FILES **fileNodeH;
+ char fileName[MAXPATHLEN];
+
+ sprintf( fileName, "%s%s", attr, LDBM_SUFFIX );
+
+ /* search for the end of the list or a node describing
+ the current attribute */
+ for ( fileNodeH = &head->dbFiles;
+ ( *fileNodeH && strcasecmp( (*fileNodeH)->dbc_name, fileName ));
+ fileNodeH = &(*fileNodeH)->next ) {
+
+ }
+
+ /* unless we have that attribute already... */
+ if ( *fileNodeH == NULL ) {
+ BDB2_TXN_FILES *p;
+
+ Debug( LDAP_DEBUG_TRACE,
+ "bdb2i_txn_attr_config(): adding node for \"%s\"\n",
+ fileName, 0, 0 );
+
+ /* if we're out of memory, we have to see, how to exit... */
+ if ( ( *fileNodeH = p = (BDB2_TXN_FILES *)
+ ch_calloc( 1, sizeof( BDB2_TXN_FILES )) ) == NULL ) {
+
+ Debug( LDAP_DEBUG_ANY,
+ "bdb2i_txn_attr_config(): out of memory -- FATAL.\n",
+ 0, 0, 0 );
+
+ /* during configuration (no files are opened)
+ we can just exit, otherwise we kill ourself and
+ hope to shutdown cleanly... */
+ if ( open ) {
+ pthread_kill( pthread_self(), LDAP_SIGUSR1 );
+ } else {
+ exit( 1 );
+ }
+ }
+
+ p->dbc_name = strdup( fileName );
+
+ /* if requested for, we have to open the DB file */
+ /* BUT NOT "objectclass", 'cause that's a default index ! */
+ if ( open && strcasecmp( fileName, "objectclass" )) {
+
+ /* since we have an mpool, we should not define a cache size */
+ p->dbc_db = ldbm_open_env( p->dbc_name, LDBM_WRCREAT,
+ li->li_mode, 0, &li->li_db_env );
+
+ /* if the files could not be opened, something is wrong;
+ complain */
+ if ( p->dbc_db == NULL ) {
+
+ Debug( LDAP_DEBUG_ANY,
+ "bdb2i_txn_open_files(): couldn't open file \"%s\" -- FATAL.\n",
+ p->dbc_name, 0, 0 );
+ pthread_kill( pthread_self(), LDAP_SIGUSR1 );
+
+ }
+
+ bdb2i_init_db_file_cache( li, p );
+
+ Debug( LDAP_DEBUG_TRACE,
+ "bdb2i_txn_attr_config(): NEW INDEX FILE \"%s\"\n",
+ p->dbc_name, 0, 0 );
+
+ }
+ }
+
+ } else { /* it is "attribute" 'default' */
+
+ head->withDefIDX = BDB2_WITH_DEF_IDX;
+
+ }
+}
+
+
+void
+bdb2i_txn_open_files( struct ldbminfo *li )
+{
+ BDB2_TXN_HEAD *head = &li->li_txn_head;
+ BDB2_TXN_FILES *dbFile;
+
+ for ( dbFile = head->dbFiles; dbFile; dbFile = dbFile->next ) {
+
+ /* since we have an mpool, we should not define a cache size */
+ dbFile->dbc_db = ldbm_open_env( dbFile->dbc_name, LDBM_WRCREAT,
+ li->li_mode, 0, &li->li_db_env );
+
+ /* if the files could not be opened, something is wrong; complain */
+ if ( dbFile->dbc_db == NULL ) {
+
+ Debug( LDAP_DEBUG_ANY,
+ "bdb2i_txn_open_files(): couldn't open file \"%s\" -- FATAL.\n",
+ dbFile->dbc_name, 0, 0 );
+ exit( 1 );
+
+ }
+
+ /* initialize the file info */
+ bdb2i_init_db_file_cache( li, dbFile );
+
+ Debug( LDAP_DEBUG_TRACE, "bdb2i_txn_open_files(): OPEN INDEX \"%s\"\n",
+ dbFile->dbc_name, 0, 0 );
+
+ }
+
+}
+
+
+void
+bdb2i_txn_close_files( BDB2_TXN_HEAD *head)
+{
+ BDB2_TXN_FILES *dbFile;
+
+ for ( dbFile = head->dbFiles; dbFile; dbFile = dbFile->next ) {
+
+ ldbm_close( dbFile->dbc_db );
+
+ }
+}
+
+
+BDB2_TXN_FILES *
+bdb2i_get_db_file_cache( struct ldbminfo *li, char *name )
+{
+ BDB2_TXN_HEAD *head = &li->li_txn_head;
+ BDB2_TXN_FILES *dbFile;
+ int dbFileNum;
+
+ for ( dbFile = head->dbFiles; dbFile; dbFile = dbFile->next ) {
+
+ if ( !strcasecmp( dbFile->dbc_name, name )) return( dbFile );
+
+ }
+
+ Debug( LDAP_DEBUG_ANY,
+ "bdb2i_get_db_file_cache(): UPS, could't find \"%s\" \n", name, 0, 0 );
+
+ /* ups, we couldn't find the file */
+ return( NULL );
+
+}
+
+
+/* check for new attribute indexes, that might have been created
+ during former runs of slapd */
+/* this is called during startup of the slapd server */
+void
+bdb2i_check_additional_attr_index( struct ldbminfo *li )
+{
+ DIR *datadir;
+ struct dirent *file;
+
+ if ( ( datadir = opendir( li->li_directory ) ) == NULL ) {
+ /* if ( ( datadir = opendir( "/tmp" ) ) == NULL ) { */
+
+ Debug( LDAP_DEBUG_ANY,
+ "bdb2i_check_additional_attr_index(): ERROR while opening datadir: %s\n",
+ strerror( errno ), 0, 0 );
+ exit( 1 );
+
+ }
+
+ for ( file = readdir( datadir ); file; file = readdir( datadir )) {
+ char filename[MAXPATHLEN];
+ int namelen;
+
+ strcpy( filename, file->d_name );
+ namelen = strlen( filename );
+
+ if ( namelen > strlen( LDBM_SUFFIX )) {
+
+ if ( !strcasecmp( filename + namelen - strlen( LDBM_SUFFIX ),
+ LDBM_SUFFIX )) {
+
+ *(filename + namelen - strlen( LDBM_SUFFIX )) = '\0';
+ bdb2i_txn_attr_config( li, filename, 0 );
+
+ Debug( LDAP_DEBUG_TRACE, "INDEX FILE: %s\n", filename, 0, 0 );
+
+ }
+
+ }
+
+ }
+
+ closedir( datadir );
+
+}
+
+
+/* check for the addition of new attribute indexes during add */
+/* this is called after startup of the slapd server */
+/* DON'T WORRY ABOUT ACCESS RIGHTS, THAT MIGHT PREVENT US
+ FROM ADDING ATTRIBUTES LATER ON */
+void
+bdb2i_check_default_attr_index_add( struct ldbminfo *li, Entry *e )
+{
+ BDB2_TXN_HEAD *head = &li->li_txn_head;
+
+ if ( head->withDefIDX == BDB2_WITH_DEF_IDX ) {
+ Attribute *ap;
+
+ for ( ap = e->e_attrs; ap != NULL; ap = ap->a_next ) {
+ if ( strcasecmp( ap->a_type, "objectclass" ))
+ bdb2i_txn_attr_config( li, ap->a_type, 1 );
+ }
+ }
+}
+
+
+/* check for the addition of new attribute indexes during modify */
+/* this is called after startup of the slapd server */
+/* DON'T WORRY ABOUT ACCESS RIGHTS, THAT MIGHT PREVENT US
+ FROM ADDING ATTRIBUTES LATER ON */
+void
+bdb2i_check_default_attr_index_mod( struct ldbminfo *li, LDAPModList *modlist )
+{
+ BDB2_TXN_HEAD *head = &li->li_txn_head;
+
+ if ( head->withDefIDX == BDB2_WITH_DEF_IDX ) {
+ LDAPModList *ml;
+ char *default_attrs[] = { "modifytimestamp", "modifiersname", NULL };
+ int attr;
+
+ for ( ml = modlist; ml != NULL; ml = ml->ml_next ) {
+ LDAPMod *mod = &ml->ml_mod;
+
+ if (( mod->mod_op & ~LDAP_MOD_BVALUES ) == LDAP_MOD_ADD )
+ if ( strcasecmp( mod->mod_type, "objectclass" ))
+ bdb2i_txn_attr_config( li, mod->mod_type, 1 );
+ }
+
+ /* these attributes are default when modifying */
+ for ( attr = 0; default_attrs[attr]; attr++ ) {
+ bdb2i_txn_attr_config( li, default_attrs[attr], 1 );
+ }
+ }
+}
+
+
--- /dev/null
+/* txn.h - Header for TP support functions of the bdb2 backend */
+
+#ifndef _BDB2_TXN_H_
+#define _BDB2_TXN_H_
+
+#include "portable.h"
+
+#include <stdio.h>
+#include <sys/time.h>
+#include <unistd.h>
+#include <sys/stat.h>
+#include <dirent.h>
+
+#include <ac/string.h>
+#include <ac/socket.h>
+#include <ac/signal.h>
+
+#include "ldapconfig.h"
+#include "slap.h"
+#include "back-bdb2.h"
+
+
+
+#define BDB2_TXN_CHKP_MAX_CNT 20 /* checkpoint every
+ 20 transactions */
+#define BDB2_TXN_CHKP_MAX_TIME 600 /* checkpoint after
+ 600 seconds */
+
+
+char *bdb2i_fixed_filenames[] = {
+
+ "dn", "dn2id", "id2entry", "id2children", "objectclass"
+
+ };
+
+
+#endif /* _BDB2_TXN_H_ */
+
--- /dev/null
+/* unbind.c - handle an ldap unbind operation */
+
+#include "portable.h"
+
+#include <stdio.h>
+#include <ac/socket.h>
+
+#include "slap.h"
+#include "back-bdb2.h"
+
+static int
+bdb2i_back_unbind_internal(
+ Backend *be,
+ Connection *conn,
+ Operation *op
+)
+{
+ return( 0 );
+}
+
+
+int
+bdb2_back_unbind(
+ Backend *be,
+ Connection *conn,
+ Operation *op
+)
+{
+ struct timeval time1, time2;
+ char *elapsed_time;
+ int ret;
+
+ gettimeofday( &time1, NULL );
+
+ ret = bdb2i_back_unbind_internal( be, conn, op );
+
+ if ( bdb2i_do_timing ) {
+
+ gettimeofday( &time2, NULL);
+ elapsed_time = bdb2i_elapsed( time1, time2 );
+ Debug( LDAP_DEBUG_ANY, "conn=%d op=%d UNBIND elapsed=%s\n",
+ conn->c_connid, op->o_opid, elapsed_time );
+ free( elapsed_time );
+
+ }
+
+ return( ret );
+}
}
Debug( LDAP_DEBUG_TRACE, "<= returning deref DN of \"%s\"\n", newDN, 0, 0 );
- if (matched != NULL) free(matched);
return newDN;
}