2003-08-13 05:53:07 +04: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
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 2 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 , write to the Free Software
Foundation , Inc . , 675 Mass Ave , Cambridge , MA 0213 9 , USA .
*/
# include "includes.h"
2004-11-02 03:24:21 +03:00
# include "system/time.h"
2003-08-13 05:53:07 +04:00
# undef DBGC_CLASS
# define DBGC_CLASS DBGC_TDB
# define TIMEOUT_LEN 12
# define CACHE_DATA_FMT "%12u / %s"
2004-10-16 17:47:00 +04:00
static struct tdb_wrap * cache ;
2003-08-13 05:53:07 +04: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
* */
BOOL gencache_init ( void )
{
char * cache_fname = NULL ;
/* skip file open if it's already opened */
if ( cache ) return True ;
asprintf ( & cache_fname , " %s/%s " , lp_lockdir ( ) , " gencache.tdb " ) ;
if ( cache_fname )
DEBUG ( 5 , ( " Opening cache file at %s \n " , cache_fname ) ) ;
else {
DEBUG ( 0 , ( " Filename allocation failed. \n " ) ) ;
return False ;
}
2004-10-16 17:47:00 +04:00
cache = tdb_wrap_open ( NULL , cache_fname , 0 , TDB_DEFAULT ,
O_RDWR | O_CREAT , 0644 ) ;
2003-08-13 05:53:07 +04:00
SAFE_FREE ( cache_fname ) ;
if ( ! cache ) {
DEBUG ( 5 , ( " Attempt to open gencache.tdb has failed. \n " ) ) ;
return False ;
}
return True ;
}
/**
* Cache shutdown function . Closes opened cache tdb file .
*
* @ return true on successful closing the cache or
* false on failure during cache shutdown
* */
BOOL gencache_shutdown ( void )
{
if ( ! cache ) return False ;
DEBUG ( 5 , ( " Closing cache file \n " ) ) ;
2004-10-16 17:47:00 +04:00
talloc_free ( cache ) ;
return True ;
2003-08-13 05:53:07 +04:00
}
/**
* 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 value text representation value being cached
* @ param timeout time when the value is expired
*
* @ retval true when entry is successfuly stored
* @ retval false on failure
* */
BOOL gencache_set ( const char * keystr , const char * value , time_t timeout )
{
int ret ;
TDB_DATA keybuf , databuf ;
char * valstr = NULL ;
/* fail completely if get null pointers passed */
SMB_ASSERT ( keystr & & value ) ;
if ( ! gencache_init ( ) ) return False ;
asprintf ( & valstr , CACHE_DATA_FMT , ( int ) timeout , value ) ;
if ( ! valstr )
return False ;
keybuf . dptr = strdup ( keystr ) ;
keybuf . dsize = strlen ( keystr ) + 1 ;
databuf . dptr = strdup ( valstr ) ;
databuf . dsize = strlen ( valstr ) + 1 ;
DEBUG ( 10 , ( " Adding cache entry with key = %s; value = %s and timeout \
= % s ( % d seconds % s ) \ n " , keybuf.dptr, value, ctime(&timeout),
( int ) ( timeout - time ( NULL ) ) , timeout > time ( NULL ) ? " ahead " : " in the past " ) ) ;
2004-10-16 17:47:00 +04:00
ret = tdb_store ( cache - > tdb , keybuf , databuf , 0 ) ;
2003-08-13 05:53:07 +04:00
SAFE_FREE ( valstr ) ;
SAFE_FREE ( keybuf . dptr ) ;
SAFE_FREE ( databuf . dptr ) ;
return ret = = 0 ;
}
/**
* Set existing entry to the cache file .
*
* @ param keystr string that represents a key of this entry
* @ param valstr text representation value being cached
* @ param timeout time when the value is expired
*
* @ retval true when entry is successfuly set
* @ retval false on failure
* */
BOOL gencache_set_only ( const char * keystr , const char * valstr , time_t timeout )
{
int ret = - 1 ;
TDB_DATA keybuf , databuf ;
char * old_valstr , * datastr ;
time_t old_timeout ;
/* fail completely if get null pointers passed */
SMB_ASSERT ( keystr & & valstr ) ;
if ( ! gencache_init ( ) ) return False ;
/*
* Check whether entry exists in the cache
* Don ' t verify gencache_get exit code , since the entry may be expired
*/
gencache_get ( keystr , & old_valstr , & old_timeout ) ;
if ( ! ( old_valstr & & old_timeout ) ) return False ;
DEBUG ( 10 , ( " Setting cache entry with key = %s; old value = %s and old timeout \
= % s \ n " , keystr, old_valstr, ctime(&old_timeout)));
asprintf ( & datastr , CACHE_DATA_FMT , ( int ) timeout , valstr ) ;
keybuf . dptr = strdup ( keystr ) ;
keybuf . dsize = strlen ( keystr ) + 1 ;
databuf . dptr = strdup ( datastr ) ;
databuf . dsize = strlen ( datastr ) + 1 ;
DEBUGADD ( 10 , ( " New value = %s, new timeout = %s (%d seconds %s) " , valstr ,
ctime ( & timeout ) , ( int ) ( timeout - time ( NULL ) ) ,
timeout > time ( NULL ) ? " ahead " : " in the past " ) ) ;
2004-10-16 17:47:00 +04:00
ret = tdb_store ( cache - > tdb , keybuf , databuf , TDB_REPLACE ) ;
2003-08-13 05:53:07 +04:00
SAFE_FREE ( datastr ) ;
SAFE_FREE ( old_valstr ) ;
SAFE_FREE ( keybuf . dptr ) ;
SAFE_FREE ( databuf . dptr ) ;
return ret = = 0 ;
}
/**
* Delete one entry from the cache file .
*
* @ param keystr string that represents a key of this entry
*
* @ retval true upon successful deletion
* @ retval false in case of failure
* */
BOOL gencache_del ( const char * keystr )
{
int ret ;
TDB_DATA keybuf ;
/* fail completely if get null pointers passed */
SMB_ASSERT ( keystr ) ;
if ( ! gencache_init ( ) ) return False ;
keybuf . dptr = strdup ( keystr ) ;
keybuf . dsize = strlen ( keystr ) + 1 ;
DEBUG ( 10 , ( " Deleting cache entry (key = %s) \n " , keystr ) ) ;
2004-10-16 17:47:00 +04:00
ret = tdb_delete ( cache - > tdb , keybuf ) ;
2003-08-13 05:53:07 +04:00
SAFE_FREE ( keybuf . dptr ) ;
return ret = = 0 ;
}
/**
* Get existing entry from the cache file .
*
* @ param keystr string that represents a key of this entry
* @ param valstr buffer that is allocated and filled with the entry value
* buffer ' s disposing must be done outside
* @ param timeout pointer to a time_t that is filled with entry ' s
* timeout
*
* @ retval true when entry is successfuly fetched
* @ retval False for failure
* */
BOOL gencache_get ( const char * keystr , char * * valstr , time_t * timeout )
{
TDB_DATA keybuf , databuf ;
/* fail completely if get null pointers passed */
SMB_ASSERT ( keystr ) ;
if ( ! gencache_init ( ) )
return False ;
keybuf . dptr = strdup ( keystr ) ;
keybuf . dsize = strlen ( keystr ) + 1 ;
2004-10-16 17:47:00 +04:00
databuf = tdb_fetch ( cache - > tdb , keybuf ) ;
2003-08-13 05:53:07 +04:00
SAFE_FREE ( keybuf . dptr ) ;
if ( databuf . dptr & & databuf . dsize > TIMEOUT_LEN ) {
char * entry_buf = strndup ( databuf . dptr , databuf . dsize ) ;
char * v ;
time_t t ;
2004-08-21 22:15:07 +04:00
unsigned i ;
2003-08-13 05:53:07 +04:00
2004-12-03 10:20:30 +03:00
v = malloc_array_p ( char , databuf . dsize - TIMEOUT_LEN ) ;
2003-08-13 05:53:07 +04:00
SAFE_FREE ( databuf . dptr ) ;
2004-08-21 22:15:07 +04:00
sscanf ( entry_buf , CACHE_DATA_FMT , ( int * ) & i , v ) ;
2003-08-13 05:53:07 +04:00
SAFE_FREE ( entry_buf ) ;
2004-08-21 22:15:07 +04:00
t = i ;
2003-08-13 05:53:07 +04:00
DEBUG ( 10 , ( " Returning %s cache entry: key = %s, value = %s, "
" timeout = %s \n " , t > time ( NULL ) ? " valid " :
" expired " , keystr , v , ctime ( & t ) ) ) ;
if ( valstr )
* valstr = v ;
else
SAFE_FREE ( v ) ;
if ( timeout )
* timeout = t ;
return t > time ( NULL ) ;
} else {
SAFE_FREE ( databuf . dptr ) ;
if ( valstr )
* valstr = NULL ;
if ( timeout )
timeout = NULL ;
DEBUG ( 10 , ( " Cache entry with key = %s couldn't be found \n " ,
keystr ) ) ;
return False ;
}
}
/**
* 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
* @ param data void pointer to an arbitrary data that is passed directly to the fn
* function on each call
* @ param keystr_pattern pattern the existing entries ' keys are matched to
*
* */
void gencache_iterate ( void ( * fn ) ( const char * key , const char * value , time_t timeout , void * dptr ) ,
void * data , const char * keystr_pattern )
{
TDB_LIST_NODE * node , * first_node ;
TDB_DATA databuf ;
char * keystr = NULL , * valstr = NULL , * entry = NULL ;
time_t timeout = 0 ;
2004-08-21 22:15:07 +04:00
unsigned i ;
2003-08-13 05:53:07 +04:00
/* fail completely if get null pointers passed */
SMB_ASSERT ( fn & & keystr_pattern ) ;
if ( ! gencache_init ( ) ) return ;
DEBUG ( 5 , ( " Searching cache keys with pattern %s \n " , keystr_pattern ) ) ;
2004-10-16 17:47:00 +04:00
node = tdb_search_keys ( cache - > tdb , keystr_pattern ) ;
2003-08-13 05:53:07 +04:00
first_node = node ;
while ( node ) {
/* ensure null termination of the key string */
keystr = strndup ( node - > node_key . dptr , node - > node_key . dsize ) ;
/*
* We don ' t use gencache_get function , because we need to iterate through
* all of the entries . Validity verification is up to fn routine .
*/
2004-10-16 17:47:00 +04:00
databuf = tdb_fetch ( cache - > tdb , node - > node_key ) ;
2003-08-13 05:53:07 +04:00
if ( ! databuf . dptr | | databuf . dsize < = TIMEOUT_LEN ) {
SAFE_FREE ( databuf . dptr ) ;
SAFE_FREE ( keystr ) ;
node = node - > next ;
continue ;
}
entry = strndup ( databuf . dptr , databuf . dsize ) ;
SAFE_FREE ( databuf . dptr ) ;
2004-12-03 10:20:30 +03:00
valstr = malloc_array_p ( char , databuf . dsize - TIMEOUT_LEN ) ;
2004-08-21 22:15:07 +04:00
sscanf ( entry , CACHE_DATA_FMT , ( int * ) ( & i ) , valstr ) ;
timeout = i ;
2003-08-13 05:53:07 +04:00
DEBUG ( 10 , ( " Calling function with arguments (key = %s, value = %s, timeout = %s) \n " ,
keystr , valstr , ctime ( & timeout ) ) ) ;
fn ( keystr , valstr , timeout , data ) ;
SAFE_FREE ( valstr ) ;
SAFE_FREE ( entry ) ;
SAFE_FREE ( keystr ) ;
node = node - > next ;
}
tdb_search_list_free ( first_node ) ;
}
/********************************************************************
lock a key
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
int gencache_lock_entry ( const char * key )
{
2004-10-16 17:47:00 +04:00
return tdb_lock_bystring ( cache - > tdb , key , 0 ) ;
2003-08-13 05:53:07 +04:00
}
/********************************************************************
unlock a key
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
void gencache_unlock_entry ( const char * key )
{
2004-10-16 17:47:00 +04:00
tdb_unlock_bystring ( cache - > tdb , key ) ;
2003-08-13 05:53:07 +04:00
}