summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--source3/tdb/tdb.c182
-rw-r--r--source3/tdb/tdb.h4
2 files changed, 127 insertions, 59 deletions
diff --git a/source3/tdb/tdb.c b/source3/tdb/tdb.c
index e5f1b0a19b..0a847ed690 100644
--- a/source3/tdb/tdb.c
+++ b/source3/tdb/tdb.c
@@ -84,16 +84,20 @@ TDB_DATA tdb_null;
/* all contexts, to ensure no double-opens (fcntl locks don't nest!) */
static TDB_CONTEXT *tdbs = NULL;
-static void tdb_munmap(TDB_CONTEXT *tdb)
+static int tdb_munmap(TDB_CONTEXT *tdb)
{
if (tdb->flags & TDB_INTERNAL)
- return;
+ return 0;
#ifdef HAVE_MMAP
- if (tdb->map_ptr)
- munmap(tdb->map_ptr, tdb->map_size);
+ if (tdb->map_ptr) {
+ int ret = munmap(tdb->map_ptr, tdb->map_size);
+ if (ret != 0)
+ return ret;
+ }
#endif
tdb->map_ptr = NULL;
+ return 0;
}
static void tdb_mmap(TDB_CONTEXT *tdb)
@@ -222,25 +226,41 @@ static int tdb_lock(TDB_CONTEXT *tdb, int list, int ltype)
}
/* unlock the database: returns void because it's too late for errors. */
-static void tdb_unlock(TDB_CONTEXT *tdb, int list, int ltype)
+ /* changed to return int it may be interesting to know there
+ has been an error --simo */
+static int tdb_unlock(TDB_CONTEXT *tdb, int list, int ltype)
{
+ int ret = -1;
+
if (tdb->flags & TDB_NOLOCK)
- return;
+ return 0;
/* Sanity checks */
- if (list < -1 || list >= (int)tdb->header.hash_size)
- return;
- if (tdb->locked[list+1].count==0)
- return;
+ if (list < -1 || list >= (int)tdb->header.hash_size) {
+ TDB_LOG((tdb, 0, "tdb_unlock: list %d invalid (%d)\n", list, tdb->header.hash_size));
+ return ret;
+ }
+
+ if (tdb->locked[list+1].count==0) {
+ TDB_LOG((tdb, 0, "tdb_unlock: count is 0\n"));
+ return ret;
+ }
if (tdb->locked[list+1].count == 1) {
/* Down to last nested lock: unlock underneath */
- if (!tdb->read_only && tdb->header.rwlocks)
- tdb_spinunlock(tdb, list, ltype);
- else
- tdb_brlock(tdb, FREELIST_TOP+4*list, F_UNLCK, F_SETLKW, 0);
+ if (!tdb->read_only && tdb->header.rwlocks) {
+ ret = tdb_spinunlock(tdb, list, ltype);
+ } else {
+ ret = tdb_brlock(tdb, FREELIST_TOP+4*list, F_UNLCK, F_SETLKW, 0);
+ }
+ } else {
+ ret = 0;
}
tdb->locked[list+1].count--;
+
+ if (ret)
+ TDB_LOG((tdb, 0,"tdb_unlock: An error occurred unlocking!\n"));
+ return ret;
}
/* This is based on the hash algorithm from gdbm */
@@ -434,18 +454,17 @@ static tdb_off tdb_dump_record(TDB_CONTEXT *tdb, tdb_off offset)
return rec.next;
}
-static void tdb_dump_chain(TDB_CONTEXT *tdb, int i)
+static int tdb_dump_chain(TDB_CONTEXT *tdb, int i)
{
tdb_off rec_ptr, top;
top = TDB_HASH_TOP(i);
- tdb_lock(tdb, i, F_WRLCK);
+ if (tdb_lock(tdb, i, F_WRLCK) != 0)
+ return -1;
- if (ofs_read(tdb, top, &rec_ptr) == -1) {
- tdb_unlock(tdb, i, F_WRLCK);
- return;
- }
+ if (ofs_read(tdb, top, &rec_ptr) == -1)
+ return tdb_unlock(tdb, i, F_WRLCK);
if (rec_ptr)
printf("hash=%d\n", i);
@@ -453,7 +472,8 @@ static void tdb_dump_chain(TDB_CONTEXT *tdb, int i)
while (rec_ptr) {
rec_ptr = tdb_dump_record(tdb, rec_ptr);
}
- tdb_unlock(tdb, i, F_WRLCK);
+
+ return tdb_unlock(tdb, i, F_WRLCK);
}
void tdb_dump_all(TDB_CONTEXT *tdb)
@@ -466,30 +486,32 @@ void tdb_dump_all(TDB_CONTEXT *tdb)
tdb_dump_chain(tdb, -1);
}
-void tdb_printfreelist(TDB_CONTEXT *tdb)
+int tdb_printfreelist(TDB_CONTEXT *tdb)
{
+ int ret;
long total_free = 0;
tdb_off offset, rec_ptr;
struct list_struct rec;
- tdb_lock(tdb, -1, F_WRLCK);
+ if ((ret = tdb_lock(tdb, -1, F_WRLCK)) != 0)
+ return ret;
offset = FREELIST_TOP;
/* read in the freelist top */
if (ofs_read(tdb, offset, &rec_ptr) == -1) {
- return;
+ return 0;
}
printf("freelist top=[0x%08x]\n", rec_ptr );
while (rec_ptr) {
if (tdb_read(tdb, rec_ptr, (char *)&rec, sizeof(rec), DOCONV()) == -1) {
- return;
+ return -1;
}
if (rec.magic != TDB_FREE_MAGIC) {
printf("bad magic 0x%08x in free list\n", rec.magic);
- return;
+ return -1;
}
printf("entry offset=[0x%08x], rec.rec_len = [0x%08x (%d)]\n", rec.next, rec.rec_len, rec.rec_len );
@@ -501,7 +523,7 @@ void tdb_printfreelist(TDB_CONTEXT *tdb)
printf("total rec_len = [0x%08x (%d)]\n", (int)total_free,
(int)total_free);
- tdb_unlock(tdb, -1, F_WRLCK);
+ return tdb_unlock(tdb, -1, F_WRLCK);
}
/* Remove an element from the freelist. Must have alloc lock. */
@@ -534,7 +556,10 @@ static int tdb_free(TDB_CONTEXT *tdb, tdb_off offset, struct list_struct *rec)
return -1;
/* set an initial tailer, so if we fail we don't leave a bogus record */
- update_tailer(tdb, offset, rec);
+ if (update_tailer(tdb, offset, rec) != 0) {
+ TDB_LOG((tdb, 0, "tdb_free: upfate_tailer failed!\n"));
+ goto fail;
+ }
/* Look right first (I'm an Australian, dammit) */
right = offset + sizeof(*rec) + rec->rec_len;
@@ -1077,7 +1102,8 @@ static int do_delete(TDB_CONTEXT *tdb, tdb_off rec_ptr, struct list_struct*rec)
rec->magic = TDB_DEAD_MAGIC;
return rec_write(tdb, rec_ptr, rec);
}
- write_unlock_record(tdb, rec_ptr);
+ if (write_unlock_record(tdb, rec_ptr) != 0)
+ return -1;
/* find previous record in hash chain */
if (ofs_read(tdb, TDB_HASH_TOP(rec->full_hash), &i) == -1)
@@ -1120,7 +1146,8 @@ static int tdb_next_lock(TDB_CONTEXT *tdb, struct tdb_traverse_lock *tlock,
goto fail;
} else {
/* Otherwise unlock the previous record. */
- unlock_record(tdb, tlock->off);
+ if (unlock_record(tdb, tlock->off) != 0)
+ goto fail;
}
if (want_next) {
@@ -1137,13 +1164,15 @@ static int tdb_next_lock(TDB_CONTEXT *tdb, struct tdb_traverse_lock *tlock,
goto fail;
if (!TDB_DEAD(rec)) {
/* Woohoo: we found one! */
- lock_record(tdb, tlock->off);
+ if (lock_record(tdb, tlock->off) != 0)
+ goto fail;
return tlock->off;
}
/* Try to clean dead ones from old traverses */
current = tlock->off;
tlock->off = rec->next;
- do_delete(tdb, current, rec);
+ if (do_delete(tdb, current, rec) != 0)
+ goto fail;
}
tdb_unlock(tdb, tlock->hash, F_WRLCK);
want_next = 0;
@@ -1153,7 +1182,8 @@ static int tdb_next_lock(TDB_CONTEXT *tdb, struct tdb_traverse_lock *tlock,
fail:
tlock->off = 0;
- tdb_unlock(tdb, tlock->hash, F_WRLCK);
+ if (tdb_unlock(tdb, tlock->hash, F_WRLCK) != 0)
+ TDB_LOG((tdb, 0, "tdb_next_lock: On error unlock failed!\n"));
return -1;
}
@@ -1184,26 +1214,36 @@ int tdb_traverse(TDB_CONTEXT *tdb, tdb_traverse_func fn, void *state)
key.dptr = tdb_alloc_read(tdb, tl.off + sizeof(rec),
rec.key_len + rec.data_len);
if (!key.dptr) {
- tdb_unlock(tdb, tl.hash, F_WRLCK);
- unlock_record(tdb, tl.off);
- tdb->travlocks.next = tl.next;
- return -1;
+ ret = -1;
+ if (tdb_unlock(tdb, tl.hash, F_WRLCK) != 0)
+ goto out;
+ if (unlock_record(tdb, tl.off) != 0)
+ TDB_LOG((tdb, 0, "tdb_traverse: key.dptr == NULL and unlock_record failed!\n"));
+ goto out;
}
key.dsize = rec.key_len;
dbuf.dptr = key.dptr + rec.key_len;
dbuf.dsize = rec.data_len;
/* Drop chain lock, call out */
- tdb_unlock(tdb, tl.hash, F_WRLCK);
+ if (tdb_unlock(tdb, tl.hash, F_WRLCK) != 0) {
+ ret = -1;
+ goto out;
+ }
if (fn && fn(tdb, key, dbuf, state)) {
/* They want us to terminate traversal */
- unlock_record(tdb, tl.off);
+ ret = count;
+ if (unlock_record(tdb, tl.off) != 0) {
+ TDB_LOG((tdb, 0, "tdb_traverse: unlock_record failed!\n"));;
+ ret = -1;
+ }
tdb->travlocks.next = tl.next;
SAFE_FREE(key.dptr);
return count;
}
SAFE_FREE(key.dptr);
}
+out:
tdb->travlocks.next = tl.next;
if (ret < 0)
return -1;
@@ -1218,7 +1258,8 @@ TDB_DATA tdb_firstkey(TDB_CONTEXT *tdb)
struct list_struct rec;
/* release any old lock */
- unlock_record(tdb, tdb->travlocks.off);
+ if (unlock_record(tdb, tdb->travlocks.off) != 0)
+ return tdb_null;
tdb->travlocks.off = tdb->travlocks.hash = 0;
if (tdb_next_lock(tdb, &tdb->travlocks, &rec) <= 0)
@@ -1226,7 +1267,8 @@ TDB_DATA tdb_firstkey(TDB_CONTEXT *tdb)
/* now read the key */
key.dsize = rec.key_len;
key.dptr =tdb_alloc_read(tdb,tdb->travlocks.off+sizeof(rec),key.dsize);
- tdb_unlock(tdb, BUCKET(tdb->travlocks.hash), F_WRLCK);
+ if (tdb_unlock(tdb, BUCKET(tdb->travlocks.hash), F_WRLCK) != 0)
+ TDB_LOG((tdb, 0, "tdb_firstkey: error occurred while tdb_unlocking!\n"));
return key;
}
@@ -1247,8 +1289,10 @@ TDB_DATA tdb_nextkey(TDB_CONTEXT *tdb, TDB_DATA oldkey)
rec.key_len))
|| memcmp(k, oldkey.dptr, oldkey.dsize) != 0) {
/* No, it wasn't: unlock it and start from scratch */
- unlock_record(tdb, tdb->travlocks.off);
- tdb_unlock(tdb, tdb->travlocks.hash, F_WRLCK);
+ if (unlock_record(tdb, tdb->travlocks.off) != 0)
+ return tdb_null;
+ if (tdb_unlock(tdb, tdb->travlocks.hash, F_WRLCK) != 0)
+ return tdb_null;
tdb->travlocks.off = 0;
}
@@ -1261,7 +1305,10 @@ TDB_DATA tdb_nextkey(TDB_CONTEXT *tdb, TDB_DATA oldkey)
if (!tdb->travlocks.off)
return tdb_null;
tdb->travlocks.hash = BUCKET(rec.full_hash);
- lock_record(tdb, tdb->travlocks.off);
+ if (lock_record(tdb, tdb->travlocks.off) != 0) {
+ TDB_LOG((tdb, 0, "tdb_nextkey: lock_record failed (%s)!\n", strerror(errno)));
+ return tdb_null;
+ }
}
oldhash = tdb->travlocks.hash;
@@ -1272,10 +1319,12 @@ TDB_DATA tdb_nextkey(TDB_CONTEXT *tdb, TDB_DATA oldkey)
key.dptr = tdb_alloc_read(tdb, tdb->travlocks.off+sizeof(rec),
key.dsize);
/* Unlock the chain of this new record */
- tdb_unlock(tdb, tdb->travlocks.hash, F_WRLCK);
+ if (tdb_unlock(tdb, tdb->travlocks.hash, F_WRLCK) != 0)
+ TDB_LOG((tdb, 0, "tdb_nextkey: WARNING tdb_unlock failed!\n"));
}
/* Unlock the chain of old record */
- tdb_unlock(tdb, BUCKET(oldhash), F_WRLCK);
+ if (tdb_unlock(tdb, BUCKET(oldhash), F_WRLCK) != 0)
+ TDB_LOG((tdb, 0, "tdb_nextkey: WARNING tdb_unlock failed!\n"));
return key;
}
@@ -1289,7 +1338,8 @@ int tdb_delete(TDB_CONTEXT *tdb, TDB_DATA key)
if (!(rec_ptr = tdb_find_lock(tdb, key, F_WRLCK, &rec)))
return -1;
ret = do_delete(tdb, rec_ptr, &rec);
- tdb_unlock(tdb, BUCKET(rec.full_hash), F_WRLCK);
+ if (tdb_unlock(tdb, BUCKET(rec.full_hash), F_WRLCK) != 0)
+ TDB_LOG((tdb, 0, "tdb_delete: WARNING tdb_unlock failed!\n"));
return ret;
}
@@ -1365,14 +1415,16 @@ int tdb_store(TDB_CONTEXT *tdb, TDB_DATA key, TDB_DATA dbuf, int flag)
if (rec_write(tdb, rec_ptr, &rec) == -1
|| tdb_write(tdb, rec_ptr+sizeof(rec), p, key.dsize+dbuf.dsize)==-1
|| ofs_write(tdb, TDB_HASH_TOP(hash), &rec_ptr) == -1) {
- fail:
/* Need to tdb_unallocate() here */
- ret = -1;
+ goto fail;
}
out:
SAFE_FREE(p);
tdb_unlock(tdb, BUCKET(hash), F_WRLCK);
return ret;
+fail:
+ ret = -1;
+ goto out;
}
static int tdb_already_open(dev_t device,
@@ -1447,7 +1499,10 @@ TDB_CONTEXT *tdb_open_ex(const char *name, int hash_size, int tdb_flags,
if (tdb->flags & TDB_INTERNAL) {
tdb->flags |= (TDB_NOLOCK | TDB_NOMMAP);
tdb->flags &= ~TDB_CLEAR_IF_FIRST;
- tdb_new_database(tdb, hash_size);
+ if (tdb_new_database(tdb, hash_size) != 0) {
+ TDB_LOG((tdb, 0, "tdb_open_ex: tdb_new_database failed!"));
+ goto fail;
+ }
goto internal;
}
@@ -1524,7 +1579,11 @@ TDB_CONTEXT *tdb_open_ex(const char *name, int hash_size, int tdb_flags,
tdb_mmap(tdb);
if (locked) {
if (!tdb->read_only)
- tdb_clear_spinlocks(tdb);
+ if (tdb_clear_spinlocks(tdb) != 0) {
+ TDB_LOG((tdb, 0, "tdb_open_ex: "
+ "failed to clear spinlock\n"));
+ goto fail;
+ }
if (tdb_brlock(tdb, ACTIVE_LOCK, F_UNLCK, F_SETLK, 0) == -1) {
TDB_LOG((tdb, 0, "tdb_open_ex: "
"failed to take ACTIVE_LOCK on %s: %s\n",
@@ -1560,7 +1619,8 @@ TDB_CONTEXT *tdb_open_ex(const char *name, int hash_size, int tdb_flags,
}
SAFE_FREE(tdb->name);
if (tdb->fd != -1)
- close(tdb->fd);
+ if (close(tdb->fd) != 0)
+ TDB_LOG((tdb, 5, "tdb_open_ex: failed to close tdb->fd on error!\n"));
SAFE_FREE(tdb->locked);
SAFE_FREE(tdb);
errno = save_errno;
@@ -1681,9 +1741,10 @@ int tdb_chainlock(TDB_CONTEXT *tdb, TDB_DATA key)
{
return tdb_lock(tdb, BUCKET(tdb_hash(&key)), F_WRLCK);
}
-void tdb_chainunlock(TDB_CONTEXT *tdb, TDB_DATA key)
+
+int tdb_chainunlock(TDB_CONTEXT *tdb, TDB_DATA key)
{
- tdb_unlock(tdb, BUCKET(tdb_hash(&key)), F_WRLCK);
+ return tdb_unlock(tdb, BUCKET(tdb_hash(&key)), F_WRLCK);
}
@@ -1700,14 +1761,21 @@ int tdb_reopen(TDB_CONTEXT *tdb)
{
struct stat st;
- tdb_munmap(tdb);
- close(tdb->fd);
+ if (tdb_munmap(tdb) != 0) {
+ TDB_LOG((tdb, 0, "tdb_reopen: munmap failed (%s)\n", strerror(errno)));
+ goto fail;
+ }
+ if (close(tdb->fd) != 0)
+ TDB_LOG((tdb, 0, "tdb_reopen: WARNING closing tdb->fd failed!\n"));
tdb->fd = open(tdb->name, tdb->open_flags & ~(O_CREAT|O_TRUNC), 0);
if (tdb->fd == -1) {
TDB_LOG((tdb, 0, "tdb_reopen: open failed (%s)\n", strerror(errno)));
goto fail;
}
- fstat(tdb->fd, &st);
+ if (fstat(tdb->fd, &st) != 0) {
+ TDB_LOG((tdb, 0, "tdb_reopen: fstat failed (%s)\n", strerror(errno)));
+ goto fail;
+ }
if (st.st_ino != tdb->inode || st.st_dev != tdb->device) {
TDB_LOG((tdb, 0, "tdb_reopen: file dev/inode has changed!\n"));
goto fail;
diff --git a/source3/tdb/tdb.h b/source3/tdb/tdb.h
index 523c617bdc..54cde10d95 100644
--- a/source3/tdb/tdb.h
+++ b/source3/tdb/tdb.h
@@ -126,11 +126,11 @@ void tdb_unlockall(TDB_CONTEXT *tdb);
/* Low level locking functions: use with care */
int tdb_chainlock(TDB_CONTEXT *tdb, TDB_DATA key);
-void tdb_chainunlock(TDB_CONTEXT *tdb, TDB_DATA key);
+int tdb_chainunlock(TDB_CONTEXT *tdb, TDB_DATA key);
/* Debug functions. Not used in production. */
void tdb_dump_all(TDB_CONTEXT *tdb);
-void tdb_printfreelist(TDB_CONTEXT *tdb);
+int tdb_printfreelist(TDB_CONTEXT *tdb);
extern TDB_DATA tdb_null;