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