2011-12-02 20:40:33 +04:00
/*
r22775: For the cluster code I've developed a wrapper around tdb to put different
database backends in place dynamically.
The main abstractions are db_context and db_record, it should be mainly
self-describing, see include/dbwrap.h. You open the db just as you would open
a tdb, this time with db_open(). If you want to fetch a record, just do the
db->fetch() call, if you want to do operations on it, you need to get it with
fetch_locked().
I added dbwrap_file.c (not heavily tested lately) as an example for what can
be done with that abstraction, uses a file per key. So if anybody is willing
to shape that up, we might have a chance on reiserfs again.... :-)
This abstraction works fine for brlock.tdb, locking.tdb, connections.tdb and
sessionid.tdb. It should work fine for the others as well, I just did not yet
get around to convert them.
If nobody loudly screams NO, then I will import the code that uses this soon.
Volker
(This used to be commit e9d7484ca246cfca4a1fd23be35edc2783136ebe)
2007-05-10 14:42:13 +04:00
Unix SMB / CIFS implementation .
Database interface wrapper
Copyright ( C ) Jim McDonough < jmcd @ us . ibm . com > 2006
Major code contributions from Aleksey Fedoseev ( fedoseev @ ru . ibm . com )
2011-12-02 20:40:33 +04:00
r22775: For the cluster code I've developed a wrapper around tdb to put different
database backends in place dynamically.
The main abstractions are db_context and db_record, it should be mainly
self-describing, see include/dbwrap.h. You open the db just as you would open
a tdb, this time with db_open(). If you want to fetch a record, just do the
db->fetch() call, if you want to do operations on it, you need to get it with
fetch_locked().
I added dbwrap_file.c (not heavily tested lately) as an example for what can
be done with that abstraction, uses a file per key. So if anybody is willing
to shape that up, we might have a chance on reiserfs again.... :-)
This abstraction works fine for brlock.tdb, locking.tdb, connections.tdb and
sessionid.tdb. It should work fine for the others as well, I just did not yet
get around to convert them.
If nobody loudly screams NO, then I will import the code that uses this soon.
Volker
(This used to be commit e9d7484ca246cfca4a1fd23be35edc2783136ebe)
2007-05-10 14:42:13 +04: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
2007-07-09 23:25:36 +04:00
the Free Software Foundation ; either version 3 of the License , or
r22775: For the cluster code I've developed a wrapper around tdb to put different
database backends in place dynamically.
The main abstractions are db_context and db_record, it should be mainly
self-describing, see include/dbwrap.h. You open the db just as you would open
a tdb, this time with db_open(). If you want to fetch a record, just do the
db->fetch() call, if you want to do operations on it, you need to get it with
fetch_locked().
I added dbwrap_file.c (not heavily tested lately) as an example for what can
be done with that abstraction, uses a file per key. So if anybody is willing
to shape that up, we might have a chance on reiserfs again.... :-)
This abstraction works fine for brlock.tdb, locking.tdb, connections.tdb and
sessionid.tdb. It should work fine for the others as well, I just did not yet
get around to convert them.
If nobody loudly screams NO, then I will import the code that uses this soon.
Volker
(This used to be commit e9d7484ca246cfca4a1fd23be35edc2783136ebe)
2007-05-10 14:42:13 +04:00
( at your option ) any later version .
2011-12-02 20:40:33 +04:00
r22775: For the cluster code I've developed a wrapper around tdb to put different
database backends in place dynamically.
The main abstractions are db_context and db_record, it should be mainly
self-describing, see include/dbwrap.h. You open the db just as you would open
a tdb, this time with db_open(). If you want to fetch a record, just do the
db->fetch() call, if you want to do operations on it, you need to get it with
fetch_locked().
I added dbwrap_file.c (not heavily tested lately) as an example for what can
be done with that abstraction, uses a file per key. So if anybody is willing
to shape that up, we might have a chance on reiserfs again.... :-)
This abstraction works fine for brlock.tdb, locking.tdb, connections.tdb and
sessionid.tdb. It should work fine for the others as well, I just did not yet
get around to convert them.
If nobody loudly screams NO, then I will import the code that uses this soon.
Volker
(This used to be commit e9d7484ca246cfca4a1fd23be35edc2783136ebe)
2007-05-10 14:42:13 +04:00
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 .
2011-12-02 20:40:33 +04:00
r22775: For the cluster code I've developed a wrapper around tdb to put different
database backends in place dynamically.
The main abstractions are db_context and db_record, it should be mainly
self-describing, see include/dbwrap.h. You open the db just as you would open
a tdb, this time with db_open(). If you want to fetch a record, just do the
db->fetch() call, if you want to do operations on it, you need to get it with
fetch_locked().
I added dbwrap_file.c (not heavily tested lately) as an example for what can
be done with that abstraction, uses a file per key. So if anybody is willing
to shape that up, we might have a chance on reiserfs again.... :-)
This abstraction works fine for brlock.tdb, locking.tdb, connections.tdb and
sessionid.tdb. It should work fine for the others as well, I just did not yet
get around to convert them.
If nobody loudly screams NO, then I will import the code that uses this soon.
Volker
(This used to be commit e9d7484ca246cfca4a1fd23be35edc2783136ebe)
2007-05-10 14:42:13 +04:00
You should have received a copy of the GNU General Public License
2007-07-10 04:52:41 +04:00
along with this program . If not , see < http : //www.gnu.org/licenses/>.
r22775: For the cluster code I've developed a wrapper around tdb to put different
database backends in place dynamically.
The main abstractions are db_context and db_record, it should be mainly
self-describing, see include/dbwrap.h. You open the db just as you would open
a tdb, this time with db_open(). If you want to fetch a record, just do the
db->fetch() call, if you want to do operations on it, you need to get it with
fetch_locked().
I added dbwrap_file.c (not heavily tested lately) as an example for what can
be done with that abstraction, uses a file per key. So if anybody is willing
to shape that up, we might have a chance on reiserfs again.... :-)
This abstraction works fine for brlock.tdb, locking.tdb, connections.tdb and
sessionid.tdb. It should work fine for the others as well, I just did not yet
get around to convert them.
If nobody loudly screams NO, then I will import the code that uses this soon.
Volker
(This used to be commit e9d7484ca246cfca4a1fd23be35edc2783136ebe)
2007-05-10 14:42:13 +04:00
*/
2016-02-22 22:39:20 +03:00
# include "replace.h"
# include "lib/util/debug.h"
# include "lib/util/fault.h"
# include "lib/util/talloc_stack.h"
2011-07-07 19:42:08 +04:00
# include "dbwrap/dbwrap.h"
2011-07-06 18:40:21 +04:00
# include "dbwrap/dbwrap_private.h"
2012-05-12 00:11:42 +04:00
# include "lib/util/util_tdb.h"
2016-12-27 11:13:37 +03:00
# include "lib/util/tevent_ntstatus.h"
2011-07-06 18:40:21 +04:00
2011-07-04 12:15:44 +04:00
/*
* Fall back using fetch if no genuine exists operation is provided
*/
static int dbwrap_fallback_exists ( struct db_context * db , TDB_DATA key )
{
2011-12-08 18:50:33 +04:00
NTSTATUS status = dbwrap_parse_record ( db , key , NULL , NULL ) ;
return NT_STATUS_IS_OK ( status ) ? 1 : 0 ;
2011-07-04 12:15:44 +04:00
}
2011-08-16 16:39:19 +04:00
static int delete_record ( struct db_record * rec , void * data )
{
2011-12-08 16:51:19 +04:00
NTSTATUS status = dbwrap_record_delete ( rec ) ;
2011-08-16 16:39:19 +04:00
return NT_STATUS_IS_OK ( status ) ? 0 : - 1 ;
}
/*
2011-12-09 14:12:59 +04:00
* Fallback wipe implementation using traverse and delete if no genuine
2011-08-16 16:39:19 +04:00
* wipe operation is provided
*/
2011-12-08 17:01:27 +04:00
static int dbwrap_fallback_wipe ( struct db_context * db )
2011-08-16 16:39:19 +04:00
{
2011-12-08 17:02:27 +04:00
NTSTATUS status = dbwrap_trans_traverse ( db , delete_record , NULL ) ;
2011-08-16 16:39:19 +04:00
return NT_STATUS_IS_OK ( status ) ? 0 : - 1 ;
}
2012-06-22 09:37:43 +04:00
static int do_nothing ( struct db_record * rec , void * unused )
{
return 0 ;
}
/*
* Fallback check operation : just traverse .
*/
static int dbwrap_fallback_check ( struct db_context * db )
{
NTSTATUS status = dbwrap_traverse_read ( db , do_nothing , NULL , NULL ) ;
return NT_STATUS_IS_OK ( status ) ? 0 : - 1 ;
}
2011-08-16 16:39:19 +04:00
2011-08-17 16:42:50 +04:00
/*
* Wrapper functions for the backend methods
*/
2011-08-19 12:50:20 +04:00
TDB_DATA dbwrap_record_get_key ( const struct db_record * rec )
{
return rec - > key ;
}
TDB_DATA dbwrap_record_get_value ( const struct db_record * rec )
{
2019-10-24 17:41:47 +03:00
SMB_ASSERT ( rec - > value_valid ) ;
2011-08-19 12:50:20 +04:00
return rec - > value ;
}
2016-09-13 13:25:14 +03:00
NTSTATUS dbwrap_record_storev ( struct db_record * rec ,
const TDB_DATA * dbufs , int num_dbufs , int flags )
2011-08-19 12:51:27 +04:00
{
2012-02-15 18:08:29 +04:00
NTSTATUS status ;
2019-10-24 17:41:47 +03:00
/*
* Invalidate before rec - > storev ( ) is called , give
* rec - > storev ( ) the chance to re - validate rec - > value .
*/
rec - > value_valid = false ;
2016-09-13 13:25:14 +03:00
status = rec - > storev ( rec , dbufs , num_dbufs , flags ) ;
2012-02-15 18:08:29 +04:00
if ( ! NT_STATUS_IS_OK ( status ) ) {
return status ;
}
return NT_STATUS_OK ;
}
2016-09-13 13:25:14 +03:00
NTSTATUS dbwrap_record_store ( struct db_record * rec , TDB_DATA data , int flags )
{
return dbwrap_record_storev ( rec , & data , 1 , flags ) ;
}
2011-08-19 12:52:57 +04:00
NTSTATUS dbwrap_record_delete ( struct db_record * rec )
{
2012-02-15 18:08:29 +04:00
NTSTATUS status ;
status = rec - > delete_rec ( rec ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
return status ;
}
2021-10-29 23:03:42 +03:00
rec - > value = tdb_null ;
2012-02-15 18:08:29 +04:00
return NT_STATUS_OK ;
2011-08-19 12:52:57 +04:00
}
2019-11-21 15:23:39 +03:00
const char * locked_dbs [ DBWRAP_LOCK_ORDER_MAX ] ;
static void debug_lock_order ( int level )
2012-08-01 17:31:18 +04:00
{
int i ;
DEBUG ( level , ( " lock order: " ) ) ;
for ( i = 0 ; i < DBWRAP_LOCK_ORDER_MAX ; i + + ) {
2019-11-21 15:23:39 +03:00
DEBUGADD ( level ,
( " %d:%s " ,
i + 1 ,
locked_dbs [ i ] ? locked_dbs [ i ] : " <none> " ) ) ;
2012-08-01 17:31:18 +04:00
}
DEBUGADD ( level , ( " \n " ) ) ;
}
2019-11-21 17:19:16 +03:00
void dbwrap_lock_order_lock ( const char * db_name ,
enum dbwrap_lock_order lock_order )
2012-01-08 22:04:39 +04:00
{
2017-07-20 17:31:14 +03:00
int idx ;
2012-08-01 17:31:18 +04:00
2019-11-21 15:23:39 +03:00
DBG_INFO ( " check lock order %d for %s \n " ,
( int ) lock_order ,
db_name ) ;
2012-08-01 17:31:18 +04:00
2019-11-21 15:23:39 +03:00
if ( ! DBWRAP_LOCK_ORDER_VALID ( lock_order ) ) {
2017-07-20 17:31:14 +03:00
DBG_ERR ( " Invalid lock order %d of %s \n " ,
2019-11-21 15:23:39 +03:00
lock_order ,
db_name ) ;
2017-07-20 17:31:14 +03:00
smb_panic ( " lock order violation " ) ;
2012-08-01 17:31:18 +04:00
}
2019-11-21 15:23:39 +03:00
for ( idx = lock_order - 1 ; idx < DBWRAP_LOCK_ORDER_MAX ; idx + + ) {
2017-07-20 17:31:14 +03:00
if ( locked_dbs [ idx ] ! = NULL ) {
DBG_ERR ( " Lock order violation: Trying %s at %d while "
" %s at %d is locked \n " ,
2019-11-21 15:23:39 +03:00
db_name ,
( int ) lock_order ,
locked_dbs [ idx ] ,
idx + 1 ) ;
debug_lock_order ( 0 ) ;
2017-07-20 17:31:14 +03:00
smb_panic ( " lock order violation " ) ;
}
}
2012-08-01 17:31:18 +04:00
2019-11-21 15:23:39 +03:00
locked_dbs [ lock_order - 1 ] = db_name ;
2012-08-01 17:31:18 +04:00
2019-11-21 15:23:39 +03:00
debug_lock_order ( 10 ) ;
2012-01-08 22:04:39 +04:00
}
2019-11-21 17:19:16 +03:00
void dbwrap_lock_order_unlock ( const char * db_name ,
enum dbwrap_lock_order lock_order )
2012-01-08 22:04:39 +04:00
{
2017-07-20 17:31:14 +03:00
DBG_INFO ( " release lock order %d for %s \n " ,
2019-11-21 15:23:39 +03:00
( int ) lock_order ,
db_name ) ;
if ( ! DBWRAP_LOCK_ORDER_VALID ( lock_order ) ) {
DBG_ERR ( " Invalid lock order %d of %s \n " ,
lock_order ,
db_name ) ;
smb_panic ( " lock order violation " ) ;
}
2012-01-08 22:04:39 +04:00
2019-11-21 15:23:39 +03:00
if ( locked_dbs [ lock_order - 1 ] = = NULL ) {
DBG_ERR ( " db %s at order %d unlocked \n " ,
db_name ,
( int ) lock_order ) ;
2017-07-20 17:31:14 +03:00
smb_panic ( " lock order violation " ) ;
2012-08-01 17:31:18 +04:00
}
2012-01-08 22:04:39 +04:00
2019-11-21 15:23:39 +03:00
if ( locked_dbs [ lock_order - 1 ] ! = db_name ) {
2017-07-20 17:31:14 +03:00
DBG_ERR ( " locked db at lock order %d is %s, expected %s \n " ,
2019-11-21 15:23:39 +03:00
( int ) lock_order ,
locked_dbs [ lock_order - 1 ] ,
db_name ) ;
2017-07-20 17:31:14 +03:00
smb_panic ( " lock order violation " ) ;
}
2012-01-08 22:04:39 +04:00
2019-11-21 15:23:39 +03:00
locked_dbs [ lock_order - 1 ] = NULL ;
2017-07-20 17:31:14 +03:00
}
2012-01-08 22:04:39 +04:00
2017-07-20 17:31:14 +03:00
struct dbwrap_lock_order_state {
struct db_context * db ;
} ;
static int dbwrap_lock_order_state_destructor (
struct dbwrap_lock_order_state * s )
{
2019-11-21 15:23:39 +03:00
struct db_context * db = s - > db ;
dbwrap_lock_order_unlock ( db - > name , db - > lock_order ) ;
2017-07-20 17:31:14 +03:00
return 0 ;
}
static struct dbwrap_lock_order_state * dbwrap_check_lock_order (
struct db_context * db , TALLOC_CTX * mem_ctx )
{
struct dbwrap_lock_order_state * state ;
2012-01-08 22:04:39 +04:00
state = talloc ( mem_ctx , struct dbwrap_lock_order_state ) ;
if ( state = = NULL ) {
2017-07-20 17:31:14 +03:00
DBG_WARNING ( " talloc failed \n " ) ;
2012-01-08 22:04:39 +04:00
return NULL ;
}
2012-08-01 17:31:18 +04:00
state - > db = db ;
2019-11-21 15:23:39 +03:00
dbwrap_lock_order_lock ( db - > name , db - > lock_order ) ;
2017-07-20 17:31:14 +03:00
talloc_set_destructor ( state , dbwrap_lock_order_state_destructor ) ;
2012-01-08 22:04:39 +04:00
return state ;
}
2012-03-27 16:31:04 +04:00
static struct db_record * dbwrap_fetch_locked_internal (
struct db_context * db , TALLOC_CTX * mem_ctx , TDB_DATA key ,
struct db_record * ( * db_fn ) ( struct db_context * db , TALLOC_CTX * mem_ctx ,
TDB_DATA key ) )
2011-08-19 12:53:29 +04:00
{
2012-01-08 22:04:39 +04:00
struct db_record * rec ;
2013-12-06 15:57:42 +04:00
struct dbwrap_lock_order_state * lock_order = NULL ;
2012-01-08 22:04:39 +04:00
2014-01-27 20:20:56 +04:00
if ( db - > lock_order ! = DBWRAP_LOCK_ORDER_NONE ) {
2013-12-06 15:57:42 +04:00
lock_order = dbwrap_check_lock_order ( db , mem_ctx ) ;
if ( lock_order = = NULL ) {
return NULL ;
}
2012-01-08 22:04:39 +04:00
}
2012-03-27 16:31:04 +04:00
rec = db_fn ( db , mem_ctx , key ) ;
2012-01-08 22:04:39 +04:00
if ( rec = = NULL ) {
2013-12-06 15:38:12 +04:00
TALLOC_FREE ( lock_order ) ;
2012-01-08 22:04:39 +04:00
return NULL ;
}
( void ) talloc_steal ( rec , lock_order ) ;
2012-01-02 16:30:51 +04:00
rec - > db = db ;
2012-01-08 22:04:39 +04:00
return rec ;
2011-08-19 12:53:29 +04:00
}
2012-03-27 16:31:04 +04:00
struct db_record * dbwrap_fetch_locked ( struct db_context * db ,
TALLOC_CTX * mem_ctx ,
TDB_DATA key )
{
return dbwrap_fetch_locked_internal ( db , mem_ctx , key ,
db - > fetch_locked ) ;
}
2012-01-02 16:30:51 +04:00
struct db_context * dbwrap_record_get_db ( struct db_record * rec )
{
return rec - > db ;
}
2011-12-08 19:43:40 +04:00
struct dbwrap_fetch_state {
TALLOC_CTX * mem_ctx ;
TDB_DATA data ;
} ;
static void dbwrap_fetch_parser ( TDB_DATA key , TDB_DATA data ,
void * private_data )
{
struct dbwrap_fetch_state * state =
( struct dbwrap_fetch_state * ) private_data ;
state - > data . dsize = data . dsize ;
state - > data . dptr = ( uint8_t * ) talloc_memdup ( state - > mem_ctx , data . dptr ,
data . dsize ) ;
}
2011-08-24 15:08:13 +04:00
NTSTATUS dbwrap_fetch ( struct db_context * db , TALLOC_CTX * mem_ctx ,
TDB_DATA key , TDB_DATA * value )
2011-08-17 10:35:21 +04:00
{
2011-12-08 19:43:40 +04:00
struct dbwrap_fetch_state state ;
NTSTATUS status ;
2011-08-24 15:08:13 +04:00
if ( value = = NULL ) {
return NT_STATUS_INVALID_PARAMETER ;
}
2011-12-08 19:43:40 +04:00
state . mem_ctx = mem_ctx ;
status = dbwrap_parse_record ( db , key , dbwrap_fetch_parser , & state ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
return status ;
}
if ( ( state . data . dsize ! = 0 ) & & ( state . data . dptr = = NULL ) ) {
return NT_STATUS_NO_MEMORY ;
2011-12-08 16:56:07 +04:00
}
2011-12-08 19:43:40 +04:00
* value = state . data ;
return NT_STATUS_OK ;
2011-08-17 10:35:21 +04:00
}
2011-08-17 10:36:52 +04:00
2011-07-04 12:15:44 +04:00
bool dbwrap_exists ( struct db_context * db , TDB_DATA key )
{
int result ;
if ( db - > exists ! = NULL ) {
result = db - > exists ( db , key ) ;
} else {
result = dbwrap_fallback_exists ( db , key ) ;
}
return ( result = = 1 ) ;
}
2016-11-09 18:34:28 +03:00
struct dbwrap_store_state {
TDB_DATA data ;
int flags ;
NTSTATUS status ;
} ;
2019-10-23 12:34:47 +03:00
static void dbwrap_store_fn (
struct db_record * rec ,
TDB_DATA value ,
void * private_data )
2016-11-09 18:34:28 +03:00
{
struct dbwrap_store_state * state = private_data ;
state - > status = dbwrap_record_store ( rec , state - > data , state - > flags ) ;
}
2011-08-17 10:38:39 +04:00
NTSTATUS dbwrap_store ( struct db_context * db , TDB_DATA key ,
TDB_DATA data , int flags )
{
2016-11-09 18:34:28 +03:00
struct dbwrap_store_state state = { . data = data , . flags = flags } ;
2011-08-17 10:38:39 +04:00
NTSTATUS status ;
2016-11-09 18:34:28 +03:00
status = dbwrap_do_locked ( db , key , dbwrap_store_fn , & state ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
return status ;
2011-08-17 10:38:39 +04:00
}
2016-11-09 18:34:28 +03:00
return state . status ;
2011-08-17 10:38:39 +04:00
}
2016-11-09 18:37:49 +03:00
struct dbwrap_delete_state {
NTSTATUS status ;
} ;
2019-10-23 12:34:47 +03:00
static void dbwrap_delete_fn (
struct db_record * rec ,
TDB_DATA value ,
void * private_data )
2016-11-09 18:37:49 +03:00
{
struct dbwrap_delete_state * state = private_data ;
state - > status = dbwrap_record_delete ( rec ) ;
}
2011-08-17 10:36:52 +04:00
NTSTATUS dbwrap_delete ( struct db_context * db , TDB_DATA key )
{
2019-08-23 18:47:47 +03:00
struct dbwrap_delete_state state = { . status = NT_STATUS_NOT_FOUND } ;
2011-08-17 10:36:52 +04:00
NTSTATUS status ;
2016-11-09 18:37:49 +03:00
status = dbwrap_do_locked ( db , key , dbwrap_delete_fn , & state ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
return status ;
2011-08-17 10:36:52 +04:00
}
2016-11-09 18:37:49 +03:00
return state . status ;
2011-08-17 10:36:52 +04:00
}
2011-08-17 10:40:53 +04:00
NTSTATUS dbwrap_traverse ( struct db_context * db ,
int ( * f ) ( struct db_record * , void * ) ,
2011-08-17 11:51:12 +04:00
void * private_data ,
int * count )
2011-08-17 10:40:53 +04:00
{
int ret = db - > traverse ( db , f , private_data ) ;
2011-08-17 11:51:12 +04:00
if ( ret < 0 ) {
return NT_STATUS_INTERNAL_DB_CORRUPTION ;
}
if ( count ! = NULL ) {
* count = ret ;
}
return NT_STATUS_OK ;
2011-08-17 10:40:53 +04:00
}
2011-08-17 11:59:25 +04:00
NTSTATUS dbwrap_traverse_read ( struct db_context * db ,
int ( * f ) ( struct db_record * , void * ) ,
void * private_data ,
int * count )
{
int ret = db - > traverse_read ( db , f , private_data ) ;
if ( ret < 0 ) {
return NT_STATUS_INTERNAL_DB_CORRUPTION ;
}
if ( count ! = NULL ) {
* count = ret ;
}
return NT_STATUS_OK ;
}
2011-07-05 15:10:30 +04:00
2011-12-08 18:50:33 +04:00
static void dbwrap_null_parser ( TDB_DATA key , TDB_DATA val , void * data )
2011-07-05 15:42:39 +04:00
{
2011-12-08 18:50:33 +04:00
return ;
2011-07-05 15:42:39 +04:00
}
2011-12-08 18:50:33 +04:00
NTSTATUS dbwrap_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 15:10:30 +04:00
{
2011-07-05 15:42:39 +04:00
if ( parser = = NULL ) {
parser = dbwrap_null_parser ;
}
2011-12-08 16:59:33 +04:00
return db - > parse_record ( db , key , parser , private_data ) ;
2011-07-05 15:10:30 +04:00
}
2011-08-16 16:39:19 +04:00
2016-12-27 11:13:37 +03:00
struct dbwrap_parse_record_state {
struct db_context * db ;
TDB_DATA key ;
uint8_t _keybuf [ 64 ] ;
} ;
static void dbwrap_parse_record_done ( struct tevent_req * subreq ) ;
struct tevent_req * dbwrap_parse_record_send (
TALLOC_CTX * mem_ctx ,
struct tevent_context * ev ,
struct db_context * db ,
TDB_DATA key ,
void ( * parser ) ( TDB_DATA key , TDB_DATA data , void * private_data ) ,
void * private_data ,
enum dbwrap_req_state * req_state )
{
struct tevent_req * req = NULL ;
struct tevent_req * subreq = NULL ;
struct dbwrap_parse_record_state * state = NULL ;
NTSTATUS status ;
req = tevent_req_create ( mem_ctx , & state , struct dbwrap_parse_record_state ) ;
if ( req = = NULL ) {
* req_state = DBWRAP_REQ_ERROR ;
return NULL ;
}
* state = ( struct dbwrap_parse_record_state ) {
. db = db ,
} ;
if ( parser = = NULL ) {
parser = dbwrap_null_parser ;
}
* req_state = DBWRAP_REQ_INIT ;
if ( db - > parse_record_send = = NULL ) {
/*
* Backend doesn ' t implement async version , call sync one
*/
status = db - > parse_record ( db , key , parser , private_data ) ;
if ( tevent_req_nterror ( req , status ) ) {
* req_state = DBWRAP_REQ_DONE ;
return tevent_req_post ( req , ev ) ;
}
* req_state = DBWRAP_REQ_DONE ;
tevent_req_done ( req ) ;
return tevent_req_post ( req , ev ) ;
}
/*
* Copy the key into our state ensuring the key data buffer is always
2018-07-30 17:29:58 +03:00
* available to all the dbwrap backends over the entire lifetime of the
2016-12-27 11:13:37 +03:00
* async request . Otherwise the caller might have free ' d the key buffer .
*/
if ( key . dsize > sizeof ( state - > _keybuf ) ) {
state - > key . dptr = talloc_memdup ( state , key . dptr , key . dsize ) ;
if ( tevent_req_nomem ( state - > key . dptr , req ) ) {
return tevent_req_post ( req , ev ) ;
}
} else {
memcpy ( state - > _keybuf , key . dptr , key . dsize ) ;
state - > key . dptr = state - > _keybuf ;
}
state - > key . dsize = key . dsize ;
subreq = db - > parse_record_send ( state ,
ev ,
db ,
state - > key ,
parser ,
private_data ,
req_state ) ;
if ( tevent_req_nomem ( subreq , req ) ) {
* req_state = DBWRAP_REQ_ERROR ;
return tevent_req_post ( req , ev ) ;
}
tevent_req_set_callback ( subreq ,
dbwrap_parse_record_done ,
req ) ;
return req ;
}
static void dbwrap_parse_record_done ( struct tevent_req * subreq )
{
struct tevent_req * req = tevent_req_callback_data (
subreq , struct tevent_req ) ;
struct dbwrap_parse_record_state * state = tevent_req_data (
req , struct dbwrap_parse_record_state ) ;
NTSTATUS status ;
status = state - > db - > parse_record_recv ( subreq ) ;
TALLOC_FREE ( subreq ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
tevent_req_nterror ( req , status ) ;
return ;
}
tevent_req_done ( req ) ;
}
NTSTATUS dbwrap_parse_record_recv ( struct tevent_req * req )
{
return tevent_req_simple_recv_ntstatus ( req ) ;
}
2016-11-09 10:45:59 +03:00
NTSTATUS dbwrap_do_locked ( struct db_context * db , TDB_DATA key ,
void ( * fn ) ( struct db_record * rec ,
2019-10-23 12:34:47 +03:00
TDB_DATA value ,
2016-11-09 10:45:59 +03:00
void * private_data ) ,
void * private_data )
{
struct db_record * rec ;
if ( db - > do_locked ! = NULL ) {
NTSTATUS status ;
if ( db - > lock_order ! = DBWRAP_LOCK_ORDER_NONE ) {
2019-11-21 15:23:39 +03:00
dbwrap_lock_order_lock ( db - > name , db - > lock_order ) ;
2016-11-09 10:45:59 +03:00
}
status = db - > do_locked ( db , key , fn , private_data ) ;
2019-11-21 15:23:39 +03:00
if ( db - > lock_order ! = DBWRAP_LOCK_ORDER_NONE ) {
dbwrap_lock_order_unlock ( db - > name , db - > lock_order ) ;
2016-11-09 10:45:59 +03:00
}
return status ;
}
rec = dbwrap_fetch_locked ( db , db , key ) ;
if ( rec = = NULL ) {
return NT_STATUS_NO_MEMORY ;
}
2019-10-23 13:19:38 +03:00
/*
* Invalidate rec - > value , nobody shall assume it ' s set from
* within dbwrap_do_locked ( ) .
*/
rec - > value_valid = false ;
2019-10-23 12:34:47 +03:00
fn ( rec , rec - > value , private_data ) ;
2016-11-09 10:45:59 +03:00
TALLOC_FREE ( rec ) ;
return NT_STATUS_OK ;
}
2011-08-16 16:39:19 +04:00
int dbwrap_wipe ( struct db_context * db )
{
2011-12-08 17:01:27 +04:00
if ( db - > wipe = = NULL ) {
return dbwrap_fallback_wipe ( db ) ;
}
2011-08-16 16:39:19 +04:00
return db - > wipe ( db ) ;
}
2011-08-18 00:43:01 +04:00
2012-06-22 09:37:43 +04:00
int dbwrap_check ( struct db_context * db )
{
if ( db - > check = = NULL ) {
return dbwrap_fallback_check ( db ) ;
}
return db - > check ( db ) ;
}
2011-08-18 16:09:56 +04:00
int dbwrap_get_seqnum ( struct db_context * db )
{
return db - > get_seqnum ( db ) ;
}
2011-08-18 00:51:12 +04:00
int dbwrap_transaction_start ( struct db_context * db )
{
2013-01-11 18:32:39 +04:00
if ( ! db - > persistent ) {
2013-03-27 13:23:50 +04:00
/*
* dbwrap_ctdb has two different data models for persistent
* and non - persistent databases . Transactions are supported
* only for the persistent databases . This check is here to
* prevent breakages of the cluster case , autobuild at this
* point only tests non - clustered Samba . Before removing this
* check , please make sure that this facility has also been
* added to dbwrap_ctdb .
*
* Thanks , vl
*/
2013-01-11 18:32:39 +04:00
DEBUG ( 1 , ( " transactions not supported on non-persistent "
" database %s \n " , db - > name ) ) ;
return - 1 ;
}
2011-08-18 00:51:12 +04:00
return db - > transaction_start ( db ) ;
}
2012-06-22 09:37:44 +04:00
NTSTATUS dbwrap_transaction_start_nonblock ( struct db_context * db )
{
if ( db - > transaction_start_nonblock ) {
return db - > transaction_start_nonblock ( db ) ;
} else {
return dbwrap_transaction_start ( db ) = = 0 ? NT_STATUS_OK
: NT_STATUS_UNSUCCESSFUL ;
}
}
2011-08-18 00:51:12 +04:00
int dbwrap_transaction_commit ( struct db_context * db )
{
return db - > transaction_commit ( db ) ;
}
int dbwrap_transaction_cancel ( struct db_context * db )
{
return db - > transaction_cancel ( db ) ;
}
2012-02-15 17:57:01 +04:00
2015-09-20 17:26:06 +03:00
size_t dbwrap_db_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
return db - > id ( db , id , idlen ) ;
2012-02-15 17:57:01 +04:00
}
2012-06-22 09:37:44 +04:00
2013-01-02 04:02:56 +04:00
bool dbwrap_is_persistent ( struct db_context * db )
{
return db - > persistent ;
}
2012-06-22 09:37:44 +04:00
const char * dbwrap_name ( struct db_context * db )
{
return db - > name ;
}
2016-09-12 18:11:09 +03:00
static ssize_t tdb_data_buf ( const TDB_DATA * dbufs , int num_dbufs ,
uint8_t * buf , size_t buflen )
{
size_t needed = 0 ;
uint8_t * p = buf ;
int i ;
for ( i = 0 ; i < num_dbufs ; i + + ) {
size_t thislen = dbufs [ i ] . dsize ;
2019-05-03 16:43:35 +03:00
needed + = thislen ;
if ( needed < thislen ) {
2016-09-12 18:11:09 +03:00
/* wrap */
return - 1 ;
}
2019-06-14 16:40:28 +03:00
if ( p ! = NULL & & ( thislen ! = 0 ) & & ( needed < = buflen ) ) {
2016-09-12 18:11:09 +03:00
memcpy ( p , dbufs [ i ] . dptr , thislen ) ;
p + = thislen ;
}
}
return needed ;
}
TDB_DATA dbwrap_merge_dbufs ( TALLOC_CTX * mem_ctx ,
const TDB_DATA * dbufs , int num_dbufs )
{
ssize_t len = tdb_data_buf ( dbufs , num_dbufs , NULL , 0 ) ;
uint8_t * buf ;
if ( len = = - 1 ) {
return ( TDB_DATA ) { 0 } ;
}
buf = talloc_array ( mem_ctx , uint8_t , len ) ;
if ( buf = = NULL ) {
return ( TDB_DATA ) { 0 } ;
}
tdb_data_buf ( dbufs , num_dbufs , buf , len ) ;
return ( TDB_DATA ) { . dptr = buf , . dsize = len } ;
}