diff options
-rw-r--r-- | lib/util/util_ntdb.c | 85 | ||||
-rw-r--r-- | lib/util/util_ntdb.h | 15 |
2 files changed, 99 insertions, 1 deletions
diff --git a/lib/util/util_ntdb.c b/lib/util/util_ntdb.c index 9c3e2a5254..10d60c2b84 100644 --- a/lib/util/util_ntdb.c +++ b/lib/util/util_ntdb.c @@ -21,6 +21,81 @@ #include "includes.h" #include "util_ntdb.h" #include "lib/param/param.h" +#include "replace.h" +#include "system/filesys.h" + +/* + * This handles NTDB_CLEAR_IF_FIRST. + * + * It's a bad idea for new code, but S3 uses it quite a bit. + */ +static enum NTDB_ERROR clear_if_first(int fd, void *unused) +{ + /* We hold a lock offset 4 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 = 4; /* ACTIVE_LOCK */ + fl.l_len = 1; + + if (fcntl(fd, F_SETLK, &fl) == 0) { + /* We must be first ones to open it w/ NTDB_CLEAR_IF_FIRST! */ + if (ftruncate(fd, 0) != 0) { + return NTDB_ERR_IO; + } + } + fl.l_type = F_RDLCK; + if (fcntl(fd, F_SETLKW, &fl) != 0) { + return NTDB_ERR_IO; + } + return NTDB_SUCCESS; +} + +/* We only need these for the CLEAR_IF_FIRST lock. */ +static int reacquire_cif_lock(struct ntdb_context *ntdb, bool *fail) +{ + struct flock fl; + union ntdb_attribute cif; + + cif.openhook.base.attr = NTDB_ATTRIBUTE_OPENHOOK; + cif.openhook.base.next = NULL; + + if (ntdb_get_attribute(ntdb, &cif) != NTDB_SUCCESS + || cif.openhook.fn != clear_if_first) { + return 0; + } + + /* We hold a lock offset 4 always, so we can tell if anyone else is. */ + fl.l_type = F_RDLCK; + fl.l_whence = SEEK_SET; + fl.l_start = 4; /* ACTIVE_LOCK */ + fl.l_len = 1; + if (fcntl(ntdb_fd(ntdb), F_SETLKW, &fl) != 0) { + *fail = true; + return -1; + } + return 0; +} + +/* You only need this on databases with NTDB_CLEAR_IF_FIRST */ +int ntdb_reopen(struct ntdb_context *ntdb) +{ + bool unused; + return reacquire_cif_lock(ntdb, &unused); +} + +/* You only need to do this if you have NTDB_CLEAR_IF_FIRST databases, and + * the parent will go away before this child. */ +int ntdb_reopen_all(void) +{ + bool fail = false; + + ntdb_foreach(reacquire_cif_lock, &fail); + if (fail) + return -1; + return 0; +} static void *ntdb_talloc(const void *owner, size_t len, void *priv_data) { @@ -74,7 +149,7 @@ struct ntdb_context *ntdb_new(TALLOC_CTX *ctx, union ntdb_attribute *attr, struct loadparm_context *lp_ctx) { - union ntdb_attribute log_attr, alloc_attr; + union ntdb_attribute log_attr, alloc_attr, open_attr; struct ntdb_context *ntdb; if (lp_ctx && !lpcfg_use_mmap(lp_ctx)) { @@ -96,6 +171,14 @@ struct ntdb_context *ntdb_new(TALLOC_CTX *ctx, alloc_attr.alloc.expand = ntdb_expand; alloc_attr.alloc.free = ntdb_free; + if (ntdb_flags & NTDB_CLEAR_IF_FIRST) { + log_attr.base.next = &open_attr; + open_attr.openhook.base.attr = NTDB_ATTRIBUTE_OPENHOOK; + open_attr.openhook.base.next = attr; + open_attr.openhook.fn = clear_if_first; + ntdb_flags &= ~NTDB_CLEAR_IF_FIRST; + } + ntdb = ntdb_open(name, ntdb_flags, open_flags, mode, &alloc_attr); if (!ntdb) { return NULL; diff --git a/lib/util/util_ntdb.h b/lib/util/util_ntdb.h index a5eab7f436..d65d8b6f7b 100644 --- a/lib/util/util_ntdb.h +++ b/lib/util/util_ntdb.h @@ -27,6 +27,21 @@ struct loadparm_context; union ntdb_attribute; + +/* You only need this on databases with NTDB_CLEAR_IF_FIRST */ +int ntdb_reopen(struct ntdb_context *ntdb); + +/* You only need to do this if you have NTDB_CLEAR_IF_FIRST databases, and + * the parent will go away before this child. */ +int ntdb_reopen_all(void); + +/* + * This is like TDB_CLEAR_IF_FIRST, for use with ntdb_new. + * + * It's a bad idea for new code. + */ +#define NTDB_CLEAR_IF_FIRST 1048576 + /*************************************************************** Open an NTDB using talloc: it will be allocated off the context, and all NTDB_DATA.dptr are allocated as children of the ntdb context. |