From 7bcdfe9532ea42d3a111707ab3b649cd602f2fbb Mon Sep 17 00:00:00 2001 From: Howard Chu Date: Sat, 29 Sep 2007 11:55:21 +0000 Subject: [PATCH] ITS#5153 from HEAD - sorted values --- doc/man/man5/slapd-config.5 | 84 ++++--- doc/man/man5/slapd.conf.5 | 11 + servers/slapd/aci.c | 5 +- servers/slapd/acl.c | 10 +- servers/slapd/add.c | 25 +- servers/slapd/attr.c | 199 +++++++++++++--- servers/slapd/back-bdb/compare.c | 4 +- servers/slapd/back-bdb/monitor.c | 17 +- servers/slapd/back-ldap/search.c | 8 +- servers/slapd/back-meta/search.c | 1 + servers/slapd/back-monitor/compare.c | 4 +- servers/slapd/back-sql/compare.c | 5 +- servers/slapd/back-sql/entry-id.c | 8 +- servers/slapd/back-sql/operational.c | 2 + servers/slapd/backend.c | 8 +- servers/slapd/bconfig.c | 99 +++++++- servers/slapd/compare.c | 4 +- servers/slapd/entry.c | 35 ++- servers/slapd/filterentry.c | 57 ++++- servers/slapd/modify.c | 344 ++++++++++++++------------- servers/slapd/modrdn.c | 2 + servers/slapd/mods.c | 207 ++++++++-------- servers/slapd/operational.c | 3 + servers/slapd/overlays/accesslog.c | 24 +- servers/slapd/overlays/dds.c | 2 + servers/slapd/overlays/dynlist.c | 15 +- servers/slapd/overlays/memberof.c | 15 +- servers/slapd/overlays/pcache.c | 5 +- servers/slapd/overlays/ppolicy.c | 10 + servers/slapd/overlays/refint.c | 10 +- servers/slapd/overlays/rwm.c | 12 +- servers/slapd/overlays/syncprov.c | 15 +- servers/slapd/overlays/translucent.c | 4 + servers/slapd/overlays/valsort.c | 4 +- servers/slapd/passwd.c | 1 + servers/slapd/proto-slap.h | 18 +- servers/slapd/sasl.c | 1 + servers/slapd/schema_check.c | 4 +- servers/slapd/slap.h | 43 ++-- servers/slapd/slapi/slapi_utils.c | 42 ++-- servers/slapd/syncrepl.c | 25 +- servers/slapd/value.c | 15 +- 42 files changed, 891 insertions(+), 516 deletions(-) diff --git a/doc/man/man5/slapd-config.5 b/doc/man/man5/slapd-config.5 index 146dc30131..0d88236129 100644 --- a/doc/man/man5/slapd-config.5 +++ b/doc/man/man5/slapd-config.5 @@ -479,6 +479,8 @@ lookup. The default is 2. For example, with the default values, a search using this filter "cn=*abcdefgh*" would generate index lookups for "abcd", "cdef", and "efgh". +Note: Indexing support depends on the particular backend in use. + .TP .B olcLocalSSF: Specifies the Security Strength Factor (SSF) to be given local LDAP sessions, @@ -616,42 +618,6 @@ versions of crypt(3) to use an MD5 algorithm and provides 8 random characters of salt. The default is "%s", which provides 31 characters of salt. .TP -.B olcPasswordHash: [...] -This option configures one or more hashes to be used in generation of user -passwords stored in the userPassword attribute during processing of -LDAP Password Modify Extended Operations (RFC 3062). -The must be one of -.BR {SSHA} , -.BR {SHA} , -.BR {SMD5} , -.BR {MD5} , -.BR {CRYPT} , -and -.BR {CLEARTEXT} . -The default is -.BR {SSHA} . - -.B {SHA} -and -.B {SSHA} -use the SHA-1 algorithm (FIPS 160-1), the latter with a seed. - -.B {MD5} -and -.B {SMD5} -use the MD5 algorithm (RFC 1321), the latter with a seed. - -.B {CRYPT} -uses the -.BR crypt (3). - -.B {CLEARTEXT} -indicates that the new password should be -added to userPassword as clear text. - -Note that this option does not alter the normal user applications -handling of userPassword during LDAP Add, Modify, or other LDAP operations. -.TP .B olcPidFile: The ( absolute ) name of a file that will hold the .B slapd @@ -1079,6 +1045,43 @@ non-base search request with an empty base DN. Base scoped search requests with an empty base DN are not affected. This setting is only allowed in the frontend entry. .TP +.B olcPasswordHash: [...] +This option configures one or more hashes to be used in generation of user +passwords stored in the userPassword attribute during processing of +LDAP Password Modify Extended Operations (RFC 3062). +The must be one of +.BR {SSHA} , +.BR {SHA} , +.BR {SMD5} , +.BR {MD5} , +.BR {CRYPT} , +and +.BR {CLEARTEXT} . +The default is +.BR {SSHA} . + +.B {SHA} +and +.B {SSHA} +use the SHA-1 algorithm (FIPS 160-1), the latter with a seed. + +.B {MD5} +and +.B {SMD5} +use the MD5 algorithm (RFC 1321), the latter with a seed. + +.B {CRYPT} +uses the +.BR crypt (3). + +.B {CLEARTEXT} +indicates that the new password should be +added to userPassword as clear text. + +Note that this option does not alter the normal user applications +handling of userPassword during LDAP Add, Modify, or other LDAP operations. +This setting is only allowed in the frontend entry. +.TP .B olcReadOnly: TRUE | FALSE This option puts the database into "read-only" mode. Any attempts to modify the database will return an "unwilling to perform" error. By @@ -1189,6 +1192,15 @@ See .BR olcLimits for an explanation of the different flags. .TP +.B olcSortVals [...] +Specify a list of multi-valued attributes whose values will always +be maintained in sorted order. Using this option will allow Modify, +Compare, and filter evaluations on these attributes to be performed +more efficiently. The resulting sort order depends on the +attributes' syntax and matching rules and may not correspond to +lexical order or any other recognizable order. +This setting is only allowed in the frontend entry. +.TP .B olcTimeLimit: {|unlimited} .TP .B olcTimeLimit: time[.{soft|hard}]= [...] diff --git a/doc/man/man5/slapd.conf.5 b/doc/man/man5/slapd.conf.5 index e5c5a1cc2e..5d9fc030e1 100644 --- a/doc/man/man5/slapd.conf.5 +++ b/doc/man/man5/slapd.conf.5 @@ -495,6 +495,9 @@ for the segments of a filter string that are processed for a subany index lookup. The default is 2. For example, with the default values, a search using this filter "cn=*abcdefgh*" would generate index lookups for "abcd", "cdef", and "efgh". + +Note: Indexing support depends on the particular backend in use. + .TP .B localSSF Specifies the Security Strength Factor (SSF) to be given local LDAP sessions, @@ -891,6 +894,14 @@ The default is 262143. Specify the maximum incoming LDAP PDU size for authenticated sessions. The default is 4194303. .TP +.B sortvals [...] +Specify a list of multi-valued attributes whose values will always +be maintained in sorted order. Using this option will allow Modify, +Compare, and filter evaluations on these attributes to be performed +more efficiently. The resulting sort order depends on the +attributes' syntax and matching rules and may not correspond to +lexical order or any other recognizable order. +.TP .B threads Specify the maximum size of the primary thread pool. The default is 16; the minimum value is 2. diff --git a/servers/slapd/aci.c b/servers/slapd/aci.c index ac786ace75..0acf6c108f 100644 --- a/servers/slapd/aci.c +++ b/servers/slapd/aci.c @@ -592,11 +592,10 @@ aci_mask( at != NULL; at = attrs_find( at->a_next, ad ) ) { - if ( value_find_ex( ad, + if ( attr_valfind( at, SLAP_MR_ATTRIBUTE_VALUE_NORMALIZED_MATCH | SLAP_MR_ASSERTED_VALUE_NORMALIZED_MATCH, - at->a_nvals, - &op->o_ndn, op->o_tmpmemctx ) == 0 ) + &op->o_ndn, NULL, op->o_tmpmemctx ) == 0 ) { rc = 1; break; diff --git a/servers/slapd/acl.c b/servers/slapd/acl.c index 5647ce57fd..adcfc15084 100644 --- a/servers/slapd/acl.c +++ b/servers/slapd/acl.c @@ -974,11 +974,10 @@ acl_mask_dnattr( at != NULL; at = attrs_find( at->a_next, bdn->a_at ) ) { - if ( value_find_ex( bdn->a_at, + if ( attr_valfind( at, SLAP_MR_ATTRIBUTE_VALUE_NORMALIZED_MATCH | SLAP_MR_ASSERTED_VALUE_NORMALIZED_MATCH, - at->a_nvals, - &bv, op->o_tmpmemctx ) == 0 ) + &bv, NULL, op->o_tmpmemctx ) == 0 ) { /* found it */ match = 1; @@ -2043,11 +2042,6 @@ acl_set_cb_gather( Operation *op, SlapReply *rs ) a = attr_find( rs->sr_entry->e_attrs, desc ); if ( a != NULL ) { - int i; - - for ( i = 0; !BER_BVISNULL( &a->a_nvals[ i ] ); i++ ) - ; - bvalsp = a->a_nvals; } } diff --git a/servers/slapd/add.c b/servers/slapd/add.c index 280fb4f20f..9c6ca2e6ee 100644 --- a/servers/slapd/add.c +++ b/servers/slapd/add.c @@ -380,6 +380,7 @@ slap_mods2entry( char *textbuf, size_t textlen ) { Attribute **tail; + int i; if ( initial ) { assert( (*e)->e_attrs == NULL ); @@ -400,7 +401,7 @@ slap_mods2entry( if( attr != NULL ) { #define SLURPD_FRIENDLY #ifdef SLURPD_FRIENDLY - ber_len_t i,j; + int j; if ( !initial ) { /* @@ -413,12 +414,9 @@ slap_mods2entry( return LDAP_SUCCESS; } - for( i=0; attr->a_vals[i].bv_val; i++ ) { - /* count them */ - } - for( j=0; mods->sml_values[j].bv_val; j++ ) { - /* count them */ - } + i = attr->a_numvals; + j = mods->sml_numvals; + attr->a_numvals += j; j++; /* NULL */ attr->a_vals = ch_realloc( attr->a_vals, @@ -466,9 +464,9 @@ slap_mods2entry( attr = attr_alloc( mods->sml_desc ); /* move values to attr structure */ + i = mods->sml_numvals; + attr->a_numvals = mods->sml_numvals; if ( dup ) { - int i; - for ( i = 0; mods->sml_values[i].bv_val; i++ ) /* EMPTY */; attr->a_vals = (BerVarray) ch_calloc( i+1, sizeof( BerValue )); for ( i = 0; mods->sml_values[i].bv_val; i++ ) { ber_dupbv( &attr->a_vals[i], &mods->sml_values[i] ); @@ -480,8 +478,7 @@ slap_mods2entry( if ( mods->sml_nvalues ) { if ( dup ) { - int i; - for ( i = 0; mods->sml_nvalues[i].bv_val; i++ ) /* EMPTY */; + i = mods->sml_numvals; attr->a_nvals = (BerVarray) ch_calloc( i+1, sizeof( BerValue )); for ( i = 0; mods->sml_nvalues[i].bv_val; i++ ) { ber_dupbv( &attr->a_nvals[i], &mods->sml_nvalues[i] ); @@ -493,6 +490,9 @@ slap_mods2entry( } else { attr->a_nvals = attr->a_vals; } + /* slap_mods_check() gives us sorted results */ + if ( attr->a_desc->ad_type->sat_flags & SLAP_AT_SORTED_VAL ) + attr->a_flags |= SLAP_ATTR_SORTED_VALS; *tail = attr; tail = &attr->a_next; @@ -528,7 +528,8 @@ slap_entry2mods( mod->sml_type = a_new_desc->ad_cname; - for ( count = 0; a_new->a_vals[count].bv_val; count++ ) /* EMPTY */; + count = a_new->a_numvals; + mod->sml_numvals = a_new->a_numvals; mod->sml_values = (struct berval*) malloc( (count+1) * sizeof( struct berval) ); diff --git a/servers/slapd/attr.c b/servers/slapd/attr.c index 315442466f..e66b65a841 100644 --- a/servers/slapd/attr.c +++ b/servers/slapd/attr.c @@ -153,6 +153,7 @@ attr_clean( Attribute *a ) a->a_comp_data = NULL; #endif a->a_flags = 0; + a->a_numvals = 0; } void @@ -210,15 +211,13 @@ attrs_free( Attribute *a ) static void attr_dup2( Attribute *tmp, Attribute *a ) { + tmp->a_flags = a->a_flags & SLAP_ATTR_PERSISTENT_FLAGS; if ( a->a_vals != NULL ) { int i; - for ( i = 0; !BER_BVISNULL( &a->a_vals[i] ); i++ ) { - /* EMPTY */ ; - } - - tmp->a_vals = ch_malloc( (i + 1) * sizeof(struct berval) ); - for ( i = 0; !BER_BVISNULL( &a->a_vals[i] ); i++ ) { + tmp->a_numvals = a->a_numvals; + tmp->a_vals = ch_malloc( (tmp->a_numvals + 1) * sizeof(struct berval) ); + for ( i = 0; i < tmp->a_numvals; i++ ) { ber_dupbv( &tmp->a_vals[i], &a->a_vals[i] ); if ( BER_BVISNULL( &tmp->a_vals[i] ) ) break; /* FIXME: error? */ @@ -231,7 +230,7 @@ attr_dup2( Attribute *tmp, Attribute *a ) if ( a->a_nvals != a->a_vals ) { int j; - tmp->a_nvals = ch_malloc( (i + 1) * sizeof(struct berval) ); + tmp->a_nvals = ch_malloc( (tmp->a_numvals + 1) * sizeof(struct berval) ); for ( j = 0; !BER_BVISNULL( &a->a_nvals[j] ); j++ ) { assert( j < i ); ber_dupbv( &tmp->a_nvals[j], &a->a_nvals[j] ); @@ -283,6 +282,163 @@ attrs_dup( Attribute *a ) return anew; } +int +attr_valfind( + Attribute *a, + unsigned flags, + struct berval *val, + unsigned *slot, + void *ctx ) +{ + struct berval nval = BER_BVNULL, *cval; + MatchingRule *mr; + const char *text; + int match = -1, rc; + unsigned i; + + if ( flags & SLAP_MR_ORDERING ) + mr = a->a_desc->ad_type->sat_ordering; + else + mr = a->a_desc->ad_type->sat_equality; + + if( !SLAP_IS_MR_ASSERTED_VALUE_NORMALIZED_MATCH( flags ) && + mr->smr_normalize ) + { + rc = (mr->smr_normalize)( + flags & (SLAP_MR_TYPE_MASK|SLAP_MR_SUBTYPE_MASK|SLAP_MR_VALUE_OF_SYNTAX), + a->a_desc->ad_type->sat_syntax, + mr, val, &nval, ctx ); + + if( rc != LDAP_SUCCESS ) { + return LDAP_INVALID_SYNTAX; + } + cval = &nval; + } else { + cval = val; + } + + if ( a->a_flags & SLAP_ATTR_SORTED_VALS ) { + /* Binary search */ + unsigned base = 0, n = a->a_numvals; + int val = 0; + + while ( 0 < n ) { + unsigned pivot = n >> 1; + i = base + pivot; + if ( i >= a->a_numvals ) { + i = a->a_numvals - 1; + break; + } + rc = value_match( &match, a->a_desc, mr, flags, + &a->a_nvals[i], cval, &text ); + if ( rc == LDAP_SUCCESS && match == 0 ) + break; + n = pivot; + if ( match < 0 ) + base = i+1; + } + if ( match < 0 ) + i++; + } else { + /* Linear search */ + for ( i = 0; i < a->a_numvals; i++ ) { + const char *text; + + rc = ordered_value_match( &match, a->a_desc, mr, flags, + &a->a_nvals[i], cval, &text ); + if ( rc == LDAP_SUCCESS && match == 0 ) + break; + } + } + if ( slot ) + *slot = i; + if ( match ) + rc = LDAP_NO_SUCH_ATTRIBUTE; + if ( nval.bv_val ) + slap_sl_free( nval.bv_val, ctx ); + + return rc; +} + +int +attr_valadd( + Attribute *a, + BerVarray vals, + BerVarray nvals, + int nn ) +{ + int i; + BerVarray v2; + + v2 = (BerVarray) SLAP_REALLOC( (char *) a->a_vals, + (a->a_numvals + nn + 1) * sizeof(struct berval) ); + if( v2 == NULL ) { + Debug(LDAP_DEBUG_TRACE, + "attr_valadd: SLAP_REALLOC failed.\n", 0, 0, 0 ); + return LBER_ERROR_MEMORY; + } + a->a_vals = v2; + if ( nvals ) { + v2 = (BerVarray) SLAP_REALLOC( (char *) a->a_nvals, + (a->a_numvals + nn + 1) * sizeof(struct berval) ); + if( v2 == NULL ) { + Debug(LDAP_DEBUG_TRACE, + "attr_valadd: SLAP_REALLOC failed.\n", 0, 0, 0 ); + return LBER_ERROR_MEMORY; + } + a->a_nvals = v2; + } else { + a->a_nvals = a->a_vals; + } + + /* If sorted and old vals exist, must insert */ + if (( a->a_flags & SLAP_ATTR_SORTED_VALS ) && a->a_numvals ) { + unsigned slot; + int j, rc; + v2 = nvals ? nvals : vals; + for ( i = 0; i < nn; i++ ) { + rc = attr_valfind( a, SLAP_MR_EQUALITY | SLAP_MR_VALUE_OF_ASSERTION_SYNTAX | + SLAP_MR_ASSERTED_VALUE_NORMALIZED_MATCH | SLAP_MR_ATTRIBUTE_VALUE_NORMALIZED_MATCH, + &v2[i], &slot, NULL ); + if ( rc != LDAP_NO_SUCH_ATTRIBUTE ) { + /* should never happen */ + if ( rc == LDAP_SUCCESS ) + rc = LDAP_TYPE_OR_VALUE_EXISTS; + return rc; + } + for ( j = a->a_numvals; j >= slot; j-- ) { + a->a_vals[j+1] = a->a_vals[j]; + if ( nvals ) + a->a_nvals[j+1] = a->a_nvals[j]; + } + ber_dupbv( &a->a_nvals[slot], &v2[i] ); + if ( nvals ) + ber_dupbv( &a->a_vals[slot], &vals[i] ); + a->a_numvals++; + } + BER_BVZERO( &a->a_vals[a->a_numvals] ); + if ( a->a_vals != a->a_nvals ) + BER_BVZERO( &a->a_nvals[a->a_numvals] ); + } else { + v2 = &a->a_vals[a->a_numvals]; + for ( i = 0 ; i < nn; i++ ) { + ber_dupbv( &v2[i], &vals[i] ); + if ( BER_BVISNULL( &v2[i] ) ) break; + } + BER_BVZERO( &v2[i] ); + + if ( nvals ) { + v2 = &a->a_nvals[a->a_numvals]; + for ( i = 0 ; i < nn; i++ ) { + ber_dupbv( &v2[i], &nvals[i] ); + if ( BER_BVISNULL( &v2[i] ) ) break; + } + BER_BVZERO( &v2[i] ); + } + a->a_numvals += i; + } + return 0; +} /* * attr_merge - merge the given type and value with the list of @@ -302,7 +458,7 @@ attr_merge( BerVarray vals, BerVarray nvals ) { - int rc; + int i = 0; Attribute **a; @@ -325,18 +481,10 @@ attr_merge( || ( (*a)->a_nvals != (*a)->a_vals ) ) ) ); } - rc = value_add( &(*a)->a_vals, vals ); - - if ( rc == LDAP_SUCCESS ) { - if ( nvals ) { - rc = value_add( &(*a)->a_nvals, nvals ); - /* FIXME: what if rc != LDAP_SUCCESS ? */ - } else { - (*a)->a_nvals = (*a)->a_vals; - } + if ( vals != NULL ) { + for ( ; !BER_BVISNULL( &vals[i] ); i++ ) ; } - - return rc; + return attr_valadd( *a, vals, nvals, i ); } /* @@ -415,7 +563,6 @@ attr_merge_one( struct berval *val, struct berval *nval ) { - int rc; Attribute **a; for ( a = &e->e_attrs; *a != NULL; a = &(*a)->a_next ) { @@ -428,17 +575,7 @@ attr_merge_one( *a = attr_alloc( desc ); } - rc = value_add_one( &(*a)->a_vals, val ); - - if ( rc == LDAP_SUCCESS ) { - if ( nval ) { - rc = value_add_one( &(*a)->a_nvals, nval ); - /* FIXME: what if rc != LDAP_SUCCESS ? */ - } else { - (*a)->a_nvals = (*a)->a_vals; - } - } - return rc; + return attr_valadd( *a, val, nval, 1 ); } /* diff --git a/servers/slapd/back-bdb/compare.c b/servers/slapd/back-bdb/compare.c index 972071314c..538d1da61a 100644 --- a/servers/slapd/back-bdb/compare.c +++ b/servers/slapd/back-bdb/compare.c @@ -158,10 +158,10 @@ dn2entry_retry: { rs->sr_err = LDAP_COMPARE_FALSE; - if ( value_find_ex( op->oq_compare.rs_ava->aa_desc, + if ( attr_valfind( a, SLAP_MR_ATTRIBUTE_VALUE_NORMALIZED_MATCH | SLAP_MR_ASSERTED_VALUE_NORMALIZED_MATCH, - a->a_nvals, &op->oq_compare.rs_ava->aa_value, + &op->oq_compare.rs_ava->aa_value, NULL, op->o_tmpmemctx ) == 0 ) { rs->sr_err = LDAP_COMPARE_TRUE; diff --git a/servers/slapd/back-bdb/monitor.c b/servers/slapd/back-bdb/monitor.c index f30469702c..2271940de1 100644 --- a/servers/slapd/back-bdb/monitor.c +++ b/servers/slapd/back-bdb/monitor.c @@ -210,6 +210,7 @@ bdb_monitor_free( mod.sm_op = LDAP_MOD_DELETE; mod.sm_desc = slap_schema.si_ad_objectClass; mod.sm_values = values; + mod.sm_numvals = 1; values[ 0 ] = oc_olmBDBDatabase->soc_cname; BER_BVZERO( &values[ 1 ] ); @@ -218,9 +219,10 @@ bdb_monitor_free( /* don't care too much about return code... */ /* remove attrs */ + mod.sm_values = NULL; + mod.sm_numvals = 0; for ( i = 0; s_at[ i ].desc != NULL; i++ ) { mod.sm_desc = *s_at[ i ].ad; - mod.sm_values = NULL; rc = modify_delete_values( e, &mod, 1, &text, textbuf, sizeof( textbuf ) ); /* don't care too much about return code... */ @@ -371,26 +373,22 @@ bdb_monitor_db_open( BackendDB *be ) } a->a_desc = slap_schema.si_ad_objectClass; - value_add_one( &a->a_vals, &oc_olmBDBDatabase->soc_cname ); - a->a_nvals = a->a_vals; + attr_valadd( a, &oc_olmBDBDatabase->soc_cname, NULL, 1 ); next = a->a_next; { struct berval bv = BER_BVC( "0" ); next->a_desc = ad_olmBDBEntryCache; - value_add_one( &next->a_vals, &bv ); - next->a_nvals = next->a_vals; + attr_valadd( next, &bv, NULL, 1 ); next = next->a_next; next->a_desc = ad_olmBDBDNCache; - value_add_one( &next->a_vals, &bv ); - next->a_nvals = next->a_vals; + attr_valadd( next, &bv, NULL, 1 ); next = next->a_next; next->a_desc = ad_olmBDBIDLCache; - value_add_one( &next->a_vals, &bv ); - next->a_nvals = next->a_vals; + attr_valadd( next, &bv, NULL, 1 ); next = next->a_next; } @@ -432,6 +430,7 @@ bdb_monitor_db_open( BackendDB *be ) next->a_desc = ad_olmDbDirectory; next->a_vals = ch_calloc( sizeof( struct berval ), 2 ); next->a_vals[ 0 ] = bv; + next->a_numvals = 1; if ( BER_BVISNULL( &nbv ) ) { next->a_nvals = next->a_vals; diff --git a/servers/slapd/back-ldap/search.c b/servers/slapd/back-ldap/search.c index 13a9fb3960..3d23276bf1 100644 --- a/servers/slapd/back-ldap/search.c +++ b/servers/slapd/back-ldap/search.c @@ -676,11 +676,6 @@ ldap_build_entry( * values result filter */ attr->a_vals = (struct berval *)&slap_dummy_bv; - last = 0; - - } else { - for ( last = 0; !BER_BVISNULL( &attr->a_vals[ last ] ); last++ ) - /* just count vals */ ; } validate = attr->a_desc->ad_type->sat_syntax->ssyn_validate; @@ -692,7 +687,7 @@ ldap_build_entry( goto next_attr; } - for ( i = 0; i < last; i++ ) { + for ( i = 0; !BER_BVISNULL( &attr->a_vals[i] ); i++ ) { struct berval pval; int rc; @@ -724,6 +719,7 @@ ldap_build_entry( attr->a_vals[i] = pval; } } + attr->a_numvals = last = i; if ( last && attr->a_desc->ad_type->sat_equality && attr->a_desc->ad_type->sat_equality->smr_normalize ) diff --git a/servers/slapd/back-meta/search.c b/servers/slapd/back-meta/search.c index c9e435b41d..571d10a663 100644 --- a/servers/slapd/back-meta/search.c +++ b/servers/slapd/back-meta/search.c @@ -1885,6 +1885,7 @@ meta_send_entry( for ( last = 0; !BER_BVISNULL( &attr->a_vals[ last ] ); ++last ) ; } + attr->a_numvals = last; validate = attr->a_desc->ad_type->sat_syntax->ssyn_validate; pretty = attr->a_desc->ad_type->sat_syntax->ssyn_pretty; diff --git a/servers/slapd/back-monitor/compare.c b/servers/slapd/back-monitor/compare.c index 3a8df66624..9cac645bc9 100644 --- a/servers/slapd/back-monitor/compare.c +++ b/servers/slapd/back-monitor/compare.c @@ -71,10 +71,10 @@ monitor_back_compare( Operation *op, SlapReply *rs ) a = attrs_find( a->a_next, op->oq_compare.rs_ava->aa_desc )) { rs->sr_err = LDAP_COMPARE_FALSE; - if ( value_find_ex( op->oq_compare.rs_ava->aa_desc, + if ( attr_valfind( a, SLAP_MR_ATTRIBUTE_VALUE_NORMALIZED_MATCH | SLAP_MR_ASSERTED_VALUE_NORMALIZED_MATCH, - a->a_nvals, &op->oq_compare.rs_ava->aa_value, + &op->oq_compare.rs_ava->aa_value, NULL, op->o_tmpmemctx ) == 0 ) { rs->sr_err = LDAP_COMPARE_TRUE; diff --git a/servers/slapd/back-sql/compare.c b/servers/slapd/back-sql/compare.c index 24fe2e9fb1..403e82c3e5 100644 --- a/servers/slapd/back-sql/compare.c +++ b/servers/slapd/back-sql/compare.c @@ -131,11 +131,10 @@ backsql_compare( Operation *op, SlapReply *rs ) a = attrs_find( a->a_next, op->oq_compare.rs_ava->aa_desc ) ) { rs->sr_err = LDAP_COMPARE_FALSE; - if ( value_find_ex( op->oq_compare.rs_ava->aa_desc, + if ( attr_valfind( a, SLAP_MR_ATTRIBUTE_VALUE_NORMALIZED_MATCH | SLAP_MR_ASSERTED_VALUE_NORMALIZED_MATCH, - a->a_nvals, - &op->oq_compare.rs_ava->aa_value, + &op->oq_compare.rs_ava->aa_value, NULL, op->o_tmpmemctx ) == 0 ) { rs->sr_err = LDAP_COMPARE_TRUE; diff --git a/servers/slapd/back-sql/entry-id.c b/servers/slapd/back-sql/entry-id.c index 78f1da1445..f61fc5c864 100644 --- a/servers/slapd/back-sql/entry-id.c +++ b/servers/slapd/back-sql/entry-id.c @@ -617,8 +617,7 @@ backsql_get_attr_vals( void *v_at, void *v_bsi ) BerVarray tmp; if ( attr->a_vals != NULL ) { - for ( ; !BER_BVISNULL( &attr->a_vals[ oldcount ] ); oldcount++ ) - /* just count */ ; + oldcount = attr->a_numvals; } tmp = ch_realloc( attr->a_vals, ( oldcount + count + 1 ) * sizeof( struct berval ) ); @@ -639,19 +638,20 @@ backsql_get_attr_vals( void *v_at, void *v_bsi ) } else { attr->a_nvals = attr->a_vals; } + attr->a_numvals += count; } else { append = 1; /* Make space for the array of values */ attr = attr_alloc( at->bam_true_ad ); + attr->a_numvals = count; attr->a_vals = ch_calloc( count + 1, sizeof( struct berval ) ); if ( attr->a_vals == NULL ) { Debug( LDAP_DEBUG_TRACE, "Out of memory!\n", 0,0,0 ); ch_free( attr ); return 1; } - memset( attr->a_vals, 0, ( count + 1 ) * sizeof( struct berval ) ); if ( normfunc ) { attr->a_nvals = ch_calloc( count + 1, sizeof( struct berval ) ); if ( attr->a_nvals == NULL ) { @@ -659,8 +659,6 @@ backsql_get_attr_vals( void *v_at, void *v_bsi ) ch_free( attr ); return 1; - } else { - memset( attr->a_nvals, 0, ( count + 1 ) * sizeof( struct berval ) ); } } else { diff --git a/servers/slapd/back-sql/operational.c b/servers/slapd/back-sql/operational.c index f6fe6aea4f..6909d7b31a 100644 --- a/servers/slapd/back-sql/operational.c +++ b/servers/slapd/back-sql/operational.c @@ -55,6 +55,7 @@ backsql_operational_entryUUID( backsql_info *bi, backsql_entryID *id ) a = attr_alloc( desc ); + a->a_numvals = 1; a->a_vals = (BerVarray) ch_malloc( 2 * sizeof( struct berval ) ); a->a_vals[ 0 ] = val; BER_BVZERO( &a->a_vals[ 1 ] ); @@ -74,6 +75,7 @@ backsql_operational_entryCSN( Operation *op ) Attribute *a; a = attr_alloc( slap_schema.si_ad_entryCSN ); + a->a_numvals = 1; a->a_vals = ch_malloc( 2 * sizeof( struct berval ) ); BER_BVZERO( &a->a_vals[ 1 ] ); diff --git a/servers/slapd/backend.c b/servers/slapd/backend.c index 3d83060f55..3eb2a679d4 100644 --- a/servers/slapd/backend.c +++ b/servers/slapd/backend.c @@ -1501,10 +1501,10 @@ loopit: op->o_bd = b2; } else { - rc = value_find_ex( group_at, + rc = attr_valfind( a, SLAP_MR_ATTRIBUTE_VALUE_NORMALIZED_MATCH | SLAP_MR_ASSERTED_VALUE_NORMALIZED_MATCH, - a->a_nvals, op_ndn, op->o_tmpmemctx ); + op_ndn, NULL, op->o_tmpmemctx ); if ( rc == LDAP_NO_SUCH_ATTRIBUTE ) { rc = LDAP_COMPARE_FALSE; } @@ -1648,9 +1648,7 @@ fe_acl_attribute( goto freeit; } - for ( i = 0; !BER_BVISNULL( &a->a_vals[i] ); i++ ) - ; - + i = a->a_numvals; v = op->o_tmpalloc( sizeof(struct berval) * ( i + 1 ), op->o_tmpmemctx ); for ( i = 0, j = 0; !BER_BVISNULL( &a->a_vals[i] ); i++ ) diff --git a/servers/slapd/bconfig.c b/servers/slapd/bconfig.c index 40d7a90585..7576a2c2f7 100644 --- a/servers/slapd/bconfig.c +++ b/servers/slapd/bconfig.c @@ -177,6 +177,7 @@ enum { CFG_HIDDEN, CFG_MONITORING, CFG_SERVERID, + CFG_SORTVALS, CFG_LAST }; @@ -552,6 +553,11 @@ static ConfigTable config_back_cf_table[] = { { "sockbuf_max_incoming_auth", "max", 2, 2, 0, ARG_BER_LEN_T, &sockbuf_max_incoming_auth, "( OLcfgGlAt:62 NAME 'olcSockbufMaxIncomingAuth' " "SYNTAX OMsInteger SINGLE-VALUE )", NULL, NULL }, + { "sortvals", "attr", 2, 0, 0, ARG_MAGIC|CFG_SORTVALS, + &config_generic, "( OLcfgGlAt:83 NAME 'olcSortVals' " + "DESC 'Attributes whose values will always be sorted' " + "EQUALITY caseIgnoreMatch " + "SYNTAX OMsDirectoryString )", NULL, NULL }, { "subordinate", "[advertise]", 1, 2, 0, ARG_DB|ARG_MAGIC, &config_subordinate, "( OLcfgDbAt:0.15 NAME 'olcSubordinate' " "SYNTAX OMsDirectoryString SINGLE-VALUE )", NULL, NULL }, @@ -765,7 +771,7 @@ static ConfigOCs cf_ocs[] = { "NAME 'olcFrontendConfig' " "DESC 'OpenLDAP frontend configuration' " "AUXILIARY " - "MAY ( olcDefaultSearchBase $ olcPasswordHash ) )", + "MAY ( olcDefaultSearchBase $ olcPasswordHash $ olcSortVals ) )", Cft_Database, NULL, NULL }, #ifdef SLAPD_MODULES { "( OLcfgGlOc:8 " @@ -786,6 +792,13 @@ typedef struct ServerID { static ServerID *sid_list; +typedef struct ADlist { + struct ADlist *al_next; + AttributeDescription *al_desc; +} ADlist; + +static ADlist *sortVals; + static int config_generic(ConfigArgs *c) { int i; @@ -1000,6 +1013,14 @@ config_generic(ConfigArgs *c) { case CFG_SSTR_IF_MIN: c->value_int = index_substr_if_minlen; break; + case CFG_SORTVALS: { + ADlist *sv; + rc = 1; + for ( sv = sortVals; sv; sv = sv->al_next ) { + value_add_one( &c->rvalue_vals, &sv->al_desc->ad_cname ); + rc = 0; + } + } break; #ifdef SLAPD_MODULES case CFG_MODLOAD: { ModPaths *mp = c->private; @@ -1224,6 +1245,27 @@ config_generic(ConfigArgs *c) { } } break; + case CFG_SORTVALS: + if ( c->valx < 0 ) { + ADlist *sv; + for ( sv = sortVals; sv; sv = sortVals ) { + sortVals = sv->al_next; + sv->al_desc->ad_type->sat_flags &= ~SLAP_AT_SORTED_VAL; + ch_free( sv ); + } + } else { + ADlist *sv, **prev; + int i = 0; + + for ( prev = &sortVals, sv = sortVals; i < c->valx; i++ ) { + prev = &sv->al_next; + sv = sv->al_next; + } + sv->al_desc->ad_type->sat_flags &= ~SLAP_AT_SORTED_VAL; + *prev = sv->al_next; + ch_free( sv ); + } + break; case CFG_LIMITS: /* FIXME: there is no limits_free function */ @@ -1447,6 +1489,53 @@ config_generic(ConfigArgs *c) { return(1); break; + case CFG_SORTVALS: { + ADlist *svnew = NULL, *svtail, *sv; + + for ( i = 1; i < c->argc; i++ ) { + AttributeDescription *ad = NULL; + const char *text; + int rc; + + rc = slap_str2ad( c->argv[i], &ad, &text ); + if ( rc ) { + snprintf( c->cr_msg, sizeof( c->cr_msg ), "<%s> unknown attribute type #%d", + c->argv[0], i ); +sortval_reject: + Debug(LDAP_DEBUG_ANY, "%s: %s %s\n", + c->log, c->cr_msg, c->argv[i] ); + for ( sv = svnew; sv; sv = svnew ) { + svnew = sv->al_next; + ch_free( sv ); + } + return 1; + } + if (( ad->ad_type->sat_flags & SLAP_AT_ORDERED ) || + ad->ad_type->sat_single_value ) { + snprintf( c->cr_msg, sizeof( c->cr_msg ), "<%s> inappropriate attribute type #%d", + c->argv[0], i ); + goto sortval_reject; + } + sv = ch_malloc( sizeof( ADlist )); + sv->al_desc = ad; + if ( !svnew ) { + svnew = sv; + } else { + svtail->al_next = sv; + } + svtail = sv; + } + sv->al_next = NULL; + for ( sv = svnew; sv; sv = sv->al_next ) + sv->al_desc->ad_type->sat_flags |= SLAP_AT_SORTED_VAL; + for ( sv = sortVals; sv && sv->al_next; sv = sv->al_next ); + if ( sv ) + sv->al_next = svnew; + else + sortVals = svnew; + } + break; + case CFG_ACL: /* Don't append to the global ACL if we're on a specific DB */ i = c->valx; @@ -4544,7 +4633,7 @@ config_modify_internal( CfEntryInfo *ce, Operation *op, SlapReply *rs, */ if ( ct && ml->sml_values ) { delrec *d; - for (i=0; ml->sml_values[i].bv_val; i++); + i = ml->sml_numvals; d = ch_malloc( sizeof(delrec) + (i - 1)* sizeof(int)); d->nidx = i; d->next = NULL; @@ -4577,8 +4666,7 @@ config_modify_internal( CfEntryInfo *ce, Operation *op, SlapReply *rs, if ( ct->arg_type & ARG_NO_INSERT ) { Attribute *a = attr_find( e->e_attrs, ml->sml_desc ); if ( a ) { - for (i = 0; a->a_vals[i].bv_val; i++ ); - navals = i; + navals = a->a_numvals; } } for ( i=0; !BER_BVISNULL( &ml->sml_values[i] ); i++ ) { @@ -5384,6 +5472,7 @@ config_check_schema(Operation *op, CfBackInfo *cfb) ber_bvarray_free( a->a_vals ); a->a_vals = NULL; a->a_nvals = NULL; + a->a_numvals = 0; } oidm_unparse( &bv, NULL, NULL, 1 ); attr_merge_normalize( e, cfAd_om, bv, NULL ); @@ -5398,6 +5487,7 @@ config_check_schema(Operation *op, CfBackInfo *cfb) ber_bvarray_free( a->a_vals ); a->a_vals = NULL; a->a_nvals = NULL; + a->a_numvals = 0; } at_unparse( &bv, NULL, NULL, 1 ); attr_merge_normalize( e, cfAd_attr, bv, NULL ); @@ -5412,6 +5502,7 @@ config_check_schema(Operation *op, CfBackInfo *cfb) ber_bvarray_free( a->a_vals ); a->a_vals = NULL; a->a_nvals = NULL; + a->a_numvals = 0; } oc_unparse( &bv, NULL, NULL, 1 ); attr_merge_normalize( e, cfAd_oc, bv, NULL ); diff --git a/servers/slapd/compare.c b/servers/slapd/compare.c index eaee0c0e9b..1af6ba0b6a 100644 --- a/servers/slapd/compare.c +++ b/servers/slapd/compare.c @@ -384,10 +384,10 @@ static int compare_entry( break; } - if ( value_find_ex( ava->aa_desc, + if ( attr_valfind( a, SLAP_MR_ATTRIBUTE_VALUE_NORMALIZED_MATCH | SLAP_MR_ASSERTED_VALUE_NORMALIZED_MATCH, - a->a_nvals, &ava->aa_value, op->o_tmpmemctx ) == 0 ) + &ava->aa_value, NULL, op->o_tmpmemctx ) == 0 ) { rc = LDAP_COMPARE_TRUE; break; diff --git a/servers/slapd/entry.c b/servers/slapd/entry.c index 660bcb676b..b83c550def 100644 --- a/servers/slapd/entry.c +++ b/servers/slapd/entry.c @@ -277,9 +277,22 @@ str2entry2( char *s, int checkvals ) if (( ad_prev && ad != ad_prev ) || ( i == lines )) { int j, k; + /* FIXME: we only need this when migrating from an unsorted DB */ + if ( atail != &ahead && atail->a_desc->ad_type->sat_flags & SLAP_AT_SORTED_VAL ) { + rc = slap_sort_vals( (Modifications *)atail, &text, &j, NULL ); + if ( rc == LDAP_SUCCESS ) { + atail->a_flags |= SLAP_ATTR_SORTED_VALS; + } else if ( rc == LDAP_TYPE_OR_VALUE_EXISTS ) { + Debug( LDAP_DEBUG_ANY, + "str2entry: attributeType %s value #%d provided more than once\n", + atail->a_desc->ad_cname.bv_val, j, 0 ); + goto fail; + } + } atail->a_next = attr_alloc( NULL ); atail = atail->a_next; atail->a_flags = 0; + atail->a_numvals = attr_cnt; atail->a_desc = ad_prev; atail->a_vals = ch_malloc( (attr_cnt + 1) * sizeof(struct berval)); if( ad_prev->ad_type->sat_equality && @@ -371,7 +384,7 @@ str2entry2( char *s, int checkvals ) if ( rc ) { Debug( LDAP_DEBUG_ANY, - "<= str2entry NULL (smr_normalize %d)\n", rc, 0, 0 ); + "<= str2entry NULL (smr_normalize %s %d)\n", ad->ad_cname.bv_val, rc, 0 ); goto fail; } } @@ -744,6 +757,7 @@ int entry_encode(Entry *e, struct berval *bv) *ptr++ = '\0'; if (a->a_vals) { for (i=0; a->a_vals[i].bv_val; i++); + assert( i == a->a_numvals ); entry_putlen(&ptr, i); for (i=0; a->a_vals[i].bv_val; i++) { entry_putlen(&ptr, a->a_vals[i].bv_len); @@ -805,7 +819,7 @@ int entry_decode(EntryHeader *eh, Entry **e, void *ctx) int entry_decode(EntryHeader *eh, Entry **e) #endif { - int i, j, count, nattrs, nvals; + int i, j, nattrs, nvals; int rc; Attribute *a; Entry *x; @@ -857,7 +871,8 @@ int entry_decode(EntryHeader *eh, Entry **e) ptr += i + 1; a->a_desc = ad; a->a_flags = SLAP_ATTR_DONT_FREE_DATA | SLAP_ATTR_DONT_FREE_VALS; - count = j = entry_getlen(&ptr); + j = entry_getlen(&ptr); + a->a_numvals = j; a->a_vals = bptr; while (j) { @@ -889,6 +904,19 @@ int entry_decode(EntryHeader *eh, Entry **e) } else { a->a_nvals = a->a_vals; } + /* FIXME: This is redundant once a sorted entry is saved into the DB */ + if ( a->a_desc->ad_type->sat_flags & SLAP_AT_SORTED_VAL ) { + rc = slap_sort_vals( (Modifications *)a, &text, &j, NULL ); + if ( rc == LDAP_SUCCESS ) { + a->a_flags |= SLAP_ATTR_SORTED_VALS; + } else if ( rc == LDAP_TYPE_OR_VALUE_EXISTS ) { + /* should never happen */ + Debug( LDAP_DEBUG_ANY, + "entry_decode: attributeType %s value #%d provided more than once\n", + a->a_desc->ad_cname.bv_val, j, 0 ); + return rc; + } + } a = a->a_next; nattrs--; if ( !nattrs ) @@ -962,6 +990,7 @@ Entry *entry_dup_bv( Entry *e ) dst->a_desc = src->a_desc; dst->a_flags = SLAP_ATTR_DONT_FREE_DATA | SLAP_ATTR_DONT_FREE_VALS; dst->a_vals = bvl; + dst->a_numvals = src->a_numvals; for ( i=0; src->a_vals[i].bv_val; i++ ) { bvl->bv_len = src->a_vals[i].bv_len; bvl->bv_val = ptr; diff --git a/servers/slapd/filterentry.c b/servers/slapd/filterentry.c index d1fb4856e3..911b72e5a0 100644 --- a/servers/slapd/filterentry.c +++ b/servers/slapd/filterentry.c @@ -212,12 +212,7 @@ static int test_mra_filter( if ( mra->ma_cf && mra->ma_rule->smr_usage & SLAP_MR_COMPONENT ) { num_attr_vals = 0; if ( !a->a_comp_data ) { - for ( ; - !BER_BVISNULL( &a->a_vals[num_attr_vals] ); - num_attr_vals++ ) - { - /* empty */; - } + num_attr_vals = a->a_numvals; if ( num_attr_vals <= 0 ) { /* no attribute value */ return LDAP_INAPPROPRIATE_MATCHING; @@ -662,6 +657,56 @@ test_ava_filter( continue; } + /* We have no Sort optimization for Approx matches */ + if (( a->a_flags & SLAP_ATTR_SORTED_VALS ) && type != LDAP_FILTER_APPROX ) { + unsigned slot; + int ret; + + /* For Ordering matches, we just need to do one comparison with + * either the first (least) or last (greatest) value. + */ + if ( use == SLAP_MR_ORDERING ) { + const char *text; + int match, which; + which = (type == LDAP_FILTER_LE) ? 0 : a->a_numvals-1; + ret = value_match( &match, a->a_desc, mr, use, + &a->a_nvals[which], &ava->aa_value, &text ); + if ( ret != LDAP_SUCCESS ) return ret; + if (( type == LDAP_FILTER_LE && match <= 0 ) || + ( type == LDAP_FILTER_GE && match >= 0 )) + return LDAP_COMPARE_TRUE; + continue; + } + /* Only Equality will get here */ + ret = attr_valfind( a, use | SLAP_MR_ASSERTED_VALUE_NORMALIZED_MATCH | + SLAP_MR_ATTRIBUTE_VALUE_NORMALIZED_MATCH, + &ava->aa_value, &slot, NULL ); + if ( ret == LDAP_SUCCESS ) + return LDAP_COMPARE_TRUE; + else if ( ret != LDAP_NO_SUCH_ATTRIBUTE ) + return ret; +#if 0 + /* The following is useful if we want to know which values + * matched an ordering test. But here we don't care, we just + * want to know if any value did, and that is checked above. + */ + if ( ret == LDAP_NO_SUCH_ATTRIBUTE ) { + /* If insertion point is not the end of the list, there was + * at least one value greater than the assertion. + */ + if ( type == LDAP_FILTER_GE && slot < a->a_numvals ) + return LDAP_COMPARE_TRUE; + /* Likewise, if insertion point is not the head of the list, + * there was at least one value less than the assertion. + */ + if ( type == LDAP_FILTER_LE && slot > 0 ) + return LDAP_COMPARE_TRUE; + return LDAP_COMPARE_FALSE; + } +#endif + continue; + } + #ifdef LDAP_COMP_MATCH if ( nibble_mem_allocator && ava->aa_cf && !a->a_comp_data ) { /* Component Matching */ diff --git a/servers/slapd/modify.c b/servers/slapd/modify.c index e6ba1dfe4b..d0282b16e6 100644 --- a/servers/slapd/modify.c +++ b/servers/slapd/modify.c @@ -585,6 +585,7 @@ int slap_mods_check( ml->sml_values[nvals] = pval; } } + ml->sml_numvals = nvals; /* * a rough single value check... an additional check is needed @@ -639,200 +640,200 @@ int slap_mods_check( /* check for duplicates, but ignore Deletes. */ if( nvals > 1 && ml->sml_op != LDAP_MOD_DELETE ) { -#define SLAP_MODS_CHECK_QUICKSORT -#ifndef SLAP_MODS_CHECK_QUICKSORT - int i, j, rc, match; - MatchingRule *mr = ad->ad_type->sat_equality; - - for ( i = 1; i < nvals ; i++ ) { - /* test asserted values against themselves */ - for( j = 0; j < i; j++ ) { - rc = ordered_value_match( &match, ml->sml_desc, mr, - SLAP_MR_EQUALITY - | SLAP_MR_VALUE_OF_ATTRIBUTE_SYNTAX - | SLAP_MR_ASSERTED_VALUE_NORMALIZED_MATCH - | SLAP_MR_ATTRIBUTE_VALUE_NORMALIZED_MATCH, - ml->sml_nvalues - ? &ml->sml_nvalues[i] - : &ml->sml_values[i], - ml->sml_nvalues - ? &ml->sml_nvalues[j] - : &ml->sml_values[j], - text ); - if ( rc == LDAP_SUCCESS && match == 0 ) { - /* value exists already */ - snprintf( textbuf, textlen, - "%s: value #%d provided more than once", - ml->sml_desc->ad_cname.bv_val, j ); - *text = textbuf; - return LDAP_TYPE_OR_VALUE_EXISTS; - - } else if ( rc != LDAP_SUCCESS ) { - return rc; - } - } + int i; + rc = slap_sort_vals( ml, text, &i, ctx ); + if ( rc == LDAP_TYPE_OR_VALUE_EXISTS ) { + /* value exists already */ + snprintf( textbuf, textlen, + "%s: value #%d provided more than once", + ml->sml_desc->ad_cname.bv_val, i ); + *text = textbuf; } -#else /* SLAP_MODS_CHECK_QUICKSORT */ + if ( rc ) + return rc; + } + } else { + ml->sml_numvals = 0; + } + } + + return LDAP_SUCCESS; +} + +/* Sort a set of values. An (Attribute *) may be used interchangeably here + * instead of a (Modifications *) structure. + * + * Uses Quicksort + Insertion sort for small arrays + */ -/* Quicksort + Insertion sort for small arrays */ +int +slap_sort_vals( + Modifications *ml, + const char **text, + int *dup, + void *ctx ) +{ + AttributeDescription *ad; + MatchingRule *mr; + int istack[sizeof(int)*16]; + int i, j, k, l, ir, jstack, match, *ix, itmp, nvals, rc; + int is_norm; + struct berval a, *cv; #define SMALL 8 #define SWAP(a,b,tmp) tmp=(a);(a)=(b);(b)=tmp #define COMP(a,b) match=0; rc = ordered_value_match( &match, \ - ml->sml_desc, mr, SLAP_MR_EQUALITY \ + ad, mr, SLAP_MR_EQUALITY \ | SLAP_MR_VALUE_OF_ATTRIBUTE_SYNTAX \ | SLAP_MR_ASSERTED_VALUE_NORMALIZED_MATCH \ | SLAP_MR_ATTRIBUTE_VALUE_NORMALIZED_MATCH, \ &(a), &(b), text ); - MatchingRule *mr = ad->ad_type->sat_equality; - int istack[sizeof(int)*16]; - int i, j, k, l, ir, jstack, match, *ix, itmp; - struct berval a, *cv; - -/* If PRESERVE_ORDER is defined only the index array is sorted; the - * actual values are left in their incoming order. Otherwise, the - * only reason to keep the index array is to identify the offending - * value when duplicates are found. - */ -#define PRESERVE_ORDER -#ifndef PRESERVE_ORDER - struct berval va, *v, *nv, bvtmp; - -#define IX(x) x -#define EXCH(x,y) SWAP(ix[x],ix[y],itmp); SWAP(cv[x],cv[y],bvtmp); \ - if (nv) {SWAP(v[x],v[y],bvtmp);} -#define SETA(x) itmp = ix[x]; a = cv[x]; if (nv) va=v[x] -#define GETA(x) ix[x] = itmp; cv[x] = a; if (nv) v[x]=va -#define SET(x,y) ix[x] = ix[y]; cv[x] = cv[y]; if (nv) v[x]=v[y] - - v = ml->sml_values; - nv = ml->sml_nvalues; - -#else /* PRESERVE_ORDER */ - #define IX(x) ix[x] #define EXCH(x,y) SWAP(ix[x],ix[y],itmp) #define SETA(x) itmp = ix[x]; a = cv[itmp] #define GETA(x) ix[x] = itmp; #define SET(x,y) ix[x] = ix[y] -#endif /* PRESERVE_ORDER */ - - cv = ml->sml_nvalues ? ml->sml_nvalues : ml->sml_values; - if ( ad == slap_schema.si_ad_objectClass ) - mr = NULL; /* shortcut matching */ - - /* record indices to preserve input ordering */ - ix = slap_sl_malloc( nvals * sizeof(int), ctx ); - for (i=0; i=0;i--) { - COMP(cv[IX(i)], a); - if ( match <= 0 ) - break; - SET(i+1,i); - } - GETA(i+1); - if ( match == 0 ) goto done; - } - if ( jstack == 0 ) break; - if ( match == 0 ) break; - ir = istack[jstack--]; - l = istack[jstack--]; - } else { - k = (l + ir) >> 1; /* Choose median of left, center, right */ - EXCH(k, l+1); - COMP( cv[IX(l)], cv[IX(ir)] ); - if ( match > 0 ) { - EXCH(l, ir); - } else if ( match == 0 ) { - i = ir; - break; - } - COMP( cv[IX(l+1)], cv[IX(ir)] ); - if ( match > 0 ) { - EXCH(l+1, ir); - } else if ( match == 0 ) { - i = ir; - break; - } - COMP( cv[IX(l)], cv[IX(l+1)] ); - if ( match > 0 ) { - EXCH(l, l+1); - } else if ( match == 0 ) { - i = l; - break; - } - i = l+1; - j = ir; - a = cv[IX(i)]; - for(;;) { - do { - i++; - COMP( cv[IX(i)], a ); - } while( match < 0 ); - while( match > 0 ) { - j--; - COMP( cv[IX(j)], a ); - } - if (j < i) { - match = 1; - break; - } - if ( match == 0 ) { - i = l+1; - break; - } - EXCH(i,j); - } - if ( match == 0 ) - break; - EXCH(l+1,j); - jstack += 2; - if (ir-i+1 >= j) { - istack[jstack] = ir; - istack[jstack-1] = i; - ir = j; - } else { - istack[jstack] = j; - istack[jstack-1] = l; - l = i; - } - } - } -done: - if ( i >= 0 ) - j = ix[i]; + ad = ml->sml_desc; + nvals = ml->sml_numvals; - slap_sl_free( ix, ctx ); + /* For Modifications, sml_nvalues is NULL if normalization wasn't needed. + * For Attributes, sml_nvalues == sml_values when normalization isn't needed. + */ + if ( ml->sml_nvalues && ml->sml_nvalues != ml->sml_values ) { + cv = ml->sml_nvalues; + is_norm = 1; + } else { + cv = ml->sml_values; + is_norm = 0; + } - if ( rc != LDAP_SUCCESS ) { - return rc; - } else if ( match == 0 ) { - /* value exists already */ - assert( i >= 0 ); - assert( i < nvals ); - snprintf( textbuf, textlen, - "%s: value #%d provided more than once", - ml->sml_desc->ad_cname.bv_val, j ); - *text = textbuf; - return LDAP_TYPE_OR_VALUE_EXISTS; + if ( ad == slap_schema.si_ad_objectClass ) + mr = NULL; /* shortcut matching */ + else + mr = ad->ad_type->sat_equality; + + /* record indices to preserve input ordering */ + ix = slap_sl_malloc( nvals * sizeof(int), ctx ); + for (i=0; i=0;i--) { + COMP(cv[IX(i)], a); + if ( match <= 0 ) + break; + SET(i+1,i); + } + GETA(i+1); + if ( match == 0 ) goto done; + } + if ( jstack == 0 ) break; + if ( match == 0 ) break; + ir = istack[jstack--]; + l = istack[jstack--]; + } else { + k = (l + ir) >> 1; /* Choose median of left, center, right */ + EXCH(k, l+1); + COMP( cv[IX(l)], cv[IX(ir)] ); + if ( match > 0 ) { + EXCH(l, ir); + } else if ( match == 0 ) { + i = ir; + break; + } + COMP( cv[IX(l+1)], cv[IX(ir)] ); + if ( match > 0 ) { + EXCH(l+1, ir); + } else if ( match == 0 ) { + i = ir; + break; + } + COMP( cv[IX(l)], cv[IX(l+1)] ); + if ( match > 0 ) { + EXCH(l, l+1); + } else if ( match == 0 ) { + i = l; + break; + } + i = l+1; + j = ir; + a = cv[IX(i)]; + for(;;) { + do { + i++; + COMP( cv[IX(i)], a ); + } while( match < 0 ); + while( match > 0 ) { + j--; + COMP( cv[IX(j)], a ); + } + if (j < i) { + match = 1; + break; + } + if ( match == 0 ) { + i = l+1; + break; } -#endif /* SLAP_MODS_CHECK_QUICKSORT */ + EXCH(i,j); + } + if ( match == 0 ) + break; + EXCH(l+1,j); + jstack += 2; + if (ir-i+1 >= j) { + istack[jstack] = ir; + istack[jstack-1] = i; + ir = j; + } else { + istack[jstack] = j; + istack[jstack-1] = l; + l = i; } } } + done: + if ( i >= 0 ) + *dup = ix[i]; + + /* For sorted attributes, put the values in index order */ + if ( rc == LDAP_SUCCESS && match && + ( ad->ad_type->sat_flags & SLAP_AT_SORTED_VAL )) { + BerVarray tmpv = slap_sl_malloc( sizeof( struct berval ) * nvals, ctx ); + for ( i = 0; isml_values; + for ( i = 0; i= 0 ); + assert( i < nvals ); + return LDAP_TYPE_OR_VALUE_EXISTS; + } return LDAP_SUCCESS; } @@ -946,6 +947,7 @@ void slap_mods_opattrs( mod->sml_next = NULL; BER_BVZERO( &mod->sml_type ); mod->sml_desc = slap_schema.si_ad_entryCSN; + mod->sml_numvals = 1; mod->sml_values = (BerVarray) ch_malloc( 2 * sizeof( struct berval ) ); ber_dupbv( &mod->sml_values[0], &csn ); BER_BVZERO( &mod->sml_values[1] ); @@ -963,6 +965,7 @@ void slap_mods_opattrs( mod->sml_next = NULL; BER_BVZERO( &mod->sml_type ); mod->sml_desc = slap_schema.si_ad_modifiersName; + mod->sml_numvals = 1; mod->sml_values = (BerVarray) ch_malloc( 2 * sizeof( struct berval ) ); ber_dupbv( &mod->sml_values[0], &name ); BER_BVZERO( &mod->sml_values[1] ); @@ -983,6 +986,7 @@ void slap_mods_opattrs( mod->sml_next = NULL; BER_BVZERO( &mod->sml_type ); mod->sml_desc = slap_schema.si_ad_modifyTimestamp; + mod->sml_numvals = 1; mod->sml_values = (BerVarray) ch_malloc( 2 * sizeof( struct berval ) ); ber_dupbv( &mod->sml_values[0], ×tamp ); BER_BVZERO( &mod->sml_values[1] ); diff --git a/servers/slapd/modrdn.c b/servers/slapd/modrdn.c index 3aae6ac444..e0f1725efe 100644 --- a/servers/slapd/modrdn.c +++ b/servers/slapd/modrdn.c @@ -428,6 +428,7 @@ slap_modrdn2mods( mod_tmp = ( Modifications * )ch_malloc( sizeof( Modifications ) ); mod_tmp->sml_desc = desc; BER_BVZERO( &mod_tmp->sml_type ); + mod_tmp->sml_numvals = 1; mod_tmp->sml_values = ( BerVarray )ch_malloc( 2 * sizeof( struct berval ) ); ber_dupbv( &mod_tmp->sml_values[0], &new_rdn[a_cnt]->la_value ); mod_tmp->sml_values[1].bv_val = NULL; @@ -469,6 +470,7 @@ slap_modrdn2mods( mod_tmp = ( Modifications * )ch_malloc( sizeof( Modifications ) ); mod_tmp->sml_desc = desc; BER_BVZERO( &mod_tmp->sml_type ); + mod_tmp->sml_numvals = 1; mod_tmp->sml_values = ( BerVarray )ch_malloc( 2 * sizeof( struct berval ) ); ber_dupbv( &mod_tmp->sml_values[0], &old_rdn[d_cnt]->la_value ); mod_tmp->sml_values[1].bv_val = NULL; diff --git a/servers/slapd/mods.c b/servers/slapd/mods.c index 31b79274c8..2d0d01fc8b 100644 --- a/servers/slapd/mods.c +++ b/servers/slapd/mods.c @@ -56,11 +56,21 @@ modify_add_values( assert( 0 ); } + /* FIXME: Catch old code that doesn't set sm_numvals. + */ + if ( !BER_BVISNULL( &mod->sm_values[mod->sm_numvals] )) { + int i; + for ( i = 0; !BER_BVISNULL( &mod->sm_values[i] ); i++ ); + assert( mod->sm_numvals == i ); + } + /* check if values to add exist in attribute */ a = attr_find( e->e_attrs, mod->sm_desc ); if ( a != NULL ) { - int rc, i, j, p; MatchingRule *mr; + struct berval *cvals; + int rc, i, j, p; + unsigned flags; mr = mod->sm_desc->ad_type->sat_equality; if( mr == NULL || !mr->smr_match ) { @@ -74,10 +84,7 @@ modify_add_values( } if ( permissive ) { - for ( i = 0; !BER_BVISNULL( &mod->sm_values[i] ); i++ ) { - /* EMPTY -- just counting 'em */; - } - + i = mod->sm_numvals; pmod.sm_values = (BerVarray)ch_malloc( (i + 1) * sizeof( struct berval )); if ( pmod.sm_nvalues != NULL ) { @@ -92,39 +99,32 @@ modify_add_values( * server (whether from LDAP or from the underlying * database). */ - for ( p = i = 0; !BER_BVISNULL( &mod->sm_values[i] ); i++ ) { - int match; - - assert( a->a_vals[0].bv_val != NULL ); - for ( j = 0; !BER_BVISNULL( &a->a_vals[j] ); j++ ) { - if ( mod->sm_nvalues ) { - rc = ordered_value_match( &match, mod->sm_desc, mr, - SLAP_MR_EQUALITY | SLAP_MR_VALUE_OF_ASSERTION_SYNTAX - | SLAP_MR_ASSERTED_VALUE_NORMALIZED_MATCH - | SLAP_MR_ATTRIBUTE_VALUE_NORMALIZED_MATCH, - &a->a_nvals[j], &mod->sm_nvalues[i], text ); - } else { - rc = ordered_value_match( &match, mod->sm_desc, mr, - SLAP_MR_EQUALITY | SLAP_MR_VALUE_OF_ASSERTION_SYNTAX, - &a->a_vals[j], &mod->sm_values[i], text ); - } + flags = SLAP_MR_EQUALITY | SLAP_MR_VALUE_OF_ASSERTION_SYNTAX; + if ( mod->sm_nvalues ) { + flags |= SLAP_MR_ASSERTED_VALUE_NORMALIZED_MATCH | + SLAP_MR_ATTRIBUTE_VALUE_NORMALIZED_MATCH; + cvals = mod->sm_nvalues; + } else { + cvals = mod->sm_values; + } + for ( p = i = 0; i < mod->sm_numvals; i++ ) { + unsigned slot; - if ( rc == LDAP_SUCCESS && match == 0 ) { + rc = attr_valfind( a, flags, &cvals[i], &slot, NULL ); + if ( rc == LDAP_SUCCESS ) { + if ( !permissive ) { /* value already exists */ - if ( permissive ) break; - *text = textbuf; snprintf( textbuf, textlen, "modify/%s: %s: value #%d already exists", op, mod->sm_desc->ad_cname.bv_val, i ); return LDAP_TYPE_OR_VALUE_EXISTS; - - } else if ( rc != LDAP_SUCCESS ) { - return rc; } + } else if ( rc != LDAP_NO_SUCH_ATTRIBUTE ) { + return rc; } - if ( permissive && match != 0 ) { + if ( permissive && rc ) { if ( pmod.sm_nvalues ) { pmod.sm_nvalues[p] = mod->sm_nvalues[i]; } @@ -164,8 +164,8 @@ modify_add_values( /* this should return result of attr_merge */ *text = textbuf; snprintf( textbuf, textlen, - "modify/%s: %s: merge error", - op, mod->sm_desc->ad_cname.bv_val ); + "modify/%s: %s: merge error (%d)", + op, mod->sm_desc->ad_cname.bv_val, rc ); return LDAP_OTHER; } @@ -192,11 +192,13 @@ modify_delete_vindex( char *textbuf, size_t textlen, int *idx ) { - int i, j, k, rc = LDAP_SUCCESS; Attribute *a; MatchingRule *mr = mod->sm_desc->ad_type->sat_equality; + struct berval *cvals; + int *id2 = NULL; + int i, j, rc = 0; + unsigned flags; char dummy = '\0'; - int match = 0; /* * If permissive is set, then the non-existence of an @@ -219,6 +221,17 @@ modify_delete_vindex( return rc; } + /* FIXME: Catch old code that doesn't set sm_numvals. + */ + if ( !BER_BVISNULL( &mod->sm_values[mod->sm_numvals] )) { + for ( i = 0; !BER_BVISNULL( &mod->sm_values[i] ); i++ ); + assert( mod->sm_numvals == i ); + } + if ( !idx ) { + id2 = ch_malloc( mod->sm_numvals * sizeof( int )); + idx = id2; + } + if( mr == NULL || !mr->smr_match ) { /* disallow specific attributes from being deleted if no equality rule */ @@ -226,101 +239,90 @@ modify_delete_vindex( snprintf( textbuf, textlen, "modify/delete: %s: no equality matching rule", mod->sm_desc->ad_cname.bv_val ); - return LDAP_INAPPROPRIATE_MATCHING; + rc = LDAP_INAPPROPRIATE_MATCHING; + goto return_result; } /* delete specific values - find the attribute first */ if ( (a = attr_find( e->e_attrs, mod->sm_desc )) == NULL ) { if( permissive ) { - return LDAP_SUCCESS; + rc = LDAP_SUCCESS; + goto return_result; } *text = textbuf; snprintf( textbuf, textlen, "modify/delete: %s: no such attribute", mod->sm_desc->ad_cname.bv_val ); - return LDAP_NO_SUCH_ATTRIBUTE; + rc = LDAP_NO_SUCH_ATTRIBUTE; + goto return_result; } - for ( i = 0; !BER_BVISNULL( &mod->sm_values[i] ); i++ ) { - int found = 0; - for ( j = 0; !BER_BVISNULL( &a->a_vals[j] ); j++ ) { - /* skip already deleted values */ - if ( a->a_vals[j].bv_val == &dummy ) { - continue; - } - - if( mod->sm_nvalues ) { - assert( a->a_nvals != NULL ); - rc = ordered_value_match( &match, a->a_desc, mr, - SLAP_MR_EQUALITY | SLAP_MR_VALUE_OF_ASSERTION_SYNTAX - | SLAP_MR_ASSERTED_VALUE_NORMALIZED_MATCH - | SLAP_MR_ATTRIBUTE_VALUE_NORMALIZED_MATCH, - &a->a_nvals[j], &mod->sm_nvalues[i], text ); - } else { -#if 0 - assert( a->a_nvals == NULL ); -#endif - rc = ordered_value_match( &match, a->a_desc, mr, - SLAP_MR_EQUALITY | SLAP_MR_VALUE_OF_ASSERTION_SYNTAX, - &a->a_vals[j], &mod->sm_values[i], text ); - } - - if ( rc != LDAP_SUCCESS ) { - *text = textbuf; - snprintf( textbuf, textlen, - "%s: matching rule failed", - mod->sm_desc->ad_cname.bv_val ); - break; - } + if ( mod->sm_nvalues ) { + flags = SLAP_MR_EQUALITY | SLAP_MR_VALUE_OF_ASSERTION_SYNTAX + | SLAP_MR_ASSERTED_VALUE_NORMALIZED_MATCH + | SLAP_MR_ATTRIBUTE_VALUE_NORMALIZED_MATCH; + cvals = mod->sm_nvalues; + } else { + flags = SLAP_MR_EQUALITY | SLAP_MR_VALUE_OF_ASSERTION_SYNTAX; + cvals = mod->sm_values; + } - if ( match != 0 ) { + /* Locate values to delete */ + for ( i = 0; !BER_BVISNULL( &mod->sm_values[i] ); i++ ) { + unsigned sort; + rc = attr_valfind( a, flags, &cvals[i], &sort, NULL ); + if ( rc == LDAP_SUCCESS ) { + idx[i] = sort; + } else if ( rc == LDAP_NO_SUCH_ATTRIBUTE ) { + if ( permissive ) { + idx[i] = -1; continue; } - - found = 1; - - if ( idx ) - idx[i] = j; - - /* delete value and mark it as dummy */ - free( a->a_vals[j].bv_val ); - a->a_vals[j].bv_val = &dummy; - if( a->a_nvals != a->a_vals ) { - free( a->a_nvals[j].bv_val ); - a->a_nvals[j].bv_val = &dummy; - } - - break; - } - - if ( found == 0 ) { *text = textbuf; snprintf( textbuf, textlen, "modify/delete: %s: no such value", mod->sm_desc->ad_cname.bv_val ); - rc = LDAP_NO_SUCH_ATTRIBUTE; - if ( i > 0 ) { - break; - } else { - goto return_results; - } + goto return_result; + } else { + *text = textbuf; + snprintf( textbuf, textlen, + "modify/delete: %s: matching rule failed", + mod->sm_desc->ad_cname.bv_val ); + goto return_result; + } + } + + /* Delete the values */ + for ( i = 0; i < mod->sm_numvals; i++ ) { + /* Skip permissive values that weren't found */ + if ( idx[i] < 0 ) + continue; + /* Skip duplicate delete specs */ + if ( a->a_vals[idx[i]].bv_val == &dummy ) + continue; + /* delete value and mark it as gone */ + free( a->a_vals[idx[i]].bv_val ); + a->a_vals[idx[i]].bv_val = &dummy; + if( a->a_nvals != a->a_vals ) { + free( a->a_nvals[idx[i]].bv_val ); + a->a_nvals[idx[i]].bv_val = &dummy; } + a->a_numvals--; } /* compact array skipping dummies */ - for ( k = 0, j = 0; !BER_BVISNULL( &a->a_vals[k] ); k++ ) { + for ( i = 0, j = 0; !BER_BVISNULL( &a->a_vals[i] ); i++ ) { /* skip dummies */ - if( a->a_vals[k].bv_val == &dummy ) { - assert( a->a_nvals[k].bv_val == &dummy ); + if( a->a_vals[i].bv_val == &dummy ) { + assert( a->a_nvals[i].bv_val == &dummy ); continue; } - if ( j != k ) { - a->a_vals[ j ] = a->a_vals[ k ]; + if ( j != i ) { + a->a_vals[ j ] = a->a_vals[ i ]; if (a->a_nvals != a->a_vals) { - a->a_nvals[ j ] = a->a_nvals[ k ]; + a->a_nvals[ j ] = a->a_nvals[ i ]; } } - j++; } @@ -330,8 +332,9 @@ modify_delete_vindex( } /* if no values remain, delete the entire attribute */ - if ( BER_BVISNULL( &a->a_vals[0] ) ) { + if ( !a->a_numvals ) { if ( attr_delete( &e->e_attrs, mod->sm_desc ) ) { + /* Can never happen */ *text = textbuf; snprintf( textbuf, textlen, "modify/delete: %s: no such attribute", @@ -342,9 +345,9 @@ modify_delete_vindex( /* For an ordered attribute, renumber the value indices */ ordered_value_sort( a, 1 ); } - -return_results:; - +return_result: + if ( id2 ) + ch_free( id2 ); return rc; } diff --git a/servers/slapd/operational.c b/servers/slapd/operational.c index fd12d0aff6..f55cfd98f8 100644 --- a/servers/slapd/operational.c +++ b/servers/slapd/operational.c @@ -31,6 +31,7 @@ slap_operational_subschemaSubentry( Backend *be ) a = attr_alloc( slap_schema.si_ad_subschemaSubentry ); + a->a_numvals = 1; a->a_vals = ch_malloc( 2 * sizeof( struct berval ) ); ber_dupbv( a->a_vals, &frontendDB->be_schemadn ); a->a_vals[1].bv_len = 0; @@ -55,6 +56,7 @@ slap_operational_entryDN( Entry *e ) a = attr_alloc( slap_schema.si_ad_entryDN ); + a->a_numvals = 1; a->a_vals = ch_malloc( 2 * sizeof( struct berval ) ); ber_dupbv( &a->a_vals[ 0 ], &e->e_name ); BER_BVZERO( &a->a_vals[ 1 ] ); @@ -75,6 +77,7 @@ slap_operational_hasSubordinate( int hs ) val = hs ? slap_true_bv : slap_false_bv; a = attr_alloc( slap_schema.si_ad_hasSubordinates ); + a->a_numvals = 1; a->a_vals = ch_malloc( 2 * sizeof( struct berval ) ); ber_dupbv( &a->a_vals[0], &val ); diff --git a/servers/slapd/overlays/accesslog.c b/servers/slapd/overlays/accesslog.c index b034d061cb..e0b0e8bb02 100644 --- a/servers/slapd/overlays/accesslog.c +++ b/servers/slapd/overlays/accesslog.c @@ -1365,11 +1365,7 @@ static int accesslog_response(Operation *op, SlapReply *rs) { /* count all the vals */ i = 0; for ( a=e2->e_attrs; a; a=a->a_next ) { - if ( a->a_vals ) { - for (b=a->a_vals; !BER_BVISNULL( b ); b++) { - i++; - } - } + i += a->a_numvals; } vals = ch_malloc( (i+1) * sizeof( struct berval )); i = 0; @@ -1383,6 +1379,7 @@ static int accesslog_response(Operation *op, SlapReply *rs) { vals[i].bv_val = NULL; vals[i].bv_len = 0; a = attr_alloc( logop == LOG_EN_ADD ? ad_reqMod : ad_reqOld ); + a->a_numvals = i; a->a_vals = vals; a->a_nvals = vals; last_attr->a_next = a; @@ -1395,9 +1392,7 @@ static int accesslog_response(Operation *op, SlapReply *rs) { i = 0; for ( m = op->orm_modlist; m; m = m->sml_next ) { if ( m->sml_values ) { - for ( b = m->sml_values; !BER_BVISNULL( b ); b++ ) { - i++; - } + i += m->sml_numvals; } else if ( m->sml_op == LDAP_MOD_DELETE || m->sml_op == LDAP_MOD_REPLACE ) { @@ -1478,6 +1473,7 @@ static int accesslog_response(Operation *op, SlapReply *rs) { if ( i > 0 ) { BER_BVZERO( &vals[i] ); a = attr_alloc( ad_reqMod ); + a->a_numvals = i; a->a_vals = vals; a->a_nvals = vals; last_attr->a_next = a; @@ -1492,9 +1488,7 @@ static int accesslog_response(Operation *op, SlapReply *rs) { i = 0; for ( a = old->e_attrs; a != NULL; a = a->a_next ) { if ( a->a_vals && a->a_flags ) { - for ( b = a->a_vals; !BER_BVISNULL( b ); b++ ) { - i++; - } + i += a->a_numvals; } } vals = ch_malloc( (i + 1) * sizeof( struct berval ) ); @@ -1509,6 +1503,7 @@ static int accesslog_response(Operation *op, SlapReply *rs) { vals[i].bv_val = NULL; vals[i].bv_len = 0; a = attr_alloc( ad_reqOld ); + a->a_numvals = i; a->a_vals = vals; a->a_nvals = vals; last_attr->a_next = a; @@ -1788,10 +1783,9 @@ accesslog_operational( Operation *op, SlapReply *rs ) ad_inlist( ad_auditContext, rs->sr_attrs ) ) { *ap = attr_alloc( ad_auditContext ); - value_add_one( &(*ap)->a_vals, - &li->li_db->be_suffix[0] ); - value_add_one( &(*ap)->a_nvals, - &li->li_db->be_nsuffix[0] ); + attr_valadd( *ap, + &li->li_db->be_suffix[0], + &li->li_db->be_nsuffix[0], 1 ); } } diff --git a/servers/slapd/overlays/dds.c b/servers/slapd/overlays/dds.c index 1df2ccd7bb..ebf70ec878 100644 --- a/servers/slapd/overlays/dds.c +++ b/servers/slapd/overlays/dds.c @@ -788,6 +788,7 @@ done:; tmpmod->sml_op = LDAP_MOD_REPLACE; value_add_one( &tmpmod->sml_values, &bv ); value_add_one( &tmpmod->sml_nvalues, &bv ); + tmpmod->sml_numvals = 1; } } @@ -1087,6 +1088,7 @@ dds_op_extended( Operation *op, SlapReply *rs ) ttlmod.sml_flags = SLAP_MOD_MANAGING; ttlmod.sml_desc = slap_schema.si_ad_entryTtl; ttlmod.sml_values = ttlvalues; + ttlmod.sml_numvals = 1; ttlvalues[ 0 ].bv_val = ttlbuf; ttlvalues[ 0 ].bv_len = snprintf( ttlbuf, sizeof( ttlbuf ), "%ld", ttl ); BER_BVZERO( &ttlvalues[ 1 ] ); diff --git a/servers/slapd/overlays/dynlist.c b/servers/slapd/overlays/dynlist.c index 1446df1fbe..4fcd0794ac 100644 --- a/servers/slapd/overlays/dynlist.c +++ b/servers/slapd/overlays/dynlist.c @@ -92,10 +92,10 @@ dynlist_is_dynlist_next( Operation *op, SlapReply *rs, dynlist_info_t *old_dli ) } for ( ; dli; dli = dli->dli_next ) { - if ( value_find_ex( slap_schema.si_ad_objectClass, + if ( attr_valfind( a, SLAP_MR_ATTRIBUTE_VALUE_NORMALIZED_MATCH | SLAP_MR_ASSERTED_VALUE_NORMALIZED_MATCH, - a->a_nvals, &dli->dli_oc->soc_cname, + &dli->dli_oc->soc_cname, NULL, op->o_tmpmemctx ) == 0 ) { return dli; @@ -189,6 +189,7 @@ dynlist_sc_update( Operation *op, SlapReply *rs ) mod.sm_type = dlc->dlc_dli->dli_member_ad->ad_cname; mod.sm_values = vals; mod.sm_nvalues = nvals; + mod.sm_numvals = 1; (void)modify_add_values( e, &mod, /* permissive */ 1, &text, textbuf, sizeof( textbuf ) ); @@ -248,8 +249,7 @@ dynlist_sc_update( Operation *op, SlapReply *rs ) } /* test access to attribute */ - for ( i = 0; !BER_BVISNULL( &a->a_vals[i] ); i++ ) - /* just count */ ; + i = a->a_numvals; vals = op->o_tmpalloc( ( i + 1 ) * sizeof( struct berval ), op->o_tmpmemctx ); if ( a->a_nvals != a->a_vals ) { @@ -293,6 +293,7 @@ dynlist_sc_update( Operation *op, SlapReply *rs ) mod.sm_type = a->a_desc->ad_cname; mod.sm_values = vals; mod.sm_nvalues = nvals; + mod.sm_numvals = j; (void)modify_add_values( e, &mod, /* permissive */ 1, &text, textbuf, sizeof( textbuf ) ); @@ -635,7 +636,7 @@ dynlist_compare( Operation *op, SlapReply *rs ) } o.ors_filterstr = *slap_filterstr_objectClass_pres; - o.ors_filter = slap_filter_objectClass_pres; + o.ors_filter = (Filter *) slap_filter_objectClass_pres; o.ors_scope = LDAP_SCOPE_BASE; o.ors_deref = LDAP_DEREF_NEVER; @@ -673,10 +674,10 @@ dynlist_compare( Operation *op, SlapReply *rs ) /* if we're here, we got a match... */ rs->sr_err = LDAP_COMPARE_FALSE; - if ( value_find_ex( op->orc_ava->aa_desc, + if ( attr_valfind( a, SLAP_MR_ATTRIBUTE_VALUE_NORMALIZED_MATCH | SLAP_MR_ASSERTED_VALUE_NORMALIZED_MATCH, - a->a_nvals, &op->orc_ava->aa_value, op->o_tmpmemctx ) == 0 ) + &op->orc_ava->aa_value, NULL, op->o_tmpmemctx ) == 0 ) { rs->sr_err = LDAP_COMPARE_TRUE; break; diff --git a/servers/slapd/overlays/memberof.c b/servers/slapd/overlays/memberof.c index 5bbe2a2dbf..40cf08b930 100644 --- a/servers/slapd/overlays/memberof.c +++ b/servers/slapd/overlays/memberof.c @@ -195,7 +195,7 @@ memberof_saved_member_get( Operation *op, void *keyp ) BerVarray vals; BerVarray *key = (BerVarray *)keyp; - assert( op ); + assert( op != NULL ); if ( op->o_threadctx == NULL ) { vals = *key; @@ -217,7 +217,7 @@ memberof_saved_member_set( Operation *op, void *keyp, BerVarray vals ) BerVarray saved_vals = NULL; BerVarray *key = (BerVarray*)keyp; - assert( op ); + assert( op != NULL ); if ( vals ) { ber_bvarray_dup_x( &saved_vals, vals, NULL ); @@ -268,8 +268,8 @@ memberof_saveMember_cb( Operation *op, SlapReply *rs ) mc = (memberof_cookie_t *)op->o_callback->sc_private; mc->foundit = 1; - assert( rs->sr_entry ); - assert( rs->sr_entry->e_attrs ); + assert( rs->sr_entry != NULL ); + assert( rs->sr_entry->e_attrs != NULL ); a = attr_find( rs->sr_entry->e_attrs, mc->ad ); @@ -416,6 +416,7 @@ memberof_value_modify( op2.o_ndn = op->o_bd->be_rootndn; ml = &mod[ 0 ]; + ml->sml_numvals = 1; ml->sml_values = &values[ 0 ]; ml->sml_values[ 0 ] = mo->mo_dn; BER_BVZERO( &ml->sml_values[ 1 ] ); @@ -430,6 +431,7 @@ memberof_value_modify( op2.orm_modlist = ml; ml = &mod[ 1 ]; + ml->sml_numvals = 1; ml->sml_values = &values[ 2 ]; BER_BVZERO( &ml->sml_values[ 1 ] ); ml->sml_nvalues = &nvalues[ 2 ]; @@ -778,7 +780,7 @@ memberof_op_modify( Operation *op, SlapReply *rs ) case LDAP_MOD_ADD: /* NOTE: right now, the attributeType we use * for member must have a normalized value */ - assert( ml->sml_nvalues ); + assert( ml->sml_nvalues != NULL ); for ( i = 0; !BER_BVISNULL( &ml->sml_nvalues[ i ] ); i++ ) { int rc; @@ -812,6 +814,7 @@ memberof_op_modify( Operation *op, SlapReply *rs ) BER_BVZERO( &ml->sml_values[ i ] ); ber_memfree( ml->sml_nvalues[ i ].bv_val ); BER_BVZERO( &ml->sml_nvalues[ i ] ); + ml->sml_numvals--; if ( j - i == 1 ) { break; } @@ -909,6 +912,7 @@ memberof_op_modify( Operation *op, SlapReply *rs ) ber_memfree( ml->sml_nvalues[ i ].bv_val ); BER_BVZERO( &ml->sml_nvalues[ i ] ); } + ml->sml_numvals--; if ( j - i == 1 ) { break; } @@ -1019,6 +1023,7 @@ memberof_op_modify( Operation *op, SlapReply *rs ) ber_memfree( ml->sml_nvalues[ i ].bv_val ); BER_BVZERO( &ml->sml_nvalues[ i ] ); } + ml->sml_numvals--; if ( j - i == 1 ) { break; } diff --git a/servers/slapd/overlays/pcache.c b/servers/slapd/overlays/pcache.c index 71e04db825..70ef66ac55 100644 --- a/servers/slapd/overlays/pcache.c +++ b/servers/slapd/overlays/pcache.c @@ -1367,8 +1367,7 @@ remove_func ( attr = attr_find( rs->sr_entry->e_attrs, ad_queryId ); if ( attr == NULL ) return 0; - for ( count = 0; !BER_BVISNULL( &attr->a_vals[count] ); count++ ) - ; + count = attr->a_numvals; assert( count > 0 ); qi = op->o_tmpalloc( sizeof( struct query_info ), op->o_tmpmemctx ); qi->next = op->o_callback->sc_private; @@ -1450,6 +1449,7 @@ remove_query_data( mod.sml_type = ad_queryId->ad_cname; mod.sml_values = vals; mod.sml_nvalues = NULL; + mod.sml_numvals = 1; mod.sml_next = NULL; Debug( pcache_debug, "REMOVING TEMP ATTR : TEMPLATE=%s\n", @@ -3354,6 +3354,7 @@ pcache_db_close( mod.sml_type = ad_cachedQueryURL->ad_cname; mod.sml_values = vals; mod.sml_nvalues = NULL; + mod.sml_numvals = 1; mod.sml_next = NULL; Debug( pcache_debug, "%sSETTING CACHED QUERY URLS\n", diff --git a/servers/slapd/overlays/ppolicy.c b/servers/slapd/overlays/ppolicy.c index 2900c64c31..e126598055 100644 --- a/servers/slapd/overlays/ppolicy.c +++ b/servers/slapd/overlays/ppolicy.c @@ -921,6 +921,7 @@ ppolicy_bind_response( Operation *op, SlapReply *rs ) m->sml_flags = 0; m->sml_type = ad_pwdFailureTime->ad_cname; m->sml_desc = ad_pwdFailureTime; + m->sml_numvals = 1; m->sml_values = ch_calloc( sizeof(struct berval), 2 ); m->sml_nvalues = ch_calloc( sizeof(struct berval), 2 ); @@ -970,6 +971,7 @@ ppolicy_bind_response( Operation *op, SlapReply *rs ) m->sml_flags = 0; m->sml_type = ad_pwdAccountLockedTime->ad_cname; m->sml_desc = ad_pwdAccountLockedTime; + m->sml_numvals = 1; m->sml_values = ch_calloc( sizeof(struct berval), 2 ); m->sml_nvalues = ch_calloc( sizeof(struct berval), 2 ); ber_dupbv( &m->sml_values[0], ×tamp ); @@ -1062,6 +1064,7 @@ grace: m->sml_flags = 0; m->sml_type = ad_pwdGraceUseTime->ad_cname; m->sml_desc = ad_pwdGraceUseTime; + m->sml_numvals = 1; m->sml_values = ch_calloc( sizeof(struct berval), 2 ); m->sml_nvalues = ch_calloc( sizeof(struct berval), 2 ); ber_dupbv( &m->sml_values[0], ×tamp ); @@ -1469,6 +1472,7 @@ ppolicy_modify( Operation *op, SlapReply *rs ) ml->sml_flags = SLAP_MOD_INTERNAL; ml->sml_type.bv_val = NULL; ml->sml_desc = ad_pwdGraceUseTime; + ml->sml_numvals = 0; ml->sml_values = NULL; ml->sml_nvalues = NULL; ml->sml_next = NULL; @@ -1481,6 +1485,7 @@ ppolicy_modify( Operation *op, SlapReply *rs ) ml->sml_flags = SLAP_MOD_INTERNAL; ml->sml_type.bv_val = NULL; ml->sml_desc = ad_pwdAccountLockedTime; + ml->sml_numvals = 0; ml->sml_values = NULL; ml->sml_nvalues = NULL; ml->sml_next = NULL; @@ -1492,6 +1497,7 @@ ppolicy_modify( Operation *op, SlapReply *rs ) ml->sml_flags = SLAP_MOD_INTERNAL; ml->sml_type.bv_val = NULL; ml->sml_desc = ad_pwdFailureTime; + ml->sml_numvals = 0; ml->sml_values = NULL; ml->sml_nvalues = NULL; ml->sml_next = NULL; @@ -1671,6 +1677,7 @@ ppolicy_modify( Operation *op, SlapReply *rs ) ml->sml_flags = SLAP_MOD_INTERNAL; ml->sml_desc = pp.ad; ml->sml_type = pp.ad->ad_cname; + ml->sml_numvals = 1; ml->sml_values = (BerVarray) ch_malloc( 2 * sizeof( struct berval ) ); ber_dupbv( &ml->sml_values[0], &oldpw ); BER_BVZERO( &ml->sml_values[1] ); @@ -1838,6 +1845,7 @@ do_modify: mods->sml_desc = ad_pwdChangedTime; if (pwmop != LDAP_MOD_DELETE) { mods->sml_op = LDAP_MOD_REPLACE; + mods->sml_numvals = 1; mods->sml_values = (BerVarray) ch_malloc( 2 * sizeof( struct berval ) ); ber_dupbv( &mods->sml_values[0], ×tamp ); BER_BVZERO( &mods->sml_values[1] ); @@ -1914,6 +1922,7 @@ do_modify: mods->sml_op = LDAP_MOD_DELETE; mods->sml_flags = SLAP_MOD_INTERNAL; mods->sml_desc = ad_pwdHistory; + mods->sml_numvals = hsize - pp.pwdInHistory + 1; mods->sml_values = ch_calloc( sizeof( struct berval ), hsize - pp.pwdInHistory + 2 ); BER_BVZERO( &mods->sml_values[ hsize - pp.pwdInHistory + 1 ] ); @@ -1945,6 +1954,7 @@ do_modify: mods->sml_type.bv_val = NULL; mods->sml_desc = ad_pwdHistory; mods->sml_nvalues = NULL; + mods->sml_numvals = 1; mods->sml_values = ch_calloc( sizeof( struct berval ), 2 ); mods->sml_values[ 1 ].bv_val = NULL; mods->sml_values[ 1 ].bv_len = 0; diff --git a/servers/slapd/overlays/refint.c b/servers/slapd/overlays/refint.c index 4afc7204e1..55fae2d0e6 100644 --- a/servers/slapd/overlays/refint.c +++ b/servers/slapd/overlays/refint.c @@ -54,6 +54,7 @@ typedef struct refint_attrs_s { BerVarray old_nvals; BerVarray new_vals; BerVarray new_nvals; + int ra_numvals; } refint_attrs; typedef struct dependents_s { @@ -423,6 +424,7 @@ refint_search_cb( ber_bvarray_add_x( &na->old_vals, &olddn, op->o_tmpmemctx ); ber_dupbv_x( &oldndn, &a->a_nvals[first], op->o_tmpmemctx ); ber_bvarray_add_x( &na->old_nvals, &oldndn, op->o_tmpmemctx ); + na->ra_numvals++; newsub = a->a_vals[first]; newsub.bv_len -= rq->olddn.bv_len + 1; @@ -445,6 +447,7 @@ refint_search_cb( ber_bvarray_add_x( &na->old_vals, &olddn, op->o_tmpmemctx ); ber_dupbv_x( &oldndn, &a->a_nvals[i], op->o_tmpmemctx ); ber_bvarray_add_x( &na->old_nvals, &oldndn, op->o_tmpmemctx ); + na->ra_numvals++; newsub = a->a_vals[i]; newsub.bv_len -= rq->olddn.bv_len + 1; @@ -461,7 +464,7 @@ refint_search_cb( ber_bvarray_add_x( &na->new_nvals, &newdn, op->o_tmpmemctx ); } - /* count deteles */ + /* count deletes */ if ( BER_BVISEMPTY( &rq->newdn ) ) { deleted++; } @@ -642,6 +645,7 @@ refint_qtask( void *ctx, void *arg ) m->sml_flags = SLAP_MOD_INTERNAL; m->sml_desc = slap_schema.si_ad_modifiersName; m->sml_type = m->sml_desc->ad_cname; + m->sml_numvals = 1; m->sml_values = (BerVarray)(m+1); m->sml_nvalues = m->sml_values+2; BER_BVZERO( &m->sml_values[1] ); @@ -672,6 +676,7 @@ refint_qtask( void *ctx, void *arg ) m->sml_nvalues = m->sml_values+2; BER_BVZERO( &m->sml_values[1] ); BER_BVZERO( &m->sml_nvalues[1] ); + m->sml_numvals = 1; if ( BER_BVISEMPTY( &rq->newdn )) { op->o_tmpfree( ra, op->o_tmpmemctx ); ra = dp->attrs; @@ -685,6 +690,7 @@ refint_qtask( void *ctx, void *arg ) } else { m->sml_values = ra->new_vals; m->sml_nvalues = ra->new_nvals; + m->sml_numvals = ra->ra_numvals; } } @@ -703,6 +709,7 @@ refint_qtask( void *ctx, void *arg ) m->sml_desc = ra->attr; m->sml_type = ra->attr->ad_cname; if ( ra->old_vals == NULL ) { + m->sml_numvals = 1; m->sml_values = (BerVarray)(m+1); m->sml_nvalues = m->sml_values+2; m->sml_values[0] = rq->olddn; @@ -712,6 +719,7 @@ refint_qtask( void *ctx, void *arg ) } else { m->sml_values = ra->old_vals; m->sml_nvalues = ra->old_nvals; + m->sml_numvals = ra->ra_numvals; } op->o_tmpfree( ra, op->o_tmpmemctx ); } diff --git a/servers/slapd/overlays/rwm.c b/servers/slapd/overlays/rwm.c index a6df790457..ed9fbfa9bb 100644 --- a/servers/slapd/overlays/rwm.c +++ b/servers/slapd/overlays/rwm.c @@ -226,9 +226,7 @@ rwm_op_add( Operation *op, SlapReply *rs ) { int j, last; - for ( last = 0; !BER_BVISNULL( &(*ap)->a_vals[ last ] ); last++ ) - /* count values */ ; - last--; + last = (*ap)->a_numvals - 1; for ( j = 0; !BER_BVISNULL( &(*ap)->a_vals[ j ] ); j++ ) { struct ldapmapping *mapping = NULL; @@ -245,6 +243,7 @@ rwm_op_add( Operation *op, SlapReply *rs ) (*ap)->a_vals[ j ] = (*ap)->a_vals[ last ]; } BER_BVZERO( &(*ap)->a_vals[ last ] ); + (*ap)->a_numvals--; last--; j--; } @@ -1057,9 +1056,8 @@ rwm_attrs( Operation *op, SlapReply *rs, Attribute** a_first, int stripEntryDN ) mapping->m_dst_ad->ad_type->sat_equality->smr_normalize ) { int i = 0; - for ( last = 0; !BER_BVISNULL( &(*ap)->a_vals[last] ); last++ ) - /* just count */ ; + last = (*ap)->a_numvals; if ( last ) { (*ap)->a_nvals = ch_malloc( (last+1) * sizeof(struct berval) ); @@ -1108,8 +1106,7 @@ rwm_attrs( Operation *op, SlapReply *rs, Attribute** a_first, int stripEntryDN ) } if ( last == -1 ) { /* not yet counted */ - for ( last = 0; !BER_BVISNULL( &(*ap)->a_vals[last] ); last++ ) - /* just count */ ; + last = (*ap)->a_numvals; } if ( last == 0 ) { @@ -1228,6 +1225,7 @@ cleanup_attr:; mod.sm_op = LDAP_MOD_ADD; mod.sm_desc = (*ap)->a_desc; mod.sm_type = mod.sm_desc->ad_cname; + mod.sm_numvals = (*tap)->a_numvals; mod.sm_values = (*tap)->a_vals; mod.sm_nvalues = (*tap)->a_nvals; diff --git a/servers/slapd/overlays/syncprov.c b/servers/slapd/overlays/syncprov.c index bbdbf30085..9cae2c53dc 100644 --- a/servers/slapd/overlays/syncprov.c +++ b/servers/slapd/overlays/syncprov.c @@ -1287,6 +1287,7 @@ syncprov_checkpoint( Operation *op, SlapReply *rs, slap_overinst *on ) SlapReply rsm = { 0 }; slap_callback cb = {0}; + mod.sml_numvals = si->si_numcsns; mod.sml_values = si->si_ctxcsn; mod.sml_nvalues = NULL; mod.sml_desc = slap_schema.si_ad_contextCSN; @@ -1679,10 +1680,10 @@ syncprov_op_compare( Operation *op, SlapReply *rs ) rs->sr_err = LDAP_COMPARE_FALSE; - if ( value_find_ex( op->oq_compare.rs_ava->aa_desc, + if ( attr_valfind( &a, SLAP_MR_ATTRIBUTE_VALUE_NORMALIZED_MATCH | SLAP_MR_ASSERTED_VALUE_NORMALIZED_MATCH, - a.a_nvals, &op->oq_compare.rs_ava->aa_value, op->o_tmpmemctx ) == 0 ) + &op->oq_compare.rs_ava->aa_value, NULL, op->o_tmpmemctx ) == 0 ) { rs->sr_err = LDAP_COMPARE_TRUE; } @@ -2306,9 +2307,9 @@ syncprov_operational( a->a_nvals = NULL; ber_bvarray_free( a->a_vals ); a->a_vals = NULL; + a->a_numvals = 0; } - ber_bvarray_dup_x( &a->a_vals, si->si_ctxcsn, NULL ); - ber_bvarray_dup_x( &a->a_nvals, si->si_ctxcsn, NULL ); + attr_valadd( a, si->si_ctxcsn, si->si_ctxcsn, si->si_numcsns ); } ldap_pvt_thread_rdwr_runlock( &si->si_csn_rwlock ); } @@ -2554,11 +2555,9 @@ syncprov_db_open( a = attr_find( e->e_attrs, slap_schema.si_ad_contextCSN ); if ( a ) { - int i; ber_bvarray_dup_x( &si->si_ctxcsn, a->a_vals, NULL ); - for ( i = 0; !BER_BVISNULL( &a->a_vals[i] ); i++ ); - si->si_numcsns = i; - si->si_sids = slap_parse_csn_sids( si->si_ctxcsn, i, NULL ); + si->si_numcsns = a->a_numvals; + si->si_sids = slap_parse_csn_sids( si->si_ctxcsn, a->a_numvals, NULL ); } overlay_entry_release_ov( op, e, 0, on ); if ( si->si_ctxcsn ) { diff --git a/servers/slapd/overlays/translucent.c b/servers/slapd/overlays/translucent.c index dce035531d..db9079692f 100644 --- a/servers/slapd/overlays/translucent.c +++ b/servers/slapd/overlays/translucent.c @@ -147,6 +147,7 @@ void glue_parent(Operation *op) { ber_dupbv(&e->e_nname, &ndn); a = attr_alloc( slap_schema.si_ad_objectClass ); + a->a_numvals = 2; a->a_vals = ch_malloc(sizeof(struct berval) * 3); ber_dupbv(&a->a_vals[0], &glue[0]); ber_dupbv(&a->a_vals[1], &glue[1]); @@ -156,6 +157,7 @@ void glue_parent(Operation *op) { e->e_attrs = a; a = attr_alloc( slap_schema.si_ad_structuralObjectClass ); + a->a_numvals = 1; a->a_vals = ch_malloc(sizeof(struct berval) * 2); ber_dupbv(&a->a_vals[0], &glue[1]); ber_dupbv(&a->a_vals[1], &glue[2]); @@ -428,6 +430,8 @@ release: atmp.a_desc = m->sml_desc; atmp.a_vals = m->sml_values; atmp.a_nvals = m->sml_nvalues ? m->sml_nvalues : atmp.a_vals; + atmp.a_numvals = m->sml_numvals; + atmp.a_flags = 0; a = attr_dup( &atmp ); a->a_next = ax; ax = a; diff --git a/servers/slapd/overlays/valsort.c b/servers/slapd/overlays/valsort.c index 5950a208c4..5cc06cfaf0 100644 --- a/servers/slapd/overlays/valsort.c +++ b/servers/slapd/overlays/valsort.c @@ -304,9 +304,7 @@ valsort_response( Operation *op, SlapReply *rs ) a = attr_find( rs->sr_entry->e_attrs, vi->vi_ad ); } - /* count values */ - for ( n = 0; !BER_BVISNULL( &a->a_vals[n] ); n++ ); - + n = a->a_numvals; if ( vi->vi_sort & VALSORT_WEIGHTED ) { int j, gotnvals; long *index = op->o_tmpalloc( n * sizeof(long), op->o_tmpmemctx ); diff --git a/servers/slapd/passwd.c b/servers/slapd/passwd.c index a287bf0356..7444b179c2 100644 --- a/servers/slapd/passwd.c +++ b/servers/slapd/passwd.c @@ -252,6 +252,7 @@ old_good: nhash = 1; hashes = (char **)defhash; } + ml->sml_numvals = nhash; ml->sml_values = ch_malloc( (nhash+1)*sizeof(struct berval) ); for ( i=0; hashes[i]; i++ ) { slap_passwd_hash_type( &qpw->rs_new, &hash, hashes[i], &rs->sr_text ); diff --git a/servers/slapd/proto-slap.h b/servers/slapd/proto-slap.h index ec130c4160..fbbc9ae675 100644 --- a/servers/slapd/proto-slap.h +++ b/servers/slapd/proto-slap.h @@ -268,6 +268,15 @@ LDAP_SLAPD_F (void) comp_tree_free LDAP_P(( Attribute *a )); LDAP_SLAPD_F (Attribute *) attr_alloc LDAP_P(( AttributeDescription *ad )); LDAP_SLAPD_F (Attribute *) attrs_alloc LDAP_P(( int num )); LDAP_SLAPD_F (int) attr_prealloc LDAP_P(( int num )); +LDAP_SLAPD_F (int) attr_valfind LDAP_P(( Attribute *a, + unsigned flags, + struct berval *val, + unsigned *slot, + void *ctx )); +LDAP_SLAPD_F (int) attr_valadd LDAP_P(( Attribute *a, + BerVarray vals, + BerVarray nvals, + int num )); LDAP_SLAPD_F (int) attr_merge LDAP_P(( Entry *e, AttributeDescription *desc, BerVarray vals, @@ -1162,6 +1171,12 @@ LDAP_SLAPD_F( int ) slap_mods_check( const char **text, char *textbuf, size_t textlen, void *ctx ); +LDAP_SLAPD_F( int ) slap_sort_vals( + Modifications *ml, + const char **text, + int *dup, + void *ctx ); + LDAP_SLAPD_F( void ) slap_timestamp( time_t *tm, struct berval *bv ); @@ -1803,8 +1818,7 @@ LDAP_SLAPD_F (int) ordered_value_match LDAP_P(( const char ** text )); LDAP_SLAPD_F (void) ordered_value_renumber LDAP_P(( - Attribute *a, - int vals )); + Attribute *a )); LDAP_SLAPD_F (int) ordered_value_sort LDAP_P(( Attribute *a, diff --git a/servers/slapd/sasl.c b/servers/slapd/sasl.c index 9e019fdec0..d9a604efc1 100644 --- a/servers/slapd/sasl.c +++ b/servers/slapd/sasl.c @@ -455,6 +455,7 @@ slap_auxprop_store( mod->sml_op = LDAP_MOD_REPLACE; mod->sml_flags = 0; ber_str2bv( pr[i].name, 0, 0, &mod->sml_type ); + mod->sml_numvals = pr[i].nvalues; mod->sml_values = (struct berval *)ch_malloc( (pr[i].nvalues + 1) * sizeof(struct berval)); for (j=0; ja_nvals, &ava->la_value, NULL ); + &ava->la_value, NULL, NULL ); if( rc != 0 ) { switch( rc ) { diff --git a/servers/slapd/slap.h b/servers/slapd/slap.h index b04ccd3f7a..65319e1a6e 100644 --- a/servers/slapd/slap.h +++ b/servers/slapd/slap.h @@ -690,10 +690,19 @@ struct AttributeType { #define SLAP_AT_MANAGEABLE 0x0800U /* no-user-mod can be by-passed */ +/* Note: ORDERED values have an ordering specifically set by the + * user, denoted by the {x} ordering prefix on the values. + * + * SORTED values are simply sorted by memcmp. SORTED values can + * be efficiently located by binary search. ORDERED values have no + * such advantage. An attribute cannot have both properties. + */ #define SLAP_AT_ORDERED_VAL 0x0001U /* values are ordered */ #define SLAP_AT_ORDERED_SIB 0x0002U /* siblings are ordered */ #define SLAP_AT_ORDERED 0x0003U /* value has order index */ +#define SLAP_AT_SORTED_VAL 0x0010U /* values should be sorted */ + #define SLAP_AT_HARDCODE 0x10000U /* hardcoded schema */ #define SLAP_AT_DELETED 0x20000U @@ -1109,20 +1118,28 @@ struct ValuesReturnFilter { /* * represents an attribute (description + values) + * desc, vals, nvals, numvals fields must align with Modification */ struct Attribute { AttributeDescription *a_desc; BerVarray a_vals; /* preserved values */ BerVarray a_nvals; /* normalized values */ -#ifdef LDAP_COMP_MATCH - ComponentData *a_comp_data; /* component values */ -#endif - Attribute *a_next; + unsigned a_numvals; /* number of vals */ unsigned a_flags; #define SLAP_ATTR_IXADD 0x1U #define SLAP_ATTR_IXDEL 0x2U #define SLAP_ATTR_DONT_FREE_DATA 0x4U #define SLAP_ATTR_DONT_FREE_VALS 0x8U +#define SLAP_ATTR_SORTED_VALS 0x10U /* values are sorted */ + +/* These flags persist across an attr_dup() */ +#define SLAP_ATTR_PERSISTENT_FLAGS \ + SLAP_ATTR_SORTED_VALS + + Attribute *a_next; +#ifdef LDAP_COMP_MATCH + ComponentData *a_comp_data; /* component values */ +#endif }; @@ -1169,8 +1186,13 @@ struct Entry { /* * A list of LDAPMods + * desc, values, nvalues, numvals must align with Attribute */ struct Modification { + AttributeDescription *sm_desc; + BerVarray sm_values; + BerVarray sm_nvalues; + unsigned sm_numvals; short sm_op; short sm_flags; /* Set for internal mods, will bypass ACL checks. Only needed when @@ -1178,11 +1200,7 @@ struct Modification { */ #define SLAP_MOD_INTERNAL 0x01 #define SLAP_MOD_MANAGING 0x02 - - AttributeDescription *sm_desc; struct berval sm_type; - BerVarray sm_values; - BerVarray sm_nvalues; }; struct Modifications { @@ -1193,17 +1211,10 @@ struct Modifications { #define sml_type sml_mod.sm_type #define sml_values sml_mod.sm_values #define sml_nvalues sml_mod.sm_nvalues +#define sml_numvals sml_mod.sm_numvals Modifications *sml_next; }; -struct LDAPModList { - LDAPMod ml_mod; - LDAPModList *ml_next; -#define ml_op ml_mod.mod_op -#define ml_type ml_mod.mod_type -#define ml_values ml_mod.mod_values -}; - /* * represents an access control list */ diff --git a/servers/slapd/slapi/slapi_utils.c b/servers/slapd/slapi/slapi_utils.c index 99d5ccbc33..6c37e3b7f4 100644 --- a/servers/slapd/slapi/slapi_utils.c +++ b/servers/slapd/slapi/slapi_utils.c @@ -72,7 +72,8 @@ static int checkBVString(const struct berval *bv) int bvptr2obj( struct berval **bvptr, - BerVarray *bvobj ) + BerVarray *bvobj, + unsigned *num ) { int rc = LDAP_SUCCESS; int i; @@ -85,6 +86,8 @@ bvptr2obj( for ( i = 0; bvptr != NULL && bvptr[i] != NULL; i++ ) { ; /* EMPTY */ } + if ( num ) + *num = i; tmpberval = (BerVarray)slapi_ch_malloc( (i + 1)*sizeof(struct berval)); if ( tmpberval == NULL ) { @@ -231,12 +234,12 @@ slapi_entry_attr_merge( return -1; } - rc = bvptr2obj( vals, &bv ); + rc = bvptr2obj( vals, &bv, NULL ); if ( rc != LDAP_SUCCESS ) { return -1; } - rc = attr_merge_normalize_one( e, ad, bv, NULL ); + rc = attr_merge_normalize( e, ad, bv, NULL ); ch_free( bv ); return rc; @@ -545,9 +548,10 @@ slapi_entry_add_values( Slapi_Entry *e, const char *type, struct berval **vals ) * FIXME: sm_values = NULL ? */ mod.sm_values = (BerVarray)ch_malloc( sizeof(struct berval) ); mod.sm_values->bv_val = NULL; + mod.sm_numvals = 0; } else { - rc = bvptr2obj( vals, &mod.sm_values ); + rc = bvptr2obj( vals, &mod.sm_values, &mod.sm_numvals ); if ( rc != LDAP_SUCCESS ) { return LDAP_CONSTRAINT_VIOLATION; } @@ -611,7 +615,7 @@ slapi_entry_delete_values( Slapi_Entry *e, const char *type, struct berval **val return attr_delete( &e->e_attrs, mod.sm_desc ) ? LDAP_OTHER : LDAP_SUCCESS; } - rc = bvptr2obj( vals, &mod.sm_values ); + rc = bvptr2obj( vals, &mod.sm_values, &mod.sm_numvals ); if ( rc != LDAP_SUCCESS ) { return LDAP_CONSTRAINT_VIOLATION; } @@ -730,7 +734,7 @@ slapi_entry_attr_replace_sv( Slapi_Entry *e, const char *type, Slapi_Value **val attr_delete( &e->e_attrs, ad ); - rc = bvptr2obj( vals, &bv ); + rc = bvptr2obj( vals, &bv, NULL ); if ( rc != LDAP_SUCCESS ) { return -1; } @@ -1350,7 +1354,7 @@ slapi_send_ldap_result( if ( pb->pb_op->o_tag == LDAP_REQ_SEARCH ) rs->sr_nentries = nentries; if ( urls != NULL ) - bvptr2obj( urls, &rs->sr_ref ); + bvptr2obj( urls, &rs->sr_ref, NULL ); send_ldap_result( pb->pb_op, rs ); @@ -1429,7 +1433,7 @@ slapi_send_ldap_search_reference( rs.sr_matched = NULL; rs.sr_text = NULL; - rc = bvptr2obj( references, &rs.sr_ref ); + rc = bvptr2obj( references, &rs.sr_ref, NULL ); if ( rc != LDAP_SUCCESS ) { return rc; } @@ -1440,7 +1444,7 @@ slapi_send_ldap_search_reference( rs.sr_entry = e; if ( v2refs != NULL ) { - rc = bvptr2obj( v2refs, &rs.sr_v2ref ); + rc = bvptr2obj( v2refs, &rs.sr_v2ref, NULL ); if ( rc != LDAP_SUCCESS ) { slapi_ch_free( (void **)&rs.sr_ref ); return rc; @@ -2148,28 +2152,15 @@ int slapi_attr_value_cmp( const Slapi_Attr *a, const struct berval *v1, const st int slapi_attr_value_find( const Slapi_Attr *a, struct berval *v ) { - MatchingRule *mr; - struct berval *bv; - int j; - const char *text; int rc; int ret; if ( a ->a_vals == NULL ) { return -1; } - mr = a->a_desc->ad_type->sat_equality; - for ( bv = a->a_vals, j = 0; bv->bv_val != NULL; bv++, j++ ) { - rc = value_match( &ret, a->a_desc, mr, - SLAP_MR_VALUE_OF_ASSERTION_SYNTAX, bv, v, &text ); - if ( rc != LDAP_SUCCESS ) { - return -1; - } - if ( ret == 0 ) { - return 0; - } - } - return -1; + rc = attr_valfind( (Attribute *)a, SLAP_MR_VALUE_OF_ASSERTION_SYNTAX, v, + NULL, NULL ); + return rc == 0 ? 0 : -1; } int slapi_attr_type_cmp( const char *t1, const char *t2, int opt ) @@ -2720,6 +2711,7 @@ Modifications *slapi_int_ldapmods2modifications ( Operation *op, LDAPMod **mods i++; } } + mod->sml_numvals = i; if ( i == 0 ) { mod->sml_values = NULL; diff --git a/servers/slapd/syncrepl.c b/servers/slapd/syncrepl.c index af6de8893d..a657088bed 100644 --- a/servers/slapd/syncrepl.c +++ b/servers/slapd/syncrepl.c @@ -562,9 +562,7 @@ do_syncrep1( ldap_pvt_thread_mutex_lock( &si->si_cookieState->cs_mutex ); rc = backend_operational( op, &rs ); if ( rc == LDAP_SUCCESS && a.a_vals ) { - int num; - for (i=0; !BER_BVISNULL( &a.a_vals[i] ); i++) ; - num = i; + int num = a.a_numvals; /* check for differences */ if ( num != si->si_cookieState->cs_num ) { changed = 1; @@ -1383,6 +1381,7 @@ syncrepl_accesslog_mods( mod->sml_type = ad->ad_cname; mod->sml_values = NULL; mod->sml_nvalues = NULL; + mod->sml_numvals = 0; *modtail = mod; modtail = &mod->sml_next; @@ -1392,6 +1391,7 @@ syncrepl_accesslog_mods( bv.bv_len = vals[i].bv_len - ( bv.bv_val - vals[i].bv_val ); ber_dupbv( &bv2, &bv ); ber_bvarray_add( &mod->sml_values, &bv2 ); + mod->sml_numvals++; } } return modlist; @@ -1724,6 +1724,7 @@ syncrepl_message_to_entry( mod->sml_type = tmp.sml_type; mod->sml_values = tmp.sml_values; mod->sml_nvalues = NULL; + mod->sml_numvals = 0; /* slap_mods_check will set this */ *modtail = mod; modtail = &mod->sml_next; @@ -2337,6 +2338,7 @@ syncrepl_del_nonpresent( mod1.sml_flags = 0; mod1.sml_desc = slap_schema.si_ad_objectClass; mod1.sml_type = mod1.sml_desc->ad_cname; + mod1.sml_numvals = 2; mod1.sml_values = &gcbva[0]; mod1.sml_nvalues = NULL; mod1.sml_next = &mod2; @@ -2345,6 +2347,7 @@ syncrepl_del_nonpresent( mod2.sml_flags = 0; mod2.sml_desc = slap_schema.si_ad_structuralObjectClass; mod2.sml_type = mod2.sml_desc->ad_cname; + mod1.sml_numvals = 1; mod2.sml_values = &gcbva[1]; mod2.sml_nvalues = NULL; mod2.sml_next = NULL; @@ -2472,6 +2475,7 @@ syncrepl_add_glue( a = attr_alloc( slap_schema.si_ad_objectClass ); + a->a_numvals = 2; a->a_vals = ch_calloc( 3, sizeof( struct berval ) ); ber_dupbv( &a->a_vals[0], &gcbva[0] ); ber_dupbv( &a->a_vals[1], &gcbva[1] ); @@ -2484,6 +2488,7 @@ syncrepl_add_glue( a = attr_alloc( slap_schema.si_ad_structuralObjectClass ); + a->a_numvals = 1; a->a_vals = ch_calloc( 2, sizeof( struct berval ) ); ber_dupbv( &a->a_vals[0], &gcbva[1] ); ber_dupbv( &a->a_vals[1], &gcbva[2] ); @@ -2562,6 +2567,7 @@ syncrepl_updateCookie( mod[0].sml_type = mod[0].sml_desc->ad_cname; mod[0].sml_values = NULL; mod[0].sml_nvalues = NULL; + mod[0].sml_numvals = 0; mod[0].sml_next = &mod[1]; mod[1].sml_op = LDAP_MOD_ADD; @@ -2569,6 +2575,7 @@ syncrepl_updateCookie( mod[1].sml_type = mod[0].sml_desc->ad_cname; mod[1].sml_values = NULL; mod[1].sml_nvalues = NULL; + mod[1].sml_numvals = 0; mod[1].sml_next = NULL; ldap_pvt_thread_mutex_lock( &si->si_cookieState->cs_mutex ); @@ -2584,8 +2591,10 @@ syncrepl_updateCookie( si->si_cookieState->cs_vals[j].bv_val, len ) > 0 ) { ber_bvarray_add_x( &mod[0].sml_values, &si->si_cookieState->cs_vals[j], op->o_tmpmemctx ); + mod[0].sml_numvals++; ber_bvarray_add_x( &mod[1].sml_values, &syncCookie->ctxcsn[i], op->o_tmpmemctx ); + mod[1].sml_numvals++; if ( BER_BVISNULL( &first )) first = syncCookie->ctxcsn[i]; } @@ -2595,6 +2604,7 @@ syncrepl_updateCookie( if ( j == si->si_cookieState->cs_num ) { ber_bvarray_add_x( &mod[1].sml_values, &syncCookie->ctxcsn[i], op->o_tmpmemctx ); + mod[1].sml_numvals++; if ( BER_BVISNULL( &first )) first = syncCookie->ctxcsn[i]; } @@ -2727,6 +2737,7 @@ attr_cmp( Operation *op, Attribute *old, Attribute *new, mod->sml_flags = 0; mod->sml_desc = old->a_desc; mod->sml_type = mod->sml_desc->ad_cname; + mod->sml_numvals = no; mod->sml_values = ch_malloc( ( no + 1 ) * sizeof(struct berval) ); if ( old->a_vals != old->a_nvals ) { mod->sml_nvalues = ch_malloc( ( no + 1 ) * sizeof(struct berval) ); @@ -2758,6 +2769,7 @@ attr_cmp( Operation *op, Attribute *old, Attribute *new, mod->sml_flags = 0; mod->sml_desc = old->a_desc; mod->sml_type = mod->sml_desc->ad_cname; + mod->sml_numvals = nn; mod->sml_values = ch_malloc( ( nn + 1 ) * sizeof(struct berval) ); if ( old->a_vals != old->a_nvals ) { mod->sml_nvalues = ch_malloc( ( nn + 1 ) * sizeof(struct berval) ); @@ -2846,11 +2858,11 @@ dn_callback( oldRDN.bv_len -= oldVal.bv_len + 2; slap_bv2ad( &oldRDN, &ad, &rs->sr_text ); a = attr_find( dni->new_entry->e_attrs, ad ); - if ( !a || value_find_ex( ad, + if ( !a || attr_valfind( a, SLAP_MR_ASSERTED_VALUE_NORMALIZED_MATCH | SLAP_MR_ATTRIBUTE_VALUE_NORMALIZED_MATCH | - SLAP_MR_VALUE_OF_SYNTAX, a->a_nvals, - &oldVal, op->o_tmpmemctx ) != LDAP_SUCCESS ) + SLAP_MR_VALUE_OF_SYNTAX, + &oldVal, NULL, op->o_tmpmemctx ) != LDAP_SUCCESS ) { dni->delOldRDN = 1; } @@ -2937,6 +2949,7 @@ dn_callback( mod->sml_flags = 0; mod->sml_desc = old->a_desc; mod->sml_type = mod->sml_desc->ad_cname; + mod->sml_numvals = 0; mod->sml_values = NULL; mod->sml_nvalues = NULL; *modtail = mod; diff --git a/servers/slapd/value.c b/servers/slapd/value.c index ac6ddd3c53..0aecdb3293 100644 --- a/servers/slapd/value.c +++ b/servers/slapd/value.c @@ -263,7 +263,7 @@ int value_find_ex( /* assign new indexes to an attribute's ordered values */ void -ordered_value_renumber( Attribute *a, int vals ) +ordered_value_renumber( Attribute *a ) { char *ptr, ibuf[64]; /* many digits */ struct berval ibv, tmp, vtmp; @@ -271,7 +271,7 @@ ordered_value_renumber( Attribute *a, int vals ) ibv.bv_val = ibuf; - for (i=0; ia_numvals; i++) { ibv.bv_len = sprintf(ibv.bv_val, "{%d}", i); vtmp = a->a_vals[i]; if ( vtmp.bv_val[0] == '{' ) { @@ -405,7 +405,7 @@ ordered_value_sort( Attribute *a, int do_renumber ) } if ( do_renumber && renumber ) - ordered_value_renumber( a, vals ); + ordered_value_renumber( a ); return 0; } @@ -706,16 +706,14 @@ ordered_value_add( vnum = i; if ( a ) { - for (i=0; !BER_BVISNULL( a->a_vals+i ); i++) ; - anum = i; ordered_value_sort( a, 0 ); } else { Attribute **ap; - anum = 0; for ( ap=&e->e_attrs; *ap; ap = &(*ap)->a_next ) ; a = attr_alloc( ad ); *ap = a; } + anum = a->a_numvals; new = ch_malloc( (anum+vnum+1) * sizeof(struct berval)); @@ -739,7 +737,7 @@ ordered_value_add( } if ( anum ) { AC_MEMCPY( new, a->a_vals, anum * sizeof(struct berval)); - if ( nnew ) + if ( nnew && a->a_nvals ) AC_MEMCPY( nnew, a->a_nvals, anum * sizeof(struct berval)); } @@ -789,7 +787,8 @@ ordered_value_add( a->a_nvals = a->a_vals; } - ordered_value_renumber( a, anum ); + a->a_numvals = anum; + ordered_value_renumber( a ); return 0; } -- 2.39.5