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
+ the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
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 02139, USA.
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "includes.h"
#define TIMEOUT_LEN 12
#define CACHE_DATA_FMT "%12u/%s"
+#define READ_CACHE_DATA_FMT_TEMPLATE "%%12u/%%%us"
static TDB_CONTEXT *cache;
+static BOOL cache_readonly;
/**
* @file gencache.c
/* 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_fname = lock_path("gencache.tdb");
+
+ DEBUG(5, ("Opening cache file at %s\n", cache_fname));
cache = tdb_open_log(cache_fname, 0, TDB_DEFAULT,
O_RDWR|O_CREAT, 0644);
- SAFE_FREE(cache_fname);
+ 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));
+ }
+ }
+
if (!cache) {
DEBUG(5, ("Attempt to open gencache.tdb has failed.\n"));
return False;
BOOL gencache_shutdown(void)
{
+ int ret;
/* tdb_close routine returns -1 on error */
if (!cache) return False;
DEBUG(5, ("Closing cache file\n"));
- return tdb_close(cache) != -1;
+ ret = tdb_close(cache);
+ cache = NULL;
+ cache_readonly = False;
+ return ret != -1;
}
BOOL gencache_set(const char *keystr, const char *value, time_t timeout)
{
int ret;
- TDB_DATA keybuf, databuf;
+ TDB_DATA databuf;
char* valstr = NULL;
/* fail completely if get null pointers passed */
if (!gencache_init()) return False;
+ if (cache_readonly) {
+ 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"));
-
- ret = tdb_store(cache, keybuf, databuf, 0);
- 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"));
+ databuf = string_term_tdb_data(valstr);
+ DEBUG(10, ("Adding cache entry with key = %s; value = %s and timeout ="
+ " %s (%d seconds %s)\n", keystr, value,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);
+ ret = tdb_store_bystring(cache, keystr, databuf, 0);
+ SAFE_FREE(valstr);
return ret == 0;
}
-
/**
* Delete one entry from the cache file.
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;
+ if (cache_readonly) {
+ return False;
+ }
+
DEBUG(10, ("Deleting cache entry (key = %s)\n", keystr));
- ret = tdb_delete(cache, keybuf);
+ ret = tdb_delete_bystring(cache, keystr);
- SAFE_FREE(keybuf.dptr);
return ret == 0;
}
BOOL gencache_get(const char *keystr, char **valstr, time_t *timeout)
{
- TDB_DATA keybuf, databuf;
+ TDB_DATA databuf;
+ time_t t;
+ char *endptr;
/* fail completely if get null pointers passed */
SMB_ASSERT(keystr);
- if (!gencache_init())
+ if (!gencache_init()) {
return False;
-
- keybuf.dptr = strdup(keystr);
- keybuf.dsize = strlen(keystr)+1;
- databuf = tdb_fetch(cache, keybuf);
- SAFE_FREE(keybuf.dptr);
-
- if (databuf.dptr && databuf.dsize > TIMEOUT_LEN) {
- char* entry_buf = strndup(databuf.dptr, databuf.dsize);
- char *v;
- time_t t;
-
- v = (char*)malloc(sizeof(char) *
- (databuf.dsize - TIMEOUT_LEN));
-
- SAFE_FREE(databuf.dptr);
- sscanf(entry_buf, CACHE_DATA_FMT, (int*)&t, v);
- SAFE_FREE(entry_buf);
-
- 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);
+ databuf = tdb_fetch_bystring(cache, keystr);
- if (timeout)
- *timeout = t;
+ if (databuf.dptr == NULL) {
+ DEBUG(10, ("Cache entry with key = %s couldn't be found\n",
+ keystr));
+ return False;
+ }
- return t > time(NULL);
+ t = strtol((const char *)databuf.dptr, &endptr, 10);
- } else {
+ if ((endptr == NULL) || (*endptr != '/')) {
+ DEBUG(2, ("Invalid gencache data format: %s\n", databuf.dptr));
SAFE_FREE(databuf.dptr);
+ return False;
+ }
- if (valstr)
- *valstr = NULL;
+ DEBUG(10, ("Returning %s cache entry: key = %s, value = %s, "
+ "timeout = %s", t > time(NULL) ? "valid" :
+ "expired", keystr, endptr+1, ctime(&t)));
- if (timeout)
- timeout = NULL;
+ if (t <= time(NULL)) {
- DEBUG(10, ("Cache entry with key = %s couldn't be found\n",
- keystr));
+ /* We're expired, delete the entry */
+ tdb_delete_bystring(cache, keystr);
+ SAFE_FREE(databuf.dptr);
return False;
}
-}
+
+ if (valstr) {
+ *valstr = SMB_STRDUP(endptr+1);
+ if (*valstr == NULL) {
+ SAFE_FREE(databuf.dptr);
+ DEBUG(0, ("strdup failed\n"));
+ return False;
+ }
+ }
+
+ SAFE_FREE(databuf.dptr);
+
+ if (timeout) {
+ *timeout = t;
+ }
+
+ return True;
+}
/**
TDB_DATA databuf;
char *keystr = NULL, *valstr = NULL, *entry = NULL;
time_t timeout = 0;
+ int status;
+ unsigned u;
/* fail completely if get null pointers passed */
SMB_ASSERT(fn && keystr_pattern);
first_node = node;
while (node) {
- /* ensure null termination of the key string */
- node->node_key.dptr[node->node_key.dsize] = '\0';
- keystr = node->node_key.dptr;
+ char *fmt;
+ /* ensure null termination of the key string */
+ keystr = SMB_STRNDUP((const char *)node->node_key.dptr, node->node_key.dsize);
+ if (!keystr) {
+ break;
+ }
+
/*
* 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);
if (!databuf.dptr || databuf.dsize <= TIMEOUT_LEN) {
SAFE_FREE(databuf.dptr);
+ SAFE_FREE(keystr);
+ node = node->next;
continue;
}
- entry = strndup(databuf.dptr, databuf.dsize);
+ entry = SMB_STRNDUP((const char *)databuf.dptr, databuf.dsize);
+ if (!entry) {
+ SAFE_FREE(databuf.dptr);
+ SAFE_FREE(keystr);
+ break;
+ }
+
SAFE_FREE(databuf.dptr);
- valstr = (char*)malloc(sizeof(char) * (databuf.dsize - TIMEOUT_LEN));
- sscanf(entry, CACHE_DATA_FMT, (int*)(&timeout), valstr);
+
+ valstr = (char *)SMB_MALLOC(databuf.dsize + 1 - TIMEOUT_LEN);
+ if (!valstr) {
+ SAFE_FREE(entry);
+ SAFE_FREE(keystr);
+ break;
+ }
+
+ asprintf(&fmt, READ_CACHE_DATA_FMT_TEMPLATE, (unsigned int)databuf.dsize - TIMEOUT_LEN);
+ if (!fmt) {
+ SAFE_FREE(valstr);
+ SAFE_FREE(entry);
+ SAFE_FREE(keystr);
+ break;
+ }
+ status = sscanf(entry, fmt, &u, valstr);
+ SAFE_FREE(fmt);
+
+ if ( status != 2 ) {
+ DEBUG(0,("gencache_iterate: invalid return from sscanf %d\n",status));
+ }
+ timeout = u;
DEBUG(10, ("Calling function with arguments (key = %s, value = %s, timeout = %s)\n",
keystr, valstr, ctime(&timeout)));
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 )
+{
+ if (!gencache_init())
+ return -1;
+
+ return tdb_lock_bystring(cache, key);
+}
+
+/********************************************************************
+ unlock a key
+********************************************************************/
+
+void gencache_unlock_entry( const char *key )
+{
+ if (!gencache_init())
+ return;
+
+ tdb_unlock_bystring(cache, key);
+ return;
+}