X-Git-Url: http://git.ozlabs.org/?p=ccan;a=blobdiff_plain;f=ccan%2Ftdb2%2Fopen.c;h=277a95f9e8ba7bb72caed6ac434f7ccb798ebc1c;hp=37e20907fedfc1a9f512c449dea8b8e727ebcf9a;hb=937d0babe99dcd315040a9e48430140e63e4a7df;hpb=66ead2bcb732aa53bde5092b34c16d780df779ea diff --git a/ccan/tdb2/open.c b/ccan/tdb2/open.c index 37e20907..277a95f9 100644 --- a/ccan/tdb2/open.c +++ b/ccan/tdb2/open.c @@ -1,3 +1,20 @@ + /* + Trivial Database 2: opening and closing TDBs + Copyright (C) Rusty Russell 2010 + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 3 of the License, or (at your option) any later version. + + This library 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, see . +*/ #include "private.h" #include #include @@ -203,6 +220,12 @@ enum TDB_ERROR tdb_set_attribute(struct tdb_context *tdb, : attr->base.attr == TDB_ATTRIBUTE_SEED ? "TDB_ATTRIBUTE_SEED" : "TDB_ATTRIBUTE_OPENHOOK"); + case TDB_ATTRIBUTE_STATS: + return tdb->last_error + = tdb_logerr(tdb, TDB_ERR_EINVAL, + TDB_LOG_USE_ERROR, + "tdb_set_attribute:" + " cannot set TDB_ATTRIBUTE_STATS"); case TDB_ATTRIBUTE_FLOCK: tdb->lock_fn = attr->flock.lock; tdb->unlock_fn = attr->flock.unlock; @@ -247,14 +270,18 @@ enum TDB_ERROR tdb_get_attribute(struct tdb_context *tdb, attr->seed.seed = tdb->hash_seed; break; case TDB_ATTRIBUTE_OPENHOOK: - return tdb->last_error - = tdb_logerr(tdb, TDB_ERR_EINVAL, - TDB_LOG_USE_ERROR, - "tdb_get_attribute:" - " cannot get TDB_ATTRIBUTE_OPENHOOK"); - case TDB_ATTRIBUTE_STATS: - /* FIXME */ - return TDB_ERR_EINVAL; + if (!tdb->openhook) + return tdb->last_error = TDB_ERR_NOEXIST; + attr->openhook.fn = tdb->openhook; + attr->openhook.data = tdb->openhook_data; + break; + case TDB_ATTRIBUTE_STATS: { + size_t size = attr->stats.size; + if (size > tdb->stats.size) + size = tdb->stats.size; + memcpy(&attr->stats, &tdb->stats, size); + break; + } case TDB_ATTRIBUTE_FLOCK: attr->flock.lock = tdb->lock_fn; attr->flock.unlock = tdb->unlock_fn; @@ -279,19 +306,22 @@ void tdb_unset_attribute(struct tdb_context *tdb, case TDB_ATTRIBUTE_LOG: tdb->log_fn = NULL; break; + case TDB_ATTRIBUTE_OPENHOOK: + tdb->openhook = NULL; + break; case TDB_ATTRIBUTE_HASH: case TDB_ATTRIBUTE_SEED: - case TDB_ATTRIBUTE_OPENHOOK: tdb_logerr(tdb, TDB_ERR_EINVAL, TDB_LOG_USE_ERROR, "tdb_unset_attribute: cannot unset %s after opening", type == TDB_ATTRIBUTE_HASH ? "TDB_ATTRIBUTE_HASH" - : type == TDB_ATTRIBUTE_SEED - ? "TDB_ATTRIBUTE_SEED" - : "TDB_ATTRIBUTE_OPENHOOK"); + : "TDB_ATTRIBUTE_SEED"); break; case TDB_ATTRIBUTE_STATS: - /* FIXME */ + tdb_logerr(tdb, TDB_ERR_EINVAL, + TDB_LOG_USE_ERROR, + "tdb_unset_attribute:" + "cannot unset TDB_ATTRIBUTE_STATS"); break; case TDB_ATTRIBUTE_FLOCK: tdb->lock_fn = tdb_fcntl_lock; @@ -317,9 +347,9 @@ struct tdb_context *tdb_open(const char *name, int tdb_flags, ssize_t rlen; struct tdb_header hdr; struct tdb_attribute_seed *seed = NULL; - struct tdb_attribute_openhook *openhook = NULL; tdb_bool_err berr; enum TDB_ERROR ecode; + int openlock; tdb = malloc(sizeof(*tdb) + (name ? strlen(name) + 1 : 0)); if (!tdb) { @@ -337,13 +367,17 @@ struct tdb_context *tdb_open(const char *name, int tdb_flags, tdb->flags = tdb_flags; tdb->log_fn = NULL; tdb->transaction = NULL; - tdb->stats = NULL; tdb->access = NULL; + tdb->open_flags = open_flags; tdb->last_error = TDB_SUCCESS; tdb->file = NULL; + tdb->openhook = NULL; tdb->lock_fn = tdb_fcntl_lock; tdb->unlock_fn = tdb_fcntl_unlock; tdb->hash_fn = jenkins_hash; + memset(&tdb->stats, 0, sizeof(tdb->stats)); + tdb->stats.base.attr = TDB_ATTRIBUTE_STATS; + tdb->stats.size = sizeof(tdb->stats); tdb_io_init(tdb); while (attr) { @@ -355,14 +389,9 @@ struct tdb_context *tdb_open(const char *name, int tdb_flags, case TDB_ATTRIBUTE_SEED: seed = &attr->seed; break; - case TDB_ATTRIBUTE_STATS: - tdb->stats = &attr->stats; - /* They have stats we don't know about? Tell them. */ - if (tdb->stats->size > sizeof(attr->stats)) - tdb->stats->size = sizeof(attr->stats); - break; case TDB_ATTRIBUTE_OPENHOOK: - openhook = &attr->openhook; + tdb->openhook = attr->openhook.fn; + tdb->openhook_data = attr->openhook.data; break; default: /* These are set as normal. */ @@ -374,7 +403,8 @@ struct tdb_context *tdb_open(const char *name, int tdb_flags, } if (tdb_flags & ~(TDB_INTERNAL | TDB_NOLOCK | TDB_NOMMAP | TDB_CONVERT - | TDB_NOSYNC | TDB_SEQNUM)) { + | TDB_NOSYNC | TDB_SEQNUM | TDB_ALLOW_NESTING + | TDB_RDONLY)) { ecode = tdb_logerr(tdb, TDB_ERR_EINVAL, TDB_LOG_USE_ERROR, "tdb_open: unknown flags %u", tdb_flags); goto fail; @@ -388,11 +418,17 @@ struct tdb_context *tdb_open(const char *name, int tdb_flags, } if ((open_flags & O_ACCMODE) == O_RDONLY) { - tdb->read_only = true; - tdb->mmap_flags = PROT_READ; + openlock = F_RDLCK; + tdb->flags |= TDB_RDONLY; } else { - tdb->read_only = false; - tdb->mmap_flags = PROT_READ | PROT_WRITE; + if (tdb_flags & TDB_RDONLY) { + ecode = tdb_logerr(tdb, TDB_ERR_EINVAL, + TDB_LOG_USE_ERROR, + "tdb_open: can't use TDB_RDONLY" + " without O_RDONLY"); + goto fail; + } + openlock = F_WRLCK; } /* internal databases don't need any of the rest. */ @@ -407,16 +443,6 @@ struct tdb_context *tdb_open(const char *name, int tdb_flags, if (ecode != TDB_SUCCESS) { goto fail; } - if (name) { - tdb->name = strdup(name); - if (!tdb->name) { - ecode = tdb_logerr(tdb, TDB_ERR_OOM, - TDB_LOG_ERROR, - "tdb_open: failed to" - " allocate name"); - goto fail; - } - } tdb_convert(tdb, &hdr.hash_seed, sizeof(hdr.hash_seed)); tdb->hash_seed = hdr.hash_seed; tdb_ftable_init(tdb); @@ -447,12 +473,15 @@ struct tdb_context *tdb_open(const char *name, int tdb_flags, tdb_logerr(tdb, TDB_ERR_IO, TDB_LOG_ERROR, "tdb_open: could not stat open %s: %s", name, strerror(errno)); + close(fd); goto fail_errno; } ecode = tdb_new_file(tdb); - if (ecode != TDB_SUCCESS) + if (ecode != TDB_SUCCESS) { + close(fd); goto fail; + } tdb->file->next = files; tdb->file->fd = fd; @@ -463,15 +492,15 @@ struct tdb_context *tdb_open(const char *name, int tdb_flags, } /* ensure there is only one process initialising at once */ - ecode = tdb_lock_open(tdb, TDB_LOCK_WAIT|TDB_LOCK_NOCHECK); + ecode = tdb_lock_open(tdb, openlock, TDB_LOCK_WAIT|TDB_LOCK_NOCHECK); if (ecode != TDB_SUCCESS) { saved_errno = errno; goto fail_errno; } /* call their open hook if they gave us one. */ - if (openhook) { - ecode = openhook->fn(tdb->file->fd, openhook->data); + if (tdb->openhook) { + ecode = tdb->openhook(tdb->file->fd, tdb->openhook_data); if (ecode != TDB_SUCCESS) { tdb_logerr(tdb, ecode, TDB_LOG_ERROR, "tdb_open: open hook failed"); @@ -510,6 +539,12 @@ struct tdb_context *tdb_open(const char *name, int tdb_flags, name, (long long)hdr.version); goto fail; } + } else if (tdb->flags & TDB_CONVERT) { + ecode = tdb_logerr(tdb, TDB_ERR_IO, TDB_LOG_ERROR, + "tdb_open:" + " %s does not need TDB_CONVERT", + name); + goto fail; } tdb_convert(tdb, &hdr, sizeof(hdr)); @@ -525,27 +560,23 @@ struct tdb_context *tdb_open(const char *name, int tdb_flags, goto fail; } - tdb->name = strdup(name); - if (!tdb->name) { - ecode = tdb_logerr(tdb, TDB_ERR_OOM, TDB_LOG_ERROR, - "tdb_open: failed to allocate name"); - goto fail; - } - /* Clear any features we don't understand. */ if ((open_flags & O_ACCMODE) != O_RDONLY) { hdr.features_used &= TDB_FEATURE_MASK; - if (tdb_write_convert(tdb, offsetof(struct tdb_header, - features_used), - &hdr.features_used, - sizeof(hdr.features_used)) == -1) + ecode = tdb_write_convert(tdb, offsetof(struct tdb_header, + features_used), + &hdr.features_used, + sizeof(hdr.features_used)); + if (ecode != TDB_SUCCESS) goto fail; } - tdb_unlock_open(tdb); + tdb_unlock_open(tdb, openlock); /* This make sure we have current map_size and mmap. */ - tdb->methods->oob(tdb, tdb->file->map_size + 1, true); + ecode = tdb->methods->oob(tdb, tdb->file->map_size + 1, true); + if (unlikely(ecode != TDB_SUCCESS)) + goto fail; /* Now it's fully formed, recover if necessary. */ berr = tdb_needs_recovery(tdb);