1 #include "../common/tdb_private.h"
2 #include "../common/io.c"
3 #include "../common/tdb.c"
4 #include "../common/lock.c"
5 #include "../common/freelist.c"
6 #include "../common/traverse.c"
7 #include "../common/transaction.c"
8 #include "../common/error.c"
9 #include "../common/open.c"
10 #include "../common/check.c"
11 #include "../common/hash.c"
12 #include "../common/mutex.c"
13 #include "tap-interface.h"
14 #include <stdlib.h>
15 
16 static unsigned int tdb_dumb_hash(TDB_DATA *key)
17 {
18 	return key->dsize;
19 }
20 
21 static void log_fn(struct tdb_context *tdb, enum tdb_debug_level level, const char *fmt, ...)
22 {
23 	unsigned int *count = tdb_get_logging_private(tdb);
24 	if (strstr(fmt, "hash"))
25 		(*count)++;
26 }
27 
28 static unsigned int hdr_rwlocks(const char *fname)
29 {
30 	struct tdb_header hdr;
31 	ssize_t nread;
32 
33 	int fd = open(fname, O_RDONLY);
34 	if (fd == -1)
35 		return -1;
36 
37 	nread = read(fd, &hdr, sizeof(hdr));
38 	close(fd);
39 	if (nread != sizeof(hdr)) {
40 		return -1;
41 	}
42 	return hdr.rwlocks;
43 }
44 
45 int main(int argc, char *argv[])
46 {
47 	struct tdb_context *tdb;
48 	unsigned int log_count, flags;
49 	TDB_DATA d, r;
50 	struct tdb_logging_context log_ctx = { log_fn, &log_count };
51 
52 	plan_tests(38 * 2);
53 
54 	for (flags = 0; flags <= TDB_CONVERT; flags += TDB_CONVERT) {
55 		unsigned int rwmagic = TDB_HASH_RWLOCK_MAGIC;
56 
57 		if (flags & TDB_CONVERT)
58 			tdb_convert(&rwmagic, sizeof(rwmagic));
59 
60 		/* Create an old-style hash. */
61 		log_count = 0;
62 		tdb = tdb_open_ex("run-incompatible.tdb", 0, flags,
63 				  O_CREAT|O_RDWR|O_TRUNC, 0600, &log_ctx,
64 				  NULL);
65 		ok1(tdb);
66 		ok1(log_count == 0);
67 		d.dptr = discard_const_p(uint8_t, "Hello");
68 		d.dsize = 5;
69 		ok1(tdb_store(tdb, d, d, TDB_INSERT) == 0);
70 		tdb_close(tdb);
71 
72 		/* Should not have marked rwlocks field. */
73 		ok1(hdr_rwlocks("run-incompatible.tdb") == 0);
74 
75 		/* We can still open any old-style with incompat flag. */
76 		log_count = 0;
77 		tdb = tdb_open_ex("run-incompatible.tdb", 0,
78 				  TDB_INCOMPATIBLE_HASH,
79 				  O_RDWR, 0600, &log_ctx, NULL);
80 		ok1(tdb);
81 		ok1(log_count == 0);
82 		r = tdb_fetch(tdb, d);
83 		ok1(r.dsize == 5);
84 		free(r.dptr);
85 		ok1(tdb_check(tdb, NULL, NULL) == 0);
86 		tdb_close(tdb);
87 
88 		log_count = 0;
89 		tdb = tdb_open_ex("test/jenkins-le-hash.tdb", 0, 0, O_RDONLY,
90 				  0, &log_ctx, tdb_jenkins_hash);
91 		ok1(tdb);
92 		ok1(log_count == 0);
93 		ok1(tdb_check(tdb, NULL, NULL) == 0);
94 		tdb_close(tdb);
95 
96 		log_count = 0;
97 		tdb = tdb_open_ex("test/jenkins-be-hash.tdb", 0, 0, O_RDONLY,
98 				  0, &log_ctx, tdb_jenkins_hash);
99 		ok1(tdb);
100 		ok1(log_count == 0);
101 		ok1(tdb_check(tdb, NULL, NULL) == 0);
102 		tdb_close(tdb);
103 
104 		/* OK, now create with incompatible flag, default hash. */
105 		log_count = 0;
106 		tdb = tdb_open_ex("run-incompatible.tdb", 0,
107 				  flags|TDB_INCOMPATIBLE_HASH,
108 				  O_CREAT|O_RDWR|O_TRUNC, 0600, &log_ctx,
109 				  NULL);
110 		ok1(tdb);
111 		ok1(log_count == 0);
112 		d.dptr = discard_const_p(uint8_t, "Hello");
113 		d.dsize = 5;
114 		ok1(tdb_store(tdb, d, d, TDB_INSERT) == 0);
115 		tdb_close(tdb);
116 
117 		/* Should have marked rwlocks field. */
118 		ok1(hdr_rwlocks("run-incompatible.tdb") == rwmagic);
119 
120 		/* Cannot open with old hash. */
121 		log_count = 0;
122 		tdb = tdb_open_ex("run-incompatible.tdb", 0, 0,
123 				  O_RDWR, 0600, &log_ctx, tdb_old_hash);
124 		ok1(!tdb);
125 		ok1(log_count == 1);
126 
127 		/* Can open with jenkins hash. */
128 		log_count = 0;
129 		tdb = tdb_open_ex("run-incompatible.tdb", 0, 0,
130 				  O_RDWR, 0600, &log_ctx, tdb_jenkins_hash);
131 		ok1(tdb);
132 		ok1(log_count == 0);
133 		r = tdb_fetch(tdb, d);
134 		ok1(r.dsize == 5);
135 		free(r.dptr);
136 		ok1(tdb_check(tdb, NULL, NULL) == 0);
137 		tdb_close(tdb);
138 
139 		/* Can open by letting it figure it out itself. */
140 		log_count = 0;
141 		tdb = tdb_open_ex("run-incompatible.tdb", 0, 0,
142 				  O_RDWR, 0600, &log_ctx, NULL);
143 		ok1(tdb);
144 		ok1(log_count == 0);
145 		r = tdb_fetch(tdb, d);
146 		ok1(r.dsize == 5);
147 		free(r.dptr);
148 		ok1(tdb_check(tdb, NULL, NULL) == 0);
149 		tdb_close(tdb);
150 
151 		/* We can also use incompatible hash with other hashes. */
152 		log_count = 0;
153 		tdb = tdb_open_ex("run-incompatible.tdb", 0,
154 				  flags|TDB_INCOMPATIBLE_HASH,
155 				  O_CREAT|O_RDWR|O_TRUNC, 0600, &log_ctx,
156 				  tdb_dumb_hash);
157 		ok1(tdb);
158 		ok1(log_count == 0);
159 		d.dptr = discard_const_p(uint8_t, "Hello");
160 		d.dsize = 5;
161 		ok1(tdb_store(tdb, d, d, TDB_INSERT) == 0);
162 		tdb_close(tdb);
163 
164 		/* Should have marked rwlocks field. */
165 		ok1(hdr_rwlocks("run-incompatible.tdb") == rwmagic);
166 
167 		/* It should not open if we don't specify. */
168 		log_count = 0;
169 		tdb = tdb_open_ex("run-incompatible.tdb", 0, 0, O_RDWR, 0,
170 				  &log_ctx, NULL);
171 		ok1(!tdb);
172 		ok1(log_count == 1);
173 
174 		/* Should reopen with correct hash. */
175 		log_count = 0;
176 		tdb = tdb_open_ex("run-incompatible.tdb", 0, 0, O_RDWR, 0,
177 				  &log_ctx, tdb_dumb_hash);
178 		ok1(tdb);
179 		ok1(log_count == 0);
180 		r = tdb_fetch(tdb, d);
181 		ok1(r.dsize == 5);
182 		free(r.dptr);
183 		ok1(tdb_check(tdb, NULL, NULL) == 0);
184 		tdb_close(tdb);
185 	}
186 
187 	return exit_status();
188 }
189