summaryrefslogtreecommitdiff
path: root/lib/tdb_compat/tdb_compat.c
diff options
context:
space:
mode:
authorRusty Russell <rusty@rustcorp.com.au>2011-06-20 16:58:15 +0930
committerRusty Russell <rusty@rustcorp.com.au>2011-06-20 11:18:34 +0200
commit61bf43f5d17c9ac3fc9a36cab74a81f26ac97ccb (patch)
treefaa7f5e9176338f3d9e236860c57cd26132a7864 /lib/tdb_compat/tdb_compat.c
parenteb8cb4f5486ec8648527e78c110b9167887ee479 (diff)
downloadsamba-61bf43f5d17c9ac3fc9a36cab74a81f26ac97ccb.tar.gz
samba-61bf43f5d17c9ac3fc9a36cab74a81f26ac97ccb.tar.bz2
samba-61bf43f5d17c9ac3fc9a36cab74a81f26ac97ccb.zip
lib/tdb_compat: header for tdb1 vs tdb2.
TDB2's API is slightly different from TDB1. In particular, all functions return 0 (TDB_SUCCESS) or a negative error number, rather than -1 or tdb_null and storing the error in tdb_error() (though TDB2 does that as well). The simplest fix is to replace all the different functions with a wrapper, and that is done here. Compatibility functions: tdb_null: not used as an error return, so not defined by tdb2. tdb_fetch_compat: TDB1-style data-returning tdb_fetch. tdb_firstkey_compat: TDB1-style data-returning tdb_firstkey tdb_nextkey_compat: TDB1-style data-returning tdb_nextkey, with TDB2-style free of old key. tdb_errorstr_compat: TDB1-style tdb_errorstr() which takes TDB instead of ecode. TDB_CONTEXT: TDB1-style typedef for struct tdb_context. tdb_open_compat: Simplified open routine which takes log function, sets TDB_ALLOW_NESTING as Samba expects, and adds TDB_CLEAR_IF_FIRST support. Things defined away in TDB2 wrappers: tdb_traverse_read: TDB2's tdb_traverse only uses read-locks anyway. tdb_reopen/tdb_reopen_all: TDB2 detects this error itself. TDB_INCOMPATIBLE_HASH: TDB2 uses the Jenkins hash already. TDB_VOLATILE: TDB2 shouldn't have freelist scaling issues. Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
Diffstat (limited to 'lib/tdb_compat/tdb_compat.c')
-rw-r--r--lib/tdb_compat/tdb_compat.c96
1 files changed, 96 insertions, 0 deletions
diff --git a/lib/tdb_compat/tdb_compat.c b/lib/tdb_compat/tdb_compat.c
new file mode 100644
index 0000000000..f432296a40
--- /dev/null
+++ b/lib/tdb_compat/tdb_compat.c
@@ -0,0 +1,96 @@
+#include <tdb_compat.h>
+
+/* Note: for the moment, we only need this file for TDB2, so we can
+ * assume waf. */
+#if BUILD_TDB2
+TDB_DATA tdb_null = { NULL, 0 };
+
+/* Proxy which sets waitflag to false so we never block. */
+static int lock_nonblock(int fd, int rw, off_t off, off_t len, bool waitflag,
+ void *_orig)
+{
+ struct tdb_attribute_flock *orig = _orig;
+
+ return orig->lock(fd, rw, off, len, false, orig->data);
+}
+
+enum TDB_ERROR tdb_transaction_start_nonblock(struct tdb_context *tdb)
+{
+ union tdb_attribute locking, orig;
+ enum TDB_ERROR ecode;
+
+ orig.base.attr = TDB_ATTRIBUTE_FLOCK;
+ ecode = tdb_get_attribute(tdb, &orig);
+ if (ecode != TDB_SUCCESS)
+ return ecode;
+
+ /* Replace locking function with our own. */
+ locking = orig;
+ locking.flock.data = &orig;
+ locking.flock.lock = lock_nonblock;
+
+ ecode = tdb_set_attribute(tdb, &locking);
+ if (ecode != TDB_SUCCESS)
+ return ecode;
+
+ ecode = tdb_transaction_start(tdb);
+ tdb_unset_attribute(tdb, TDB_ATTRIBUTE_FLOCK);
+ return ecode;
+}
+
+/*
+ * This handles TDB_CLEAR_IF_FIRST.
+ */
+static enum TDB_ERROR clear_if_first(int fd, void *unused)
+{
+ /* We hold a lock offset 63 always, so we can tell if anyone else is. */
+ struct flock fl;
+
+ fl.l_type = F_WRLCK;
+ fl.l_whence = SEEK_SET;
+ fl.l_start = 63;
+ fl.l_len = 1;
+
+ if (fcntl(fd, F_SETLK, &fl) == 0) {
+ /* We must be first ones to open it w/ TDB_CLEAR_IF_FIRST! */
+ if (ftruncate(fd, 0) != 0) {
+ return TDB_ERR_IO;
+ }
+ }
+ fl.l_type = F_RDLCK;
+ if (fcntl(fd, F_SETLKW, &fl) != 0) {
+ return TDB_ERR_IO;
+ }
+ return TDB_SUCCESS;
+}
+
+struct tdb_context *
+tdb_open_compat_(const char *name, int hash_size_unused,
+ int tdb_flags, int open_flags, mode_t mode,
+ void (*log_fn)(struct tdb_context *,
+ enum tdb_log_level,
+ const char *message,
+ void *data),
+ void *log_data)
+{
+ union tdb_attribute cif, log, *attr = NULL;
+
+ if (log_fn) {
+ log.log.base.attr = TDB_ATTRIBUTE_LOG;
+ log.log.base.next = NULL;
+ log.log.fn = log_fn;
+ log.log.data = log_data;
+ attr = &log;
+ }
+
+ if (tdb_flags & TDB_CLEAR_IF_FIRST) {
+ cif.openhook.base.attr = TDB_ATTRIBUTE_OPENHOOK;
+ cif.openhook.base.next = attr;
+ cif.openhook.fn = clear_if_first;
+ attr = &cif;
+ tdb_flags &= ~TDB_CLEAR_IF_FIRST;
+ }
+ return tdb_open(name, tdb_flags|TDB_ALLOW_NESTING, open_flags, mode,
+ attr);
+}
+#endif