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