summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--source3/tdb/tdb.c54
-rw-r--r--source3/tdb/tdb.h14
2 files changed, 55 insertions, 13 deletions
diff --git a/source3/tdb/tdb.c b/source3/tdb/tdb.c
index 69e36ebd3e..85429d6546 100644
--- a/source3/tdb/tdb.c
+++ b/source3/tdb/tdb.c
@@ -1,4 +1,4 @@
-/*
+ /*
Unix SMB/Netbios implementation.
Version 3.0
Samba database functions
@@ -149,7 +149,10 @@ struct list_struct {
};
/* a byte range locking function - return 0 on success
- this functions locks/unlocks 1 byte at the specified offset */
+ this functions locks/unlocks 1 byte at the specified offset.
+
+ On error, errno is also set so that errors are passed back properly
+ through tdb_open(). */
static int tdb_brlock(TDB_CONTEXT *tdb, tdb_off offset,
int rw_type, int lck_type, int probe)
{
@@ -157,8 +160,10 @@ static int tdb_brlock(TDB_CONTEXT *tdb, tdb_off offset,
if (tdb->flags & TDB_NOLOCK)
return 0;
- if (tdb->read_only)
+ if (tdb->read_only) {
+ errno = EACCES;
return -1;
+ }
fl.l_type = rw_type;
fl.l_whence = SEEK_SET;
@@ -171,6 +176,7 @@ static int tdb_brlock(TDB_CONTEXT *tdb, tdb_off offset,
TDB_LOG((tdb, 5,"tdb_brlock failed at offset %d rw_type=%d lck_type=%d\n",
offset, rw_type, lck_type));
}
+ /* errno set by fcntl */
return TDB_ERRCODE(TDB_ERR_LOCK, -1);
}
return 0;
@@ -1369,10 +1375,18 @@ int tdb_store(TDB_CONTEXT *tdb, TDB_DATA key, TDB_DATA dbuf, int flag)
database file. A flags value of O_WRONLY is invalid. The hash size
is advisory, use zero for a default value.
- return is NULL on error */
+ Return is NULL on error, in which case errno is also set. Don't
+ try to call tdb_error or tdb_errname, just do strerror(errno). */
TDB_CONTEXT *tdb_open(char *name, int hash_size, int tdb_flags,
int open_flags, mode_t mode)
{
+ return tdb_open_ex(name, hash_size, tdb_flags, open_flags, mode, NULL);
+}
+
+TDB_CONTEXT *tdb_open_ex(char *name, int hash_size, int tdb_flags,
+ int open_flags, mode_t mode,
+ tdb_log_func log_fn)
+{
TDB_CONTEXT tdb, *ret, *i;
struct stat st;
int rev = 0, locked;
@@ -1384,9 +1398,13 @@ TDB_CONTEXT *tdb_open(char *name, int hash_size, int tdb_flags,
tdb.lockedkeys = NULL;
tdb.flags = tdb_flags;
tdb.open_flags = open_flags;
+ tdb.log_fn = log_fn;
- if ((open_flags & O_ACCMODE) == O_WRONLY)
+ if ((open_flags & O_ACCMODE) == O_WRONLY) {
+ errno = EINVAL;
goto fail;
+ }
+
if (hash_size == 0)
hash_size = DEFAULT_HASH_SIZE;
if ((open_flags & O_ACCMODE) == O_RDONLY) {
@@ -1405,18 +1423,18 @@ TDB_CONTEXT *tdb_open(char *name, int hash_size, int tdb_flags,
}
if ((tdb.fd = open(name, open_flags, mode)) == -1)
- goto fail;
+ goto fail; /* errno set by open(2) */
/* ensure there is only one process initialising at once */
if (tdb_brlock(&tdb, GLOBAL_LOCK, F_WRLCK, F_SETLKW, 0) == -1)
- goto fail;
+ goto fail; /* errno set by tdb_brlock */
/* we need to zero database if we are the only one with it open */
if ((locked = (tdb_brlock(&tdb, ACTIVE_LOCK, F_WRLCK, F_SETLK, 0) == 0))
&& (tdb_flags & TDB_CLEAR_IF_FIRST)) {
open_flags |= O_CREAT;
if (ftruncate(tdb.fd, 0) == -1)
- goto fail;
+ goto fail; /* errno set by ftruncate */
}
if (read(tdb.fd, &tdb.header, sizeof(tdb.header)) != sizeof(tdb.header)
@@ -1424,8 +1442,10 @@ TDB_CONTEXT *tdb_open(char *name, int hash_size, int tdb_flags,
|| (tdb.header.version != TDB_VERSION
&& !(rev = (tdb.header.version==TDB_BYTEREV(TDB_VERSION))))) {
/* its not a valid database - possibly initialise it */
- if (!(open_flags & O_CREAT) || tdb_new_database(&tdb, hash_size) == -1)
+ if (!(open_flags & O_CREAT) || tdb_new_database(&tdb, hash_size) == -1) {
+ errno = EIO; /* ie bad format or something */
goto fail;
+ }
rev = (tdb.flags & TDB_CONVERT);
}
if (!rev)
@@ -1448,14 +1468,18 @@ TDB_CONTEXT *tdb_open(char *name, int hash_size, int tdb_flags,
/* map the database and fill in the return structure */
tdb.name = (char *)strdup(name);
- if (!tdb.name)
+ if (!tdb.name) {
+ errno = ENOMEM;
goto fail;
+ }
tdb.map_size = st.st_size;
tdb.device = st.st_dev;
tdb.inode = st.st_ino;
tdb.locked = calloc(tdb.header.hash_size+1, sizeof(tdb.locked[0]));
- if (!tdb.locked)
+ if (!tdb.locked) {
+ errno = ENOMEM;
goto fail;
+ }
tdb_mmap(&tdb);
if (locked) {
if (!tdb.read_only)
@@ -1468,8 +1492,10 @@ TDB_CONTEXT *tdb_open(char *name, int hash_size, int tdb_flags,
goto fail;
internal:
- if (!(ret = malloc(sizeof(tdb))))
+ if (!(ret = malloc(sizeof(tdb)))) {
+ errno = ENOMEM;
goto fail;
+ }
*ret = tdb;
if (tdb_brlock(&tdb, GLOBAL_LOCK, F_UNLCK, F_SETLKW, 0) == -1)
goto fail;
@@ -1478,6 +1504,8 @@ TDB_CONTEXT *tdb_open(char *name, int hash_size, int tdb_flags,
return ret;
fail:
+ { int save_errno = errno;
+
if (tdb.map_ptr) {
if (tdb.flags & TDB_INTERNAL)
free(tdb.map_ptr);
@@ -1490,7 +1518,9 @@ TDB_CONTEXT *tdb_open(char *name, int hash_size, int tdb_flags,
close(tdb.fd);
if (tdb.locked)
free(tdb.locked);
+ errno = save_errno;
return NULL;
+ }
}
/* close a database */
diff --git a/source3/tdb/tdb.h b/source3/tdb/tdb.h
index 4efe263ee8..e3eab41fd6 100644
--- a/source3/tdb/tdb.h
+++ b/source3/tdb/tdb.h
@@ -99,10 +99,17 @@ typedef struct tdb_context {
} TDB_CONTEXT;
typedef int (*tdb_traverse_func)(TDB_CONTEXT *, TDB_DATA, TDB_DATA, void *);
+typedef void (*tdb_log_func)(TDB_CONTEXT *, int , const char *, ...);
TDB_CONTEXT *tdb_open(char *name, int hash_size, int tdb_flags,
int open_flags, mode_t mode);
-void tdb_logging_function(TDB_CONTEXT *tdb, void (*fn)(TDB_CONTEXT *, int , const char *, ...));
+TDB_CONTEXT *tdb_open_ex(char *name, int hash_size, int tdb_flags,
+ int open_flags, mode_t mode,
+ tdb_log_func log_fn);
+
+int tdb_reopen(TDB_CONTEXT *tdb);
+int tdb_reopen_all(void);
+void tdb_logging_function(TDB_CONTEXT *tdb, tdb_log_func);
enum TDB_ERROR tdb_error(TDB_CONTEXT *tdb);
const char *tdb_errorstr(TDB_CONTEXT *tdb);
TDB_DATA tdb_fetch(TDB_CONTEXT *tdb, TDB_DATA key);
@@ -121,6 +128,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);
+
+/* Debug functions. Not used in production. */
+void tdb_dump_all(TDB_CONTEXT *tdb);
+void tdb_printfreelist(TDB_CONTEXT *tdb);
+
extern TDB_DATA tdb_null;
#ifdef __cplusplus
}