From efdf0f2d8f34b4c01c82c558b350ec36c7329b1e Mon Sep 17 00:00:00 2001 From: Rusty Russell Date: Thu, 17 Mar 2011 22:12:21 +1030 Subject: [PATCH] tdb2: move open routines into a separate file (open.c) Simply tidying up. --- ccan/tdb2/open.c | 479 +++++++++++++++++ ccan/tdb2/tdb.c | 480 ------------------ ccan/tdb2/test/failtest_helper.h | 6 +- ccan/tdb2/test/run-001-encode.c | 1 + ccan/tdb2/test/run-001-fls.c | 1 + ccan/tdb2/test/run-01-new_database.c | 1 + ccan/tdb2/test/run-02-expand.c | 1 + ccan/tdb2/test/run-03-coalesce.c | 1 + ccan/tdb2/test/run-04-basichash.c | 1 + ccan/tdb2/test/run-10-simple-store.c | 1 + ccan/tdb2/test/run-11-simple-fetch.c | 1 + ccan/tdb2/test/run-12-store.c | 1 + ccan/tdb2/test/run-13-delete.c | 1 + ccan/tdb2/test/run-15-append.c | 1 + ccan/tdb2/test/run-20-growhash.c | 1 + ccan/tdb2/test/run-25-hashoverload.c | 1 + ccan/tdb2/test/run-30-exhaust-before-expand.c | 1 + ccan/tdb2/test/run-50-multiple-freelists.c | 1 + ccan/tdb2/test/run-55-transaction.c | 1 + .../test/run-56-open-during-transaction.c | 1 + .../tdb2/test/run-57-die-during-transaction.c | 1 + ccan/tdb2/test/run-add-remove-flags.c | 1 + ccan/tdb2/test/run-features.c | 1 + ccan/tdb2/test/run-firstkey-nextkey.c | 1 + ccan/tdb2/test/run-missing-entries.c | 1 + ccan/tdb2/test/run-record-expand.c | 1 + ccan/tdb2/test/run-remap-in-read_traverse.c | 1 + ccan/tdb2/test/run-seed.c | 1 + ccan/tdb2/test/run-simple-delete.c | 1 + ccan/tdb2/test/run-summary.c | 1 + ccan/tdb2/test/run-tdb_errorstr.c | 1 + ccan/tdb2/test/run-traverse.c | 1 + 32 files changed, 511 insertions(+), 483 deletions(-) create mode 100644 ccan/tdb2/open.c diff --git a/ccan/tdb2/open.c b/ccan/tdb2/open.c new file mode 100644 index 00000000..21881c35 --- /dev/null +++ b/ccan/tdb2/open.c @@ -0,0 +1,479 @@ +#include "private.h" + +/* all contexts, to ensure no double-opens (fcntl locks don't nest!) */ +static struct tdb_context *tdbs = NULL; + +static bool tdb_already_open(dev_t device, ino_t ino) +{ + struct tdb_context *i; + + for (i = tdbs; i; i = i->next) { + if (i->device == device && i->inode == ino) { + return true; + } + } + + return false; +} + +static bool read_all(int fd, void *buf, size_t len) +{ + while (len) { + ssize_t ret; + ret = read(fd, buf, len); + if (ret < 0) + return false; + if (ret == 0) { + /* ETOOSHORT? */ + errno = EWOULDBLOCK; + return false; + } + buf = (char *)buf + ret; + len -= ret; + } + return true; +} + +static uint64_t random_number(struct tdb_context *tdb) +{ + int fd; + uint64_t ret = 0; + struct timeval now; + + fd = open("/dev/urandom", O_RDONLY); + if (fd >= 0) { + if (read_all(fd, &ret, sizeof(ret))) { + close(fd); + return ret; + } + close(fd); + } + /* FIXME: Untested! Based on Wikipedia protocol description! */ + fd = open("/dev/egd-pool", O_RDWR); + if (fd >= 0) { + /* Command is 1, next byte is size we want to read. */ + char cmd[2] = { 1, sizeof(uint64_t) }; + if (write(fd, cmd, sizeof(cmd)) == sizeof(cmd)) { + char reply[1 + sizeof(uint64_t)]; + int r = read(fd, reply, sizeof(reply)); + if (r > 1) { + /* Copy at least some bytes. */ + memcpy(&ret, reply+1, r - 1); + if (reply[0] == sizeof(uint64_t) + && r == sizeof(reply)) { + close(fd); + return ret; + } + } + } + close(fd); + } + + /* Fallback: pid and time. */ + gettimeofday(&now, NULL); + ret = getpid() * 100132289ULL + now.tv_sec * 1000000ULL + now.tv_usec; + tdb_logerr(tdb, TDB_SUCCESS, TDB_LOG_WARNING, + "tdb_open: random from getpid and time"); + return ret; +} + +struct new_database { + struct tdb_header hdr; + struct tdb_freetable ftable; +}; + +/* initialise a new database */ +static enum TDB_ERROR tdb_new_database(struct tdb_context *tdb, + struct tdb_attribute_seed *seed, + struct tdb_header *hdr) +{ + /* We make it up in memory, then write it out if not internal */ + struct new_database newdb; + unsigned int magic_len; + ssize_t rlen; + enum TDB_ERROR ecode; + + /* Fill in the header */ + newdb.hdr.version = TDB_VERSION; + if (seed) + newdb.hdr.hash_seed = seed->seed; + else + newdb.hdr.hash_seed = random_number(tdb); + newdb.hdr.hash_test = TDB_HASH_MAGIC; + newdb.hdr.hash_test = tdb->khash(&newdb.hdr.hash_test, + sizeof(newdb.hdr.hash_test), + newdb.hdr.hash_seed, + tdb->hash_priv); + newdb.hdr.recovery = 0; + newdb.hdr.features_used = newdb.hdr.features_offered = TDB_FEATURE_MASK; + memset(newdb.hdr.reserved, 0, sizeof(newdb.hdr.reserved)); + /* Initial hashes are empty. */ + memset(newdb.hdr.hashtable, 0, sizeof(newdb.hdr.hashtable)); + + /* Free is empty. */ + newdb.hdr.free_table = offsetof(struct new_database, ftable); + memset(&newdb.ftable, 0, sizeof(newdb.ftable)); + ecode = set_header(NULL, &newdb.ftable.hdr, TDB_FTABLE_MAGIC, 0, + sizeof(newdb.ftable) - sizeof(newdb.ftable.hdr), + sizeof(newdb.ftable) - sizeof(newdb.ftable.hdr), + 0); + if (ecode != TDB_SUCCESS) { + return ecode; + } + + /* Magic food */ + memset(newdb.hdr.magic_food, 0, sizeof(newdb.hdr.magic_food)); + strcpy(newdb.hdr.magic_food, TDB_MAGIC_FOOD); + + /* This creates an endian-converted database, as if read from disk */ + magic_len = sizeof(newdb.hdr.magic_food); + tdb_convert(tdb, + (char *)&newdb.hdr + magic_len, sizeof(newdb) - magic_len); + + *hdr = newdb.hdr; + + if (tdb->flags & TDB_INTERNAL) { + tdb->map_size = sizeof(newdb); + tdb->map_ptr = malloc(tdb->map_size); + if (!tdb->map_ptr) { + return tdb_logerr(tdb, TDB_ERR_OOM, TDB_LOG_ERROR, + "tdb_new_database:" + " failed to allocate"); + } + memcpy(tdb->map_ptr, &newdb, tdb->map_size); + return TDB_SUCCESS; + } + if (lseek(tdb->fd, 0, SEEK_SET) == -1) { + return tdb_logerr(tdb, TDB_ERR_IO, TDB_LOG_ERROR, + "tdb_new_database:" + " failed to seek: %s", strerror(errno)); + } + + if (ftruncate(tdb->fd, 0) == -1) { + return tdb_logerr(tdb, TDB_ERR_IO, TDB_LOG_ERROR, + "tdb_new_database:" + " failed to truncate: %s", strerror(errno)); + } + + rlen = write(tdb->fd, &newdb, sizeof(newdb)); + if (rlen != sizeof(newdb)) { + if (rlen >= 0) + errno = ENOSPC; + return tdb_logerr(tdb, TDB_ERR_IO, TDB_LOG_ERROR, + "tdb_new_database: %zi writing header: %s", + rlen, strerror(errno)); + } + return TDB_SUCCESS; +} + +struct tdb_context *tdb_open(const char *name, int tdb_flags, + int open_flags, mode_t mode, + union tdb_attribute *attr) +{ + struct tdb_context *tdb; + struct stat st; + int saved_errno = 0; + uint64_t hash_test; + unsigned v; + ssize_t rlen; + struct tdb_header hdr; + struct tdb_attribute_seed *seed = NULL; + tdb_bool_err berr; + enum TDB_ERROR ecode; + + tdb = malloc(sizeof(*tdb)); + if (!tdb) { + /* Can't log this */ + errno = ENOMEM; + return NULL; + } + tdb->name = NULL; + tdb->map_ptr = NULL; + tdb->direct_access = 0; + tdb->fd = -1; + tdb->map_size = sizeof(struct tdb_header); + tdb->flags = tdb_flags; + tdb->logfn = NULL; + tdb->transaction = NULL; + tdb->stats = NULL; + tdb->access = NULL; + tdb_hash_init(tdb); + tdb_io_init(tdb); + tdb_lock_init(tdb); + + while (attr) { + switch (attr->base.attr) { + case TDB_ATTRIBUTE_LOG: + tdb->logfn = attr->log.log_fn; + tdb->log_private = attr->log.log_private; + break; + case TDB_ATTRIBUTE_HASH: + tdb->khash = attr->hash.hash_fn; + tdb->hash_priv = attr->hash.hash_private; + break; + 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; + default: + ecode = tdb_logerr(tdb, TDB_ERR_EINVAL, + TDB_LOG_USE_ERROR, + "tdb_open:" + " unknown attribute type %u", + attr->base.attr); + goto fail; + } + attr = attr->base.next; + } + + if (tdb_flags & ~(TDB_INTERNAL | TDB_NOLOCK | TDB_NOMMAP | TDB_CONVERT + | TDB_NOSYNC)) { + ecode = tdb_logerr(tdb, TDB_ERR_EINVAL, TDB_LOG_USE_ERROR, + "tdb_open: unknown flags %u", tdb_flags); + goto fail; + } + + if ((open_flags & O_ACCMODE) == O_WRONLY) { + ecode = tdb_logerr(tdb, TDB_ERR_EINVAL, TDB_LOG_USE_ERROR, + "tdb_open: can't open tdb %s write-only", + name); + goto fail; + } + + if ((open_flags & O_ACCMODE) == O_RDONLY) { + tdb->read_only = true; + tdb->mmap_flags = PROT_READ; + } else { + tdb->read_only = false; + tdb->mmap_flags = PROT_READ | PROT_WRITE; + } + + /* internal databases don't need any of the rest. */ + if (tdb->flags & TDB_INTERNAL) { + tdb->flags |= (TDB_NOLOCK | TDB_NOMMAP); + ecode = tdb_new_database(tdb, seed, &hdr); + if (ecode != TDB_SUCCESS) { + goto fail; + } + tdb_convert(tdb, &hdr.hash_seed, sizeof(hdr.hash_seed)); + tdb->hash_seed = hdr.hash_seed; + tdb_ftable_init(tdb); + return tdb; + } + + if ((tdb->fd = open(name, open_flags, mode)) == -1) { + /* errno set by open(2) */ + saved_errno = errno; + ecode = tdb_logerr(tdb, TDB_ERR_IO, TDB_LOG_ERROR, + "tdb_open: could not open file %s: %s", + name, strerror(errno)); + goto fail; + } + + /* on exec, don't inherit the fd */ + v = fcntl(tdb->fd, F_GETFD, 0); + fcntl(tdb->fd, F_SETFD, v | FD_CLOEXEC); + + /* ensure there is only one process initialising at once */ + ecode = tdb_lock_open(tdb, TDB_LOCK_WAIT|TDB_LOCK_NOCHECK); + if (ecode != TDB_SUCCESS) { + goto fail; + } + + /* If they used O_TRUNC, read will return 0. */ + rlen = read(tdb->fd, &hdr, sizeof(hdr)); + if (rlen == 0 && (open_flags & O_CREAT)) { + ecode = tdb_new_database(tdb, seed, &hdr); + if (ecode != TDB_SUCCESS) { + goto fail; + } + } else if (rlen < 0) { + ecode = tdb_logerr(tdb, TDB_ERR_IO, TDB_LOG_ERROR, + "tdb_open: error %s reading %s", + strerror(errno), name); + goto fail; + } else if (rlen < sizeof(hdr) + || strcmp(hdr.magic_food, TDB_MAGIC_FOOD) != 0) { + ecode = tdb_logerr(tdb, TDB_ERR_IO, TDB_LOG_ERROR, + "tdb_open: %s is not a tdb file", name); + goto fail; + } + + if (hdr.version != TDB_VERSION) { + if (hdr.version == bswap_64(TDB_VERSION)) + tdb->flags |= TDB_CONVERT; + else { + /* wrong version */ + ecode = tdb_logerr(tdb, TDB_ERR_IO, TDB_LOG_ERROR, + "tdb_open:" + " %s is unknown version 0x%llx", + name, (long long)hdr.version); + goto fail; + } + } + + tdb_convert(tdb, &hdr, sizeof(hdr)); + tdb->hash_seed = hdr.hash_seed; + hash_test = TDB_HASH_MAGIC; + hash_test = tdb_hash(tdb, &hash_test, sizeof(hash_test)); + if (hdr.hash_test != hash_test) { + /* wrong hash variant */ + ecode = tdb_logerr(tdb, TDB_ERR_IO, TDB_LOG_ERROR, + "tdb_open:" + " %s uses a different hash function", + name); + goto fail; + } + + if (fstat(tdb->fd, &st) == -1) { + saved_errno = errno; + ecode = tdb_logerr(tdb, TDB_ERR_IO, TDB_LOG_ERROR, + "tdb_open: could not stat open %s: %s", + name, strerror(errno)); + goto fail; + } + + /* Is it already in the open list? If so, fail. */ + if (tdb_already_open(st.st_dev, st.st_ino)) { + /* FIXME */ + ecode = tdb_logerr(tdb, TDB_ERR_IO, TDB_LOG_USE_ERROR, + "tdb_open: %s (%d,%d) is already open" + " in this process", + name, (int)st.st_dev, (int)st.st_ino); + 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) + goto fail; + } + + tdb->device = st.st_dev; + tdb->inode = st.st_ino; + tdb_unlock_open(tdb); + + /* This make sure we have current map_size and mmap. */ + tdb->methods->oob(tdb, tdb->map_size + 1, true); + + /* Now it's fully formed, recover if necessary. */ + berr = tdb_needs_recovery(tdb); + if (unlikely(berr != false)) { + if (berr < 0) { + ecode = berr; + goto fail; + } + ecode = tdb_lock_and_recover(tdb); + if (ecode != TDB_SUCCESS) { + goto fail; + } + } + + ecode = tdb_ftable_init(tdb); + if (ecode != TDB_SUCCESS) { + goto fail; + } + + tdb->next = tdbs; + tdbs = tdb; + return tdb; + + fail: + /* Map ecode to some logical errno. */ + if (!saved_errno) { + switch (ecode) { + case TDB_ERR_CORRUPT: + case TDB_ERR_IO: + saved_errno = EIO; + break; + case TDB_ERR_LOCK: + saved_errno = EWOULDBLOCK; + break; + case TDB_ERR_OOM: + saved_errno = ENOMEM; + break; + case TDB_ERR_EINVAL: + saved_errno = EINVAL; + break; + default: + saved_errno = EINVAL; + break; + } + } + +#ifdef TDB_TRACE + close(tdb->tracefd); +#endif + if (tdb->map_ptr) { + if (tdb->flags & TDB_INTERNAL) { + free(tdb->map_ptr); + } else + tdb_munmap(tdb); + } + free(tdb->lockrecs); + free((char *)tdb->name); + if (tdb->fd != -1) + if (close(tdb->fd) != 0) + tdb_logerr(tdb, TDB_ERR_IO, TDB_LOG_ERROR, + "tdb_open: failed to close tdb->fd" + " on error: %s", strerror(errno)); + free(tdb); + errno = saved_errno; + return NULL; +} + +int tdb_close(struct tdb_context *tdb) +{ + struct tdb_context **i; + int ret = 0; + + tdb_trace(tdb, "tdb_close"); + + if (tdb->transaction) { + tdb_transaction_cancel(tdb); + } + + if (tdb->map_ptr) { + if (tdb->flags & TDB_INTERNAL) + free(tdb->map_ptr); + else + tdb_munmap(tdb); + } + free((char *)tdb->name); + if (tdb->fd != -1) { + ret = close(tdb->fd); + tdb->fd = -1; + } + free(tdb->lockrecs); + + /* Remove from contexts list */ + for (i = &tdbs; *i; i = &(*i)->next) { + if (*i == tdb) { + *i = tdb->next; + break; + } + } + +#ifdef TDB_TRACE + close(tdb->tracefd); +#endif + free(tdb); + + return ret; +} diff --git a/ccan/tdb2/tdb.c b/ccan/tdb2/tdb.c index b5e54576..02642f58 100644 --- a/ccan/tdb2/tdb.c +++ b/ccan/tdb2/tdb.c @@ -1,450 +1,10 @@ #include "private.h" #include -#include -#include #include /* The null return. */ struct tdb_data tdb_null = { .dptr = NULL, .dsize = 0 }; -/* all contexts, to ensure no double-opens (fcntl locks don't nest!) */ -static struct tdb_context *tdbs = NULL; - -static bool tdb_already_open(dev_t device, ino_t ino) -{ - struct tdb_context *i; - - for (i = tdbs; i; i = i->next) { - if (i->device == device && i->inode == ino) { - return true; - } - } - - return false; -} - -static bool read_all(int fd, void *buf, size_t len) -{ - while (len) { - ssize_t ret; - ret = read(fd, buf, len); - if (ret < 0) - return false; - if (ret == 0) { - /* ETOOSHORT? */ - errno = EWOULDBLOCK; - return false; - } - buf = (char *)buf + ret; - len -= ret; - } - return true; -} - -static uint64_t random_number(struct tdb_context *tdb) -{ - int fd; - uint64_t ret = 0; - struct timeval now; - - fd = open("/dev/urandom", O_RDONLY); - if (fd >= 0) { - if (read_all(fd, &ret, sizeof(ret))) { - close(fd); - return ret; - } - close(fd); - } - /* FIXME: Untested! Based on Wikipedia protocol description! */ - fd = open("/dev/egd-pool", O_RDWR); - if (fd >= 0) { - /* Command is 1, next byte is size we want to read. */ - char cmd[2] = { 1, sizeof(uint64_t) }; - if (write(fd, cmd, sizeof(cmd)) == sizeof(cmd)) { - char reply[1 + sizeof(uint64_t)]; - int r = read(fd, reply, sizeof(reply)); - if (r > 1) { - /* Copy at least some bytes. */ - memcpy(&ret, reply+1, r - 1); - if (reply[0] == sizeof(uint64_t) - && r == sizeof(reply)) { - close(fd); - return ret; - } - } - } - close(fd); - } - - /* Fallback: pid and time. */ - gettimeofday(&now, NULL); - ret = getpid() * 100132289ULL + now.tv_sec * 1000000ULL + now.tv_usec; - tdb_logerr(tdb, TDB_SUCCESS, TDB_LOG_WARNING, - "tdb_open: random from getpid and time"); - return ret; -} - -struct new_database { - struct tdb_header hdr; - struct tdb_freetable ftable; -}; - -/* initialise a new database */ -static enum TDB_ERROR tdb_new_database(struct tdb_context *tdb, - struct tdb_attribute_seed *seed, - struct tdb_header *hdr) -{ - /* We make it up in memory, then write it out if not internal */ - struct new_database newdb; - unsigned int magic_len; - ssize_t rlen; - enum TDB_ERROR ecode; - - /* Fill in the header */ - newdb.hdr.version = TDB_VERSION; - if (seed) - newdb.hdr.hash_seed = seed->seed; - else - newdb.hdr.hash_seed = random_number(tdb); - newdb.hdr.hash_test = TDB_HASH_MAGIC; - newdb.hdr.hash_test = tdb->khash(&newdb.hdr.hash_test, - sizeof(newdb.hdr.hash_test), - newdb.hdr.hash_seed, - tdb->hash_priv); - newdb.hdr.recovery = 0; - newdb.hdr.features_used = newdb.hdr.features_offered = TDB_FEATURE_MASK; - memset(newdb.hdr.reserved, 0, sizeof(newdb.hdr.reserved)); - /* Initial hashes are empty. */ - memset(newdb.hdr.hashtable, 0, sizeof(newdb.hdr.hashtable)); - - /* Free is empty. */ - newdb.hdr.free_table = offsetof(struct new_database, ftable); - memset(&newdb.ftable, 0, sizeof(newdb.ftable)); - ecode = set_header(NULL, &newdb.ftable.hdr, TDB_FTABLE_MAGIC, 0, - sizeof(newdb.ftable) - sizeof(newdb.ftable.hdr), - sizeof(newdb.ftable) - sizeof(newdb.ftable.hdr), - 0); - if (ecode != TDB_SUCCESS) { - return ecode; - } - - /* Magic food */ - memset(newdb.hdr.magic_food, 0, sizeof(newdb.hdr.magic_food)); - strcpy(newdb.hdr.magic_food, TDB_MAGIC_FOOD); - - /* This creates an endian-converted database, as if read from disk */ - magic_len = sizeof(newdb.hdr.magic_food); - tdb_convert(tdb, - (char *)&newdb.hdr + magic_len, sizeof(newdb) - magic_len); - - *hdr = newdb.hdr; - - if (tdb->flags & TDB_INTERNAL) { - tdb->map_size = sizeof(newdb); - tdb->map_ptr = malloc(tdb->map_size); - if (!tdb->map_ptr) { - return tdb_logerr(tdb, TDB_ERR_OOM, TDB_LOG_ERROR, - "tdb_new_database:" - " failed to allocate"); - } - memcpy(tdb->map_ptr, &newdb, tdb->map_size); - return TDB_SUCCESS; - } - if (lseek(tdb->fd, 0, SEEK_SET) == -1) { - return tdb_logerr(tdb, TDB_ERR_IO, TDB_LOG_ERROR, - "tdb_new_database:" - " failed to seek: %s", strerror(errno)); - } - - if (ftruncate(tdb->fd, 0) == -1) { - return tdb_logerr(tdb, TDB_ERR_IO, TDB_LOG_ERROR, - "tdb_new_database:" - " failed to truncate: %s", strerror(errno)); - } - - rlen = write(tdb->fd, &newdb, sizeof(newdb)); - if (rlen != sizeof(newdb)) { - if (rlen >= 0) - errno = ENOSPC; - return tdb_logerr(tdb, TDB_ERR_IO, TDB_LOG_ERROR, - "tdb_new_database: %zi writing header: %s", - rlen, strerror(errno)); - } - return TDB_SUCCESS; -} - -struct tdb_context *tdb_open(const char *name, int tdb_flags, - int open_flags, mode_t mode, - union tdb_attribute *attr) -{ - struct tdb_context *tdb; - struct stat st; - int saved_errno = 0; - uint64_t hash_test; - unsigned v; - ssize_t rlen; - struct tdb_header hdr; - struct tdb_attribute_seed *seed = NULL; - tdb_bool_err berr; - enum TDB_ERROR ecode; - - tdb = malloc(sizeof(*tdb)); - if (!tdb) { - /* Can't log this */ - errno = ENOMEM; - return NULL; - } - tdb->name = NULL; - tdb->map_ptr = NULL; - tdb->direct_access = 0; - tdb->fd = -1; - tdb->map_size = sizeof(struct tdb_header); - tdb->flags = tdb_flags; - tdb->logfn = NULL; - tdb->transaction = NULL; - tdb->stats = NULL; - tdb->access = NULL; - tdb_hash_init(tdb); - tdb_io_init(tdb); - tdb_lock_init(tdb); - - while (attr) { - switch (attr->base.attr) { - case TDB_ATTRIBUTE_LOG: - tdb->logfn = attr->log.log_fn; - tdb->log_private = attr->log.log_private; - break; - case TDB_ATTRIBUTE_HASH: - tdb->khash = attr->hash.hash_fn; - tdb->hash_priv = attr->hash.hash_private; - break; - 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; - default: - ecode = tdb_logerr(tdb, TDB_ERR_EINVAL, - TDB_LOG_USE_ERROR, - "tdb_open:" - " unknown attribute type %u", - attr->base.attr); - goto fail; - } - attr = attr->base.next; - } - - if (tdb_flags & ~(TDB_INTERNAL | TDB_NOLOCK | TDB_NOMMAP | TDB_CONVERT - | TDB_NOSYNC)) { - ecode = tdb_logerr(tdb, TDB_ERR_EINVAL, TDB_LOG_USE_ERROR, - "tdb_open: unknown flags %u", tdb_flags); - goto fail; - } - - if ((open_flags & O_ACCMODE) == O_WRONLY) { - ecode = tdb_logerr(tdb, TDB_ERR_EINVAL, TDB_LOG_USE_ERROR, - "tdb_open: can't open tdb %s write-only", - name); - goto fail; - } - - if ((open_flags & O_ACCMODE) == O_RDONLY) { - tdb->read_only = true; - tdb->mmap_flags = PROT_READ; - } else { - tdb->read_only = false; - tdb->mmap_flags = PROT_READ | PROT_WRITE; - } - - /* internal databases don't need any of the rest. */ - if (tdb->flags & TDB_INTERNAL) { - tdb->flags |= (TDB_NOLOCK | TDB_NOMMAP); - ecode = tdb_new_database(tdb, seed, &hdr); - if (ecode != TDB_SUCCESS) { - goto fail; - } - tdb_convert(tdb, &hdr.hash_seed, sizeof(hdr.hash_seed)); - tdb->hash_seed = hdr.hash_seed; - tdb_ftable_init(tdb); - return tdb; - } - - if ((tdb->fd = open(name, open_flags, mode)) == -1) { - /* errno set by open(2) */ - saved_errno = errno; - ecode = tdb_logerr(tdb, TDB_ERR_IO, TDB_LOG_ERROR, - "tdb_open: could not open file %s: %s", - name, strerror(errno)); - goto fail; - } - - /* on exec, don't inherit the fd */ - v = fcntl(tdb->fd, F_GETFD, 0); - fcntl(tdb->fd, F_SETFD, v | FD_CLOEXEC); - - /* ensure there is only one process initialising at once */ - ecode = tdb_lock_open(tdb, TDB_LOCK_WAIT|TDB_LOCK_NOCHECK); - if (ecode != TDB_SUCCESS) { - goto fail; - } - - /* If they used O_TRUNC, read will return 0. */ - rlen = read(tdb->fd, &hdr, sizeof(hdr)); - if (rlen == 0 && (open_flags & O_CREAT)) { - ecode = tdb_new_database(tdb, seed, &hdr); - if (ecode != TDB_SUCCESS) { - goto fail; - } - } else if (rlen < 0) { - ecode = tdb_logerr(tdb, TDB_ERR_IO, TDB_LOG_ERROR, - "tdb_open: error %s reading %s", - strerror(errno), name); - goto fail; - } else if (rlen < sizeof(hdr) - || strcmp(hdr.magic_food, TDB_MAGIC_FOOD) != 0) { - ecode = tdb_logerr(tdb, TDB_ERR_IO, TDB_LOG_ERROR, - "tdb_open: %s is not a tdb file", name); - goto fail; - } - - if (hdr.version != TDB_VERSION) { - if (hdr.version == bswap_64(TDB_VERSION)) - tdb->flags |= TDB_CONVERT; - else { - /* wrong version */ - ecode = tdb_logerr(tdb, TDB_ERR_IO, TDB_LOG_ERROR, - "tdb_open:" - " %s is unknown version 0x%llx", - name, (long long)hdr.version); - goto fail; - } - } - - tdb_convert(tdb, &hdr, sizeof(hdr)); - tdb->hash_seed = hdr.hash_seed; - hash_test = TDB_HASH_MAGIC; - hash_test = tdb_hash(tdb, &hash_test, sizeof(hash_test)); - if (hdr.hash_test != hash_test) { - /* wrong hash variant */ - ecode = tdb_logerr(tdb, TDB_ERR_IO, TDB_LOG_ERROR, - "tdb_open:" - " %s uses a different hash function", - name); - goto fail; - } - - if (fstat(tdb->fd, &st) == -1) { - saved_errno = errno; - ecode = tdb_logerr(tdb, TDB_ERR_IO, TDB_LOG_ERROR, - "tdb_open: could not stat open %s: %s", - name, strerror(errno)); - goto fail; - } - - /* Is it already in the open list? If so, fail. */ - if (tdb_already_open(st.st_dev, st.st_ino)) { - /* FIXME */ - ecode = tdb_logerr(tdb, TDB_ERR_IO, TDB_LOG_USE_ERROR, - "tdb_open: %s (%d,%d) is already open" - " in this process", - name, (int)st.st_dev, (int)st.st_ino); - 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) - goto fail; - } - - tdb->device = st.st_dev; - tdb->inode = st.st_ino; - tdb_unlock_open(tdb); - - /* This make sure we have current map_size and mmap. */ - tdb->methods->oob(tdb, tdb->map_size + 1, true); - - /* Now it's fully formed, recover if necessary. */ - berr = tdb_needs_recovery(tdb); - if (unlikely(berr != false)) { - if (berr < 0) { - ecode = berr; - goto fail; - } - ecode = tdb_lock_and_recover(tdb); - if (ecode != TDB_SUCCESS) { - goto fail; - } - } - - ecode = tdb_ftable_init(tdb); - if (ecode != TDB_SUCCESS) { - goto fail; - } - - tdb->next = tdbs; - tdbs = tdb; - return tdb; - - fail: - /* Map ecode to some logical errno. */ - if (!saved_errno) { - switch (ecode) { - case TDB_ERR_CORRUPT: - case TDB_ERR_IO: - saved_errno = EIO; - break; - case TDB_ERR_LOCK: - saved_errno = EWOULDBLOCK; - break; - case TDB_ERR_OOM: - saved_errno = ENOMEM; - break; - case TDB_ERR_EINVAL: - saved_errno = EINVAL; - break; - default: - saved_errno = EINVAL; - break; - } - } - -#ifdef TDB_TRACE - close(tdb->tracefd); -#endif - if (tdb->map_ptr) { - if (tdb->flags & TDB_INTERNAL) { - free(tdb->map_ptr); - } else - tdb_munmap(tdb); - } - free(tdb->lockrecs); - free((char *)tdb->name); - if (tdb->fd != -1) - if (close(tdb->fd) != 0) - tdb_logerr(tdb, TDB_ERR_IO, TDB_LOG_ERROR, - "tdb_open: failed to close tdb->fd" - " on error: %s", strerror(errno)); - free(tdb); - errno = saved_errno; - return NULL; -} - static enum TDB_ERROR update_rec_hdr(struct tdb_context *tdb, tdb_off_t off, tdb_len_t keylen, @@ -718,46 +278,6 @@ unlock: return ecode; } -int tdb_close(struct tdb_context *tdb) -{ - struct tdb_context **i; - int ret = 0; - - tdb_trace(tdb, "tdb_close"); - - if (tdb->transaction) { - tdb_transaction_cancel(tdb); - } - - if (tdb->map_ptr) { - if (tdb->flags & TDB_INTERNAL) - free(tdb->map_ptr); - else - tdb_munmap(tdb); - } - free((char *)tdb->name); - if (tdb->fd != -1) { - ret = close(tdb->fd); - tdb->fd = -1; - } - free(tdb->lockrecs); - - /* Remove from contexts list */ - for (i = &tdbs; *i; i = &(*i)->next) { - if (*i == tdb) { - *i = tdb->next; - break; - } - } - -#ifdef TDB_TRACE - close(tdb->tracefd); -#endif - free(tdb); - - return ret; -} - unsigned int tdb_get_flags(struct tdb_context *tdb) { return tdb->flags; diff --git a/ccan/tdb2/test/failtest_helper.h b/ccan/tdb2/test/failtest_helper.h index 418c1968..56cb267a 100644 --- a/ccan/tdb2/test/failtest_helper.h +++ b/ccan/tdb2/test/failtest_helper.h @@ -4,9 +4,9 @@ #include /* FIXME: Check these! */ -#define INITIAL_TDB_MALLOC "tdb.c", 191, FAILTEST_MALLOC -#define URANDOM_OPEN "tdb.c", 49, FAILTEST_OPEN -#define URANDOM_READ "tdb.c", 29, FAILTEST_READ +#define INITIAL_TDB_MALLOC "open.c", 184, FAILTEST_MALLOC +#define URANDOM_OPEN "open.c", 43, FAILTEST_OPEN +#define URANDOM_READ "open.c", 23, FAILTEST_READ bool exit_check_log(struct failtest_call *history, unsigned num); bool failmatch(const struct failtest_call *call, diff --git a/ccan/tdb2/test/run-001-encode.c b/ccan/tdb2/test/run-001-encode.c index 0c8ab61e..bfc9400d 100644 --- a/ccan/tdb2/test/run-001-encode.c +++ b/ccan/tdb2/test/run-001-encode.c @@ -1,4 +1,5 @@ #include +#include #include #include #include diff --git a/ccan/tdb2/test/run-001-fls.c b/ccan/tdb2/test/run-001-fls.c index a54d90d6..d54cad1d 100644 --- a/ccan/tdb2/test/run-001-fls.c +++ b/ccan/tdb2/test/run-001-fls.c @@ -1,4 +1,5 @@ #include +#include #include #include #include diff --git a/ccan/tdb2/test/run-01-new_database.c b/ccan/tdb2/test/run-01-new_database.c index 2d1cfc83..4cfd04d9 100644 --- a/ccan/tdb2/test/run-01-new_database.c +++ b/ccan/tdb2/test/run-01-new_database.c @@ -1,5 +1,6 @@ #include #include +#include #include #include #include diff --git a/ccan/tdb2/test/run-02-expand.c b/ccan/tdb2/test/run-02-expand.c index 0a1bc991..7f74cdd5 100644 --- a/ccan/tdb2/test/run-02-expand.c +++ b/ccan/tdb2/test/run-02-expand.c @@ -1,5 +1,6 @@ #include #include +#include #include #include #include diff --git a/ccan/tdb2/test/run-03-coalesce.c b/ccan/tdb2/test/run-03-coalesce.c index ffa2b6c9..d4009651 100644 --- a/ccan/tdb2/test/run-03-coalesce.c +++ b/ccan/tdb2/test/run-03-coalesce.c @@ -1,4 +1,5 @@ #include +#include #include #include #include diff --git a/ccan/tdb2/test/run-04-basichash.c b/ccan/tdb2/test/run-04-basichash.c index 0745a23c..8a756637 100644 --- a/ccan/tdb2/test/run-04-basichash.c +++ b/ccan/tdb2/test/run-04-basichash.c @@ -1,4 +1,5 @@ #include +#include #include #include #include diff --git a/ccan/tdb2/test/run-10-simple-store.c b/ccan/tdb2/test/run-10-simple-store.c index 760ead38..daf97555 100644 --- a/ccan/tdb2/test/run-10-simple-store.c +++ b/ccan/tdb2/test/run-10-simple-store.c @@ -1,5 +1,6 @@ #include #include +#include #include #include #include diff --git a/ccan/tdb2/test/run-11-simple-fetch.c b/ccan/tdb2/test/run-11-simple-fetch.c index 1a68b54e..c16c28f8 100644 --- a/ccan/tdb2/test/run-11-simple-fetch.c +++ b/ccan/tdb2/test/run-11-simple-fetch.c @@ -1,5 +1,6 @@ #include #include +#include #include #include #include diff --git a/ccan/tdb2/test/run-12-store.c b/ccan/tdb2/test/run-12-store.c index 8ab9ddc1..0b3c2965 100644 --- a/ccan/tdb2/test/run-12-store.c +++ b/ccan/tdb2/test/run-12-store.c @@ -1,4 +1,5 @@ #include +#include #include #include #include diff --git a/ccan/tdb2/test/run-13-delete.c b/ccan/tdb2/test/run-13-delete.c index 6295523b..8322ff50 100644 --- a/ccan/tdb2/test/run-13-delete.c +++ b/ccan/tdb2/test/run-13-delete.c @@ -1,4 +1,5 @@ #include +#include #include #include #include diff --git a/ccan/tdb2/test/run-15-append.c b/ccan/tdb2/test/run-15-append.c index d2481658..e1b85b48 100644 --- a/ccan/tdb2/test/run-15-append.c +++ b/ccan/tdb2/test/run-15-append.c @@ -1,4 +1,5 @@ #include +#include #include #include #include diff --git a/ccan/tdb2/test/run-20-growhash.c b/ccan/tdb2/test/run-20-growhash.c index 160f37de..b504e490 100644 --- a/ccan/tdb2/test/run-20-growhash.c +++ b/ccan/tdb2/test/run-20-growhash.c @@ -1,4 +1,5 @@ #include +#include #include #include #include diff --git a/ccan/tdb2/test/run-25-hashoverload.c b/ccan/tdb2/test/run-25-hashoverload.c index b96a4cc4..4ddb54bc 100644 --- a/ccan/tdb2/test/run-25-hashoverload.c +++ b/ccan/tdb2/test/run-25-hashoverload.c @@ -1,4 +1,5 @@ #include +#include #include #include #include diff --git a/ccan/tdb2/test/run-30-exhaust-before-expand.c b/ccan/tdb2/test/run-30-exhaust-before-expand.c index f887b8b4..ed7c66dd 100644 --- a/ccan/tdb2/test/run-30-exhaust-before-expand.c +++ b/ccan/tdb2/test/run-30-exhaust-before-expand.c @@ -1,4 +1,5 @@ #include +#include #include #include #include diff --git a/ccan/tdb2/test/run-50-multiple-freelists.c b/ccan/tdb2/test/run-50-multiple-freelists.c index b1a8747e..8220b911 100644 --- a/ccan/tdb2/test/run-50-multiple-freelists.c +++ b/ccan/tdb2/test/run-50-multiple-freelists.c @@ -1,4 +1,5 @@ #include +#include #include #include #include diff --git a/ccan/tdb2/test/run-55-transaction.c b/ccan/tdb2/test/run-55-transaction.c index 4ebf792a..d1224a7f 100644 --- a/ccan/tdb2/test/run-55-transaction.c +++ b/ccan/tdb2/test/run-55-transaction.c @@ -1,4 +1,5 @@ #include +#include #include #include #include diff --git a/ccan/tdb2/test/run-56-open-during-transaction.c b/ccan/tdb2/test/run-56-open-during-transaction.c index 8a6a0e52..b242eab7 100644 --- a/ccan/tdb2/test/run-56-open-during-transaction.c +++ b/ccan/tdb2/test/run-56-open-during-transaction.c @@ -12,6 +12,7 @@ static int ftruncate_check(int fd, off_t length); #define ftruncate ftruncate_check #include +#include #include #include #include diff --git a/ccan/tdb2/test/run-57-die-during-transaction.c b/ccan/tdb2/test/run-57-die-during-transaction.c index b6c3557a..59b4d62c 100644 --- a/ccan/tdb2/test/run-57-die-during-transaction.c +++ b/ccan/tdb2/test/run-57-die-during-transaction.c @@ -59,6 +59,7 @@ static void free_all(void) #define free free_noleak #include +#include #include #include #include diff --git a/ccan/tdb2/test/run-add-remove-flags.c b/ccan/tdb2/test/run-add-remove-flags.c index 7c74e536..23a11cdc 100644 --- a/ccan/tdb2/test/run-add-remove-flags.c +++ b/ccan/tdb2/test/run-add-remove-flags.c @@ -1,4 +1,5 @@ #include +#include #include #include #include diff --git a/ccan/tdb2/test/run-features.c b/ccan/tdb2/test/run-features.c index a09ddb96..f00c74bc 100644 --- a/ccan/tdb2/test/run-features.c +++ b/ccan/tdb2/test/run-features.c @@ -1,4 +1,5 @@ #include +#include #include #include #include diff --git a/ccan/tdb2/test/run-firstkey-nextkey.c b/ccan/tdb2/test/run-firstkey-nextkey.c index b8a12bd3..895734a7 100644 --- a/ccan/tdb2/test/run-firstkey-nextkey.c +++ b/ccan/tdb2/test/run-firstkey-nextkey.c @@ -1,4 +1,5 @@ #include +#include #include #include #include diff --git a/ccan/tdb2/test/run-missing-entries.c b/ccan/tdb2/test/run-missing-entries.c index e197143f..9bc77877 100644 --- a/ccan/tdb2/test/run-missing-entries.c +++ b/ccan/tdb2/test/run-missing-entries.c @@ -1,5 +1,6 @@ /* Another test revealed that we lost an entry. This reproduces it. */ #include +#include #include #include #include diff --git a/ccan/tdb2/test/run-record-expand.c b/ccan/tdb2/test/run-record-expand.c index 3f008b0a..63bbf18d 100644 --- a/ccan/tdb2/test/run-record-expand.c +++ b/ccan/tdb2/test/run-record-expand.c @@ -1,4 +1,5 @@ #include +#include #include #include #include diff --git a/ccan/tdb2/test/run-remap-in-read_traverse.c b/ccan/tdb2/test/run-remap-in-read_traverse.c index 5c473cbe..66fc82ed 100644 --- a/ccan/tdb2/test/run-remap-in-read_traverse.c +++ b/ccan/tdb2/test/run-remap-in-read_traverse.c @@ -1,6 +1,7 @@ /* We had a bug where we marked the tdb read-only for a tdb_traverse_read. * If we then expanded the tdb, we would remap read-only, and later SEGV. */ #include +#include #include #include #include diff --git a/ccan/tdb2/test/run-seed.c b/ccan/tdb2/test/run-seed.c index 98a6b0b3..09ed1cb3 100644 --- a/ccan/tdb2/test/run-seed.c +++ b/ccan/tdb2/test/run-seed.c @@ -1,4 +1,5 @@ #include +#include #include #include #include diff --git a/ccan/tdb2/test/run-simple-delete.c b/ccan/tdb2/test/run-simple-delete.c index d9d0fb1a..fef79a9b 100644 --- a/ccan/tdb2/test/run-simple-delete.c +++ b/ccan/tdb2/test/run-simple-delete.c @@ -1,4 +1,5 @@ #include +#include #include #include #include diff --git a/ccan/tdb2/test/run-summary.c b/ccan/tdb2/test/run-summary.c index 24d9428e..6217021b 100644 --- a/ccan/tdb2/test/run-summary.c +++ b/ccan/tdb2/test/run-summary.c @@ -1,4 +1,5 @@ #include +#include #include #include #include diff --git a/ccan/tdb2/test/run-tdb_errorstr.c b/ccan/tdb2/test/run-tdb_errorstr.c index 8a7e378e..27bdfcd6 100644 --- a/ccan/tdb2/test/run-tdb_errorstr.c +++ b/ccan/tdb2/test/run-tdb_errorstr.c @@ -1,4 +1,5 @@ #include +#include #include #include #include diff --git a/ccan/tdb2/test/run-traverse.c b/ccan/tdb2/test/run-traverse.c index 13c3d457..36077e4a 100644 --- a/ccan/tdb2/test/run-traverse.c +++ b/ccan/tdb2/test/run-traverse.c @@ -1,4 +1,5 @@ #include +#include #include #include #include -- 2.39.2