attr.c revision 1.1.1.6 1 1.1.1.6 christos /* $NetBSD: attr.c,v 1.1.1.6 2021/08/14 16:05:23 christos Exp $ */
2 1.1 tron
3 1.1 tron /* attr.c - backend routines for dealing with attributes */
4 1.1 tron /* $OpenLDAP$ */
5 1.1 tron /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
6 1.1 tron *
7 1.1.1.6 christos * Copyright 2000-2021 The OpenLDAP Foundation.
8 1.1 tron * All rights reserved.
9 1.1 tron *
10 1.1 tron * Redistribution and use in source and binary forms, with or without
11 1.1 tron * modification, are permitted only as authorized by the OpenLDAP
12 1.1 tron * Public License.
13 1.1 tron *
14 1.1 tron * A copy of this license is available in the file LICENSE in the
15 1.1 tron * top-level directory of the distribution or, alternatively, at
16 1.1 tron * <http://www.OpenLDAP.org/license.html>.
17 1.1 tron */
18 1.1 tron
19 1.1.1.2 christos #include <sys/cdefs.h>
20 1.1.1.6 christos __RCSID("$NetBSD: attr.c,v 1.1.1.6 2021/08/14 16:05:23 christos Exp $");
21 1.1.1.2 christos
22 1.1 tron #include "portable.h"
23 1.1 tron
24 1.1 tron #include <stdio.h>
25 1.1 tron
26 1.1 tron #include <ac/socket.h>
27 1.1 tron #include <ac/string.h>
28 1.1 tron
29 1.1 tron #include "slap.h"
30 1.1 tron #include "back-mdb.h"
31 1.1.1.6 christos #include "slap-config.h"
32 1.1 tron #include "lutil.h"
33 1.1 tron
34 1.1 tron /* Find the ad, return -1 if not found,
35 1.1 tron * set point for insertion if ins is non-NULL
36 1.1 tron */
37 1.1 tron int
38 1.1 tron mdb_attr_slot( struct mdb_info *mdb, AttributeDescription *ad, int *ins )
39 1.1 tron {
40 1.1 tron unsigned base = 0, cursor = 0;
41 1.1 tron unsigned n = mdb->mi_nattrs;
42 1.1 tron int val = 0;
43 1.1 tron
44 1.1 tron while ( 0 < n ) {
45 1.1 tron unsigned pivot = n >> 1;
46 1.1 tron cursor = base + pivot;
47 1.1 tron
48 1.1 tron val = SLAP_PTRCMP( ad, mdb->mi_attrs[cursor]->ai_desc );
49 1.1 tron if ( val < 0 ) {
50 1.1 tron n = pivot;
51 1.1 tron } else if ( val > 0 ) {
52 1.1 tron base = cursor + 1;
53 1.1 tron n -= pivot + 1;
54 1.1 tron } else {
55 1.1 tron return cursor;
56 1.1 tron }
57 1.1 tron }
58 1.1 tron if ( ins ) {
59 1.1 tron if ( val > 0 )
60 1.1 tron ++cursor;
61 1.1 tron *ins = cursor;
62 1.1 tron }
63 1.1 tron return -1;
64 1.1 tron }
65 1.1 tron
66 1.1 tron static int
67 1.1 tron ainfo_insert( struct mdb_info *mdb, AttrInfo *a )
68 1.1 tron {
69 1.1 tron int x;
70 1.1 tron int i = mdb_attr_slot( mdb, a->ai_desc, &x );
71 1.1 tron
72 1.1 tron /* Is it a dup? */
73 1.1 tron if ( i >= 0 )
74 1.1 tron return -1;
75 1.1 tron
76 1.1 tron mdb->mi_attrs = ch_realloc( mdb->mi_attrs, ( mdb->mi_nattrs+1 ) *
77 1.1 tron sizeof( AttrInfo * ));
78 1.1 tron if ( x < mdb->mi_nattrs )
79 1.1 tron AC_MEMCPY( &mdb->mi_attrs[x+1], &mdb->mi_attrs[x],
80 1.1 tron ( mdb->mi_nattrs - x ) * sizeof( AttrInfo *));
81 1.1 tron mdb->mi_attrs[x] = a;
82 1.1 tron mdb->mi_nattrs++;
83 1.1 tron return 0;
84 1.1 tron }
85 1.1 tron
86 1.1 tron AttrInfo *
87 1.1 tron mdb_attr_mask(
88 1.1 tron struct mdb_info *mdb,
89 1.1 tron AttributeDescription *desc )
90 1.1 tron {
91 1.1 tron int i = mdb_attr_slot( mdb, desc, NULL );
92 1.1 tron return i < 0 ? NULL : mdb->mi_attrs[i];
93 1.1 tron }
94 1.1 tron
95 1.1 tron /* Open all un-opened index DB handles */
96 1.1 tron int
97 1.1 tron mdb_attr_dbs_open(
98 1.1 tron BackendDB *be, MDB_txn *tx0, ConfigReply *cr )
99 1.1 tron {
100 1.1 tron struct mdb_info *mdb = (struct mdb_info *) be->be_private;
101 1.1 tron MDB_txn *txn;
102 1.1 tron MDB_dbi *dbis = NULL;
103 1.1 tron int i, flags;
104 1.1 tron int rc;
105 1.1 tron
106 1.1 tron txn = tx0;
107 1.1 tron if ( txn == NULL ) {
108 1.1 tron rc = mdb_txn_begin( mdb->mi_dbenv, NULL, 0, &txn );
109 1.1 tron if ( rc ) {
110 1.1 tron snprintf( cr->msg, sizeof(cr->msg), "database \"%s\": "
111 1.1 tron "txn_begin failed: %s (%d).",
112 1.1 tron be->be_suffix[0].bv_val, mdb_strerror(rc), rc );
113 1.1 tron Debug( LDAP_DEBUG_ANY,
114 1.1 tron LDAP_XSTRING(mdb_attr_dbs) ": %s\n",
115 1.1.1.6 christos cr->msg );
116 1.1 tron return rc;
117 1.1 tron }
118 1.1 tron dbis = ch_calloc( 1, mdb->mi_nattrs * sizeof(MDB_dbi) );
119 1.1 tron } else {
120 1.1 tron rc = 0;
121 1.1 tron }
122 1.1 tron
123 1.1 tron flags = MDB_DUPSORT|MDB_DUPFIXED|MDB_INTEGERDUP;
124 1.1 tron if ( !(slapMode & SLAP_TOOL_READONLY) )
125 1.1 tron flags |= MDB_CREATE;
126 1.1 tron
127 1.1 tron for ( i=0; i<mdb->mi_nattrs; i++ ) {
128 1.1 tron if ( mdb->mi_attrs[i]->ai_dbi ) /* already open */
129 1.1 tron continue;
130 1.1.1.6 christos if ( !( mdb->mi_attrs[i]->ai_indexmask || mdb->mi_attrs[i]->ai_newmask )) /* not an index record */
131 1.1.1.6 christos continue;
132 1.1 tron rc = mdb_dbi_open( txn, mdb->mi_attrs[i]->ai_desc->ad_type->sat_cname.bv_val,
133 1.1 tron flags, &mdb->mi_attrs[i]->ai_dbi );
134 1.1 tron if ( rc ) {
135 1.1 tron snprintf( cr->msg, sizeof(cr->msg), "database \"%s\": "
136 1.1 tron "mdb_dbi_open(%s) failed: %s (%d).",
137 1.1 tron be->be_suffix[0].bv_val,
138 1.1 tron mdb->mi_attrs[i]->ai_desc->ad_type->sat_cname.bv_val,
139 1.1 tron mdb_strerror(rc), rc );
140 1.1 tron Debug( LDAP_DEBUG_ANY,
141 1.1 tron LDAP_XSTRING(mdb_attr_dbs) ": %s\n",
142 1.1.1.6 christos cr->msg );
143 1.1 tron break;
144 1.1 tron }
145 1.1 tron /* Remember newly opened DBI handles */
146 1.1 tron if ( dbis )
147 1.1 tron dbis[i] = mdb->mi_attrs[i]->ai_dbi;
148 1.1 tron }
149 1.1 tron
150 1.1 tron /* Only commit if this is our txn */
151 1.1 tron if ( tx0 == NULL ) {
152 1.1 tron if ( !rc ) {
153 1.1 tron rc = mdb_txn_commit( txn );
154 1.1 tron if ( rc ) {
155 1.1 tron snprintf( cr->msg, sizeof(cr->msg), "database \"%s\": "
156 1.1 tron "txn_commit failed: %s (%d).",
157 1.1 tron be->be_suffix[0].bv_val, mdb_strerror(rc), rc );
158 1.1 tron Debug( LDAP_DEBUG_ANY,
159 1.1 tron LDAP_XSTRING(mdb_attr_dbs) ": %s\n",
160 1.1.1.6 christos cr->msg );
161 1.1 tron }
162 1.1 tron } else {
163 1.1 tron mdb_txn_abort( txn );
164 1.1 tron }
165 1.1 tron /* Something failed, forget anything we just opened */
166 1.1 tron if ( rc ) {
167 1.1 tron for ( i=0; i<mdb->mi_nattrs; i++ ) {
168 1.1 tron if ( dbis[i] ) {
169 1.1 tron mdb->mi_attrs[i]->ai_dbi = 0;
170 1.1 tron mdb->mi_attrs[i]->ai_indexmask |= MDB_INDEX_DELETING;
171 1.1 tron }
172 1.1 tron }
173 1.1 tron mdb_attr_flush( mdb );
174 1.1 tron }
175 1.1 tron ch_free( dbis );
176 1.1 tron }
177 1.1 tron
178 1.1 tron return rc;
179 1.1 tron }
180 1.1 tron
181 1.1 tron void
182 1.1 tron mdb_attr_dbs_close(
183 1.1 tron struct mdb_info *mdb
184 1.1 tron )
185 1.1 tron {
186 1.1 tron int i;
187 1.1 tron for ( i=0; i<mdb->mi_nattrs; i++ )
188 1.1 tron if ( mdb->mi_attrs[i]->ai_dbi ) {
189 1.1 tron mdb_dbi_close( mdb->mi_dbenv, mdb->mi_attrs[i]->ai_dbi );
190 1.1 tron mdb->mi_attrs[i]->ai_dbi = 0;
191 1.1 tron }
192 1.1 tron }
193 1.1 tron
194 1.1 tron int
195 1.1 tron mdb_attr_index_config(
196 1.1 tron struct mdb_info *mdb,
197 1.1 tron const char *fname,
198 1.1 tron int lineno,
199 1.1 tron int argc,
200 1.1 tron char **argv,
201 1.1 tron struct config_reply_s *c_reply)
202 1.1 tron {
203 1.1 tron int rc = 0;
204 1.1 tron int i;
205 1.1 tron slap_mask_t mask;
206 1.1 tron char **attrs;
207 1.1 tron char **indexes = NULL;
208 1.1 tron
209 1.1 tron attrs = ldap_str2charray( argv[0], "," );
210 1.1 tron
211 1.1 tron if( attrs == NULL ) {
212 1.1 tron fprintf( stderr, "%s: line %d: "
213 1.1 tron "no attributes specified: %s\n",
214 1.1 tron fname, lineno, argv[0] );
215 1.1 tron return LDAP_PARAM_ERROR;
216 1.1 tron }
217 1.1 tron
218 1.1 tron if ( argc > 1 ) {
219 1.1 tron indexes = ldap_str2charray( argv[1], "," );
220 1.1 tron
221 1.1 tron if( indexes == NULL ) {
222 1.1 tron fprintf( stderr, "%s: line %d: "
223 1.1 tron "no indexes specified: %s\n",
224 1.1 tron fname, lineno, argv[1] );
225 1.1 tron rc = LDAP_PARAM_ERROR;
226 1.1 tron goto done;
227 1.1 tron }
228 1.1 tron }
229 1.1 tron
230 1.1 tron if( indexes == NULL ) {
231 1.1 tron mask = mdb->mi_defaultmask;
232 1.1 tron
233 1.1 tron } else {
234 1.1 tron mask = 0;
235 1.1 tron
236 1.1 tron for ( i = 0; indexes[i] != NULL; i++ ) {
237 1.1 tron slap_mask_t index;
238 1.1 tron rc = slap_str2index( indexes[i], &index );
239 1.1 tron
240 1.1 tron if( rc != LDAP_SUCCESS ) {
241 1.1 tron if ( c_reply )
242 1.1 tron {
243 1.1 tron snprintf(c_reply->msg, sizeof(c_reply->msg),
244 1.1 tron "index type \"%s\" undefined", indexes[i] );
245 1.1 tron
246 1.1 tron fprintf( stderr, "%s: line %d: %s\n",
247 1.1 tron fname, lineno, c_reply->msg );
248 1.1 tron }
249 1.1 tron rc = LDAP_PARAM_ERROR;
250 1.1 tron goto done;
251 1.1 tron }
252 1.1 tron
253 1.1 tron mask |= index;
254 1.1 tron }
255 1.1 tron }
256 1.1 tron
257 1.1 tron if( !mask ) {
258 1.1 tron if ( c_reply )
259 1.1 tron {
260 1.1 tron snprintf(c_reply->msg, sizeof(c_reply->msg),
261 1.1 tron "no indexes selected" );
262 1.1 tron fprintf( stderr, "%s: line %d: %s\n",
263 1.1 tron fname, lineno, c_reply->msg );
264 1.1 tron }
265 1.1 tron rc = LDAP_PARAM_ERROR;
266 1.1 tron goto done;
267 1.1 tron }
268 1.1 tron
269 1.1 tron for ( i = 0; attrs[i] != NULL; i++ ) {
270 1.1 tron AttrInfo *a;
271 1.1 tron AttributeDescription *ad;
272 1.1 tron const char *text;
273 1.1 tron #ifdef LDAP_COMP_MATCH
274 1.1 tron ComponentReference* cr = NULL;
275 1.1 tron AttrInfo *a_cr = NULL;
276 1.1 tron #endif
277 1.1 tron
278 1.1 tron if( strcasecmp( attrs[i], "default" ) == 0 ) {
279 1.1 tron mdb->mi_defaultmask |= mask;
280 1.1 tron continue;
281 1.1 tron }
282 1.1 tron
283 1.1 tron #ifdef LDAP_COMP_MATCH
284 1.1 tron if ( is_component_reference( attrs[i] ) ) {
285 1.1 tron rc = extract_component_reference( attrs[i], &cr );
286 1.1 tron if ( rc != LDAP_SUCCESS ) {
287 1.1 tron if ( c_reply )
288 1.1 tron {
289 1.1 tron snprintf(c_reply->msg, sizeof(c_reply->msg),
290 1.1 tron "index component reference\"%s\" undefined",
291 1.1 tron attrs[i] );
292 1.1 tron fprintf( stderr, "%s: line %d: %s\n",
293 1.1 tron fname, lineno, c_reply->msg );
294 1.1 tron }
295 1.1 tron goto done;
296 1.1 tron }
297 1.1 tron cr->cr_indexmask = mask;
298 1.1 tron /*
299 1.1 tron * After extracting a component reference
300 1.1 tron * only the name of a attribute will be remaining
301 1.1 tron */
302 1.1 tron } else {
303 1.1 tron cr = NULL;
304 1.1 tron }
305 1.1 tron #endif
306 1.1 tron ad = NULL;
307 1.1 tron rc = slap_str2ad( attrs[i], &ad, &text );
308 1.1 tron
309 1.1 tron if( rc != LDAP_SUCCESS ) {
310 1.1 tron if ( c_reply )
311 1.1 tron {
312 1.1 tron snprintf(c_reply->msg, sizeof(c_reply->msg),
313 1.1 tron "index attribute \"%s\" undefined",
314 1.1 tron attrs[i] );
315 1.1 tron
316 1.1 tron fprintf( stderr, "%s: line %d: %s\n",
317 1.1 tron fname, lineno, c_reply->msg );
318 1.1 tron }
319 1.1.1.6 christos fail:
320 1.1.1.6 christos #ifdef LDAP_COMP_MATCH
321 1.1.1.6 christos ch_free( cr );
322 1.1.1.6 christos #endif
323 1.1 tron goto done;
324 1.1 tron }
325 1.1 tron
326 1.1 tron if( ad == slap_schema.si_ad_entryDN || slap_ad_is_binary( ad ) ) {
327 1.1 tron if (c_reply) {
328 1.1 tron snprintf(c_reply->msg, sizeof(c_reply->msg),
329 1.1 tron "index of attribute \"%s\" disallowed", attrs[i] );
330 1.1 tron fprintf( stderr, "%s: line %d: %s\n",
331 1.1 tron fname, lineno, c_reply->msg );
332 1.1 tron }
333 1.1 tron rc = LDAP_UNWILLING_TO_PERFORM;
334 1.1.1.6 christos goto fail;
335 1.1 tron }
336 1.1 tron
337 1.1 tron if( IS_SLAP_INDEX( mask, SLAP_INDEX_APPROX ) && !(
338 1.1 tron ad->ad_type->sat_approx
339 1.1 tron && ad->ad_type->sat_approx->smr_indexer
340 1.1 tron && ad->ad_type->sat_approx->smr_filter ) )
341 1.1 tron {
342 1.1 tron if (c_reply) {
343 1.1 tron snprintf(c_reply->msg, sizeof(c_reply->msg),
344 1.1 tron "approx index of attribute \"%s\" disallowed", attrs[i] );
345 1.1 tron fprintf( stderr, "%s: line %d: %s\n",
346 1.1 tron fname, lineno, c_reply->msg );
347 1.1 tron }
348 1.1 tron rc = LDAP_INAPPROPRIATE_MATCHING;
349 1.1.1.6 christos goto fail;
350 1.1 tron }
351 1.1 tron
352 1.1 tron if( IS_SLAP_INDEX( mask, SLAP_INDEX_EQUALITY ) && !(
353 1.1 tron ad->ad_type->sat_equality
354 1.1 tron && ad->ad_type->sat_equality->smr_indexer
355 1.1 tron && ad->ad_type->sat_equality->smr_filter ) )
356 1.1 tron {
357 1.1 tron if (c_reply) {
358 1.1 tron snprintf(c_reply->msg, sizeof(c_reply->msg),
359 1.1 tron "equality index of attribute \"%s\" disallowed", attrs[i] );
360 1.1 tron fprintf( stderr, "%s: line %d: %s\n",
361 1.1 tron fname, lineno, c_reply->msg );
362 1.1 tron }
363 1.1 tron rc = LDAP_INAPPROPRIATE_MATCHING;
364 1.1.1.6 christos goto fail;
365 1.1 tron }
366 1.1 tron
367 1.1 tron if( IS_SLAP_INDEX( mask, SLAP_INDEX_SUBSTR ) && !(
368 1.1 tron ad->ad_type->sat_substr
369 1.1 tron && ad->ad_type->sat_substr->smr_indexer
370 1.1 tron && ad->ad_type->sat_substr->smr_filter ) )
371 1.1 tron {
372 1.1 tron if (c_reply) {
373 1.1 tron snprintf(c_reply->msg, sizeof(c_reply->msg),
374 1.1 tron "substr index of attribute \"%s\" disallowed", attrs[i] );
375 1.1 tron fprintf( stderr, "%s: line %d: %s\n",
376 1.1 tron fname, lineno, c_reply->msg );
377 1.1 tron }
378 1.1 tron rc = LDAP_INAPPROPRIATE_MATCHING;
379 1.1.1.6 christos goto fail;
380 1.1 tron }
381 1.1 tron
382 1.1 tron Debug( LDAP_DEBUG_CONFIG, "index %s 0x%04lx\n",
383 1.1.1.6 christos ad->ad_cname.bv_val, mask );
384 1.1 tron
385 1.1 tron a = (AttrInfo *) ch_malloc( sizeof(AttrInfo) );
386 1.1 tron
387 1.1 tron #ifdef LDAP_COMP_MATCH
388 1.1 tron a->ai_cr = NULL;
389 1.1 tron #endif
390 1.1 tron a->ai_cursor = NULL;
391 1.1 tron a->ai_root = NULL;
392 1.1 tron a->ai_desc = ad;
393 1.1 tron a->ai_dbi = 0;
394 1.1.1.6 christos a->ai_multi_hi = UINT_MAX;
395 1.1.1.6 christos a->ai_multi_lo = UINT_MAX;
396 1.1 tron
397 1.1 tron if ( mdb->mi_flags & MDB_IS_OPEN ) {
398 1.1 tron a->ai_indexmask = 0;
399 1.1 tron a->ai_newmask = mask;
400 1.1 tron } else {
401 1.1 tron a->ai_indexmask = mask;
402 1.1 tron a->ai_newmask = 0;
403 1.1 tron }
404 1.1 tron
405 1.1 tron #ifdef LDAP_COMP_MATCH
406 1.1 tron if ( cr ) {
407 1.1 tron a_cr = mdb_attr_mask( mdb, ad );
408 1.1 tron if ( a_cr ) {
409 1.1 tron /*
410 1.1 tron * AttrInfo is already in AVL
411 1.1 tron * just add the extracted component reference
412 1.1 tron * in the AttrInfo
413 1.1 tron */
414 1.1.1.6 christos ch_free( a );
415 1.1 tron rc = insert_component_reference( cr, &a_cr->ai_cr );
416 1.1 tron if ( rc != LDAP_SUCCESS) {
417 1.1 tron fprintf( stderr, " error during inserting component reference in %s ", attrs[i]);
418 1.1 tron rc = LDAP_PARAM_ERROR;
419 1.1.1.6 christos goto fail;
420 1.1 tron }
421 1.1 tron continue;
422 1.1 tron } else {
423 1.1 tron rc = insert_component_reference( cr, &a->ai_cr );
424 1.1 tron if ( rc != LDAP_SUCCESS) {
425 1.1 tron fprintf( stderr, " error during inserting component reference in %s ", attrs[i]);
426 1.1 tron rc = LDAP_PARAM_ERROR;
427 1.1.1.6 christos ch_free( a );
428 1.1.1.6 christos goto fail;
429 1.1 tron }
430 1.1 tron }
431 1.1 tron }
432 1.1 tron #endif
433 1.1 tron rc = ainfo_insert( mdb, a );
434 1.1 tron if( rc ) {
435 1.1.1.6 christos AttrInfo *b = mdb_attr_mask( mdb, ad );
436 1.1.1.6 christos /* If this is just a multival record, reuse it for index info */
437 1.1.1.6 christos if ( !( b->ai_indexmask || b->ai_newmask ) && b->ai_multi_lo < UINT_MAX ) {
438 1.1.1.6 christos b->ai_indexmask = a->ai_indexmask;
439 1.1.1.6 christos b->ai_newmask = a->ai_newmask;
440 1.1.1.6 christos ch_free( a );
441 1.1.1.6 christos rc = 0;
442 1.1.1.6 christos continue;
443 1.1.1.6 christos }
444 1.1 tron if ( mdb->mi_flags & MDB_IS_OPEN ) {
445 1.1 tron /* If there is already an index defined for this attribute
446 1.1 tron * it must be replaced. Otherwise we end up with multiple
447 1.1 tron * olcIndex values for the same attribute */
448 1.1 tron if ( b->ai_indexmask & MDB_INDEX_DELETING ) {
449 1.1 tron /* If we were editing this attr, reset it */
450 1.1 tron b->ai_indexmask &= ~MDB_INDEX_DELETING;
451 1.1 tron /* If this is leftover from a previous add, commit it */
452 1.1 tron if ( b->ai_newmask )
453 1.1 tron b->ai_indexmask = b->ai_newmask;
454 1.1 tron b->ai_newmask = a->ai_newmask;
455 1.1 tron ch_free( a );
456 1.1 tron rc = 0;
457 1.1 tron continue;
458 1.1 tron }
459 1.1 tron }
460 1.1 tron if (c_reply) {
461 1.1 tron snprintf(c_reply->msg, sizeof(c_reply->msg),
462 1.1 tron "duplicate index definition for attr \"%s\"",
463 1.1 tron attrs[i] );
464 1.1 tron fprintf( stderr, "%s: line %d: %s\n",
465 1.1 tron fname, lineno, c_reply->msg );
466 1.1 tron }
467 1.1 tron
468 1.1 tron rc = LDAP_PARAM_ERROR;
469 1.1 tron goto done;
470 1.1 tron }
471 1.1 tron }
472 1.1 tron
473 1.1 tron done:
474 1.1 tron ldap_charray_free( attrs );
475 1.1 tron if ( indexes != NULL ) ldap_charray_free( indexes );
476 1.1 tron
477 1.1 tron return rc;
478 1.1 tron }
479 1.1 tron
480 1.1 tron static int
481 1.1 tron mdb_attr_index_unparser( void *v1, void *v2 )
482 1.1 tron {
483 1.1 tron AttrInfo *ai = v1;
484 1.1 tron BerVarray *bva = v2;
485 1.1 tron struct berval bv;
486 1.1 tron char *ptr;
487 1.1 tron
488 1.1 tron slap_index2bvlen( ai->ai_indexmask, &bv );
489 1.1 tron if ( bv.bv_len ) {
490 1.1 tron bv.bv_len += ai->ai_desc->ad_cname.bv_len + 1;
491 1.1 tron ptr = ch_malloc( bv.bv_len+1 );
492 1.1 tron bv.bv_val = lutil_strcopy( ptr, ai->ai_desc->ad_cname.bv_val );
493 1.1 tron *bv.bv_val++ = ' ';
494 1.1 tron slap_index2bv( ai->ai_indexmask, &bv );
495 1.1 tron bv.bv_val = ptr;
496 1.1 tron ber_bvarray_add( bva, &bv );
497 1.1 tron }
498 1.1 tron return 0;
499 1.1 tron }
500 1.1 tron
501 1.1 tron static AttributeDescription addef = { NULL, NULL, BER_BVC("default") };
502 1.1 tron static AttrInfo aidef = { &addef };
503 1.1 tron
504 1.1 tron void
505 1.1 tron mdb_attr_index_unparse( struct mdb_info *mdb, BerVarray *bva )
506 1.1 tron {
507 1.1 tron int i;
508 1.1 tron
509 1.1 tron if ( mdb->mi_defaultmask ) {
510 1.1 tron aidef.ai_indexmask = mdb->mi_defaultmask;
511 1.1 tron mdb_attr_index_unparser( &aidef, bva );
512 1.1 tron }
513 1.1 tron for ( i=0; i<mdb->mi_nattrs; i++ )
514 1.1.1.6 christos if ( mdb->mi_attrs[i]->ai_indexmask )
515 1.1.1.6 christos mdb_attr_index_unparser( mdb->mi_attrs[i], bva );
516 1.1.1.6 christos }
517 1.1.1.6 christos
518 1.1.1.6 christos int
519 1.1.1.6 christos mdb_attr_multi_config(
520 1.1.1.6 christos struct mdb_info *mdb,
521 1.1.1.6 christos const char *fname,
522 1.1.1.6 christos int lineno,
523 1.1.1.6 christos int argc,
524 1.1.1.6 christos char **argv,
525 1.1.1.6 christos struct config_reply_s *c_reply)
526 1.1.1.6 christos {
527 1.1.1.6 christos int rc = 0;
528 1.1.1.6 christos int i;
529 1.1.1.6 christos unsigned hi,lo;
530 1.1.1.6 christos char **attrs, *next, *s;
531 1.1.1.6 christos
532 1.1.1.6 christos attrs = ldap_str2charray( argv[0], "," );
533 1.1.1.6 christos
534 1.1.1.6 christos if( attrs == NULL ) {
535 1.1.1.6 christos fprintf( stderr, "%s: line %d: "
536 1.1.1.6 christos "no attributes specified: %s\n",
537 1.1.1.6 christos fname, lineno, argv[0] );
538 1.1.1.6 christos return LDAP_PARAM_ERROR;
539 1.1.1.6 christos }
540 1.1.1.6 christos
541 1.1.1.6 christos hi = strtoul( argv[1], &next, 10 );
542 1.1.1.6 christos if ( next == argv[1] || next[0] != ',' )
543 1.1.1.6 christos goto badval;
544 1.1.1.6 christos s = next+1;
545 1.1.1.6 christos lo = strtoul( s, &next, 10 );
546 1.1.1.6 christos if ( next == s || next[0] != '\0' )
547 1.1.1.6 christos goto badval;
548 1.1.1.6 christos
549 1.1.1.6 christos if ( lo > hi ) {
550 1.1.1.6 christos badval:
551 1.1.1.6 christos snprintf(c_reply->msg, sizeof(c_reply->msg),
552 1.1.1.6 christos "invalid hi/lo thresholds" );
553 1.1.1.6 christos fprintf( stderr, "%s: line %d: %s\n",
554 1.1.1.6 christos fname, lineno, c_reply->msg );
555 1.1.1.6 christos return LDAP_PARAM_ERROR;
556 1.1.1.6 christos }
557 1.1.1.6 christos
558 1.1.1.6 christos for ( i = 0; attrs[i] != NULL; i++ ) {
559 1.1.1.6 christos AttrInfo *a;
560 1.1.1.6 christos AttributeDescription *ad;
561 1.1.1.6 christos const char *text;
562 1.1.1.6 christos
563 1.1.1.6 christos if( strcasecmp( attrs[i], "default" ) == 0 ) {
564 1.1.1.6 christos mdb->mi_multi_hi = hi;
565 1.1.1.6 christos mdb->mi_multi_lo = lo;
566 1.1.1.6 christos continue;
567 1.1.1.6 christos }
568 1.1.1.6 christos
569 1.1.1.6 christos ad = NULL;
570 1.1.1.6 christos rc = slap_str2ad( attrs[i], &ad, &text );
571 1.1.1.6 christos
572 1.1.1.6 christos if( rc != LDAP_SUCCESS ) {
573 1.1.1.6 christos if ( c_reply )
574 1.1.1.6 christos {
575 1.1.1.6 christos snprintf(c_reply->msg, sizeof(c_reply->msg),
576 1.1.1.6 christos "multival attribute \"%s\" undefined",
577 1.1.1.6 christos attrs[i] );
578 1.1.1.6 christos
579 1.1.1.6 christos fprintf( stderr, "%s: line %d: %s\n",
580 1.1.1.6 christos fname, lineno, c_reply->msg );
581 1.1.1.6 christos }
582 1.1.1.6 christos fail:
583 1.1.1.6 christos goto done;
584 1.1.1.6 christos }
585 1.1.1.6 christos
586 1.1.1.6 christos a = (AttrInfo *) ch_calloc( 1, sizeof(AttrInfo) );
587 1.1.1.6 christos
588 1.1.1.6 christos a->ai_desc = ad;
589 1.1.1.6 christos a->ai_multi_hi = hi;
590 1.1.1.6 christos a->ai_multi_lo = lo;
591 1.1.1.6 christos
592 1.1.1.6 christos rc = ainfo_insert( mdb, a );
593 1.1.1.6 christos if( rc ) {
594 1.1.1.6 christos AttrInfo *b = mdb_attr_mask( mdb, ad );
595 1.1.1.6 christos /* If this is just an index record, reuse it for multival info */
596 1.1.1.6 christos if ( b->ai_multi_lo == UINT_MAX ) {
597 1.1.1.6 christos b->ai_multi_hi = a->ai_multi_hi;
598 1.1.1.6 christos b->ai_multi_lo = a->ai_multi_lo;
599 1.1.1.6 christos ch_free( a );
600 1.1.1.6 christos rc = 0;
601 1.1.1.6 christos continue;
602 1.1.1.6 christos }
603 1.1.1.6 christos if (c_reply) {
604 1.1.1.6 christos snprintf(c_reply->msg, sizeof(c_reply->msg),
605 1.1.1.6 christos "duplicate multival definition for attr \"%s\"",
606 1.1.1.6 christos attrs[i] );
607 1.1.1.6 christos fprintf( stderr, "%s: line %d: %s\n",
608 1.1.1.6 christos fname, lineno, c_reply->msg );
609 1.1.1.6 christos }
610 1.1.1.6 christos
611 1.1.1.6 christos rc = LDAP_PARAM_ERROR;
612 1.1.1.6 christos goto done;
613 1.1.1.6 christos }
614 1.1.1.6 christos }
615 1.1.1.6 christos
616 1.1.1.6 christos done:
617 1.1.1.6 christos ldap_charray_free( attrs );
618 1.1.1.6 christos
619 1.1.1.6 christos return rc;
620 1.1.1.6 christos }
621 1.1.1.6 christos
622 1.1.1.6 christos static int
623 1.1.1.6 christos mdb_attr_multi_unparser( void *v1, void *v2 )
624 1.1.1.6 christos {
625 1.1.1.6 christos AttrInfo *ai = v1;
626 1.1.1.6 christos BerVarray *bva = v2;
627 1.1.1.6 christos struct berval bv;
628 1.1.1.6 christos char digbuf[sizeof("4294967296,4294967296")];
629 1.1.1.6 christos char *ptr;
630 1.1.1.6 christos
631 1.1.1.6 christos bv.bv_len = snprintf( digbuf, sizeof(digbuf), "%u,%u",
632 1.1.1.6 christos ai->ai_multi_hi, ai->ai_multi_lo );
633 1.1.1.6 christos if ( bv.bv_len ) {
634 1.1.1.6 christos bv.bv_len += ai->ai_desc->ad_cname.bv_len + 1;
635 1.1.1.6 christos ptr = ch_malloc( bv.bv_len+1 );
636 1.1.1.6 christos bv.bv_val = lutil_strcopy( ptr, ai->ai_desc->ad_cname.bv_val );
637 1.1.1.6 christos *bv.bv_val++ = ' ';
638 1.1.1.6 christos strcpy(bv.bv_val, digbuf);
639 1.1.1.6 christos bv.bv_val = ptr;
640 1.1.1.6 christos ber_bvarray_add( bva, &bv );
641 1.1.1.6 christos }
642 1.1.1.6 christos return 0;
643 1.1.1.6 christos }
644 1.1.1.6 christos
645 1.1.1.6 christos void
646 1.1.1.6 christos mdb_attr_multi_unparse( struct mdb_info *mdb, BerVarray *bva )
647 1.1.1.6 christos {
648 1.1.1.6 christos int i;
649 1.1.1.6 christos
650 1.1.1.6 christos if ( mdb->mi_multi_hi < UINT_MAX ) {
651 1.1.1.6 christos aidef.ai_multi_hi = mdb->mi_multi_hi;
652 1.1.1.6 christos aidef.ai_multi_lo = mdb->mi_multi_lo;
653 1.1.1.6 christos mdb_attr_multi_unparser( &aidef, bva );
654 1.1.1.6 christos }
655 1.1.1.6 christos for ( i=0; i<mdb->mi_nattrs; i++ )
656 1.1.1.6 christos if ( mdb->mi_attrs[i]->ai_multi_hi < UINT_MAX )
657 1.1.1.6 christos mdb_attr_multi_unparser( mdb->mi_attrs[i], bva );
658 1.1.1.6 christos }
659 1.1.1.6 christos
660 1.1.1.6 christos void
661 1.1.1.6 christos mdb_attr_multi_thresh( struct mdb_info *mdb, AttributeDescription *ad, unsigned *hi, unsigned *lo )
662 1.1.1.6 christos {
663 1.1.1.6 christos AttrInfo *ai = mdb_attr_mask( mdb, ad );
664 1.1.1.6 christos if ( ai && ai->ai_multi_hi < UINT_MAX )
665 1.1.1.6 christos {
666 1.1.1.6 christos if ( hi )
667 1.1.1.6 christos *hi = ai->ai_multi_hi;
668 1.1.1.6 christos if ( lo )
669 1.1.1.6 christos *lo = ai->ai_multi_lo;
670 1.1.1.6 christos } else
671 1.1.1.6 christos {
672 1.1.1.6 christos if ( hi )
673 1.1.1.6 christos *hi = mdb->mi_multi_hi;
674 1.1.1.6 christos if ( lo )
675 1.1.1.6 christos *lo = mdb->mi_multi_lo;
676 1.1.1.6 christos }
677 1.1 tron }
678 1.1 tron
679 1.1 tron void
680 1.1 tron mdb_attr_info_free( AttrInfo *ai )
681 1.1 tron {
682 1.1 tron #ifdef LDAP_COMP_MATCH
683 1.1 tron free( ai->ai_cr );
684 1.1 tron #endif
685 1.1 tron free( ai );
686 1.1 tron }
687 1.1 tron
688 1.1 tron void
689 1.1 tron mdb_attr_index_destroy( struct mdb_info *mdb )
690 1.1 tron {
691 1.1 tron int i;
692 1.1 tron
693 1.1 tron for ( i=0; i<mdb->mi_nattrs; i++ )
694 1.1 tron mdb_attr_info_free( mdb->mi_attrs[i] );
695 1.1 tron
696 1.1 tron free( mdb->mi_attrs );
697 1.1 tron }
698 1.1 tron
699 1.1 tron void mdb_attr_index_free( struct mdb_info *mdb, AttributeDescription *ad )
700 1.1 tron {
701 1.1 tron int i;
702 1.1 tron
703 1.1 tron i = mdb_attr_slot( mdb, ad, NULL );
704 1.1 tron if ( i >= 0 ) {
705 1.1 tron mdb_attr_info_free( mdb->mi_attrs[i] );
706 1.1 tron mdb->mi_nattrs--;
707 1.1 tron for (; i<mdb->mi_nattrs; i++)
708 1.1 tron mdb->mi_attrs[i] = mdb->mi_attrs[i+1];
709 1.1 tron }
710 1.1 tron }
711 1.1 tron
712 1.1 tron void mdb_attr_flush( struct mdb_info *mdb )
713 1.1 tron {
714 1.1 tron int i;
715 1.1 tron
716 1.1 tron for ( i=0; i<mdb->mi_nattrs; i++ ) {
717 1.1 tron if ( mdb->mi_attrs[i]->ai_indexmask & MDB_INDEX_DELETING ) {
718 1.1.1.6 christos /* if this is also a multival rec, just clear index */
719 1.1.1.6 christos if ( mdb->mi_attrs[i]->ai_multi_lo < UINT_MAX ) {
720 1.1.1.6 christos mdb->mi_attrs[i]->ai_indexmask = 0;
721 1.1.1.6 christos mdb->mi_attrs[i]->ai_newmask = 0;
722 1.1.1.6 christos } else {
723 1.1.1.6 christos int j;
724 1.1.1.6 christos mdb_attr_info_free( mdb->mi_attrs[i] );
725 1.1.1.6 christos mdb->mi_nattrs--;
726 1.1.1.6 christos for (j=i; j<mdb->mi_nattrs; j++)
727 1.1.1.6 christos mdb->mi_attrs[j] = mdb->mi_attrs[j+1];
728 1.1.1.6 christos i--;
729 1.1.1.6 christos }
730 1.1 tron }
731 1.1 tron }
732 1.1 tron }
733 1.1 tron
734 1.1 tron int mdb_ad_read( struct mdb_info *mdb, MDB_txn *txn )
735 1.1 tron {
736 1.1 tron int i, rc;
737 1.1 tron MDB_cursor *mc;
738 1.1 tron MDB_val key, data;
739 1.1 tron struct berval bdata;
740 1.1 tron const char *text;
741 1.1 tron AttributeDescription *ad;
742 1.1 tron
743 1.1 tron rc = mdb_cursor_open( txn, mdb->mi_ad2id, &mc );
744 1.1 tron if ( rc ) {
745 1.1 tron Debug( LDAP_DEBUG_ANY,
746 1.1 tron "mdb_ad_read: cursor_open failed %s(%d)\n",
747 1.1.1.6 christos mdb_strerror(rc), rc );
748 1.1 tron return rc;
749 1.1 tron }
750 1.1 tron
751 1.1 tron /* our array is 1-based, an index of 0 means no data */
752 1.1 tron i = mdb->mi_numads+1;
753 1.1 tron key.mv_size = sizeof(int);
754 1.1 tron key.mv_data = &i;
755 1.1 tron
756 1.1 tron rc = mdb_cursor_get( mc, &key, &data, MDB_SET );
757 1.1 tron
758 1.1 tron while ( rc == MDB_SUCCESS ) {
759 1.1 tron bdata.bv_len = data.mv_size;
760 1.1 tron bdata.bv_val = data.mv_data;
761 1.1 tron ad = NULL;
762 1.1 tron rc = slap_bv2ad( &bdata, &ad, &text );
763 1.1 tron if ( rc ) {
764 1.1 tron rc = slap_bv2undef_ad( &bdata, &mdb->mi_ads[i], &text, 0 );
765 1.1 tron } else {
766 1.1 tron if ( ad->ad_index >= MDB_MAXADS ) {
767 1.1 tron Debug( LDAP_DEBUG_ANY,
768 1.1.1.6 christos "mdb_adb_read: too many AttributeDescriptions in use\n" );
769 1.1 tron return LDAP_OTHER;
770 1.1 tron }
771 1.1 tron mdb->mi_adxs[ad->ad_index] = i;
772 1.1 tron mdb->mi_ads[i] = ad;
773 1.1 tron }
774 1.1 tron i++;
775 1.1 tron rc = mdb_cursor_get( mc, &key, &data, MDB_NEXT );
776 1.1 tron }
777 1.1 tron mdb->mi_numads = i-1;
778 1.1 tron
779 1.1 tron done:
780 1.1 tron if ( rc == MDB_NOTFOUND )
781 1.1 tron rc = 0;
782 1.1 tron
783 1.1 tron mdb_cursor_close( mc );
784 1.1 tron
785 1.1 tron return rc;
786 1.1 tron }
787 1.1 tron
788 1.1 tron int mdb_ad_get( struct mdb_info *mdb, MDB_txn *txn, AttributeDescription *ad )
789 1.1 tron {
790 1.1 tron int i, rc;
791 1.1 tron MDB_val key, val;
792 1.1 tron
793 1.1 tron rc = mdb_ad_read( mdb, txn );
794 1.1 tron if (rc)
795 1.1 tron return rc;
796 1.1 tron
797 1.1 tron if ( mdb->mi_adxs[ad->ad_index] )
798 1.1 tron return 0;
799 1.1 tron
800 1.1 tron i = mdb->mi_numads+1;
801 1.1 tron key.mv_size = sizeof(int);
802 1.1 tron key.mv_data = &i;
803 1.1 tron val.mv_size = ad->ad_cname.bv_len;
804 1.1 tron val.mv_data = ad->ad_cname.bv_val;
805 1.1 tron
806 1.1 tron rc = mdb_put( txn, mdb->mi_ad2id, &key, &val, 0 );
807 1.1 tron if ( rc == MDB_SUCCESS ) {
808 1.1 tron mdb->mi_adxs[ad->ad_index] = i;
809 1.1 tron mdb->mi_ads[i] = ad;
810 1.1.1.2 christos mdb->mi_numads = i;
811 1.1 tron } else {
812 1.1 tron Debug( LDAP_DEBUG_ANY,
813 1.1 tron "mdb_ad_get: mdb_put failed %s(%d)\n",
814 1.1.1.6 christos mdb_strerror(rc), rc );
815 1.1 tron }
816 1.1 tron
817 1.1 tron return rc;
818 1.1 tron }
819 1.1.1.5 christos
820 1.1.1.5 christos void mdb_ad_unwind( struct mdb_info *mdb, int prev_ads )
821 1.1.1.5 christos {
822 1.1.1.5 christos int i;
823 1.1.1.5 christos
824 1.1.1.5 christos for (i=mdb->mi_numads; i>prev_ads; i--) {
825 1.1.1.5 christos mdb->mi_adxs[mdb->mi_ads[i]->ad_index] = 0;
826 1.1.1.5 christos mdb->mi_ads[i] = NULL;
827 1.1.1.5 christos }
828 1.1.1.5 christos mdb->mi_numads = i;
829 1.1.1.5 christos }
830