]> git.sur5r.net Git - openldap/commitdiff
Fix ITS#402 - index corruption in idl_insert_key
authorHoward Chu <hyc@openldap.org>
Mon, 20 Dec 1999 15:57:19 +0000 (15:57 +0000)
committerHoward Chu <hyc@openldap.org>
Mon, 20 Dec 1999 15:57:19 +0000 (15:57 +0000)
servers/slapd/back-ldbm/idl.c

index b6d649325308f0fc422cc5520ef745f67216e056..56fadb8401ae8ab67f6ee980371f48cf1e2a806b 100644 (file)
@@ -478,18 +478,52 @@ idl_insert_key(
                /* is there a next block? */
                if ( !first && !ID_BLOCK_NOID(idl, i + 1) ) {
                        /* read it in */
-                       sprintf( kstr, "%c%s%ld", CONT_PREFIX, key.dptr,
+                       k2.dptr = (char *) ch_malloc( key.dsize + 20 );
+                       sprintf( k2.dptr, "%c%s%ld", CONT_PREFIX, key.dptr,
                            ID_BLOCK_ID(idl, i + 1) );
-                       k2.dptr = kstr;
-                       k2.dsize = strlen( kstr ) + 1;
+                       k2.dsize = strlen( k2.dptr ) + 1;
                        if ( (tmp2 = idl_fetch_one( be, db, k2 )) == NULL ) {
                                Debug( LDAP_DEBUG_ANY,
                                    "idl_fetch_one (%s) returns NULL\n",
                                    k2.dptr, 0, 0 );
                                /* split the original block */
+                               free( k2.dptr );
                                goto split;
                        }
 
+                       /* If the new id is less than the last id in the
+                        * current block, it must not be put into the next
+                        * block. Push the last id of the current block
+                        * into the next block instead.
+                        */
+                       if (id < ID_BLOCK_ID(tmp, ID_BLOCK_NIDS(tmp) - 1)) {
+                           ID id2 = ID_BLOCK_ID(tmp, ID_BLOCK_NIDS(tmp) - 1);
+                           Datum k3;
+
+                           ldbm_datum_init( k3 );
+
+                           --ID_BLOCK_NIDS(tmp);
+                           /* This must succeed since we just popped one
+                            * ID off the end of it.
+                            */
+                           rc = idl_insert( &tmp, id, db->dbc_maxids );
+                           assert( rc == 0 );
+                           k3.dptr = kstr;
+                           k3.dsize = strlen( kstr ) + 1;
+                           if ( (rc = idl_store( be, db, k3, tmp )) != 0 ) {
+                               Debug( LDAP_DEBUG_ANY,
+                           "idl_store of (%s) returns %d\n", k3.dptr, rc, 0 );
+                           }
+                           free( kstr );
+                           kstr = k2.dptr;
+
+                           id = id2;
+                           /* This new id will necessarily be inserted
+                            * as the first id of the next block by the
+                            * following switch() statement.
+                            */
+                       }
+
                        switch ( (rc = idl_insert( &tmp2, id,
                            db->dbc_maxids )) ) {
                        case 1:         /* id inserted first in block */