]> git.sur5r.net Git - openldap/blob - servers/slapd/back-bdb/dn2id.c
Another BDB_HIER e_name / e_nname fix
[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 int
709 hdb_dn2id(
710         Operation       *op,
711         DB_TXN *txn,
712         struct berval   *in,
713         EntryInfo       *ei )
714 {
715         struct bdb_info *bdb = (struct bdb_info *) op->o_bd->be_private;
716         DB *db = bdb->bi_dn2id->bdi_db;
717         DBT             key, data;
718         DBC     *cursor;
719         int             rc = 0, nrlen;
720         diskNode *d;
721         char    *ptr;
722         ID idp = ei->bei_parent->bei_id;
723
724         nrlen = dn_rdnlen( op->o_bd, in );
725         if (!nrlen) nrlen = in->bv_len;
726
727         DBTzero(&key);
728         key.size = sizeof(ID);
729         key.data = &idp;
730         key.ulen = sizeof(ID);
731         key.flags = DB_DBT_USERMEM;
732
733         DBTzero(&data);
734         data.size = sizeof(diskNode) + nrlen;
735         data.ulen = data.size * 3;
736         data.flags = DB_DBT_USERMEM;
737
738         rc = db->cursor( db, txn, &cursor, bdb->bi_db_opflags );
739         if ( rc ) return rc;
740
741         d = op->o_tmpalloc( data.size * 3, op->o_tmpmemctx );
742         d->nrdnlen = nrlen;
743         ptr = lutil_strncopy( d->nrdn, in->bv_val, nrlen );
744         *ptr = '\0';
745         data.data = d;
746
747         rc = cursor->c_get( cursor, &key, &data, DB_GET_BOTH );
748         cursor->c_close( cursor );
749
750         if ( rc == 0 ) {
751                 AC_MEMCPY( &ei->bei_id, &d->entryID, sizeof(ID) );
752                 ei->bei_rdn.bv_len = data.size - sizeof(diskNode) - nrlen;
753                 ptr = d->nrdn + nrlen + 1;
754                 ei->bei_rdn.bv_val = ch_malloc( ei->bei_rdn.bv_len + 1 );
755                 strcpy( ei->bei_rdn.bv_val, ptr );
756         }
757         op->o_tmpfree( d, op->o_tmpmemctx );
758
759         return rc;
760 }
761
762 int
763 hdb_dn2id_parent(
764         Operation *op,
765         DB_TXN *txn,
766         EntryInfo *ei,
767         ID *idp )
768 {
769         struct bdb_info *bdb = (struct bdb_info *) op->o_bd->be_private;
770         DB *db = bdb->bi_dn2id->bdi_db;
771         DBT             key, data;
772         DBC     *cursor;
773         int             rc = 0;
774         diskNode *d;
775         char    *ptr;
776         unsigned char *pt2;
777
778         DBTzero(&key);
779         key.size = sizeof(ID);
780         key.data = &ei->bei_id;
781         key.ulen = sizeof(ID);
782         key.flags = DB_DBT_USERMEM;
783
784         DBTzero(&data);
785         data.flags = DB_DBT_USERMEM;
786
787         rc = db->cursor( db, txn, &cursor, bdb->bi_db_opflags );
788         if ( rc ) return rc;
789
790         data.ulen = sizeof(diskNode) + (SLAP_LDAPDN_MAXLEN * 2);
791         d = op->o_tmpalloc( data.ulen, op->o_tmpmemctx );
792         data.data = d;
793
794         rc = cursor->c_get( cursor, &key, &data, DB_SET );
795         cursor->c_close( cursor );
796         if ( rc == 0 ) {
797                 if (d->nrdnlen >= 0) {
798                         return LDAP_OTHER;
799                 }
800                 AC_MEMCPY( idp, &d->entryID, sizeof(ID) );
801                 ei->bei_nrdn.bv_len = 0 - d->nrdnlen;
802                 ber_str2bv( d->nrdn, ei->bei_nrdn.bv_len, 1, &ei->bei_nrdn );
803                 ei->bei_rdn.bv_len = data.size - sizeof(diskNode) -
804                         ei->bei_nrdn.bv_len;
805                 ptr = d->nrdn + ei->bei_nrdn.bv_len + 1;
806                 ber_str2bv( ptr, ei->bei_rdn.bv_len, 1, &ei->bei_rdn );
807         }
808         op->o_tmpfree( d, op->o_tmpmemctx );
809         return rc;
810 }
811
812 int
813 hdb_dn2id_children(
814         Operation *op,
815         DB_TXN *txn,
816         Entry *e )
817 {
818         struct bdb_info *bdb = (struct bdb_info *) op->o_bd->be_private;
819         DB *db = bdb->bi_dn2id->bdi_db;
820         DBT             key, data;
821         DBC             *cursor;
822         int             rc;
823         ID              id;
824         diskNode d;
825
826         DBTzero(&key);
827         key.size = sizeof(ID);
828         key.data = &e->e_id;
829         key.flags = DB_DBT_USERMEM;
830
831 #ifdef SLAP_IDL_CACHE
832         if ( bdb->bi_idl_cache_size ) {
833                 rc = bdb_idl_cache_get( bdb, db, &key, NULL );
834                 if ( rc != LDAP_NO_SUCH_OBJECT ) {
835                         return rc;
836                 }
837         }
838 #endif
839         DBTzero(&data);
840         data.data = &d;
841         data.ulen = sizeof(d);
842         data.flags = DB_DBT_USERMEM | DB_DBT_PARTIAL;
843         data.dlen = sizeof(d);
844
845         rc = db->cursor( db, txn, &cursor, bdb->bi_db_opflags );
846         if ( rc ) return rc;
847
848         rc = cursor->c_get( cursor, &key, &data, DB_SET );
849         if ( rc == 0 ) {
850                 rc = cursor->c_get( cursor, &key, &data, DB_NEXT_DUP );
851         }
852         cursor->c_close( cursor );
853         return rc;
854 }
855
856 /* bdb_dn2idl:
857  * We can't just use bdb_idl_fetch_key because
858  * 1 - our data items are longer than just an entry ID
859  * 2 - our data items are sorted alphabetically by nrdn, not by ID.
860  *
861  * We descend the tree recursively, so we define this cookie
862  * to hold our necessary state information. The bdb_dn2idl_internal
863  * function uses this cookie when calling itself.
864  */
865
866 struct dn2id_cookie {
867         struct bdb_info *bdb;
868         DB *db;
869         int prefix;
870         int rc;
871         ID id;
872         ID dbuf;
873         ID *ids;
874         void *ptr;
875         ID tmp[BDB_IDL_DB_SIZE];
876         ID *buf;
877         DBT key;
878         DBT data;
879         DBC *dbc;
880         Operation *op;
881 };
882
883 static int
884 hdb_dn2idl_internal(
885         struct dn2id_cookie *cx
886 )
887 {
888 #ifdef SLAP_IDL_CACHE
889         if ( cx->bdb->bi_idl_cache_size ) {
890                 cx->rc = bdb_idl_cache_get(cx->bdb, cx->db, &cx->key, cx->tmp);
891                 if ( cx->rc == DB_NOTFOUND ) {
892                         return cx->rc;
893                 }
894                 if ( cx->rc == LDAP_SUCCESS ) {
895                         goto gotit;
896                 }
897         }
898 #endif
899
900         cx->rc = cx->db->cursor( cx->db, NULL, &cx->dbc,
901                 cx->bdb->bi_db_opflags );
902         if ( cx->rc ) return cx->rc;
903         BDB_IDL_ZERO( cx->tmp );
904
905         cx->data.data = &cx->dbuf;
906         cx->data.ulen = sizeof(ID);
907         cx->data.dlen = sizeof(ID);
908         cx->data.flags = DB_DBT_USERMEM | DB_DBT_PARTIAL;
909
910         /* The first item holds the parent ID. Ignore it. */
911         cx->rc = cx->dbc->c_get( cx->dbc, &cx->key, &cx->data, DB_SET );
912         if ( cx->rc == DB_NOTFOUND ) goto saveit;
913         if ( cx->rc ) return cx->rc;
914
915         cx->data.data = cx->buf;
916         cx->data.ulen = BDB_IDL_UM_SIZE * sizeof(ID);
917         cx->data.flags = DB_DBT_USERMEM;
918
919         /* Fetch the rest of the IDs in a loop... */
920         while ( (cx->rc = cx->dbc->c_get( cx->dbc, &cx->key, &cx->data,
921                 DB_MULTIPLE | DB_NEXT_DUP )) == 0 ) {
922                 u_int8_t *j;
923                 size_t len;
924                 DB_MULTIPLE_INIT( cx->ptr, &cx->data );
925                 while (cx->ptr) {
926                         DB_MULTIPLE_NEXT( cx->ptr, &cx->data, j, len );
927                         if (j) {
928                                 AC_MEMCPY( &cx->dbuf, j, sizeof(ID) );
929                                 bdb_idl_insert( cx->tmp, cx->dbuf );
930                         }
931                 }
932         }
933         cx->dbc->c_close( cx->dbc );
934
935         /* If we got some records, treat as success */
936         if (!BDB_IDL_IS_ZERO(cx->tmp)) {
937                 cx->rc = 0;
938         }
939
940 saveit:
941 #ifdef SLAP_IDL_CACHE
942         if ( cx->bdb->bi_idl_cache_max_size ) {
943                 bdb_idl_cache_put( cx->bdb, cx->db, &cx->key, cx->tmp, cx->rc );
944         }
945 #endif
946         ;
947 gotit:
948         if ( cx->rc == 0 ) {
949                 if ( cx->prefix == DN_SUBTREE_PREFIX ) {
950                         ID *save, idcurs;
951
952                         save = cx->op->o_tmpalloc( BDB_IDL_SIZEOF( cx->tmp ),
953                                 cx->op->o_tmpmemctx );
954                         BDB_IDL_CPY( save, cx->tmp );
955                         bdb_idl_union( cx->ids, cx->tmp );
956         
957                         idcurs = 0;
958                         for ( cx->id = bdb_idl_first( save, &idcurs );
959                                 cx->id != NOID;
960                                 cx->id = bdb_idl_next( save, &idcurs )) {
961                                 hdb_dn2idl_internal( cx );
962                         }
963                         cx->op->o_tmpfree( save, cx->op->o_tmpmemctx );
964                         cx->rc = 0;
965                 } else {
966                         BDB_IDL_CPY( cx->ids, cx->tmp );
967                 }
968         }
969         return cx->rc;
970 }
971
972 int
973 hdb_dn2idl(
974         Operation       *op,
975         Entry           *e,
976         ID *ids,
977         ID *stack )
978 {
979         struct bdb_info *bdb = (struct bdb_info *)op->o_bd->be_private;
980         struct dn2id_cookie cx;
981
982 #ifdef NEW_LOGGING
983         LDAP_LOG ( INDEX, ARGS, 
984                 "=> hdb_dn2ididl( \"%s\" )\n", e->e_nname.bv_val, 0, 0 );
985 #else
986         Debug( LDAP_DEBUG_TRACE, "=> hdb_dn2idl( \"%s\" )\n", e->e_nname.bv_val, 0, 0 );
987 #endif
988
989 #ifndef BDB_MULTIPLE_SUFFIXES
990         if ( op->ors_scope == LDAP_SCOPE_SUBTREE && 
991                 BEI(e)->bei_parent->bei_id == 0 ) {
992                 BDB_IDL_ALL( bdb, ids );
993                 return 0;
994         }
995 #endif
996
997         cx.id = e->e_id;
998         cx.bdb = bdb;
999         cx.db = cx.bdb->bi_dn2id->bdi_db;
1000         cx.prefix = op->ors_scope == LDAP_SCOPE_SUBTREE ? DN_SUBTREE_PREFIX :
1001                         DN_ONE_PREFIX;
1002         cx.ids = ids;
1003         cx.buf = stack;
1004         cx.op = op;
1005
1006         BDB_IDL_ZERO( ids );
1007         if ( cx.prefix == DN_SUBTREE_PREFIX ) {
1008                 bdb_idl_insert( ids, cx.id );
1009         }
1010
1011         DBTzero(&cx.key);
1012         cx.key.data = &cx.id;
1013         cx.key.ulen = sizeof(ID);
1014         cx.key.size = sizeof(ID);
1015         cx.key.flags = DB_DBT_USERMEM;
1016
1017         DBTzero(&cx.data);
1018
1019         return hdb_dn2idl_internal(&cx);
1020 }
1021 #endif  /* BDB_HIER */