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