X-Git-Url: https://git.sur5r.net/?a=blobdiff_plain;f=servers%2Fslapd%2Fmods.c;h=f1dbdffcb804468ef7db1ad83b7d3e8358aeeae0;hb=fa1f4d3c38b332fc5faf6d84911df2618ce9af09;hp=946aa1b2a7eecc87539c45e21cff336d5d460c2f;hpb=603543ca2652575cce15ada3b8c7f8cedfa6b933;p=openldap diff --git a/servers/slapd/mods.c b/servers/slapd/mods.c index 946aa1b2a7..f1dbdffcb8 100644 --- a/servers/slapd/mods.c +++ b/servers/slapd/mods.c @@ -1,9 +1,18 @@ -/* - * Copyright 1998-2003 The OpenLDAP Foundation, All Rights Reserved. - * COPYING RESTRICTIONS APPLY, see COPYRIGHT file +/* $OpenLDAP$ */ +/* This work is part of OpenLDAP Software . + * + * Copyright 1998-2006 The OpenLDAP Foundation. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted only as authorized by the OpenLDAP + * Public License. + * + * A copy of this license is available in the file LICENSE in the + * top-level directory of the distribution or, alternatively, at + * . */ -/* - * Copyright (c) 1995 Regents of the University of Michigan. +/* Portions Copyright (c) 1995 Regents of the University of Michigan. * All rights reserved. * * Redistribution and use in source and binary forms are permitted @@ -16,284 +25,26 @@ #include "portable.h" -#include "slap.h" - -int -modify_check_duplicates( - AttributeDescription *ad, - MatchingRule *mr, - BerVarray vals, - BerVarray mods, - int permissive, - const char **text, - char *textbuf, size_t textlen ) -{ - int i, j, numvals = 0, nummods, - rc = LDAP_SUCCESS, matched; -#ifdef SLAP_NVALUES - /* needs major reworking */ -#else - BerVarray nvals = NULL, nmods = NULL; - - /* - * FIXME: better do the following - * - * - count the existing values - * - count the new values - * - * - if the existing values are less than the new ones { - * - normalize all the existing values - * - for each new value { - * - normalize - * - check with existing - * - cross-check with already normalized new vals - * } - * } else { - * - for each new value { - * - normalize - * - cross-check with already normalized new vals - * } - * - for each existing value { - * - normalize - * - check with already normalized new values - * } - * } - * - * The first case is good when adding a lot of new values, - * and significantly at first import of values (e.g. adding - * a new group); the latter case seems to be quite important - * as well, because it is likely to be the most frequently - * used when administering the entry. The current - * implementation will always normalize all the existing - * values before checking. If there's no duplicate, the - * performances should not change; they will in case of error. - */ - - for ( nummods = 0; mods[ nummods ].bv_val != NULL; nummods++ ) - /* count new values */ ; - - if ( vals ) { - for ( numvals = 0; vals[ numvals ].bv_val != NULL; numvals++ ) - /* count existing values */ ; - - if ( numvals < nummods ) { - nvals = SLAP_CALLOC( numvals + 1, sizeof( struct berval ) ); - if( nvals == NULL ) { -#ifdef NEW_LOGGING - LDAP_LOG( OPERATION, ERR, - "modify_check_duplicates: SLAP_CALLOC failed", 0, 0, 0 ); -#else - Debug( LDAP_DEBUG_ANY, - "modify_check_duplicates: SLAP_CALLOC failed", 0, 0, 0 ); -#endif - goto return_results; - } - - /* normalize the existing values first */ - for ( j = 0; vals[ j ].bv_val != NULL; j++ ) { - rc = value_normalize( ad, SLAP_MR_EQUALITY, - &vals[ j ], &nvals[ j ], text ); - - /* existing attribute values must normalize */ - assert( rc == LDAP_SUCCESS ); - - if ( rc != LDAP_SUCCESS ) { - nvals[ j ].bv_val = NULL; - goto return_results; - } - } - nvals[ j ].bv_val = NULL; - } - } - - /* - * If the existing values are less than the new values, - * it is more convenient to normalize all the existing - * values and test each new value against them first, - * then to other already normalized values - */ - nmods = SLAP_CALLOC( nummods + 1, sizeof( struct berval ) ); - if ( nmods == NULL ) { -#ifdef NEW_LOGGING - LDAP_LOG( OPERATION, ERR, - "modify_check_duplicates: SLAP_CALLOC failed", 0, 0, 0 ); -#else - Debug( LDAP_DEBUG_ANY, - "modify_check_duplicates: SLAP_CALLOC failed", 0, 0, 0 ); -#endif - goto return_results; - } - - for ( i=0; mods[i].bv_val != NULL; i++ ) { - rc = value_normalize( ad, SLAP_MR_EQUALITY, - &mods[i], &nmods[i], text ); - - if ( rc != LDAP_SUCCESS ) { - nmods[i].bv_val = NULL; - goto return_results; - } - - if ( numvals > 0 && numvals < nummods ) { - for ( matched=0, j=0; nvals[j].bv_val; j++ ) { - int match; - - rc = (*mr->smr_match)( &match, - SLAP_MR_ATTRIBUTE_SYNTAX_MATCH, - ad->ad_type->sat_syntax, - mr, &nmods[ i ], &nvals[ j ] ); - - if ( rc != LDAP_SUCCESS ) { - nmods[ i + 1 ].bv_val = NULL; - *text = textbuf; - snprintf( textbuf, textlen, - "%s: matching rule failed", - ad->ad_cname.bv_val ); - goto return_results; - } - - if ( match == 0 ) { - if ( permissive ) { - matched++; - continue; - } - *text = textbuf; - snprintf( textbuf, textlen, - "%s: value #%d provided more than once", - ad->ad_cname.bv_val, i ); - rc = LDAP_TYPE_OR_VALUE_EXISTS; - nmods[ i + 1 ].bv_val = NULL; - goto return_results; - } - } - - if ( permissive && matched == j ) { - nmods[ i + 1 ].bv_val = NULL; - rc = LDAP_TYPE_OR_VALUE_EXISTS; - goto return_results; - } - } - - for ( matched = 0, j = 0; j < i; j++ ) { - int match; - - rc = (*mr->smr_match)( &match, - SLAP_MR_ATTRIBUTE_SYNTAX_MATCH, - ad->ad_type->sat_syntax, - mr, &nmods[ i ], &nmods[ j ] ); - if ( rc != LDAP_SUCCESS ) { - nmods[ i + 1 ].bv_val = NULL; - *text = textbuf; - snprintf( textbuf, textlen, - "%s: matching rule failed", - ad->ad_cname.bv_val ); - goto return_results; - } +#include - if ( match == 0 ) { - if ( permissive ) { - matched++; - continue; - } - *text = textbuf; - snprintf( textbuf, textlen, - "%s: value #%d provided more than once", - ad->ad_cname.bv_val, j ); - rc = LDAP_TYPE_OR_VALUE_EXISTS; - nmods[ i + 1 ].bv_val = NULL; - goto return_results; - } - } - - if ( permissive && matched == j ) { - nmods[ i + 1 ].bv_val = NULL; - rc = LDAP_TYPE_OR_VALUE_EXISTS; - goto return_results; - } - } - nmods[ i ].bv_val = NULL; - - /* - * if new values are more than existing values, it is more - * convenient to normalize and check all new values first, - * then check each new value against existing values, which - * can be normalized in place - */ - - if ( numvals >= nummods ) { - for ( j = 0; vals[ j ].bv_val; j++ ) { - struct berval asserted; - - rc = value_normalize( ad, SLAP_MR_EQUALITY, - &vals[ j ], &asserted, text ); - - if ( rc != LDAP_SUCCESS ) { - goto return_results; - } - - for ( matched = 0, i = 0; nmods[ i ].bv_val; i++ ) { - int match; - - rc = (*mr->smr_match)( &match, - SLAP_MR_ATTRIBUTE_SYNTAX_MATCH, - ad->ad_type->sat_syntax, - mr, &nmods[ i ], &asserted ); - if ( rc != LDAP_SUCCESS ) { - *text = textbuf; - snprintf( textbuf, textlen, - "%s: matching rule failed", - ad->ad_cname.bv_val ); - goto return_results; - } - - if ( match == 0 ) { - if ( permissive ) { - matched++; - continue; - } - *text = textbuf; - snprintf( textbuf, textlen, - "%s: value #%d provided more than once", - ad->ad_cname.bv_val, j ); - rc = LDAP_TYPE_OR_VALUE_EXISTS; - goto return_results; - } - } - - if ( permissive && matched == i ) { - rc = LDAP_TYPE_OR_VALUE_EXISTS; - goto return_results; - } - } - } - -return_results:; - if ( nvals ) { - ber_bvarray_free( nvals ); - } - if ( nmods ) { - ber_bvarray_free( nmods ); - } - -#endif - return rc; -} +#include "slap.h" +#include "lutil.h" int modify_add_values( - Entry *e, + Entry *e, Modification *mod, - int permissive, + int permissive, const char **text, - char *textbuf, size_t textlen -) + char *textbuf, + size_t textlen ) { - int i, j; - int matched; + int rc; + const char *op; Attribute *a; - MatchingRule *mr = mod->sm_desc->ad_type->sat_equality; - const char *op; + Modification pmod = *mod; - switch( mod->sm_op ) { + switch ( mod->sm_op ) { case LDAP_MOD_ADD: op = "add"; break; @@ -305,22 +56,14 @@ modify_add_values( assert( 0 ); } + /* 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; - /* - * With permissive set, as long as the attribute being added - * has the same value(s?) as the existing attribute, then the - * modify will succeed. - */ - - /* check if the values we're adding already exist */ - if( mr == NULL || !mr->smr_match ) { -#ifdef SLAP_NVALUES - /* we should have no normalized values as there is no equality rule */ - /* assert( mod->sm_nvalues[0].bv_val == NULL); */ -#endif - - if ( a != NULL ) { + mr = mod->sm_desc->ad_type->sat_equality; + if( mr == NULL || !mr->smr_match ) { /* do not allow add of additional attribute if no equality rule exists */ *text = textbuf; @@ -330,176 +73,94 @@ modify_add_values( return LDAP_INAPPROPRIATE_MATCHING; } - for ( i = 0; mod->sm_bvalues[i].bv_val != NULL; i++ ) { - /* test asserted values against existing values */ - if( a ) { -#ifdef SLAP_NVALUES - /* we should have no normalized values as there - is no equality rule */ - assert( a->a_nvals == NULL); -#endif - for( matched = 0, j = 0; a->a_vals[j].bv_val != NULL; j++ ) { - if ( bvmatch( &mod->sm_bvalues[i], &a->a_vals[j] ) ) { - if ( permissive ) { - matched++; - continue; - } - /* value exists already */ - *text = textbuf; - snprintf( textbuf, textlen, - "modify/%s: %s: value #%i already exists", - op, mod->sm_desc->ad_cname.bv_val, j ); - return LDAP_TYPE_OR_VALUE_EXISTS; - } - } - if ( permissive && matched == j ) { - /* values already exist; do nothing */ - return LDAP_SUCCESS; - } + if ( permissive ) { + for ( i = 0; !BER_BVISNULL( &mod->sm_values[i] ); i++ ) { + /* EMPTY -- just counting 'em */; } - /* test asserted values against themselves */ - for( j = 0; j < i; j++ ) { - if ( bvmatch( &mod->sm_bvalues[i], - &mod->sm_bvalues[j] ) ) { - - /* value exists already */ - *text = textbuf; - snprintf( textbuf, textlen, - "modify/%s: %s: value #%i already exists", - op, mod->sm_desc->ad_cname.bv_val, j ); - return LDAP_TYPE_OR_VALUE_EXISTS; - } + pmod.sm_values = (BerVarray)ch_malloc( + (i + 1) * sizeof( struct berval )); + if ( pmod.sm_nvalues != NULL ) { + pmod.sm_nvalues = (BerVarray)ch_malloc( + (i + 1) * sizeof( struct berval )); } } - } else { -#ifdef SLAP_NVALUES /* no normalization is done in this routine nor * in the matching routines called by this routine. * values are now normalized once on input to the * server (whether from LDAP or from the underlying * database). - * This should outperform the old code. No numbers - * are available yet. */ -#else - /* - * The original code performs ( n ) normalizations - * and ( n * ( n - 1 ) / 2 ) matches, which hide - * the same number of normalizations. The new code - * performs the same number of normalizations ( n ) - * and ( n * ( n - 1 ) / 2 ) mem compares, far less - * expensive than an entire match, if a match is - * equivalent to a normalization and a mem compare ... - * - * This is far more memory expensive than the previous, - * but it can heavily improve performances when big - * chunks of data are added (typical example is a group - * with thousands of DN-syntax members; on my system: - * for members of 5-RDN DNs, - - members orig bvmatch (dirty) new - 1000 0m38.456s 0m0.553s 0m0.608s - 2000 2m33.341s 0m0.851s 0m1.003s - - * Moreover, 100 groups with 10000 members each were - * added in 37m27.933s (an analogous LDIF file was - * loaded into Active Directory in 38m28.682s, BTW). - * - * Maybe we could switch to the new algorithm when - * the number of values overcomes a given threshold? - */ -#endif + 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 ); + } - int rc; + if ( rc == LDAP_SUCCESS && match == 0 ) { + /* value already exists */ + if ( permissive ) break; - if ( mod->sm_bvalues[1].bv_val == 0 ) { - if ( a != NULL ) { - struct berval asserted; - int i; + *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; -#ifndef SLAP_NVALUES - rc = value_normalize( mod->sm_desc, SLAP_MR_EQUALITY, - &mod->sm_bvalues[ 0 ], &asserted, text ); - if ( rc != LDAP_SUCCESS ) { + } else if ( rc != LDAP_SUCCESS ) { return rc; } -#endif - - for ( matched = 0, i = 0; a->a_vals[ i ].bv_val; i++ ) { - int match; - -#ifdef SLAP_NVALUES - if( mod->sm_nvalues ) { - rc = 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[i], - &mod->sm_nvalues[0], - text ); - - } else { - rc = value_match( &match, mod->sm_desc, mr, - SLAP_MR_EQUALITY - | SLAP_MR_VALUE_OF_ATTRIBUTE_SYNTAX, - &a->a_vals[i], - &mod->sm_values[0], - text ); - } - -#else - rc = value_match( &match, mod->sm_desc, mr, - SLAP_MR_ATTRIBUTE_SYNTAX_MATCH, - &a->a_vals[i], - &asserted, - text ); -#endif + } - if( rc == LDAP_SUCCESS && match == 0 ) { - if ( permissive ) { - matched++; - continue; - } - free( asserted.bv_val ); - *text = textbuf; - snprintf( textbuf, textlen, - "modify/%s: %s: value #0 already exists", - op, mod->sm_desc->ad_cname.bv_val, 0 ); - return LDAP_TYPE_OR_VALUE_EXISTS; - } - } - if ( permissive && matched == i ) { - /* values already exist; do nothing */ - return LDAP_SUCCESS; + if ( permissive && match != 0 ) { + if ( pmod.sm_nvalues ) { + pmod.sm_nvalues[p] = mod->sm_nvalues[i]; } + pmod.sm_values[p++] = mod->sm_values[i]; } + } - } else { - rc = modify_check_duplicates( mod->sm_desc, mr, - a ? a->a_vals : NULL, mod->sm_bvalues, - permissive, - text, textbuf, textlen ); - - if ( permissive && rc == LDAP_TYPE_OR_VALUE_EXISTS ) { + if ( permissive ) { + if ( p == 0 ) { + /* all new values match exist */ + ch_free( pmod.sm_values ); + if ( pmod.sm_nvalues ) ch_free( pmod.sm_nvalues ); return LDAP_SUCCESS; } - if ( rc != LDAP_SUCCESS ) { - return rc; + BER_BVZERO( &pmod.sm_values[p] ); + if ( pmod.sm_nvalues ) { + BER_BVZERO( &pmod.sm_nvalues[p] ); } } } /* no - add them */ -#ifdef SLAP_NVALUES - if( attr_merge( e, mod->sm_desc, mod->sm_values, mod->sm_nvalues ) != 0 ) -#else - if( attr_merge( e, mod->sm_desc, mod->sm_bvalues ) != 0 ) -#endif - { + if ( mod->sm_desc->ad_type->sat_flags & SLAP_AT_ORDERED_VAL ) { + rc = ordered_value_add( e, mod->sm_desc, a, + pmod.sm_values, pmod.sm_nvalues ); + } else { + rc = attr_merge( e, mod->sm_desc, pmod.sm_values, pmod.sm_nvalues ); + } + + if ( a != NULL && permissive ) { + ch_free( pmod.sm_values ); + if ( pmod.sm_nvalues ) ch_free( pmod.sm_nvalues ); + } + + if ( rc != 0 ) { /* this should return result of attr_merge */ *text = textbuf; snprintf( textbuf, textlen, @@ -513,20 +174,29 @@ modify_add_values( int modify_delete_values( + Entry *e, + Modification *m, + int perm, + const char **text, + char *textbuf, size_t textlen ) +{ + return modify_delete_vindex( e, m, perm, text, textbuf, textlen, NULL ); +} + +int +modify_delete_vindex( Entry *e, Modification *mod, int permissive, const char **text, - char *textbuf, size_t textlen -) + 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; -#ifndef SLAP_NVALUES - BerVarray nvals = NULL; -#endif char dummy = '\0'; + int match = 0; /* * If permissive is set, then the non-existence of an @@ -534,7 +204,7 @@ modify_delete_values( */ /* delete the entire attribute */ - if ( mod->sm_bvalues == NULL ) { + if ( mod->sm_values == NULL ) { rc = attr_delete( &e->e_attrs, mod->sm_desc ); if( permissive ) { @@ -571,97 +241,36 @@ modify_delete_values( return LDAP_NO_SUCH_ATTRIBUTE; } -#ifndef SLAP_NVALUES - /* find each value to delete */ - for ( j = 0; a->a_vals[ j ].bv_val != NULL; j++ ) - /* count existing values */ ; - - nvals = (BerVarray)SLAP_CALLOC( j + 1, sizeof ( struct berval ) ); - if( nvals == NULL ) { -#ifdef NEW_LOGGING - LDAP_LOG( OPERATION, ERR, - "modify_delete_values: SLAP_CALLOC failed", 0, 0, 0 ); -#else - Debug( LDAP_DEBUG_ANY, - "modify_delete_values: SLAP_CALLOC failed", 0, 0, 0 ); -#endif - goto return_results; - } - - /* normalize existing values */ - for ( j = 0; a->a_vals[ j ].bv_val != NULL; j++ ) { - rc = value_normalize( a->a_desc, SLAP_MR_EQUALITY, - &a->a_vals[ j ], &nvals[ j ], text ); - - if ( rc != LDAP_SUCCESS ) { - nvals[ j ].bv_val = NULL; - goto return_results; - } - } -#endif - - for ( i = 0; mod->sm_values[i].bv_val != NULL; i++ ) { + for ( i = 0; !BER_BVISNULL( &mod->sm_values[i] ); i++ ) { int found = 0; -#ifndef SLAP_NVALUES - struct berval asserted; - - /* normalize the value to be deleted */ - rc = value_normalize( mod->sm_desc, SLAP_MR_EQUALITY, - &mod->sm_bvalues[ i ], &asserted, text ); - - if( rc != LDAP_SUCCESS ) { - goto return_results; - } - - /* search it */ - for ( j = 0; nvals[ j ].bv_val != NULL; j++ ) -#else - for ( j = 0; a->a_vals[j].bv_val != NULL; j++ ) -#endif - { - int match; - -#ifndef SLAP_NVALUES - if ( nvals[j].bv_val == &dummy ) { + for ( j = 0; !BER_BVISNULL( &a->a_vals[j] ); j++ ) { + /* skip already deleted values */ + if ( a->a_vals[j].bv_val == &dummy ) { continue; } -#endif -#ifdef SLAP_NVALUES if( mod->sm_nvalues ) { - assert( a->a_nvals ); - rc = (*mr->smr_match)( &match, - SLAP_MR_VALUE_OF_ASSERTION_SYNTAX + 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_desc->ad_type->sat_syntax, - mr, &a->a_nvals[j], - &mod->sm_nvalues[i] ); + &a->a_nvals[j], &mod->sm_nvalues[i], text ); } else { +#if 0 assert( a->a_nvals == NULL ); - rc = (*mr->smr_match)( &match, - SLAP_MR_VALUE_OF_ATTRIBUTE_SYNTAX, - a->a_desc->ad_type->sat_syntax, - mr, &a->a_nvals[j], - &mod->sm_values[i] ); - } -#else - rc = (*mr->smr_match)( &match, - SLAP_MR_ATTRIBUTE_SYNTAX_MATCH, - a->a_desc->ad_type->sat_syntax, - mr, &nvals[ j ], - &asserted ); #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 ) { -#ifndef SLAP_NVALUES - free( asserted.bv_val ); -#endif *text = textbuf; snprintf( textbuf, textlen, "%s: matching rule failed", mod->sm_desc->ad_cname.bv_val ); - goto return_results; + break; } if ( match != 0 ) { @@ -670,83 +279,58 @@ modify_delete_values( found = 1; + if ( idx ) + idx[i] = j; + /* delete value and mark it as dummy */ -#ifdef SLAP_NVALUES free( a->a_vals[j].bv_val ); a->a_vals[j].bv_val = &dummy; - if( a->a_nvals ) { + if( a->a_nvals != a->a_vals ) { free( a->a_nvals[j].bv_val ); a->a_nvals[j].bv_val = &dummy; } -#else - free( nvals[ j ].bv_val ); - nvals[ j ].bv_val = &dummy; -#endif break; } -#ifndef SLAP_NVALUES - free( asserted.bv_val ); -#endif - 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; - goto return_results; + if ( i > 0 ) { + break; + } else { + goto return_results; + } } } /* compact array skipping dummies */ -#ifdef SLAP_NVALUES - for ( k = 0, j = 0; a->a_vals[k].bv_val != NULL; k++ ) -#else - for ( k = 0, j = 0; nvals[k].bv_val != NULL; j++, k++ ) -#endif - { -#ifdef SLAP_NVALUES + for ( k = 0, j = 0; !BER_BVISNULL( &a->a_vals[k] ); k++ ) { /* skip dummies */ if( a->a_vals[k].bv_val == &dummy ) { - assert( a->a_nvals == NULL || a->a_nvals[k].bv_val == &dummy ); + assert( a->a_nvals[k].bv_val == &dummy ); continue; } -#else - /* delete and skip dummies */ ; - for ( ; nvals[ k ].bv_val == &dummy; k++ ) { - free( a->a_vals[ k ].bv_val ); - } -#endif if ( j != k ) { a->a_vals[ j ] = a->a_vals[ k ]; -#ifdef SLAP_NVALUES - if (a->a_nvals) { + if (a->a_nvals != a->a_vals) { a->a_nvals[ j ] = a->a_nvals[ k ]; } -#endif } -#ifndef SLAP_NVALUES - if ( a->a_vals[ k ].bv_val == NULL ) { - break; - } -#else j++; -#endif } - a->a_vals[j].bv_val = NULL; -#ifdef SLAP_NVALUES - if (a->a_nvals) a->a_nvals[j].bv_val = NULL; -#else - - assert( i == k - j ); -#endif + BER_BVZERO( &a->a_vals[j] ); + if (a->a_nvals != a->a_vals) { + BER_BVZERO( &a->a_nvals[j] ); + } /* if no values remain, delete the entire attribute */ - if ( a->a_vals[0].bv_val == NULL ) { + if ( BER_BVISNULL( &a->a_vals[0] ) ) { if ( attr_delete( &e->e_attrs, mod->sm_desc ) ) { *text = textbuf; snprintf( textbuf, textlen, @@ -754,20 +338,12 @@ modify_delete_values( mod->sm_desc->ad_cname.bv_val ); rc = LDAP_NO_SUCH_ATTRIBUTE; } + } else if ( a->a_desc->ad_type->sat_flags & SLAP_AT_ORDERED_VAL ) { + /* For an ordered attribute, renumber the value indices */ + ordered_value_sort( a, 1 ); } return_results:; -#ifndef SLAP_NVALUES - if ( nvals ) { - /* delete the remaining normalized values */ - for ( j = 0; nvals[ j ].bv_val != NULL; j++ ) { - if ( nvals[ j ].bv_val != &dummy ) { - ber_memfree( nvals[ j ].bv_val ); - } - } - ber_memfree( nvals ); - } -#endif return rc; } @@ -778,46 +354,117 @@ modify_replace_values( Modification *mod, int permissive, const char **text, - char *textbuf, size_t textlen -) + char *textbuf, size_t textlen ) { (void) attr_delete( &e->e_attrs, mod->sm_desc ); - if ( mod->sm_bvalues ) { + if ( mod->sm_values ) { return modify_add_values( e, mod, permissive, text, textbuf, textlen ); } return LDAP_SUCCESS; } +int +modify_increment_values( + Entry *e, + Modification *mod, + int permissive, + const char **text, + char *textbuf, size_t textlen ) +{ + Attribute *a; + + a = attr_find( e->e_attrs, mod->sm_desc ); + if( a == NULL ) { + if ( permissive ) { + Modification modReplace = *mod; + + modReplace.sm_op = LDAP_MOD_REPLACE; + + return modify_add_values(e, &modReplace, permissive, text, textbuf, textlen); + } else { + *text = textbuf; + snprintf( textbuf, textlen, + "modify/increment: %s: no such attribute", + mod->sm_desc->ad_cname.bv_val ); + return LDAP_NO_SUCH_ATTRIBUTE; + } + } + + if ( !strcmp( a->a_desc->ad_type->sat_syntax_oid, SLAPD_INTEGER_SYNTAX )) { + int i; + char str[sizeof(long)*3 + 2]; /* overly long */ + long incr; + + if ( lutil_atol( &incr, mod->sm_values[0].bv_val ) != 0 ) { + *text = "modify/increment: invalid syntax of increment"; + return LDAP_INVALID_SYNTAX; + } + + /* treat zero and errors as a no-op */ + if( incr == 0 ) { + return LDAP_SUCCESS; + } + + for( i = 0; !BER_BVISNULL( &a->a_nvals[i] ); i++ ) { + char *tmp; + long value; + size_t strln; + if ( lutil_atol( &value, a->a_nvals[i].bv_val ) != 0 ) { + *text = "modify/increment: invalid syntax of original value"; + return LDAP_INVALID_SYNTAX; + } + strln = snprintf( str, sizeof(str), "%ld", value+incr ); + + tmp = SLAP_REALLOC( a->a_nvals[i].bv_val, strln+1 ); + if( tmp == NULL ) { + *text = "modify/increment: reallocation error"; + return LDAP_OTHER; + } + a->a_nvals[i].bv_val = tmp; + a->a_nvals[i].bv_len = strln; + + AC_MEMCPY( a->a_nvals[i].bv_val, str, strln+1 ); + } + + } else { + snprintf( textbuf, textlen, + "modify/increment: %s: increment not supported for value syntax %s", + mod->sm_desc->ad_cname.bv_val, + a->a_desc->ad_type->sat_syntax_oid ); + return LDAP_CONSTRAINT_VIOLATION; + } + + return LDAP_SUCCESS; +} + void slap_mod_free( Modification *mod, - int freeit -) + int freeit ) { if ( mod->sm_values != NULL ) ber_bvarray_free( mod->sm_values ); mod->sm_values = NULL; -#ifdef SLAP_NVALUES if ( mod->sm_nvalues != NULL ) ber_bvarray_free( mod->sm_nvalues ); mod->sm_nvalues = NULL; -#endif if( freeit ) free( mod ); } void slap_mods_free( - Modifications *ml -) + Modifications *ml, + int freevals ) { Modifications *next; for ( ; ml != NULL; ml = next ) { next = ml->sml_next; - slap_mod_free( &ml->sml_mod, 0 ); + if ( freevals ) + slap_mod_free( &ml->sml_mod, 0 ); free( ml ); } }