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