diff options
Diffstat (limited to 'lib/tdb_wrap')
-rw-r--r-- | lib/tdb_wrap/tdb_wrap.c | 212 | ||||
-rw-r--r-- | lib/tdb_wrap/tdb_wrap.h | 45 | ||||
-rw-r--r-- | lib/tdb_wrap/wscript_build | 8 |
3 files changed, 265 insertions, 0 deletions
diff --git a/lib/tdb_wrap/tdb_wrap.c b/lib/tdb_wrap/tdb_wrap.c new file mode 100644 index 0000000000..0994b1b79c --- /dev/null +++ b/lib/tdb_wrap/tdb_wrap.c @@ -0,0 +1,212 @@ +/* + Unix SMB/CIFS implementation. + TDB wrap functions + + Copyright (C) Andrew Tridgell 2004 + Copyright (C) Jelmer Vernooij <jelmer@samba.org> 2007 + + 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 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + 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, see <http://www.gnu.org/licenses/>. +*/ + +#include "includes.h" +#include "lib/util/dlinklist.h" +#include "lib/tdb_wrap/tdb_wrap.h" +#include "lib/param/param.h" + +/* FIXME: TDB2 does this internally, so no need to wrap multiple opens! */ +#if BUILD_TDB2 +static void tdb_wrap_log(struct tdb_context *tdb, + enum tdb_log_level level, + enum TDB_ERROR ecode, + const char *message, + void *unused) +{ + int dl; + const char *name = tdb_name(tdb); + + switch (level) { + case TDB_LOG_USE_ERROR: + case TDB_LOG_ERROR: + dl = 0; + break; + case TDB_LOG_WARNING: + dl = 2; + break; + default: + dl = 0; + } + + DEBUG(dl, ("tdb(%s):%s: %s", name ? name : "unnamed", + tdb_errorstr(ecode), message)); +} +#else +/* + Log tdb messages via DEBUG(). +*/ +static void tdb_wrap_log(TDB_CONTEXT *tdb, enum tdb_debug_level level, + const char *format, ...) PRINTF_ATTRIBUTE(3,4); + +static void tdb_wrap_log(TDB_CONTEXT *tdb, enum tdb_debug_level level, + const char *format, ...) +{ + va_list ap; + char *ptr = NULL; + int debuglevel = 0; + int ret; + + switch (level) { + case TDB_DEBUG_FATAL: + debuglevel = 0; + break; + case TDB_DEBUG_ERROR: + debuglevel = 1; + break; + case TDB_DEBUG_WARNING: + debuglevel = 2; + break; + case TDB_DEBUG_TRACE: + debuglevel = 5; + break; + default: + debuglevel = 0; + } + + va_start(ap, format); + ret = vasprintf(&ptr, format, ap); + va_end(ap); + + if (ret != -1) { + const char *name = tdb_name(tdb); + DEBUG(debuglevel, ("tdb(%s): %s", name ? name : "unnamed", ptr)); + free(ptr); + } +} +#endif + +struct tdb_wrap_private { + struct tdb_context *tdb; + const char *name; + struct tdb_wrap_private *next, *prev; +}; + +static struct tdb_wrap_private *tdb_list; + +/* destroy the last connection to a tdb */ +static int tdb_wrap_private_destructor(struct tdb_wrap_private *w) +{ + tdb_close(w->tdb); + DLIST_REMOVE(tdb_list, w); + return 0; +} + +static struct tdb_wrap_private *tdb_wrap_private_open(TALLOC_CTX *mem_ctx, + const char *name, + int hash_size, + int tdb_flags, + int open_flags, + mode_t mode, + struct loadparm_context *lp_ctx) +{ + struct tdb_wrap_private *result; + + result = talloc(mem_ctx, struct tdb_wrap_private); + if (result == NULL) { + return NULL; + } + result->name = talloc_strdup(result, name); + if (result->name == NULL) { + goto fail; + } + + if (!lpcfg_use_mmap(lp_ctx)) { + tdb_flags |= TDB_NOMMAP; + } + + if ((hash_size == 0) && (name != NULL)) { + const char *base; + base = strrchr_m(name, '/'); + + if (base != NULL) { + base += 1; + } else { + base = name; + } + hash_size = lpcfg_parm_int(lp_ctx, NULL, "tdb_hashsize", base, 0); + } + + result->tdb = tdb_open_compat(name, hash_size, tdb_flags, + open_flags, mode, tdb_wrap_log, NULL); + if (result->tdb == NULL) { + goto fail; + } + talloc_set_destructor(result, tdb_wrap_private_destructor); + DLIST_ADD(tdb_list, result); + return result; + +fail: + TALLOC_FREE(result); + return NULL; +} + +/* + wrapped connection to a tdb database + to close just talloc_free() the tdb_wrap pointer + */ +struct tdb_wrap *tdb_wrap_open(TALLOC_CTX *mem_ctx, + const char *name, int hash_size, int tdb_flags, + int open_flags, mode_t mode, + struct loadparm_context *lp_ctx) +{ + struct tdb_wrap *result; + struct tdb_wrap_private *w; + + result = talloc(mem_ctx, struct tdb_wrap); + if (result == NULL) { + return NULL; + } + + for (w=tdb_list;w;w=w->next) { + if (strcmp(name, w->name) == 0) { + break; + } + } + + if (w == NULL) { + w = tdb_wrap_private_open(result, name, hash_size, tdb_flags, + open_flags, mode, lp_ctx); + } else { + /* + * Correctly use talloc_reference: The tdb will be + * closed when "w" is being freed. The caller never + * sees "w", so an incorrect use of talloc_free(w) + * instead of calling talloc_unlink is not possible. + * To avoid having to refcount ourselves, "w" will + * have multiple parents that hang off all the + * tdb_wrap's being returned from here. Those parents + * can be freed without problem. + */ + if (talloc_reference(result, w) == NULL) { + goto fail; + } + } + if (w == NULL) { + goto fail; + } + result->tdb = w->tdb; + return result; +fail: + TALLOC_FREE(result); + return NULL; +} + diff --git a/lib/tdb_wrap/tdb_wrap.h b/lib/tdb_wrap/tdb_wrap.h new file mode 100644 index 0000000000..81e77e76a4 --- /dev/null +++ b/lib/tdb_wrap/tdb_wrap.h @@ -0,0 +1,45 @@ +/* + Unix SMB/CIFS implementation. + + database wrap headers + + Copyright (C) Andrew Tridgell 2004 + + 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 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + 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, see <http://www.gnu.org/licenses/>. +*/ + +/* IMPORTANT: tdb_wrap should be always preferred over tdb_context for end consumer functions + it's because if the code will be running inside smbd, then we must use the linked list + of open tdb files, to determine if the tdb we desire is already open + as otherwise, when you close the tdb (even on a different file descriptor), + ALL LOCKS are lost (due to a real screwup in the POSIX specification that nobody has been able to get fixed) +*/ + +#ifndef _TDB_WRAP_H_ +#define _TDB_WRAP_H_ + +#include "tdb_compat.h" + +struct tdb_wrap { + struct tdb_context *tdb; +}; + +struct loadparm_context; + +struct tdb_wrap *tdb_wrap_open(TALLOC_CTX *mem_ctx, + const char *name, int hash_size, int tdb_flags, + int open_flags, mode_t mode, + struct loadparm_context *lp_ctx); + +#endif /* _TDB_WRAP_H_ */ diff --git a/lib/tdb_wrap/wscript_build b/lib/tdb_wrap/wscript_build new file mode 100644 index 0000000000..0811bc5a2d --- /dev/null +++ b/lib/tdb_wrap/wscript_build @@ -0,0 +1,8 @@ +#!/usr/bin/python + +bld.SAMBA_LIBRARY('tdb-wrap', + source='tdb_wrap.c', + deps='tdb_compat talloc samba-util samba-hostconfig', + private_library=True, + local_include=False + ) |