]> git.sur5r.net Git - openldap/blob - servers/slapd/back-bdb/dn2id.c
Cleanup prev commit
[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                 free( e->e_nname.bv_val );
560         }
561
562         e->e_name.bv_len = rlen - 1;
563         e->e_nname.bv_len = nrlen - 1;
564         e->e_name.bv_val = ch_malloc(rlen);
565         e->e_nname.bv_val = ch_malloc(nrlen);
566         ptr = e->e_name.bv_val;
567         nptr = e->e_nname.bv_val;
568         for ( ei = BEI(e); ei && ei->bei_id; ei=ei->bei_parent ) {
569                 ptr = lutil_strcopy(ptr, ei->bei_rdn.bv_val);
570                 nptr = lutil_strcopy(nptr, ei->bei_nrdn.bv_val);
571                 if ( ei->bei_parent ) {
572                         *ptr++ = ',';
573                         *nptr++ = ',';
574                 }
575         }
576         BEI(e)->bei_modrdns = max;
577         ptr[-1] = '\0';
578         nptr[-1] = '\0';
579
580         return 0;
581 }
582
583 /* We add two elements to the DN2ID database - a data item under the parent's
584  * entryID containing the child's RDN and entryID, and an item under the
585  * child's entryID containing the parent's entryID.
586  */
587 int
588 hdb_dn2id_add(
589         Operation       *op,
590         DB_TXN *txn,
591         EntryInfo       *eip,
592         Entry           *e )
593 {
594         struct bdb_info *bdb = (struct bdb_info *) op->o_bd->be_private;
595         DB *db = bdb->bi_dn2id->bdi_db;
596         DBT             key, data;
597         int             rc, rlen, nrlen;
598         diskNode *d;
599         char *ptr;
600
601         nrlen = dn_rdnlen( op->o_bd, &e->e_nname );
602         if (nrlen) {
603                 rlen = dn_rdnlen( op->o_bd, &e->e_name );
604         } else {
605                 nrlen = e->e_nname.bv_len;
606                 rlen = e->e_name.bv_len;
607         }
608
609         d = op->o_tmpalloc(sizeof(diskNode) + rlen + nrlen, op->o_tmpmemctx);
610         d->entryID = e->e_id;
611         d->nrdnlen = nrlen;
612         ptr = lutil_strncopy( d->nrdn, e->e_nname.bv_val, nrlen );
613         *ptr++ = '\0';
614         ptr = lutil_strncopy( ptr, e->e_name.bv_val, rlen );
615         *ptr = '\0';
616
617         DBTzero(&key);
618         DBTzero(&data);
619         key.data = &eip->bei_id;
620         key.size = sizeof(ID);
621         key.flags = DB_DBT_USERMEM;
622
623 #ifdef SLAP_IDL_CACHE
624         if ( bdb->bi_idl_cache_size ) {
625                 bdb_idl_cache_del( bdb, db, &key );
626         }
627 #endif
628         data.data = d;
629         data.size = sizeof(diskNode) + rlen + nrlen;
630         data.flags = DB_DBT_USERMEM;
631
632         rc = db->put( db, txn, &key, &data, DB_NODUPDATA );
633
634         if (rc == 0) {
635                 key.data = &e->e_id;
636                 d->entryID = eip->bei_id;
637                 d->nrdnlen = 0 - nrlen;
638
639                 rc = db->put( db, txn, &key, &data, DB_NODUPDATA );
640         }
641
642         op->o_tmpfree( d, op->o_tmpmemctx );
643
644         return rc;
645 }
646
647 int
648 hdb_dn2id_delete(
649         Operation       *op,
650         DB_TXN *txn,
651         EntryInfo       *eip,
652         Entry   *e )
653 {
654         struct bdb_info *bdb = (struct bdb_info *) op->o_bd->be_private;
655         DB *db = bdb->bi_dn2id->bdi_db;
656         DBT             key, data;
657         DBC     *cursor;
658         diskNode *d;
659         int rc, nrlen;
660
661         DBTzero(&key);
662         key.size = sizeof(ID);
663         key.ulen = key.size;
664         key.data = &eip->bei_id;
665         key.flags = DB_DBT_USERMEM;
666
667         DBTzero(&data);
668         data.size = sizeof(diskNode) + BEI(e)->bei_nrdn.bv_len;
669         data.ulen = data.size;
670         data.dlen = data.size;
671         data.flags = DB_DBT_USERMEM | DB_DBT_PARTIAL;
672
673 #ifdef SLAP_IDL_CACHE
674         if ( bdb->bi_idl_cache_size ) {
675                 bdb_idl_cache_del( bdb, db, &key );
676         }
677 #endif
678         rc = db->cursor( db, txn, &cursor, bdb->bi_db_opflags );
679         if ( rc ) return rc;
680
681         d = op->o_tmpalloc( data.size, op->o_tmpmemctx );
682         d->entryID = e->e_id;
683         d->nrdnlen = BEI(e)->bei_nrdn.bv_len;
684         strcpy( d->nrdn, BEI(e)->bei_nrdn.bv_val );
685         data.data = d;
686
687         /* Delete our ID from the parent's list */
688         rc = cursor->c_get( cursor, &key, &data, DB_GET_BOTH | DB_RMW );
689         if ( rc == 0 )
690                 rc = cursor->c_del( cursor, 0 );
691
692         /* Delete our ID from the tree. With sorted duplicates, this
693          * will leave any child nodes still hanging around. This is OK
694          * for modrdn, which will add our info back in later.
695          */
696         if ( rc == 0 ) {
697                 key.data = &e->e_id;
698                 rc = cursor->c_get( cursor, &key, &data, DB_SET | DB_RMW );
699                 if ( rc == 0 )
700                         rc = cursor->c_del( cursor, 0 );
701         }
702         cursor->c_close( cursor );
703         op->o_tmpfree( d, op->o_tmpmemctx );
704
705         return rc;
706 }
707
708
709 int
710 hdb_dn2id(
711         Operation       *op,
712         DB_TXN *txn,
713         struct berval   *in,
714         EntryInfo       *ei )
715 {
716         struct bdb_info *bdb = (struct bdb_info *) op->o_bd->be_private;
717         DB *db = bdb->bi_dn2id->bdi_db;
718         DBT             key, data;
719         DBC     *cursor;
720         int             rc = 0, nrlen;
721         diskNode *d;
722         char    *ptr;
723         ID idp = ei->bei_parent->bei_id;
724
725         nrlen = dn_rdnlen( op->o_bd, in );
726         if (!nrlen) nrlen = in->bv_len;
727
728         DBTzero(&key);
729         key.size = sizeof(ID);
730         key.data = &idp;
731         key.ulen = sizeof(ID);
732         key.flags = DB_DBT_USERMEM;
733
734         DBTzero(&data);
735         data.size = sizeof(diskNode) + nrlen;
736         data.ulen = data.size * 3;
737         data.flags = DB_DBT_USERMEM;
738
739         rc = db->cursor( db, txn, &cursor, bdb->bi_db_opflags );
740         if ( rc ) return rc;
741
742         d = op->o_tmpalloc( data.size * 3, op->o_tmpmemctx );
743         d->nrdnlen = nrlen;
744         ptr = lutil_strncopy( d->nrdn, in->bv_val, nrlen );
745         *ptr = '\0';
746         data.data = d;
747
748         rc = cursor->c_get( cursor, &key, &data, DB_GET_BOTH );
749         if ( rc == 0 ) {
750                 ei->bei_id = d->entryID;
751                 ei->bei_rdn.bv_len = data.size - sizeof(diskNode) - nrlen;
752                 ptr = d->nrdn + nrlen + 1;
753                 ber_str2bv( ptr, ei->bei_rdn.bv_len, 1, &ei->bei_rdn );
754                 if ( !ei->bei_parent->bei_dkids ) {
755                         db_recno_t dkids;
756                         /* How many children does the parent have? */
757                         /* FIXME: do we need to lock the parent
758                          * entryinfo? Seems safe...
759                          */
760                         cursor->c_count( cursor, &dkids, 0 );
761                         ei->bei_parent->bei_dkids = dkids;
762                 }
763         }
764         cursor->c_close( cursor );
765         op->o_tmpfree( d, op->o_tmpmemctx );
766
767         return rc;
768 }
769
770 int
771 hdb_dn2id_parent(
772         Operation *op,
773         DB_TXN *txn,
774         EntryInfo *ei,
775         ID *idp )
776 {
777         struct bdb_info *bdb = (struct bdb_info *) op->o_bd->be_private;
778         DB *db = bdb->bi_dn2id->bdi_db;
779         DBT             key, data;
780         DBC     *cursor;
781         int             rc = 0;
782         diskNode *d;
783         char    *ptr;
784         unsigned char *pt2;
785
786         DBTzero(&key);
787         key.size = sizeof(ID);
788         key.data = &ei->bei_id;
789         key.ulen = sizeof(ID);
790         key.flags = DB_DBT_USERMEM;
791
792         DBTzero(&data);
793         data.flags = DB_DBT_USERMEM;
794
795         rc = db->cursor( db, txn, &cursor, bdb->bi_db_opflags );
796         if ( rc ) return rc;
797
798         data.ulen = sizeof(diskNode) + (SLAP_LDAPDN_MAXLEN * 2);
799         d = op->o_tmpalloc( data.ulen, op->o_tmpmemctx );
800         data.data = d;
801
802         rc = cursor->c_get( cursor, &key, &data, DB_SET );
803         if ( rc == 0 ) {
804                 if (d->nrdnlen >= 0) {
805                         rc = LDAP_OTHER;
806                 } else {
807                         db_recno_t dkids;
808                         *idp = d->entryID;
809                         ei->bei_nrdn.bv_len = 0 - d->nrdnlen;
810                         ber_str2bv( d->nrdn, ei->bei_nrdn.bv_len, 1, &ei->bei_nrdn );
811                         ei->bei_rdn.bv_len = data.size - sizeof(diskNode) -
812                                 ei->bei_nrdn.bv_len;
813                         ptr = d->nrdn + ei->bei_nrdn.bv_len + 1;
814                         ber_str2bv( ptr, ei->bei_rdn.bv_len, 1, &ei->bei_rdn );
815                         /* How many children does this node have? */
816                         cursor->c_count( cursor, &dkids, 0 );
817                         ei->bei_dkids = dkids;
818                 }
819         }
820         cursor->c_close( cursor );
821         op->o_tmpfree( d, op->o_tmpmemctx );
822         return rc;
823 }
824
825 int
826 hdb_dn2id_children(
827         Operation *op,
828         DB_TXN *txn,
829         Entry *e )
830 {
831         struct bdb_info *bdb = (struct bdb_info *) op->o_bd->be_private;
832         DB *db = bdb->bi_dn2id->bdi_db;
833         DBT             key, data;
834         DBC             *cursor;
835         int             rc;
836         ID              id;
837         diskNode d;
838
839         DBTzero(&key);
840         key.size = sizeof(ID);
841         key.data = &e->e_id;
842         key.flags = DB_DBT_USERMEM;
843
844 #ifdef SLAP_IDL_CACHE
845         if ( bdb->bi_idl_cache_size ) {
846                 rc = bdb_idl_cache_get( bdb, db, &key, NULL );
847                 if ( rc != LDAP_NO_SUCH_OBJECT ) {
848                         return rc;
849                 }
850         }
851 #endif
852         DBTzero(&data);
853         data.data = &d;
854         data.ulen = sizeof(d);
855         data.flags = DB_DBT_USERMEM | DB_DBT_PARTIAL;
856         data.dlen = sizeof(d);
857
858         rc = db->cursor( db, txn, &cursor, bdb->bi_db_opflags );
859         if ( rc ) return rc;
860
861         rc = cursor->c_get( cursor, &key, &data, DB_SET );
862         if ( rc == 0 ) {
863                 db_recno_t dkids;
864                 rc = cursor->c_count( cursor, &dkids, 0 );
865                 if ( rc == 0 ) {
866                         BEI(e)->bei_dkids = dkids;
867                         if ( dkids < 2 ) rc = DB_NOTFOUND;
868                 }
869         }
870         cursor->c_close( cursor );
871         return rc;
872 }
873
874 /* bdb_dn2idl:
875  * We can't just use bdb_idl_fetch_key because
876  * 1 - our data items are longer than just an entry ID
877  * 2 - our data items are sorted alphabetically by nrdn, not by ID.
878  *
879  * We descend the tree recursively, so we define this cookie
880  * to hold our necessary state information. The bdb_dn2idl_internal
881  * function uses this cookie when calling itself.
882  */
883
884 struct dn2id_cookie {
885         struct bdb_info *bdb;
886         DB *db;
887         int prefix;
888         int rc;
889         EntryInfo *ei;
890         ID id;
891         ID dbuf;
892         ID *ids;
893         void *ptr;
894         ID tmp[BDB_IDL_DB_SIZE];
895         ID *buf;
896         DBT key;
897         DBT data;
898         DBC *dbc;
899         Operation *op;
900 };
901
902 /* Stuff for iterating over a bei_kids AVL tree and adding the
903  * IDs to an IDL
904  */
905 struct apply_arg {
906         ID *idl;
907         EntryInfo **ei;
908 };
909
910 static int
911 apply_func(
912         void *data,
913         void *arg )
914 {
915         EntryInfo *ei = data;
916         struct apply_arg *ap = arg;
917
918         bdb_idl_insert( ap->idl, ei->bei_id );
919         if ( ap->ei ) {
920                 *(ap->ei)++ = ei;
921         }
922         return 0;
923 }
924
925 static int
926 hdb_dn2idl_internal(
927         struct dn2id_cookie *cx
928 )
929 {
930         EntryInfo **eilist = NULL, **ptr;
931 #ifdef SLAP_IDL_CACHE
932         if ( cx->bdb->bi_idl_cache_size ) {
933                 cx->rc = bdb_idl_cache_get(cx->bdb, cx->db, &cx->key, cx->tmp);
934                 if ( cx->rc == DB_NOTFOUND ) {
935                         return cx->rc;
936                 }
937                 if ( cx->rc == LDAP_SUCCESS ) {
938                         goto gotit;
939                 }
940         }
941 #endif
942         BDB_IDL_ZERO( cx->tmp );
943
944         /* If number of kids in the cache differs from on-disk, load
945          * up all the kids from the database
946          */
947         if ( cx->ei->bei_ckids+1 != cx->ei->bei_dkids ) {
948                 EntryInfo ei;
949                 ei.bei_parent = cx->ei;
950
951                 cx->rc = cx->db->cursor( cx->db, NULL, &cx->dbc,
952                         cx->bdb->bi_db_opflags );
953                 if ( cx->rc ) return cx->rc;
954
955                 cx->data.data = &cx->dbuf;
956                 cx->data.ulen = sizeof(ID);
957                 cx->data.dlen = sizeof(ID);
958                 cx->data.flags = DB_DBT_USERMEM | DB_DBT_PARTIAL;
959
960                 /* The first item holds the parent ID. Ignore it. */
961                 cx->rc = cx->dbc->c_get( cx->dbc, &cx->key, &cx->data, DB_SET );
962                 if ( cx->rc == DB_NOTFOUND ) goto saveit;
963                 if ( cx->rc ) return cx->rc;
964
965                 /* If the on-disk count is zero we've never checked it.
966                  * Count it now.
967                  */
968                 if ( !cx->ei->bei_dkids ) {
969                         db_recno_t dkids;
970                         cx->dbc->c_count( cx->dbc, &dkids, 0 );
971                         cx->ei->bei_dkids = dkids;
972                 }
973
974                 /* If there are kids and this is a subtree search, allocate
975                  * temp storage for the list of kids.
976                  */
977                 if ( cx->prefix == DN_SUBTREE_PREFIX && cx->ei->bei_dkids > 1 ) {
978                         eilist = cx->op->o_tmpalloc( sizeof(EntryInfo *) * cx->ei->bei_dkids, cx->op->o_tmpmemctx );
979                         eilist[cx->ei->bei_dkids-1] = NULL;
980                         ptr = eilist;
981                 }
982
983                 cx->data.data = cx->buf;
984                 cx->data.ulen = BDB_IDL_UM_SIZE * sizeof(ID);
985                 cx->data.flags = DB_DBT_USERMEM;
986
987                 /* Fetch the rest of the IDs in a loop... */
988                 while ( (cx->rc = cx->dbc->c_get( cx->dbc, &cx->key, &cx->data,
989                         DB_MULTIPLE | DB_NEXT_DUP )) == 0 ) {
990                         u_int8_t *j;
991                         size_t len;
992                         DB_MULTIPLE_INIT( cx->ptr, &cx->data );
993                         while (cx->ptr) {
994                                 DB_MULTIPLE_NEXT( cx->ptr, &cx->data, j, len );
995                                 if (j) {
996                                         EntryInfo *ei2;
997                                         diskNode *d = (diskNode *)j;
998
999                                         AC_MEMCPY( &ei.bei_id, &d->entryID, sizeof(ID) );
1000                                         AC_MEMCPY( &ei.bei_nrdn.bv_len, &d->nrdnlen, sizeof(d->nrdnlen) );
1001                                         /* nrdn/rdn are set in-place.
1002                                          * hdb_cache_load will copy them as needed
1003                                          */
1004                                         ei.bei_nrdn.bv_val = d->nrdn;
1005                                         ei.bei_rdn.bv_len = len - sizeof(diskNode) - ei.bei_nrdn.bv_len;
1006                                         ei.bei_rdn.bv_val = d->nrdn + ei.bei_nrdn.bv_len + 1;
1007                                         bdb_idl_insert( cx->tmp, ei.bei_id );
1008                                         hdb_cache_load( cx->bdb, &ei, &ei2 );
1009                                         if ( eilist )
1010                                                 *ptr++ = ei2;
1011                                 }
1012                         }
1013                 }
1014                 cx->dbc->c_close( cx->dbc );
1015         } else {
1016                 /* The in-memory cache is in sync with the on-disk data.
1017                  * do we have any kids?
1018                  */
1019                 if ( cx->ei->bei_ckids > 0 ) {
1020                         struct apply_arg ap;
1021
1022                         /* Temp storage for subtree search */
1023                         if ( cx->prefix == DN_SUBTREE_PREFIX ) {
1024                                 eilist = cx->op->o_tmpalloc( sizeof(EntryInfo *) * cx->ei->bei_dkids, cx->op->o_tmpmemctx );
1025                                 eilist[cx->ei->bei_dkids-1] = NULL;
1026                         }
1027
1028                         /* Walk the kids tree; order is irrelevant since bdb_idl_insert
1029                          * will insert in sorted order.
1030                          */
1031                         ap.idl = cx->tmp;
1032                         ap.ei = eilist;
1033                         bdb_cache_entryinfo_lock( cx->ei );
1034                         avl_apply( cx->ei->bei_kids, apply_func, &ap, -1, AVL_POSTORDER );
1035                         bdb_cache_entryinfo_unlock( cx->ei );
1036                 }
1037         }
1038
1039         /* If we got some records, treat as success */
1040         if (!BDB_IDL_IS_ZERO(cx->tmp)) {
1041                 cx->rc = 0;
1042         }
1043
1044 saveit:
1045 #ifdef SLAP_IDL_CACHE
1046         if ( cx->bdb->bi_idl_cache_max_size ) {
1047                 bdb_idl_cache_put( cx->bdb, cx->db, &cx->key, cx->tmp, cx->rc );
1048         }
1049 #endif
1050         ;
1051 gotit:
1052         if ( cx->rc == 0 ) {
1053                 /* If eilist is NULL, cx->tmp is empty... */
1054                 if ( cx->prefix == DN_SUBTREE_PREFIX && eilist ) {
1055                         bdb_idl_union( cx->ids, cx->tmp );
1056                         for (ptr = eilist; *ptr; ptr++) {
1057                                 cx->ei = *ptr;
1058                                 cx->id = cx->ei->bei_id;
1059                                 hdb_dn2idl_internal( cx );
1060                         }
1061                         cx->op->o_tmpfree( eilist, cx->op->o_tmpmemctx );
1062                         cx->rc = 0;
1063                 } else {
1064                         BDB_IDL_CPY( cx->ids, cx->tmp );
1065                 }
1066         }
1067         return cx->rc;
1068 }
1069
1070 int
1071 hdb_dn2idl(
1072         Operation       *op,
1073         Entry           *e,
1074         ID *ids,
1075         ID *stack )
1076 {
1077         struct bdb_info *bdb = (struct bdb_info *)op->o_bd->be_private;
1078         struct dn2id_cookie cx;
1079
1080 #ifdef NEW_LOGGING
1081         LDAP_LOG ( INDEX, ARGS, 
1082                 "=> hdb_dn2ididl( \"%s\" )\n", e->e_nname.bv_val, 0, 0 );
1083 #else
1084         Debug( LDAP_DEBUG_TRACE, "=> hdb_dn2idl( \"%s\" )\n", e->e_nname.bv_val, 0, 0 );
1085 #endif
1086
1087 #ifndef BDB_MULTIPLE_SUFFIXES
1088         if ( op->ors_scope == LDAP_SCOPE_SUBTREE && 
1089                 BEI(e)->bei_parent->bei_id == 0 ) {
1090                 BDB_IDL_ALL( bdb, ids );
1091                 return 0;
1092         }
1093 #endif
1094
1095         cx.id = e->e_id;
1096         cx.ei = BEI(e);
1097         cx.bdb = bdb;
1098         cx.db = cx.bdb->bi_dn2id->bdi_db;
1099         cx.prefix = op->ors_scope == LDAP_SCOPE_SUBTREE ? DN_SUBTREE_PREFIX :
1100                         DN_ONE_PREFIX;
1101         cx.ids = ids;
1102         cx.buf = stack;
1103         cx.op = op;
1104
1105         BDB_IDL_ZERO( ids );
1106         if ( cx.prefix == DN_SUBTREE_PREFIX ) {
1107                 bdb_idl_insert( ids, cx.id );
1108         }
1109
1110         DBTzero(&cx.key);
1111         cx.key.data = &cx.id;
1112         cx.key.ulen = sizeof(ID);
1113         cx.key.size = sizeof(ID);
1114         cx.key.flags = DB_DBT_USERMEM;
1115
1116         DBTzero(&cx.data);
1117
1118         return hdb_dn2idl_internal(&cx);
1119 }
1120 #endif  /* BDB_HIER */