1 /* $NetBSD: id2entry.c,v 1.2 2020/08/11 13:15:40 christos Exp $ */ 2 3 /* id2entry.c - routines to deal with the id2entry database */ 4 /* $OpenLDAP$ */ 5 /* This work is part of OpenLDAP Software <http://www.openldap.org/>. 6 * 7 * Copyright 2000-2020 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: id2entry.c,v 1.2 2020/08/11 13:15:40 christos Exp $"); 21 22 #include "portable.h" 23 24 #include <stdio.h> 25 #include <ac/string.h> 26 #include <ac/errno.h> 27 28 #include "back-mdb.h" 29 30 typedef struct Ecount { 31 ber_len_t len; 32 int nattrs; 33 int nvals; 34 int offset; 35 } Ecount; 36 37 static int mdb_entry_partsize(struct mdb_info *mdb, MDB_txn *txn, Entry *e, 38 Ecount *eh); 39 static int mdb_entry_encode(Operation *op, Entry *e, MDB_val *data, 40 Ecount *ec); 41 static Entry *mdb_entry_alloc( Operation *op, int nattrs, int nvals ); 42 43 #define ADD_FLAGS (MDB_NOOVERWRITE|MDB_APPEND) 44 45 static int mdb_id2entry_put( 46 Operation *op, 47 MDB_txn *txn, 48 MDB_cursor *mc, 49 Entry *e, 50 int flag ) 51 { 52 struct mdb_info *mdb = (struct mdb_info *) op->o_bd->be_private; 53 Ecount ec; 54 MDB_val key, data; 55 int rc, prev_ads = mdb->mi_numads; 56 57 /* We only store rdns, and they go in the dn2id database. */ 58 59 key.mv_data = &e->e_id; 60 key.mv_size = sizeof(ID); 61 62 rc = mdb_entry_partsize( mdb, txn, e, &ec ); 63 if (rc) { 64 rc = LDAP_OTHER; 65 goto fail; 66 } 67 68 flag |= MDB_RESERVE; 69 70 if (e->e_id < mdb->mi_nextid) 71 flag &= ~MDB_APPEND; 72 73 again: 74 data.mv_size = ec.len; 75 if ( mc ) 76 rc = mdb_cursor_put( mc, &key, &data, flag ); 77 else 78 rc = mdb_put( txn, mdb->mi_id2entry, &key, &data, flag ); 79 if (rc == MDB_SUCCESS) { 80 rc = mdb_entry_encode( op, e, &data, &ec ); 81 if( rc != LDAP_SUCCESS ) 82 goto fail; 83 } 84 if (rc) { 85 /* Was there a hole from slapadd? */ 86 if ( (flag & MDB_NOOVERWRITE) && data.mv_size == 0 ) { 87 flag &= ~ADD_FLAGS; 88 goto again; 89 } 90 Debug( LDAP_DEBUG_ANY, 91 "mdb_id2entry_put: mdb_put failed: %s(%d) \"%s\"\n", 92 mdb_strerror(rc), rc, 93 e->e_nname.bv_val ); 94 if ( rc != MDB_KEYEXIST ) 95 rc = LDAP_OTHER; 96 } 97 fail: 98 if (rc) { 99 mdb_ad_unwind( mdb, prev_ads ); 100 } 101 return rc; 102 } 103 104 /* 105 * This routine adds (or updates) an entry on disk. 106 * The cache should be already be updated. 107 */ 108 109 110 int mdb_id2entry_add( 111 Operation *op, 112 MDB_txn *txn, 113 MDB_cursor *mc, 114 Entry *e ) 115 { 116 return mdb_id2entry_put(op, txn, mc, e, ADD_FLAGS); 117 } 118 119 int mdb_id2entry_update( 120 Operation *op, 121 MDB_txn *txn, 122 MDB_cursor *mc, 123 Entry *e ) 124 { 125 return mdb_id2entry_put(op, txn, mc, e, 0); 126 } 127 128 int mdb_id2edata( 129 Operation *op, 130 MDB_cursor *mc, 131 ID id, 132 MDB_val *data ) 133 { 134 MDB_val key; 135 int rc; 136 137 key.mv_data = &id; 138 key.mv_size = sizeof(ID); 139 140 /* fetch it */ 141 rc = mdb_cursor_get( mc, &key, data, MDB_SET ); 142 /* stubs from missing parents - DB is actually invalid */ 143 if ( rc == MDB_SUCCESS && !data->mv_size ) 144 rc = MDB_NOTFOUND; 145 return rc; 146 } 147 148 int mdb_id2entry( 149 Operation *op, 150 MDB_cursor *mc, 151 ID id, 152 Entry **e ) 153 { 154 MDB_val key, data; 155 int rc = 0; 156 157 *e = NULL; 158 159 key.mv_data = &id; 160 key.mv_size = sizeof(ID); 161 162 /* fetch it */ 163 rc = mdb_cursor_get( mc, &key, &data, MDB_SET ); 164 if ( rc == MDB_NOTFOUND ) { 165 /* Looking for root entry on an empty-dn suffix? */ 166 if ( !id && BER_BVISEMPTY( &op->o_bd->be_nsuffix[0] )) { 167 struct berval gluebv = BER_BVC("glue"); 168 Entry *r = mdb_entry_alloc(op, 2, 4); 169 Attribute *a = r->e_attrs; 170 struct berval *bptr; 171 172 r->e_id = 0; 173 r->e_ocflags = SLAP_OC_GLUE|SLAP_OC__END; 174 bptr = a->a_vals; 175 a->a_flags = SLAP_ATTR_DONT_FREE_DATA | SLAP_ATTR_DONT_FREE_VALS; 176 a->a_desc = slap_schema.si_ad_objectClass; 177 a->a_nvals = a->a_vals; 178 a->a_numvals = 1; 179 *bptr++ = gluebv; 180 BER_BVZERO(bptr); 181 bptr++; 182 a->a_next = a+1; 183 a = a->a_next; 184 a->a_flags = SLAP_ATTR_DONT_FREE_DATA | SLAP_ATTR_DONT_FREE_VALS; 185 a->a_desc = slap_schema.si_ad_structuralObjectClass; 186 a->a_vals = bptr; 187 a->a_nvals = a->a_vals; 188 a->a_numvals = 1; 189 *bptr++ = gluebv; 190 BER_BVZERO(bptr); 191 a->a_next = NULL; 192 *e = r; 193 return MDB_SUCCESS; 194 } 195 } 196 /* stubs from missing parents - DB is actually invalid */ 197 if ( rc == MDB_SUCCESS && !data.mv_size ) 198 rc = MDB_NOTFOUND; 199 if ( rc ) return rc; 200 201 rc = mdb_entry_decode( op, mdb_cursor_txn( mc ), &data, e ); 202 if ( rc ) return rc; 203 204 (*e)->e_id = id; 205 (*e)->e_name.bv_val = NULL; 206 (*e)->e_nname.bv_val = NULL; 207 208 return rc; 209 } 210 211 int mdb_id2entry_delete( 212 BackendDB *be, 213 MDB_txn *tid, 214 Entry *e ) 215 { 216 struct mdb_info *mdb = (struct mdb_info *) be->be_private; 217 MDB_dbi dbi = mdb->mi_id2entry; 218 MDB_val key; 219 int rc; 220 221 key.mv_data = &e->e_id; 222 key.mv_size = sizeof(ID); 223 224 /* delete from database */ 225 rc = mdb_del( tid, dbi, &key, NULL ); 226 227 return rc; 228 } 229 230 static Entry * mdb_entry_alloc( 231 Operation *op, 232 int nattrs, 233 int nvals ) 234 { 235 Entry *e = op->o_tmpalloc( sizeof(Entry) + 236 nattrs * sizeof(Attribute) + 237 nvals * sizeof(struct berval), op->o_tmpmemctx ); 238 BER_BVZERO(&e->e_bv); 239 e->e_private = e; 240 if (nattrs) { 241 e->e_attrs = (Attribute *)(e+1); 242 e->e_attrs->a_vals = (struct berval *)(e->e_attrs+nattrs); 243 } else { 244 e->e_attrs = NULL; 245 } 246 247 return e; 248 } 249 250 int mdb_entry_return( 251 Operation *op, 252 Entry *e 253 ) 254 { 255 if ( !e ) 256 return 0; 257 if ( e->e_private ) { 258 if ( op->o_hdr ) { 259 op->o_tmpfree( e->e_nname.bv_val, op->o_tmpmemctx ); 260 op->o_tmpfree( e->e_name.bv_val, op->o_tmpmemctx ); 261 op->o_tmpfree( e, op->o_tmpmemctx ); 262 } else { 263 ch_free( e->e_nname.bv_val ); 264 ch_free( e->e_name.bv_val ); 265 ch_free( e ); 266 } 267 } else { 268 entry_free( e ); 269 } 270 return 0; 271 } 272 273 int mdb_entry_release( 274 Operation *op, 275 Entry *e, 276 int rw ) 277 { 278 struct mdb_info *mdb = (struct mdb_info *) op->o_bd->be_private; 279 struct mdb_op_info *moi = NULL; 280 281 /* slapMode : SLAP_SERVER_MODE, SLAP_TOOL_MODE, 282 SLAP_TRUNCATE_MODE, SLAP_UNDEFINED_MODE */ 283 284 int release = 1; 285 if ( slapMode & SLAP_SERVER_MODE ) { 286 OpExtra *oex; 287 LDAP_SLIST_FOREACH( oex, &op->o_extra, oe_next ) { 288 release = 0; 289 if ( oex->oe_key == mdb ) { 290 mdb_entry_return( op, e ); 291 moi = (mdb_op_info *)oex; 292 /* If it was setup by entry_get we should probably free it */ 293 if ( moi->moi_flag & MOI_FREEIT ) { 294 moi->moi_ref--; 295 if ( moi->moi_ref < 1 ) { 296 mdb_txn_reset( moi->moi_txn ); 297 moi->moi_ref = 0; 298 LDAP_SLIST_REMOVE( &op->o_extra, &moi->moi_oe, OpExtra, oe_next ); 299 op->o_tmpfree( moi, op->o_tmpmemctx ); 300 } 301 } 302 break; 303 } 304 } 305 } 306 307 if (release) 308 mdb_entry_return( op, e ); 309 310 return 0; 311 } 312 313 /* return LDAP_SUCCESS IFF we can retrieve the specified entry. 314 */ 315 int mdb_entry_get( 316 Operation *op, 317 struct berval *ndn, 318 ObjectClass *oc, 319 AttributeDescription *at, 320 int rw, 321 Entry **ent ) 322 { 323 struct mdb_info *mdb = (struct mdb_info *) op->o_bd->be_private; 324 struct mdb_op_info *moi = NULL; 325 MDB_txn *txn = NULL; 326 Entry *e = NULL; 327 int rc; 328 const char *at_name = at ? at->ad_cname.bv_val : "(null)"; 329 330 Debug( LDAP_DEBUG_ARGS, 331 "=> mdb_entry_get: ndn: \"%s\"\n", ndn->bv_val, 0, 0 ); 332 Debug( LDAP_DEBUG_ARGS, 333 "=> mdb_entry_get: oc: \"%s\", at: \"%s\"\n", 334 oc ? oc->soc_cname.bv_val : "(null)", at_name, 0); 335 336 rc = mdb_opinfo_get( op, mdb, rw == 0, &moi ); 337 if ( rc ) 338 return LDAP_OTHER; 339 txn = moi->moi_txn; 340 341 /* can we find entry */ 342 rc = mdb_dn2entry( op, txn, NULL, ndn, &e, NULL, 0 ); 343 switch( rc ) { 344 case MDB_NOTFOUND: 345 case 0: 346 break; 347 default: 348 return (rc != LDAP_BUSY) ? LDAP_OTHER : LDAP_BUSY; 349 } 350 if (e == NULL) { 351 Debug( LDAP_DEBUG_ACL, 352 "=> mdb_entry_get: cannot find entry: \"%s\"\n", 353 ndn->bv_val, 0, 0 ); 354 rc = LDAP_NO_SUCH_OBJECT; 355 goto return_results; 356 } 357 358 Debug( LDAP_DEBUG_ACL, 359 "=> mdb_entry_get: found entry: \"%s\"\n", 360 ndn->bv_val, 0, 0 ); 361 362 if ( oc && !is_entry_objectclass( e, oc, 0 )) { 363 Debug( LDAP_DEBUG_ACL, 364 "<= mdb_entry_get: failed to find objectClass %s\n", 365 oc->soc_cname.bv_val, 0, 0 ); 366 rc = LDAP_NO_SUCH_ATTRIBUTE; 367 goto return_results; 368 } 369 370 /* NOTE: attr_find() or attrs_find()? */ 371 if ( at && attr_find( e->e_attrs, at ) == NULL ) { 372 Debug( LDAP_DEBUG_ACL, 373 "<= mdb_entry_get: failed to find attribute %s\n", 374 at->ad_cname.bv_val, 0, 0 ); 375 rc = LDAP_NO_SUCH_ATTRIBUTE; 376 goto return_results; 377 } 378 379 return_results: 380 if( rc != LDAP_SUCCESS ) { 381 /* free entry */ 382 mdb_entry_release( op, e, rw ); 383 } else { 384 *ent = e; 385 } 386 387 Debug( LDAP_DEBUG_TRACE, 388 "mdb_entry_get: rc=%d\n", 389 rc, 0, 0 ); 390 return(rc); 391 } 392 393 static void 394 mdb_reader_free( void *key, void *data ) 395 { 396 MDB_txn *txn = data; 397 398 if ( txn ) mdb_txn_abort( txn ); 399 } 400 401 /* free up any keys used by the main thread */ 402 void 403 mdb_reader_flush( MDB_env *env ) 404 { 405 void *data; 406 void *ctx = ldap_pvt_thread_pool_context(); 407 408 if ( !ldap_pvt_thread_pool_getkey( ctx, env, &data, NULL ) ) { 409 ldap_pvt_thread_pool_setkey( ctx, env, NULL, 0, NULL, NULL ); 410 mdb_reader_free( env, data ); 411 } 412 } 413 414 extern MDB_txn *mdb_tool_txn; 415 416 int 417 mdb_opinfo_get( Operation *op, struct mdb_info *mdb, int rdonly, mdb_op_info **moip ) 418 { 419 int rc, renew = 0; 420 void *data; 421 void *ctx; 422 mdb_op_info *moi = NULL; 423 OpExtra *oex; 424 425 assert( op != NULL ); 426 427 if ( !mdb || !moip ) return -1; 428 429 /* If no op was provided, try to find the ctx anyway... */ 430 if ( op ) { 431 ctx = op->o_threadctx; 432 } else { 433 ctx = ldap_pvt_thread_pool_context(); 434 } 435 436 if ( op ) { 437 LDAP_SLIST_FOREACH( oex, &op->o_extra, oe_next ) { 438 if ( oex->oe_key == mdb ) break; 439 } 440 moi = (mdb_op_info *)oex; 441 } 442 443 if ( !moi ) { 444 moi = *moip; 445 446 if ( !moi ) { 447 if ( op ) { 448 moi = op->o_tmpalloc(sizeof(struct mdb_op_info),op->o_tmpmemctx); 449 } else { 450 moi = ch_malloc(sizeof(mdb_op_info)); 451 } 452 moi->moi_flag = MOI_FREEIT; 453 *moip = moi; 454 } 455 LDAP_SLIST_INSERT_HEAD( &op->o_extra, &moi->moi_oe, oe_next ); 456 moi->moi_oe.oe_key = mdb; 457 moi->moi_ref = 0; 458 moi->moi_txn = NULL; 459 } 460 461 if ( !rdonly ) { 462 /* This op started as a reader, but now wants to write. */ 463 if ( moi->moi_flag & MOI_READER ) { 464 moi = *moip; 465 LDAP_SLIST_INSERT_HEAD( &op->o_extra, &moi->moi_oe, oe_next ); 466 } else { 467 /* This op is continuing an existing write txn */ 468 *moip = moi; 469 } 470 moi->moi_ref++; 471 if ( !moi->moi_txn ) { 472 if (( slapMode & SLAP_TOOL_MODE ) && mdb_tool_txn ) { 473 moi->moi_txn = mdb_tool_txn; 474 } else { 475 rc = mdb_txn_begin( mdb->mi_dbenv, NULL, 0, &moi->moi_txn ); 476 if (rc) { 477 Debug( LDAP_DEBUG_ANY, "mdb_opinfo_get: err %s(%d)\n", 478 mdb_strerror(rc), rc, 0 ); 479 } 480 return rc; 481 } 482 } 483 return 0; 484 } 485 486 /* OK, this is a reader */ 487 if ( !moi->moi_txn ) { 488 if (( slapMode & SLAP_TOOL_MODE ) && mdb_tool_txn ) { 489 moi->moi_txn = mdb_tool_txn; 490 goto ok; 491 } 492 if ( !ctx ) { 493 /* Shouldn't happen unless we're single-threaded */ 494 rc = mdb_txn_begin( mdb->mi_dbenv, NULL, MDB_RDONLY, &moi->moi_txn ); 495 if (rc) { 496 Debug( LDAP_DEBUG_ANY, "mdb_opinfo_get: err %s(%d)\n", 497 mdb_strerror(rc), rc, 0 ); 498 } 499 return rc; 500 } 501 if ( ldap_pvt_thread_pool_getkey( ctx, mdb->mi_dbenv, &data, NULL ) ) { 502 rc = mdb_txn_begin( mdb->mi_dbenv, NULL, MDB_RDONLY, &moi->moi_txn ); 503 if (rc) { 504 Debug( LDAP_DEBUG_ANY, "mdb_opinfo_get: err %s(%d)\n", 505 mdb_strerror(rc), rc, 0 ); 506 return rc; 507 } 508 data = moi->moi_txn; 509 if ( ( rc = ldap_pvt_thread_pool_setkey( ctx, mdb->mi_dbenv, 510 data, mdb_reader_free, NULL, NULL ) ) ) { 511 mdb_txn_abort( moi->moi_txn ); 512 moi->moi_txn = NULL; 513 Debug( LDAP_DEBUG_ANY, "mdb_opinfo_get: thread_pool_setkey failed err (%d)\n", 514 rc, 0, 0 ); 515 return rc; 516 } 517 } else { 518 moi->moi_txn = data; 519 renew = 1; 520 } 521 moi->moi_flag |= MOI_READER; 522 } 523 ok: 524 if ( moi->moi_ref < 1 ) { 525 moi->moi_ref = 0; 526 } 527 if ( renew ) { 528 rc = mdb_txn_renew( moi->moi_txn ); 529 assert(!rc); 530 } 531 moi->moi_ref++; 532 if ( *moip != moi ) 533 *moip = moi; 534 535 return 0; 536 } 537 538 /* Count up the sizes of the components of an entry */ 539 static int mdb_entry_partsize(struct mdb_info *mdb, MDB_txn *txn, Entry *e, 540 Ecount *eh) 541 { 542 ber_len_t len; 543 int i, nat = 0, nval = 0, nnval = 0; 544 Attribute *a; 545 546 len = 4*sizeof(int); /* nattrs, nvals, ocflags, offset */ 547 for (a=e->e_attrs; a; a=a->a_next) { 548 /* For AttributeDesc, we only store the attr index */ 549 nat++; 550 if (a->a_desc->ad_index >= MDB_MAXADS) { 551 Debug( LDAP_DEBUG_ANY, "mdb_entry_partsize: too many AttributeDescriptions used\n", 552 0, 0, 0 ); 553 return LDAP_OTHER; 554 } 555 if (!mdb->mi_adxs[a->a_desc->ad_index]) { 556 int rc = mdb_ad_get(mdb, txn, a->a_desc); 557 if (rc) 558 return rc; 559 } 560 len += 2*sizeof(int); /* AD index, numvals */ 561 nval += a->a_numvals + 1; /* empty berval at end */ 562 for (i=0; i<a->a_numvals; i++) { 563 len += a->a_vals[i].bv_len + 1 + sizeof(int); /* len */ 564 } 565 if (a->a_nvals != a->a_vals) { 566 nval += a->a_numvals + 1; 567 nnval++; 568 for (i=0; i<a->a_numvals; i++) { 569 len += a->a_nvals[i].bv_len + 1 + sizeof(int);; 570 } 571 } 572 } 573 /* padding */ 574 len = (len + sizeof(ID)-1) & ~(sizeof(ID)-1); 575 eh->len = len; 576 eh->nattrs = nat; 577 eh->nvals = nval; 578 eh->offset = nat + nval - nnval; 579 return 0; 580 } 581 582 #define HIGH_BIT (1U<<(sizeof(unsigned int)*CHAR_BIT-1)) 583 584 /* Flatten an Entry into a buffer. The buffer starts with the count of the 585 * number of attributes in the entry, the total number of values in the 586 * entry, and the e_ocflags. It then contains a list of integers for each 587 * attribute. For each attribute the first integer gives the index of the 588 * matching AttributeDescription, followed by the number of values in the 589 * attribute. If the high bit of the attr index is set, the attribute's 590 * values are already sorted. 591 * If the high bit of numvals is set, the attribute also has normalized 592 * values present. (Note - a_numvals is an unsigned int, so this means 593 * it's possible to receive an attribute that we can't encode due to size 594 * overflow. In practice, this should not be an issue.) Then the length 595 * of each value is listed. If there are normalized values, their lengths 596 * come next. This continues for each attribute. After all of the lengths 597 * for the last attribute, the actual values are copied, with a NUL 598 * terminator after each value. The buffer is padded to the sizeof(ID). 599 * The entire buffer size is precomputed so that a single malloc can be 600 * performed. 601 */ 602 static int mdb_entry_encode(Operation *op, Entry *e, MDB_val *data, Ecount *eh) 603 { 604 struct mdb_info *mdb = (struct mdb_info *) op->o_bd->be_private; 605 ber_len_t i; 606 Attribute *a; 607 unsigned char *ptr; 608 unsigned int *lp, l; 609 610 Debug( LDAP_DEBUG_TRACE, "=> mdb_entry_encode(0x%08lx): %s\n", 611 (long) e->e_id, e->e_dn, 0 ); 612 613 /* make sure e->e_ocflags is set */ 614 if (is_entry_referral(e)) 615 ; /* empty */ 616 617 lp = (unsigned int *)data->mv_data; 618 *lp++ = eh->nattrs; 619 *lp++ = eh->nvals; 620 *lp++ = (unsigned int)e->e_ocflags; 621 *lp++ = eh->offset; 622 ptr = (unsigned char *)(lp + eh->offset); 623 624 for (a=e->e_attrs; a; a=a->a_next) { 625 if (!a->a_desc->ad_index) 626 return LDAP_UNDEFINED_TYPE; 627 l = mdb->mi_adxs[a->a_desc->ad_index]; 628 if (a->a_flags & SLAP_ATTR_SORTED_VALS) 629 l |= HIGH_BIT; 630 *lp++ = l; 631 l = a->a_numvals; 632 if (a->a_nvals != a->a_vals) 633 l |= HIGH_BIT; 634 *lp++ = l; 635 if (a->a_vals) { 636 for (i=0; a->a_vals[i].bv_val; i++); 637 assert( i == a->a_numvals ); 638 for (i=0; i<a->a_numvals; i++) { 639 *lp++ = a->a_vals[i].bv_len; 640 memcpy(ptr, a->a_vals[i].bv_val, 641 a->a_vals[i].bv_len); 642 ptr += a->a_vals[i].bv_len; 643 *ptr++ = '\0'; 644 } 645 if (a->a_nvals != a->a_vals) { 646 for (i=0; i<a->a_numvals; i++) { 647 *lp++ = a->a_nvals[i].bv_len; 648 memcpy(ptr, a->a_nvals[i].bv_val, 649 a->a_nvals[i].bv_len); 650 ptr += a->a_nvals[i].bv_len; 651 *ptr++ = '\0'; 652 } 653 } 654 } 655 } 656 657 Debug( LDAP_DEBUG_TRACE, "<= mdb_entry_encode(0x%08lx): %s\n", 658 (long) e->e_id, e->e_dn, 0 ); 659 660 return 0; 661 } 662 663 /* Retrieve an Entry that was stored using entry_encode above. 664 * 665 * Note: everything is stored in a single contiguous block, so 666 * you can not free individual attributes or names from this 667 * structure. Attempting to do so will likely corrupt memory. 668 */ 669 670 int mdb_entry_decode(Operation *op, MDB_txn *txn, MDB_val *data, Entry **e) 671 { 672 struct mdb_info *mdb = (struct mdb_info *) op->o_bd->be_private; 673 int i, j, nattrs, nvals; 674 int rc; 675 Attribute *a; 676 Entry *x; 677 const char *text; 678 unsigned int *lp = (unsigned int *)data->mv_data; 679 unsigned char *ptr; 680 BerVarray bptr; 681 682 Debug( LDAP_DEBUG_TRACE, 683 "=> mdb_entry_decode:\n", 684 0, 0, 0 ); 685 686 nattrs = *lp++; 687 nvals = *lp++; 688 x = mdb_entry_alloc(op, nattrs, nvals); 689 x->e_ocflags = *lp++; 690 if (!nvals) { 691 goto done; 692 } 693 a = x->e_attrs; 694 bptr = a->a_vals; 695 i = *lp++; 696 ptr = (unsigned char *)(lp + i); 697 698 for (;nattrs>0; nattrs--) { 699 int have_nval = 0; 700 a->a_flags = SLAP_ATTR_DONT_FREE_DATA | SLAP_ATTR_DONT_FREE_VALS; 701 i = *lp++; 702 if (i & HIGH_BIT) { 703 i ^= HIGH_BIT; 704 a->a_flags |= SLAP_ATTR_SORTED_VALS; 705 } 706 if (i > mdb->mi_numads) { 707 rc = mdb_ad_read(mdb, txn); 708 if (rc) 709 return rc; 710 if (i > mdb->mi_numads) { 711 Debug( LDAP_DEBUG_ANY, 712 "mdb_entry_decode: attribute index %d not recognized\n", 713 i, 0, 0 ); 714 return LDAP_OTHER; 715 } 716 } 717 a->a_desc = mdb->mi_ads[i]; 718 a->a_numvals = *lp++; 719 if (a->a_numvals & HIGH_BIT) { 720 a->a_numvals ^= HIGH_BIT; 721 have_nval = 1; 722 } 723 a->a_vals = bptr; 724 for (i=0; i<a->a_numvals; i++) { 725 bptr->bv_len = *lp++;; 726 bptr->bv_val = (char *)ptr; 727 ptr += bptr->bv_len+1; 728 bptr++; 729 } 730 bptr->bv_val = NULL; 731 bptr->bv_len = 0; 732 bptr++; 733 734 if (have_nval) { 735 a->a_nvals = bptr; 736 for (i=0; i<a->a_numvals; i++) { 737 bptr->bv_len = *lp++; 738 bptr->bv_val = (char *)ptr; 739 ptr += bptr->bv_len+1; 740 bptr++; 741 } 742 bptr->bv_val = NULL; 743 bptr->bv_len = 0; 744 bptr++; 745 } else { 746 a->a_nvals = a->a_vals; 747 } 748 /* FIXME: This is redundant once a sorted entry is saved into the DB */ 749 if (( a->a_desc->ad_type->sat_flags & SLAP_AT_SORTED_VAL ) 750 && !(a->a_flags & SLAP_ATTR_SORTED_VALS)) { 751 rc = slap_sort_vals( (Modifications *)a, &text, &j, NULL ); 752 if ( rc == LDAP_SUCCESS ) { 753 a->a_flags |= SLAP_ATTR_SORTED_VALS; 754 } else if ( rc == LDAP_TYPE_OR_VALUE_EXISTS ) { 755 /* should never happen */ 756 Debug( LDAP_DEBUG_ANY, 757 "mdb_entry_decode: attributeType %s value #%d provided more than once\n", 758 a->a_desc->ad_cname.bv_val, j, 0 ); 759 return rc; 760 } 761 } 762 a->a_next = a+1; 763 a = a->a_next; 764 } 765 a[-1].a_next = NULL; 766 done: 767 768 Debug(LDAP_DEBUG_TRACE, "<= mdb_entry_decode\n", 769 0, 0, 0 ); 770 *e = x; 771 return 0; 772 } 773