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