+ "tdb_check: Invalid offset %llu "
+ "in hash\n",
+ (long long)off);
+ goto fail;
+ }
+ /* Mark it invalid. */
+ *p ^= 1;
+ (*num_found)++;
+
+ if (is_subhash(group[b])) {
+ uint64_t subprefix;
+ subprefix = (hprefix
+ << (group_bits + TDB_HASH_GROUP_BITS))
+ + g * (1 << TDB_HASH_GROUP_BITS) + b;
+
+ if (!check_hash_record(tdb,
+ group[b] & TDB_OFF_MASK,
+ subprefix,
+ hprefix_bits
+ + group_bits
+ + TDB_HASH_GROUP_BITS,
+ used, num_used, num_found))
+ goto fail;
+ continue;
+ }
+ /* A normal entry */
+
+ /* Does it belong here at all? */
+ h = hash_record(tdb, off);
+ used_bits = 0;
+ if (get_bits(h, hprefix_bits, &used_bits) != hprefix
+ && hprefix_bits) {
+ tdb->log(tdb, TDB_DEBUG_ERROR, tdb->log_priv,
+ "check: bad hash placement"
+ " 0x%llx vs 0x%llx\n",
+ (long long)h, (long long)hprefix);
+ goto fail;
+ }
+
+ /* Does it belong in this group? */
+ if (get_bits(h, group_bits, &used_bits) != g) {
+ tdb->log(tdb, TDB_DEBUG_ERROR, tdb->log_priv,
+ "check: bad group %llu vs %u\n",
+ (long long)h, g);
+ goto fail;
+ }
+
+ /* Are bucket bits correct? */
+ bucket = group[b] & TDB_OFF_HASH_GROUP_MASK;
+ if (get_bits(h, TDB_HASH_GROUP_BITS, &used_bits)
+ != bucket) {
+ used_bits -= TDB_HASH_GROUP_BITS;
+ tdb->log(tdb, TDB_DEBUG_ERROR, tdb->log_priv,
+ "check: bad bucket %u vs %u\n",
+ (unsigned)get_bits(h,
+ TDB_HASH_GROUP_BITS,
+ &used_bits),
+ bucket);
+ goto fail;
+ }
+
+ /* There must not be any zero entries between
+ * the bucket it belongs in and this one! */
+ for (i = bucket;
+ i != b;
+ i = (i + 1) % (1 << TDB_HASH_GROUP_BITS)) {
+ if (group[i] == 0) {
+ tdb->log(tdb, TDB_DEBUG_ERROR,
+ tdb->log_priv,
+ "check: bad group placement"
+ " %u vs %u\n",
+ b, bucket);
+ goto fail;
+ }
+ }
+
+ if (tdb_read_convert(tdb, off, &rec, sizeof(rec)) == -1)
+ goto fail;
+
+ /* Bottom bits must match header. */
+ if ((h & ((1 << 5)-1)) != rec_hash(&rec)) {
+ tdb->log(tdb, TDB_DEBUG_ERROR, tdb->log_priv,
+ "tdb_check: Bad hash magic at"
+ " offset %llu (0x%llx vs 0x%llx)\n",