]> git.sur5r.net Git - openldap/commitdiff
ITS#4752 try to undo failed Modifies
authorHoward Chu <hyc@openldap.org>
Wed, 7 Feb 2007 11:42:23 +0000 (11:42 +0000)
committerHoward Chu <hyc@openldap.org>
Wed, 7 Feb 2007 11:42:23 +0000 (11:42 +0000)
servers/slapd/bconfig.c

index 9b39755e06b3b4fbdc0b285d8e6900a416a31a0b..a12e9ee457b6a68ddf4a91a8b1ed3dee9aec00af 100644 (file)
@@ -4528,6 +4528,33 @@ typedef struct delrec {
        int idx[1];
 } delrec;
 
+static int
+config_modify_add( ConfigTable *ct, ConfigArgs *ca, AttributeDescription *ad,
+       int i )
+{
+       int rc;
+
+       if (ad->ad_type->sat_flags & SLAP_AT_ORDERED &&
+               ca->line[0] == '{' )
+       {
+               char *ptr = strchr( ca->line + 1, '}' );
+               if ( ptr ) {
+                       char    *next;
+
+                       ca->valx = strtol( ca->line + 1, &next, 0 );
+                       if ( next == ca->line + 1 || next[ 0 ] != '}' ) {
+                               return LDAP_OTHER;
+                       }
+                       ca->line = ptr+1;
+               }
+       }
+       rc = config_parse_add( ct, ca, i );
+       if ( rc ) {
+               rc = LDAP_OTHER;
+       }
+       return rc;
+}
+
 static int
 config_modify_internal( CfEntryInfo *ce, Operation *op, SlapReply *rs,
        ConfigArgs *ca )
@@ -4535,7 +4562,7 @@ config_modify_internal( CfEntryInfo *ce, Operation *op, SlapReply *rs,
        int rc = LDAP_UNWILLING_TO_PERFORM;
        Modifications *ml;
        Entry *e = ce->ce_entry;
-       Attribute *save_attrs = e->e_attrs, *oc_at;
+       Attribute *save_attrs = e->e_attrs, *oc_at, *s, *a;
        ConfigTable *ct;
        ConfigOCs **colst;
        int i, nocs;
@@ -4547,6 +4574,11 @@ config_modify_internal( CfEntryInfo *ce, Operation *op, SlapReply *rs,
 
        colst = count_ocs( oc_at, &nocs );
 
+       /* make sure add/del flags are clear; should always be true */
+       for ( s = save_attrs; s; s = s->a_next ) {
+               s->a_flags &= ~(SLAP_ATTR_IXADD|SLAP_ATTR_IXDEL);
+       }
+
        e->e_attrs = attrs_dup( e->e_attrs );
 
        init_config_argv( ca );
@@ -4569,7 +4601,7 @@ config_modify_internal( CfEntryInfo *ce, Operation *op, SlapReply *rs,
                                rc = LDAP_OTHER;
                                snprintf(ca->msg, sizeof(ca->msg), "cannot delete %s",
                                        ml->sml_desc->ad_cname.bv_val );
-                               goto out;
+                               goto out_noop;
                        }
                        if ( ml->sml_op == LDAP_MOD_REPLACE ) {
                                vals = ml->sml_values;
@@ -4631,11 +4663,11 @@ config_modify_internal( CfEntryInfo *ce, Operation *op, SlapReply *rs,
                                                        rc = LDAP_OTHER;
                                                        snprintf(ca->msg, sizeof(ca->msg), "cannot insert %s",
                                                                ml->sml_desc->ad_cname.bv_val );
-                                                       goto out;
+                                                       goto out_noop;
                                                }
                                        }
                                        rc = check_vals( ct, ca, ml, 0 );
-                                       if ( rc ) goto out;
+                                       if ( rc ) goto out_noop;
                                }
                        }
                        rc = modify_add_values(e, &ml->sml_mod,
@@ -4664,117 +4696,142 @@ config_modify_internal( CfEntryInfo *ce, Operation *op, SlapReply *rs,
                if(rc != LDAP_SUCCESS) break;
        }
        
-       if(rc == LDAP_SUCCESS) {
+       if ( rc == LDAP_SUCCESS) {
                /* check that the entry still obeys the schema */
                rc = entry_schema_check(op, e, NULL, 0, 0,
                        &rs->sr_text, ca->msg, sizeof(ca->msg) );
+               if ( rc ) goto out_noop;
        }
-       if ( rc == LDAP_SUCCESS ) {
-               /* Basic syntax checks are OK. Do the actual settings. */
-               for ( ml = op->orm_modlist; ml; ml = ml->sml_next ) {
-                       ct = config_find_table( colst, nocs, ml->sml_desc );
-                       if ( !ct ) continue;
-
-                       switch (ml->sml_op) {
-                       case LDAP_MOD_DELETE:
-                       case LDAP_MOD_REPLACE: {
-                               BerVarray vals = NULL, nvals = NULL;
-                               Attribute *a;
-                               delrec *d = NULL;
-
-                               a = attr_find( e->e_attrs, ml->sml_desc );
-
-                               if ( ml->sml_op == LDAP_MOD_REPLACE ) {
-                                       vals = ml->sml_values;
-                                       nvals = ml->sml_nvalues;
-                                       ml->sml_values = NULL;
-                                       ml->sml_nvalues = NULL;
-                               }
+       /* Basic syntax checks are OK. Do the actual settings. */
+       for ( ml = op->orm_modlist; ml; ml = ml->sml_next ) {
+               ct = config_find_table( colst, nocs, ml->sml_desc );
+               if ( !ct ) continue;
 
-                               if ( ml->sml_values )
-                                       d = dels;
+               s = attr_find( save_attrs, ml->sml_desc );
+               a = attr_find( e->e_attrs, ml->sml_desc );
 
-                               /* If we didn't delete the whole attribute */
-                               if ( ml->sml_values && a ) {
-                                       struct berval *mvals;
-                                       int j;
+               switch (ml->sml_op) {
+               case LDAP_MOD_DELETE:
+               case LDAP_MOD_REPLACE: {
+                       BerVarray vals = NULL, nvals = NULL;
+                       delrec *d = NULL;
 
-                                       if ( ml->sml_nvalues )
-                                               mvals = ml->sml_nvalues;
-                                       else
-                                               mvals = ml->sml_values;
-
-                                       /* use the indexes we saved up above */
-                                       for (i=0; i < d->nidx; i++) {
-                                               struct berval bv = *mvals++;
-                                               if ( a->a_desc->ad_type->sat_flags & SLAP_AT_ORDERED &&
-                                                       bv.bv_val[0] == '{' ) {
-                                                       ptr = strchr( bv.bv_val, '}' ) + 1;
-                                                       bv.bv_len -= ptr - bv.bv_val;
-                                                       bv.bv_val = ptr;
-                                               }
-                                               ca->line = bv.bv_val;
-                                               ca->valx = d->idx[i];
-                                               rc = config_del_vals( ct, ca );
-                                               if ( rc != LDAP_SUCCESS ) break;
-                                               for (j=i+1; j < d->nidx; j++)
-                                                       if ( d->idx[j] >d->idx[i] )
-                                                               d->idx[j]--;
+                       if ( ml->sml_op == LDAP_MOD_REPLACE ) {
+                               vals = ml->sml_values;
+                               nvals = ml->sml_nvalues;
+                               ml->sml_values = NULL;
+                               ml->sml_nvalues = NULL;
+                       }
+
+                       if ( ml->sml_values )
+                               d = dels;
+
+                       /* If we didn't delete the whole attribute */
+                       if ( ml->sml_values && a ) {
+                               struct berval *mvals;
+                               int j;
+
+                               if ( ml->sml_nvalues )
+                                       mvals = ml->sml_nvalues;
+                               else
+                                       mvals = ml->sml_values;
+
+                               /* use the indexes we saved up above */
+                               for (i=0; i < d->nidx; i++) {
+                                       struct berval bv = *mvals++;
+                                       if ( a->a_desc->ad_type->sat_flags & SLAP_AT_ORDERED &&
+                                               bv.bv_val[0] == '{' ) {
+                                               ptr = strchr( bv.bv_val, '}' ) + 1;
+                                               bv.bv_len -= ptr - bv.bv_val;
+                                               bv.bv_val = ptr;
                                        }
-                               } else {
-                                       ca->valx = -1;
-                                       ca->line = NULL;
+                                       ca->line = bv.bv_val;
+                                       ca->valx = d->idx[i];
                                        rc = config_del_vals( ct, ca );
-                                       if ( rc ) rc = LDAP_OTHER;
-                               }
-                               if ( ml->sml_values ) {
-                                       d = d->next;
-                                       ch_free( dels );
-                                       dels = d;
-                               }
-                               if ( ml->sml_op == LDAP_MOD_REPLACE ) {
-                                       ml->sml_values = vals;
-                                       ml->sml_nvalues = nvals;
+                                       if ( rc != LDAP_SUCCESS ) break;
+                                       s->a_flags |= SLAP_ATTR_IXDEL;
+                                       for (j=i+1; j < d->nidx; j++)
+                                               if ( d->idx[j] >d->idx[i] )
+                                                       d->idx[j]--;
                                }
-                               if ( !vals || rc != LDAP_SUCCESS )
-                                       break;
-                               }
-                               /* FALLTHRU: LDAP_MOD_REPLACE && vals */
+                       } else {
+                               ca->valx = -1;
+                               ca->line = NULL;
+                               rc = config_del_vals( ct, ca );
+                               if ( rc ) rc = LDAP_OTHER;
+                               s->a_flags |= SLAP_ATTR_IXDEL;
+                       }
+                       if ( ml->sml_values ) {
+                               d = d->next;
+                               ch_free( dels );
+                               dels = d;
+                       }
+                       if ( ml->sml_op == LDAP_MOD_REPLACE ) {
+                               ml->sml_values = vals;
+                               ml->sml_nvalues = nvals;
+                       }
+                       if ( !vals || rc != LDAP_SUCCESS )
+                               break;
+                       }
+                       /* FALLTHRU: LDAP_MOD_REPLACE && vals */
 
-                       case LDAP_MOD_ADD:
-                               for (i=0; ml->sml_values[i].bv_val; i++) {
-                                       ca->line = ml->sml_values[i].bv_val;
+               case LDAP_MOD_ADD:
+                       for (i=0; ml->sml_values[i].bv_val; i++) {
+                               ca->line = ml->sml_values[i].bv_val;
+                               ca->valx = -1;
+                               rc = config_modify_add( ct, ca, ml->sml_desc, i );
+                               if ( rc )
+                                       goto out;
+                               a->a_flags |= SLAP_ATTR_IXADD;
+                       }
+                       break;
+               }
+       }
+
+out:
+       /* Undo for a failed operation */
+       if ( rc != LDAP_SUCCESS ) {
+               for ( s = save_attrs; s; s = s->a_next ) {
+                       if ( s->a_flags & SLAP_ATTR_IXDEL ) {
+                               s->a_flags &= ~(SLAP_ATTR_IXDEL|SLAP_ATTR_IXADD);
+                               ct = config_find_table( colst, nocs, s->a_desc );
+                               a = attr_find( e->e_attrs, s->a_desc );
+                               if ( a ) {
+                                       /* clear the flag so the add check below will skip it */
+                                       a->a_flags &= ~(SLAP_ATTR_IXDEL|SLAP_ATTR_IXADD);
                                        ca->valx = -1;
-                                       if ( ml->sml_desc->ad_type->sat_flags & SLAP_AT_ORDERED &&
-                                               ca->line[0] == '{' )
-                                       {
-                                               ptr = strchr( ca->line + 1, '}' );
-                                               if ( ptr ) {
-                                                       char    *next;
-
-                                                       ca->valx = strtol( ca->line + 1, &next, 0 );
-                                                       if ( next == ca->line + 1 || next[ 0 ] != '}' ) {
-                                                               rc = LDAP_OTHER;
-                                                               goto out;
-                                                       }
-                                                       ca->line = ptr+1;
-                                               }
-                                       }
-                                       rc = config_parse_add( ct, ca, i );
-                                       if ( rc ) {
-                                               rc = LDAP_OTHER;
-                                               goto out;
+                                       ca->line = NULL;
+                                       config_del_vals( ct, ca );
+                               }
+                               for ( i=0; !BER_BVISNULL( &s->a_vals[i] ); i++ ) {
+                                       ca->line = s->a_vals[i].bv_val;
+                                       ca->valx = -1;
+                                       config_modify_add( ct, ca, s->a_desc, i );
+                               }
+                       }
+               }
+               for ( a = e->e_attrs; a; a = a->a_next ) {
+                       if ( a->a_flags & SLAP_ATTR_IXADD ) {
+                               ct = config_find_table( colst, nocs, a->a_desc );
+                               ca->valx = -1;
+                               ca->line = NULL;
+                               config_del_vals( ct, ca );
+                               s = attr_find( save_attrs, a->a_desc );
+                               if ( s ) {
+                                       s->a_flags &= ~(SLAP_ATTR_IXDEL|SLAP_ATTR_IXADD);
+                                       for ( i=0; !BER_BVISNULL( &s->a_vals[i] ); i++ ) {
+                                               ca->line = s->a_vals[i].bv_val;
+                                               ca->valx = -1;
+                                               config_modify_add( ct, ca, s->a_desc, i );
                                        }
                                }
-
-                               break;
                        }
                }
        }
 
-out:
        if ( ca->cleanup )
                ca->cleanup( ca );
+out_noop:
        if ( rc == LDAP_SUCCESS ) {
                attrs_free( save_attrs );
        } else {