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