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