summaryrefslogtreecommitdiffstats
path: root/source/tdb/tdb.c
diff options
context:
space:
mode:
Diffstat (limited to 'source/tdb/tdb.c')
-rw-r--r--source/tdb/tdb.c213
1 files changed, 146 insertions, 67 deletions
diff --git a/source/tdb/tdb.c b/source/tdb/tdb.c
index 5a871e7fcc6..c937090de4d 100644
--- a/source/tdb/tdb.c
+++ b/source/tdb/tdb.c
@@ -1,6 +1,5 @@
/*
- Unix SMB/Netbios implementation.
- Version 3.0
+ Unix SMB/CIFS implementation.
Samba database functions
Copyright (C) Andrew Tridgell 1999-2000
Copyright (C) Luke Kenneth Casson Leighton 2000
@@ -85,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)
@@ -166,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;
@@ -180,7 +184,11 @@ 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) {
+ do {
+ ret = fcntl(tdb->fd,lck_type,&fl);
+ } while (ret == -1 && errno == EINTR);
+
+ if (ret == -1) {
if (!probe) {
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));
@@ -223,28 +231,44 @@ 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 agorithm from gdbm */
+/* This is based on the hash algorithm from gdbm */
static u32 tdb_hash(TDB_DATA *key)
{
u32 value; /* Used to compute the hash value. */
@@ -287,7 +311,8 @@ static int tdb_oob(TDB_CONTEXT *tdb, tdb_off len, int probe)
}
/* Unmap, update size, remap */
- tdb_munmap(tdb);
+ if (tdb_munmap(tdb) == -1)
+ return TDB_ERRCODE(TDB_ERR_IO, -1);
tdb->map_size = st.st_size;
tdb_mmap(tdb);
return 0;
@@ -435,18 +460,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);
@@ -454,7 +478,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)
@@ -467,30 +492,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 );
@@ -502,7 +529,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. */
@@ -535,7 +562,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;
@@ -1078,7 +1108,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)
@@ -1121,7 +1152,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) {
@@ -1138,13 +1170,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;
@@ -1154,7 +1188,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;
}
@@ -1185,26 +1220,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;
@@ -1219,7 +1264,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)
@@ -1227,7 +1273,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;
}
@@ -1248,8 +1295,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;
}
@@ -1262,7 +1311,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;
@@ -1273,10 +1325,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;
}
@@ -1290,7 +1344,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;
}
@@ -1366,20 +1421,22 @@ 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,
ino_t ino)
{
- TDB_CONTEXT *i = NULL;
+ TDB_CONTEXT *i;
for (i = tdbs; i; i = i->next) {
if (i->device == device && i->inode == ino) {
@@ -1411,9 +1468,11 @@ TDB_CONTEXT *tdb_open_ex(const char *name, int hash_size, int tdb_flags,
int open_flags, mode_t mode,
tdb_log_func log_fn)
{
- TDB_CONTEXT *tdb = NULL;
+ 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 */
@@ -1448,12 +1507,15 @@ 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;
}
if ((tdb->fd = open(name, open_flags, mode)) == -1) {
- TDB_LOG((tdb, 0, "tdb_open_ex: could not open file %s: %s\n",
+ TDB_LOG((tdb, 5, "tdb_open_ex: could not open file %s: %s\n",
name, strerror(errno)));
goto fail; /* errno set by open(2) */
}
@@ -1488,6 +1550,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 {
@@ -1525,7 +1591,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",
@@ -1561,7 +1631,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;
@@ -1572,7 +1643,7 @@ TDB_CONTEXT *tdb_open_ex(const char *name, int hash_size, int tdb_flags,
/* close a database */
int tdb_close(TDB_CONTEXT *tdb)
{
- TDB_CONTEXT **i = NULL;
+ TDB_CONTEXT **i;
int ret = 0;
if (tdb->map_ptr) {
@@ -1682,9 +1753,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);
}
@@ -1701,14 +1773,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;
@@ -1729,7 +1808,7 @@ fail:
/* reopen all tdb's */
int tdb_reopen_all(void)
{
- TDB_CONTEXT *tdb = NULL;
+ TDB_CONTEXT *tdb;
for (tdb=tdbs; tdb; tdb = tdb->next) {
if (tdb_reopen(tdb) != 0) return -1;