/* Find each id in ids that is a child of base and move it to res. */ int mdb_idscope( Operation *op, MDB_txn *txn, ID base, ID *ids, ID *res ) { struct mdb_info *mdb = (struct mdb_info *) op->o_bd->be_private; MDB_dbi dbi = mdb->mi_dn2id; MDB_val key, data; MDB_cursor *cursor; ID ida, id, cid = 0, ci0 = 0, idc = 0; char *ptr; int rc, copy; key.mv_size = sizeof(ID); MDB_IDL_ZERO( res ); rc = mdb_cursor_open( txn, dbi, &cursor ); if ( rc ) return rc; ida = mdb_idl_first( ids, &cid ); /* Don't bother moving out of ids if it's a range */ if (!MDB_IDL_IS_RANGE(ids)) { idc = ids[0]; ci0 = cid; } while (ida != NOID) { copy = 1; id = ida; while (id) { key.mv_data = &id; rc = mdb_cursor_get( cursor, &key, &data, MDB_SET ); if ( rc ) { /* not found, drop this from ids */ copy = 0; break; } ptr = data.mv_data; ptr += data.mv_size - sizeof(ID); memcpy( &id, ptr, sizeof(ID) ); if ( id == base ) { if ( res[0] >= MDB_IDL_DB_SIZE-1 ) { /* too many aliases in scope. Fallback to range */ MDB_IDL_RANGE( res, MDB_IDL_FIRST( ids ), MDB_IDL_LAST( ids )); goto leave; } res[0]++; res[res[0]] = ida; copy = 0; break; } if ( op->ors_scope == LDAP_SCOPE_ONELEVEL ) break; } if (idc) { if (copy) { if (ci0 != cid) ids[ci0] = ids[cid]; ci0++; } else idc--; } ida = mdb_idl_next( ids, &cid ); } if (!MDB_IDL_IS_RANGE( ids )) ids[0] = idc; leave: mdb_cursor_close( cursor ); return rc; }
int mdb_idl_fetch_key( BackendDB *be, MDB_txn *txn, MDB_dbi dbi, MDB_val *key, ID *ids, MDB_cursor **saved_cursor, int get_flag ) { MDB_val data, key2, *kptr; MDB_cursor *cursor; ID *i; size_t len; int rc; MDB_cursor_op opflag; char keybuf[16]; Debug( LDAP_DEBUG_ARGS, "mdb_idl_fetch_key: %s\n", mdb_show_key( keybuf, key->mv_data, key->mv_size ), 0, 0 ); assert( ids != NULL ); if ( saved_cursor && *saved_cursor ) { opflag = MDB_NEXT; } else if ( get_flag == LDAP_FILTER_GE ) { opflag = MDB_SET_RANGE; } else if ( get_flag == LDAP_FILTER_LE ) { opflag = MDB_FIRST; } else { opflag = MDB_SET; } /* If we're not reusing an existing cursor, get a new one */ if( opflag != MDB_NEXT ) { rc = mdb_cursor_open( txn, dbi, &cursor ); if( rc != 0 ) { Debug( LDAP_DEBUG_ANY, "=> mdb_idl_fetch_key: " "cursor failed: %s (%d)\n", mdb_strerror(rc), rc, 0 ); return rc; } } else { cursor = *saved_cursor; } /* If this is a LE lookup, save original key so we can determine * when to stop. If this is a GE lookup, save the key since it * will be overwritten. */ if ( get_flag == LDAP_FILTER_LE || get_flag == LDAP_FILTER_GE ) { key2.mv_data = keybuf; key2.mv_size = key->mv_size; AC_MEMCPY( keybuf, key->mv_data, key->mv_size ); kptr = &key2; } else { kptr = key; } len = key->mv_size; rc = mdb_cursor_get( cursor, kptr, &data, opflag ); /* skip presence key on range inequality lookups */ while (rc == 0 && kptr->mv_size != len) { rc = mdb_cursor_get( cursor, kptr, &data, MDB_NEXT_NODUP ); } /* If we're doing a LE compare and the new key is greater than * our search key, we're done */ if (rc == 0 && get_flag == LDAP_FILTER_LE && memcmp( kptr->mv_data, key->mv_data, key->mv_size ) > 0 ) { rc = MDB_NOTFOUND; } if (rc == 0) { i = ids+1; rc = mdb_cursor_get( cursor, key, &data, MDB_GET_MULTIPLE ); while (rc == 0) { memcpy( i, data.mv_data, data.mv_size ); i += data.mv_size / sizeof(ID); rc = mdb_cursor_get( cursor, key, &data, MDB_NEXT_MULTIPLE ); } if ( rc == MDB_NOTFOUND ) rc = 0; ids[0] = i - &ids[1]; /* On disk, a range is denoted by 0 in the first element */ if (ids[1] == 0) { if (ids[0] != MDB_IDL_RANGE_SIZE) { Debug( LDAP_DEBUG_ANY, "=> mdb_idl_fetch_key: " "range size mismatch: expected %d, got %ld\n", MDB_IDL_RANGE_SIZE, ids[0], 0 ); mdb_cursor_close( cursor ); return -1; } MDB_IDL_RANGE( ids, ids[2], ids[3] ); } data.mv_size = MDB_IDL_SIZEOF(ids); } if ( saved_cursor && rc == 0 ) { if ( !*saved_cursor ) *saved_cursor = cursor; } else mdb_cursor_close( cursor ); if( rc == MDB_NOTFOUND ) { return rc; } else if( rc != 0 ) { Debug( LDAP_DEBUG_ANY, "=> mdb_idl_fetch_key: " "get failed: %s (%d)\n", mdb_strerror(rc), rc, 0 ); return rc; } else if ( data.mv_size == 0 || data.mv_size % sizeof( ID ) ) { /* size not multiple of ID size */ Debug( LDAP_DEBUG_ANY, "=> mdb_idl_fetch_key: " "odd size: expected %ld multiple, got %ld\n", (long) sizeof( ID ), (long) data.mv_size, 0 ); return -1; } else if ( data.mv_size != MDB_IDL_SIZEOF(ids) ) { /* size mismatch */ Debug( LDAP_DEBUG_ANY, "=> mdb_idl_fetch_key: " "get size mismatch: expected %ld, got %ld\n", (long) ((1 + ids[0]) * sizeof( ID )), (long) data.mv_size, 0 ); return -1; } return rc; }