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