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