1 #include "tdb2-source.h"
2 #include <ccan/tap/tap.h>
7 static int check(TDB_DATA key
, TDB_DATA data
, void *private)
9 unsigned int *sizes
= private;
11 if (key
.dsize
> strlen("hello"))
13 if (memcmp(key
.dptr
, "hello", key
.dsize
) != 0)
16 if (data
.dsize
!= strlen("world"))
18 if (memcmp(data
.dptr
, "world", data
.dsize
) != 0)
21 sizes
[0] += key
.dsize
;
22 sizes
[1] += data
.dsize
;
26 static void tdb1_flip_bit(struct tdb_context
*tdb
, unsigned int bit
)
28 unsigned int off
= bit
/ CHAR_BIT
;
29 unsigned char mask
= (1 << (bit
% CHAR_BIT
));
31 if (tdb
->file
->map_ptr
)
32 ((unsigned char *)tdb
->file
->map_ptr
)[off
] ^= mask
;
35 if (pread(tdb
->file
->fd
, &c
, 1, off
) != 1)
38 if (pwrite(tdb
->file
->fd
, &c
, 1, off
) != 1)
43 static void check_test(struct tdb_context
*tdb
)
46 unsigned int i
, verifiable
, corrupt
, sizes
[2], dsize
, ksize
;
48 ok1(tdb_check(tdb
, NULL
, NULL
) == TDB_SUCCESS
);
50 key
.dptr
= (void *)"hello";
51 data
.dsize
= strlen("world");
52 data
.dptr
= (void *)"world";
54 /* Key and data size respectively. */
57 /* 5 keys in hash size 2 means we'll have multichains. */
58 for (key
.dsize
= 1; key
.dsize
<= 5; key
.dsize
++) {
61 if (tdb_store(tdb
, key
, data
, TDB_INSERT
) != TDB_SUCCESS
)
65 /* This is how many bytes we expect to be verifiable. */
66 /* From the file header. */
67 verifiable
= strlen(TDB_MAGIC_FOOD
) + 1
68 + 2 * sizeof(uint32_t) + 2 * sizeof(tdb1_off_t
)
69 + 2 * sizeof(uint32_t);
70 /* From the free list chain and hash chains. */
71 verifiable
+= 3 * sizeof(tdb1_off_t
);
72 /* From the record headers & tailer */
73 verifiable
+= 5 * (sizeof(struct tdb1_record
) + sizeof(uint32_t));
74 /* The free block: we ignore datalen, keylen, full_hash. */
75 verifiable
+= sizeof(struct tdb1_record
) - 3*sizeof(uint32_t) +
77 /* Our check function verifies the key and data. */
78 verifiable
+= ksize
+ dsize
;
80 /* Flip one bit at a time, make sure it detects verifiable bytes. */
81 for (i
= 0, corrupt
= 0; i
< tdb
->file
->map_size
* CHAR_BIT
; i
++) {
82 tdb1_flip_bit(tdb
, i
);
83 memset(sizes
, 0, sizeof(sizes
));
84 if (tdb_check(tdb
, check
, sizes
) == TDB_ERR_CORRUPT
)
86 else if (sizes
[0] != ksize
|| sizes
[1] != dsize
)
88 tdb1_flip_bit(tdb
, i
);
90 ok(corrupt
== verifiable
* CHAR_BIT
, "corrupt %u should be %u",
91 corrupt
, verifiable
* CHAR_BIT
);
94 int main(int argc
, char *argv
[])
96 struct tdb_context
*tdb
;
97 union tdb_attribute hsize
;
99 hsize
.base
.attr
= TDB_ATTRIBUTE_TDB1_HASHSIZE
;
100 hsize
.base
.next
= &tap_log_attr
;
101 hsize
.tdb1_hashsize
.hsize
= 2;
104 /* This should use mmap. */
105 tdb
= tdb_open("run-corrupt.tdb1", TDB_VERSION1
,
106 O_CREAT
|O_TRUNC
|O_RDWR
, 0600, &hsize
);
113 /* This should not. */
114 tdb
= tdb_open("run-corrupt.tdb1", TDB_VERSION1
|TDB_NOMMAP
,
115 O_CREAT
|O_TRUNC
|O_RDWR
, 0600, &hsize
);
122 return exit_status();