diff --git a/servers/slapd/back-bdb/back-bdb.h b/servers/slapd/back-bdb/back-bdb.h index bee41a46f45580b5b5c1632c4aaf58e62ef95c1d..341d0e9989c60a7d61ecef447a7d62fa2a63f8eb 100644 --- a/servers/slapd/back-bdb/back-bdb.h +++ b/servers/slapd/back-bdb/back-bdb.h @@ -261,19 +261,19 @@ struct bdb_op_info { /* Copy an ID "src" to pointer "dst" in big-endian byte order */ #define BDB_ID2DISK( src, dst ) \ - do { int i0; ID tmp; char *ptr; \ - tmp = (src); ptr = (char *)(dst); \ + do { int i0; ID tmp; unsigned char *_p; \ + tmp = (src); _p = (char *)(dst); \ for ( i0=sizeof(ID)-1; i0>=0; i0-- ) { \ - ptr[i0] = tmp & 0xff; tmp >>= 8; \ + _p[i0] = tmp & 0xff; tmp >>= 8; \ } \ } while(0); /* Copy a pointer "src" to a pointer "dst" from big-endian to native order */ #define BDB_DISK2ID( src, dst ) \ - do { int i0; ID tmp = 0; unsigned char *ptr; \ - ptr = (unsigned char *)(src); \ + do { int i0; ID tmp = 0; unsigned char *_p; \ + _p = (unsigned char *)(src); \ for ( i0=0; i0<sizeof(ID); i0++ ) { \ - tmp <<= 8; tmp |= *ptr++; \ + tmp <<= 8; tmp |= *_p++; \ } *(dst) = tmp; \ } while (0); diff --git a/servers/slapd/back-bdb/dn2id.c b/servers/slapd/back-bdb/dn2id.c index 912d5c05e80223c629e02492649c28304a8a3dfb..b157ad23a9245f40b15eff0d8005893ef342181b 100644 --- a/servers/slapd/back-bdb/dn2id.c +++ b/servers/slapd/back-bdb/dn2id.c @@ -391,45 +391,21 @@ bdb_dn2idl( * a B-Tree with sorted duplicates to store all the children of a node under * the same key. Also, the first item under the key contains the entry's own * rdn and the ID of the node's parent, to allow bottom-up tree traversal as - * well as top-down. To keep this info first in the list, the nrdnlen is set - * to the negative of its value. + * well as top-down. To keep this info first in the list, the high bit of all + * subsequent nrdnlen's is always set. This means we can only accomodate + * RDNs up to length 32767, but that's fine since full DNs are already + * restricted to 8192. * * The diskNode is a variable length structure. This definition is not * directly usable for in-memory manipulation. */ typedef struct diskNode { - ID entryID; - short nrdnlen; - char nrdn[1]; - char rdn[1]; + unsigned char nrdnlen[2]; + unsigned char nrdn[1]; + unsigned char rdn[1]; + unsigned char entryID[sizeof(ID)]; } diskNode; -/* Sort function for the sorted duplicate data items of a dn2id key. - * Sorts based on normalized RDN, in length order. - */ -int -hdb_dup_compare( - DB *db, - const DBT *usrkey, - const DBT *curkey ) -{ - signed char *u = (signed char *)&(((diskNode *)(usrkey->data))->nrdnlen); - signed char *c = (signed char *)&(((diskNode *)(curkey->data))->nrdnlen); - int rc, i; - - /* data is not aligned, cannot compare directly */ -#ifdef WORDS_BIGENDIAN - for( i = 0; i < (int)sizeof(short); i++) -#else - for( i = sizeof(short)-1; i >= 0; i--) -#endif - { - rc = u[i] - c[i]; - if( rc ) return rc; - } - return strcmp( u+sizeof(short), c+sizeof(short) ); -} - /* This function constructs a full DN for a given entry. */ int hdb_fix_dn( @@ -511,12 +487,13 @@ hdb_dn2id_add( } d = op->o_tmpalloc(sizeof(diskNode) + rlen + nrlen, op->o_tmpmemctx); - BDB_ID2DISK( e->e_id, &d->entryID ); - d->nrdnlen = nrlen; + d->nrdnlen[1] = nrlen & 0xff; + d->nrdnlen[0] = (nrlen >> 8) | 0x80; ptr = lutil_strncopy( d->nrdn, e->e_nname.bv_val, nrlen ); *ptr++ = '\0'; ptr = lutil_strncopy( ptr, e->e_name.bv_val, rlen ); - *ptr = '\0'; + *ptr++ = '\0'; + BDB_ID2DISK( e->e_id, ptr ); DBTzero(&key); DBTzero(&data); @@ -547,10 +524,9 @@ hdb_dn2id_add( rc = db->put( db, txn, &key, &data, DB_NODUPDATA ); if (rc == 0) { - ID tmp = nid; - nid = d->entryID; - d->entryID = tmp; - d->nrdnlen = 0 - nrlen; + BDB_ID2DISK( e->e_id, &nid ); + BDB_ID2DISK( eip->bei_id, ptr ); + d->nrdnlen[0] ^= 0x80; rc = db->put( db, txn, &key, &data, DB_NODUPDATA ); } @@ -583,7 +559,7 @@ hdb_dn2id_delete( BDB_ID2DISK( eip->bei_id, &nid ); DBTzero(&data); - data.size = sizeof(diskNode) + BEI(e)->bei_nrdn.bv_len; + data.size = sizeof(diskNode) + BEI(e)->bei_nrdn.bv_len - sizeof(ID) - 1; data.ulen = data.size; data.dlen = data.size; data.flags = DB_DBT_USERMEM | DB_DBT_PARTIAL; @@ -595,15 +571,19 @@ hdb_dn2id_delete( if ( rc ) return rc; d = op->o_tmpalloc( data.size, op->o_tmpmemctx ); - BDB_ID2DISK( e->e_id, &d->entryID ); - d->nrdnlen = BEI(e)->bei_nrdn.bv_len; + d->nrdnlen[1] = BEI(e)->bei_nrdn.bv_len & 0xff; + d->nrdnlen[0] = (BEI(e)->bei_nrdn.bv_len >> 8) | 0x80; strcpy( d->nrdn, BEI(e)->bei_nrdn.bv_val ); data.data = d; /* Delete our ID from the parent's list */ - rc = cursor->c_get( cursor, &key, &data, DB_GET_BOTH | DB_RMW ); - if ( rc == 0 ) - rc = cursor->c_del( cursor, 0 ); + rc = cursor->c_get( cursor, &key, &data, DB_GET_BOTH_RANGE | DB_RMW ); + if ( rc == 0 ) { + if ( !strcmp( d->nrdn, BEI(e)->bei_nrdn.bv_val )) + rc = cursor->c_del( cursor, 0 ); + else + rc = DB_NOTFOUND; + } /* Delete our ID from the tree. With sorted duplicates, this * will leave any child nodes still hanging around. This is OK @@ -649,22 +629,28 @@ hdb_dn2id( BDB_ID2DISK( ei->bei_parent->bei_id, &idp ); DBTzero(&data); - data.size = sizeof(diskNode) + nrlen; + data.size = sizeof(diskNode) + nrlen - sizeof(ID) - 1; data.ulen = data.size * 3; - data.flags = DB_DBT_USERMEM; + data.dlen = data.ulen; + data.flags = DB_DBT_USERMEM | DB_DBT_PARTIAL; rc = db->cursor( db, txn, &cursor, bdb->bi_db_opflags ); if ( rc ) return rc; d = op->o_tmpalloc( data.size * 3, op->o_tmpmemctx ); - d->nrdnlen = nrlen; + d->nrdnlen[1] = nrlen & 0xff; + d->nrdnlen[0] = (nrlen >> 8) | 0x80; ptr = lutil_strncopy( d->nrdn, in->bv_val, nrlen ); *ptr = '\0'; data.data = d; - rc = cursor->c_get( cursor, &key, &data, DB_GET_BOTH ); + rc = cursor->c_get( cursor, &key, &data, DB_GET_BOTH_RANGE ); + if ( rc == 0 && strncmp( d->nrdn, in->bv_val, nrlen )) { + rc = DB_NOTFOUND; + } if ( rc == 0 ) { - BDB_DISK2ID( &d->entryID, &ei->bei_id ); + ptr = data.data + data.size - sizeof(ID); + BDB_DISK2ID( ptr, &ei->bei_id ); ei->bei_rdn.bv_len = data.size - sizeof(diskNode) - nrlen; ptr = d->nrdn + nrlen + 1; ber_str2bv( ptr, ei->bei_rdn.bv_len, 1, &ei->bei_rdn ); @@ -720,12 +706,13 @@ hdb_dn2id_parent( rc = cursor->c_get( cursor, &key, &data, DB_SET ); if ( rc == 0 ) { - if (d->nrdnlen >= 0) { + if (d->nrdnlen[0] & 0x80) { rc = LDAP_OTHER; } else { db_recno_t dkids; - BDB_DISK2ID( &d->entryID, idp ); - ei->bei_nrdn.bv_len = 0 - d->nrdnlen; + ptr = data.data + data.size - sizeof(ID); + BDB_DISK2ID( ptr, idp ); + ei->bei_nrdn.bv_len = (d->nrdnlen[0] << 8) | d->nrdnlen[1]; ber_str2bv( d->nrdn, ei->bei_nrdn.bv_len, 1, &ei->bei_nrdn ); ei->bei_rdn.bv_len = data.size - sizeof(diskNode) - ei->bei_nrdn.bv_len; @@ -913,8 +900,8 @@ hdb_dn2idl_internal( diskNode *d = (diskNode *)j; short nrlen; - BDB_DISK2ID( &d->entryID, &ei.bei_id ); - AC_MEMCPY( &nrlen, &d->nrdnlen, sizeof(d->nrdnlen) ); + BDB_DISK2ID( j + len - sizeof(ID), &ei.bei_id ); + nrlen = ((d->nrdnlen[0] ^ 0x80) << 8) | d->nrdnlen[1]; ei.bei_nrdn.bv_len = nrlen; /* nrdn/rdn are set in-place. * hdb_cache_load will copy them as needed diff --git a/servers/slapd/back-bdb/init.c b/servers/slapd/back-bdb/init.c index 133732223b41977ffa4e8727025f7c1161a9f104..975ee8a56e045b5d655459e3876069ec577e9d6c 100644 --- a/servers/slapd/back-bdb/init.c +++ b/servers/slapd/back-bdb/init.c @@ -348,9 +348,9 @@ bdb_db_open( BackendDB *be ) flags |= DB_CREATE; } #else +#if 0 rc = db->bdi_db->set_dup_compare( db->bdi_db, bdb_dup_compare ); -#if 0 rc = db->bdi_db->set_bt_compare( db->bdi_db, bdb_bt_compare ); #endif