< tdb->map_size) {
tdb->log(tdb, TDB_DEBUG_ERROR, tdb->log_priv,
"check: %llu zones size %llu don't cover %llu\n",
- (long long)(1ULL << tdb->header.v.zone_bits),
(long long)tdb->header.v.num_zones,
+ (long long)(1ULL << tdb->header.v.zone_bits),
(long long)tdb->map_size);
return false;
}
static int off_cmp(const tdb_off_t *a, const tdb_off_t *b)
{
/* Can overflow an int. */
- return a > b ? 1
- : a < b ? -1
+ return *a > *b ? 1
+ : *a < *b ? -1
: 0;
}
num_nonzero++;
}
- if (num_found != num_used) {
+ /* free table and hash table are two of the used blocks. */
+ if (num_found != num_used - 2) {
tdb->log(tdb, TDB_DEBUG_ERROR, tdb->log_priv,
"tdb_check: Not all entries are in hash\n");
return false;
size_t num_free = 0, num_used = 0;
bool hash_found = false, free_found = false;
+ /* This always ensures the header is uptodate. */
if (tdb_allrecord_lock(tdb, F_RDLCK, TDB_LOCK_WAIT, false) != 0)
return -1;
- update_header(tdb);
-
if (!check_header(tdb))
goto fail;
if (tdb->methods->oob(tdb, off + len, false))
goto fail;
+ if (len < sizeof(p->f)) {
+ tdb->log(tdb, TDB_DEBUG_ERROR, tdb->log_priv,
+ "tdb_check: too short record %llu at"
+ " %llu\n",
+ (long long)len, (long long)off);
+ goto fail;
+ }
+
if (off + sizeof(p->u) == tdb->header.v.hash_off) {
hash_found = true;
} else if (off + sizeof(p->u)
goto fail;
tdb_allrecord_unlock(tdb, F_RDLCK);
- return true;
+ return 0;
fail:
tdb_allrecord_unlock(tdb, F_RDLCK);
- return false;
+ return -1;
}