]> git.sur5r.net Git - openldap/blob - servers/slapd/back-bdb/dn2id.c
Revert to original code
[openldap] / servers / slapd / back-bdb / dn2id.c
1 /* dn2id.c - routines to deal with the dn2id index */
2 /* $OpenLDAP$ */
3 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
4  *
5  * Copyright 2000-2004 The OpenLDAP Foundation.
6  * All rights reserved.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted only as authorized by the OpenLDAP
10  * Public License.
11  *
12  * A copy of this license is available in the file LICENSE in the
13  * top-level directory of the distribution or, alternatively, at
14  * <http://www.OpenLDAP.org/license.html>.
15  */
16
17 #include "portable.h"
18
19 #include <stdio.h>
20 #include <ac/string.h>
21
22 #include "back-bdb.h"
23 #include "idl.h"
24 #include "lutil.h"
25
26 #ifndef BDB_HIER
27 int
28 bdb_dn2id_add(
29         Operation *op,
30         DB_TXN *txn,
31         EntryInfo *eip,
32         Entry           *e )
33 {
34         struct bdb_info *bdb = (struct bdb_info *) op->o_bd->be_private;
35         DB *db = bdb->bi_dn2id->bdi_db;
36         int             rc;
37         DBT             key, data;
38         char            *buf;
39         struct berval   ptr, pdn;
40
41 #ifdef NEW_LOGGING
42         LDAP_LOG ( INDEX, ARGS, "bdb_dn2id_add( \"%s\", 0x%08lx )\n",
43                 e->e_ndn, (long) e->e_id, 0 );
44 #else
45         Debug( LDAP_DEBUG_TRACE, "=> bdb_dn2id_add( \"%s\", 0x%08lx )\n",
46                 e->e_ndn, (long) e->e_id, 0 );
47 #endif
48         assert( e->e_id != NOID );
49
50         DBTzero( &key );
51         key.size = e->e_nname.bv_len + 2;
52         key.ulen = key.size;
53         key.flags = DB_DBT_USERMEM;
54         buf = op->o_tmpalloc( key.size, op->o_tmpmemctx );
55         key.data = buf;
56         buf[0] = DN_BASE_PREFIX;
57         ptr.bv_val = buf + 1;
58         ptr.bv_len = e->e_nname.bv_len;
59         AC_MEMCPY( ptr.bv_val, e->e_nname.bv_val, e->e_nname.bv_len );
60         ptr.bv_val[ptr.bv_len] = '\0';
61
62         DBTzero( &data );
63         data.data = (char *) &e->e_id;
64         data.size = sizeof( e->e_id );
65
66         /* store it -- don't override */
67         rc = db->put( db, txn, &key, &data, DB_NOOVERWRITE );
68         if( rc != 0 ) {
69 #ifdef NEW_LOGGING
70                 LDAP_LOG ( INDEX, ERR, "bdb_dn2id_add: put failed: %s %d\n",
71                         db_strerror(rc), rc, 0 );
72 #else
73                 Debug( LDAP_DEBUG_ANY, "=> bdb_dn2id_add: put failed: %s %d\n",
74                         db_strerror(rc), rc, 0 );
75 #endif
76                 goto done;
77         }
78
79 #ifndef BDB_MULTIPLE_SUFFIXES
80         if( !be_issuffix( op->o_bd, &ptr )) {
81 #endif
82                 buf[0] = DN_SUBTREE_PREFIX;
83                 rc = db->put( db, txn, &key, &data, DB_NOOVERWRITE );
84                 if( rc != 0 ) {
85 #ifdef NEW_LOGGING
86                         LDAP_LOG ( INDEX, ERR, 
87                                 "=> bdb_dn2id_add: subtree (%s) put failed: %d\n",
88                                 ptr.bv_val, rc, 0 );
89 #else
90                         Debug( LDAP_DEBUG_ANY,
91                         "=> bdb_dn2id_add: subtree (%s) put failed: %d\n",
92                         ptr.bv_val, rc, 0 );
93 #endif
94                         goto done;
95                 }
96                 
97 #ifdef BDB_MULTIPLE_SUFFIXES
98         if( !be_issuffix( op->o_bd, &ptr )) {
99 #endif
100                 dnParent( &ptr, &pdn );
101         
102                 key.size = pdn.bv_len + 2;
103                 key.ulen = key.size;
104                 pdn.bv_val[-1] = DN_ONE_PREFIX;
105                 key.data = pdn.bv_val-1;
106                 ptr = pdn;
107
108                 rc = bdb_idl_insert_key( op->o_bd, db, txn, &key, e->e_id );
109
110                 if( rc != 0 ) {
111 #ifdef NEW_LOGGING
112                         LDAP_LOG ( INDEX, ERR, 
113                                 "=> bdb_dn2id_add: parent (%s) insert failed: %d\n",
114                                 ptr.bv_val, rc, 0 );
115 #else
116                         Debug( LDAP_DEBUG_ANY,
117                                 "=> bdb_dn2id_add: parent (%s) insert failed: %d\n",
118                                         ptr.bv_val, rc, 0 );
119 #endif
120                         goto done;
121                 }
122 #ifndef BDB_MULTIPLE_SUFFIXES
123         }
124
125         while( !be_issuffix( op->o_bd, &ptr ))
126 #else
127         for (;;)
128 #endif
129         {
130                 ptr.bv_val[-1] = DN_SUBTREE_PREFIX;
131
132                 rc = bdb_idl_insert_key( op->o_bd, db, txn, &key, e->e_id );
133
134                 if( rc != 0 ) {
135 #ifdef NEW_LOGGING
136                         LDAP_LOG ( INDEX, ERR, 
137                                 "=> bdb_dn2id_add: subtree (%s) insert failed: %d\n",
138                                 ptr.bv_val, rc, 0 );
139 #else
140                         Debug( LDAP_DEBUG_ANY,
141                                 "=> bdb_dn2id_add: subtree (%s) insert failed: %d\n",
142                                         ptr.bv_val, rc, 0 );
143 #endif
144                         break;
145                 }
146 #ifdef BDB_MULTIPLE_SUFFIXES
147                 if( be_issuffix( op->o_bd, &ptr )) break;
148 #endif
149                 dnParent( &ptr, &pdn );
150
151                 key.size = pdn.bv_len + 2;
152                 key.ulen = key.size;
153                 key.data = pdn.bv_val - 1;
154                 ptr = pdn;
155         }
156 #ifdef BDB_MULTIPLE_SUFFIXES
157         }
158 #endif
159
160 done:
161         op->o_tmpfree( buf, op->o_tmpmemctx );
162 #ifdef NEW_LOGGING
163         LDAP_LOG ( INDEX, RESULTS, "<= bdb_dn2id_add: %d\n", rc, 0, 0 );
164 #else
165         Debug( LDAP_DEBUG_TRACE, "<= bdb_dn2id_add: %d\n", rc, 0, 0 );
166 #endif
167         return rc;
168 }
169
170 int
171 bdb_dn2id_delete(
172         Operation *op,
173         DB_TXN *txn,
174         EntryInfo       *eip,
175         Entry           *e )
176 {
177         struct bdb_info *bdb = (struct bdb_info *) op->o_bd->be_private;
178         DB *db = bdb->bi_dn2id->bdi_db;
179         int             rc;
180         DBT             key;
181         char            *buf;
182         struct berval   pdn, ptr;
183
184 #ifdef NEW_LOGGING
185         LDAP_LOG ( INDEX, ARGS, 
186                 "=> bdb_dn2id_delete ( \"%s\", 0x%08lx )\n", e->e_ndn, e->e_id, 0);
187 #else
188         Debug( LDAP_DEBUG_TRACE, "=> bdb_dn2id_delete( \"%s\", 0x%08lx )\n",
189                 e->e_ndn, e->e_id, 0 );
190 #endif
191
192         DBTzero( &key );
193         key.size = e->e_nname.bv_len + 2;
194         buf = op->o_tmpalloc( key.size, op->o_tmpmemctx );
195         key.data = buf;
196         key.flags = DB_DBT_USERMEM;
197         buf[0] = DN_BASE_PREFIX;
198         ptr.bv_val = buf+1;
199         ptr.bv_len = e->e_nname.bv_len;
200         AC_MEMCPY( ptr.bv_val, e->e_nname.bv_val, e->e_nname.bv_len );
201         ptr.bv_val[ptr.bv_len] = '\0';
202
203         /* delete it */
204         rc = db->del( db, txn, &key, 0 );
205         if( rc != 0 ) {
206 #ifdef NEW_LOGGING
207                 LDAP_LOG ( INDEX, ERR, 
208                         "=> bdb_dn2id_delete: delete failed: %s %d\n", 
209                         db_strerror(rc), rc, 0 );
210 #else
211                 Debug( LDAP_DEBUG_ANY, "=> bdb_dn2id_delete: delete failed: %s %d\n",
212                         db_strerror(rc), rc, 0 );
213 #endif
214                 goto done;
215         }
216
217 #ifndef BDB_MULTIPLE_SUFFIXES
218         if( !be_issuffix( op->o_bd, &ptr )) {
219 #endif
220                 buf[0] = DN_SUBTREE_PREFIX;
221                 rc = db->del( db, txn, &key, 0 );
222                 if( rc != 0 ) {
223 #ifdef NEW_LOGGING
224                         LDAP_LOG ( INDEX, ERR, 
225                                 "=> bdb_dn2id_delete: subtree (%s) delete failed: %d\n", 
226                                 ptr.bv_val, rc, 0 );
227 #else
228                         Debug( LDAP_DEBUG_ANY,
229                         "=> bdb_dn2id_delete: subtree (%s) delete failed: %d\n",
230                         ptr.bv_val, rc, 0 );
231 #endif
232                         goto done;
233                 }
234
235 #ifdef BDB_MULTIPLE_SUFFIXES
236         if( !be_issuffix( op->o_bd, &ptr )) {
237 #endif
238                 dnParent( &ptr, &pdn );
239
240                 key.size = pdn.bv_len + 2;
241                 key.ulen = key.size;
242                 pdn.bv_val[-1] = DN_ONE_PREFIX;
243                 key.data = pdn.bv_val - 1;
244                 ptr = pdn;
245
246                 rc = bdb_idl_delete_key( op->o_bd, db, txn, &key, e->e_id );
247
248                 if( rc != 0 ) {
249 #ifdef NEW_LOGGING
250                         LDAP_LOG ( INDEX, ERR, 
251                                 "=> bdb_dn2id_delete: parent (%s) delete failed: %d\n", 
252                                 ptr.bv_val, rc, 0 );
253 #else
254                         Debug( LDAP_DEBUG_ANY,
255                                 "=> bdb_dn2id_delete: parent (%s) delete failed: %d\n",
256                                 ptr.bv_val, rc, 0 );
257 #endif
258                         goto done;
259                 }
260 #ifndef BDB_MULTIPLE_SUFFIXES
261         }
262
263         while( !be_issuffix( op->o_bd, &ptr )) {
264 #else
265         for (;;) {
266 #endif
267                 ptr.bv_val[-1] = DN_SUBTREE_PREFIX;
268
269                 rc = bdb_idl_delete_key( op->o_bd, db, txn, &key, e->e_id );
270                 if( rc != 0 ) {
271 #ifdef NEW_LOGGING
272                         LDAP_LOG ( INDEX, ERR, 
273                                 "=> bdb_dn2id_delete: subtree (%s) delete failed: %d\n", 
274                                 ptr.bv_val, rc, 0 );
275 #else
276                         Debug( LDAP_DEBUG_ANY,
277                                 "=> bdb_dn2id_delete: subtree (%s) delete failed: %d\n",
278                                 ptr.bv_val, rc, 0 );
279 #endif
280                         goto done;
281                 }
282 #ifdef BDB_MULTIPLE_SUFFIXES
283                 if( be_issuffix( op->o_bd, &ptr )) break;
284 #endif
285                 dnParent( &ptr, &pdn );
286
287                 key.size = pdn.bv_len + 2;
288                 key.ulen = key.size;
289                 key.data = pdn.bv_val - 1;
290                 ptr = pdn;
291         }
292 #ifdef BDB_MULTIPLE_SUFFIXES
293         }
294 #endif
295
296 done:
297         op->o_tmpfree( buf, op->o_tmpmemctx );
298 #ifdef NEW_LOGGING
299         LDAP_LOG ( INDEX, RESULTS, "<= bdb_dn2id_delete %d\n", rc, 0, 0 );
300 #else
301         Debug( LDAP_DEBUG_TRACE, "<= bdb_dn2id_delete %d\n", rc, 0, 0 );
302 #endif
303         return rc;
304 }
305
306 int
307 bdb_dn2id(
308         Operation *op,
309         DB_TXN *txn,
310         struct berval   *dn,
311         EntryInfo *ei )
312 {
313         int             rc;
314         DBT             key, data;
315         struct bdb_info *bdb = (struct bdb_info *) op->o_bd->be_private;
316         DB *db = bdb->bi_dn2id->bdi_db;
317
318 #ifdef NEW_LOGGING
319         LDAP_LOG ( INDEX, ARGS, "=> bdb_dn2id( \"%s\" )\n", dn->bv_val, 0, 0 );
320 #else
321         Debug( LDAP_DEBUG_TRACE, "=> bdb_dn2id( \"%s\" )\n", dn->bv_val, 0, 0 );
322 #endif
323         DBTzero( &key );
324         key.size = dn->bv_len + 2;
325         key.data = op->o_tmpalloc( key.size, op->o_tmpmemctx );
326         ((char *)key.data)[0] = DN_BASE_PREFIX;
327         AC_MEMCPY( &((char *)key.data)[1], dn->bv_val, key.size - 1 );
328
329         /* store the ID */
330         DBTzero( &data );
331         data.data = &ei->bei_id;
332         data.ulen = sizeof(ID);
333         data.flags = DB_DBT_USERMEM;
334
335         /* fetch it */
336         rc = db->get( db, txn, &key, &data, bdb->bi_db_opflags );
337
338         if( rc != 0 ) {
339 #ifdef NEW_LOGGING
340                 LDAP_LOG ( INDEX, ERR, "<= bdb_dn2id: get failed %s (%d)\n", 
341                         db_strerror(rc), rc, 0 );
342 #else
343                 Debug( LDAP_DEBUG_TRACE, "<= bdb_dn2id: get failed: %s (%d)\n",
344                         db_strerror( rc ), rc, 0 );
345 #endif
346         } else {
347 #ifdef NEW_LOGGING
348                 LDAP_LOG ( INDEX, RESULTS, 
349                         "<= bdb_dn2id: got id=0x%08lx\n", ei->bei_id, 0, 0 );
350 #else
351                 Debug( LDAP_DEBUG_TRACE, "<= bdb_dn2id: got id=0x%08lx\n",
352                         ei->bei_id, 0, 0 );
353 #endif
354         }
355
356         op->o_tmpfree( key.data, op->o_tmpmemctx );
357         return rc;
358 }
359
360 int
361 bdb_dn2id_children(
362         Operation *op,
363         DB_TXN *txn,
364         Entry *e )
365 {
366         DBT             key, data;
367         struct bdb_info *bdb = (struct bdb_info *) op->o_bd->be_private;
368         DB *db = bdb->bi_dn2id->bdi_db;
369         ID              id;
370         int             rc;
371
372 #ifdef NEW_LOGGING
373         LDAP_LOG ( INDEX, ARGS, 
374                 "=> bdb_dn2id_children( %s )\n", e->e_nname.bv_val, 0, 0 );
375 #else
376         Debug( LDAP_DEBUG_TRACE, "=> bdb_dn2id_children( %s )\n",
377                 e->e_nname.bv_val, 0, 0 );
378 #endif
379         DBTzero( &key );
380         key.size = e->e_nname.bv_len + 2;
381         key.data = op->o_tmpalloc( key.size, op->o_tmpmemctx );
382         ((char *)key.data)[0] = DN_ONE_PREFIX;
383         AC_MEMCPY( &((char *)key.data)[1], e->e_nname.bv_val, key.size - 1 );
384
385 #ifdef SLAP_IDL_CACHE
386         if ( bdb->bi_idl_cache_size ) {
387                 rc = bdb_idl_cache_get( bdb, db, &key, NULL );
388                 if ( rc != LDAP_NO_SUCH_OBJECT ) {
389                         op->o_tmpfree( key.data, op->o_tmpmemctx );
390                         return rc;
391                 }
392         }
393 #endif
394         /* we actually could do a empty get... */
395         DBTzero( &data );
396         data.data = &id;
397         data.ulen = sizeof(id);
398         data.flags = DB_DBT_USERMEM;
399         data.doff = 0;
400         data.dlen = sizeof(id);
401
402         rc = db->get( db, txn, &key, &data, bdb->bi_db_opflags );
403         op->o_tmpfree( key.data, op->o_tmpmemctx );
404
405 #ifdef NEW_LOGGING
406         LDAP_LOG ( INDEX, DETAIL1, 
407                 "<= bdb_dn2id_children( %s ): %s (%d)\n", 
408                 e->e_nname.bv_val, rc == 0 ? "" : ( rc == DB_NOTFOUND ? "no " :
409                 db_strerror(rc)), rc );
410 #else
411         Debug( LDAP_DEBUG_TRACE, "<= bdb_dn2id_children( %s ): %s (%d)\n",
412                 e->e_nname.bv_val,
413                 rc == 0 ? "" : ( rc == DB_NOTFOUND ? "no " :
414                         db_strerror(rc) ), rc );
415 #endif
416
417         return rc;
418 }
419
420 int
421 bdb_dn2idl(
422         Operation *op,
423         Entry *e,
424         ID *ids,
425         ID *stack )
426 {
427         int             rc;
428         DBT             key;
429         struct bdb_info *bdb = (struct bdb_info *) op->o_bd->be_private;
430         DB *db = bdb->bi_dn2id->bdi_db;
431         int prefix = ( op->ors_scope == LDAP_SCOPE_ONELEVEL )
432                 ? DN_ONE_PREFIX : DN_SUBTREE_PREFIX;
433
434 #ifdef NEW_LOGGING
435         LDAP_LOG ( INDEX, ARGS, "=> bdb_dn2ididl( \"%s\" )\n",
436                 e->e_nname.bv_val, 0, 0 );
437 #else
438         Debug( LDAP_DEBUG_TRACE, "=> bdb_dn2idl( \"%s\" )\n",
439                 e->e_nname.bv_val, 0, 0 );
440 #endif
441
442 #ifndef BDB_MULTIPLE_SUFFIXES
443         if ( prefix == DN_SUBTREE_PREFIX && BEI(e)->bei_parent->bei_id == 0 ) {
444                 BDB_IDL_ALL(bdb, ids);
445                 return 0;
446         }
447 #endif
448
449         DBTzero( &key );
450         key.size = e->e_nname.bv_len + 2;
451         key.ulen = key.size;
452         key.flags = DB_DBT_USERMEM;
453         key.data = op->o_tmpalloc( key.size, op->o_tmpmemctx );
454         ((char *)key.data)[0] = prefix;
455         AC_MEMCPY( &((char *)key.data)[1], e->e_nname.bv_val, key.size - 1 );
456
457         rc = bdb_idl_fetch_key( op->o_bd, db, NULL, &key, ids );
458
459         if( rc != 0 ) {
460 #ifdef NEW_LOGGING
461                 LDAP_LOG ( INDEX, ERR, 
462                         "<= bdb_dn2ididl: get failed: %s (%d)\n", db_strerror(rc), rc, 0 );
463 #else
464                 Debug( LDAP_DEBUG_TRACE,
465                         "<= bdb_dn2idl: get failed: %s (%d)\n",
466                         db_strerror( rc ), rc, 0 );
467 #endif
468
469         } else {
470 #ifdef NEW_LOGGING
471                 LDAP_LOG ( INDEX, RESULTS, 
472                         "<= bdb_dn2ididl: id=%ld first=%ld last=%ld\n", 
473                         (long) ids[0], (long) BDB_IDL_FIRST( ids ), 
474                         (long) BDB_IDL_LAST( ids ) );
475 #else
476                 Debug( LDAP_DEBUG_TRACE,
477                         "<= bdb_dn2idl: id=%ld first=%ld last=%ld\n",
478                         (long) ids[0],
479                         (long) BDB_IDL_FIRST( ids ), (long) BDB_IDL_LAST( ids ) );
480 #endif
481         }
482
483         op->o_tmpfree( key.data, op->o_tmpmemctx );
484         return rc;
485 }
486 #else   /* BDB_HIER */
487
488 /* Experimental management routines for a hierarchically structured database.
489  *
490  * Unsupported! Use at your own risk!
491  * -- Howard Chu, Symas Corp. 2003.
492  *
493  * Instead of a ldbm-style dn2id database, we use a hierarchical one. Each
494  * entry in this database is a struct diskNode, keyed by entryID and with
495  * the data containing the RDN and entryID of the node's children. We use
496  * a B-Tree with sorted duplicates to store all the children of a node under
497  * the same key. Also, the first item under the key contains the entry's own
498  * rdn and the ID of the node's parent, to allow bottom-up tree traversal as
499  * well as top-down. To keep this info first in the list, the nrdnlen is set
500  * to the negative of its value.
501  *
502  * The diskNode is a variable length structure. This definition is not
503  * directly usable for in-memory manipulation.
504  */
505 typedef struct diskNode {
506         ID entryID;
507         short nrdnlen;
508         char nrdn[1];
509         char rdn[1];
510 } diskNode;
511
512 /* Sort function for the sorted duplicate data items of a dn2id key.
513  * Sorts based on normalized RDN, in length order.
514  */
515 int
516 hdb_dup_compare(
517         DB *db, 
518         const DBT *usrkey,
519         const DBT *curkey
520 )
521 {
522         char *u = (char *)&(((diskNode *)(usrkey->data))->nrdnlen);
523         char *c = (char *)&(((diskNode *)(curkey->data))->nrdnlen);
524         int rc, i;
525
526         /* data is not aligned, cannot compare directly */
527 #ifdef WORDS_BIGENDIAN
528         for( i = 0; i < (int)sizeof(short); i++)
529 #else
530         for( i = sizeof(short)-1; i >= 0; i--)
531 #endif
532         {
533                 rc = u[i] - c[i];
534                 if( rc ) return rc;
535         }
536         return strcmp( u+sizeof(short), c+sizeof(short) );
537 }
538
539 /* This function constructs a full DN for a given entry.
540  */
541 int hdb_fix_dn(
542         Entry *e,
543         int checkit
544 )
545 {
546         EntryInfo *ei;
547         int rlen = 0, nrlen = 0;
548         char *ptr, *nptr;
549         int max = 0;
550
551         /* count length of all DN components */
552         for ( ei = BEI(e); ei && ei->bei_id; ei=ei->bei_parent ) {
553                 rlen += ei->bei_rdn.bv_len + 1;
554                 nrlen += ei->bei_nrdn.bv_len + 1;
555                 if (ei->bei_modrdns > max) max = ei->bei_modrdns;
556         }
557
558         /* See if the entry DN was invalidated by a subtree rename */
559         if ( checkit ) {
560                 if ( BEI(e)->bei_modrdns >= max ) {
561                         return 0;
562                 }
563                 /* We found a mismatch, tell the caller to lock it */
564                 if ( checkit == 1 ) {
565                         return 1;
566                 }
567                 /* checkit == 2. do the fix. */
568                 free( e->e_name.bv_val );
569                 free( e->e_nname.bv_val );
570         }
571
572         e->e_name.bv_len = rlen - 1;
573         e->e_nname.bv_len = nrlen - 1;
574         e->e_name.bv_val = ch_malloc(rlen);
575         e->e_nname.bv_val = ch_malloc(nrlen);
576         ptr = e->e_name.bv_val;
577         nptr = e->e_nname.bv_val;
578         for ( ei = BEI(e); ei && ei->bei_id; ei=ei->bei_parent ) {
579                 ptr = lutil_strcopy(ptr, ei->bei_rdn.bv_val);
580                 nptr = lutil_strcopy(nptr, ei->bei_nrdn.bv_val);
581                 if ( ei->bei_parent ) {
582                         *ptr++ = ',';
583                         *nptr++ = ',';
584                 }
585         }
586         BEI(e)->bei_modrdns = max;
587         ptr[-1] = '\0';
588         nptr[-1] = '\0';
589
590         return 0;
591 }
592
593 /* We add two elements to the DN2ID database - a data item under the parent's
594  * entryID containing the child's RDN and entryID, and an item under the
595  * child's entryID containing the parent's entryID.
596  */
597 int
598 hdb_dn2id_add(
599         Operation       *op,
600         DB_TXN *txn,
601         EntryInfo       *eip,
602         Entry           *e )
603 {
604         struct bdb_info *bdb = (struct bdb_info *) op->o_bd->be_private;
605         DB *db = bdb->bi_dn2id->bdi_db;
606         DBT             key, data;
607         int             rc, rlen, nrlen;
608         diskNode *d;
609         char *ptr;
610
611         nrlen = dn_rdnlen( op->o_bd, &e->e_nname );
612         if (nrlen) {
613                 rlen = dn_rdnlen( op->o_bd, &e->e_name );
614         } else {
615                 nrlen = e->e_nname.bv_len;
616                 rlen = e->e_name.bv_len;
617         }
618
619         d = op->o_tmpalloc(sizeof(diskNode) + rlen + nrlen, op->o_tmpmemctx);
620         d->entryID = e->e_id;
621         d->nrdnlen = nrlen;
622         ptr = lutil_strncopy( d->nrdn, e->e_nname.bv_val, nrlen );
623         *ptr++ = '\0';
624         ptr = lutil_strncopy( ptr, e->e_name.bv_val, rlen );
625         *ptr = '\0';
626
627         DBTzero(&key);
628         DBTzero(&data);
629         key.data = &eip->bei_id;
630         key.size = sizeof(ID);
631         key.flags = DB_DBT_USERMEM;
632
633 #ifdef SLAP_IDL_CACHE
634         if ( bdb->bi_idl_cache_size ) {
635                 bdb_idl_cache_del( bdb, db, &key );
636         }
637 #endif
638         data.data = d;
639         data.size = sizeof(diskNode) + rlen + nrlen;
640         data.flags = DB_DBT_USERMEM;
641
642         rc = db->put( db, txn, &key, &data, DB_NODUPDATA );
643
644         if (rc == 0) {
645                 key.data = &e->e_id;
646                 d->entryID = eip->bei_id;
647                 d->nrdnlen = 0 - nrlen;
648
649                 rc = db->put( db, txn, &key, &data, DB_NODUPDATA );
650         }
651
652         op->o_tmpfree( d, op->o_tmpmemctx );
653
654         return rc;
655 }
656
657 int
658 hdb_dn2id_delete(
659         Operation       *op,
660         DB_TXN *txn,
661         EntryInfo       *eip,
662         Entry   *e )
663 {
664         struct bdb_info *bdb = (struct bdb_info *) op->o_bd->be_private;
665         DB *db = bdb->bi_dn2id->bdi_db;
666         DBT             key, data;
667         DBC     *cursor;
668         diskNode *d;
669         int rc, nrlen;
670
671         DBTzero(&key);
672         key.size = sizeof(ID);
673         key.ulen = key.size;
674         key.data = &eip->bei_id;
675         key.flags = DB_DBT_USERMEM;
676
677         DBTzero(&data);
678         data.size = sizeof(diskNode) + BEI(e)->bei_nrdn.bv_len;
679         data.ulen = data.size;
680         data.dlen = data.size;
681         data.flags = DB_DBT_USERMEM | DB_DBT_PARTIAL;
682
683 #ifdef SLAP_IDL_CACHE
684         if ( bdb->bi_idl_cache_size ) {
685                 bdb_idl_cache_del( bdb, db, &key );
686         }
687 #endif
688         rc = db->cursor( db, txn, &cursor, bdb->bi_db_opflags );
689         if ( rc ) return rc;
690
691         d = op->o_tmpalloc( data.size, op->o_tmpmemctx );
692         d->entryID = e->e_id;
693         d->nrdnlen = BEI(e)->bei_nrdn.bv_len;
694         strcpy( d->nrdn, BEI(e)->bei_nrdn.bv_val );
695         data.data = d;
696
697         /* Delete our ID from the parent's list */
698         rc = cursor->c_get( cursor, &key, &data, DB_GET_BOTH | DB_RMW );
699         if ( rc == 0 )
700                 rc = cursor->c_del( cursor, 0 );
701
702         /* Delete our ID from the tree. With sorted duplicates, this
703          * will leave any child nodes still hanging around. This is OK
704          * for modrdn, which will add our info back in later.
705          */
706         if ( rc == 0 ) {
707                 key.data = &e->e_id;
708                 rc = cursor->c_get( cursor, &key, &data, DB_SET | DB_RMW );
709                 if ( rc == 0 )
710                         rc = cursor->c_del( cursor, 0 );
711         }
712         cursor->c_close( cursor );
713         op->o_tmpfree( d, op->o_tmpmemctx );
714
715         return rc;
716 }
717
718
719 int
720 hdb_dn2id(
721         Operation       *op,
722         DB_TXN *txn,
723         struct berval   *in,
724         EntryInfo       *ei )
725 {
726         struct bdb_info *bdb = (struct bdb_info *) op->o_bd->be_private;
727         DB *db = bdb->bi_dn2id->bdi_db;
728         DBT             key, data;
729         DBC     *cursor;
730         int             rc = 0, nrlen;
731         diskNode *d;
732         char    *ptr;
733         ID idp = ei->bei_parent->bei_id;
734
735         nrlen = dn_rdnlen( op->o_bd, in );
736         if (!nrlen) nrlen = in->bv_len;
737
738         DBTzero(&key);
739         key.size = sizeof(ID);
740         key.data = &idp;
741         key.ulen = sizeof(ID);
742         key.flags = DB_DBT_USERMEM;
743
744         DBTzero(&data);
745         data.size = sizeof(diskNode) + nrlen;
746         data.ulen = data.size * 3;
747         data.flags = DB_DBT_USERMEM;
748
749         rc = db->cursor( db, txn, &cursor, bdb->bi_db_opflags );
750         if ( rc ) return rc;
751
752         d = op->o_tmpalloc( data.size * 3, op->o_tmpmemctx );
753         d->nrdnlen = nrlen;
754         ptr = lutil_strncopy( d->nrdn, in->bv_val, nrlen );
755         *ptr = '\0';
756         data.data = d;
757
758         rc = cursor->c_get( cursor, &key, &data, DB_GET_BOTH );
759         if ( rc == 0 ) {
760                 ei->bei_id = d->entryID;
761                 ei->bei_rdn.bv_len = data.size - sizeof(diskNode) - nrlen;
762                 ptr = d->nrdn + nrlen + 1;
763                 ber_str2bv( ptr, ei->bei_rdn.bv_len, 1, &ei->bei_rdn );
764                 if ( !ei->bei_parent->bei_dkids ) {
765                         db_recno_t dkids;
766                         /* How many children does the parent have? */
767                         /* FIXME: do we need to lock the parent
768                          * entryinfo? Seems safe...
769                          */
770                         cursor->c_count( cursor, &dkids, 0 );
771                         ei->bei_parent->bei_dkids = dkids;
772                 }
773         }
774         cursor->c_close( cursor );
775         op->o_tmpfree( d, op->o_tmpmemctx );
776
777         return rc;
778 }
779
780 int
781 hdb_dn2id_parent(
782         Operation *op,
783         DB_TXN *txn,
784         EntryInfo *ei,
785         ID *idp )
786 {
787         struct bdb_info *bdb = (struct bdb_info *) op->o_bd->be_private;
788         DB *db = bdb->bi_dn2id->bdi_db;
789         DBT             key, data;
790         DBC     *cursor;
791         int             rc = 0;
792         diskNode *d;
793         char    *ptr;
794         unsigned char *pt2;
795
796         DBTzero(&key);
797         key.size = sizeof(ID);
798         key.data = &ei->bei_id;
799         key.ulen = sizeof(ID);
800         key.flags = DB_DBT_USERMEM;
801
802         DBTzero(&data);
803         data.flags = DB_DBT_USERMEM;
804
805         rc = db->cursor( db, txn, &cursor, bdb->bi_db_opflags );
806         if ( rc ) return rc;
807
808         data.ulen = sizeof(diskNode) + (SLAP_LDAPDN_MAXLEN * 2);
809         d = op->o_tmpalloc( data.ulen, op->o_tmpmemctx );
810         data.data = d;
811
812         rc = cursor->c_get( cursor, &key, &data, DB_SET );
813         if ( rc == 0 ) {
814                 if (d->nrdnlen >= 0) {
815                         rc = LDAP_OTHER;
816                 } else {
817                         db_recno_t dkids;
818                         *idp = d->entryID;
819                         ei->bei_nrdn.bv_len = 0 - d->nrdnlen;
820                         ber_str2bv( d->nrdn, ei->bei_nrdn.bv_len, 1, &ei->bei_nrdn );
821                         ei->bei_rdn.bv_len = data.size - sizeof(diskNode) -
822                                 ei->bei_nrdn.bv_len;
823                         ptr = d->nrdn + ei->bei_nrdn.bv_len + 1;
824                         ber_str2bv( ptr, ei->bei_rdn.bv_len, 1, &ei->bei_rdn );
825                         /* How many children does this node have? */
826                         cursor->c_count( cursor, &dkids, 0 );
827                         ei->bei_dkids = dkids;
828                 }
829         }
830         cursor->c_close( cursor );
831         op->o_tmpfree( d, op->o_tmpmemctx );
832         return rc;
833 }
834
835 int
836 hdb_dn2id_children(
837         Operation *op,
838         DB_TXN *txn,
839         Entry *e )
840 {
841         struct bdb_info *bdb = (struct bdb_info *) op->o_bd->be_private;
842         DB *db = bdb->bi_dn2id->bdi_db;
843         DBT             key, data;
844         DBC             *cursor;
845         int             rc;
846         ID              id;
847         diskNode d;
848
849         DBTzero(&key);
850         key.size = sizeof(ID);
851         key.data = &e->e_id;
852         key.flags = DB_DBT_USERMEM;
853
854 #ifdef SLAP_IDL_CACHE
855         if ( bdb->bi_idl_cache_size ) {
856                 rc = bdb_idl_cache_get( bdb, db, &key, NULL );
857                 if ( rc != LDAP_NO_SUCH_OBJECT ) {
858                         return rc;
859                 }
860         }
861 #endif
862         DBTzero(&data);
863         data.data = &d;
864         data.ulen = sizeof(d);
865         data.flags = DB_DBT_USERMEM | DB_DBT_PARTIAL;
866         data.dlen = sizeof(d);
867
868         rc = db->cursor( db, txn, &cursor, bdb->bi_db_opflags );
869         if ( rc ) return rc;
870
871         rc = cursor->c_get( cursor, &key, &data, DB_SET );
872         if ( rc == 0 ) {
873                 db_recno_t dkids;
874                 rc = cursor->c_count( cursor, &dkids, 0 );
875                 if ( rc == 0 ) {
876                         BEI(e)->bei_dkids = dkids;
877                         if ( dkids < 2 ) rc = DB_NOTFOUND;
878                 }
879         }
880         cursor->c_close( cursor );
881         return rc;
882 }
883
884 /* bdb_dn2idl:
885  * We can't just use bdb_idl_fetch_key because
886  * 1 - our data items are longer than just an entry ID
887  * 2 - our data items are sorted alphabetically by nrdn, not by ID.
888  *
889  * We descend the tree recursively, so we define this cookie
890  * to hold our necessary state information. The bdb_dn2idl_internal
891  * function uses this cookie when calling itself.
892  */
893
894 struct dn2id_cookie {
895         struct bdb_info *bdb;
896         DB *db;
897         int prefix;
898         int rc;
899         EntryInfo *ei;
900         ID id;
901         ID dbuf;
902         ID *ids;
903         void *ptr;
904         ID tmp[BDB_IDL_DB_SIZE];
905         ID *buf;
906         DBT key;
907         DBT data;
908         DBC *dbc;
909         Operation *op;
910 };
911
912 static int
913 apply_func(
914         void *data,
915         void *arg )
916 {
917         EntryInfo *ei = data;
918         ID *idl = arg;
919
920         bdb_idl_insert( idl, ei->bei_id );
921         return 0;
922 }
923
924 static int
925 hdb_dn2idl_internal(
926         struct dn2id_cookie *cx
927 )
928 {
929 #ifdef SLAP_IDL_CACHE
930         if ( cx->bdb->bi_idl_cache_size ) {
931                 cx->rc = bdb_idl_cache_get(cx->bdb, cx->db, &cx->key, cx->tmp);
932                 if ( cx->rc == DB_NOTFOUND ) {
933                         return cx->rc;
934                 }
935                 if ( cx->rc == LDAP_SUCCESS ) {
936                         goto gotit;
937                 }
938         }
939 #endif
940         BDB_IDL_ZERO( cx->tmp );
941
942         if ( !cx->ei ) {
943                 cx->ei = bdb_cache_find_info( cx->bdb, cx->id );
944                 if ( !cx->ei ) {
945                         cx->rc = DB_NOTFOUND;
946                         goto saveit;
947                 }
948         }
949
950         bdb_cache_entryinfo_lock( cx->ei );
951
952         /* If number of kids in the cache differs from on-disk, load
953          * up all the kids from the database
954          */
955         if ( cx->ei->bei_ckids+1 != cx->ei->bei_dkids ) {
956                 EntryInfo ei;
957                 db_recno_t dkids = cx->ei->bei_dkids;
958                 ei.bei_parent = cx->ei;
959
960                 bdb_cache_entryinfo_unlock( cx->ei );
961
962                 cx->rc = cx->db->cursor( cx->db, NULL, &cx->dbc,
963                         cx->bdb->bi_db_opflags );
964                 if ( cx->rc ) return cx->rc;
965
966                 cx->data.data = &cx->dbuf;
967                 cx->data.ulen = sizeof(ID);
968                 cx->data.dlen = sizeof(ID);
969                 cx->data.flags = DB_DBT_USERMEM | DB_DBT_PARTIAL;
970
971                 /* The first item holds the parent ID. Ignore it. */
972                 cx->rc = cx->dbc->c_get( cx->dbc, &cx->key, &cx->data, DB_SET );
973                 if ( cx->rc ) {
974                         cx->dbc->c_close( cx->dbc );
975                         if ( cx->rc == DB_NOTFOUND ) goto saveit;
976                         return cx->rc;
977                 }
978
979                 /* If the on-disk count is zero we've never checked it.
980                  * Count it now.
981                  */
982                 if ( !dkids ) {
983                         cx->dbc->c_count( cx->dbc, &dkids, 0 );
984                         cx->ei->bei_dkids = dkids;
985                 }
986
987                 cx->data.data = cx->buf;
988                 cx->data.ulen = BDB_IDL_UM_SIZE * sizeof(ID);
989                 cx->data.flags = DB_DBT_USERMEM;
990
991                 /* Fetch the rest of the IDs in a loop... */
992                 while ( (cx->rc = cx->dbc->c_get( cx->dbc, &cx->key, &cx->data,
993                         DB_MULTIPLE | DB_NEXT_DUP )) == 0 ) {
994                         u_int8_t *j;
995                         size_t len;
996                         DB_MULTIPLE_INIT( cx->ptr, &cx->data );
997                         while (cx->ptr) {
998                                 DB_MULTIPLE_NEXT( cx->ptr, &cx->data, j, len );
999                                 if (j) {
1000                                         EntryInfo *ei2;
1001                                         diskNode *d = (diskNode *)j;
1002                                         short nrlen;
1003
1004                                         AC_MEMCPY( &ei.bei_id, &d->entryID, sizeof(ID) );
1005                                         AC_MEMCPY( &nrlen, &d->nrdnlen, sizeof(d->nrdnlen) );
1006                                         ei.bei_nrdn.bv_len = nrlen;
1007                                         /* nrdn/rdn are set in-place.
1008                                          * hdb_cache_load will copy them as needed
1009                                          */
1010                                         ei.bei_nrdn.bv_val = d->nrdn;
1011                                         ei.bei_rdn.bv_len = len - sizeof(diskNode) - ei.bei_nrdn.bv_len;
1012                                         ei.bei_rdn.bv_val = d->nrdn + ei.bei_nrdn.bv_len + 1;
1013                                         bdb_idl_insert( cx->tmp, ei.bei_id );
1014                                         hdb_cache_load( cx->bdb, &ei, &ei2 );
1015                                 }
1016                         }
1017                 }
1018                 cx->rc = cx->dbc->c_close( cx->dbc );
1019         } else {
1020                 /* The in-memory cache is in sync with the on-disk data.
1021                  * do we have any kids?
1022                  */
1023                 cx->rc = 0;
1024                 if ( cx->ei->bei_ckids > 0 ) {
1025
1026                         /* Walk the kids tree; order is irrelevant since bdb_idl_insert
1027                          * will insert in sorted order.
1028                          */
1029                         avl_apply( cx->ei->bei_kids, apply_func, cx->tmp, -1, AVL_POSTORDER );
1030                 }
1031                 bdb_cache_entryinfo_unlock( cx->ei );
1032         }
1033
1034 saveit:
1035 #ifdef SLAP_IDL_CACHE
1036         if ( cx->bdb->bi_idl_cache_max_size ) {
1037                 bdb_idl_cache_put( cx->bdb, cx->db, &cx->key, cx->tmp, cx->rc );
1038         }
1039 #endif
1040         ;
1041 gotit:
1042         if ( !BDB_IDL_IS_ZERO( cx->tmp )) {
1043                 if ( cx->prefix == DN_SUBTREE_PREFIX ) {
1044                         if (cx->ei->bei_state & CACHE_ENTRY_NO_GRANDKIDS) {
1045                                 bdb_idl_union( cx->ids, cx->tmp );
1046                         } else {
1047                                 ID *save, idcurs;
1048                                 EntryInfo *ei = cx->ei;
1049                                 int nokids = 1;
1050                                 save = cx->op->o_tmpalloc( BDB_IDL_SIZEOF( cx->tmp ),
1051                                         cx->op->o_tmpmemctx );
1052                                 BDB_IDL_CPY( save, cx->tmp );
1053                                 bdb_idl_union( cx->ids, cx->tmp );
1054
1055                                 idcurs = 0;
1056                                 for ( cx->id = bdb_idl_first( save, &idcurs );
1057                                         cx->id != NOID;
1058                                         cx->id = bdb_idl_next( save, &idcurs )) {
1059                                         cx->ei = NULL;
1060                                         hdb_dn2idl_internal( cx );
1061                                         if ( !BDB_IDL_IS_ZERO( cx->tmp ))
1062                                                 nokids = 0;
1063                                 }
1064                                 cx->op->o_tmpfree( save, cx->op->o_tmpmemctx );
1065                                 if ( nokids ) ei->bei_state |= CACHE_ENTRY_NO_GRANDKIDS;
1066                         }
1067                         /* Make sure caller knows it had kids! */
1068                         cx->tmp[0]=1;
1069
1070                         cx->rc = 0;
1071                 } else {
1072                         BDB_IDL_CPY( cx->ids, cx->tmp );
1073                 }
1074         }
1075         return cx->rc;
1076 }
1077
1078 int
1079 hdb_dn2idl(
1080         Operation       *op,
1081         Entry           *e,
1082         ID *ids,
1083         ID *stack )
1084 {
1085         struct bdb_info *bdb = (struct bdb_info *)op->o_bd->be_private;
1086         struct dn2id_cookie cx;
1087
1088 #ifdef NEW_LOGGING
1089         LDAP_LOG ( INDEX, ARGS, 
1090                 "=> hdb_dn2ididl( \"%s\" )\n", e->e_nname.bv_val, 0, 0 );
1091 #else
1092         Debug( LDAP_DEBUG_TRACE, "=> hdb_dn2idl( \"%s\" )\n", e->e_nname.bv_val, 0, 0 );
1093 #endif
1094
1095 #ifndef BDB_MULTIPLE_SUFFIXES
1096         if ( op->ors_scope != LDAP_SCOPE_ONELEVEL && 
1097                 BEI(e)->bei_parent->bei_id == 0 )
1098         {
1099                 BDB_IDL_ALL( bdb, ids );
1100                 return 0;
1101         }
1102 #endif
1103
1104         cx.id = e->e_id;
1105         cx.ei = BEI(e);
1106         cx.bdb = bdb;
1107         cx.db = cx.bdb->bi_dn2id->bdi_db;
1108         cx.prefix = op->ors_scope == LDAP_SCOPE_ONELEVEL
1109                 ? DN_ONE_PREFIX : DN_SUBTREE_PREFIX;
1110         cx.ids = ids;
1111         cx.buf = stack;
1112         cx.op = op;
1113
1114         BDB_IDL_ZERO( ids );
1115         if ( cx.prefix == DN_SUBTREE_PREFIX ) {
1116                 bdb_idl_insert( ids, cx.id );
1117         }
1118
1119         DBTzero(&cx.key);
1120         cx.key.data = &cx.id;
1121         cx.key.ulen = sizeof(ID);
1122         cx.key.size = sizeof(ID);
1123         cx.key.flags = DB_DBT_USERMEM;
1124
1125         DBTzero(&cx.data);
1126
1127         return hdb_dn2idl_internal(&cx);
1128 }
1129 #endif  /* BDB_HIER */