/* Fill in the header */
newdb->version = TDB_VERSION;
newdb->hash_size = hash_size;
+ newdb->hashcheck = hashcheck(tdb);
if (tdb->flags & TDB_INTERNAL) {
tdb->map_size = size;
tdb->map_ptr = (char *)newdb;
{
}
+uint32_t hashcheck(struct tdb_context *tdb)
+{
+ uint32_t vals[] = { TDB_VERSION, TDB_MAGIC };
+ TDB_DATA hashkey = { (unsigned char *)vals, sizeof(vals) };
+
+ /* If we're using the default hash, let old code still open the db. */
+ if (tdb->hash_fn == default_tdb_hash)
+ return 0;
+
+ /* Only let new hash-aware TDB code open it (must not be zero!) */
+ return (tdb->hash_fn(&hashkey) | 1);
+}
struct tdb_context *tdb_open_ex(const char *name, int hash_size, int tdb_flags,
int open_flags, mode_t mode,
if (fstat(tdb->fd, &st) == -1)
goto fail;
- if (tdb->header.rwlocks != 0) {
- TDB_LOG((tdb, TDB_DEBUG_ERROR, "tdb_open_ex: spinlocks no longer supported\n"));
+ if (tdb->header.hashcheck != hashcheck(tdb)) {
+ TDB_LOG((tdb, TDB_DEBUG_ERROR, "tdb_open_ex: wrong hash?\n"));
goto fail;
}
char magic_food[32]; /* for /etc/magic */
uint32_t version; /* version of the code */
uint32_t hash_size; /* number of hash entries */
- tdb_off_t rwlocks; /* obsolete - kept to detect old formats */
+ tdb_off_t hashcheck; /* 0 for default hash. */
tdb_off_t recovery_start; /* offset of transaction recovery region */
tdb_off_t sequence_number; /* used when TDB_SEQNUM is set */
tdb_off_t reserved[29];
/*
internal prototypes
*/
+uint32_t hashcheck(struct tdb_context *tdb);
int tdb_munmap(struct tdb_context *tdb);
void tdb_mmap(struct tdb_context *tdb);
int tdb_lock(struct tdb_context *tdb, int list, int ltype);
--- /dev/null
+#define _XOPEN_SOURCE 500
+#include <ccan/tdb/tdb.h>
+#include <ccan/tdb/io.c>
+#include <ccan/tdb/tdb.c>
+#include <ccan/tdb/lock.c>
+#include <ccan/tdb/freelist.c>
+#include <ccan/tdb/traverse.c>
+#include <ccan/tdb/transaction.c>
+#include <ccan/tdb/error.c>
+#include <ccan/tdb/open.c>
+#include <ccan/tdb/check.c>
+#include <ccan/hash/hash.h>
+#include <ccan/tap/tap.h>
+#include <stdlib.h>
+#include <err.h>
+
+static unsigned int jenkins_hash(TDB_DATA *key)
+{
+ return hash_stable(key->dptr, key->dsize, 0);
+}
+
+static void log_fn(struct tdb_context *tdb, enum tdb_debug_level level, const char *fmt, ...)
+{
+ unsigned int *count = tdb_get_logging_private(tdb);
+ /* Old code used to complain about spinlocks when we put something
+ here. */
+ if (strstr(fmt, "wrong hash") || strstr(fmt, "spinlock"))
+ (*count)++;
+}
+
+int main(int argc, char *argv[])
+{
+ struct tdb_context *tdb;
+ unsigned int log_count;
+ struct tdb_logging_context log_ctx = { log_fn, &log_count };
+
+ plan_tests(16);
+
+ /* Create with default hash. */
+ log_count = 0;
+ tdb = tdb_open_ex("run-wronghash-fail.tdb", 0, 0,
+ O_CREAT|O_RDWR|O_TRUNC, 0600, &log_ctx, NULL);
+ ok1(tdb);
+ ok1(log_count == 0);
+ tdb_close(tdb);
+
+ /* Fail to open with different hash. */
+ tdb = tdb_open_ex("run-wronghash-fail.tdb", 0, 0, O_RDWR, 0,
+ &log_ctx, jenkins_hash);
+ ok1(!tdb);
+ ok1(log_count == 1);
+
+ /* Create with different hash. */
+ log_count = 0;
+ tdb = tdb_open_ex("run-wronghash-fail.tdb", 0, 0,
+ O_CREAT|O_RDWR|O_TRUNC,
+ 0600, &log_ctx, jenkins_hash);
+ ok1(tdb);
+ ok1(log_count == 0);
+ tdb_close(tdb);
+
+ /* Endian should be no problem. */
+ log_count = 0;
+ tdb = tdb_open_ex("test/jenkins-le-hash.tdb", 0, 0, O_RDWR, 0,
+ &log_ctx, NULL);
+ ok1(!tdb);
+ ok1(log_count == 1);
+
+ log_count = 0;
+ tdb = tdb_open_ex("test/jenkins-be-hash.tdb", 0, 0, O_RDWR, 0,
+ &log_ctx, NULL);
+ ok1(!tdb);
+ ok1(log_count == 1);
+
+ log_count = 0;
+ /* Fail to open with defailt hash. */
+ tdb = tdb_open_ex("run-wronghash-fail.tdb", 0, 0, O_RDWR, 0,
+ &log_ctx, NULL);
+ ok1(!tdb);
+ ok1(log_count == 1);
+
+ log_count = 0;
+ tdb = tdb_open_ex("test/jenkins-le-hash.tdb", 0, 0, O_RDONLY,
+ 0, &log_ctx, jenkins_hash);
+ ok1(tdb);
+ ok1(log_count == 0);
+ tdb_close(tdb);
+
+ log_count = 0;
+ tdb = tdb_open_ex("test/jenkins-be-hash.tdb", 0, 0, O_RDONLY,
+ 0, &log_ctx, jenkins_hash);
+ ok1(tdb);
+ ok1(log_count == 0);
+ tdb_close(tdb);
+
+ return exit_status();
+}