summaryrefslogtreecommitdiff
path: root/source3/tdb
diff options
context:
space:
mode:
Diffstat (limited to 'source3/tdb')
-rw-r--r--source3/tdb/.cvsignore1
-rw-r--r--source3/tdb/tdb.c26
-rw-r--r--source3/tdb/tdb.h1
-rw-r--r--source3/tdb/tdbbackup.c18
-rw-r--r--source3/tdb/tdbtool.c6
-rw-r--r--source3/tdb/tdbutil.c111
6 files changed, 153 insertions, 10 deletions
diff --git a/source3/tdb/.cvsignore b/source3/tdb/.cvsignore
index 15ff2846c7..66445fe269 100644
--- a/source3/tdb/.cvsignore
+++ b/source3/tdb/.cvsignore
@@ -1,5 +1,6 @@
*.po
*.po32
+tdbbackup
tdbdump
tdbtest
tdbtool
diff --git a/source3/tdb/tdb.c b/source3/tdb/tdb.c
index 98caca82a1..ed75a55e3e 100644
--- a/source3/tdb/tdb.c
+++ b/source3/tdb/tdb.c
@@ -169,6 +169,7 @@ static int tdb_brlock(TDB_CONTEXT *tdb, tdb_off offset,
int rw_type, int lck_type, int probe)
{
struct flock fl;
+ int ret;
if (tdb->flags & TDB_NOLOCK)
return 0;
@@ -183,8 +184,12 @@ static int tdb_brlock(TDB_CONTEXT *tdb, tdb_off offset,
fl.l_len = 1;
fl.l_pid = 0;
- if (fcntl(tdb->fd,lck_type,&fl) == -1) {
- if (!probe) {
+ do {
+ ret = fcntl(tdb->fd,lck_type,&fl);
+ } while (ret == -1 && errno == EINTR);
+
+ if (ret == -1) {
+ if (!probe && lck_type != F_SETLK) {
TDB_LOG((tdb, 5,"tdb_brlock failed (fd=%d) at offset %d rw_type=%d lck_type=%d\n",
tdb->fd, offset, rw_type, lck_type));
}
@@ -407,6 +412,17 @@ static int rec_free_read(TDB_CONTEXT *tdb, tdb_off off, struct list_struct *rec)
{
if (tdb_read(tdb, off, rec, sizeof(*rec),DOCONV()) == -1)
return -1;
+
+ if (rec->magic == TDB_MAGIC) {
+ /* this happens when a app is showdown while deleting a record - we should
+ not completely fail when this happens */
+ TDB_LOG((tdb, 0,"rec_free_read non-free magic at offset=%d - fixing\n",
+ rec->magic, off));
+ rec->magic = TDB_FREE_MAGIC;
+ if (tdb_write(tdb, off, rec, sizeof(*rec)) == -1)
+ return -1;
+ }
+
if (rec->magic != TDB_FREE_MAGIC) {
TDB_LOG((tdb, 0,"rec_free_read bad magic 0x%x at offset=%d\n",
rec->magic, off));
@@ -1466,6 +1482,8 @@ TDB_CONTEXT *tdb_open_ex(const char *name, int hash_size, int tdb_flags,
TDB_CONTEXT *tdb;
struct stat st;
int rev = 0, locked;
+ unsigned char *vp;
+ u32 vertest;
if (!(tdb = calloc(1, sizeof *tdb))) {
/* Can't log this */
@@ -1543,6 +1561,10 @@ TDB_CONTEXT *tdb_open_ex(const char *name, int hash_size, int tdb_flags,
}
rev = (tdb->flags & TDB_CONVERT);
}
+ vp = (unsigned char *)&tdb->header.version;
+ vertest = (((u32)vp[0]) << 24) | (((u32)vp[1]) << 16) |
+ (((u32)vp[2]) << 8) | (u32)vp[3];
+ tdb->flags |= (vertest==TDB_VERSION) ? TDB_BIGENDIAN : 0;
if (!rev)
tdb->flags &= ~TDB_CONVERT;
else {
diff --git a/source3/tdb/tdb.h b/source3/tdb/tdb.h
index 54cde10d95..8cc908703f 100644
--- a/source3/tdb/tdb.h
+++ b/source3/tdb/tdb.h
@@ -38,6 +38,7 @@ extern "C" {
#define TDB_NOLOCK 4 /* don't do any locking */
#define TDB_NOMMAP 8 /* don't use mmap */
#define TDB_CONVERT 16 /* convert endian (internal use) */
+#define TDB_BIGENDIAN 32 /* header is big-endian (internal use) */
#define TDB_ERRCODE(code, ret) ((tdb->ecode = (code)), ret)
diff --git a/source3/tdb/tdbbackup.c b/source3/tdb/tdbbackup.c
index 48c4272d33..f59f98a90f 100644
--- a/source3/tdb/tdbbackup.c
+++ b/source3/tdb/tdbbackup.c
@@ -224,6 +224,21 @@ static int verify_tdb(const char *fname, const char *bak_name)
}
+/*
+ see if one file is newer than another
+*/
+static int file_newer(const char *fname1, const char *fname2)
+{
+ struct stat st1, st2;
+ if (stat(fname1, &st1) != 0) {
+ return 0;
+ }
+ if (stat(fname2, &st2) != 0) {
+ return 1;
+ }
+ return (st1.st_mtime > st2.st_mtime);
+}
+
static void usage(void)
{
printf("Usage: tdbbackup [options] <fname...>\n\n");
@@ -276,7 +291,8 @@ static void usage(void)
ret = 1;
}
} else {
- if (backup_tdb(fname, bak_name) != 0) {
+ if (file_newer(fname, bak_name) &&
+ backup_tdb(fname, bak_name) != 0) {
ret = 1;
}
}
diff --git a/source3/tdb/tdbtool.c b/source3/tdb/tdbtool.c
index caa2940141..ba0fb48957 100644
--- a/source3/tdb/tdbtool.c
+++ b/source3/tdb/tdbtool.c
@@ -368,8 +368,10 @@ static void first_record(TDB_CONTEXT *the_tdb, TDB_DATA *pkey)
dbuf = tdb_fetch(the_tdb, *pkey);
if (!dbuf.dptr) terror("fetch failed");
- /* printf("%s : %*.*s\n", k, (int)dbuf.dsize, (int)dbuf.dsize, dbuf.dptr); */
- print_rec(the_tdb, *pkey, dbuf, NULL);
+ else {
+ /* printf("%s : %*.*s\n", k, (int)dbuf.dsize, (int)dbuf.dsize, dbuf.dptr); */
+ print_rec(the_tdb, *pkey, dbuf, NULL);
+ }
}
static void next_record(TDB_CONTEXT *the_tdb, TDB_DATA *pkey)
diff --git a/source3/tdb/tdbutil.c b/source3/tdb/tdbutil.c
index 3e16a03047..1a3a8bb9a5 100644
--- a/source3/tdb/tdbutil.c
+++ b/source3/tdb/tdbutil.c
@@ -19,6 +19,7 @@
*/
#include "includes.h"
+#include <fnmatch.h>
/* these are little tdb utility functions that are meant to make
dealing with a tdb database a little less cumbersome in Samba */
@@ -207,6 +208,20 @@ TDB_DATA tdb_fetch_by_string(TDB_CONTEXT *tdb, char *keystr)
}
/****************************************************************************
+ Delete a buffer using a null terminated string key.
+****************************************************************************/
+
+int tdb_delete_by_string(TDB_CONTEXT *tdb, char *keystr)
+{
+ TDB_DATA key;
+
+ key.dptr = keystr;
+ key.dsize = strlen(keystr) + 1;
+
+ return tdb_delete(tdb, key);
+}
+
+/****************************************************************************
Atomic integer change. Returns old value. To create, set initial value in *oldval.
****************************************************************************/
@@ -219,15 +234,22 @@ int32 tdb_change_int32_atomic(TDB_CONTEXT *tdb, char *keystr, int32 *oldval, int
return -1;
if ((val = tdb_fetch_int32(tdb, keystr)) == -1) {
- if (tdb_error(tdb) != TDB_ERR_NOEXIST)
+ /* The lookup failed */
+ if (tdb_error(tdb) != TDB_ERR_NOEXIST) {
+ /* but not becouse it didn't exist */
goto err_out;
-
+ }
+
+ /* Start with 'old' value */
val = *oldval;
} else {
+ /* It worked, set return value (oldval) to tdb data */
*oldval = val;
- val += change_val;
}
+
+ /* Increment value for storage and return next time */
+ val += change_val;
if (tdb_store_int32(tdb, keystr, val) == -1)
goto err_out;
@@ -253,15 +275,23 @@ BOOL tdb_change_uint32_atomic(TDB_CONTEXT *tdb, char *keystr, uint32 *oldval, ui
return False;
if (!tdb_fetch_uint32(tdb, keystr, &val)) {
- if (tdb_error(tdb) != TDB_ERR_NOEXIST)
+ /* It failed */
+ if (tdb_error(tdb) != TDB_ERR_NOEXIST) {
+ /* and not becouse it didn't exist */
goto err_out;
+ }
+ /* Start with 'old' value */
val = *oldval;
} else {
+ /* it worked, set return value (oldval) to tdb data */
*oldval = val;
- val += change_val;
+
}
+
+ /* get a new value to store */
+ val += change_val;
if (!tdb_store_uint32(tdb, keystr, val))
goto err_out;
@@ -509,3 +539,74 @@ int tdb_traverse_delete_fn(TDB_CONTEXT *the_tdb, TDB_DATA key, TDB_DATA dbuf,
{
return tdb_delete(the_tdb, key);
}
+
+
+
+/**
+ * Search across the whole tdb for keys that match the given pattern
+ * return the result as a list of keys
+ *
+ * @param tdb pointer to opened tdb file context
+ * @param pattern searching pattern used by fnmatch(3) functions
+ *
+ * @return list of keys found by looking up with given pattern
+ **/
+TDB_LIST_NODE *tdb_search_keys(TDB_CONTEXT *tdb, const char* pattern)
+{
+ TDB_DATA key, next;
+ TDB_LIST_NODE *list = NULL;
+ TDB_LIST_NODE *rec = NULL;
+ TDB_LIST_NODE *tmp = NULL;
+
+ for (key = tdb_firstkey(tdb); key.dptr; key = next) {
+ /* duplicate key string to ensure null-termination */
+ char *key_str = (char*) strndup(key.dptr, key.dsize);
+ if (!key_str) {
+ DEBUG(0, ("tdb_search_keys: strndup() failed!\n"));
+ smb_panic("strndup failed!\n");
+ }
+
+ DEBUG(18, ("checking %s for match to pattern %s\n", key_str, pattern));
+
+ next = tdb_nextkey(tdb, key);
+
+ /* do the pattern checking */
+ if (fnmatch(pattern, key_str, 0) == 0) {
+ rec = (TDB_LIST_NODE*) malloc(sizeof(*rec));
+ ZERO_STRUCTP(rec);
+
+ rec->node_key = key;
+
+ DLIST_ADD_END(list, rec, tmp);
+
+ DEBUG(18, ("checking %s matched pattern %s\n", key_str, pattern));
+ } else {
+ free(key.dptr);
+ }
+
+ /* free duplicated key string */
+ free(key_str);
+ }
+
+ return list;
+
+};
+
+
+/**
+ * Free the list returned by tdb_search_keys
+ *
+ * @param node list of results found by tdb_search_keys
+ **/
+void tdb_search_list_free(TDB_LIST_NODE* node)
+{
+ TDB_LIST_NODE *next_node;
+
+ while (node) {
+ next_node = node->next;
+ SAFE_FREE(node);
+ node = next_node;
+ };
+};
+
+