2007-11-10 01:43:24 +03:00
/*
Unix SMB / CIFS implementation .
Database interface wrapper around red - black trees
2008-01-12 12:38:17 +03:00
Copyright ( C ) Volker Lendecke 2007 , 2008
2007-11-10 01:43:24 +03:00
This program is free software ; you can redistribute it and / or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation ; either version 3 of the License , or
( at your option ) any later version .
This program is distributed in the hope that it will be useful ,
but WITHOUT ANY WARRANTY ; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
GNU General Public License for more details .
You should have received a copy of the GNU General Public License
along with this program . If not , see < http : //www.gnu.org/licenses/>.
*/
# include "includes.h"
2011-07-07 19:42:08 +04:00
# include "dbwrap/dbwrap.h"
2011-08-24 16:53:42 +04:00
# include "dbwrap/dbwrap_private.h"
2011-08-16 18:20:14 +04:00
# include "dbwrap/dbwrap_rbt.h"
2008-10-12 18:27:00 +04:00
# include "../lib/util/rbtree.h"
2015-11-25 11:22:08 +03:00
# include "../lib/util/dlinklist.h"
2007-11-10 01:43:24 +03:00
2008-06-19 11:50:34 +04:00
# define DBWRAP_RBT_ALIGN(_size_) (((_size_)+15)&~15)
2008-01-12 12:38:17 +03:00
2007-11-10 01:43:24 +03:00
struct db_rbt_ctx {
struct rb_root tree ;
2015-11-25 11:22:08 +03:00
struct db_rbt_node * nodes ;
2015-11-25 11:22:08 +03:00
size_t traverse_read ;
2015-11-25 11:22:08 +03:00
struct db_rbt_node * * traverse_nextp ;
2007-11-10 01:43:24 +03:00
} ;
struct db_rbt_rec {
struct db_rbt_node * node ;
} ;
/* The structure that ends up in the tree */
struct db_rbt_node {
struct rb_node rb_node ;
size_t keysize , valuesize ;
2015-11-25 11:22:08 +03:00
struct db_rbt_node * prev , * next ;
2007-11-10 01:43:24 +03:00
} ;
2008-01-12 12:38:17 +03:00
/*
* Hide the ugly pointer calculations in a function
*/
static struct db_rbt_node * db_rbt2node ( struct rb_node * node )
{
return ( struct db_rbt_node * )
( ( char * ) node - offsetof ( struct db_rbt_node , rb_node ) ) ;
}
/*
* Compare two keys
*/
static int db_rbt_compare ( TDB_DATA a , TDB_DATA b )
{
int res ;
res = memcmp ( a . dptr , b . dptr , MIN ( a . dsize , b . dsize ) ) ;
if ( ( res < 0 ) | | ( ( res = = 0 ) & & ( a . dsize < b . dsize ) ) ) {
return - 1 ;
}
if ( ( res > 0 ) | | ( ( res = = 0 ) & & ( a . dsize > b . dsize ) ) ) {
return 1 ;
}
return 0 ;
}
2007-11-10 01:43:24 +03:00
/*
* dissect a db_rbt_node into its implicit key and value parts
*/
static void db_rbt_parse_node ( struct db_rbt_node * node ,
TDB_DATA * key , TDB_DATA * value )
{
2015-07-18 22:50:55 +03:00
size_t key_offset , value_offset ;
key_offset = DBWRAP_RBT_ALIGN ( sizeof ( struct db_rbt_node ) ) ;
key - > dptr = ( ( uint8_t * ) node ) + key_offset ;
2007-11-10 01:43:24 +03:00
key - > dsize = node - > keysize ;
2015-07-18 22:50:55 +03:00
value_offset = DBWRAP_RBT_ALIGN ( node - > keysize ) ;
value - > dptr = key - > dptr + value_offset ;
2007-11-10 01:43:24 +03:00
value - > dsize = node - > valuesize ;
}
2015-07-18 22:50:55 +03:00
static ssize_t db_rbt_reclen ( size_t keylen , size_t valuelen )
{
size_t len , tmp ;
len = DBWRAP_RBT_ALIGN ( sizeof ( struct db_rbt_node ) ) ;
tmp = DBWRAP_RBT_ALIGN ( keylen ) ;
if ( tmp < keylen ) {
goto overflow ;
}
len + = tmp ;
if ( len < tmp ) {
goto overflow ;
}
len + = valuelen ;
if ( len < valuelen ) {
goto overflow ;
}
return len ;
overflow :
return - 1 ;
}
2016-09-12 18:30:55 +03:00
static NTSTATUS db_rbt_storev ( struct db_record * rec ,
const TDB_DATA * dbufs , int num_dbufs , int flag )
2007-11-10 01:43:24 +03:00
{
2012-05-30 18:05:03 +04:00
struct db_rbt_ctx * db_ctx = talloc_get_type_abort (
rec - > db - > private_data , struct db_rbt_ctx ) ;
2008-01-12 12:38:17 +03:00
struct db_rbt_rec * rec_priv = ( struct db_rbt_rec * ) rec - > private_data ;
2007-11-10 01:43:24 +03:00
struct db_rbt_node * node ;
struct rb_node * * p ;
2015-11-25 11:22:08 +03:00
struct rb_node * parent = NULL ;
struct db_rbt_node * parent_node = NULL ;
2007-11-10 01:43:24 +03:00
2015-07-18 22:50:55 +03:00
ssize_t reclen ;
2016-09-12 18:30:55 +03:00
TDB_DATA data , this_key , this_val ;
void * to_free = NULL ;
2007-11-10 01:43:24 +03:00
2015-11-25 11:22:08 +03:00
if ( db_ctx - > traverse_read > 0 ) {
return NT_STATUS_MEDIA_WRITE_PROTECTED ;
}
2020-06-09 16:46:51 +03:00
if ( ( flag = = TDB_INSERT ) & & ( rec_priv - > node ! = NULL ) ) {
return NT_STATUS_OBJECT_NAME_COLLISION ;
}
if ( ( flag = = TDB_MODIFY ) & & ( rec_priv - > node = = NULL ) ) {
return NT_STATUS_OBJECT_NAME_NOT_FOUND ;
}
2016-09-12 18:30:55 +03:00
if ( num_dbufs = = 1 ) {
data = dbufs [ 0 ] ;
} else {
2022-09-10 18:33:31 +03:00
NTSTATUS status ;
data = ( TDB_DATA ) { 0 } ;
status = dbwrap_merge_dbufs ( & data , rec , dbufs , num_dbufs ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
return status ;
2016-09-12 18:30:55 +03:00
}
to_free = data . dptr ;
}
2007-11-10 01:43:24 +03:00
if ( rec_priv - > node ! = NULL ) {
/*
* The record was around previously
*/
db_rbt_parse_node ( rec_priv - > node , & this_key , & this_val ) ;
SMB_ASSERT ( this_key . dsize = = rec - > key . dsize ) ;
SMB_ASSERT ( memcmp ( this_key . dptr , rec - > key . dptr ,
this_key . dsize ) = = 0 ) ;
if ( this_val . dsize > = data . dsize ) {
/*
* The new value fits into the old space
*/
memcpy ( this_val . dptr , data . dptr , data . dsize ) ;
rec_priv - > node - > valuesize = data . dsize ;
2016-09-12 18:30:55 +03:00
TALLOC_FREE ( to_free ) ;
2007-11-10 01:43:24 +03:00
return NT_STATUS_OK ;
}
2012-05-30 18:50:06 +04:00
}
2015-07-18 22:50:55 +03:00
reclen = db_rbt_reclen ( rec - > key . dsize , data . dsize ) ;
if ( reclen = = - 1 ) {
2016-09-12 18:30:55 +03:00
TALLOC_FREE ( to_free ) ;
2015-07-18 22:50:55 +03:00
return NT_STATUS_INSUFFICIENT_RESOURCES ;
}
2012-05-30 18:50:06 +04:00
2015-11-25 12:17:34 +03:00
node = talloc_zero_size ( db_ctx , reclen ) ;
2012-05-30 18:50:06 +04:00
if ( node = = NULL ) {
2016-09-12 18:30:55 +03:00
TALLOC_FREE ( to_free ) ;
2012-05-30 18:50:06 +04:00
return NT_STATUS_NO_MEMORY ;
}
2007-11-10 01:43:24 +03:00
2012-05-30 18:50:06 +04:00
if ( rec_priv - > node ! = NULL ) {
2015-11-25 11:22:08 +03:00
if ( db_ctx - > traverse_nextp ! = NULL ) {
if ( * db_ctx - > traverse_nextp = = rec_priv - > node ) {
* db_ctx - > traverse_nextp = node ;
}
}
2007-11-10 01:43:24 +03:00
/*
* We need to delete the key from the tree and start fresh ,
* there ' s not enough space in the existing record
*/
2012-05-30 18:05:03 +04:00
rb_erase ( & rec_priv - > node - > rb_node , & db_ctx - > tree ) ;
2015-11-25 11:22:08 +03:00
DLIST_REMOVE ( db_ctx - > nodes , rec_priv - > node ) ;
2007-12-19 15:48:49 +03:00
/*
* Keep the existing node around for a while : If the record
* existed before , we reference the key data in there .
*/
2007-11-10 01:43:24 +03:00
}
node - > keysize = rec - > key . dsize ;
node - > valuesize = data . dsize ;
db_rbt_parse_node ( node , & this_key , & this_val ) ;
memcpy ( this_key . dptr , rec - > key . dptr , node - > keysize ) ;
2009-02-27 17:28:52 +03:00
TALLOC_FREE ( rec_priv - > node ) ;
2012-05-30 18:48:39 +04:00
rec_priv - > node = node ;
2007-11-10 01:43:24 +03:00
2019-05-24 02:00:05 +03:00
if ( node - > valuesize > 0 ) {
memcpy ( this_val . dptr , data . dptr , node - > valuesize ) ;
}
2007-12-19 04:30:02 +03:00
2007-11-10 01:43:24 +03:00
parent = NULL ;
2012-05-30 18:05:03 +04:00
p = & db_ctx - > tree . rb_node ;
2007-11-10 01:43:24 +03:00
while ( * p ) {
struct db_rbt_node * r ;
TDB_DATA search_key , search_val ;
int res ;
2008-01-12 12:38:17 +03:00
r = db_rbt2node ( * p ) ;
2007-11-10 01:43:24 +03:00
2015-11-25 11:22:08 +03:00
parent = ( * p ) ;
parent_node = r ;
2007-11-10 01:43:24 +03:00
db_rbt_parse_node ( r , & search_key , & search_val ) ;
2008-01-12 12:38:17 +03:00
res = db_rbt_compare ( this_key , search_key ) ;
2007-11-10 01:43:24 +03:00
2008-01-12 12:38:17 +03:00
if ( res = = - 1 ) {
2007-11-10 01:43:24 +03:00
p = & ( * p ) - > rb_left ;
}
2008-01-12 12:38:17 +03:00
else if ( res = = 1 ) {
2007-11-10 01:43:24 +03:00
p = & ( * p ) - > rb_right ;
}
else {
smb_panic ( " someone messed with the tree " ) ;
}
}
rb_link_node ( & node - > rb_node , parent , p ) ;
2015-11-25 11:22:08 +03:00
DLIST_ADD_AFTER ( db_ctx - > nodes , node , parent_node ) ;
2012-05-30 18:05:03 +04:00
rb_insert_color ( & node - > rb_node , & db_ctx - > tree ) ;
2007-11-10 01:43:24 +03:00
2016-09-12 18:30:55 +03:00
TALLOC_FREE ( to_free ) ;
2007-11-10 01:43:24 +03:00
return NT_STATUS_OK ;
}
static NTSTATUS db_rbt_delete ( struct db_record * rec )
{
2012-05-30 18:05:03 +04:00
struct db_rbt_ctx * db_ctx = talloc_get_type_abort (
rec - > db - > private_data , struct db_rbt_ctx ) ;
2008-01-12 12:38:17 +03:00
struct db_rbt_rec * rec_priv = ( struct db_rbt_rec * ) rec - > private_data ;
2007-11-10 01:43:24 +03:00
2015-11-25 11:22:08 +03:00
if ( db_ctx - > traverse_read > 0 ) {
return NT_STATUS_MEDIA_WRITE_PROTECTED ;
}
2007-11-10 01:43:24 +03:00
if ( rec_priv - > node = = NULL ) {
return NT_STATUS_OK ;
}
2015-11-25 11:22:08 +03:00
if ( db_ctx - > traverse_nextp ! = NULL ) {
if ( * db_ctx - > traverse_nextp = = rec_priv - > node ) {
* db_ctx - > traverse_nextp = rec_priv - > node - > next ;
}
}
2012-05-30 18:05:03 +04:00
rb_erase ( & rec_priv - > node - > rb_node , & db_ctx - > tree ) ;
2015-11-25 11:22:08 +03:00
DLIST_REMOVE ( db_ctx - > nodes , rec_priv - > node ) ;
2009-02-27 17:28:52 +03:00
TALLOC_FREE ( rec_priv - > node ) ;
2007-11-10 01:43:24 +03:00
return NT_STATUS_OK ;
}
2012-05-30 17:06:12 +04:00
2011-07-04 11:54:31 +04:00
struct db_rbt_search_result {
TDB_DATA key ;
TDB_DATA val ;
struct db_rbt_node * node ;
} ;
2007-11-10 01:43:24 +03:00
2011-07-04 11:54:31 +04:00
static bool db_rbt_search_internal ( struct db_context * db , TDB_DATA key ,
struct db_rbt_search_result * result )
2007-11-10 01:43:24 +03:00
{
struct db_rbt_ctx * ctx = talloc_get_type_abort (
2011-07-04 11:54:31 +04:00
db - > private_data , struct db_rbt_ctx ) ;
2007-11-10 01:43:24 +03:00
struct rb_node * n ;
2008-01-12 12:38:17 +03:00
bool found = false ;
struct db_rbt_node * r = NULL ;
2016-06-03 00:53:29 +03:00
TDB_DATA search_key = { 0 } ;
TDB_DATA search_val = { 0 } ;
2007-11-10 01:43:24 +03:00
2008-01-12 12:38:17 +03:00
n = ctx - > tree . rb_node ;
2007-11-10 01:43:24 +03:00
2008-01-12 12:38:17 +03:00
while ( n ! = NULL ) {
int res ;
r = db_rbt2node ( n ) ;
db_rbt_parse_node ( r , & search_key , & search_val ) ;
res = db_rbt_compare ( key , search_key ) ;
if ( res = = - 1 ) {
n = n - > rb_left ;
}
else if ( res = = 1 ) {
n = n - > rb_right ;
}
else {
found = true ;
break ;
}
2007-11-10 01:43:24 +03:00
}
2011-07-04 11:54:31 +04:00
if ( result ! = NULL ) {
if ( found ) {
result - > key = search_key ;
result - > val = search_val ;
result - > node = r ;
} else {
ZERO_STRUCT ( * result ) ;
}
}
return found ;
}
static struct db_record * db_rbt_fetch_locked ( struct db_context * db_ctx ,
TALLOC_CTX * mem_ctx ,
TDB_DATA key )
{
struct db_rbt_rec * rec_priv ;
struct db_record * result ;
size_t size ;
bool found ;
struct db_rbt_search_result res ;
found = db_rbt_search_internal ( db_ctx , key , & res ) ;
2007-11-10 01:43:24 +03:00
2008-01-12 12:38:17 +03:00
/*
* In this low - level routine , play tricks to reduce the number of
2023-03-31 12:10:03 +03:00
* tallocs to one . Not recommended for general use , but here it pays
2008-01-12 12:38:17 +03:00
* off .
*/
2007-11-10 01:43:24 +03:00
2008-06-19 11:50:34 +04:00
size = DBWRAP_RBT_ALIGN ( sizeof ( struct db_record ) )
+ sizeof ( struct db_rbt_rec ) ;
2008-01-12 12:38:17 +03:00
if ( ! found ) {
/*
* We need to keep the key around for later store
*/
size + = key . dsize ;
}
result = ( struct db_record * ) talloc_size ( mem_ctx , size ) ;
if ( result = = NULL ) {
2007-11-10 01:43:24 +03:00
return NULL ;
}
2008-01-12 12:38:17 +03:00
rec_priv = ( struct db_rbt_rec * )
2008-06-19 11:50:34 +04:00
( ( char * ) result + DBWRAP_RBT_ALIGN ( sizeof ( struct db_record ) ) ) ;
2007-11-10 01:43:24 +03:00
2016-09-12 18:30:55 +03:00
result - > storev = db_rbt_storev ;
2007-11-10 01:43:24 +03:00
result - > delete_rec = db_rbt_delete ;
result - > private_data = rec_priv ;
2011-07-04 11:54:31 +04:00
rec_priv - > node = res . node ;
result - > value = res . val ;
2019-10-24 17:41:47 +03:00
result - > value_valid = true ;
2011-07-04 11:54:31 +04:00
2008-01-12 12:38:17 +03:00
if ( found ) {
2011-07-04 11:54:31 +04:00
result - > key = res . key ;
2008-01-12 12:38:17 +03:00
}
else {
2012-05-11 23:54:46 +04:00
result - > key . dptr = ( uint8_t * )
2008-01-12 12:38:17 +03:00
( ( char * ) rec_priv + sizeof ( * rec_priv ) ) ;
result - > key . dsize = key . dsize ;
memcpy ( result - > key . dptr , key . dptr , key . dsize ) ;
}
return result ;
}
2011-07-04 12:22:46 +04:00
static int db_rbt_exists ( struct db_context * db , TDB_DATA key )
{
return db_rbt_search_internal ( db , key , NULL ) ;
}
2011-08-16 16:55:30 +04:00
static int db_rbt_wipe ( struct db_context * db )
{
struct db_rbt_ctx * old_ctx = talloc_get_type_abort (
db - > private_data , struct db_rbt_ctx ) ;
2011-08-17 13:44:12 +04:00
struct db_rbt_ctx * new_ctx = talloc_zero ( db , struct db_rbt_ctx ) ;
2011-08-16 16:55:30 +04:00
if ( new_ctx = = NULL ) {
return - 1 ;
}
db - > private_data = new_ctx ;
talloc_free ( old_ctx ) ;
return 0 ;
}
2011-12-08 18:50:33 +04:00
static NTSTATUS db_rbt_parse_record ( struct db_context * db , TDB_DATA key ,
void ( * parser ) ( TDB_DATA key , TDB_DATA data ,
void * private_data ) ,
void * private_data )
2011-07-05 17:06:05 +04:00
{
struct db_rbt_search_result res ;
bool found = db_rbt_search_internal ( db , key , & res ) ;
if ( ! found ) {
2011-12-08 18:50:33 +04:00
return NT_STATUS_NOT_FOUND ;
2011-07-05 17:06:05 +04:00
}
2011-12-08 18:50:33 +04:00
parser ( res . key , res . val , private_data ) ;
return NT_STATUS_OK ;
2011-07-05 17:06:05 +04:00
}
2012-05-30 17:06:12 +04:00
static int db_rbt_traverse_internal ( struct db_context * db ,
2009-08-08 15:43:41 +04:00
int ( * f ) ( struct db_record * db ,
void * private_data ) ,
2012-05-30 17:06:12 +04:00
void * private_data , uint32_t * count ,
bool rw )
2009-08-08 15:43:41 +04:00
{
2015-11-25 11:22:08 +03:00
struct db_rbt_ctx * ctx = talloc_get_type_abort (
db - > private_data , struct db_rbt_ctx ) ;
struct db_rbt_node * cur = NULL ;
struct db_rbt_node * next = NULL ;
2009-08-08 15:43:41 +04:00
int ret ;
2015-11-25 11:22:08 +03:00
for ( cur = ctx - > nodes ; cur ! = NULL ; cur = next ) {
struct db_record rec ;
struct db_rbt_rec rec_priv ;
2012-05-30 17:06:12 +04:00
2015-11-25 11:22:08 +03:00
rec_priv . node = cur ;
next = rec_priv . node - > next ;
2009-08-08 15:43:41 +04:00
2015-11-25 11:22:08 +03:00
ZERO_STRUCT ( rec ) ;
rec . db = db ;
rec . private_data = & rec_priv ;
2016-09-12 18:30:55 +03:00
rec . storev = db_rbt_storev ;
2015-11-25 11:22:08 +03:00
rec . delete_rec = db_rbt_delete ;
db_rbt_parse_node ( rec_priv . node , & rec . key , & rec . value ) ;
2019-10-24 17:41:47 +03:00
rec . value_valid = true ;
2012-05-30 17:06:12 +04:00
2015-11-25 11:22:08 +03:00
if ( rw ) {
ctx - > traverse_nextp = & next ;
}
ret = f ( & rec , private_data ) ;
( * count ) + + ;
if ( rw ) {
ctx - > traverse_nextp = NULL ;
}
if ( ret ! = 0 ) {
return ret ;
}
if ( rec_priv . node ! = NULL ) {
next = rec_priv . node - > next ;
}
2012-05-30 17:06:12 +04:00
}
2015-11-25 11:22:08 +03:00
return 0 ;
2009-08-08 15:43:41 +04:00
}
2007-11-10 01:43:24 +03:00
2015-11-25 11:22:08 +03:00
static int db_rbt_traverse_read ( struct db_context * db ,
int ( * f ) ( struct db_record * db ,
void * private_data ) ,
void * private_data )
2007-11-10 01:43:24 +03:00
{
2009-08-08 15:43:41 +04:00
struct db_rbt_ctx * ctx = talloc_get_type_abort (
db - > private_data , struct db_rbt_ctx ) ;
2011-08-17 13:44:12 +04:00
uint32_t count = 0 ;
2015-11-25 11:22:08 +03:00
int ret ;
2009-08-08 15:43:41 +04:00
2015-11-25 11:22:08 +03:00
ctx - > traverse_read + + ;
2015-11-25 11:22:08 +03:00
ret = db_rbt_traverse_internal ( db ,
2015-11-25 11:22:08 +03:00
f , private_data , & count ,
false /* rw */ ) ;
ctx - > traverse_read - - ;
2012-05-30 17:06:12 +04:00
if ( ret ! = 0 ) {
return - 1 ;
}
if ( count > INT_MAX ) {
return - 1 ;
}
return count ;
}
2015-11-25 11:22:08 +03:00
static int db_rbt_traverse ( struct db_context * db ,
int ( * f ) ( struct db_record * db ,
void * private_data ) ,
void * private_data )
2012-05-30 17:06:12 +04:00
{
struct db_rbt_ctx * ctx = talloc_get_type_abort (
db - > private_data , struct db_rbt_ctx ) ;
uint32_t count = 0 ;
2015-11-25 11:22:08 +03:00
int ret ;
2015-11-25 11:22:08 +03:00
if ( ctx - > traverse_nextp ! = NULL ) {
2015-11-25 11:22:08 +03:00
return - 1 ;
} ;
if ( ctx - > traverse_read > 0 ) {
return db_rbt_traverse_read ( db , f , private_data ) ;
}
2012-05-30 17:06:12 +04:00
2015-11-25 11:22:08 +03:00
ret = db_rbt_traverse_internal ( db ,
2015-11-25 11:22:08 +03:00
f , private_data , & count ,
true /* rw */ ) ;
2011-08-17 13:44:12 +04:00
if ( ret ! = 0 ) {
return - 1 ;
}
if ( count > INT_MAX ) {
return - 1 ;
}
return count ;
2007-11-10 01:43:24 +03:00
}
static int db_rbt_get_seqnum ( struct db_context * db )
{
return 0 ;
}
2008-03-10 12:17:05 +03:00
static int db_rbt_trans_dummy ( struct db_context * db )
{
/*
* Transactions are pretty pointless in - memory , just return success .
*/
return 0 ;
}
2015-09-20 17:26:06 +03:00
static size_t db_rbt_id ( struct db_context * db , uint8_t * id , size_t idlen )
2012-02-15 17:57:01 +04:00
{
2015-09-20 17:26:06 +03:00
if ( idlen > = sizeof ( struct db_context * ) ) {
memcpy ( id , & db , sizeof ( struct db_context * ) ) ;
}
return sizeof ( struct db_context * ) ;
2012-02-15 17:57:01 +04:00
}
2007-11-10 01:43:24 +03:00
struct db_context * db_open_rbt ( TALLOC_CTX * mem_ctx )
{
struct db_context * result ;
2012-11-29 18:02:43 +04:00
result = talloc_zero ( mem_ctx , struct db_context ) ;
2007-11-10 01:43:24 +03:00
if ( result = = NULL ) {
return NULL ;
}
2011-06-07 05:44:43 +04:00
result - > private_data = talloc_zero ( result , struct db_rbt_ctx ) ;
2007-11-10 01:43:24 +03:00
if ( result - > private_data = = NULL ) {
TALLOC_FREE ( result ) ;
return NULL ;
}
result - > fetch_locked = db_rbt_fetch_locked ;
result - > traverse = db_rbt_traverse ;
2012-05-30 17:06:12 +04:00
result - > traverse_read = db_rbt_traverse_read ;
2007-11-10 01:43:24 +03:00
result - > get_seqnum = db_rbt_get_seqnum ;
2008-03-10 12:17:05 +03:00
result - > transaction_start = db_rbt_trans_dummy ;
result - > transaction_commit = db_rbt_trans_dummy ;
result - > transaction_cancel = db_rbt_trans_dummy ;
2011-07-04 12:22:46 +04:00
result - > exists = db_rbt_exists ;
2011-08-16 16:55:30 +04:00
result - > wipe = db_rbt_wipe ;
2011-07-05 17:06:05 +04:00
result - > parse_record = db_rbt_parse_record ;
2012-02-15 17:57:01 +04:00
result - > id = db_rbt_id ;
2012-06-22 09:37:44 +04:00
result - > name = " dbwrap rbt " ;
2007-11-10 01:43:24 +03:00
return result ;
}