1 /* $NetBSD: attr.c,v 1.3 2021/08/14 16:15:00 christos Exp $ */
2
3 /* attr.c - backend routines for dealing with attributes */
4 /* $OpenLDAP$ */
5 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
6 *
7 * Copyright 2000-2021 The OpenLDAP Foundation.
8 * All rights reserved.
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted only as authorized by the OpenLDAP
12 * Public License.
13 *
14 * A copy of this license is available in the file LICENSE in the
15 * top-level directory of the distribution or, alternatively, at
16 * <http://www.OpenLDAP.org/license.html>.
17 */
18
19 #include <sys/cdefs.h>
20 __RCSID("$NetBSD: attr.c,v 1.3 2021/08/14 16:15:00 christos Exp $");
21
22 #include "portable.h"
23
24 #include <stdio.h>
25
26 #include <ac/socket.h>
27 #include <ac/string.h>
28
29 #include "slap.h"
30 #include "back-mdb.h"
31 #include "slap-config.h"
32 #include "lutil.h"
33
34 /* Find the ad, return -1 if not found,
35 * set point for insertion if ins is non-NULL
36 */
37 int
mdb_attr_slot(struct mdb_info * mdb,AttributeDescription * ad,int * ins)38 mdb_attr_slot( struct mdb_info *mdb, AttributeDescription *ad, int *ins )
39 {
40 unsigned base = 0, cursor = 0;
41 unsigned n = mdb->mi_nattrs;
42 int val = 0;
43
44 while ( 0 < n ) {
45 unsigned pivot = n >> 1;
46 cursor = base + pivot;
47
48 val = SLAP_PTRCMP( ad, mdb->mi_attrs[cursor]->ai_desc );
49 if ( val < 0 ) {
50 n = pivot;
51 } else if ( val > 0 ) {
52 base = cursor + 1;
53 n -= pivot + 1;
54 } else {
55 return cursor;
56 }
57 }
58 if ( ins ) {
59 if ( val > 0 )
60 ++cursor;
61 *ins = cursor;
62 }
63 return -1;
64 }
65
66 static int
ainfo_insert(struct mdb_info * mdb,AttrInfo * a)67 ainfo_insert( struct mdb_info *mdb, AttrInfo *a )
68 {
69 int x;
70 int i = mdb_attr_slot( mdb, a->ai_desc, &x );
71
72 /* Is it a dup? */
73 if ( i >= 0 )
74 return -1;
75
76 mdb->mi_attrs = ch_realloc( mdb->mi_attrs, ( mdb->mi_nattrs+1 ) *
77 sizeof( AttrInfo * ));
78 if ( x < mdb->mi_nattrs )
79 AC_MEMCPY( &mdb->mi_attrs[x+1], &mdb->mi_attrs[x],
80 ( mdb->mi_nattrs - x ) * sizeof( AttrInfo *));
81 mdb->mi_attrs[x] = a;
82 mdb->mi_nattrs++;
83 return 0;
84 }
85
86 AttrInfo *
mdb_attr_mask(struct mdb_info * mdb,AttributeDescription * desc)87 mdb_attr_mask(
88 struct mdb_info *mdb,
89 AttributeDescription *desc )
90 {
91 int i = mdb_attr_slot( mdb, desc, NULL );
92 return i < 0 ? NULL : mdb->mi_attrs[i];
93 }
94
95 /* Open all un-opened index DB handles */
96 int
mdb_attr_dbs_open(BackendDB * be,MDB_txn * tx0,ConfigReply * cr)97 mdb_attr_dbs_open(
98 BackendDB *be, MDB_txn *tx0, ConfigReply *cr )
99 {
100 struct mdb_info *mdb = (struct mdb_info *) be->be_private;
101 MDB_txn *txn;
102 MDB_dbi *dbis = NULL;
103 int i, flags;
104 int rc;
105
106 txn = tx0;
107 if ( txn == NULL ) {
108 rc = mdb_txn_begin( mdb->mi_dbenv, NULL, 0, &txn );
109 if ( rc ) {
110 snprintf( cr->msg, sizeof(cr->msg), "database \"%s\": "
111 "txn_begin failed: %s (%d).",
112 be->be_suffix[0].bv_val, mdb_strerror(rc), rc );
113 Debug( LDAP_DEBUG_ANY,
114 LDAP_XSTRING(mdb_attr_dbs) ": %s\n",
115 cr->msg );
116 return rc;
117 }
118 dbis = ch_calloc( 1, mdb->mi_nattrs * sizeof(MDB_dbi) );
119 } else {
120 rc = 0;
121 }
122
123 flags = MDB_DUPSORT|MDB_DUPFIXED|MDB_INTEGERDUP;
124 if ( !(slapMode & SLAP_TOOL_READONLY) )
125 flags |= MDB_CREATE;
126
127 for ( i=0; i<mdb->mi_nattrs; i++ ) {
128 if ( mdb->mi_attrs[i]->ai_dbi ) /* already open */
129 continue;
130 if ( !( mdb->mi_attrs[i]->ai_indexmask || mdb->mi_attrs[i]->ai_newmask )) /* not an index record */
131 continue;
132 rc = mdb_dbi_open( txn, mdb->mi_attrs[i]->ai_desc->ad_type->sat_cname.bv_val,
133 flags, &mdb->mi_attrs[i]->ai_dbi );
134 if ( rc ) {
135 snprintf( cr->msg, sizeof(cr->msg), "database \"%s\": "
136 "mdb_dbi_open(%s) failed: %s (%d).",
137 be->be_suffix[0].bv_val,
138 mdb->mi_attrs[i]->ai_desc->ad_type->sat_cname.bv_val,
139 mdb_strerror(rc), rc );
140 Debug( LDAP_DEBUG_ANY,
141 LDAP_XSTRING(mdb_attr_dbs) ": %s\n",
142 cr->msg );
143 break;
144 }
145 /* Remember newly opened DBI handles */
146 if ( dbis )
147 dbis[i] = mdb->mi_attrs[i]->ai_dbi;
148 }
149
150 /* Only commit if this is our txn */
151 if ( tx0 == NULL ) {
152 if ( !rc ) {
153 rc = mdb_txn_commit( txn );
154 if ( rc ) {
155 snprintf( cr->msg, sizeof(cr->msg), "database \"%s\": "
156 "txn_commit failed: %s (%d).",
157 be->be_suffix[0].bv_val, mdb_strerror(rc), rc );
158 Debug( LDAP_DEBUG_ANY,
159 LDAP_XSTRING(mdb_attr_dbs) ": %s\n",
160 cr->msg );
161 }
162 } else {
163 mdb_txn_abort( txn );
164 }
165 /* Something failed, forget anything we just opened */
166 if ( rc ) {
167 for ( i=0; i<mdb->mi_nattrs; i++ ) {
168 if ( dbis[i] ) {
169 mdb->mi_attrs[i]->ai_dbi = 0;
170 mdb->mi_attrs[i]->ai_indexmask |= MDB_INDEX_DELETING;
171 }
172 }
173 mdb_attr_flush( mdb );
174 }
175 ch_free( dbis );
176 }
177
178 return rc;
179 }
180
181 void
mdb_attr_dbs_close(struct mdb_info * mdb)182 mdb_attr_dbs_close(
183 struct mdb_info *mdb
184 )
185 {
186 int i;
187 for ( i=0; i<mdb->mi_nattrs; i++ )
188 if ( mdb->mi_attrs[i]->ai_dbi ) {
189 mdb_dbi_close( mdb->mi_dbenv, mdb->mi_attrs[i]->ai_dbi );
190 mdb->mi_attrs[i]->ai_dbi = 0;
191 }
192 }
193
194 int
mdb_attr_index_config(struct mdb_info * mdb,const char * fname,int lineno,int argc,char ** argv,struct config_reply_s * c_reply)195 mdb_attr_index_config(
196 struct mdb_info *mdb,
197 const char *fname,
198 int lineno,
199 int argc,
200 char **argv,
201 struct config_reply_s *c_reply)
202 {
203 int rc = 0;
204 int i;
205 slap_mask_t mask;
206 char **attrs;
207 char **indexes = NULL;
208
209 attrs = ldap_str2charray( argv[0], "," );
210
211 if( attrs == NULL ) {
212 fprintf( stderr, "%s: line %d: "
213 "no attributes specified: %s\n",
214 fname, lineno, argv[0] );
215 return LDAP_PARAM_ERROR;
216 }
217
218 if ( argc > 1 ) {
219 indexes = ldap_str2charray( argv[1], "," );
220
221 if( indexes == NULL ) {
222 fprintf( stderr, "%s: line %d: "
223 "no indexes specified: %s\n",
224 fname, lineno, argv[1] );
225 rc = LDAP_PARAM_ERROR;
226 goto done;
227 }
228 }
229
230 if( indexes == NULL ) {
231 mask = mdb->mi_defaultmask;
232
233 } else {
234 mask = 0;
235
236 for ( i = 0; indexes[i] != NULL; i++ ) {
237 slap_mask_t index;
238 rc = slap_str2index( indexes[i], &index );
239
240 if( rc != LDAP_SUCCESS ) {
241 if ( c_reply )
242 {
243 snprintf(c_reply->msg, sizeof(c_reply->msg),
244 "index type \"%s\" undefined", indexes[i] );
245
246 fprintf( stderr, "%s: line %d: %s\n",
247 fname, lineno, c_reply->msg );
248 }
249 rc = LDAP_PARAM_ERROR;
250 goto done;
251 }
252
253 mask |= index;
254 }
255 }
256
257 if( !mask ) {
258 if ( c_reply )
259 {
260 snprintf(c_reply->msg, sizeof(c_reply->msg),
261 "no indexes selected" );
262 fprintf( stderr, "%s: line %d: %s\n",
263 fname, lineno, c_reply->msg );
264 }
265 rc = LDAP_PARAM_ERROR;
266 goto done;
267 }
268
269 for ( i = 0; attrs[i] != NULL; i++ ) {
270 AttrInfo *a;
271 AttributeDescription *ad;
272 const char *text;
273 #ifdef LDAP_COMP_MATCH
274 ComponentReference* cr = NULL;
275 AttrInfo *a_cr = NULL;
276 #endif
277
278 if( strcasecmp( attrs[i], "default" ) == 0 ) {
279 mdb->mi_defaultmask |= mask;
280 continue;
281 }
282
283 #ifdef LDAP_COMP_MATCH
284 if ( is_component_reference( attrs[i] ) ) {
285 rc = extract_component_reference( attrs[i], &cr );
286 if ( rc != LDAP_SUCCESS ) {
287 if ( c_reply )
288 {
289 snprintf(c_reply->msg, sizeof(c_reply->msg),
290 "index component reference\"%s\" undefined",
291 attrs[i] );
292 fprintf( stderr, "%s: line %d: %s\n",
293 fname, lineno, c_reply->msg );
294 }
295 goto done;
296 }
297 cr->cr_indexmask = mask;
298 /*
299 * After extracting a component reference
300 * only the name of a attribute will be remaining
301 */
302 } else {
303 cr = NULL;
304 }
305 #endif
306 ad = NULL;
307 rc = slap_str2ad( attrs[i], &ad, &text );
308
309 if( rc != LDAP_SUCCESS ) {
310 if ( c_reply )
311 {
312 snprintf(c_reply->msg, sizeof(c_reply->msg),
313 "index attribute \"%s\" undefined",
314 attrs[i] );
315
316 fprintf( stderr, "%s: line %d: %s\n",
317 fname, lineno, c_reply->msg );
318 }
319 fail:
320 #ifdef LDAP_COMP_MATCH
321 ch_free( cr );
322 #endif
323 goto done;
324 }
325
326 if( ad == slap_schema.si_ad_entryDN || slap_ad_is_binary( ad ) ) {
327 if (c_reply) {
328 snprintf(c_reply->msg, sizeof(c_reply->msg),
329 "index of attribute \"%s\" disallowed", attrs[i] );
330 fprintf( stderr, "%s: line %d: %s\n",
331 fname, lineno, c_reply->msg );
332 }
333 rc = LDAP_UNWILLING_TO_PERFORM;
334 goto fail;
335 }
336
337 if( IS_SLAP_INDEX( mask, SLAP_INDEX_APPROX ) && !(
338 ad->ad_type->sat_approx
339 && ad->ad_type->sat_approx->smr_indexer
340 && ad->ad_type->sat_approx->smr_filter ) )
341 {
342 if (c_reply) {
343 snprintf(c_reply->msg, sizeof(c_reply->msg),
344 "approx index of attribute \"%s\" disallowed", attrs[i] );
345 fprintf( stderr, "%s: line %d: %s\n",
346 fname, lineno, c_reply->msg );
347 }
348 rc = LDAP_INAPPROPRIATE_MATCHING;
349 goto fail;
350 }
351
352 if( IS_SLAP_INDEX( mask, SLAP_INDEX_EQUALITY ) && !(
353 ad->ad_type->sat_equality
354 && ad->ad_type->sat_equality->smr_indexer
355 && ad->ad_type->sat_equality->smr_filter ) )
356 {
357 if (c_reply) {
358 snprintf(c_reply->msg, sizeof(c_reply->msg),
359 "equality index of attribute \"%s\" disallowed", attrs[i] );
360 fprintf( stderr, "%s: line %d: %s\n",
361 fname, lineno, c_reply->msg );
362 }
363 rc = LDAP_INAPPROPRIATE_MATCHING;
364 goto fail;
365 }
366
367 if( IS_SLAP_INDEX( mask, SLAP_INDEX_SUBSTR ) && !(
368 ad->ad_type->sat_substr
369 && ad->ad_type->sat_substr->smr_indexer
370 && ad->ad_type->sat_substr->smr_filter ) )
371 {
372 if (c_reply) {
373 snprintf(c_reply->msg, sizeof(c_reply->msg),
374 "substr index of attribute \"%s\" disallowed", attrs[i] );
375 fprintf( stderr, "%s: line %d: %s\n",
376 fname, lineno, c_reply->msg );
377 }
378 rc = LDAP_INAPPROPRIATE_MATCHING;
379 goto fail;
380 }
381
382 Debug( LDAP_DEBUG_CONFIG, "index %s 0x%04lx\n",
383 ad->ad_cname.bv_val, mask );
384
385 a = (AttrInfo *) ch_malloc( sizeof(AttrInfo) );
386
387 #ifdef LDAP_COMP_MATCH
388 a->ai_cr = NULL;
389 #endif
390 a->ai_cursor = NULL;
391 a->ai_root = NULL;
392 a->ai_desc = ad;
393 a->ai_dbi = 0;
394 a->ai_multi_hi = UINT_MAX;
395 a->ai_multi_lo = UINT_MAX;
396
397 if ( mdb->mi_flags & MDB_IS_OPEN ) {
398 a->ai_indexmask = 0;
399 a->ai_newmask = mask;
400 } else {
401 a->ai_indexmask = mask;
402 a->ai_newmask = 0;
403 }
404
405 #ifdef LDAP_COMP_MATCH
406 if ( cr ) {
407 a_cr = mdb_attr_mask( mdb, ad );
408 if ( a_cr ) {
409 /*
410 * AttrInfo is already in AVL
411 * just add the extracted component reference
412 * in the AttrInfo
413 */
414 ch_free( a );
415 rc = insert_component_reference( cr, &a_cr->ai_cr );
416 if ( rc != LDAP_SUCCESS) {
417 fprintf( stderr, " error during inserting component reference in %s ", attrs[i]);
418 rc = LDAP_PARAM_ERROR;
419 goto fail;
420 }
421 continue;
422 } else {
423 rc = insert_component_reference( cr, &a->ai_cr );
424 if ( rc != LDAP_SUCCESS) {
425 fprintf( stderr, " error during inserting component reference in %s ", attrs[i]);
426 rc = LDAP_PARAM_ERROR;
427 ch_free( a );
428 goto fail;
429 }
430 }
431 }
432 #endif
433 rc = ainfo_insert( mdb, a );
434 if( rc ) {
435 AttrInfo *b = mdb_attr_mask( mdb, ad );
436 /* If this is just a multival record, reuse it for index info */
437 if ( !( b->ai_indexmask || b->ai_newmask ) && b->ai_multi_lo < UINT_MAX ) {
438 b->ai_indexmask = a->ai_indexmask;
439 b->ai_newmask = a->ai_newmask;
440 ch_free( a );
441 rc = 0;
442 continue;
443 }
444 if ( mdb->mi_flags & MDB_IS_OPEN ) {
445 /* If there is already an index defined for this attribute
446 * it must be replaced. Otherwise we end up with multiple
447 * olcIndex values for the same attribute */
448 if ( b->ai_indexmask & MDB_INDEX_DELETING ) {
449 /* If we were editing this attr, reset it */
450 b->ai_indexmask &= ~MDB_INDEX_DELETING;
451 /* If this is leftover from a previous add, commit it */
452 if ( b->ai_newmask )
453 b->ai_indexmask = b->ai_newmask;
454 b->ai_newmask = a->ai_newmask;
455 ch_free( a );
456 rc = 0;
457 continue;
458 }
459 }
460 if (c_reply) {
461 snprintf(c_reply->msg, sizeof(c_reply->msg),
462 "duplicate index definition for attr \"%s\"",
463 attrs[i] );
464 fprintf( stderr, "%s: line %d: %s\n",
465 fname, lineno, c_reply->msg );
466 }
467
468 rc = LDAP_PARAM_ERROR;
469 goto done;
470 }
471 }
472
473 done:
474 ldap_charray_free( attrs );
475 if ( indexes != NULL ) ldap_charray_free( indexes );
476
477 return rc;
478 }
479
480 static int
mdb_attr_index_unparser(void * v1,void * v2)481 mdb_attr_index_unparser( void *v1, void *v2 )
482 {
483 AttrInfo *ai = v1;
484 BerVarray *bva = v2;
485 struct berval bv;
486 char *ptr;
487
488 slap_index2bvlen( ai->ai_indexmask, &bv );
489 if ( bv.bv_len ) {
490 bv.bv_len += ai->ai_desc->ad_cname.bv_len + 1;
491 ptr = ch_malloc( bv.bv_len+1 );
492 bv.bv_val = lutil_strcopy( ptr, ai->ai_desc->ad_cname.bv_val );
493 *bv.bv_val++ = ' ';
494 slap_index2bv( ai->ai_indexmask, &bv );
495 bv.bv_val = ptr;
496 ber_bvarray_add( bva, &bv );
497 }
498 return 0;
499 }
500
501 static AttributeDescription addef = { NULL, NULL, BER_BVC("default") };
502 static AttrInfo aidef = { &addef };
503
504 void
mdb_attr_index_unparse(struct mdb_info * mdb,BerVarray * bva)505 mdb_attr_index_unparse( struct mdb_info *mdb, BerVarray *bva )
506 {
507 int i;
508
509 if ( mdb->mi_defaultmask ) {
510 aidef.ai_indexmask = mdb->mi_defaultmask;
511 mdb_attr_index_unparser( &aidef, bva );
512 }
513 for ( i=0; i<mdb->mi_nattrs; i++ )
514 if ( mdb->mi_attrs[i]->ai_indexmask )
515 mdb_attr_index_unparser( mdb->mi_attrs[i], bva );
516 }
517
518 int
mdb_attr_multi_config(struct mdb_info * mdb,const char * fname,int lineno,int argc,char ** argv,struct config_reply_s * c_reply)519 mdb_attr_multi_config(
520 struct mdb_info *mdb,
521 const char *fname,
522 int lineno,
523 int argc,
524 char **argv,
525 struct config_reply_s *c_reply)
526 {
527 int rc = 0;
528 int i;
529 unsigned hi,lo;
530 char **attrs, *next, *s;
531
532 attrs = ldap_str2charray( argv[0], "," );
533
534 if( attrs == NULL ) {
535 fprintf( stderr, "%s: line %d: "
536 "no attributes specified: %s\n",
537 fname, lineno, argv[0] );
538 return LDAP_PARAM_ERROR;
539 }
540
541 hi = strtoul( argv[1], &next, 10 );
542 if ( next == argv[1] || next[0] != ',' )
543 goto badval;
544 s = next+1;
545 lo = strtoul( s, &next, 10 );
546 if ( next == s || next[0] != '\0' )
547 goto badval;
548
549 if ( lo > hi ) {
550 badval:
551 snprintf(c_reply->msg, sizeof(c_reply->msg),
552 "invalid hi/lo thresholds" );
553 fprintf( stderr, "%s: line %d: %s\n",
554 fname, lineno, c_reply->msg );
555 return LDAP_PARAM_ERROR;
556 }
557
558 for ( i = 0; attrs[i] != NULL; i++ ) {
559 AttrInfo *a;
560 AttributeDescription *ad;
561 const char *text;
562
563 if( strcasecmp( attrs[i], "default" ) == 0 ) {
564 mdb->mi_multi_hi = hi;
565 mdb->mi_multi_lo = lo;
566 continue;
567 }
568
569 ad = NULL;
570 rc = slap_str2ad( attrs[i], &ad, &text );
571
572 if( rc != LDAP_SUCCESS ) {
573 if ( c_reply )
574 {
575 snprintf(c_reply->msg, sizeof(c_reply->msg),
576 "multival attribute \"%s\" undefined",
577 attrs[i] );
578
579 fprintf( stderr, "%s: line %d: %s\n",
580 fname, lineno, c_reply->msg );
581 }
582 fail:
583 goto done;
584 }
585
586 a = (AttrInfo *) ch_calloc( 1, sizeof(AttrInfo) );
587
588 a->ai_desc = ad;
589 a->ai_multi_hi = hi;
590 a->ai_multi_lo = lo;
591
592 rc = ainfo_insert( mdb, a );
593 if( rc ) {
594 AttrInfo *b = mdb_attr_mask( mdb, ad );
595 /* If this is just an index record, reuse it for multival info */
596 if ( b->ai_multi_lo == UINT_MAX ) {
597 b->ai_multi_hi = a->ai_multi_hi;
598 b->ai_multi_lo = a->ai_multi_lo;
599 ch_free( a );
600 rc = 0;
601 continue;
602 }
603 if (c_reply) {
604 snprintf(c_reply->msg, sizeof(c_reply->msg),
605 "duplicate multival definition for attr \"%s\"",
606 attrs[i] );
607 fprintf( stderr, "%s: line %d: %s\n",
608 fname, lineno, c_reply->msg );
609 }
610
611 rc = LDAP_PARAM_ERROR;
612 goto done;
613 }
614 }
615
616 done:
617 ldap_charray_free( attrs );
618
619 return rc;
620 }
621
622 static int
mdb_attr_multi_unparser(void * v1,void * v2)623 mdb_attr_multi_unparser( void *v1, void *v2 )
624 {
625 AttrInfo *ai = v1;
626 BerVarray *bva = v2;
627 struct berval bv;
628 char digbuf[sizeof("4294967296,4294967296")];
629 char *ptr;
630
631 bv.bv_len = snprintf( digbuf, sizeof(digbuf), "%u,%u",
632 ai->ai_multi_hi, ai->ai_multi_lo );
633 if ( bv.bv_len ) {
634 bv.bv_len += ai->ai_desc->ad_cname.bv_len + 1;
635 ptr = ch_malloc( bv.bv_len+1 );
636 bv.bv_val = lutil_strcopy( ptr, ai->ai_desc->ad_cname.bv_val );
637 *bv.bv_val++ = ' ';
638 strcpy(bv.bv_val, digbuf);
639 bv.bv_val = ptr;
640 ber_bvarray_add( bva, &bv );
641 }
642 return 0;
643 }
644
645 void
mdb_attr_multi_unparse(struct mdb_info * mdb,BerVarray * bva)646 mdb_attr_multi_unparse( struct mdb_info *mdb, BerVarray *bva )
647 {
648 int i;
649
650 if ( mdb->mi_multi_hi < UINT_MAX ) {
651 aidef.ai_multi_hi = mdb->mi_multi_hi;
652 aidef.ai_multi_lo = mdb->mi_multi_lo;
653 mdb_attr_multi_unparser( &aidef, bva );
654 }
655 for ( i=0; i<mdb->mi_nattrs; i++ )
656 if ( mdb->mi_attrs[i]->ai_multi_hi < UINT_MAX )
657 mdb_attr_multi_unparser( mdb->mi_attrs[i], bva );
658 }
659
660 void
mdb_attr_multi_thresh(struct mdb_info * mdb,AttributeDescription * ad,unsigned * hi,unsigned * lo)661 mdb_attr_multi_thresh( struct mdb_info *mdb, AttributeDescription *ad, unsigned *hi, unsigned *lo )
662 {
663 AttrInfo *ai = mdb_attr_mask( mdb, ad );
664 if ( ai && ai->ai_multi_hi < UINT_MAX )
665 {
666 if ( hi )
667 *hi = ai->ai_multi_hi;
668 if ( lo )
669 *lo = ai->ai_multi_lo;
670 } else
671 {
672 if ( hi )
673 *hi = mdb->mi_multi_hi;
674 if ( lo )
675 *lo = mdb->mi_multi_lo;
676 }
677 }
678
679 void
mdb_attr_info_free(AttrInfo * ai)680 mdb_attr_info_free( AttrInfo *ai )
681 {
682 #ifdef LDAP_COMP_MATCH
683 free( ai->ai_cr );
684 #endif
685 free( ai );
686 }
687
688 void
mdb_attr_index_destroy(struct mdb_info * mdb)689 mdb_attr_index_destroy( struct mdb_info *mdb )
690 {
691 int i;
692
693 for ( i=0; i<mdb->mi_nattrs; i++ )
694 mdb_attr_info_free( mdb->mi_attrs[i] );
695
696 free( mdb->mi_attrs );
697 }
698
mdb_attr_index_free(struct mdb_info * mdb,AttributeDescription * ad)699 void mdb_attr_index_free( struct mdb_info *mdb, AttributeDescription *ad )
700 {
701 int i;
702
703 i = mdb_attr_slot( mdb, ad, NULL );
704 if ( i >= 0 ) {
705 mdb_attr_info_free( mdb->mi_attrs[i] );
706 mdb->mi_nattrs--;
707 for (; i<mdb->mi_nattrs; i++)
708 mdb->mi_attrs[i] = mdb->mi_attrs[i+1];
709 }
710 }
711
mdb_attr_flush(struct mdb_info * mdb)712 void mdb_attr_flush( struct mdb_info *mdb )
713 {
714 int i;
715
716 for ( i=0; i<mdb->mi_nattrs; i++ ) {
717 if ( mdb->mi_attrs[i]->ai_indexmask & MDB_INDEX_DELETING ) {
718 /* if this is also a multival rec, just clear index */
719 if ( mdb->mi_attrs[i]->ai_multi_lo < UINT_MAX ) {
720 mdb->mi_attrs[i]->ai_indexmask = 0;
721 mdb->mi_attrs[i]->ai_newmask = 0;
722 } else {
723 int j;
724 mdb_attr_info_free( mdb->mi_attrs[i] );
725 mdb->mi_nattrs--;
726 for (j=i; j<mdb->mi_nattrs; j++)
727 mdb->mi_attrs[j] = mdb->mi_attrs[j+1];
728 i--;
729 }
730 }
731 }
732 }
733
mdb_ad_read(struct mdb_info * mdb,MDB_txn * txn)734 int mdb_ad_read( struct mdb_info *mdb, MDB_txn *txn )
735 {
736 int i, rc;
737 MDB_cursor *mc;
738 MDB_val key, data;
739 struct berval bdata;
740 const char *text;
741 AttributeDescription *ad;
742
743 rc = mdb_cursor_open( txn, mdb->mi_ad2id, &mc );
744 if ( rc ) {
745 Debug( LDAP_DEBUG_ANY,
746 "mdb_ad_read: cursor_open failed %s(%d)\n",
747 mdb_strerror(rc), rc );
748 return rc;
749 }
750
751 /* our array is 1-based, an index of 0 means no data */
752 i = mdb->mi_numads+1;
753 key.mv_size = sizeof(int);
754 key.mv_data = &i;
755
756 rc = mdb_cursor_get( mc, &key, &data, MDB_SET );
757
758 while ( rc == MDB_SUCCESS ) {
759 bdata.bv_len = data.mv_size;
760 bdata.bv_val = data.mv_data;
761 ad = NULL;
762 rc = slap_bv2ad( &bdata, &ad, &text );
763 if ( rc ) {
764 rc = slap_bv2undef_ad( &bdata, &mdb->mi_ads[i], &text, 0 );
765 } else {
766 if ( ad->ad_index >= MDB_MAXADS ) {
767 Debug( LDAP_DEBUG_ANY,
768 "mdb_adb_read: too many AttributeDescriptions in use\n" );
769 return LDAP_OTHER;
770 }
771 mdb->mi_adxs[ad->ad_index] = i;
772 mdb->mi_ads[i] = ad;
773 }
774 i++;
775 rc = mdb_cursor_get( mc, &key, &data, MDB_NEXT );
776 }
777 mdb->mi_numads = i-1;
778
779 done:
780 if ( rc == MDB_NOTFOUND )
781 rc = 0;
782
783 mdb_cursor_close( mc );
784
785 return rc;
786 }
787
mdb_ad_get(struct mdb_info * mdb,MDB_txn * txn,AttributeDescription * ad)788 int mdb_ad_get( struct mdb_info *mdb, MDB_txn *txn, AttributeDescription *ad )
789 {
790 int i, rc;
791 MDB_val key, val;
792
793 rc = mdb_ad_read( mdb, txn );
794 if (rc)
795 return rc;
796
797 if ( mdb->mi_adxs[ad->ad_index] )
798 return 0;
799
800 i = mdb->mi_numads+1;
801 key.mv_size = sizeof(int);
802 key.mv_data = &i;
803 val.mv_size = ad->ad_cname.bv_len;
804 val.mv_data = ad->ad_cname.bv_val;
805
806 rc = mdb_put( txn, mdb->mi_ad2id, &key, &val, 0 );
807 if ( rc == MDB_SUCCESS ) {
808 mdb->mi_adxs[ad->ad_index] = i;
809 mdb->mi_ads[i] = ad;
810 mdb->mi_numads = i;
811 } else {
812 Debug( LDAP_DEBUG_ANY,
813 "mdb_ad_get: mdb_put failed %s(%d)\n",
814 mdb_strerror(rc), rc );
815 }
816
817 return rc;
818 }
819
mdb_ad_unwind(struct mdb_info * mdb,int prev_ads)820 void mdb_ad_unwind( struct mdb_info *mdb, int prev_ads )
821 {
822 int i;
823
824 for (i=mdb->mi_numads; i>prev_ads; i--) {
825 mdb->mi_adxs[mdb->mi_ads[i]->ad_index] = 0;
826 mdb->mi_ads[i] = NULL;
827 }
828 mdb->mi_numads = i;
829 }
830