2002-09-11 18:07:21 +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"
# undef DBGC_CLASS
# define DBGC_CLASS DBGC_TDB
# define TIMEOUT_LEN 12
# define CACHE_DATA_FMT "%12u / %s"
static TDB_CONTEXT * cache ;
/**
* @ 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 ;
}
cache = tdb_open_log ( cache_fname , 0 , TDB_DEFAULT ,
O_RDWR | O_CREAT , 0644 ) ;
SAFE_FREE ( cache_fname ) ;
if ( ! cache ) {
2003-02-12 04:20:56 +03:00
DEBUG ( 5 , ( " Attempt to open gencache.tdb has failed. \n " ) ) ;
2002-09-11 18:07:21 +04:00
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 )
{
2003-02-20 01:50:29 +03:00
/* tdb_close routine returns -1 on error */
2002-09-11 18:07:21 +04:00
if ( ! cache ) return False ;
DEBUG ( 5 , ( " Closing cache file \n " ) ) ;
2003-02-20 01:50:29 +03:00
return tdb_close ( cache ) ! = - 1 ;
2002-09-11 18:07:21 +04:00
}
/**
2003-01-04 11:48:15 +03:00
* Set an entry in the cache file . If there ' s no such
* one , then add it .
2002-09-11 18:07:21 +04:00
*
2003-04-14 06:18:10 +04:00
* @ param keystr string that represents a key of this entry
2002-09-11 18:07:21 +04:00
* @ param value text representation value being cached
* @ param timeout time when the value is expired
*
2003-04-14 06:18:10 +04:00
* @ retval true when entry is successfuly stored
* @ retval false on failure
2002-09-11 18:07:21 +04:00
* */
2003-01-04 11:48:15 +03:00
BOOL gencache_set ( const char * keystr , const char * value , time_t timeout )
2002-09-11 18:07:21 +04:00
{
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 ) ;
2003-03-23 02:32:50 +03:00
if ( ! valstr )
return False ;
2002-09-11 18:07:21 +04:00
keybuf . dptr = strdup ( keystr ) ;
2003-03-22 16:47:42 +03:00
keybuf . dsize = strlen ( keystr ) + 1 ;
2002-09-11 18:07:21 +04:00
databuf . dptr = strdup ( valstr ) ;
2003-03-22 16:47:42 +03:00
databuf . dsize = strlen ( valstr ) + 1 ;
2003-09-08 05:28:48 +04:00
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 " ) ) ;
2003-01-04 11:48:15 +03:00
ret = tdb_store ( cache , keybuf , databuf , 0 ) ;
2002-09-11 18:07:21 +04:00
SAFE_FREE ( valstr ) ;
SAFE_FREE ( keybuf . dptr ) ;
SAFE_FREE ( databuf . dptr ) ;
2003-02-20 01:50:29 +03:00
return ret = = 0 ;
2002-09-11 18:07:21 +04:00
}
/**
* Set existing entry to the cache file .
*
2003-04-14 06:18:10 +04:00
* @ param keystr string that represents a key of this entry
* @ param valstr text representation value being cached
2002-09-11 18:07:21 +04:00
* @ param timeout time when the value is expired
*
2003-04-14 06:18:10 +04:00
* @ retval true when entry is successfuly set
* @ retval false on failure
2002-09-11 18:07:21 +04:00
* */
2003-01-04 11:48:15 +03:00
BOOL gencache_set_only ( const char * keystr , const char * valstr , time_t timeout )
2002-09-11 18:07:21 +04:00
{
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 ) ;
2003-03-22 16:47:42 +03:00
keybuf . dsize = strlen ( keystr ) + 1 ;
2002-09-11 18:07:21 +04:00
databuf . dptr = strdup ( datastr ) ;
2003-03-22 16:47:42 +03:00
databuf . dsize = strlen ( datastr ) + 1 ;
2002-09-11 18:07:21 +04:00
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 " ) ) ;
ret = tdb_store ( cache , keybuf , databuf , TDB_REPLACE ) ;
SAFE_FREE ( datastr ) ;
SAFE_FREE ( old_valstr ) ;
SAFE_FREE ( keybuf . dptr ) ;
SAFE_FREE ( databuf . dptr ) ;
2003-02-20 01:50:29 +03:00
return ret = = 0 ;
2002-09-11 18:07:21 +04:00
}
/**
* Delete one entry from the cache file .
*
2003-04-14 06:18:10 +04:00
* @ param keystr string that represents a key of this entry
2002-09-11 18:07:21 +04:00
*
2003-04-14 06:18:10 +04:00
* @ retval true upon successful deletion
* @ retval false in case of failure
2002-09-11 18:07:21 +04:00
* */
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 ) ;
2003-03-22 16:47:42 +03:00
keybuf . dsize = strlen ( keystr ) + 1 ;
2002-09-11 18:07:21 +04:00
DEBUG ( 10 , ( " Deleting cache entry (key = %s) \n " , keystr ) ) ;
ret = tdb_delete ( cache , keybuf ) ;
SAFE_FREE ( keybuf . dptr ) ;
2003-02-20 01:50:29 +03:00
return ret = = 0 ;
2002-09-11 18:07:21 +04:00
}
/**
* Get existing entry from the cache file .
*
2003-04-14 06:18:10 +04:00
* @ param keystr string that represents a key of this entry
* @ param valstr buffer that is allocated and filled with the entry value
2003-01-04 11:48:15 +03:00
* buffer ' s disposing must be done outside
2002-09-11 18:07:21 +04:00
* @ param timeout pointer to a time_t that is filled with entry ' s
* timeout
*
2003-04-14 06:18:10 +04:00
* @ retval true when entry is successfuly fetched
* @ retval False for failure
2002-09-11 18:07:21 +04:00
* */
BOOL gencache_get ( const char * keystr , char * * valstr , time_t * timeout )
{
TDB_DATA keybuf , databuf ;
/* fail completely if get null pointers passed */
2003-01-25 00:25:12 +03:00
SMB_ASSERT ( keystr ) ;
2002-09-11 18:07:21 +04:00
2002-11-23 05:52:36 +03:00
if ( ! gencache_init ( ) )
return False ;
2002-09-11 18:07:21 +04:00
keybuf . dptr = strdup ( keystr ) ;
2003-03-22 16:47:42 +03:00
keybuf . dsize = strlen ( keystr ) + 1 ;
2002-09-11 18:07:21 +04:00
databuf = tdb_fetch ( cache , keybuf ) ;
2003-03-23 02:32:50 +03:00
SAFE_FREE ( keybuf . dptr ) ;
2002-09-11 18:07:21 +04:00
2002-11-23 05:52:36 +03:00
if ( databuf . dptr & & databuf . dsize > TIMEOUT_LEN ) {
2002-09-11 18:07:21 +04:00
char * entry_buf = strndup ( databuf . dptr , databuf . dsize ) ;
2003-01-25 00:25:12 +03:00
char * v ;
time_t t ;
v = ( char * ) malloc ( sizeof ( char ) *
( databuf . dsize - TIMEOUT_LEN ) ) ;
2002-09-11 18:07:21 +04:00
2002-11-23 05:52:36 +03:00
SAFE_FREE ( databuf . dptr ) ;
2003-01-25 00:25:12 +03:00
sscanf ( entry_buf , CACHE_DATA_FMT , ( int * ) & t , v ) ;
2002-09-11 18:07:21 +04:00
SAFE_FREE ( entry_buf ) ;
2003-01-25 00:25:12 +03: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 ) ;
2002-09-11 18:07:21 +04:00
} else {
2002-11-23 05:52:36 +03:00
SAFE_FREE ( databuf . dptr ) ;
2003-01-25 00:25:12 +03:00
if ( valstr )
* valstr = NULL ;
if ( timeout )
timeout = NULL ;
DEBUG ( 10 , ( " Cache entry with key = %s couldn't be found \n " ,
keystr ) ) ;
2002-09-11 18:07:21 +04:00
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
2003-01-04 11:48:15 +03:00
* @ param data void pointer to an arbitrary data that is passed directly to the fn
* function on each call
2002-09-11 18:07:21 +04:00
* @ param keystr_pattern pattern the existing entries ' keys are matched to
*
* */
2003-01-04 11:48:15 +03: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 18:07:21 +04:00
{
TDB_LIST_NODE * node , * first_node ;
TDB_DATA databuf ;
char * keystr = NULL , * valstr = NULL , * entry = NULL ;
time_t timeout = 0 ;
/* fail completely if get null pointers passed */
SMB_ASSERT ( fn & & keystr_pattern ) ;
if ( ! gencache_init ( ) ) return ;
2003-01-04 11:48:15 +03:00
DEBUG ( 5 , ( " Searching cache keys with pattern %s \n " , keystr_pattern ) ) ;
2002-09-11 18:07:21 +04:00
node = tdb_search_keys ( cache , keystr_pattern ) ;
first_node = node ;
while ( node ) {
/* ensure null termination of the key string */
2003-07-01 16:03:00 +04:00
keystr = strndup ( node - > node_key . dptr , node - > node_key . dsize ) ;
2002-09-11 18:07:21 +04:00
/*
* We don ' t use gencache_get function , because we need to iterate through
* all of the entries . Validity verification is up to fn routine .
*/
databuf = tdb_fetch ( cache , node - > node_key ) ;
2002-11-23 05:52:36 +03:00
if ( ! databuf . dptr | | databuf . dsize < = TIMEOUT_LEN ) {
SAFE_FREE ( databuf . dptr ) ;
2003-07-01 16:03:00 +04:00
SAFE_FREE ( keystr ) ;
node = node - > next ;
2002-11-23 05:52:36 +03:00
continue ;
}
2002-09-11 18:07:21 +04:00
entry = strndup ( databuf . dptr , databuf . dsize ) ;
2002-11-23 05:52:36 +03:00
SAFE_FREE ( databuf . dptr ) ;
2002-09-11 18:07:21 +04:00
valstr = ( char * ) malloc ( sizeof ( char ) * ( databuf . dsize - TIMEOUT_LEN ) ) ;
sscanf ( entry , CACHE_DATA_FMT , ( int * ) ( & timeout ) , valstr ) ;
DEBUG ( 10 , ( " Calling function with arguments (key = %s, value = %s, timeout = %s) \n " ,
keystr , valstr , ctime ( & timeout ) ) ) ;
2003-01-04 11:48:15 +03:00
fn ( keystr , valstr , timeout , data ) ;
2002-09-11 18:07:21 +04:00
SAFE_FREE ( valstr ) ;
SAFE_FREE ( entry ) ;
2003-07-01 16:03:00 +04:00
SAFE_FREE ( keystr ) ;
2002-09-11 18:07:21 +04:00
node = node - > next ;
}
tdb_search_list_free ( first_node ) ;
}
2003-07-01 07:49:41 +04:00
/********************************************************************
lock a key
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
int gencache_lock_entry ( const char * key )
{
return tdb_lock_bystring ( cache , key , 0 ) ;
}
/********************************************************************
unlock a key
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
void gencache_unlock_entry ( const char * key )
{
tdb_unlock_bystring ( cache , key ) ;
return ;
}