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