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"
2006-06-16 01:03:40 +04:00
# define READ_CACHE_DATA_FMT_TEMPLATE "%%12u / %%%us"
2002-09-11 18:07:21 +04:00
static TDB_CONTEXT * cache ;
2006-10-03 03:34:03 +04:00
static BOOL cache_readonly ;
2002-09-11 18:07:21 +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 ;
2006-10-19 19:47:19 +04:00
cache_fname = lock_path ( " gencache.tdb " ) ;
2002-09-11 18:07:21 +04:00
2006-09-10 01:05:51 +04:00
DEBUG ( 5 , ( " Opening cache file at %s \n " , cache_fname ) ) ;
2002-09-11 18:07:21 +04:00
cache = tdb_open_log ( cache_fname , 0 , TDB_DEFAULT ,
O_RDWR | O_CREAT , 0644 ) ;
2006-10-03 03:34:03 +04:00
if ( ! cache & & ( errno = = EACCES ) ) {
cache = tdb_open_log ( cache_fname , 0 , TDB_DEFAULT , O_RDONLY , 0644 ) ;
if ( cache ) {
cache_readonly = True ;
DEBUG ( 5 , ( " gencache_init: Opening cache file %s read-only. \n " , cache_fname ) ) ;
}
}
2002-09-11 18:07:21 +04:00
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 )
{
2006-01-13 21:45:30 +03:00
int ret ;
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 " ) ) ;
2006-01-13 21:45:30 +03:00
ret = tdb_close ( cache ) ;
cache = NULL ;
2006-10-03 03:34:03 +04:00
cache_readonly = False ;
2006-01-13 21:45:30 +03:00
return ret ! = - 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 ;
2007-03-27 13:59:32 +04:00
TDB_DATA databuf ;
2002-09-11 18:07:21 +04:00
char * valstr = NULL ;
/* fail completely if get null pointers passed */
SMB_ASSERT ( keystr & & value ) ;
if ( ! gencache_init ( ) ) return False ;
2006-10-03 03:34:03 +04:00
if ( cache_readonly ) {
return False ;
}
2002-09-11 18:07:21 +04:00
asprintf ( & valstr , CACHE_DATA_FMT , ( int ) timeout , value ) ;
2003-03-23 02:32:50 +03:00
if ( ! valstr )
return False ;
2007-03-27 13:59:32 +04:00
databuf = string_term_tdb_data ( valstr ) ;
2003-09-08 05:28:48 +04:00
DEBUG ( 10 , ( " Adding cache entry with key = %s; value = %s and timeout = "
2007-03-27 13:59:32 +04:00
" %s (%d seconds %s) \n " , keystr , value , ctime ( & timeout ) ,
2003-09-08 05:28:48 +04:00
( int ) ( timeout - time ( NULL ) ) ,
timeout > time ( NULL ) ? " ahead " : " in the past " ) ) ;
2007-03-27 13:59:32 +04:00
ret = tdb_store_bystring ( cache , keystr , databuf , 0 ) ;
2002-09-11 18:07:21 +04:00
SAFE_FREE ( valstr ) ;
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 ;
/* fail completely if get null pointers passed */
SMB_ASSERT ( keystr ) ;
if ( ! gencache_init ( ) ) return False ;
2006-10-03 03:34:03 +04:00
if ( cache_readonly ) {
return False ;
}
2002-09-11 18:07:21 +04:00
DEBUG ( 10 , ( " Deleting cache entry (key = %s) \n " , keystr ) ) ;
2007-03-27 13:59:32 +04:00
ret = tdb_delete_bystring ( cache , keystr ) ;
2002-09-11 18:07:21 +04:00
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 )
{
2007-03-27 13:59:32 +04:00
TDB_DATA databuf ;
2006-09-10 01:31:56 +04:00
time_t t ;
char * endptr ;
2002-09-11 18:07:21 +04:00
/* 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
2006-06-16 01:03:40 +04:00
if ( ! gencache_init ( ) ) {
2002-11-23 05:52:36 +03:00
return False ;
2006-06-16 01:03:40 +04:00
}
2007-03-27 13:59:32 +04:00
databuf = tdb_fetch_bystring ( cache , keystr ) ;
2003-01-25 00:25:12 +03:00
2006-09-10 01:31:56 +04:00
if ( databuf . dptr = = NULL ) {
DEBUG ( 10 , ( " Cache entry with key = %s couldn't be found \n " ,
keystr ) ) ;
return False ;
}
2006-06-16 01:03:40 +04:00
2007-03-29 13:35:51 +04:00
t = strtol ( ( const char * ) databuf . dptr , & endptr , 10 ) ;
2002-09-11 18:07:21 +04:00
2006-09-10 01:31:56 +04:00
if ( ( endptr = = NULL ) | | ( * endptr ! = ' / ' ) ) {
DEBUG ( 2 , ( " Invalid gencache data format: %s \n " , databuf . dptr ) ) ;
SAFE_FREE ( databuf . dptr ) ;
return False ;
}
2003-01-25 00:25:12 +03:00
2006-09-10 01:31:56 +04: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-25 00:25:12 +03:00
2006-09-10 01:40:47 +04:00
if ( t < = time ( NULL ) ) {
/* We're expired, delete the entry */
2007-03-27 13:59:32 +04:00
tdb_delete_bystring ( cache , keystr ) ;
2006-09-10 01:40:47 +04:00
SAFE_FREE ( databuf . dptr ) ;
return False ;
}
2006-09-10 01:31:56 +04:00
if ( valstr ) {
* valstr = SMB_STRDUP ( endptr + 1 ) ;
if ( * valstr = = NULL ) {
SAFE_FREE ( databuf . dptr ) ;
DEBUG ( 0 , ( " strdup failed \n " ) ) ;
return False ;
2006-06-16 01:03:40 +04:00
}
2006-09-10 01:31:56 +04:00
}
2006-02-04 00:19:24 +03:00
SAFE_FREE ( databuf . dptr ) ;
2003-01-25 00:25:12 +03:00
2006-06-16 01:03:40 +04:00
if ( timeout ) {
2006-09-10 01:31:56 +04:00
* timeout = t ;
2006-06-16 01:03:40 +04:00
}
2003-01-25 00:25:12 +03:00
2006-09-10 01:40:47 +04:00
return True ;
2006-09-10 01:31:56 +04:00
}
2002-09-11 18:07:21 +04: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 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 ;
2005-09-30 21:13:37 +04:00
int status ;
unsigned u ;
2002-09-11 18:07:21 +04:00
/* 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 ) {
2006-06-16 01:03:40 +04:00
char * fmt ;
2002-09-11 18:07:21 +04:00
/* ensure null termination of the key string */
2007-03-29 13:35:51 +04:00
keystr = SMB_STRNDUP ( ( const char * ) node - > node_key . dptr , node - > node_key . dsize ) ;
2006-06-16 01:03:40 +04:00
if ( ! keystr ) {
2006-06-16 16:30:39 +04:00
break ;
2006-06-16 01:03:40 +04:00
}
2003-07-01 16:03:00 +04:00
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 ;
}
2007-03-29 13:35:51 +04:00
entry = SMB_STRNDUP ( ( const char * ) databuf . dptr , databuf . dsize ) ;
2006-06-16 01:03:40 +04:00
if ( ! entry ) {
SAFE_FREE ( databuf . dptr ) ;
SAFE_FREE ( keystr ) ;
2006-06-16 16:30:39 +04:00
break ;
2006-06-16 01:03:40 +04:00
}
2002-11-23 05:52:36 +03:00
SAFE_FREE ( databuf . dptr ) ;
2006-06-16 01:03:40 +04:00
2006-07-31 08:30:55 +04:00
valstr = ( char * ) SMB_MALLOC ( databuf . dsize + 1 - TIMEOUT_LEN ) ;
2006-06-16 01:03:40 +04:00
if ( ! valstr ) {
SAFE_FREE ( entry ) ;
SAFE_FREE ( keystr ) ;
2006-06-16 16:30:39 +04:00
break ;
2006-06-16 01:03:40 +04:00
}
asprintf ( & fmt , READ_CACHE_DATA_FMT_TEMPLATE , ( unsigned int ) databuf . dsize - TIMEOUT_LEN ) ;
if ( ! fmt ) {
SAFE_FREE ( valstr ) ;
SAFE_FREE ( entry ) ;
SAFE_FREE ( keystr ) ;
2006-06-16 16:30:39 +04:00
break ;
2006-06-16 01:03:40 +04:00
}
status = sscanf ( entry , fmt , & u , valstr ) ;
SAFE_FREE ( fmt ) ;
2005-09-30 21:13:37 +04:00
if ( status ! = 2 ) {
2006-06-16 01:03:40 +04:00
DEBUG ( 0 , ( " gencache_iterate: invalid return from sscanf %d \n " , status ) ) ;
2005-09-30 21:13:37 +04:00
}
timeout = u ;
2002-09-11 18:07:21 +04:00
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 )
{
2004-01-05 07:15:55 +03:00
if ( ! gencache_init ( ) )
return - 1 ;
2006-04-17 15:49:06 +04:00
return tdb_lock_bystring ( cache , key ) ;
2003-07-01 07:49:41 +04:00
}
/********************************************************************
unlock a key
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
void gencache_unlock_entry ( const char * key )
{
2004-01-05 07:15:55 +03:00
if ( ! gencache_init ( ) )
return ;
2003-07-01 07:49:41 +04:00
tdb_unlock_bystring ( cache , key ) ;
return ;
}