2002-09-11 14:07:21 +00:00
/*
Unix SMB / CIFS implementation .
Generic , persistent and shared between processes cache mechanism for use
by various parts of the Samba code
Copyright ( C ) Rafal Szczesniak 2002
2009-01-19 00:01:08 +01:00
2002-09-11 14:07:21 +00: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 19:25:36 +00:00
the Free Software Foundation ; either version 3 of the License , or
2002-09-11 14:07:21 +00:00
( at your option ) any later version .
2009-01-19 00:01:08 +01:00
2002-09-11 14:07:21 +00: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 .
2009-01-19 00:01:08 +01:00
2002-09-11 14:07:21 +00:00
You should have received a copy of the GNU General Public License
2007-07-10 00:52:41 +00:00
along with this program . If not , see < http : //www.gnu.org/licenses/>.
2002-09-11 14:07:21 +00:00
*/
# include "includes.h"
# undef DBGC_CLASS
# define DBGC_CLASS DBGC_TDB
# define TIMEOUT_LEN 12
# define CACHE_DATA_FMT "%12u / %s"
2006-06-15 21:03:40 +00:00
# define READ_CACHE_DATA_FMT_TEMPLATE "%%12u / %%%us"
2007-08-28 12:40:01 +00:00
# define BLOB_TYPE "DATA_BLOB"
# define BLOB_TYPE_LEN 9
2002-09-11 14:07:21 +00:00
2009-07-10 11:00:24 +02:00
static struct tdb_context * cache ;
2009-07-13 17:04:29 +02:00
static struct tdb_context * cache_notrans ;
2002-09-11 14:07:21 +00:00
/**
* @ file gencache . c
* @ brief Generic , persistent and shared between processes cache mechanism
* for use by various parts of the Samba code
*
* */
/**
* Cache initialisation function . Opens cache tdb file or creates
* it if does not exist .
*
* @ return true on successful initialisation of the cache or
* false on failure
* */
2009-07-10 12:24:56 +02:00
static bool gencache_init ( void )
2002-09-11 14:07:21 +00:00
{
char * cache_fname = NULL ;
2009-07-13 17:04:29 +02:00
int open_flags = O_RDWR | O_CREAT ;
2009-01-19 00:01:08 +01:00
2002-09-11 14:07:21 +00:00
/* skip file open if it's already opened */
if ( cache ) return True ;
2006-10-19 15:47:19 +00:00
cache_fname = lock_path ( " gencache.tdb " ) ;
2002-09-11 14:07:21 +00:00
2006-09-09 21:05:51 +00:00
DEBUG ( 5 , ( " Opening cache file at %s \n " , cache_fname ) ) ;
2009-07-13 17:04:29 +02:00
cache = tdb_open_log ( cache_fname , 0 , TDB_DEFAULT , open_flags , 0644 ) ;
2002-09-11 14:07:21 +00:00
2006-10-02 23:34:03 +00:00
if ( ! cache & & ( errno = = EACCES ) ) {
2009-07-13 17:04:29 +02:00
open_flags = O_RDONLY ;
cache = tdb_open_log ( cache_fname , 0 , TDB_DEFAULT , open_flags ,
0644 ) ;
2006-10-02 23:34:03 +00:00
if ( cache ) {
DEBUG ( 5 , ( " gencache_init: Opening cache file %s read-only. \n " , cache_fname ) ) ;
}
}
2002-09-11 14:07:21 +00:00
if ( ! cache ) {
2003-02-12 01:20:56 +00:00
DEBUG ( 5 , ( " Attempt to open gencache.tdb has failed. \n " ) ) ;
2002-09-11 14:07:21 +00:00
return False ;
}
2009-07-13 17:04:29 +02:00
cache_fname = lock_path ( " gencache_notrans.tdb " ) ;
DEBUG ( 5 , ( " Opening cache file at %s \n " , cache_fname ) ) ;
cache_notrans = tdb_open_log ( cache_fname , 0 , TDB_CLEAR_IF_FIRST ,
open_flags , 0644 ) ;
if ( cache_notrans = = NULL ) {
DEBUG ( 5 , ( " Opening %s failed: %s \n " , cache_fname ,
strerror ( errno ) ) ) ;
tdb_close ( cache ) ;
return false ;
}
2002-09-11 14:07:21 +00:00
return True ;
}
2009-07-13 17:04:29 +02:00
static TDB_DATA last_stabilize_key ( void )
{
TDB_DATA result ;
result . dptr = ( uint8_t * ) " @LAST_STABILIZED " ;
result . dsize = 17 ;
return result ;
}
2002-09-11 14:07:21 +00:00
/**
2003-01-04 08:48:15 +00:00
* Set an entry in the cache file . If there ' s no such
* one , then add it .
2002-09-11 14:07:21 +00:00
*
2003-04-14 02:18:10 +00:00
* @ param keystr string that represents a key of this entry
2002-09-11 14:07:21 +00:00
* @ param value text representation value being cached
* @ param timeout time when the value is expired
*
2003-04-14 02:18:10 +00:00
* @ retval true when entry is successfuly stored
* @ retval false on failure
2002-09-11 14:07:21 +00:00
* */
2009-01-19 00:01:08 +01:00
2007-10-18 17:40:25 -07:00
bool gencache_set ( const char * keystr , const char * value , time_t timeout )
2002-09-11 14:07:21 +00:00
{
int ret ;
2007-03-27 09:59:32 +00:00
TDB_DATA databuf ;
2002-09-11 14:07:21 +00:00
char * valstr = NULL ;
2009-07-13 17:04:29 +02:00
time_t last_stabilize ;
if ( tdb_data_cmp ( string_term_tdb_data ( keystr ) ,
last_stabilize_key ( ) ) = = 0 ) {
DEBUG ( 10 , ( " Can't store %s as a key \n " , keystr ) ) ;
return false ;
}
2009-01-19 00:01:08 +01:00
2009-07-10 10:54:33 +02:00
if ( ( keystr = = NULL ) | | ( value = = NULL ) ) {
return false ;
}
2002-09-11 14:07:21 +00:00
if ( ! gencache_init ( ) ) return False ;
2009-01-19 00:01:08 +01:00
2008-02-25 15:24:49 +01:00
if ( asprintf ( & valstr , CACHE_DATA_FMT , ( int ) timeout , value ) = = - 1 ) {
2003-03-22 23:32:50 +00:00
return False ;
2008-02-25 15:24:49 +01:00
}
2003-03-22 23:32:50 +00:00
2007-03-27 09:59:32 +00:00
databuf = string_term_tdb_data ( valstr ) ;
2003-09-08 01:28:48 +00:00
DEBUG ( 10 , ( " Adding cache entry with key = %s; value = %s and timeout = "
2007-03-27 09:59:32 +00:00
" %s (%d seconds %s) \n " , keystr , value , ctime ( & timeout ) ,
2003-09-08 01:28:48 +00:00
( int ) ( timeout - time ( NULL ) ) ,
timeout > time ( NULL ) ? " ahead " : " in the past " ) ) ;
2009-07-13 17:04:29 +02:00
ret = tdb_store_bystring ( cache_notrans , keystr , databuf , 0 ) ;
2002-09-11 14:07:21 +00:00
SAFE_FREE ( valstr ) ;
2009-01-19 00:01:08 +01:00
2009-07-13 17:04:29 +02:00
if ( ret ! = 0 ) {
return false ;
}
/*
* Every 5 minutes , call gencache_stabilize ( ) to not let grow
* gencache_notrans . tdb too large .
*/
last_stabilize = 0 ;
databuf = tdb_fetch ( cache_notrans , last_stabilize_key ( ) ) ;
if ( ( databuf . dptr ! = NULL )
& & ( databuf . dptr [ databuf . dsize - 1 ] = = ' \0 ' ) ) {
last_stabilize = atoi ( ( char * ) databuf . dptr ) ;
SAFE_FREE ( databuf . dptr ) ;
}
if ( ( last_stabilize
+ lp_parm_int ( - 1 , " gencache " , " stabilize_interval " , 300 ) )
< time ( NULL ) ) {
gencache_stabilize ( ) ;
}
2003-02-19 22:50:29 +00:00
return ret = = 0 ;
2002-09-11 14:07:21 +00:00
}
/**
* Delete one entry from the cache file .
*
2003-04-14 02:18:10 +00:00
* @ param keystr string that represents a key of this entry
2002-09-11 14:07:21 +00:00
*
2003-04-14 02:18:10 +00:00
* @ retval true upon successful deletion
* @ retval false in case of failure
2002-09-11 14:07:21 +00:00
* */
2007-10-18 17:40:25 -07:00
bool gencache_del ( const char * keystr )
2002-09-11 14:07:21 +00:00
{
2009-07-13 17:04:29 +02:00
bool exists ;
bool ret = false ;
char * value ;
2009-01-19 00:01:08 +01:00
2009-07-10 10:54:33 +02:00
if ( keystr = = NULL ) {
return false ;
}
2002-09-11 14:07:21 +00:00
if ( ! gencache_init ( ) ) return False ;
2009-01-19 00:01:08 +01:00
2002-09-11 14:07:21 +00:00
DEBUG ( 10 , ( " Deleting cache entry (key = %s) \n " , keystr ) ) ;
2009-01-19 00:01:08 +01:00
2009-07-13 17:04:29 +02:00
if ( tdb_lock_bystring ( cache_notrans , keystr ) = = - 1 ) {
DEBUG ( 5 , ( " Could not lock key for %s \n " , keystr ) ) ;
return false ;
}
/*
* We delete an element by setting its timeout to 0. This way we don ' t
* have to do a transaction on gencache . tdb every time we delete an
* element .
*/
exists = gencache_get ( keystr , & value , NULL ) ;
if ( exists ) {
SAFE_FREE ( value ) ;
ret = gencache_set ( keystr , " " , 0 ) ;
}
tdb_unlock_bystring ( cache_notrans , keystr ) ;
return ret ;
2002-09-11 14:07:21 +00:00
}
2009-07-13 17:04:29 +02:00
static bool gencache_pull_timeout ( char * val , time_t * pres , char * * pendptr )
{
time_t res ;
char * endptr ;
res = strtol ( val , & endptr , 10 ) ;
if ( ( endptr = = NULL ) | | ( * endptr ! = ' / ' ) ) {
DEBUG ( 2 , ( " Invalid gencache data format: %s \n " , val ) ) ;
return false ;
}
if ( pres ! = NULL ) {
* pres = res ;
}
if ( pendptr ! = NULL ) {
* pendptr = endptr ;
}
return true ;
}
2002-09-11 14:07:21 +00:00
/**
* Get existing entry from the cache file .
*
2003-04-14 02:18:10 +00:00
* @ param keystr string that represents a key of this entry
* @ param valstr buffer that is allocated and filled with the entry value
2008-07-11 17:44:15 +02:00
* buffer ' s disposing must be done outside
* @ param timeout pointer to a time_t that is filled with entry ' s
* timeout
2002-09-11 14:07:21 +00:00
*
2003-04-14 02:18:10 +00:00
* @ retval true when entry is successfuly fetched
* @ retval False for failure
2002-09-11 14:07:21 +00:00
* */
2008-07-11 17:44:15 +02:00
bool gencache_get ( const char * keystr , char * * valstr , time_t * timeout )
2002-09-11 14:07:21 +00:00
{
2007-03-27 09:59:32 +00:00
TDB_DATA databuf ;
2006-09-09 21:31:56 +00:00
time_t t ;
char * endptr ;
2002-09-11 14:07:21 +00:00
2009-07-10 10:54:33 +02:00
if ( keystr = = NULL ) {
return false ;
}
2002-09-11 14:07:21 +00:00
2009-07-13 17:04:29 +02:00
if ( tdb_data_cmp ( string_term_tdb_data ( keystr ) ,
last_stabilize_key ( ) ) = = 0 ) {
DEBUG ( 10 , ( " Can't get %s as a key \n " , keystr ) ) ;
return false ;
}
2006-06-15 21:03:40 +00:00
if ( ! gencache_init ( ) ) {
2002-11-23 02:52:36 +00:00
return False ;
2006-06-15 21:03:40 +00:00
}
2007-03-27 09:59:32 +00:00
2009-07-13 17:04:29 +02:00
databuf = tdb_fetch_bystring ( cache_notrans , keystr ) ;
2003-01-24 21:25:12 +00:00
2006-09-09 21:31:56 +00:00
if ( databuf . dptr = = NULL ) {
2009-07-13 17:04:29 +02:00
databuf = tdb_fetch_bystring ( cache , keystr ) ;
}
if ( databuf . dptr = = NULL ) {
DEBUG ( 10 , ( " Cache entry with key = %s couldn't be found \n " ,
2006-09-09 21:31:56 +00:00
keystr ) ) ;
return False ;
}
2006-06-15 21:03:40 +00:00
2009-07-13 17:04:29 +02:00
if ( ! gencache_pull_timeout ( ( char * ) databuf . dptr , & t , & endptr ) ) {
2006-09-09 21:31:56 +00:00
SAFE_FREE ( databuf . dptr ) ;
return False ;
}
2003-01-24 21:25:12 +00:00
2006-09-09 21:31:56 +00:00
DEBUG ( 10 , ( " Returning %s cache entry: key = %s, value = %s, "
" timeout = %s " , t > time ( NULL ) ? " valid " :
" expired " , keystr , endptr + 1 , ctime ( & t ) ) ) ;
2003-01-24 21:25:12 +00:00
2009-07-13 17:04:29 +02:00
if ( t = = 0 ) {
/* Deleted */
SAFE_FREE ( databuf . dptr ) ;
return False ;
}
2008-07-11 17:44:15 +02:00
if ( t < = time ( NULL ) ) {
2006-09-09 21:40:47 +00:00
2009-07-13 17:04:29 +02:00
/*
* We ' re expired , delete the entry . We can ' t use gencache_del
* here , because that uses gencache_get_data_blob for checking
* the existence of a record . We know the thing exists and
* directly store an empty value with 0 timeout .
*/
gencache_set ( keystr , " " , 0 ) ;
2006-09-09 21:40:47 +00:00
SAFE_FREE ( databuf . dptr ) ;
return False ;
}
2006-09-09 21:31:56 +00:00
if ( valstr ) {
* valstr = SMB_STRDUP ( endptr + 1 ) ;
if ( * valstr = = NULL ) {
SAFE_FREE ( databuf . dptr ) ;
DEBUG ( 0 , ( " strdup failed \n " ) ) ;
return False ;
2006-06-15 21:03:40 +00:00
}
2006-09-09 21:31:56 +00:00
}
2009-01-19 00:01:08 +01:00
2006-02-03 21:19:24 +00:00
SAFE_FREE ( databuf . dptr ) ;
2003-01-24 21:25:12 +00:00
2008-07-11 17:44:15 +02:00
if ( timeout ) {
* timeout = t ;
2006-06-15 21:03:40 +00:00
}
2003-01-24 21:25:12 +00:00
2006-09-09 21:40:47 +00:00
return True ;
2008-07-11 17:44:15 +02:00
}
2006-09-09 21:31:56 +00:00
2009-07-13 17:04:29 +02:00
struct stabilize_state {
bool written ;
bool error ;
} ;
static int stabilize_fn ( struct tdb_context * tdb , TDB_DATA key , TDB_DATA val ,
void * priv ) ;
/**
* Stabilize gencache
*
* Migrate the clear - if - first gencache data to the stable ,
* transaction - based gencache . tdb
*/
bool gencache_stabilize ( void )
{
struct stabilize_state state ;
int res ;
char * now ;
if ( ! gencache_init ( ) ) {
return false ;
}
res = tdb_transaction_start ( cache ) ;
if ( res = = - 1 ) {
DEBUG ( 10 , ( " Could not start transaction on gencache.tdb: "
" %s \n " , tdb_errorstr ( cache ) ) ) ;
return false ;
}
res = tdb_transaction_start ( cache_notrans ) ;
if ( res = = - 1 ) {
tdb_transaction_cancel ( cache ) ;
DEBUG ( 10 , ( " Could not start transaction on "
" gencache_notrans.tdb: %s \n " ,
tdb_errorstr ( cache_notrans ) ) ) ;
return false ;
}
state . error = false ;
state . written = false ;
res = tdb_traverse ( cache_notrans , stabilize_fn , & state ) ;
if ( ( res = = - 1 ) | | state . error ) {
if ( ( tdb_transaction_cancel ( cache_notrans ) = = - 1 )
| | ( tdb_transaction_cancel ( cache ) = = - 1 ) ) {
smb_panic ( " tdb_transaction_cancel failed \n " ) ;
}
return false ;
}
if ( ! state . written ) {
if ( ( tdb_transaction_cancel ( cache_notrans ) = = - 1 )
| | ( tdb_transaction_cancel ( cache ) = = - 1 ) ) {
smb_panic ( " tdb_transaction_cancel failed \n " ) ;
}
return true ;
}
res = tdb_transaction_commit ( cache ) ;
if ( res = = - 1 ) {
DEBUG ( 10 , ( " tdb_transaction_commit on gencache.tdb failed: "
" %s \n " , tdb_errorstr ( cache ) ) ) ;
if ( tdb_transaction_cancel ( cache_notrans ) = = - 1 ) {
smb_panic ( " tdb_transaction_cancel failed \n " ) ;
}
return false ;
}
res = tdb_transaction_commit ( cache_notrans ) ;
if ( res = = - 1 ) {
DEBUG ( 10 , ( " tdb_transaction_commit on gencache.tdb failed: "
" %s \n " , tdb_errorstr ( cache ) ) ) ;
return false ;
}
now = talloc_asprintf ( talloc_tos ( ) , " %d " , ( int ) time ( NULL ) ) ;
if ( now ! = NULL ) {
tdb_store ( cache_notrans , last_stabilize_key ( ) ,
string_term_tdb_data ( now ) , 0 ) ;
TALLOC_FREE ( now ) ;
}
return true ;
}
static int stabilize_fn ( struct tdb_context * tdb , TDB_DATA key , TDB_DATA val ,
void * priv )
{
struct stabilize_state * state = ( struct stabilize_state * ) priv ;
int res ;
time_t timeout ;
if ( tdb_data_cmp ( key , last_stabilize_key ( ) ) = = 0 ) {
return 0 ;
}
if ( ! gencache_pull_timeout ( ( char * ) val . dptr , & timeout , NULL ) ) {
DEBUG ( 10 , ( " Ignoring invalid entry \n " ) ) ;
return 0 ;
}
if ( ( timeout < time ( NULL ) ) | | ( val . dsize = = 0 ) ) {
res = tdb_delete ( cache , key ) ;
if ( ( res = = - 1 ) & & ( tdb_error ( cache ) = = TDB_ERR_NOEXIST ) ) {
res = 0 ;
} else {
state - > written = true ;
}
} else {
res = tdb_store ( cache , key , val , 0 ) ;
if ( res = = 0 ) {
state - > written = true ;
}
}
if ( res = = - 1 ) {
DEBUG ( 10 , ( " Transfer to gencache.tdb failed: %s \n " ,
tdb_errorstr ( cache ) ) ) ;
state - > error = true ;
return - 1 ;
}
if ( tdb_delete ( cache_notrans , key ) = = - 1 ) {
DEBUG ( 10 , ( " tdb_delete from gencache_notrans.tdb failed: "
" %s \n " , tdb_errorstr ( cache_notrans ) ) ) ;
state - > error = true ;
return - 1 ;
}
return 0 ;
}
2007-08-28 12:40:01 +00:00
/**
* Get existing entry from the cache file .
*
* @ param keystr string that represents a key of this entry
* @ param blob DATA_BLOB that is filled with entry ' s blob
2007-10-18 17:40:25 -07:00
* @ param expired pointer to a bool that indicates whether the entry is expired
2007-08-28 12:40:01 +00:00
*
* @ retval true when entry is successfuly fetched
* @ retval False for failure
* */
2007-10-18 17:40:25 -07:00
bool gencache_get_data_blob ( const char * keystr , DATA_BLOB * blob , bool * expired )
2007-08-28 12:40:01 +00:00
{
TDB_DATA databuf ;
time_t t ;
char * blob_type ;
unsigned char * buf = NULL ;
2007-10-18 17:40:25 -07:00
bool ret = False ;
2007-08-28 12:40:01 +00:00
fstring valstr ;
int buflen = 0 , len = 0 , blob_len = 0 ;
unsigned char * blob_buf = NULL ;
2009-07-10 10:54:33 +02:00
if ( keystr = = NULL ) {
return false ;
}
2007-08-28 12:40:01 +00:00
if ( ! gencache_init ( ) ) {
return False ;
}
databuf = tdb_fetch_bystring ( cache , keystr ) ;
if ( ! databuf . dptr ) {
DEBUG ( 10 , ( " Cache entry with key = %s couldn't be found \n " ,
keystr ) ) ;
return False ;
}
buf = ( unsigned char * ) databuf . dptr ;
buflen = databuf . dsize ;
len + = tdb_unpack ( buf + len , buflen - len , " fB " ,
& valstr ,
& blob_len , & blob_buf ) ;
if ( len = = - 1 ) {
goto out ;
}
t = strtol ( valstr , & blob_type , 10 ) ;
if ( strcmp ( blob_type + 1 , BLOB_TYPE ) ! = 0 ) {
goto out ;
}
DEBUG ( 10 , ( " Returning %s cache entry: key = %s, "
" timeout = %s " , t > time ( NULL ) ? " valid " :
" expired " , keystr , ctime ( & t ) ) ) ;
if ( t < = time ( NULL ) ) {
/* We're expired */
if ( expired ) {
* expired = True ;
}
}
if ( blob ) {
* blob = data_blob ( blob_buf , blob_len ) ;
if ( ! blob - > data ) {
goto out ;
}
}
ret = True ;
out :
SAFE_FREE ( blob_buf ) ;
SAFE_FREE ( databuf . dptr ) ;
return ret ;
}
/**
* Set an entry in the cache file . If there ' s no such
* one , then add it .
*
* @ param keystr string that represents a key of this entry
* @ param blob DATA_BLOB value being cached
* @ param timeout time when the value is expired
*
* @ retval true when entry is successfuly stored
* @ retval false on failure
* */
2008-05-07 21:01:46 +02:00
bool gencache_set_data_blob ( const char * keystr , const DATA_BLOB * blob , time_t timeout )
2007-08-28 12:40:01 +00:00
{
2007-10-18 17:40:25 -07:00
bool ret = False ;
2007-08-28 12:40:01 +00:00
int tdb_ret ;
TDB_DATA databuf ;
char * valstr = NULL ;
unsigned char * buf = NULL ;
int len = 0 , buflen = 0 ;
2009-07-10 10:54:33 +02:00
if ( ( keystr = = NULL ) | | ( blob = = NULL ) ) {
return false ;
}
2007-08-28 12:40:01 +00:00
if ( ! gencache_init ( ) ) {
return False ;
}
2008-02-25 15:24:49 +01:00
if ( asprintf ( & valstr , " %12u/%s " , ( int ) timeout , BLOB_TYPE ) = = - 1 ) {
2007-08-28 12:40:01 +00:00
return False ;
}
again :
len = 0 ;
len + = tdb_pack ( buf + len , buflen - len , " fB " ,
valstr ,
blob - > length , blob - > data ) ;
if ( len = = - 1 ) {
goto out ;
}
if ( buflen < len ) {
SAFE_FREE ( buf ) ;
buf = SMB_MALLOC_ARRAY ( unsigned char , len ) ;
if ( ! buf ) {
goto out ;
}
buflen = len ;
goto again ;
}
databuf = make_tdb_data ( buf , len ) ;
DEBUG ( 10 , ( " Adding cache entry with key = %s; "
" blob size = %d and timeout = %s "
" (%d seconds %s) \n " , keystr , ( int ) databuf . dsize ,
ctime ( & timeout ) , ( int ) ( timeout - time ( NULL ) ) ,
timeout > time ( NULL ) ? " ahead " : " in the past " ) ) ;
tdb_ret = tdb_store_bystring ( cache , keystr , databuf , 0 ) ;
if ( tdb_ret = = 0 ) {
ret = True ;
}
out :
SAFE_FREE ( valstr ) ;
SAFE_FREE ( buf ) ;
return ret ;
}
2002-09-11 14:07:21 +00:00
/**
* Iterate through all entries which key matches to specified pattern
*
* @ param fn pointer to the function that will be supplied with each single
* matching cache entry ( key , value and timeout ) as an arguments
2003-01-04 08:48:15 +00:00
* @ param data void pointer to an arbitrary data that is passed directly to the fn
* function on each call
2002-09-11 14:07:21 +00:00
* @ param keystr_pattern pattern the existing entries ' keys are matched to
*
* */
2009-01-19 00:01:08 +01:00
struct gencache_iterate_state {
void ( * fn ) ( const char * key , const char * value , time_t timeout ,
void * priv ) ;
const char * pattern ;
void * priv ;
2009-07-13 17:04:29 +02:00
bool in_persistent ;
2009-01-19 00:01:08 +01:00
} ;
static int gencache_iterate_fn ( struct tdb_context * tdb , TDB_DATA key ,
TDB_DATA value , void * priv )
{
struct gencache_iterate_state * state =
( struct gencache_iterate_state * ) priv ;
char * keystr ;
char * free_key = NULL ;
char * valstr ;
char * free_val = NULL ;
unsigned long u ;
time_t timeout ;
char * timeout_endp ;
2009-07-13 17:04:29 +02:00
if ( tdb_data_cmp ( key , last_stabilize_key ( ) ) = = 0 ) {
return 0 ;
}
if ( state - > in_persistent & & tdb_exists ( cache_notrans , key ) ) {
return 0 ;
}
2009-01-19 00:01:08 +01:00
if ( key . dptr [ key . dsize - 1 ] = = ' \0 ' ) {
keystr = ( char * ) key . dptr ;
} else {
/* ensure 0-termination */
keystr = SMB_STRNDUP ( ( char * ) key . dptr , key . dsize ) ;
free_key = keystr ;
}
if ( ( value . dptr = = NULL ) | | ( value . dsize < = TIMEOUT_LEN ) ) {
goto done ;
}
if ( fnmatch ( state - > pattern , keystr , 0 ) ! = 0 ) {
goto done ;
}
if ( value . dptr [ value . dsize - 1 ] = = ' \0 ' ) {
valstr = ( char * ) value . dptr ;
} else {
/* ensure 0-termination */
valstr = SMB_STRNDUP ( ( char * ) value . dptr , value . dsize ) ;
free_val = valstr ;
}
u = strtoul ( valstr , & timeout_endp , 10 ) ;
if ( ( * timeout_endp ! = ' / ' ) | | ( ( timeout_endp - valstr ) ! = TIMEOUT_LEN ) ) {
goto done ;
}
timeout = u ;
timeout_endp + = 1 ;
DEBUG ( 10 , ( " Calling function with arguments "
" (key = %s, value = %s, timeout = %s) \n " ,
keystr , timeout_endp , ctime ( & timeout ) ) ) ;
state - > fn ( keystr , timeout_endp , timeout , state - > priv ) ;
done :
SAFE_FREE ( free_key ) ;
SAFE_FREE ( free_val ) ;
return 0 ;
}
2003-01-04 08:48:15 +00:00
void gencache_iterate ( void ( * fn ) ( const char * key , const char * value , time_t timeout , void * dptr ) ,
void * data , const char * keystr_pattern )
2002-09-11 14:07:21 +00:00
{
2009-01-19 00:01:08 +01:00
struct gencache_iterate_state state ;
2002-09-11 14:07:21 +00:00
2009-07-10 10:54:33 +02:00
if ( ( fn = = NULL ) | | ( keystr_pattern = = NULL ) ) {
return ;
}
2002-09-11 14:07:21 +00:00
if ( ! gencache_init ( ) ) return ;
2003-01-04 08:48:15 +00:00
DEBUG ( 5 , ( " Searching cache keys with pattern %s \n " , keystr_pattern ) ) ;
2006-06-15 21:03:40 +00:00
2009-01-19 00:01:08 +01:00
state . fn = fn ;
state . pattern = keystr_pattern ;
state . priv = data ;
2009-07-13 17:04:29 +02:00
state . in_persistent = false ;
tdb_traverse ( cache_notrans , gencache_iterate_fn , & state ) ;
state . in_persistent = true ;
2009-01-19 00:01:08 +01:00
tdb_traverse ( cache , gencache_iterate_fn , & state ) ;
2002-09-11 14:07:21 +00:00
}