]> git.sur5r.net Git - openldap/blob - servers/slapd/back-bdb/dn2id.c
ITS#3556: 64-bit portability
[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-2005 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         /* we actually could do a empty get... */
393         DBTzero( &data );
394         data.data = &id;
395         data.ulen = sizeof(id);
396         data.flags = DB_DBT_USERMEM;
397         data.doff = 0;
398         data.dlen = sizeof(id);
399
400         rc = db->get( db, txn, &key, &data, bdb->bi_db_opflags );
401         op->o_tmpfree( key.data, op->o_tmpmemctx );
402
403 #ifdef NEW_LOGGING
404         LDAP_LOG ( INDEX, DETAIL1, 
405                 "<= bdb_dn2id_children( %s ): %s (%d)\n", 
406                 e->e_nname.bv_val, rc == 0 ? "" : ( rc == DB_NOTFOUND ? "no " :
407                 db_strerror(rc)), rc );
408 #else
409         Debug( LDAP_DEBUG_TRACE, "<= bdb_dn2id_children( %s ): %s (%d)\n",
410                 e->e_nname.bv_val,
411                 rc == 0 ? "" : ( rc == DB_NOTFOUND ? "no " :
412                         db_strerror(rc) ), rc );
413 #endif
414
415         return rc;
416 }
417
418 int
419 bdb_dn2idl(
420         Operation *op,
421         Entry *e,
422         ID *ids,
423         ID *stack )
424 {
425         int             rc;
426         DBT             key;
427         struct bdb_info *bdb = (struct bdb_info *) op->o_bd->be_private;
428         DB *db = bdb->bi_dn2id->bdi_db;
429         int prefix = ( op->ors_scope == LDAP_SCOPE_ONELEVEL )
430                 ? DN_ONE_PREFIX : DN_SUBTREE_PREFIX;
431
432 #ifdef NEW_LOGGING
433         LDAP_LOG ( INDEX, ARGS, "=> bdb_dn2ididl( \"%s\" )\n",
434                 e->e_nname.bv_val, 0, 0 );
435 #else
436         Debug( LDAP_DEBUG_TRACE, "=> bdb_dn2idl( \"%s\" )\n",
437                 e->e_nname.bv_val, 0, 0 );
438 #endif
439
440 #ifndef BDB_MULTIPLE_SUFFIXES
441         if ( prefix == DN_SUBTREE_PREFIX && BEI(e)->bei_parent->bei_id == 0 ) {
442                 BDB_IDL_ALL(bdb, ids);
443                 return 0;
444         }
445 #endif
446
447         DBTzero( &key );
448         key.size = e->e_nname.bv_len + 2;
449         key.ulen = key.size;
450         key.flags = DB_DBT_USERMEM;
451         key.data = op->o_tmpalloc( key.size, op->o_tmpmemctx );
452         ((char *)key.data)[0] = prefix;
453         AC_MEMCPY( &((char *)key.data)[1], e->e_nname.bv_val, key.size - 1 );
454
455         rc = bdb_idl_fetch_key( op->o_bd, db, NULL, &key, ids );
456
457         if( rc != 0 ) {
458 #ifdef NEW_LOGGING
459                 LDAP_LOG ( INDEX, ERR, 
460                         "<= bdb_dn2ididl: get failed: %s (%d)\n", db_strerror(rc), rc, 0 );
461 #else
462                 Debug( LDAP_DEBUG_TRACE,
463                         "<= bdb_dn2idl: get failed: %s (%d)\n",
464                         db_strerror( rc ), rc, 0 );
465 #endif
466
467         } else {
468 #ifdef NEW_LOGGING
469                 LDAP_LOG ( INDEX, RESULTS, 
470                         "<= bdb_dn2ididl: id=%ld first=%ld last=%ld\n", 
471                         (long) ids[0], (long) BDB_IDL_FIRST( ids ), 
472                         (long) BDB_IDL_LAST( ids ) );
473 #else
474                 Debug( LDAP_DEBUG_TRACE,
475                         "<= bdb_dn2idl: id=%ld first=%ld last=%ld\n",
476                         (long) ids[0],
477                         (long) BDB_IDL_FIRST( ids ), (long) BDB_IDL_LAST( ids ) );
478 #endif
479         }
480
481         op->o_tmpfree( key.data, op->o_tmpmemctx );
482         return rc;
483 }
484 #else   /* BDB_HIER */
485
486 /* Experimental management routines for a hierarchically structured database.
487  *
488  * Unsupported! Use at your own risk!
489  * -- Howard Chu, Symas Corp. 2003.
490  *
491  * Instead of a ldbm-style dn2id database, we use a hierarchical one. Each
492  * entry in this database is a struct diskNode, keyed by entryID and with
493  * the data containing the RDN and entryID of the node's children. We use
494  * a B-Tree with sorted duplicates to store all the children of a node under
495  * the same key. Also, the first item under the key contains the entry's own
496  * rdn and the ID of the node's parent, to allow bottom-up tree traversal as
497  * well as top-down. To keep this info first in the list, the nrdnlen is set
498  * to the negative of its value.
499  *
500  * The diskNode is a variable length structure. This definition is not
501  * directly usable for in-memory manipulation.
502  */
503 typedef struct diskNode {
504         ID entryID;
505         short nrdnlen;
506         char nrdn[1];
507         char rdn[1];
508 } diskNode;
509
510 /* Sort function for the sorted duplicate data items of a dn2id key.
511  * Sorts based on normalized RDN, in length order.
512  */
513 int
514 hdb_dup_compare(
515         DB *db, 
516         const DBT *usrkey,
517         const DBT *curkey
518 )
519 {
520         signed char *u = (signed char *)&(((diskNode *)(usrkey->data))->nrdnlen);
521         signed char *c = (signed char *)&(((diskNode *)(curkey->data))->nrdnlen);
522         int rc, i;
523
524         /* data is not aligned, cannot compare directly */
525 #ifdef WORDS_BIGENDIAN
526         for( i = 0; i < (int)sizeof(short); i++)
527 #else
528         for( i = sizeof(short)-1; i >= 0; i--)
529 #endif
530         {
531                 rc = u[i] - c[i];
532                 if( rc ) return rc;
533         }
534         return strcmp( u+sizeof(short), c+sizeof(short) );
535 }
536
537 /* This function constructs a full DN for a given entry.
538  */
539 int hdb_fix_dn(
540         Entry *e,
541         int checkit
542 )
543 {
544         EntryInfo *ei;
545         int rlen = 0, nrlen = 0;
546         char *ptr, *nptr;
547         int max = 0;
548
549         /* count length of all DN components */
550         for ( ei = BEI(e); ei && ei->bei_id; ei=ei->bei_parent ) {
551                 rlen += ei->bei_rdn.bv_len + 1;
552                 nrlen += ei->bei_nrdn.bv_len + 1;
553                 if (ei->bei_modrdns > max) max = ei->bei_modrdns;
554         }
555
556         /* See if the entry DN was invalidated by a subtree rename */
557         if ( checkit ) {
558                 if ( BEI(e)->bei_modrdns >= max ) {
559                         return 0;
560                 }
561                 /* We found a mismatch, tell the caller to lock it */
562                 if ( checkit == 1 ) {
563                         return 1;
564                 }
565                 /* checkit == 2. do the fix. */
566                 free( e->e_name.bv_val );
567                 free( e->e_nname.bv_val );
568         }
569
570         e->e_name.bv_len = rlen - 1;
571         e->e_nname.bv_len = nrlen - 1;
572         e->e_name.bv_val = ch_malloc(rlen);
573         e->e_nname.bv_val = ch_malloc(nrlen);
574         ptr = e->e_name.bv_val;
575         nptr = e->e_nname.bv_val;
576         for ( ei = BEI(e); ei && ei->bei_id; ei=ei->bei_parent ) {
577                 ptr = lutil_strcopy(ptr, ei->bei_rdn.bv_val);
578                 nptr = lutil_strcopy(nptr, ei->bei_nrdn.bv_val);
579                 if ( ei->bei_parent ) {
580                         *ptr++ = ',';
581                         *nptr++ = ',';
582                 }
583         }
584         BEI(e)->bei_modrdns = max;
585         ptr[-1] = '\0';
586         nptr[-1] = '\0';
587
588         return 0;
589 }
590
591 /* We add two elements to the DN2ID database - a data item under the parent's
592  * entryID containing the child's RDN and entryID, and an item under the
593  * child's entryID containing the parent's entryID.
594  */
595 int
596 hdb_dn2id_add(
597         Operation       *op,
598         DB_TXN *txn,
599         EntryInfo       *eip,
600         Entry           *e )
601 {
602         struct bdb_info *bdb = (struct bdb_info *) op->o_bd->be_private;
603         DB *db = bdb->bi_dn2id->bdi_db;
604         DBT             key, data;
605         int             rc, rlen, nrlen;
606         diskNode *d;
607         char *ptr;
608
609         nrlen = dn_rdnlen( op->o_bd, &e->e_nname );
610         if (nrlen) {
611                 rlen = dn_rdnlen( op->o_bd, &e->e_name );
612         } else {
613                 nrlen = e->e_nname.bv_len;
614                 rlen = e->e_name.bv_len;
615         }
616
617         d = op->o_tmpalloc(sizeof(diskNode) + rlen + nrlen, op->o_tmpmemctx);
618         d->entryID = e->e_id;
619         d->nrdnlen = nrlen;
620         ptr = lutil_strncopy( d->nrdn, e->e_nname.bv_val, nrlen );
621         *ptr++ = '\0';
622         ptr = lutil_strncopy( ptr, e->e_name.bv_val, rlen );
623         *ptr = '\0';
624
625         DBTzero(&key);
626         DBTzero(&data);
627         key.data = &eip->bei_id;
628         key.size = sizeof(ID);
629         key.flags = DB_DBT_USERMEM;
630
631         /* Need to make dummy root node once. Subsequent attempts
632          * will fail harmlessly.
633          */
634         if ( eip->bei_id == 0 ) {
635                 diskNode dummy = {0};
636                 data.data = &dummy;
637                 data.size = sizeof(diskNode);
638                 data.flags = DB_DBT_USERMEM;
639
640                 db->put( db, txn, &key, &data, DB_NODUPDATA );
641         }
642
643         if ( bdb->bi_idl_cache_size ) {
644                 bdb_idl_cache_del( bdb, db, &key );
645         }
646         data.data = d;
647         data.size = sizeof(diskNode) + rlen + nrlen;
648         data.flags = DB_DBT_USERMEM;
649
650         rc = db->put( db, txn, &key, &data, DB_NODUPDATA );
651
652         if (rc == 0) {
653                 key.data = &e->e_id;
654                 d->entryID = eip->bei_id;
655                 d->nrdnlen = 0 - nrlen;
656
657                 rc = db->put( db, txn, &key, &data, DB_NODUPDATA );
658         }
659
660         op->o_tmpfree( d, op->o_tmpmemctx );
661
662         return rc;
663 }
664
665 int
666 hdb_dn2id_delete(
667         Operation       *op,
668         DB_TXN *txn,
669         EntryInfo       *eip,
670         Entry   *e )
671 {
672         struct bdb_info *bdb = (struct bdb_info *) op->o_bd->be_private;
673         DB *db = bdb->bi_dn2id->bdi_db;
674         DBT             key, data;
675         DBC     *cursor;
676         diskNode *d;
677         int rc, nrlen;
678
679         DBTzero(&key);
680         key.size = sizeof(ID);
681         key.ulen = key.size;
682         key.data = &eip->bei_id;
683         key.flags = DB_DBT_USERMEM;
684
685         DBTzero(&data);
686         data.size = sizeof(diskNode) + BEI(e)->bei_nrdn.bv_len;
687         data.ulen = data.size;
688         data.dlen = data.size;
689         data.flags = DB_DBT_USERMEM | DB_DBT_PARTIAL;
690
691         if ( bdb->bi_idl_cache_size ) {
692                 bdb_idl_cache_del( bdb, db, &key );
693         }
694         rc = db->cursor( db, txn, &cursor, bdb->bi_db_opflags );
695         if ( rc ) return rc;
696
697         d = op->o_tmpalloc( data.size, op->o_tmpmemctx );
698         d->entryID = e->e_id;
699         d->nrdnlen = BEI(e)->bei_nrdn.bv_len;
700         strcpy( d->nrdn, BEI(e)->bei_nrdn.bv_val );
701         data.data = d;
702
703         /* Delete our ID from the parent's list */
704         rc = cursor->c_get( cursor, &key, &data, DB_GET_BOTH | DB_RMW );
705         if ( rc == 0 )
706                 rc = cursor->c_del( cursor, 0 );
707
708         /* Delete our ID from the tree. With sorted duplicates, this
709          * will leave any child nodes still hanging around. This is OK
710          * for modrdn, which will add our info back in later.
711          */
712         if ( rc == 0 ) {
713                 key.data = &e->e_id;
714                 rc = cursor->c_get( cursor, &key, &data, DB_SET | DB_RMW );
715                 if ( rc == 0 )
716                         rc = cursor->c_del( cursor, 0 );
717         }
718         cursor->c_close( cursor );
719         op->o_tmpfree( d, op->o_tmpmemctx );
720
721         return rc;
722 }
723
724
725 int
726 hdb_dn2id(
727         Operation       *op,
728         DB_TXN *txn,
729         struct berval   *in,
730         EntryInfo       *ei )
731 {
732         struct bdb_info *bdb = (struct bdb_info *) op->o_bd->be_private;
733         DB *db = bdb->bi_dn2id->bdi_db;
734         DBT             key, data;
735         DBC     *cursor;
736         int             rc = 0, nrlen;
737         diskNode *d;
738         char    *ptr;
739         ID idp = ei->bei_parent->bei_id;
740
741         nrlen = dn_rdnlen( op->o_bd, in );
742         if (!nrlen) nrlen = in->bv_len;
743
744         DBTzero(&key);
745         key.size = sizeof(ID);
746         key.data = &idp;
747         key.ulen = sizeof(ID);
748         key.flags = DB_DBT_USERMEM;
749
750         DBTzero(&data);
751         data.size = sizeof(diskNode) + nrlen;
752         data.ulen = data.size * 3;
753         data.flags = DB_DBT_USERMEM;
754
755         rc = db->cursor( db, txn, &cursor, bdb->bi_db_opflags );
756         if ( rc ) return rc;
757
758         d = op->o_tmpalloc( data.size * 3, op->o_tmpmemctx );
759         d->nrdnlen = nrlen;
760         ptr = lutil_strncopy( d->nrdn, in->bv_val, nrlen );
761         *ptr = '\0';
762         data.data = d;
763
764         rc = cursor->c_get( cursor, &key, &data, DB_GET_BOTH );
765         if ( rc == 0 ) {
766                 ei->bei_id = d->entryID;
767                 ei->bei_rdn.bv_len = data.size - sizeof(diskNode) - nrlen;
768                 ptr = d->nrdn + nrlen + 1;
769                 ber_str2bv( ptr, ei->bei_rdn.bv_len, 1, &ei->bei_rdn );
770                 if ( !ei->bei_parent->bei_dkids ) {
771                         db_recno_t dkids;
772                         /* How many children does the parent have? */
773                         /* FIXME: do we need to lock the parent
774                          * entryinfo? Seems safe...
775                          */
776                         cursor->c_count( cursor, &dkids, 0 );
777                         ei->bei_parent->bei_dkids = dkids;
778                 }
779         }
780         cursor->c_close( cursor );
781         op->o_tmpfree( d, op->o_tmpmemctx );
782
783         return rc;
784 }
785
786 int
787 hdb_dn2id_parent(
788         Operation *op,
789         DB_TXN *txn,
790         EntryInfo *ei,
791         ID *idp )
792 {
793         struct bdb_info *bdb = (struct bdb_info *) op->o_bd->be_private;
794         DB *db = bdb->bi_dn2id->bdi_db;
795         DBT             key, data;
796         DBC     *cursor;
797         int             rc = 0;
798         diskNode *d;
799         char    *ptr;
800         unsigned char *pt2;
801
802         DBTzero(&key);
803         key.size = sizeof(ID);
804         key.data = &ei->bei_id;
805         key.ulen = sizeof(ID);
806         key.flags = DB_DBT_USERMEM;
807
808         DBTzero(&data);
809         data.flags = DB_DBT_USERMEM;
810
811         rc = db->cursor( db, txn, &cursor, bdb->bi_db_opflags );
812         if ( rc ) return rc;
813
814         data.ulen = sizeof(diskNode) + (SLAP_LDAPDN_MAXLEN * 2);
815         d = op->o_tmpalloc( data.ulen, op->o_tmpmemctx );
816         data.data = d;
817
818         rc = cursor->c_get( cursor, &key, &data, DB_SET );
819         if ( rc == 0 ) {
820                 if (d->nrdnlen >= 0) {
821                         rc = LDAP_OTHER;
822                 } else {
823                         db_recno_t dkids;
824                         *idp = d->entryID;
825                         ei->bei_nrdn.bv_len = 0 - d->nrdnlen;
826                         ber_str2bv( d->nrdn, ei->bei_nrdn.bv_len, 1, &ei->bei_nrdn );
827                         ei->bei_rdn.bv_len = data.size - sizeof(diskNode) -
828                                 ei->bei_nrdn.bv_len;
829                         ptr = d->nrdn + ei->bei_nrdn.bv_len + 1;
830                         ber_str2bv( ptr, ei->bei_rdn.bv_len, 1, &ei->bei_rdn );
831                         /* How many children does this node have? */
832                         cursor->c_count( cursor, &dkids, 0 );
833                         ei->bei_dkids = dkids;
834                 }
835         }
836         cursor->c_close( cursor );
837         op->o_tmpfree( d, op->o_tmpmemctx );
838         return rc;
839 }
840
841 int
842 hdb_dn2id_children(
843         Operation *op,
844         DB_TXN *txn,
845         Entry *e )
846 {
847         struct bdb_info *bdb = (struct bdb_info *) op->o_bd->be_private;
848         DB *db = bdb->bi_dn2id->bdi_db;
849         DBT             key, data;
850         DBC             *cursor;
851         int             rc;
852         ID              id;
853         diskNode d;
854
855         DBTzero(&key);
856         key.size = sizeof(ID);
857         key.data = &e->e_id;
858         key.flags = DB_DBT_USERMEM;
859
860         if ( bdb->bi_idl_cache_size ) {
861                 rc = bdb_idl_cache_get( bdb, db, &key, NULL );
862                 if ( rc != LDAP_NO_SUCH_OBJECT ) {
863                         return rc;
864                 }
865         }
866         DBTzero(&data);
867         data.data = &d;
868         data.ulen = sizeof(d);
869         data.flags = DB_DBT_USERMEM | DB_DBT_PARTIAL;
870         data.dlen = sizeof(d);
871
872         rc = db->cursor( db, txn, &cursor, bdb->bi_db_opflags );
873         if ( rc ) return rc;
874
875         rc = cursor->c_get( cursor, &key, &data, DB_SET );
876         if ( rc == 0 ) {
877                 db_recno_t dkids;
878                 rc = cursor->c_count( cursor, &dkids, 0 );
879                 if ( rc == 0 ) {
880                         BEI(e)->bei_dkids = dkids;
881                         if ( dkids < 2 ) rc = DB_NOTFOUND;
882                 }
883         }
884         cursor->c_close( cursor );
885         return rc;
886 }
887
888 /* bdb_dn2idl:
889  * We can't just use bdb_idl_fetch_key because
890  * 1 - our data items are longer than just an entry ID
891  * 2 - our data items are sorted alphabetically by nrdn, not by ID.
892  *
893  * We descend the tree recursively, so we define this cookie
894  * to hold our necessary state information. The bdb_dn2idl_internal
895  * function uses this cookie when calling itself.
896  */
897
898 struct dn2id_cookie {
899         struct bdb_info *bdb;
900         DB *db;
901         int prefix;
902         int rc;
903         EntryInfo *ei;
904         ID id;
905         ID dbuf;
906         ID *ids;
907         void *ptr;
908         ID tmp[BDB_IDL_DB_SIZE];
909         ID *buf;
910         DBT key;
911         DBT data;
912         DBC *dbc;
913         Operation *op;
914 };
915
916 static int
917 apply_func(
918         void *data,
919         void *arg )
920 {
921         EntryInfo *ei = data;
922         ID *idl = arg;
923
924         bdb_idl_insert( idl, ei->bei_id );
925         return 0;
926 }
927
928 static int
929 hdb_dn2idl_internal(
930         struct dn2id_cookie *cx
931 )
932 {
933         BDB_IDL_ZERO( cx->tmp );
934
935         if ( !cx->ei ) {
936                 cx->ei = bdb_cache_find_info( cx->bdb, cx->id );
937                 if ( !cx->ei ) {
938                         cx->rc = DB_NOTFOUND;
939                         goto saveit;
940                 }
941         }
942
943         if ( cx->bdb->bi_idl_cache_size ) {
944                 cx->rc = bdb_idl_cache_get(cx->bdb, cx->db, &cx->key, cx->tmp);
945                 if ( cx->rc == DB_NOTFOUND ) {
946                         return cx->rc;
947                 }
948                 if ( cx->rc == LDAP_SUCCESS ) {
949                         goto gotit;
950                 }
951         }
952
953         bdb_cache_entryinfo_lock( cx->ei );
954
955         /* If number of kids in the cache differs from on-disk, load
956          * up all the kids from the database
957          */
958         if ( cx->ei->bei_ckids+1 != cx->ei->bei_dkids ) {
959                 EntryInfo ei;
960                 db_recno_t dkids = cx->ei->bei_dkids;
961                 ei.bei_parent = cx->ei;
962
963                 bdb_cache_entryinfo_unlock( cx->ei );
964
965                 cx->rc = cx->db->cursor( cx->db, NULL, &cx->dbc,
966                         cx->bdb->bi_db_opflags );
967                 if ( cx->rc ) return cx->rc;
968
969                 cx->data.data = &cx->dbuf;
970                 cx->data.ulen = sizeof(ID);
971                 cx->data.dlen = sizeof(ID);
972                 cx->data.flags = DB_DBT_USERMEM | DB_DBT_PARTIAL;
973
974                 /* The first item holds the parent ID. Ignore it. */
975                 cx->rc = cx->dbc->c_get( cx->dbc, &cx->key, &cx->data, DB_SET );
976                 if ( cx->rc ) {
977                         cx->dbc->c_close( cx->dbc );
978                         if ( cx->rc == DB_NOTFOUND ) goto saveit;
979                         return cx->rc;
980                 }
981
982                 /* If the on-disk count is zero we've never checked it.
983                  * Count it now.
984                  */
985                 if ( !dkids ) {
986                         cx->dbc->c_count( cx->dbc, &dkids, 0 );
987                         cx->ei->bei_dkids = dkids;
988                 }
989
990                 cx->data.data = cx->buf;
991                 cx->data.ulen = BDB_IDL_UM_SIZE * sizeof(ID);
992                 cx->data.flags = DB_DBT_USERMEM;
993
994                 /* Fetch the rest of the IDs in a loop... */
995                 while ( (cx->rc = cx->dbc->c_get( cx->dbc, &cx->key, &cx->data,
996                         DB_MULTIPLE | DB_NEXT_DUP )) == 0 ) {
997                         u_int8_t *j;
998                         size_t len;
999                         DB_MULTIPLE_INIT( cx->ptr, &cx->data );
1000                         while (cx->ptr) {
1001                                 DB_MULTIPLE_NEXT( cx->ptr, &cx->data, j, len );
1002                                 if (j) {
1003                                         EntryInfo *ei2;
1004                                         diskNode *d = (diskNode *)j;
1005                                         short nrlen;
1006
1007                                         AC_MEMCPY( &ei.bei_id, &d->entryID, sizeof(ID) );
1008                                         AC_MEMCPY( &nrlen, &d->nrdnlen, sizeof(d->nrdnlen) );
1009                                         ei.bei_nrdn.bv_len = nrlen;
1010                                         /* nrdn/rdn are set in-place.
1011                                          * hdb_cache_load will copy them as needed
1012                                          */
1013                                         ei.bei_nrdn.bv_val = d->nrdn;
1014                                         ei.bei_rdn.bv_len = len - sizeof(diskNode) - ei.bei_nrdn.bv_len;
1015                                         ei.bei_rdn.bv_val = d->nrdn + ei.bei_nrdn.bv_len + 1;
1016                                         bdb_idl_insert( cx->tmp, ei.bei_id );
1017                                         hdb_cache_load( cx->bdb, &ei, &ei2 );
1018                                 }
1019                         }
1020                 }
1021                 cx->rc = cx->dbc->c_close( cx->dbc );
1022         } else {
1023                 /* The in-memory cache is in sync with the on-disk data.
1024                  * do we have any kids?
1025                  */
1026                 cx->rc = 0;
1027                 if ( cx->ei->bei_ckids > 0 ) {
1028
1029                         /* Walk the kids tree; order is irrelevant since bdb_idl_insert
1030                          * will insert in sorted order.
1031                          */
1032                         avl_apply( cx->ei->bei_kids, apply_func, cx->tmp, -1, AVL_POSTORDER );
1033                 }
1034                 bdb_cache_entryinfo_unlock( cx->ei );
1035         }
1036
1037 saveit:
1038         if ( cx->bdb->bi_idl_cache_max_size ) {
1039                 bdb_idl_cache_put( cx->bdb, cx->db, &cx->key, cx->tmp, cx->rc );
1040         }
1041         ;
1042 gotit:
1043         if ( !BDB_IDL_IS_ZERO( cx->tmp )) {
1044                 if ( cx->prefix == DN_SUBTREE_PREFIX ) {
1045                         if (cx->ei->bei_state & CACHE_ENTRY_NO_GRANDKIDS) {
1046                                 bdb_idl_union( cx->ids, cx->tmp );
1047                         } else {
1048                                 ID *save, idcurs;
1049                                 EntryInfo *ei = cx->ei;
1050                                 int nokids = 1;
1051                                 save = cx->op->o_tmpalloc( BDB_IDL_SIZEOF( cx->tmp ),
1052                                         cx->op->o_tmpmemctx );
1053                                 BDB_IDL_CPY( save, cx->tmp );
1054                                 bdb_idl_union( cx->ids, cx->tmp );
1055
1056                                 idcurs = 0;
1057                                 for ( cx->id = bdb_idl_first( save, &idcurs );
1058                                         cx->id != NOID;
1059                                         cx->id = bdb_idl_next( save, &idcurs )) {
1060                                         cx->ei = NULL;
1061                                         hdb_dn2idl_internal( cx );
1062                                         if ( !BDB_IDL_IS_ZERO( cx->tmp ))
1063                                                 nokids = 0;
1064                                 }
1065                                 cx->op->o_tmpfree( save, cx->op->o_tmpmemctx );
1066                                 if ( nokids ) ei->bei_state |= CACHE_ENTRY_NO_GRANDKIDS;
1067                         }
1068                         /* Make sure caller knows it had kids! */
1069                         cx->tmp[0]=1;
1070
1071                         cx->rc = 0;
1072                 } else {
1073                         BDB_IDL_CPY( cx->ids, cx->tmp );
1074                 }
1075         }
1076         return cx->rc;
1077 }
1078
1079 int
1080 hdb_dn2idl(
1081         Operation       *op,
1082         Entry           *e,
1083         ID *ids,
1084         ID *stack )
1085 {
1086         struct bdb_info *bdb = (struct bdb_info *)op->o_bd->be_private;
1087         struct dn2id_cookie cx;
1088
1089 #ifdef NEW_LOGGING
1090         LDAP_LOG ( INDEX, ARGS, 
1091                 "=> hdb_dn2ididl( \"%s\" )\n", e->e_nname.bv_val, 0, 0 );
1092 #else
1093         Debug( LDAP_DEBUG_TRACE, "=> hdb_dn2idl( \"%s\" )\n", e->e_nname.bv_val, 0, 0 );
1094 #endif
1095
1096 #ifndef BDB_MULTIPLE_SUFFIXES
1097         if ( op->ors_scope != LDAP_SCOPE_ONELEVEL && 
1098                 BEI(e)->bei_parent->bei_id == 0 )
1099         {
1100                 BDB_IDL_ALL( bdb, ids );
1101                 return 0;
1102         }
1103 #endif
1104
1105         cx.id = e->e_id;
1106         cx.ei = e->e_id ? BEI(e) : &bdb->bi_cache.c_dntree;
1107         cx.bdb = bdb;
1108         cx.db = cx.bdb->bi_dn2id->bdi_db;
1109         cx.prefix = op->ors_scope == LDAP_SCOPE_ONELEVEL
1110                 ? DN_ONE_PREFIX : DN_SUBTREE_PREFIX;
1111         cx.ids = ids;
1112         cx.buf = stack;
1113         cx.op = op;
1114
1115         BDB_IDL_ZERO( ids );
1116         if ( cx.prefix == DN_SUBTREE_PREFIX ) {
1117                 bdb_idl_insert( ids, cx.id );
1118         }
1119
1120         DBTzero(&cx.key);
1121         cx.key.data = &cx.id;
1122         cx.key.ulen = sizeof(ID);
1123         cx.key.size = sizeof(ID);
1124         cx.key.flags = DB_DBT_USERMEM;
1125
1126         DBTzero(&cx.data);
1127
1128         return hdb_dn2idl_internal(&cx);
1129 }
1130 #endif  /* BDB_HIER */