-/* all contexts, to ensure no double-opens (fcntl locks don't nest!) */
-static struct tdb_context *tdbs = NULL;
-
-PRINTF_ATTRIBUTE(4, 5) static void
-null_log_fn(struct tdb_context *tdb,
- enum tdb_debug_level level, void *priv,
- const char *fmt, ...)
-{
-}
-
-/* We do a lot of work assuming our copy of the header volatile area
- * is uptodate, and usually it is. However, once we grab a lock, we have to
- * re-check it. */
-bool header_changed(struct tdb_context *tdb)
-{
- uint64_t gen;
-
- if (!(tdb->flags & TDB_NOLOCK) && tdb->header_uptodate) {
- tdb->log(tdb, TDB_DEBUG_WARNING, tdb->log_priv,
- "warning: header uptodate already\n");
- }
-
- /* We could get a partial update if we're not holding any locks. */
- assert((tdb->flags & TDB_NOLOCK) || tdb_has_locks(tdb));
-
- tdb->header_uptodate = true;
- gen = tdb_read_off(tdb, offsetof(struct tdb_header, v.generation));
- if (unlikely(gen != tdb->header.v.generation)) {
- tdb_read_convert(tdb, offsetof(struct tdb_header, v),
- &tdb->header.v, sizeof(tdb->header.v));
- return true;
- }
- return false;
-}
-
-int write_header(struct tdb_context *tdb)
-{
- assert(tdb_read_off(tdb, offsetof(struct tdb_header, v.generation))
- == tdb->header.v.generation);
- tdb->header.v.generation++;
- return tdb_write_convert(tdb, offsetof(struct tdb_header, v),
- &tdb->header.v, sizeof(tdb->header.v));
-}
-
-static uint64_t jenkins_hash(const void *key, size_t length, uint64_t seed,
- void *arg)
-{
- return hash64_stable((const unsigned char *)key, length, seed);
-}
-
-uint64_t tdb_hash(struct tdb_context *tdb, const void *ptr, size_t len)
-{
- return tdb->khash(ptr, len, tdb->header.hash_seed, tdb->hash_priv);
-}
-
-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 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 (tdb_read_all(fd, &ret, sizeof(ret))) {
- tdb->log(tdb, TDB_DEBUG_TRACE, tdb->log_priv,
- "tdb_open: random from /dev/urandom\n");
- 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) {
- tdb->log(tdb, TDB_DEBUG_TRACE, tdb->log_priv,
- "tdb_open: %u random bytes from"
- " /dev/egd-pool\n", 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->log(tdb, TDB_DEBUG_TRACE, tdb->log_priv,
- "tdb_open: random from getpid and time\n");
- return ret;
-}
-
-struct new_database {
- struct tdb_header hdr;
- struct tdb_used_record hrec;
- tdb_off_t hash[1ULL << INITIAL_HASH_BITS];
- struct tdb_used_record frec;
- tdb_off_t free[INITIAL_FREE_BUCKETS + 1]; /* One overflow bucket */
-};
-
-/* initialise a new database */
-static int tdb_new_database(struct tdb_context *tdb)